mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
fix: draw cursor on top of text for most cursor styles (#7810)
This addresses #7739. ## Changes * Added second cursor list to the renderer as suggested * Modified `Contents.setCursor` to accept a cursor style argument in order to conditionally render the cursor * Not sure if this the optimal workaround so suggestions would be appreciated ## Screenshots Block:  Hollow block: 
This commit is contained in:
@ -103,11 +103,12 @@ pub const Contents = struct {
|
|||||||
// form a single grapheme, and multi-substitutions in fonts, the number
|
// form a single grapheme, and multi-substitutions in fonts, the number
|
||||||
// of glyphs in a row is theoretically unlimited.
|
// of glyphs in a row is theoretically unlimited.
|
||||||
//
|
//
|
||||||
// We have size.rows + 1 lists because index 0 is used for a special
|
// We have size.rows + 2 lists because indexes 0 and size.rows - 1 are
|
||||||
// list containing the cursor cell which needs to be first in the buffer.
|
// 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(
|
var fg_rows = try ArrayListCollection(shaderpkg.CellText).init(
|
||||||
alloc,
|
alloc,
|
||||||
size.rows + 1,
|
size.rows + 2,
|
||||||
size.columns * 3,
|
size.columns * 3,
|
||||||
);
|
);
|
||||||
errdefer fg_rows.deinit(alloc);
|
errdefer fg_rows.deinit(alloc);
|
||||||
@ -118,14 +119,19 @@ pub const Contents = struct {
|
|||||||
self.bg_cells = bg_cells;
|
self.bg_cells = bg_cells;
|
||||||
self.fg_rows = fg_rows;
|
self.fg_rows = fg_rows;
|
||||||
|
|
||||||
// We don't need 3*cols worth of cells for the cursor list, so we can
|
// We don't need 3*cols worth of cells for the cursor lists, so we can
|
||||||
// replace it with a smaller list. This is technically a tiny bit of
|
// 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
|
// extra work but resize is not a hot function so it's worth it to not
|
||||||
// waste the memory.
|
// waste the memory.
|
||||||
self.fg_rows.lists[0].deinit(alloc);
|
self.fg_rows.lists[0].deinit(alloc);
|
||||||
self.fg_rows.lists[0] = try std.ArrayListUnmanaged(
|
self.fg_rows.lists[0] = try std.ArrayListUnmanaged(
|
||||||
shaderpkg.CellText,
|
shaderpkg.CellText,
|
||||||
).initCapacity(alloc, 1);
|
).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.
|
/// Reset the cell contents to an empty state without resizing.
|
||||||
@ -135,11 +141,18 @@ pub const Contents = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set the cursor value. If the value is null then the cursor is hidden.
|
/// 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[0].clearRetainingCapacity();
|
||||||
|
self.fg_rows.lists[self.size.rows + 1].clearRetainingCapacity();
|
||||||
|
|
||||||
if (v) |cell| {
|
const cell = v orelse return;
|
||||||
self.fg_rows.lists[0].appendAssumeCapacity(cell);
|
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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,18 +380,22 @@ test Contents {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a cursor.
|
// Add a block cursor.
|
||||||
const cursor_cell: shaderpkg.CellText = .{
|
const cursor_cell: shaderpkg.CellText = .{
|
||||||
.mode = .cursor,
|
.mode = .cursor,
|
||||||
.grid_pos = .{ 2, 3 },
|
.grid_pos = .{ 2, 3 },
|
||||||
.color = .{ 0, 0, 0, 1 },
|
.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]);
|
try testing.expectEqual(cursor_cell, c.fg_rows.lists[0].items[0]);
|
||||||
|
|
||||||
// And remove it.
|
// And remove it.
|
||||||
c.setCursor(null);
|
c.setCursor(null, null);
|
||||||
try testing.expectEqual(0, c.fg_rows.lists[0].items.len);
|
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" {
|
test "Contents clear retains other content" {
|
||||||
|
@ -2791,7 +2791,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
|||||||
// Setup our cursor rendering information.
|
// Setup our cursor rendering information.
|
||||||
cursor: {
|
cursor: {
|
||||||
// By default, we don't handle cursor inversion on the shader.
|
// By default, we don't handle cursor inversion on the shader.
|
||||||
self.cells.setCursor(null);
|
self.cells.setCursor(null, null);
|
||||||
self.uniforms.cursor_pos = .{
|
self.uniforms.cursor_pos = .{
|
||||||
std.math.maxInt(u16),
|
std.math.maxInt(u16),
|
||||||
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_x),
|
||||||
@intCast(render.glyph.offset_y),
|
@intCast(render.glyph.offset_y),
|
||||||
},
|
},
|
||||||
});
|
}, cursor_style);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addPreeditCell(
|
fn addPreeditCell(
|
||||||
|
Reference in New Issue
Block a user