diff --git a/include/ghostty/vt/terminal.h b/include/ghostty/vt/terminal.h index 88fac14ef..8ebd4e7dd 100644 --- a/include/ghostty/vt/terminal.h +++ b/include/ghostty/vt/terminal.h @@ -13,6 +13,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -208,6 +209,15 @@ typedef enum { * Output type: GhosttyTerminalScrollbar * */ GHOSTTY_TERMINAL_DATA_SCROLLBAR = 9, + + /** + * The current SGR style of the cursor. + * + * This is the style that will be applied to newly printed characters. + * + * Output type: GhosttyStyle * + */ + GHOSTTY_TERMINAL_DATA_CURSOR_STYLE = 10, } GhosttyTerminalData; /** diff --git a/src/terminal/c/style.zig b/src/terminal/c/style.zig index 01f079ccc..5538c42cc 100644 --- a/src/terminal/c/style.zig +++ b/src/terminal/c/style.zig @@ -23,6 +23,23 @@ pub const ColorValue = extern union { pub const Color = extern struct { tag: ColorTag, value: ColorValue, + + pub fn fromColor(c: style.Style.Color) Color { + return switch (c) { + .none => .{ + .tag = .none, + .value = .{ ._padding = 0 }, + }, + .palette => |idx| .{ + .tag = .palette, + .value = .{ .palette = idx }, + }, + .rgb => |rgb| .{ + .tag = .rgb, + .value = .{ .rgb = rgb.cval() }, + }, + }; + } }; /// C: GhosttyStyle @@ -40,45 +57,28 @@ pub const Style = extern struct { strikethrough: bool, overline: bool, underline: c_int, + + pub fn fromStyle(s: style.Style) Style { + return .{ + .fg_color = .fromColor(s.fg_color), + .bg_color = .fromColor(s.bg_color), + .underline_color = .fromColor(s.underline_color), + .bold = s.flags.bold, + .italic = s.flags.italic, + .faint = s.flags.faint, + .blink = s.flags.blink, + .inverse = s.flags.inverse, + .invisible = s.flags.invisible, + .strikethrough = s.flags.strikethrough, + .overline = s.flags.overline, + .underline = @intFromEnum(s.flags.underline), + }; + } }; -fn convertColor(c: style.Style.Color) Color { - return switch (c) { - .none => .{ - .tag = .none, - .value = .{ ._padding = 0 }, - }, - .palette => |idx| .{ - .tag = .palette, - .value = .{ .palette = idx }, - }, - .rgb => |rgb| .{ - .tag = .rgb, - .value = .{ .rgb = rgb.cval() }, - }, - }; -} - -pub fn convertStyle(s: style.Style) Style { - return .{ - .fg_color = convertColor(s.fg_color), - .bg_color = convertColor(s.bg_color), - .underline_color = convertColor(s.underline_color), - .bold = s.flags.bold, - .italic = s.flags.italic, - .faint = s.flags.faint, - .blink = s.flags.blink, - .inverse = s.flags.inverse, - .invisible = s.flags.invisible, - .strikethrough = s.flags.strikethrough, - .overline = s.flags.overline, - .underline = @intFromEnum(s.flags.underline), - }; -} - /// Returns the default style. pub fn default_style(result: *Style) callconv(.c) void { - result.* = convertStyle(.{}); + result.* = .fromStyle(.{}); assert(result.size == @sizeOf(Style)); } @@ -119,7 +119,7 @@ test "convert style with colors" { .flags = .{ .bold = true, .underline = .curly }, }; - const c_style = convertStyle(zig_style); + const c_style: Style = .fromStyle(zig_style); try testing.expectEqual(ColorTag.palette, c_style.fg_color.tag); try testing.expectEqual(@as(u8, 42), c_style.fg_color.value.palette); try testing.expectEqual(ColorTag.rgb, c_style.bg_color.tag); diff --git a/src/terminal/c/terminal.zig b/src/terminal/c/terminal.zig index 3c771f16e..1d31d5ae2 100644 --- a/src/terminal/c/terminal.zig +++ b/src/terminal/c/terminal.zig @@ -8,6 +8,7 @@ const PageList = @import("../PageList.zig"); const kitty = @import("../kitty/key.zig"); const modes = @import("../modes.zig"); const size = @import("../size.zig"); +const style_c = @import("style.zig"); const Result = @import("result.zig").Result; const log = std.log.scoped(.terminal_c); @@ -146,6 +147,7 @@ pub const TerminalData = enum(c_int) { cursor_visible = 7, kitty_keyboard_flags = 8, scrollbar = 9, + cursor_style = 10, /// Output type expected for querying the data of the given kind. pub fn OutType(comptime self: TerminalData) type { @@ -156,6 +158,7 @@ pub const TerminalData = enum(c_int) { .active_screen => TerminalScreen, .kitty_keyboard_flags => u8, .scrollbar => TerminalScrollbar, + .cursor_style => style_c.Style, }; } }; @@ -198,6 +201,7 @@ fn getTyped( .cursor_visible => out.* = t.modes.get(.cursor_visible), .kitty_keyboard_flags => out.* = @as(u8, t.screens.active.kitty_keyboard.current().int()), .scrollbar => out.* = t.screens.active.pages.scrollbar().cval(), + .cursor_style => out.* = .fromStyle(t.screens.active.cursor.style), } return .success;