Skip to content

Commit e66a57d

Browse files
committed
Set default terminal fg/bg from Emacs theme colors
The terminal hardcoded default colors to rgb(204,204,204) on black, ignoring the active Emacs theme. Add ghostel--set-default-colors (Zig) to set the terminal's default fg/bg from hex strings, and call it from ghostel--apply-palette using the Emacs default face. This makes terminals respect the current theme at creation and on theme change.
1 parent 57c6352 commit e66a57d

3 files changed

Lines changed: 96 additions & 9 deletions

File tree

ghostel.el

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ Bump this only when the Elisp code requires a newer native module
312312
(declare-function ghostel--scroll "ghostel-module")
313313
(declare-function ghostel--scroll-bottom "ghostel-module")
314314
(declare-function ghostel--scroll-top "ghostel-module")
315+
(declare-function ghostel--set-default-colors "ghostel-module")
315316
(declare-function ghostel--set-palette "ghostel-module")
316317
(declare-function ghostel--set-size "ghostel-module")
317318
(declare-function ghostel--write-input "ghostel-module")
@@ -1502,15 +1503,20 @@ Falls back to \"#000000\" if the color cannot be resolved."
15021503
"#000000"))
15031504

15041505
(defun ghostel--apply-palette (term)
1505-
"Apply colors from `ghostel-color-palette' faces to TERM."
1506-
(when (and term ghostel-color-palette)
1507-
(let ((colors
1508-
(mapconcat
1509-
(lambda (face)
1510-
(ghostel--face-hex-color face :foreground))
1511-
ghostel-color-palette
1512-
"")))
1513-
(ghostel--set-palette term colors))))
1506+
"Apply colors from `ghostel-color-palette' faces and default fg/bg to TERM."
1507+
(when term
1508+
(ghostel--set-default-colors
1509+
term
1510+
(ghostel--face-hex-color 'default :foreground)
1511+
(ghostel--face-hex-color 'default :background))
1512+
(when ghostel-color-palette
1513+
(let ((colors
1514+
(mapconcat
1515+
(lambda (face)
1516+
(ghostel--face-hex-color face :foreground))
1517+
ghostel-color-palette
1518+
"")))
1519+
(ghostel--set-palette term colors)))))
15141520

15151521

15161522
;;; Theme synchronization

src/module.zig

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export fn emacs_module_init(runtime: *c.struct_emacs_runtime) callconv(.c) c_int
4242
env.bindFunction("ghostel--mouse-event", 6, 6, &fnMouseEvent, "Send a mouse event to the terminal.\n\n(ghostel--mouse-event TERM ACTION BUTTON ROW COL MODS)");
4343
env.bindFunction("ghostel--focus-event", 2, 2, &fnFocusEvent, "Send a focus event to the terminal.\n\n(ghostel--focus-event TERM GAINED)");
4444
env.bindFunction("ghostel--set-palette", 2, 2, &fnSetPalette, "Set the ANSI color palette.\n\n(ghostel--set-palette TERM COLORS-STRING)");
45+
env.bindFunction("ghostel--set-default-colors", 3, 3, &fnSetDefaultColors, "Set default foreground and background colors.\n\n(ghostel--set-default-colors TERM FG-HEX BG-HEX)");
4546
env.bindFunction("ghostel--mode-enabled", 2, 2, &fnModeEnabled, "Return t if terminal DEC private MODE is enabled.\n\n(ghostel--mode-enabled TERM MODE)");
4647
env.bindFunction("ghostel--debug-state", 1, 1, &fnDebugState, "Return debug info about terminal/render state.\n\n(ghostel--debug-state TERM)");
4748
env.bindFunction("ghostel--debug-feed", 2, 2, &fnDebugFeed, "Feed STR to terminal and return first row + cursor.\n\n(ghostel--debug-feed TERM STR)");
@@ -559,6 +560,55 @@ fn hexDigit(ch: u8) ?u8 {
559560
return null;
560561
}
561562

563+
/// Parse a "#RRGGBB" hex color string into a ColorRgb.
564+
fn parseHexColor(s: []const u8) ?gt.ColorRgb {
565+
if (s.len < 7 or s[0] != '#') return null;
566+
const r = parseHexByte(s[1], s[2]) orelse return null;
567+
const g = parseHexByte(s[3], s[4]) orelse return null;
568+
const b = parseHexByte(s[5], s[6]) orelse return null;
569+
return .{ .r = r, .g = g, .b = b };
570+
}
571+
572+
/// (ghostel--set-default-colors TERM FG-HEX BG-HEX)
573+
/// Set the terminal's default foreground and background colors from "#RRGGBB" strings.
574+
fn fnSetDefaultColors(raw_env: ?*c.emacs_env, _: isize, args: [*c]c.emacs_value, _: ?*anyopaque) callconv(.c) c.emacs_value {
575+
const env = emacs.Env.init(raw_env.?);
576+
const term = env.getUserPtr(Terminal, args[0]) orelse {
577+
env.signalError("ghostel: invalid terminal handle");
578+
return env.nil();
579+
};
580+
581+
var fg_buf: [16]u8 = undefined;
582+
var bg_buf: [16]u8 = undefined;
583+
const fg_str = env.extractString(args[1], &fg_buf) orelse {
584+
env.signalError("ghostel: invalid foreground color");
585+
return env.nil();
586+
};
587+
const bg_str = env.extractString(args[2], &bg_buf) orelse {
588+
env.signalError("ghostel: invalid background color");
589+
return env.nil();
590+
};
591+
592+
const fg = parseHexColor(fg_str) orelse {
593+
env.signalError("ghostel: cannot parse foreground color");
594+
return env.nil();
595+
};
596+
const bg = parseHexColor(bg_str) orelse {
597+
env.signalError("ghostel: cannot parse background color");
598+
return env.nil();
599+
};
600+
601+
term.setColorForeground(&fg) catch {
602+
env.signalError("ghostel: failed to set foreground color");
603+
return env.nil();
604+
};
605+
term.setColorBackground(&bg) catch {
606+
env.signalError("ghostel: failed to set background color");
607+
return env.nil();
608+
};
609+
return env.t();
610+
}
611+
562612
/// (ghostel--debug-state TERM)
563613
/// Returns a string with render state debug info.
564614
fn fnDebugState(raw_env: ?*c.emacs_env, _: isize, args: [*c]c.emacs_value, _: ?*anyopaque) callconv(.c) c.emacs_value {

test/ghostel-test.el

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,36 @@ cell, so the visual line width must equal the terminal column count."
923923
(kill-buffer buf)
924924
(kill-buffer other))))))
925925

926+
;; -----------------------------------------------------------------------
927+
;; Test: apply-palette sets default fg/bg from Emacs default face
928+
;; -----------------------------------------------------------------------
929+
930+
(ert-deftest ghostel-test-apply-palette-default-colors ()
931+
"Test that ghostel--apply-palette sets default fg/bg from the Emacs default face."
932+
(let ((default-colors-calls nil)
933+
(palette-calls nil))
934+
(cl-letf (((symbol-function 'ghostel--set-default-colors)
935+
(lambda (term fg bg)
936+
(push (list term fg bg) default-colors-calls)))
937+
((symbol-function 'ghostel--set-palette)
938+
(lambda (term colors) (push (list term colors) palette-calls))))
939+
;; With a fake terminal, apply-palette should call set-default-colors
940+
(ghostel--apply-palette 'fake-term)
941+
(should (= 1 (length default-colors-calls)))
942+
(should (eq 'fake-term (car (car default-colors-calls))))
943+
;; fg and bg should be hex color strings from the default face
944+
(let ((fg (nth 1 (car default-colors-calls)))
945+
(bg (nth 2 (car default-colors-calls))))
946+
(should (string-prefix-p "#" fg))
947+
(should (string-prefix-p "#" bg)))
948+
;; Palette should also be set
949+
(should (= 1 (length palette-calls)))
950+
;; With nil term, nothing should be called
951+
(setq default-colors-calls nil palette-calls nil)
952+
(ghostel--apply-palette nil)
953+
(should-not default-colors-calls)
954+
(should-not palette-calls))))
955+
926956
;; -----------------------------------------------------------------------
927957
;; OSC 51 elisp eval
928958
;; -----------------------------------------------------------------------
@@ -1066,6 +1096,7 @@ cell, so the visual line width must equal the terminal column count."
10661096
ghostel-test-filter-soft-wraps
10671097
ghostel-test-prompt-navigation
10681098
ghostel-test-sync-theme
1099+
ghostel-test-apply-palette-default-colors
10691100
ghostel-test-osc51-eval
10701101
ghostel-test-osc51-eval-unknown
10711102
ghostel-test-copy-mode-cursor

0 commit comments

Comments
 (0)