feat(terminal/cursor): add support for cursor shape configuration
Some checks failed
Zig Project Action / Lint, Spell-check and test zig project (push) Failing after 1m5s

This commit is contained in:
2025-11-20 18:46:58 +01:00
parent 424740d350
commit 9488d0b64d
6 changed files with 22 additions and 5 deletions

View File

@@ -93,7 +93,7 @@ pub fn App(comptime M: type, comptime E: type) type {
if (this.termios) |termios| { if (this.termios) |termios| {
try terminal.disableMouseSupport(); try terminal.disableMouseSupport();
try terminal.showCursor(); try terminal.showCursor();
try terminal.resetCursorColor(); try terminal.resetCursor();
try terminal.restoreScreen(); try terminal.restoreScreen();
try terminal.disableRawMode(&termios); try terminal.disableRawMode(&termios);
try terminal.exitAltScreen(); try terminal.exitAltScreen();
@@ -427,7 +427,7 @@ pub fn App(comptime M: type, comptime E: type) type {
pub fn panic_handler(msg: []const u8, _: ?*std.builtin.StackTrace, ret_addr: ?usize) noreturn { pub fn panic_handler(msg: []const u8, _: ?*std.builtin.StackTrace, ret_addr: ?usize) noreturn {
terminal.disableMouseSupport() catch {}; terminal.disableMouseSupport() catch {};
terminal.showCursor() catch {}; terminal.showCursor() catch {};
terminal.resetCursorColor() catch {}; terminal.resetCursor() catch {};
terminal.restoreScreen() catch {}; terminal.restoreScreen() catch {};
terminal.disableRawMode(&.{ terminal.disableRawMode(&.{
.iflag = .{}, .iflag = .{},

View File

@@ -50,6 +50,7 @@ pub const home = "\x1b[H";
pub const cup = "\x1b[{d};{d}H"; pub const cup = "\x1b[{d};{d}H";
pub const hide_cursor = "\x1b[?25l"; pub const hide_cursor = "\x1b[?25l";
pub const show_cursor = "\x1b[?25h"; pub const show_cursor = "\x1b[?25h";
pub const reset_cursor_shape = "\x1b[0 q";
pub const cursor_shape = "\x1b[{d} q"; pub const cursor_shape = "\x1b[{d} q";
pub const ri = "\x1bM"; pub const ri = "\x1bM";
pub const ind = "\n"; pub const ind = "\n";

View File

@@ -687,9 +687,11 @@ pub fn Input(Model: type, Event: type, Queue: type) fn (meta.FieldEnum(Event)) t
if (this.input.items.len < cells.len) { if (this.input.items.len < cells.len) {
cells[this.input.items.len - this.cursor_offset].style.cursor = true; cells[this.input.items.len - this.cursor_offset].style.cursor = true;
cells[this.input.items.len - this.cursor_offset].style.cursor_color = this.configuration.cursor; cells[this.input.items.len - this.cursor_offset].style.cursor_color = this.configuration.cursor;
cells[this.input.items.len - this.cursor_offset].style.cursor_shape = .bar_blinking;
} else { } else {
cells[this.input.items.len - offset - this.cursor_offset].style.cursor = true; cells[this.input.items.len - offset - this.cursor_offset].style.cursor = true;
cells[this.input.items.len - offset - this.cursor_offset].style.cursor_color = this.configuration.cursor; cells[this.input.items.len - offset - this.cursor_offset].style.cursor_color = this.configuration.cursor;
cells[this.input.items.len - offset - this.cursor_offset].style.cursor_shape = .bar_blinking;
} }
} }
}; };

View File

@@ -104,7 +104,7 @@ pub const Buffered = struct {
.x = @truncate(col), .x = @truncate(col),
.y = @truncate(row), .y = @truncate(row),
}; };
try cvs.style.set_cursor_color(&writer); try cvs.style.set_cursor_style(&writer);
} }
if (cs.eql(cvs)) continue; if (cs.eql(cvs)) continue;

View File

@@ -13,6 +13,7 @@ bg: Color = .default,
ul: Color = .default, ul: Color = .default,
cursor: bool = false, cursor: bool = false,
cursor_color: Color = .default, cursor_color: Color = .default,
cursor_shape: CursorShape = .default,
ul_style: Underline = .off, ul_style: Underline = .off,
emphasis: []const Emphasis, emphasis: []const Emphasis,
@@ -37,16 +38,28 @@ pub const Emphasis = enum(u8) {
strikethrough, strikethrough,
}; };
pub const CursorShape = enum(u4) {
default = 0,
block_blinking = 1,
block_steady,
underline_blinking,
underline_steady,
bar_blinking,
bar_steady,
};
pub fn eql(this: Style, other: Style) bool { pub fn eql(this: Style, other: Style) bool {
// TODO should there be a compare for every field?
return meta.eql(this, other); return meta.eql(this, other);
} }
pub fn set_cursor_color(this: Style, writer: *std.Io.Writer) !void { pub fn set_cursor_style(this: Style, writer: *std.Io.Writer) !void {
if (!this.cursor) return; if (!this.cursor) return;
switch (this.cursor_color) { switch (this.cursor_color) {
.default => try writer.print(ctlseqs.osc12_reset, .{}), .default => try writer.print(ctlseqs.osc12_reset, .{}),
else => try writer.print(ctlseqs.osc12_set, .{@tagName(this.cursor_color)}), else => try writer.print(ctlseqs.osc12_set, .{@tagName(this.cursor_color)}),
} }
try writer.print(ctlseqs.cursor_shape, .{@intFromEnum(this.cursor_shape)});
} }
pub fn value(this: Style, writer: *std.Io.Writer, cp: u21) !void { pub fn value(this: Style, writer: *std.Io.Writer, cp: u21) !void {

View File

@@ -42,7 +42,8 @@ pub fn showCursor() !void {
_ = try posix.write(posix.STDIN_FILENO, ctlseqs.show_cursor); _ = try posix.write(posix.STDIN_FILENO, ctlseqs.show_cursor);
} }
pub fn resetCursorColor() !void { pub fn resetCursor() !void {
_ = try posix.write(posix.STDIN_FILENO, ctlseqs.reset_cursor_shape);
_ = try posix.write(posix.STDIN_FILENO, ctlseqs.osc12_reset); _ = try posix.write(posix.STDIN_FILENO, ctlseqs.osc12_reset);
} }