mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
fix(renderer): make all decorations and combining marks visible under cursor
Metal needed to be changed to account for wide chars having decorations on the right half and OpenGL needed to account for multiple glyphs being under the cursor at once (decorations and combining marks) as well as wide chars.
This commit is contained in:
@ -631,6 +631,7 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
|
|||||||
.min_contrast = options.config.min_contrast,
|
.min_contrast = options.config.min_contrast,
|
||||||
.cursor_pos = .{ std.math.maxInt(u16), std.math.maxInt(u16) },
|
.cursor_pos = .{ std.math.maxInt(u16), std.math.maxInt(u16) },
|
||||||
.cursor_color = undefined,
|
.cursor_color = undefined,
|
||||||
|
.wide_cursor = false,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Fonts
|
// Fonts
|
||||||
@ -2034,6 +2035,7 @@ pub fn setScreenSize(
|
|||||||
.min_contrast = old.min_contrast,
|
.min_contrast = old.min_contrast,
|
||||||
.cursor_pos = old.cursor_pos,
|
.cursor_pos = old.cursor_pos,
|
||||||
.cursor_color = old.cursor_color,
|
.cursor_color = old.cursor_color,
|
||||||
|
.wide_cursor = old.wide_cursor,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reset our cell contents if our grid size has changed.
|
// Reset our cell contents if our grid size has changed.
|
||||||
@ -2353,10 +2355,19 @@ fn rebuildCells(
|
|||||||
|
|
||||||
// If the cursor is visible then we set our uniforms.
|
// If the cursor is visible then we set our uniforms.
|
||||||
if (style == .block and screen.viewportIsBottom()) {
|
if (style == .block and screen.viewportIsBottom()) {
|
||||||
|
const wide = screen.cursor.page_cell.wide;
|
||||||
|
|
||||||
self.uniforms.cursor_pos = .{
|
self.uniforms.cursor_pos = .{
|
||||||
screen.cursor.x,
|
switch (wide) {
|
||||||
|
.narrow, .spacer_head, .wide => screen.cursor.x,
|
||||||
|
.spacer_tail => screen.cursor.x -| 1,
|
||||||
|
},
|
||||||
screen.cursor.y,
|
screen.cursor.y,
|
||||||
};
|
};
|
||||||
|
self.uniforms.wide_cursor = switch (wide) {
|
||||||
|
.narrow, .spacer_head => false,
|
||||||
|
.wide, .spacer_tail => true,
|
||||||
|
};
|
||||||
|
|
||||||
const uniform_color = if (self.cursor_invert) blk: {
|
const uniform_color = if (self.cursor_invert) blk: {
|
||||||
const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
|
const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
|
||||||
|
@ -1227,10 +1227,15 @@ pub fn rebuildCells(
|
|||||||
};
|
};
|
||||||
} else null;
|
} else null;
|
||||||
|
|
||||||
// This is the cell that has [mode == .fg] and is underneath our cursor.
|
// These are all the foreground cells underneath the cursor.
|
||||||
// We keep track of it so that we can invert the colors so the character
|
//
|
||||||
// remains visible.
|
// We keep track of these so that we can invert the colors and move them
|
||||||
var cursor_cell: ?CellProgram.Cell = null;
|
// in front of the block cursor so that the character remains visible.
|
||||||
|
//
|
||||||
|
// We init with a capacity of 4 to account for decorations such
|
||||||
|
// as underline and strikethrough, as well as combining chars.
|
||||||
|
var cursor_cells = try std.ArrayListUnmanaged(CellProgram.Cell).initCapacity(arena_alloc, 4);
|
||||||
|
defer cursor_cells.deinit(arena_alloc);
|
||||||
|
|
||||||
if (rebuild) {
|
if (rebuild) {
|
||||||
switch (self.config.padding_color) {
|
switch (self.config.padding_color) {
|
||||||
@ -1277,14 +1282,24 @@ pub fn rebuildCells(
|
|||||||
// the cell with the cursor.
|
// the cell with the cursor.
|
||||||
const start_i: usize = self.cells.items.len;
|
const start_i: usize = self.cells.items.len;
|
||||||
defer if (cursor_row) {
|
defer if (cursor_row) {
|
||||||
// If we're on a wide spacer tail, then we want to look for
|
const x = screen.cursor.x;
|
||||||
// the previous cell.
|
const wide = row.cells(.all)[x].wide;
|
||||||
const screen_cell = row.cells(.all)[screen.cursor.x];
|
const min_x = switch (wide) {
|
||||||
const x = screen.cursor.x - @intFromBool(screen_cell.wide == .spacer_tail);
|
.narrow, .spacer_head, .wide => x,
|
||||||
|
.spacer_tail => x -| 1,
|
||||||
|
};
|
||||||
|
const max_x = switch (wide) {
|
||||||
|
.narrow, .spacer_head, .spacer_tail => x,
|
||||||
|
.wide => x +| 1,
|
||||||
|
};
|
||||||
for (self.cells.items[start_i..]) |cell| {
|
for (self.cells.items[start_i..]) |cell| {
|
||||||
if (cell.grid_col == x and cell.mode.isFg()) {
|
if (cell.grid_col < min_x or cell.grid_col > max_x) continue;
|
||||||
cursor_cell = cell;
|
if (cell.mode.isFg()) {
|
||||||
break;
|
cursor_cells.append(arena_alloc, cell) catch {
|
||||||
|
// We silently ignore if this fails because
|
||||||
|
// worst case scenario some combining glyphs
|
||||||
|
// aren't visible under the cursor '\_('-')_/'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1422,7 +1437,7 @@ pub fn rebuildCells(
|
|||||||
};
|
};
|
||||||
|
|
||||||
_ = try self.addCursor(screen, cursor_style, cursor_color);
|
_ = try self.addCursor(screen, cursor_style, cursor_color);
|
||||||
if (cursor_cell) |*cell| {
|
for (cursor_cells.items) |*cell| {
|
||||||
if (cell.mode.isFg() and cell.mode != .fg_color) {
|
if (cell.mode.isFg() and cell.mode != .fg_color) {
|
||||||
const cell_color = if (self.cursor_invert) blk: {
|
const cell_color = if (self.cursor_invert) blk: {
|
||||||
const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
|
const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
|
||||||
|
@ -137,6 +137,9 @@ pub const Uniforms = extern struct {
|
|||||||
cursor_pos: [2]u16 align(4),
|
cursor_pos: [2]u16 align(4),
|
||||||
cursor_color: [4]u8 align(4),
|
cursor_color: [4]u8 align(4),
|
||||||
|
|
||||||
|
// Whether the cursor is 2 cells wide.
|
||||||
|
wide_cursor: bool align(1),
|
||||||
|
|
||||||
const PaddingExtend = packed struct(u8) {
|
const PaddingExtend = packed struct(u8) {
|
||||||
left: bool = false,
|
left: bool = false,
|
||||||
right: bool = false,
|
right: bool = false,
|
||||||
|
@ -18,6 +18,7 @@ struct Uniforms {
|
|||||||
float min_contrast;
|
float min_contrast;
|
||||||
ushort2 cursor_pos;
|
ushort2 cursor_pos;
|
||||||
uchar4 cursor_color;
|
uchar4 cursor_color;
|
||||||
|
bool wide_cursor;
|
||||||
};
|
};
|
||||||
|
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
@ -293,7 +294,11 @@ vertex CellTextVertexOut cell_text_vertex(
|
|||||||
// If this cell is the cursor cell, then we need to change the color.
|
// If this cell is the cursor cell, then we need to change the color.
|
||||||
if (
|
if (
|
||||||
in.mode != MODE_TEXT_CURSOR &&
|
in.mode != MODE_TEXT_CURSOR &&
|
||||||
in.grid_pos.x == uniforms.cursor_pos.x &&
|
(
|
||||||
|
in.grid_pos.x == uniforms.cursor_pos.x ||
|
||||||
|
uniforms.wide_cursor &&
|
||||||
|
in.grid_pos.x == uniforms.cursor_pos.x + 1
|
||||||
|
) &&
|
||||||
in.grid_pos.y == uniforms.cursor_pos.y
|
in.grid_pos.y == uniforms.cursor_pos.y
|
||||||
) {
|
) {
|
||||||
out.color = float4(uniforms.cursor_color) / 255.0f;
|
out.color = float4(uniforms.cursor_color) / 255.0f;
|
||||||
|
Reference in New Issue
Block a user