mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-24 20:56:08 +03:00
Merge pull request #159 from mitchellh/invisible
Implement SGR 8/28 Invisible
This commit is contained in:
@ -935,22 +935,26 @@ pub fn updateCell(
|
|||||||
// cell is selected.
|
// cell is selected.
|
||||||
// TODO(perf): we can check in advance if selection is in
|
// TODO(perf): we can check in advance if selection is in
|
||||||
// our viewport at all and not run this on every point.
|
// our viewport at all and not run this on every point.
|
||||||
if (selection) |sel| {
|
var selection_res: ?BgFg = sel_colors: {
|
||||||
const screen_point = (terminal.point.Viewport{
|
if (selection) |sel| {
|
||||||
.x = x,
|
const screen_point = (terminal.point.Viewport{
|
||||||
.y = y,
|
.x = x,
|
||||||
}).toScreen(screen);
|
.y = y,
|
||||||
|
}).toScreen(screen);
|
||||||
|
|
||||||
// If we are selected, we our colors are just inverted fg/bg
|
// If we are selected, we our colors are just inverted fg/bg
|
||||||
if (sel.contains(screen_point)) {
|
if (sel.contains(screen_point)) {
|
||||||
break :colors BgFg{
|
break :sel_colors BgFg{
|
||||||
.bg = self.config.selection_background orelse self.config.foreground,
|
.bg = self.config.selection_background orelse self.config.foreground,
|
||||||
.fg = self.config.selection_foreground orelse self.config.background,
|
.fg = self.config.selection_foreground orelse self.config.background,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const res: BgFg = if (!cell.attrs.inverse) .{
|
break :sel_colors null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const res: BgFg = selection_res orelse if (!cell.attrs.inverse) .{
|
||||||
// In normal mode, background and fg match the cell. We
|
// In normal mode, background and fg match the cell. We
|
||||||
// un-optionalize the fg by defaulting to our fg color.
|
// un-optionalize the fg by defaulting to our fg color.
|
||||||
.bg = if (cell.attrs.has_bg) cell.bg else null,
|
.bg = if (cell.attrs.has_bg) cell.bg else null,
|
||||||
@ -962,6 +966,16 @@ pub fn updateCell(
|
|||||||
.bg = if (cell.attrs.has_fg) cell.fg else self.config.foreground,
|
.bg = if (cell.attrs.has_fg) cell.fg else self.config.foreground,
|
||||||
.fg = if (cell.attrs.has_bg) cell.bg else self.config.background,
|
.fg = if (cell.attrs.has_bg) cell.bg else self.config.background,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// If the cell is "invisible" then we just make fg = bg so that
|
||||||
|
// the cell is transparent but still copy-able.
|
||||||
|
if (cell.attrs.invisible) {
|
||||||
|
break :colors BgFg{
|
||||||
|
.bg = res.bg,
|
||||||
|
.fg = res.bg orelse self.config.background,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
break :colors res;
|
break :colors res;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1056,22 +1056,26 @@ pub fn updateCell(
|
|||||||
// cell is selected.
|
// cell is selected.
|
||||||
// TODO(perf): we can check in advance if selection is in
|
// TODO(perf): we can check in advance if selection is in
|
||||||
// our viewport at all and not run this on every point.
|
// our viewport at all and not run this on every point.
|
||||||
if (selection) |sel| {
|
var selection_res: ?BgFg = sel_colors: {
|
||||||
const screen_point = (terminal.point.Viewport{
|
if (selection) |sel| {
|
||||||
.x = x,
|
const screen_point = (terminal.point.Viewport{
|
||||||
.y = y,
|
.x = x,
|
||||||
}).toScreen(screen);
|
.y = y,
|
||||||
|
}).toScreen(screen);
|
||||||
|
|
||||||
// If we are selected, we use the selection colors
|
// If we are selected, we our colors are just inverted fg/bg
|
||||||
if (sel.contains(screen_point)) {
|
if (sel.contains(screen_point)) {
|
||||||
break :colors BgFg{
|
break :sel_colors BgFg{
|
||||||
.bg = self.config.selection_background orelse self.config.foreground,
|
.bg = self.config.selection_background orelse self.config.foreground,
|
||||||
.fg = self.config.selection_foreground orelse self.config.background,
|
.fg = self.config.selection_foreground orelse self.config.background,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const res: BgFg = if (!cell.attrs.inverse) .{
|
break :sel_colors null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const res: BgFg = selection_res orelse if (!cell.attrs.inverse) .{
|
||||||
// In normal mode, background and fg match the cell. We
|
// In normal mode, background and fg match the cell. We
|
||||||
// un-optionalize the fg by defaulting to our fg color.
|
// un-optionalize the fg by defaulting to our fg color.
|
||||||
.bg = if (cell.attrs.has_bg) cell.bg else null,
|
.bg = if (cell.attrs.has_bg) cell.bg else null,
|
||||||
@ -1083,6 +1087,16 @@ pub fn updateCell(
|
|||||||
.bg = if (cell.attrs.has_fg) cell.fg else self.config.foreground,
|
.bg = if (cell.attrs.has_fg) cell.fg else self.config.foreground,
|
||||||
.fg = if (cell.attrs.has_bg) cell.bg else self.config.background,
|
.fg = if (cell.attrs.has_bg) cell.bg else self.config.background,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// If the cell is "invisible" then we just make fg = bg so that
|
||||||
|
// the cell is transparent but still copy-able.
|
||||||
|
if (cell.attrs.invisible) {
|
||||||
|
break :colors BgFg{
|
||||||
|
.bg = res.bg,
|
||||||
|
.fg = res.bg orelse self.config.background,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
break :colors res;
|
break :colors res;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -198,6 +198,7 @@ pub const Cell = struct {
|
|||||||
faint: bool = false,
|
faint: bool = false,
|
||||||
blink: bool = false,
|
blink: bool = false,
|
||||||
inverse: bool = false,
|
inverse: bool = false,
|
||||||
|
invisible: bool = false,
|
||||||
strikethrough: bool = false,
|
strikethrough: bool = false,
|
||||||
underline: sgr.Attribute.Underline = .none,
|
underline: sgr.Attribute.Underline = .none,
|
||||||
underline_color: bool = false,
|
underline_color: bool = false,
|
||||||
@ -272,7 +273,7 @@ pub const Cell = struct {
|
|||||||
|
|
||||||
test {
|
test {
|
||||||
//log.warn("CELL={} bits={} {}", .{ @sizeOf(Cell), @bitSizeOf(Cell), @alignOf(Cell) });
|
//log.warn("CELL={} bits={} {}", .{ @sizeOf(Cell), @bitSizeOf(Cell), @alignOf(Cell) });
|
||||||
try std.testing.expectEqual(16, @sizeOf(Cell));
|
try std.testing.expectEqual(20, @sizeOf(Cell));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -491,6 +491,14 @@ pub fn setAttribute(self: *Terminal, attr: sgr.Attribute) !void {
|
|||||||
self.screen.cursor.pen.attrs.inverse = false;
|
self.screen.cursor.pen.attrs.inverse = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.invisible => {
|
||||||
|
self.screen.cursor.pen.attrs.invisible = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
.reset_invisible => {
|
||||||
|
self.screen.cursor.pen.attrs.invisible = false;
|
||||||
|
},
|
||||||
|
|
||||||
.strikethrough => {
|
.strikethrough => {
|
||||||
self.screen.cursor.pen.attrs.strikethrough = true;
|
self.screen.cursor.pen.attrs.strikethrough = true;
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! SGR (Select Graphic Rendition) attribute parsing and types.
|
//! SGR (Select Graphic Rendition) attrinvbute parsing and types.
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
@ -44,6 +44,10 @@ pub const Attribute = union(enum) {
|
|||||||
inverse: void,
|
inverse: void,
|
||||||
reset_inverse: void,
|
reset_inverse: void,
|
||||||
|
|
||||||
|
/// Invisible
|
||||||
|
invisible: void,
|
||||||
|
reset_invisible: void,
|
||||||
|
|
||||||
/// Strikethrough the text.
|
/// Strikethrough the text.
|
||||||
strikethrough: void,
|
strikethrough: void,
|
||||||
reset_strikethrough: void,
|
reset_strikethrough: void,
|
||||||
@ -163,6 +167,8 @@ pub const Parser = struct {
|
|||||||
|
|
||||||
7 => return Attribute{ .inverse = {} },
|
7 => return Attribute{ .inverse = {} },
|
||||||
|
|
||||||
|
8 => return Attribute{ .invisible = {} },
|
||||||
|
|
||||||
9 => return Attribute{ .strikethrough = {} },
|
9 => return Attribute{ .strikethrough = {} },
|
||||||
|
|
||||||
22 => return Attribute{ .reset_bold = {} },
|
22 => return Attribute{ .reset_bold = {} },
|
||||||
@ -175,6 +181,8 @@ pub const Parser = struct {
|
|||||||
|
|
||||||
27 => return Attribute{ .reset_inverse = {} },
|
27 => return Attribute{ .reset_inverse = {} },
|
||||||
|
|
||||||
|
28 => return Attribute{ .reset_invisible = {} },
|
||||||
|
|
||||||
29 => return Attribute{ .reset_strikethrough = {} },
|
29 => return Attribute{ .reset_strikethrough = {} },
|
||||||
|
|
||||||
30...37 => return Attribute{
|
30...37 => return Attribute{
|
||||||
@ -499,3 +507,9 @@ test "sgr: reset underline color" {
|
|||||||
var p: Parser = .{ .params = &[_]u16{59} };
|
var p: Parser = .{ .params = &[_]u16{59} };
|
||||||
try testing.expect(p.next().? == .reset_underline_color);
|
try testing.expect(p.next().? == .reset_underline_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "sgr: invisible" {
|
||||||
|
var p: Parser = .{ .params = &[_]u16{ 8, 28 } };
|
||||||
|
try testing.expect(p.next().? == .invisible);
|
||||||
|
try testing.expect(p.next().? == .reset_invisible);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user