vt: expose cursor_style via terminal_get

Add cursor_style to TerminalData, returning the current SGR style
of the cursor (the style applied to newly printed characters) as a
GhosttyStyle.

Refactor the C style conversion helpers: replace the standalone
convertStyle and convertColor functions with fromStyle and fromColor
initializers on the Style and Color extern structs respectively.
This commit is contained in:
Mitchell Hashimoto
2026-03-19 12:04:56 -07:00
parent 7f36e8bd43
commit d62f6df1d5
3 changed files with 50 additions and 36 deletions

View File

@@ -13,6 +13,7 @@
#include <ghostty/vt/types.h>
#include <ghostty/vt/allocator.h>
#include <ghostty/vt/modes.h>
#include <ghostty/vt/style.h>
#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;
/**

View File

@@ -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);

View File

@@ -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;