mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 00:06:09 +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,
|
strikethrough,
|
||||||
|
|
||||||
|
overline,
|
||||||
|
|
||||||
cursor_rect,
|
cursor_rect,
|
||||||
cursor_hollow_rect,
|
cursor_hollow_rect,
|
||||||
cursor_bar,
|
cursor_bar,
|
||||||
|
@ -150,6 +150,16 @@ pub fn renderGlyph(
|
|||||||
self.thickness,
|
self.thickness,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
.overline => try underline.renderGlyph(
|
||||||
|
alloc,
|
||||||
|
atlas,
|
||||||
|
@enumFromInt(cp),
|
||||||
|
width,
|
||||||
|
self.height,
|
||||||
|
0,
|
||||||
|
self.thickness,
|
||||||
|
),
|
||||||
|
|
||||||
.powerline => powerline: {
|
.powerline => powerline: {
|
||||||
const f: Powerline = .{
|
const f: Powerline = .{
|
||||||
.width = width,
|
.width = width,
|
||||||
@ -166,6 +176,7 @@ pub fn renderGlyph(
|
|||||||
const Kind = enum {
|
const Kind = enum {
|
||||||
box,
|
box,
|
||||||
underline,
|
underline,
|
||||||
|
overline,
|
||||||
strikethrough,
|
strikethrough,
|
||||||
powerline,
|
powerline,
|
||||||
|
|
||||||
@ -179,6 +190,9 @@ const Kind = enum {
|
|||||||
.underline_curly,
|
.underline_curly,
|
||||||
=> .underline,
|
=> .underline,
|
||||||
|
|
||||||
|
.overline,
|
||||||
|
=> .overline,
|
||||||
|
|
||||||
.strikethrough,
|
.strikethrough,
|
||||||
=> .strikethrough,
|
=> .strikethrough,
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ pub fn renderGlyph(
|
|||||||
.underline_dotted => try drawDotted(alloc, width, line_thickness),
|
.underline_dotted => try drawDotted(alloc, width, line_thickness),
|
||||||
.underline_dashed => try drawDashed(alloc, width, line_thickness),
|
.underline_dashed => try drawDashed(alloc, width, line_thickness),
|
||||||
.underline_curly => try drawCurly(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),
|
.strikethrough => try drawSingle(alloc, width, line_thickness),
|
||||||
else => unreachable,
|
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
|
// If we're at or past the end of our shaper run then
|
||||||
// we need to get the next run from the run iterator.
|
// we need to get the next run from the run iterator.
|
||||||
if (shaper_cells != null and shaper_cells_i >= shaper_cells.?.len) {
|
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
|
/// Add a strikethrough decoration to the specified cell
|
||||||
fn addStrikethrough(
|
fn addStrikethrough(
|
||||||
self: *Metal,
|
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
|
// If we're at or past the end of our shaper run then
|
||||||
// we need to get the next run from the run iterator.
|
// we need to get the next run from the run iterator.
|
||||||
if (shaper_cells != null and shaper_cells_i >= shaper_cells.?.len) {
|
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
|
/// Add a strikethrough decoration to the specified cell
|
||||||
fn addStrikethrough(
|
fn addStrikethrough(
|
||||||
self: *OpenGL,
|
self: *OpenGL,
|
||||||
|
@ -12,6 +12,7 @@ pub const Key = enum {
|
|||||||
text,
|
text,
|
||||||
underline,
|
underline,
|
||||||
strikethrough,
|
strikethrough,
|
||||||
|
overline,
|
||||||
|
|
||||||
/// Returns the GPU vertex type for this key.
|
/// Returns the GPU vertex type for this key.
|
||||||
pub fn CellType(self: Key) type {
|
pub fn CellType(self: Key) type {
|
||||||
@ -21,6 +22,7 @@ pub const Key = enum {
|
|||||||
.text,
|
.text,
|
||||||
.underline,
|
.underline,
|
||||||
.strikethrough,
|
.strikethrough,
|
||||||
|
.overline,
|
||||||
=> mtl_shaders.CellText,
|
=> mtl_shaders.CellText,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -196,6 +198,7 @@ pub const Contents = struct {
|
|||||||
.text,
|
.text,
|
||||||
.underline,
|
.underline,
|
||||||
.strikethrough,
|
.strikethrough,
|
||||||
|
.overline,
|
||||||
// We have a special list containing the cursor cell at the start
|
// 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
|
// of our fg row pool, so we need to add 1 to the y to get the
|
||||||
// correct index.
|
// correct index.
|
||||||
|
@ -1618,6 +1618,14 @@ pub fn setAttribute(self: *Screen, attr: sgr.Attribute) !void {
|
|||||||
self.cursor.style.underline_color = .none;
|
self.cursor.style.underline_color = .none;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.overline => {
|
||||||
|
self.cursor.style.flags.overline = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
.reset_overline => {
|
||||||
|
self.cursor.style.flags.overline = false;
|
||||||
|
},
|
||||||
|
|
||||||
.blink => {
|
.blink => {
|
||||||
self.cursor.style.flags.blink = true;
|
self.cursor.style.flags.blink = true;
|
||||||
},
|
},
|
||||||
|
@ -37,6 +37,10 @@ pub const Attribute = union(enum) {
|
|||||||
@"256_underline_color": u8,
|
@"256_underline_color": u8,
|
||||||
reset_underline_color: void,
|
reset_underline_color: void,
|
||||||
|
|
||||||
|
// Overline the text
|
||||||
|
overline: void,
|
||||||
|
reset_overline: void,
|
||||||
|
|
||||||
/// Blink the text
|
/// Blink the text
|
||||||
blink: void,
|
blink: void,
|
||||||
reset_blink: void,
|
reset_blink: void,
|
||||||
@ -237,6 +241,9 @@ pub const Parser = struct {
|
|||||||
|
|
||||||
49 => return Attribute{ .reset_bg = {} },
|
49 => return Attribute{ .reset_bg = {} },
|
||||||
|
|
||||||
|
53 => return Attribute{ .overline = {} },
|
||||||
|
55 => return Attribute{ .reset_overline = {} },
|
||||||
|
|
||||||
58 => if (slice.len >= 5 and slice[1] == 2) {
|
58 => if (slice.len >= 5 and slice[1] == 2) {
|
||||||
self.idx += 4;
|
self.idx += 4;
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ pub const Style = struct {
|
|||||||
inverse: bool = false,
|
inverse: bool = false,
|
||||||
invisible: bool = false,
|
invisible: bool = false,
|
||||||
strikethrough: bool = false,
|
strikethrough: bool = false,
|
||||||
|
overline: bool = false,
|
||||||
underline: sgr.Attribute.Underline = .none,
|
underline: sgr.Attribute.Underline = .none,
|
||||||
} = .{},
|
} = .{},
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user