mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
implement overline decoration (SGR 53/55)
This commit is contained in:

committed by
Mitchell Hashimoto

parent
1134a9cbea
commit
4496e7d314
@ -27,6 +27,8 @@ pub const Sprite = enum(u32) {
|
||||
|
||||
strikethrough,
|
||||
|
||||
overline,
|
||||
|
||||
cursor_rect,
|
||||
cursor_hollow_rect,
|
||||
cursor_bar,
|
||||
|
@ -150,6 +150,16 @@ pub fn renderGlyph(
|
||||
self.thickness,
|
||||
),
|
||||
|
||||
.overline => try underline.renderGlyph(
|
||||
alloc,
|
||||
atlas,
|
||||
@enumFromInt(cp),
|
||||
width,
|
||||
self.height,
|
||||
0,
|
||||
self.thickness,
|
||||
),
|
||||
|
||||
.powerline => powerline: {
|
||||
const f: Powerline = .{
|
||||
.width = width,
|
||||
@ -166,6 +176,7 @@ pub fn renderGlyph(
|
||||
const Kind = enum {
|
||||
box,
|
||||
underline,
|
||||
overline,
|
||||
strikethrough,
|
||||
powerline,
|
||||
|
||||
@ -179,6 +190,9 @@ const Kind = enum {
|
||||
.underline_curly,
|
||||
=> .underline,
|
||||
|
||||
.overline,
|
||||
=> .overline,
|
||||
|
||||
.strikethrough,
|
||||
=> .strikethrough,
|
||||
|
||||
|
@ -34,6 +34,7 @@ pub fn renderGlyph(
|
||||
.underline_dotted => try drawDotted(alloc, width, line_thickness),
|
||||
.underline_dashed => try drawDashed(alloc, width, line_thickness),
|
||||
.underline_curly => try drawCurly(alloc, width, line_thickness),
|
||||
.overline => try drawSingle(alloc, width, line_thickness),
|
||||
.strikethrough => try drawSingle(alloc, width, line_thickness),
|
||||
else => unreachable,
|
||||
};
|
||||
|
@ -2492,6 +2492,18 @@ fn rebuildCells(
|
||||
);
|
||||
};
|
||||
|
||||
if (style.flags.overline) self.addOverline(
|
||||
@intCast(x),
|
||||
@intCast(y),
|
||||
fg,
|
||||
alpha
|
||||
) catch |err| {
|
||||
log.warn(
|
||||
"error adding overline to cell, will be invalid x={} y={}, err={}",
|
||||
.{ x, y, err },
|
||||
);
|
||||
};
|
||||
|
||||
// If we're at or past the end of our shaper run then
|
||||
// we need to get the next run from the run iterator.
|
||||
if (shaper_cells != null and shaper_cells_i >= shaper_cells.?.len) {
|
||||
@ -2709,6 +2721,38 @@ fn addUnderline(
|
||||
});
|
||||
}
|
||||
|
||||
/// Add a overline decoration to the specified cell
|
||||
fn addOverline(
|
||||
self: *Metal,
|
||||
x: terminal.size.CellCountInt,
|
||||
y: terminal.size.CellCountInt,
|
||||
color: terminal.color.RGB,
|
||||
alpha: u8,
|
||||
) !void {
|
||||
const render = try self.font_grid.renderGlyph(
|
||||
self.alloc,
|
||||
font.sprite_index,
|
||||
@intFromEnum(font.Sprite.overline),
|
||||
.{
|
||||
.cell_width = 1,
|
||||
.grid_metrics = self.grid_metrics,
|
||||
},
|
||||
);
|
||||
|
||||
try self.cells.add(self.alloc, .overline, .{
|
||||
.mode = .fg,
|
||||
.grid_pos = .{ @intCast(x), @intCast(y) },
|
||||
.constraint_width = 1,
|
||||
.color = .{ color.r, color.g, color.b, alpha },
|
||||
.glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y },
|
||||
.glyph_size = .{ render.glyph.width, render.glyph.height },
|
||||
.bearings = .{
|
||||
@intCast(render.glyph.offset_x),
|
||||
@intCast(render.glyph.offset_y),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/// Add a strikethrough decoration to the specified cell
|
||||
fn addStrikethrough(
|
||||
self: *Metal,
|
||||
|
@ -1586,6 +1586,19 @@ pub fn rebuildCells(
|
||||
);
|
||||
};
|
||||
|
||||
if (style.flags.overline) self.addOverline(
|
||||
@intCast(x),
|
||||
@intCast(y),
|
||||
fg,
|
||||
alpha,
|
||||
bg_color,
|
||||
) catch |err| {
|
||||
log.warn(
|
||||
"error adding overline to cell, will be invalid x={} y={}, err={}",
|
||||
.{ x, y, err },
|
||||
);
|
||||
};
|
||||
|
||||
// If we're at or past the end of our shaper run then
|
||||
// we need to get the next run from the run iterator.
|
||||
if (shaper_cells != null and shaper_cells_i >= shaper_cells.?.len) {
|
||||
@ -1955,6 +1968,47 @@ fn addUnderline(
|
||||
});
|
||||
}
|
||||
|
||||
/// Add an overline decoration to the specified cell
|
||||
fn addOverline(
|
||||
self: *OpenGL,
|
||||
x: terminal.size.CellCountInt,
|
||||
y: terminal.size.CellCountInt,
|
||||
color: terminal.color.RGB,
|
||||
alpha: u8,
|
||||
bg: [4]u8,
|
||||
) !void {
|
||||
const render = try self.font_grid.renderGlyph(
|
||||
self.alloc,
|
||||
font.sprite_index,
|
||||
@intFromEnum(font.Sprite.overline),
|
||||
.{
|
||||
.cell_width = 1,
|
||||
.grid_metrics = self.grid_metrics,
|
||||
},
|
||||
);
|
||||
|
||||
try self.cells.append(self.alloc, .{
|
||||
.mode = .fg,
|
||||
.grid_col = @intCast(x),
|
||||
.grid_row = @intCast(y),
|
||||
.grid_width = 1,
|
||||
.glyph_x = render.glyph.atlas_x,
|
||||
.glyph_y = render.glyph.atlas_y,
|
||||
.glyph_width = render.glyph.width,
|
||||
.glyph_height = render.glyph.height,
|
||||
.glyph_offset_x = render.glyph.offset_x,
|
||||
.glyph_offset_y = render.glyph.offset_y,
|
||||
.r = color.r,
|
||||
.g = color.g,
|
||||
.b = color.b,
|
||||
.a = alpha,
|
||||
.bg_r = bg[0],
|
||||
.bg_g = bg[1],
|
||||
.bg_b = bg[2],
|
||||
.bg_a = bg[3],
|
||||
});
|
||||
}
|
||||
|
||||
/// Add a strikethrough decoration to the specified cell
|
||||
fn addStrikethrough(
|
||||
self: *OpenGL,
|
||||
|
@ -12,6 +12,7 @@ pub const Key = enum {
|
||||
text,
|
||||
underline,
|
||||
strikethrough,
|
||||
overline,
|
||||
|
||||
/// Returns the GPU vertex type for this key.
|
||||
pub fn CellType(self: Key) type {
|
||||
@ -21,6 +22,7 @@ pub const Key = enum {
|
||||
.text,
|
||||
.underline,
|
||||
.strikethrough,
|
||||
.overline,
|
||||
=> mtl_shaders.CellText,
|
||||
};
|
||||
}
|
||||
@ -196,6 +198,7 @@ pub const Contents = struct {
|
||||
.text,
|
||||
.underline,
|
||||
.strikethrough,
|
||||
.overline,
|
||||
// We have a special list containing the cursor cell at the start
|
||||
// of our fg row pool, so we need to add 1 to the y to get the
|
||||
// correct index.
|
||||
|
@ -1618,6 +1618,14 @@ pub fn setAttribute(self: *Screen, attr: sgr.Attribute) !void {
|
||||
self.cursor.style.underline_color = .none;
|
||||
},
|
||||
|
||||
.overline => {
|
||||
self.cursor.style.flags.overline = true;
|
||||
},
|
||||
|
||||
.reset_overline => {
|
||||
self.cursor.style.flags.overline = false;
|
||||
},
|
||||
|
||||
.blink => {
|
||||
self.cursor.style.flags.blink = true;
|
||||
},
|
||||
|
@ -37,6 +37,10 @@ pub const Attribute = union(enum) {
|
||||
@"256_underline_color": u8,
|
||||
reset_underline_color: void,
|
||||
|
||||
// Overline the text
|
||||
overline: void,
|
||||
reset_overline: void,
|
||||
|
||||
/// Blink the text
|
||||
blink: void,
|
||||
reset_blink: void,
|
||||
@ -237,6 +241,9 @@ pub const Parser = struct {
|
||||
|
||||
49 => return Attribute{ .reset_bg = {} },
|
||||
|
||||
53 => return Attribute{ .overline = {} },
|
||||
55 => return Attribute{ .reset_overline = {} },
|
||||
|
||||
58 => if (slice.len >= 5 and slice[1] == 2) {
|
||||
self.idx += 4;
|
||||
|
||||
|
@ -35,6 +35,7 @@ pub const Style = struct {
|
||||
inverse: bool = false,
|
||||
invisible: bool = false,
|
||||
strikethrough: bool = false,
|
||||
overline: bool = false,
|
||||
underline: sgr.Attribute.Underline = .none,
|
||||
} = .{},
|
||||
|
||||
|
Reference in New Issue
Block a user