Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions packages/core/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ export class CliRenderer extends EventEmitter implements RenderContext {
private _cachedPalette: TerminalColors | null = null
private _paletteDetectionPromise: Promise<TerminalColors> | null = null
private _onDestroy?: () => void
private _themeMode: "dark" | "light" | null = null

private inputHandlers: ((sequence: string) => boolean)[] = []
private prependedInputHandlers: ((sequence: string) => boolean)[] = []
Expand Down Expand Up @@ -848,6 +849,10 @@ export class CliRenderer extends EventEmitter implements RenderContext {
return this._capabilities
}

public get themeMode(): "dark" | "light" | null {
return this._themeMode
}

public getDebugInputs(): Array<{ timestamp: string; sequence: string }> {
return [...this._debugInputs]
}
Expand Down Expand Up @@ -1060,6 +1065,24 @@ export class CliRenderer extends EventEmitter implements RenderContext {
return false
}).bind(this)

private themeModeHandler: (sequence: string) => boolean = ((sequence: string) => {
if (sequence === "\x1b[?997;1n") {
if (this._themeMode !== "dark") {
this._themeMode = "dark"
this.emit("theme_mode", "dark")
}
return true
}
if (sequence === "\x1b[?997;2n") {
if (this._themeMode !== "light") {
this._themeMode = "light"
this.emit("theme_mode", "light")
}
return true
}
return false
}).bind(this)

private setupInput(): void {
for (const handler of this.prependedInputHandlers) {
this.addInputHandler(handler)
Expand All @@ -1078,6 +1101,7 @@ export class CliRenderer extends EventEmitter implements RenderContext {
})
this.addInputHandler(this.capabilityHandler)
this.addInputHandler(this.focusHandler)
this.addInputHandler(this.themeModeHandler)
this.addInputHandler((sequence: string) => {
return this._keyHandler.processInput(sequence)
})
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,15 @@ export enum DebugOverlayCorner {

export type WidthMethod = "wcwidth" | "unicode"

export type ThemeMode = "dark" | "light"

export interface RendererEvents {
resize: (width: number, height: number) => void
key: (data: Buffer) => void
"memory:snapshot": (snapshot: { heapUsed: number; heapTotal: number; arrayBuffers: number }) => void
selection: (selection: Selection) => void
"debugOverlay:toggle": (enabled: boolean) => void
theme_mode: (mode: ThemeMode) => void
}

export interface RenderContext extends EventEmitter {
Expand Down
14 changes: 12 additions & 2 deletions packages/core/src/zig/terminal.zig
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,7 @@ pub fn resetState(self: *Terminal, tty: anytype) !void {
}

if (self.state.color_scheme_updates) {
try tty.writeAll(ansi.ANSI.colorSchemeReset);
self.state.color_scheme_updates = false;
try self.setColorSchemeUpdates(tty, false);
}

self.setTerminalTitle(tty, "");
Expand Down Expand Up @@ -270,6 +269,11 @@ pub fn enableDetectedFeatures(self: *Terminal, tty: anytype, use_kitty_keyboard:
if (self.caps.focus_tracking) {
try self.setFocusTracking(tty, true);
}

if (self.caps.color_scheme_updates) {
try self.setColorSchemeUpdates(tty, true);
try tty.writeAll(ansi.ANSI.colorSchemeRequest);
}
}

fn checkEnvironmentOverrides(self: *Terminal) void {
Expand Down Expand Up @@ -488,6 +492,12 @@ pub fn setModifyOtherKeys(self: *Terminal, tty: anytype, enable: bool) !void {
self.state.modify_other_keys = enable;
}

pub fn setColorSchemeUpdates(self: *Terminal, tty: anytype, enable: bool) !void {
const seq = if (enable) ansi.ANSI.colorSchemeSet else ansi.ANSI.colorSchemeReset;
try tty.writeAll(seq);
self.state.color_scheme_updates = enable;
}

/// The responses look like these:
/// kitty - '\x1B[?1016;2$y\x1B[?2027;0$y\x1B[?2031;2$y\x1B[?1004;1$y\x1B[?2026;2$y\x1B[1;2R\x1B[1;3R\x1BP>|kitty(0.40.1)\x1B\\\x1B[?0u\x1B_Gi=1;EINVAL:Zero width/height not allowed\x1B\\\x1B[?62;c'
/// ghostty - '\x1B[?1016;1$y\x1B[?2027;1$y\x1B[?2031;2$y\x1B[?1004;1$y\x1B[?2004;2$y\x1B[?2026;2$y\x1B[1;1R\x1B[1;1R\x1BP>|ghostty 1.1.3\x1B\\\x1B[?0u\x1B_Gi=1;OK\x1B\\\x1B[?62;22c'
Expand Down
Loading