From de3e77570e479033853733736a025ae05100f6bd Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 4 Jul 2025 18:26:27 -0400 Subject: [PATCH 1/4] add second cursor list --- src/renderer/cell.zig | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/renderer/cell.zig b/src/renderer/cell.zig index ef7122699..3e5ae92c0 100644 --- a/src/renderer/cell.zig +++ b/src/renderer/cell.zig @@ -103,11 +103,12 @@ pub const Contents = struct { // form a single grapheme, and multi-substitutions in fonts, the number // of glyphs in a row is theoretically unlimited. // - // We have size.rows + 1 lists because index 0 is used for a special - // list containing the cursor cell which needs to be first in the buffer. + // We have size.rows + 2 lists because indexes 0 and size.rows - 1 are + // used for special lists containing the cursor cell which need to + // be first and last in the buffer, respectively. var fg_rows = try ArrayListCollection(shaderpkg.CellText).init( alloc, - size.rows + 1, + size.rows + 2, size.columns * 3, ); errdefer fg_rows.deinit(alloc); @@ -118,14 +119,19 @@ pub const Contents = struct { self.bg_cells = bg_cells; self.fg_rows = fg_rows; - // We don't need 3*cols worth of cells for the cursor list, so we can - // replace it with a smaller list. This is technically a tiny bit of + // We don't need 3*cols worth of cells for the cursor lists, so we can + // replace them with smaller lists. This is technically a tiny bit of // extra work but resize is not a hot function so it's worth it to not // waste the memory. self.fg_rows.lists[0].deinit(alloc); self.fg_rows.lists[0] = try std.ArrayListUnmanaged( shaderpkg.CellText, ).initCapacity(alloc, 1); + + self.fg_rows.lists[size.rows + 1].deinit(alloc); + self.fg_rows.lists[size.rows + 1] = try std.ArrayListUnmanaged( + shaderpkg.CellText, + ).initCapacity(alloc, 1); } /// Reset the cell contents to an empty state without resizing. @@ -137,6 +143,7 @@ pub const Contents = struct { /// Set the cursor value. If the value is null then the cursor is hidden. pub fn setCursor(self: *Contents, v: ?shaderpkg.CellText) void { self.fg_rows.lists[0].clearRetainingCapacity(); + self.fg_rows.lists[self.size.rows + 1].clearRetainingCapacity(); if (v) |cell| { self.fg_rows.lists[0].appendAssumeCapacity(cell); From a9fc3b6fa0f862f00825664c44e6dcd8305e2141 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 4 Jul 2025 18:50:23 -0400 Subject: [PATCH 2/4] enable drawing cursor on top or bottom based on style --- src/renderer/cell.zig | 17 ++++++++++++----- src/renderer/generic.zig | 4 ++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/renderer/cell.zig b/src/renderer/cell.zig index 3e5ae92c0..821ac1c7c 100644 --- a/src/renderer/cell.zig +++ b/src/renderer/cell.zig @@ -141,12 +141,19 @@ pub const Contents = struct { } /// Set the cursor value. If the value is null then the cursor is hidden. - pub fn setCursor(self: *Contents, v: ?shaderpkg.CellText) void { + pub fn setCursor(self: *Contents, v: ?shaderpkg.CellText, cursor_style: ?renderer.CursorStyle) void { self.fg_rows.lists[0].clearRetainingCapacity(); self.fg_rows.lists[self.size.rows + 1].clearRetainingCapacity(); if (v) |cell| { - self.fg_rows.lists[0].appendAssumeCapacity(cell); + if (cursor_style) |style| { + switch (style) { + // Block cursors should be drawn first + .block => self.fg_rows.lists[0].appendAssumeCapacity(cell), + // Other cursor styles should be drawn last + .block_hollow, .bar, .underline, .lock => self.fg_rows.lists[self.size.rows + 1].appendAssumeCapacity(cell), + } + } } } @@ -374,17 +381,17 @@ test Contents { } } - // Add a cursor. + // Add a block cursor. const cursor_cell: shaderpkg.CellText = .{ .mode = .cursor, .grid_pos = .{ 2, 3 }, .color = .{ 0, 0, 0, 1 }, }; - c.setCursor(cursor_cell); + c.setCursor(cursor_cell, .block); try testing.expectEqual(cursor_cell, c.fg_rows.lists[0].items[0]); // And remove it. - c.setCursor(null); + c.setCursor(null, null); try testing.expectEqual(0, c.fg_rows.lists[0].items.len); } diff --git a/src/renderer/generic.zig b/src/renderer/generic.zig index e7faf633f..3a65b9ac5 100644 --- a/src/renderer/generic.zig +++ b/src/renderer/generic.zig @@ -2791,7 +2791,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type { // Setup our cursor rendering information. cursor: { // By default, we don't handle cursor inversion on the shader. - self.cells.setCursor(null); + self.cells.setCursor(null, null); self.uniforms.cursor_pos = .{ std.math.maxInt(u16), std.math.maxInt(u16), @@ -3162,7 +3162,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type { @intCast(render.glyph.offset_x), @intCast(render.glyph.offset_y), }, - }); + }, cursor_style); } fn addPreeditCell( From 0b4a1e21540b8368507bd0f4e0ef2eb328ce670a Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 4 Jul 2025 18:54:55 -0400 Subject: [PATCH 3/4] added test for other cursor style --- src/renderer/cell.zig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/renderer/cell.zig b/src/renderer/cell.zig index 821ac1c7c..083adee40 100644 --- a/src/renderer/cell.zig +++ b/src/renderer/cell.zig @@ -393,6 +393,10 @@ test Contents { // And remove it. c.setCursor(null, null); try testing.expectEqual(0, c.fg_rows.lists[0].items.len); + + // Add a hollow cursor. + c.setCursor(cursor_cell, .block_hollow); + try testing.expectEqual(cursor_cell, c.fg_rows.lists[rows + 1].items[0]); } test "Contents clear retains other content" { From 1a4b128af336d497deab540ec976db7f7926064e Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 4 Jul 2025 21:36:17 -0400 Subject: [PATCH 4/4] replace nested if for readability --- src/renderer/cell.zig | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/renderer/cell.zig b/src/renderer/cell.zig index 083adee40..97b24aa90 100644 --- a/src/renderer/cell.zig +++ b/src/renderer/cell.zig @@ -145,15 +145,14 @@ pub const Contents = struct { self.fg_rows.lists[0].clearRetainingCapacity(); self.fg_rows.lists[self.size.rows + 1].clearRetainingCapacity(); - if (v) |cell| { - if (cursor_style) |style| { - switch (style) { - // Block cursors should be drawn first - .block => self.fg_rows.lists[0].appendAssumeCapacity(cell), - // Other cursor styles should be drawn last - .block_hollow, .bar, .underline, .lock => self.fg_rows.lists[self.size.rows + 1].appendAssumeCapacity(cell), - } - } + const cell = v orelse return; + const style = cursor_style orelse return; + + switch (style) { + // Block cursors should be drawn first + .block => self.fg_rows.lists[0].appendAssumeCapacity(cell), + // Other cursor styles should be drawn last + .block_hollow, .bar, .underline, .lock => self.fg_rows.lists[self.size.rows + 1].appendAssumeCapacity(cell), } }