fix(tui): detect terminal color scheme and apply light-optimised palette
This commit is contained in:
@@ -30,6 +30,7 @@ import {
|
|||||||
type OverlayHandle,
|
type OverlayHandle,
|
||||||
type SelectListTheme,
|
type SelectListTheme,
|
||||||
type Terminal,
|
type Terminal,
|
||||||
|
type TerminalColorScheme,
|
||||||
} from '@earendil-works/pi-tui'
|
} from '@earendil-works/pi-tui'
|
||||||
import type { Context } from 'cordis'
|
import type { Context } from 'cordis'
|
||||||
import z from 'schemastery'
|
import z from 'schemastery'
|
||||||
@@ -199,17 +200,21 @@ function displayText(text: string): string {
|
|||||||
* backgrounds alike; grouping uses foreground-only gutter bars and reverse
|
* backgrounds alike; grouping uses foreground-only gutter bars and reverse
|
||||||
* video rather than fixed background fills.
|
* video rather than fixed background fills.
|
||||||
*/
|
*/
|
||||||
function createPalette(enabled: boolean): Palette {
|
function createPalette(enabled: boolean, scheme: TerminalColorScheme = 'dark'): Palette {
|
||||||
return {
|
return {
|
||||||
accent: ansi('94', '39', enabled),
|
accent: ansi('94', '39', enabled),
|
||||||
accent2: ansi('95', '39', enabled),
|
accent2: ansi('95', '39', enabled),
|
||||||
text: text => text,
|
text: text => text,
|
||||||
muted: ansi('90', '39', enabled),
|
muted: ansi('90', '39', enabled),
|
||||||
dim: ansi('2', '22', enabled),
|
// SGR 2 (dim) lightens text on a light background — substitute ANSI 90
|
||||||
|
// (bright black / gray) which renders as a readable muted tone on any scheme.
|
||||||
|
dim: scheme === 'light' ? ansi('90', '39', enabled) : ansi('2', '22', enabled),
|
||||||
success: ansi('32', '39', enabled),
|
success: ansi('32', '39', enabled),
|
||||||
warning: ansi('33', '39', enabled),
|
warning: ansi('33', '39', enabled),
|
||||||
error: ansi('31', '39', enabled),
|
error: ansi('31', '39', enabled),
|
||||||
code: ansi('36', '39', enabled),
|
// ANSI 36 (cyan) is difficult to read on a light background — use
|
||||||
|
// ANSI 34 (blue) which is legible on both light and dark schemes.
|
||||||
|
code: scheme === 'light' ? ansi('34', '39', enabled) : ansi('36', '39', enabled),
|
||||||
added: ansi('32', '39', enabled),
|
added: ansi('32', '39', enabled),
|
||||||
removed: ansi('31', '39', enabled),
|
removed: ansi('31', '39', enabled),
|
||||||
bold: ansi('1', '22', enabled),
|
bold: ansi('1', '22', enabled),
|
||||||
@@ -1123,6 +1128,31 @@ export function createTuiChat(
|
|||||||
{ name: 'exit', description: 'Exit after the active turn reaches idle' },
|
{ name: 'exit', description: 'Exit after the active turn reaches idle' },
|
||||||
], agent.session.header.cwd ?? process.cwd()))
|
], agent.session.header.cwd ?? process.cwd()))
|
||||||
|
|
||||||
|
/** Swap the palette and all derived themes for the given terminal color scheme. */
|
||||||
|
const applyColorScheme = (scheme: TerminalColorScheme): void => {
|
||||||
|
if (scheme === currentScheme) return
|
||||||
|
currentScheme = scheme
|
||||||
|
Object.assign(palette, createPalette(resolved.color, scheme))
|
||||||
|
Object.assign(mdTheme, markdownTheme(palette))
|
||||||
|
editor.borderColor = text => palette.dim(text)
|
||||||
|
rebuildTranscript(false)
|
||||||
|
setStatus(agent.status)
|
||||||
|
requestRender()
|
||||||
|
}
|
||||||
|
let currentScheme: TerminalColorScheme = 'dark'
|
||||||
|
|
||||||
|
// Detect the terminal's color scheme via device-status report. Most terminals
|
||||||
|
// do not respond, so the promise settles with `undefined` and we keep the
|
||||||
|
// dark-optimised palette.
|
||||||
|
ui.queryTerminalColorScheme({ timeoutMs: 2000 }).then((scheme) => {
|
||||||
|
if (scheme !== undefined) applyColorScheme(scheme)
|
||||||
|
}).catch(() => {
|
||||||
|
// Timeout or query failure — keep dark default.
|
||||||
|
})
|
||||||
|
|
||||||
|
// Live-update when the user switches their terminal theme behind us.
|
||||||
|
const disposeSchemeListener = ui.onTerminalColorSchemeChange(applyColorScheme)
|
||||||
|
|
||||||
const toggleTools = (): void => {
|
const toggleTools = (): void => {
|
||||||
toolsExpanded = !toolsExpanded
|
toolsExpanded = !toolsExpanded
|
||||||
for (const card of allToolCards) card.setExpanded(toolsExpanded)
|
for (const card of allToolCards) card.setExpanded(toolsExpanded)
|
||||||
@@ -1271,6 +1301,7 @@ export function createTuiChat(
|
|||||||
disposeStatus()
|
disposeStatus()
|
||||||
disposeError()
|
disposeError()
|
||||||
disposeAgent()
|
disposeAgent()
|
||||||
|
disposeSchemeListener()
|
||||||
}
|
}
|
||||||
|
|
||||||
rebuildTranscript(true)
|
rebuildTranscript(true)
|
||||||
|
|||||||
Reference in New Issue
Block a user