mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
Merge pull request #1202 from gpanders/cell-color-refactor
terminal: track palette color in cell state
This commit is contained in:
@ -260,8 +260,7 @@ test "run iterator: empty cells with background set" {
|
||||
// Make a screen with some data
|
||||
var screen = try terminal.Screen.init(alloc, 3, 5, 0);
|
||||
defer screen.deinit();
|
||||
screen.cursor.pen.bg = try terminal.color.Name.cyan.default();
|
||||
screen.cursor.pen.attrs.has_bg = true;
|
||||
screen.cursor.pen.bg = .{ .rgb = try terminal.color.Name.cyan.default() };
|
||||
try screen.testWriteString("A");
|
||||
|
||||
// Get our first row
|
||||
@ -836,10 +835,9 @@ test "shape cell attribute change" {
|
||||
{
|
||||
var screen = try terminal.Screen.init(alloc, 3, 10, 0);
|
||||
defer screen.deinit();
|
||||
screen.cursor.pen.attrs.has_fg = true;
|
||||
screen.cursor.pen.fg = .{ .r = 1, .g = 2, .b = 3 };
|
||||
screen.cursor.pen.fg = .{ .rgb = .{ .r = 1, .g = 2, .b = 3 } };
|
||||
try screen.testWriteString(">");
|
||||
screen.cursor.pen.fg = .{ .r = 3, .g = 2, .b = 1 };
|
||||
screen.cursor.pen.fg = .{ .rgb = .{ .r = 3, .g = 2, .b = 1 } };
|
||||
try screen.testWriteString("=");
|
||||
|
||||
var shaper = &testdata.shaper;
|
||||
@ -856,10 +854,9 @@ test "shape cell attribute change" {
|
||||
{
|
||||
var screen = try terminal.Screen.init(alloc, 3, 10, 0);
|
||||
defer screen.deinit();
|
||||
screen.cursor.pen.attrs.has_bg = true;
|
||||
screen.cursor.pen.bg = .{ .r = 1, .g = 2, .b = 3 };
|
||||
screen.cursor.pen.bg = .{ .rgb = .{ .r = 1, .g = 2, .b = 3 } };
|
||||
try screen.testWriteString(">");
|
||||
screen.cursor.pen.bg = .{ .r = 3, .g = 2, .b = 1 };
|
||||
screen.cursor.pen.bg = .{ .rgb = .{ .r = 3, .g = 2, .b = 1 } };
|
||||
try screen.testWriteString("=");
|
||||
|
||||
var shaper = &testdata.shaper;
|
||||
@ -876,8 +873,7 @@ test "shape cell attribute change" {
|
||||
{
|
||||
var screen = try terminal.Screen.init(alloc, 3, 10, 0);
|
||||
defer screen.deinit();
|
||||
screen.cursor.pen.attrs.has_bg = true;
|
||||
screen.cursor.pen.bg = .{ .r = 1, .g = 2, .b = 3 };
|
||||
screen.cursor.pen.bg = .{ .rgb = .{ .r = 1, .g = 2, .b = 3 } };
|
||||
try screen.testWriteString(">");
|
||||
try screen.testWriteString("=");
|
||||
|
||||
|
@ -87,8 +87,8 @@ pub const RunIterator = struct {
|
||||
const prev_attrs: Int = @bitCast(prev_cell.attrs.styleAttrs());
|
||||
const attrs: Int = @bitCast(cell.attrs.styleAttrs());
|
||||
if (prev_attrs != attrs) break;
|
||||
if (cell.attrs.has_bg and !cell.bg.eql(prev_cell.bg)) break;
|
||||
if (cell.attrs.has_fg and !cell.fg.eql(prev_cell.fg)) break;
|
||||
if (!cell.bg.eql(prev_cell.bg)) break;
|
||||
if (!cell.fg.eql(prev_cell.fg)) break;
|
||||
}
|
||||
|
||||
// Text runs break when font styles change so we need to get
|
||||
|
@ -299,7 +299,8 @@ fn renderScreenWindow(self: *Inspector) void {
|
||||
);
|
||||
defer cimgui.c.igEndTable();
|
||||
|
||||
inspector.cursor.renderInTable(&screen.cursor);
|
||||
const palette = self.surface.io.terminal.color_palette.colors;
|
||||
inspector.cursor.renderInTable(&screen.cursor, &palette);
|
||||
} // table
|
||||
|
||||
cimgui.c.igTextDisabled("(Any styles not shown are not currently set)");
|
||||
@ -871,49 +872,66 @@ fn renderCellWindow(self: *Inspector) void {
|
||||
}
|
||||
|
||||
// If we have a color then we show the color
|
||||
color: {
|
||||
cimgui.c.igTableNextRow(cimgui.c.ImGuiTableRowFlags_None, 0);
|
||||
_ = cimgui.c.igTableSetColumnIndex(0);
|
||||
cimgui.c.igText("Foreground Color");
|
||||
_ = cimgui.c.igTableSetColumnIndex(1);
|
||||
if (!selected.cell.attrs.has_fg) {
|
||||
cimgui.c.igText("default");
|
||||
break :color;
|
||||
}
|
||||
cimgui.c.igTableNextRow(cimgui.c.ImGuiTableRowFlags_None, 0);
|
||||
_ = cimgui.c.igTableSetColumnIndex(0);
|
||||
cimgui.c.igText("Foreground Color");
|
||||
_ = cimgui.c.igTableSetColumnIndex(1);
|
||||
switch (selected.cell.fg) {
|
||||
.none => cimgui.c.igText("default"),
|
||||
else => {
|
||||
const rgb = switch (selected.cell.fg) {
|
||||
.none => unreachable,
|
||||
.indexed => |idx| self.surface.io.terminal.color_palette.colors[idx],
|
||||
.rgb => |rgb| rgb,
|
||||
};
|
||||
|
||||
var color: [3]f32 = .{
|
||||
@as(f32, @floatFromInt(selected.cell.fg.r)) / 255,
|
||||
@as(f32, @floatFromInt(selected.cell.fg.g)) / 255,
|
||||
@as(f32, @floatFromInt(selected.cell.fg.b)) / 255,
|
||||
};
|
||||
_ = cimgui.c.igColorEdit3(
|
||||
"color_fg",
|
||||
&color,
|
||||
cimgui.c.ImGuiColorEditFlags_NoPicker |
|
||||
cimgui.c.ImGuiColorEditFlags_NoLabel,
|
||||
);
|
||||
if (selected.cell.fg == .indexed) {
|
||||
cimgui.c.igValue_Int("Palette", selected.cell.fg.indexed);
|
||||
}
|
||||
|
||||
var color: [3]f32 = .{
|
||||
@as(f32, @floatFromInt(rgb.r)) / 255,
|
||||
@as(f32, @floatFromInt(rgb.g)) / 255,
|
||||
@as(f32, @floatFromInt(rgb.b)) / 255,
|
||||
};
|
||||
_ = cimgui.c.igColorEdit3(
|
||||
"color_fg",
|
||||
&color,
|
||||
cimgui.c.ImGuiColorEditFlags_NoPicker |
|
||||
cimgui.c.ImGuiColorEditFlags_NoLabel,
|
||||
);
|
||||
},
|
||||
}
|
||||
color: {
|
||||
cimgui.c.igTableNextRow(cimgui.c.ImGuiTableRowFlags_None, 0);
|
||||
_ = cimgui.c.igTableSetColumnIndex(0);
|
||||
cimgui.c.igText("Background Color");
|
||||
_ = cimgui.c.igTableSetColumnIndex(1);
|
||||
if (!selected.cell.attrs.has_bg) {
|
||||
cimgui.c.igText("default");
|
||||
break :color;
|
||||
}
|
||||
|
||||
var color: [3]f32 = .{
|
||||
@as(f32, @floatFromInt(selected.cell.bg.r)) / 255,
|
||||
@as(f32, @floatFromInt(selected.cell.bg.g)) / 255,
|
||||
@as(f32, @floatFromInt(selected.cell.bg.b)) / 255,
|
||||
};
|
||||
_ = cimgui.c.igColorEdit3(
|
||||
"color_bg",
|
||||
&color,
|
||||
cimgui.c.ImGuiColorEditFlags_NoPicker |
|
||||
cimgui.c.ImGuiColorEditFlags_NoLabel,
|
||||
);
|
||||
cimgui.c.igTableNextRow(cimgui.c.ImGuiTableRowFlags_None, 0);
|
||||
_ = cimgui.c.igTableSetColumnIndex(0);
|
||||
cimgui.c.igText("Background Color");
|
||||
_ = cimgui.c.igTableSetColumnIndex(1);
|
||||
switch (selected.cell.bg) {
|
||||
.none => cimgui.c.igText("default"),
|
||||
else => {
|
||||
const rgb = switch (selected.cell.bg) {
|
||||
.none => unreachable,
|
||||
.indexed => |idx| self.surface.io.terminal.color_palette.colors[idx],
|
||||
.rgb => |rgb| rgb,
|
||||
};
|
||||
|
||||
if (selected.cell.bg == .indexed) {
|
||||
cimgui.c.igValue_Int("Palette", selected.cell.bg.indexed);
|
||||
}
|
||||
|
||||
var color: [3]f32 = .{
|
||||
@as(f32, @floatFromInt(rgb.r)) / 255,
|
||||
@as(f32, @floatFromInt(rgb.g)) / 255,
|
||||
@as(f32, @floatFromInt(rgb.b)) / 255,
|
||||
};
|
||||
_ = cimgui.c.igColorEdit3(
|
||||
"color_bg",
|
||||
&color,
|
||||
cimgui.c.ImGuiColorEditFlags_NoPicker |
|
||||
cimgui.c.ImGuiColorEditFlags_NoLabel,
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
// Boolean styles
|
||||
@ -1109,7 +1127,8 @@ fn renderTermioWindow(self: *Inspector) void {
|
||||
0,
|
||||
);
|
||||
defer cimgui.c.igEndTable();
|
||||
inspector.cursor.renderInTable(&ev.cursor);
|
||||
const palette = self.surface.io.terminal.color_palette.colors;
|
||||
inspector.cursor.renderInTable(&ev.cursor, &palette);
|
||||
|
||||
{
|
||||
cimgui.c.igTableNextRow(cimgui.c.ImGuiTableRowFlags_None, 0);
|
||||
|
@ -3,7 +3,10 @@ const cimgui = @import("cimgui");
|
||||
const terminal = @import("../terminal/main.zig");
|
||||
|
||||
/// Render cursor information with a table already open.
|
||||
pub fn renderInTable(cursor: *const terminal.Screen.Cursor) void {
|
||||
pub fn renderInTable(
|
||||
cursor: *const terminal.Screen.Cursor,
|
||||
palette: *const terminal.color.Palette,
|
||||
) void {
|
||||
{
|
||||
cimgui.c.igTableNextRow(cimgui.c.ImGuiTableRowFlags_None, 0);
|
||||
{
|
||||
@ -41,49 +44,66 @@ pub fn renderInTable(cursor: *const terminal.Screen.Cursor) void {
|
||||
}
|
||||
|
||||
// If we have a color then we show the color
|
||||
if (cursor.pen.attrs.has_fg) color: {
|
||||
cimgui.c.igTableNextRow(cimgui.c.ImGuiTableRowFlags_None, 0);
|
||||
_ = cimgui.c.igTableSetColumnIndex(0);
|
||||
cimgui.c.igText("Foreground Color");
|
||||
_ = cimgui.c.igTableSetColumnIndex(1);
|
||||
if (!cursor.pen.attrs.has_fg) {
|
||||
cimgui.c.igText("default");
|
||||
break :color;
|
||||
}
|
||||
cimgui.c.igTableNextRow(cimgui.c.ImGuiTableRowFlags_None, 0);
|
||||
_ = cimgui.c.igTableSetColumnIndex(0);
|
||||
cimgui.c.igText("Foreground Color");
|
||||
_ = cimgui.c.igTableSetColumnIndex(1);
|
||||
switch (cursor.pen.fg) {
|
||||
.none => cimgui.c.igText("default"),
|
||||
else => {
|
||||
const rgb = switch (cursor.pen.fg) {
|
||||
.none => unreachable,
|
||||
.indexed => |idx| palette[idx],
|
||||
.rgb => |rgb| rgb,
|
||||
};
|
||||
|
||||
var color: [3]f32 = .{
|
||||
@as(f32, @floatFromInt(cursor.pen.fg.r)) / 255,
|
||||
@as(f32, @floatFromInt(cursor.pen.fg.g)) / 255,
|
||||
@as(f32, @floatFromInt(cursor.pen.fg.b)) / 255,
|
||||
};
|
||||
_ = cimgui.c.igColorEdit3(
|
||||
"color_fg",
|
||||
&color,
|
||||
cimgui.c.ImGuiColorEditFlags_NoPicker |
|
||||
cimgui.c.ImGuiColorEditFlags_NoLabel,
|
||||
);
|
||||
if (cursor.pen.fg == .indexed) {
|
||||
cimgui.c.igValue_Int("Palette", cursor.pen.fg.indexed);
|
||||
}
|
||||
|
||||
var color: [3]f32 = .{
|
||||
@as(f32, @floatFromInt(rgb.r)) / 255,
|
||||
@as(f32, @floatFromInt(rgb.g)) / 255,
|
||||
@as(f32, @floatFromInt(rgb.b)) / 255,
|
||||
};
|
||||
_ = cimgui.c.igColorEdit3(
|
||||
"color_fg",
|
||||
&color,
|
||||
cimgui.c.ImGuiColorEditFlags_NoPicker |
|
||||
cimgui.c.ImGuiColorEditFlags_NoLabel,
|
||||
);
|
||||
},
|
||||
}
|
||||
if (cursor.pen.attrs.has_bg) color: {
|
||||
cimgui.c.igTableNextRow(cimgui.c.ImGuiTableRowFlags_None, 0);
|
||||
_ = cimgui.c.igTableSetColumnIndex(0);
|
||||
cimgui.c.igText("Background Color");
|
||||
_ = cimgui.c.igTableSetColumnIndex(1);
|
||||
if (!cursor.pen.attrs.has_bg) {
|
||||
cimgui.c.igText("default");
|
||||
break :color;
|
||||
}
|
||||
|
||||
var color: [3]f32 = .{
|
||||
@as(f32, @floatFromInt(cursor.pen.bg.r)) / 255,
|
||||
@as(f32, @floatFromInt(cursor.pen.bg.g)) / 255,
|
||||
@as(f32, @floatFromInt(cursor.pen.bg.b)) / 255,
|
||||
};
|
||||
_ = cimgui.c.igColorEdit3(
|
||||
"color_bg",
|
||||
&color,
|
||||
cimgui.c.ImGuiColorEditFlags_NoPicker |
|
||||
cimgui.c.ImGuiColorEditFlags_NoLabel,
|
||||
);
|
||||
cimgui.c.igTableNextRow(cimgui.c.ImGuiTableRowFlags_None, 0);
|
||||
_ = cimgui.c.igTableSetColumnIndex(0);
|
||||
cimgui.c.igText("Background Color");
|
||||
_ = cimgui.c.igTableSetColumnIndex(1);
|
||||
switch (cursor.pen.bg) {
|
||||
.none => cimgui.c.igText("default"),
|
||||
else => {
|
||||
const rgb = switch (cursor.pen.bg) {
|
||||
.none => unreachable,
|
||||
.indexed => |idx| palette[idx],
|
||||
.rgb => |rgb| rgb,
|
||||
};
|
||||
|
||||
if (cursor.pen.bg == .indexed) {
|
||||
cimgui.c.igValue_Int("Palette", cursor.pen.bg.indexed);
|
||||
}
|
||||
|
||||
var color: [3]f32 = .{
|
||||
@as(f32, @floatFromInt(rgb.r)) / 255,
|
||||
@as(f32, @floatFromInt(rgb.g)) / 255,
|
||||
@as(f32, @floatFromInt(rgb.b)) / 255,
|
||||
};
|
||||
_ = cimgui.c.igColorEdit3(
|
||||
"color_bg",
|
||||
&color,
|
||||
cimgui.c.ImGuiColorEditFlags_NoPicker |
|
||||
cimgui.c.ImGuiColorEditFlags_NoLabel,
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
// Boolean styles
|
||||
|
@ -579,6 +579,7 @@ pub fn updateFrame(
|
||||
mouse: renderer.State.Mouse,
|
||||
preedit: ?renderer.State.Preedit,
|
||||
cursor_style: ?renderer.CursorStyle,
|
||||
color_palette: terminal.color.Palette,
|
||||
};
|
||||
|
||||
// Update all our data as tightly as possible within the mutex.
|
||||
@ -655,6 +656,7 @@ pub fn updateFrame(
|
||||
.mouse = state.mouse,
|
||||
.preedit = preedit,
|
||||
.cursor_style = cursor_style,
|
||||
.color_palette = state.terminal.color_palette.colors,
|
||||
};
|
||||
};
|
||||
defer {
|
||||
@ -669,6 +671,7 @@ pub fn updateFrame(
|
||||
critical.mouse,
|
||||
critical.preedit,
|
||||
critical.cursor_style,
|
||||
&critical.color_palette,
|
||||
);
|
||||
|
||||
// Update our background color
|
||||
@ -1424,6 +1427,7 @@ fn rebuildCells(
|
||||
mouse: renderer.State.Mouse,
|
||||
preedit: ?renderer.State.Preedit,
|
||||
cursor_style_: ?renderer.CursorStyle,
|
||||
color_palette: *const terminal.color.Palette,
|
||||
) !void {
|
||||
// Bg cells at most will need space for the visible screen size
|
||||
self.cells_bg.clearRetainingCapacity();
|
||||
@ -1579,6 +1583,7 @@ fn rebuildCells(
|
||||
term_selection,
|
||||
screen,
|
||||
cell,
|
||||
color_palette,
|
||||
shaper_cell,
|
||||
run,
|
||||
shaper_cell.x,
|
||||
@ -1644,11 +1649,12 @@ fn rebuildCells(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updateCell(
|
||||
fn updateCell(
|
||||
self: *Metal,
|
||||
selection: ?terminal.Selection,
|
||||
screen: *terminal.Screen,
|
||||
cell: terminal.Screen.Cell,
|
||||
palette: *const terminal.color.Palette,
|
||||
shaper_cell: font.shape.Cell,
|
||||
shaper_run: font.shape.TextRun,
|
||||
x: usize,
|
||||
@ -1684,14 +1690,30 @@ pub fn updateCell(
|
||||
const cell_res: BgFg = if (!cell.attrs.inverse) .{
|
||||
// In normal mode, background and fg match the cell. We
|
||||
// un-optionalize the fg by defaulting to our fg color.
|
||||
.bg = if (cell.attrs.has_bg) cell.bg else null,
|
||||
.fg = if (cell.attrs.has_fg) cell.fg else self.foreground_color,
|
||||
.bg = switch (cell.bg) {
|
||||
.none => null,
|
||||
.indexed => |i| palette[i],
|
||||
.rgb => |rgb| rgb,
|
||||
},
|
||||
.fg = switch (cell.fg) {
|
||||
.none => self.foreground_color,
|
||||
.indexed => |i| palette[i],
|
||||
.rgb => |rgb| rgb,
|
||||
},
|
||||
} else .{
|
||||
// In inverted mode, the background MUST be set to something
|
||||
// (is never null) so it is either the fg or default fg. The
|
||||
// fg is either the bg or default background.
|
||||
.bg = if (cell.attrs.has_fg) cell.fg else self.foreground_color,
|
||||
.fg = if (cell.attrs.has_bg) cell.bg else self.background_color,
|
||||
.bg = switch (cell.fg) {
|
||||
.none => self.foreground_color,
|
||||
.indexed => |i| palette[i],
|
||||
.rgb => |rgb| rgb,
|
||||
},
|
||||
.fg = switch (cell.bg) {
|
||||
.none => self.background_color,
|
||||
.indexed => |i| palette[i],
|
||||
.rgb => |rgb| rgb,
|
||||
},
|
||||
};
|
||||
|
||||
// If we are selected, we our colors are just inverted fg/bg
|
||||
@ -1741,7 +1763,7 @@ pub fn updateCell(
|
||||
|
||||
// If we have a background and its not the default background
|
||||
// then we apply background opacity
|
||||
if (cell.attrs.has_bg and !std.meta.eql(rgb, self.background_color)) {
|
||||
if (cell.bg != .none and !rgb.eql(self.background_color)) {
|
||||
break :bg_alpha default;
|
||||
}
|
||||
|
||||
|
@ -649,6 +649,7 @@ pub fn updateFrame(
|
||||
mouse: renderer.State.Mouse,
|
||||
preedit: ?renderer.State.Preedit,
|
||||
cursor_style: ?renderer.CursorStyle,
|
||||
color_palette: terminal.color.Palette,
|
||||
};
|
||||
|
||||
// Update all our data as tightly as possible within the mutex.
|
||||
@ -730,6 +731,7 @@ pub fn updateFrame(
|
||||
.mouse = state.mouse,
|
||||
.preedit = preedit,
|
||||
.cursor_style = cursor_style,
|
||||
.color_palette = state.terminal.color_palette.colors,
|
||||
};
|
||||
};
|
||||
defer {
|
||||
@ -752,6 +754,7 @@ pub fn updateFrame(
|
||||
critical.mouse,
|
||||
critical.preedit,
|
||||
critical.cursor_style,
|
||||
&critical.color_palette,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -943,6 +946,7 @@ pub fn rebuildCells(
|
||||
mouse: renderer.State.Mouse,
|
||||
preedit: ?renderer.State.Preedit,
|
||||
cursor_style_: ?renderer.CursorStyle,
|
||||
color_palette: *const terminal.color.Palette,
|
||||
) !void {
|
||||
const t = trace(@src());
|
||||
defer t.end();
|
||||
@ -1097,6 +1101,7 @@ pub fn rebuildCells(
|
||||
term_selection,
|
||||
screen,
|
||||
cell,
|
||||
color_palette,
|
||||
shaper_cell,
|
||||
run,
|
||||
shaper_cell.x,
|
||||
@ -1330,11 +1335,12 @@ fn addCursor(
|
||||
/// Update a single cell. The bool returns whether the cell was updated
|
||||
/// or not. If the cell wasn't updated, a full refreshCells call is
|
||||
/// needed.
|
||||
pub fn updateCell(
|
||||
fn updateCell(
|
||||
self: *OpenGL,
|
||||
selection: ?terminal.Selection,
|
||||
screen: *terminal.Screen,
|
||||
cell: terminal.Screen.Cell,
|
||||
palette: *const terminal.color.Palette,
|
||||
shaper_cell: font.shape.Cell,
|
||||
shaper_run: font.shape.TextRun,
|
||||
x: usize,
|
||||
@ -1373,14 +1379,30 @@ pub fn updateCell(
|
||||
const cell_res: BgFg = if (!cell.attrs.inverse) .{
|
||||
// In normal mode, background and fg match the cell. We
|
||||
// un-optionalize the fg by defaulting to our fg color.
|
||||
.bg = if (cell.attrs.has_bg) cell.bg else null,
|
||||
.fg = if (cell.attrs.has_fg) cell.fg else self.foreground_color,
|
||||
.bg = switch (cell.bg) {
|
||||
.none => null,
|
||||
.indexed => |i| palette[i],
|
||||
.rgb => |rgb| rgb,
|
||||
},
|
||||
.fg = switch (cell.fg) {
|
||||
.none => self.foreground_color,
|
||||
.indexed => |i| palette[i],
|
||||
.rgb => |rgb| rgb,
|
||||
},
|
||||
} else .{
|
||||
// In inverted mode, the background MUST be set to something
|
||||
// (is never null) so it is either the fg or default fg. The
|
||||
// fg is either the bg or default background.
|
||||
.bg = if (cell.attrs.has_fg) cell.fg else self.foreground_color,
|
||||
.fg = if (cell.attrs.has_bg) cell.bg else self.background_color,
|
||||
.bg = switch (cell.fg) {
|
||||
.none => self.foreground_color,
|
||||
.indexed => |i| palette[i],
|
||||
.rgb => |rgb| rgb,
|
||||
},
|
||||
.fg = switch (cell.bg) {
|
||||
.none => self.background_color,
|
||||
.indexed => |i| palette[i],
|
||||
.rgb => |rgb| rgb,
|
||||
},
|
||||
};
|
||||
|
||||
// If we are selected, we our colors are just inverted fg/bg
|
||||
@ -1441,7 +1463,7 @@ pub fn updateCell(
|
||||
|
||||
// If we have a background and its not the default background
|
||||
// then we apply background opacity
|
||||
if (cell.attrs.has_bg and !std.meta.eql(rgb, self.background_color)) {
|
||||
if (cell.bg != .none and !rgb.eql(self.background_color)) {
|
||||
break :bg_alpha default;
|
||||
}
|
||||
|
||||
|
@ -211,6 +211,27 @@ pub const RowHeader = struct {
|
||||
};
|
||||
};
|
||||
|
||||
/// The color associated with a single cell's foreground or background.
|
||||
const CellColor = union(enum) {
|
||||
none,
|
||||
indexed: u8,
|
||||
rgb: color.RGB,
|
||||
|
||||
pub fn eql(self: CellColor, other: CellColor) bool {
|
||||
return switch (self) {
|
||||
.none => other == .none,
|
||||
.indexed => |i| switch (other) {
|
||||
.indexed => other.indexed == i,
|
||||
else => false,
|
||||
},
|
||||
.rgb => |rgb| switch (other) {
|
||||
.rgb => other.rgb.eql(rgb),
|
||||
else => false,
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Cell is a single cell within the screen.
|
||||
pub const Cell = struct {
|
||||
/// The primary unicode codepoint for this cell. Most cells (almost all)
|
||||
@ -224,10 +245,9 @@ pub const Cell = struct {
|
||||
/// waste memory for every cell, so we use a side lookup for it.
|
||||
char: u32 = 0,
|
||||
|
||||
/// Foreground and background color. attrs.has_{bg/fg} must be checked
|
||||
/// to see if these are useful values.
|
||||
fg: color.RGB = .{},
|
||||
bg: color.RGB = .{},
|
||||
/// Foreground and background color.
|
||||
fg: CellColor = .none,
|
||||
bg: CellColor = .none,
|
||||
|
||||
/// Underline color.
|
||||
/// NOTE(mitchellh): This is very rarely set so ideally we wouldn't waste
|
||||
@ -237,9 +257,6 @@ pub const Cell = struct {
|
||||
|
||||
/// On/off attributes that can be set
|
||||
attrs: packed struct {
|
||||
has_bg: bool = false,
|
||||
has_fg: bool = false,
|
||||
|
||||
bold: bool = false,
|
||||
italic: bool = false,
|
||||
faint: bool = false,
|
||||
@ -286,7 +303,10 @@ pub const Cell = struct {
|
||||
} });
|
||||
|
||||
// We're empty if we have no char AND we have no styling
|
||||
return self.char == 0 and @as(AttrInt, @bitCast(self.attrs)) == 0;
|
||||
return self.char == 0 and
|
||||
self.fg == .none and
|
||||
self.bg == .none and
|
||||
@as(AttrInt, @bitCast(self.attrs)) == 0;
|
||||
}
|
||||
|
||||
/// The width of the cell.
|
||||
@ -1297,9 +1317,9 @@ pub fn scrollRegionUp(self: *Screen, top: RowIndex, bottom: RowIndex, count_req:
|
||||
|
||||
// The pen we'll use for new cells (only the BG attribute is applied to new
|
||||
// cells)
|
||||
const pen: Cell = if (!self.cursor.pen.attrs.has_bg) .{} else .{
|
||||
.bg = self.cursor.pen.bg,
|
||||
.attrs = .{ .has_bg = true },
|
||||
const pen: Cell = switch (self.cursor.pen.bg) {
|
||||
.none => .{},
|
||||
else => |bg| .{ .bg = bg },
|
||||
};
|
||||
|
||||
// Fast-path is that we have a contiguous buffer in our circular buffer.
|
||||
@ -2190,9 +2210,9 @@ fn scrollDelta(self: *Screen, delta: isize, viewport_only: bool) Allocator.Error
|
||||
const dst = slices[0];
|
||||
// The pen we'll use for new cells (only the BG attribute is applied to new
|
||||
// cells)
|
||||
const pen: Cell = if (!self.cursor.pen.attrs.has_bg) .{} else .{
|
||||
.bg = self.cursor.pen.bg,
|
||||
.attrs = .{ .has_bg = true },
|
||||
const pen: Cell = switch (self.cursor.pen.bg) {
|
||||
.none => .{},
|
||||
else => |bg| .{ .bg = bg },
|
||||
};
|
||||
@memset(dst, .{ .cell = pen });
|
||||
|
||||
@ -3488,8 +3508,7 @@ test "Row: isEmpty with only styled cells" {
|
||||
const row = s.getRow(.{ .active = 0 });
|
||||
for (0..s.cols) |x| {
|
||||
const cell = row.getCellPtr(x);
|
||||
cell.*.bg = .{ .r = 0xAA, .g = 0xBB, .b = 0xCC };
|
||||
cell.*.attrs.has_bg = true;
|
||||
cell.*.bg = .{ .rgb = .{ .r = 0xAA, .g = 0xBB, .b = 0xCC } };
|
||||
}
|
||||
try testing.expect(row.isEmpty());
|
||||
}
|
||||
@ -3763,8 +3782,7 @@ test "Screen: scrolling" {
|
||||
|
||||
var s = try init(alloc, 3, 5, 0);
|
||||
defer s.deinit();
|
||||
s.cursor.pen.bg = .{ .r = 155 };
|
||||
s.cursor.pen.attrs.has_bg = true;
|
||||
s.cursor.pen.bg = .{ .rgb = .{ .r = 155 } };
|
||||
try s.testWriteString("1ABCD\n2EFGH\n3IJKL");
|
||||
try testing.expect(s.viewportIsBottom());
|
||||
|
||||
@ -3781,7 +3799,7 @@ test "Screen: scrolling" {
|
||||
{
|
||||
// Test that our new row has the correct background
|
||||
const cell = s.getCell(.active, 2, 0);
|
||||
try testing.expectEqual(@as(u8, 155), cell.bg.r);
|
||||
try testing.expectEqual(@as(u8, 155), cell.bg.rgb.r);
|
||||
}
|
||||
|
||||
// Scrolling to the bottom does nothing
|
||||
@ -5095,8 +5113,7 @@ test "Screen: scrollRegionUp single with pen" {
|
||||
try s.testWriteString("1ABCD\n2EFGH\n3IJKL\n4ABCD");
|
||||
|
||||
s.cursor.pen = .{ .char = 'X' };
|
||||
s.cursor.pen.bg = .{ .r = 155 };
|
||||
s.cursor.pen.attrs.has_bg = true;
|
||||
s.cursor.pen.bg = .{ .rgb = .{ .r = 155 } };
|
||||
s.cursor.pen.attrs.bold = true;
|
||||
s.scrollRegionUp(.{ .active = 1 }, .{ .active = 2 }, 1);
|
||||
{
|
||||
@ -5105,7 +5122,7 @@ test "Screen: scrollRegionUp single with pen" {
|
||||
defer alloc.free(contents);
|
||||
try testing.expectEqualStrings("1ABCD\n3IJKL\n\n4ABCD", contents);
|
||||
const cell = s.getCell(.active, 2, 0);
|
||||
try testing.expectEqual(@as(u8, 155), cell.bg.r);
|
||||
try testing.expectEqual(@as(u8, 155), cell.bg.rgb.r);
|
||||
try testing.expect(!cell.attrs.bold);
|
||||
try testing.expect(s.cursor.pen.attrs.bold);
|
||||
}
|
||||
@ -5170,8 +5187,7 @@ test "Screen: scrollRegionUp fills with pen" {
|
||||
try s.testWriteString("A\nB\nC\nD");
|
||||
|
||||
s.cursor.pen = .{ .char = 'X' };
|
||||
s.cursor.pen.bg = .{ .r = 155 };
|
||||
s.cursor.pen.attrs.has_bg = true;
|
||||
s.cursor.pen.bg = .{ .rgb = .{ .r = 155 } };
|
||||
s.cursor.pen.attrs.bold = true;
|
||||
s.scrollRegionUp(.{ .active = 0 }, .{ .active = 2 }, 1);
|
||||
{
|
||||
@ -5180,7 +5196,7 @@ test "Screen: scrollRegionUp fills with pen" {
|
||||
defer alloc.free(contents);
|
||||
try testing.expectEqualStrings("B\nC\n\nD", contents);
|
||||
const cell = s.getCell(.active, 2, 0);
|
||||
try testing.expectEqual(@as(u8, 155), cell.bg.r);
|
||||
try testing.expectEqual(@as(u8, 155), cell.bg.rgb.r);
|
||||
try testing.expect(!cell.attrs.bold);
|
||||
try testing.expect(s.cursor.pen.attrs.bold);
|
||||
}
|
||||
@ -5202,8 +5218,7 @@ test "Screen: scrollRegionUp buffer wrap" {
|
||||
|
||||
// Scroll
|
||||
s.cursor.pen = .{ .char = 'X' };
|
||||
s.cursor.pen.bg = .{ .r = 155 };
|
||||
s.cursor.pen.attrs.has_bg = true;
|
||||
s.cursor.pen.bg = .{ .rgb = .{ .r = 155 } };
|
||||
s.cursor.pen.attrs.bold = true;
|
||||
s.scrollRegionUp(.{ .screen = 0 }, .{ .screen = 2 }, 1);
|
||||
|
||||
@ -5213,7 +5228,7 @@ test "Screen: scrollRegionUp buffer wrap" {
|
||||
defer alloc.free(contents);
|
||||
try testing.expectEqualStrings("3IJKL\n4ABCD", contents);
|
||||
const cell = s.getCell(.active, 2, 0);
|
||||
try testing.expectEqual(@as(u8, 155), cell.bg.r);
|
||||
try testing.expectEqual(@as(u8, 155), cell.bg.rgb.r);
|
||||
try testing.expect(!cell.attrs.bold);
|
||||
try testing.expect(s.cursor.pen.attrs.bold);
|
||||
}
|
||||
@ -5235,8 +5250,7 @@ test "Screen: scrollRegionUp buffer wrap alternate" {
|
||||
|
||||
// Scroll
|
||||
s.cursor.pen = .{ .char = 'X' };
|
||||
s.cursor.pen.bg = .{ .r = 155 };
|
||||
s.cursor.pen.attrs.has_bg = true;
|
||||
s.cursor.pen.bg = .{ .rgb = .{ .r = 155 } };
|
||||
s.cursor.pen.attrs.bold = true;
|
||||
s.scrollRegionUp(.{ .screen = 0 }, .{ .screen = 2 }, 2);
|
||||
|
||||
@ -5246,7 +5260,7 @@ test "Screen: scrollRegionUp buffer wrap alternate" {
|
||||
defer alloc.free(contents);
|
||||
try testing.expectEqualStrings("4ABCD", contents);
|
||||
const cell = s.getCell(.active, 2, 0);
|
||||
try testing.expectEqual(@as(u8, 155), cell.bg.r);
|
||||
try testing.expectEqual(@as(u8, 155), cell.bg.rgb.r);
|
||||
try testing.expect(!cell.attrs.bold);
|
||||
try testing.expect(s.cursor.pen.attrs.bold);
|
||||
}
|
||||
@ -5964,8 +5978,7 @@ test "Screen: resize (no reflow) less rows trims blank lines" {
|
||||
const row = s.getRow(.{ .active = y });
|
||||
for (0..s.cols) |x| {
|
||||
const cell = row.getCellPtr(x);
|
||||
cell.*.bg = .{ .r = 0xFF, .g = 0, .b = 0 };
|
||||
cell.*.attrs.has_bg = true;
|
||||
cell.*.bg = .{ .rgb = .{ .r = 0xFF, .g = 0, .b = 0 } };
|
||||
}
|
||||
}
|
||||
|
||||
@ -6000,8 +6013,7 @@ test "Screen: resize (no reflow) more rows trims blank lines" {
|
||||
const row = s.getRow(.{ .active = y });
|
||||
for (0..s.cols) |x| {
|
||||
const cell = row.getCellPtr(x);
|
||||
cell.*.bg = .{ .r = 0xFF, .g = 0, .b = 0 };
|
||||
cell.*.attrs.has_bg = true;
|
||||
cell.*.bg = .{ .rgb = .{ .r = 0xFF, .g = 0, .b = 0 } };
|
||||
}
|
||||
}
|
||||
|
||||
@ -6934,7 +6946,7 @@ test "Screen: resize less cols trailing background colors" {
|
||||
const cursor = s.cursor;
|
||||
|
||||
// Color our cells red
|
||||
const pen: Cell = .{ .bg = .{ .r = 0xFF }, .attrs = .{ .has_bg = true } };
|
||||
const pen: Cell = .{ .bg = .{ .rgb = .{ .r = 0xFF } } };
|
||||
for (s.cursor.x..s.cols) |x| {
|
||||
const row = s.getRow(.{ .active = s.cursor.y });
|
||||
const cell = row.getCellPtr(x);
|
||||
|
@ -474,8 +474,8 @@ pub fn setAttribute(self: *Terminal, attr: sgr.Attribute) !void {
|
||||
|
||||
switch (attr) {
|
||||
.unset => {
|
||||
self.screen.cursor.pen.attrs.has_fg = false;
|
||||
self.screen.cursor.pen.attrs.has_bg = false;
|
||||
self.screen.cursor.pen.fg = .none;
|
||||
self.screen.cursor.pen.bg = .none;
|
||||
self.screen.cursor.pen.attrs = .{};
|
||||
},
|
||||
|
||||
@ -561,55 +561,51 @@ pub fn setAttribute(self: *Terminal, attr: sgr.Attribute) !void {
|
||||
},
|
||||
|
||||
.direct_color_fg => |rgb| {
|
||||
self.screen.cursor.pen.attrs.has_fg = true;
|
||||
self.screen.cursor.pen.fg = .{
|
||||
.r = rgb.r,
|
||||
.g = rgb.g,
|
||||
.b = rgb.b,
|
||||
.rgb = .{
|
||||
.r = rgb.r,
|
||||
.g = rgb.g,
|
||||
.b = rgb.b,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
.direct_color_bg => |rgb| {
|
||||
self.screen.cursor.pen.attrs.has_bg = true;
|
||||
self.screen.cursor.pen.bg = .{
|
||||
.r = rgb.r,
|
||||
.g = rgb.g,
|
||||
.b = rgb.b,
|
||||
.rgb = .{
|
||||
.r = rgb.r,
|
||||
.g = rgb.g,
|
||||
.b = rgb.b,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
.@"8_fg" => |n| {
|
||||
self.screen.cursor.pen.attrs.has_fg = true;
|
||||
self.screen.cursor.pen.fg = self.color_palette.colors[@intFromEnum(n)];
|
||||
self.screen.cursor.pen.fg = .{ .indexed = @intFromEnum(n) };
|
||||
},
|
||||
|
||||
.@"8_bg" => |n| {
|
||||
self.screen.cursor.pen.attrs.has_bg = true;
|
||||
self.screen.cursor.pen.bg = self.color_palette.colors[@intFromEnum(n)];
|
||||
self.screen.cursor.pen.bg = .{ .indexed = @intFromEnum(n) };
|
||||
},
|
||||
|
||||
.reset_fg => self.screen.cursor.pen.attrs.has_fg = false,
|
||||
.reset_fg => self.screen.cursor.pen.fg = .none,
|
||||
|
||||
.reset_bg => self.screen.cursor.pen.attrs.has_bg = false,
|
||||
.reset_bg => self.screen.cursor.pen.bg = .none,
|
||||
|
||||
.@"8_bright_fg" => |n| {
|
||||
self.screen.cursor.pen.attrs.has_fg = true;
|
||||
self.screen.cursor.pen.fg = self.color_palette.colors[@intFromEnum(n)];
|
||||
self.screen.cursor.pen.fg = .{ .indexed = @intFromEnum(n) };
|
||||
},
|
||||
|
||||
.@"8_bright_bg" => |n| {
|
||||
self.screen.cursor.pen.attrs.has_bg = true;
|
||||
self.screen.cursor.pen.bg = self.color_palette.colors[@intFromEnum(n)];
|
||||
self.screen.cursor.pen.bg = .{ .indexed = @intFromEnum(n) };
|
||||
},
|
||||
|
||||
.@"256_fg" => |idx| {
|
||||
self.screen.cursor.pen.attrs.has_fg = true;
|
||||
self.screen.cursor.pen.fg = self.color_palette.colors[idx];
|
||||
self.screen.cursor.pen.fg = .{ .indexed = idx };
|
||||
},
|
||||
|
||||
.@"256_bg" => |idx| {
|
||||
self.screen.cursor.pen.attrs.has_bg = true;
|
||||
self.screen.cursor.pen.bg = self.color_palette.colors[idx];
|
||||
self.screen.cursor.pen.bg = .{ .indexed = idx };
|
||||
},
|
||||
|
||||
.unknown => return error.InvalidAttribute,
|
||||
@ -676,12 +672,26 @@ pub fn printAttributes(self: *Terminal, buf: []u8) ![]const u8 {
|
||||
try writer.print(";{c}", .{c});
|
||||
}
|
||||
|
||||
if (pen.attrs.has_fg) {
|
||||
try writer.print(";38:2::{[r]}:{[g]}:{[b]}", pen.fg);
|
||||
switch (pen.fg) {
|
||||
.none => {},
|
||||
.indexed => |idx| if (idx >= 16)
|
||||
try writer.print(";38:5:{}", .{idx})
|
||||
else if (idx >= 8)
|
||||
try writer.print(";9{}", .{idx - 8})
|
||||
else
|
||||
try writer.print(";3{}", .{idx}),
|
||||
.rgb => |rgb| try writer.print(";38:2::{[r]}:{[g]}:{[b]}", rgb),
|
||||
}
|
||||
|
||||
if (pen.attrs.has_bg) {
|
||||
try writer.print(";48:2::{[r]}:{[g]}:{[b]}", pen.bg);
|
||||
switch (pen.bg) {
|
||||
.none => {},
|
||||
.indexed => |idx| if (idx >= 16)
|
||||
try writer.print(";48:5:{}", .{idx})
|
||||
else if (idx >= 8)
|
||||
try writer.print(";10{}", .{idx - 8})
|
||||
else
|
||||
try writer.print(";4{}", .{idx}),
|
||||
.rgb => |rgb| try writer.print(";48:2::{[r]}:{[g]}:{[b]}", rgb),
|
||||
}
|
||||
|
||||
return stream.getWritten();
|
||||
@ -1080,8 +1090,6 @@ pub fn decaln(self: *Terminal) !void {
|
||||
.bg = self.screen.cursor.pen.bg,
|
||||
.fg = self.screen.cursor.pen.fg,
|
||||
.attrs = .{
|
||||
.has_bg = self.screen.cursor.pen.attrs.has_bg,
|
||||
.has_fg = self.screen.cursor.pen.attrs.has_fg,
|
||||
.protected = self.screen.cursor.pen.attrs.protected,
|
||||
},
|
||||
};
|
||||
@ -1229,9 +1237,9 @@ pub fn eraseDisplay(
|
||||
defer tracy.end();
|
||||
|
||||
// Erasing clears all attributes / colors _except_ the background
|
||||
const pen: Screen.Cell = if (!self.screen.cursor.pen.attrs.has_bg) .{} else .{
|
||||
.bg = self.screen.cursor.pen.bg,
|
||||
.attrs = .{ .has_bg = true },
|
||||
const pen: Screen.Cell = switch (self.screen.cursor.pen.bg) {
|
||||
.none => .{},
|
||||
else => |bg| .{ .bg = bg },
|
||||
};
|
||||
|
||||
// We respect protected attributes if explicitly requested (probably
|
||||
@ -1380,9 +1388,9 @@ pub fn eraseLine(
|
||||
defer tracy.end();
|
||||
|
||||
// We always fill with the background
|
||||
const pen: Screen.Cell = if (!self.screen.cursor.pen.attrs.has_bg) .{} else .{
|
||||
.bg = self.screen.cursor.pen.bg,
|
||||
.attrs = .{ .has_bg = true },
|
||||
const pen: Screen.Cell = switch (self.screen.cursor.pen.bg) {
|
||||
.none => .{},
|
||||
else => |bg| .{ .bg = bg },
|
||||
};
|
||||
|
||||
// Get our start/end positions depending on mode.
|
||||
@ -1470,7 +1478,6 @@ pub fn deleteChars(self: *Terminal, count: usize) !void {
|
||||
|
||||
const pen: Screen.Cell = .{
|
||||
.bg = self.screen.cursor.pen.bg,
|
||||
.attrs = .{ .has_bg = self.screen.cursor.pen.attrs.has_bg },
|
||||
};
|
||||
|
||||
// If our X is a wide spacer tail then we need to erase the
|
||||
@ -1529,7 +1536,6 @@ pub fn eraseChars(self: *Terminal, count_req: usize) void {
|
||||
|
||||
const pen: Screen.Cell = .{
|
||||
.bg = self.screen.cursor.pen.bg,
|
||||
.attrs = .{ .has_bg = self.screen.cursor.pen.attrs.has_bg },
|
||||
};
|
||||
|
||||
// If we never had a protection mode, then we can assume no cells
|
||||
@ -1873,7 +1879,6 @@ pub fn insertBlanks(self: *Terminal, count: usize) void {
|
||||
// Insert blanks. The blanks preserve the background color.
|
||||
row.fillSlice(.{
|
||||
.bg = self.screen.cursor.pen.bg,
|
||||
.attrs = .{ .has_bg = self.screen.cursor.pen.attrs.has_bg },
|
||||
}, start, pivot);
|
||||
}
|
||||
|
||||
@ -1939,7 +1944,6 @@ pub fn insertLines(self: *Terminal, count: usize) !void {
|
||||
const row = self.screen.getRow(.{ .active = y });
|
||||
row.fillSlice(.{
|
||||
.bg = self.screen.cursor.pen.bg,
|
||||
.attrs = .{ .has_bg = self.screen.cursor.pen.attrs.has_bg },
|
||||
}, self.scrolling_region.left, self.scrolling_region.right + 1);
|
||||
}
|
||||
}
|
||||
@ -2014,7 +2018,6 @@ pub fn deleteLines(self: *Terminal, count: usize) !void {
|
||||
row.setWrapped(false);
|
||||
row.fillSlice(.{
|
||||
.bg = self.screen.cursor.pen.bg,
|
||||
.attrs = .{ .has_bg = self.screen.cursor.pen.attrs.has_bg },
|
||||
}, self.scrolling_region.left, self.scrolling_region.right + 1);
|
||||
}
|
||||
}
|
||||
@ -2247,13 +2250,13 @@ test "Terminal: fullReset with a non-empty pen" {
|
||||
var t = try init(testing.allocator, 80, 80);
|
||||
defer t.deinit(testing.allocator);
|
||||
|
||||
t.screen.cursor.pen.bg = .{ .r = 0xFF, .g = 0x00, .b = 0x7F };
|
||||
t.screen.cursor.pen.fg = .{ .r = 0xFF, .g = 0x00, .b = 0x7F };
|
||||
t.screen.cursor.pen.bg = .{ .rgb = .{ .r = 0xFF, .g = 0x00, .b = 0x7F } };
|
||||
t.screen.cursor.pen.fg = .{ .rgb = .{ .r = 0xFF, .g = 0x00, .b = 0x7F } };
|
||||
t.fullReset(testing.allocator);
|
||||
|
||||
const cell = t.screen.getCell(.active, t.screen.cursor.y, t.screen.cursor.x);
|
||||
try testing.expect(cell.bg.eql(.{}));
|
||||
try testing.expect(cell.fg.eql(.{}));
|
||||
try testing.expect(cell.bg == .none);
|
||||
try testing.expect(cell.fg == .none);
|
||||
}
|
||||
|
||||
test "Terminal: fullReset origin mode" {
|
||||
@ -4165,8 +4168,7 @@ test "Terminal: index bottom of primary screen background sgr" {
|
||||
defer t.deinit(alloc);
|
||||
|
||||
const pen: Screen.Cell = .{
|
||||
.bg = .{ .r = 0xFF, .g = 0x00, .b = 0x00 },
|
||||
.attrs = .{ .has_bg = true },
|
||||
.bg = .{ .rgb = .{ .r = 0xFF, .g = 0x00, .b = 0x00 } },
|
||||
};
|
||||
|
||||
t.setCursorPos(5, 1);
|
||||
@ -4338,8 +4340,7 @@ test "Terminal: decaln preserves color" {
|
||||
defer t.deinit(alloc);
|
||||
|
||||
const pen: Screen.Cell = .{
|
||||
.bg = .{ .r = 0xFF, .g = 0x00, .b = 0x00 },
|
||||
.attrs = .{ .has_bg = true },
|
||||
.bg = .{ .rgb = .{ .r = 0xFF, .g = 0x00, .b = 0x00 } },
|
||||
};
|
||||
|
||||
// Initial value
|
||||
@ -4443,8 +4444,7 @@ test "Terminal: insertBlanks preserves background sgr" {
|
||||
defer t.deinit(alloc);
|
||||
|
||||
const pen: Screen.Cell = .{
|
||||
.bg = .{ .r = 0xFF, .g = 0x00, .b = 0x00 },
|
||||
.attrs = .{ .has_bg = true },
|
||||
.bg = .{ .rgb = .{ .r = 0xFF, .g = 0x00, .b = 0x00 } },
|
||||
};
|
||||
|
||||
for ("ABC") |c| try t.print(c);
|
||||
@ -4836,8 +4836,7 @@ test "Terminal: deleteChars background sgr" {
|
||||
defer t.deinit(alloc);
|
||||
|
||||
const pen: Screen.Cell = .{
|
||||
.bg = .{ .r = 0xFF, .g = 0x00, .b = 0x00 },
|
||||
.attrs = .{ .has_bg = true },
|
||||
.bg = .{ .rgb = .{ .r = 0xFF, .g = 0x00, .b = 0x00 } },
|
||||
};
|
||||
|
||||
try t.printString("ABC123");
|
||||
@ -5001,8 +5000,7 @@ test "Terminal: eraseChars preserves background sgr" {
|
||||
defer t.deinit(alloc);
|
||||
|
||||
const pen: Screen.Cell = .{
|
||||
.bg = .{ .r = 0xFF, .g = 0x00, .b = 0x00 },
|
||||
.attrs = .{ .has_bg = true },
|
||||
.bg = .{ .rgb = .{ .r = 0xFF, .g = 0x00, .b = 0x00 } },
|
||||
};
|
||||
|
||||
for ("ABC") |c| try t.print(c);
|
||||
@ -5312,8 +5310,7 @@ test "Terminal: eraseLine right preserves background sgr" {
|
||||
defer t.deinit(alloc);
|
||||
|
||||
const pen: Screen.Cell = .{
|
||||
.bg = .{ .r = 0xFF, .g = 0x00, .b = 0x00 },
|
||||
.attrs = .{ .has_bg = true },
|
||||
.bg = .{ .rgb = .{ .r = 0xFF, .g = 0x00, .b = 0x00 } },
|
||||
};
|
||||
|
||||
for ("ABCDE") |c| try t.print(c);
|
||||
@ -5462,8 +5459,7 @@ test "Terminal: eraseLine left preserves background sgr" {
|
||||
defer t.deinit(alloc);
|
||||
|
||||
const pen: Screen.Cell = .{
|
||||
.bg = .{ .r = 0xFF, .g = 0x00, .b = 0x00 },
|
||||
.attrs = .{ .has_bg = true },
|
||||
.bg = .{ .rgb = .{ .r = 0xFF, .g = 0x00, .b = 0x00 } },
|
||||
};
|
||||
|
||||
for ("ABCDE") |c| try t.print(c);
|
||||
@ -5578,8 +5574,7 @@ test "Terminal: eraseLine complete preserves background sgr" {
|
||||
defer t.deinit(alloc);
|
||||
|
||||
const pen: Screen.Cell = .{
|
||||
.bg = .{ .r = 0xFF, .g = 0x00, .b = 0x00 },
|
||||
.attrs = .{ .has_bg = true },
|
||||
.bg = .{ .rgb = .{ .r = 0xFF, .g = 0x00, .b = 0x00 } },
|
||||
};
|
||||
|
||||
for ("ABCDE") |c| try t.print(c);
|
||||
@ -5707,8 +5702,7 @@ test "Terminal: eraseDisplay erase below preserves SGR bg" {
|
||||
t.setCursorPos(2, 2);
|
||||
|
||||
const pen: Screen.Cell = .{
|
||||
.bg = .{ .r = 0xFF, .g = 0x00, .b = 0x00 },
|
||||
.attrs = .{ .has_bg = true },
|
||||
.bg = .{ .rgb = .{ .r = 0xFF, .g = 0x00, .b = 0x00 } },
|
||||
};
|
||||
|
||||
t.screen.cursor.pen = pen;
|
||||
@ -5878,8 +5872,7 @@ test "Terminal: eraseDisplay erase above preserves SGR bg" {
|
||||
t.setCursorPos(2, 2);
|
||||
|
||||
const pen: Screen.Cell = .{
|
||||
.bg = .{ .r = 0xFF, .g = 0x00, .b = 0x00 },
|
||||
.attrs = .{ .has_bg = true },
|
||||
.bg = .{ .rgb = .{ .r = 0xFF, .g = 0x00, .b = 0x00 } },
|
||||
};
|
||||
|
||||
t.screen.cursor.pen = pen;
|
||||
@ -6018,16 +6011,16 @@ test "Terminal: eraseDisplay above" {
|
||||
const pink = color.RGB{ .r = 0xFF, .g = 0x00, .b = 0x7F };
|
||||
t.screen.cursor.pen = Screen.Cell{
|
||||
.char = 'a',
|
||||
.bg = pink,
|
||||
.fg = pink,
|
||||
.attrs = .{ .bold = true, .has_bg = true },
|
||||
.bg = .{ .rgb = pink },
|
||||
.fg = .{ .rgb = pink },
|
||||
.attrs = .{ .bold = true },
|
||||
};
|
||||
const cell_ptr = t.screen.getCellPtr(.active, 0, 0);
|
||||
cell_ptr.* = t.screen.cursor.pen;
|
||||
// verify the cell was set
|
||||
var cell = t.screen.getCell(.active, 0, 0);
|
||||
try testing.expect(cell.bg.eql(pink));
|
||||
try testing.expect(cell.fg.eql(pink));
|
||||
try testing.expect(cell.bg.rgb.eql(pink));
|
||||
try testing.expect(cell.fg.rgb.eql(pink));
|
||||
try testing.expect(cell.char == 'a');
|
||||
try testing.expect(cell.attrs.bold);
|
||||
// move the cursor below it
|
||||
@ -6037,18 +6030,17 @@ test "Terminal: eraseDisplay above" {
|
||||
t.eraseDisplay(testing.allocator, .above, false);
|
||||
// check it was erased
|
||||
cell = t.screen.getCell(.active, 0, 0);
|
||||
try testing.expect(cell.bg.eql(pink));
|
||||
try testing.expect(cell.fg.eql(.{}));
|
||||
try testing.expect(cell.bg.rgb.eql(pink));
|
||||
try testing.expect(cell.fg == .none);
|
||||
try testing.expect(cell.char == 0);
|
||||
try testing.expect(!cell.attrs.bold);
|
||||
try testing.expect(cell.attrs.has_bg);
|
||||
|
||||
// Check that our pen hasn't changed
|
||||
try testing.expect(t.screen.cursor.pen.attrs.bold);
|
||||
|
||||
// check that another cell got the correct bg
|
||||
cell = t.screen.getCell(.active, 0, 1);
|
||||
try testing.expect(cell.bg.eql(pink));
|
||||
try testing.expect(cell.bg.rgb.eql(pink));
|
||||
}
|
||||
|
||||
test "Terminal: eraseDisplay below" {
|
||||
@ -6058,31 +6050,30 @@ test "Terminal: eraseDisplay below" {
|
||||
const pink = color.RGB{ .r = 0xFF, .g = 0x00, .b = 0x7F };
|
||||
t.screen.cursor.pen = Screen.Cell{
|
||||
.char = 'a',
|
||||
.bg = pink,
|
||||
.fg = pink,
|
||||
.attrs = .{ .bold = true, .has_bg = true },
|
||||
.bg = .{ .rgb = pink },
|
||||
.fg = .{ .rgb = pink },
|
||||
.attrs = .{ .bold = true },
|
||||
};
|
||||
const cell_ptr = t.screen.getCellPtr(.active, 60, 60);
|
||||
cell_ptr.* = t.screen.cursor.pen;
|
||||
// verify the cell was set
|
||||
var cell = t.screen.getCell(.active, 60, 60);
|
||||
try testing.expect(cell.bg.eql(pink));
|
||||
try testing.expect(cell.fg.eql(pink));
|
||||
try testing.expect(cell.bg.rgb.eql(pink));
|
||||
try testing.expect(cell.fg.rgb.eql(pink));
|
||||
try testing.expect(cell.char == 'a');
|
||||
try testing.expect(cell.attrs.bold);
|
||||
// erase below the cursor
|
||||
t.eraseDisplay(testing.allocator, .below, false);
|
||||
// check it was erased
|
||||
cell = t.screen.getCell(.active, 60, 60);
|
||||
try testing.expect(cell.bg.eql(pink));
|
||||
try testing.expect(cell.fg.eql(.{}));
|
||||
try testing.expect(cell.bg.rgb.eql(pink));
|
||||
try testing.expect(cell.fg == .none);
|
||||
try testing.expect(cell.char == 0);
|
||||
try testing.expect(!cell.attrs.bold);
|
||||
try testing.expect(cell.attrs.has_bg);
|
||||
|
||||
// check that another cell got the correct bg
|
||||
cell = t.screen.getCell(.active, 0, 1);
|
||||
try testing.expect(cell.bg.eql(pink));
|
||||
try testing.expect(cell.bg.rgb.eql(pink));
|
||||
}
|
||||
|
||||
test "Terminal: eraseDisplay complete" {
|
||||
@ -6092,9 +6083,9 @@ test "Terminal: eraseDisplay complete" {
|
||||
const pink = color.RGB{ .r = 0xFF, .g = 0x00, .b = 0x7F };
|
||||
t.screen.cursor.pen = Screen.Cell{
|
||||
.char = 'a',
|
||||
.bg = pink,
|
||||
.fg = pink,
|
||||
.attrs = .{ .bold = true, .has_bg = true },
|
||||
.bg = .{ .rgb = pink },
|
||||
.fg = .{ .rgb = pink },
|
||||
.attrs = .{ .bold = true },
|
||||
};
|
||||
var cell_ptr = t.screen.getCellPtr(.active, 60, 60);
|
||||
cell_ptr.* = t.screen.cursor.pen;
|
||||
@ -6102,14 +6093,14 @@ test "Terminal: eraseDisplay complete" {
|
||||
cell_ptr.* = t.screen.cursor.pen;
|
||||
// verify the cell was set
|
||||
var cell = t.screen.getCell(.active, 60, 60);
|
||||
try testing.expect(cell.bg.eql(pink));
|
||||
try testing.expect(cell.fg.eql(pink));
|
||||
try testing.expect(cell.bg.rgb.eql(pink));
|
||||
try testing.expect(cell.fg.rgb.eql(pink));
|
||||
try testing.expect(cell.char == 'a');
|
||||
try testing.expect(cell.attrs.bold);
|
||||
// verify the cell was set
|
||||
cell = t.screen.getCell(.active, 0, 0);
|
||||
try testing.expect(cell.bg.eql(pink));
|
||||
try testing.expect(cell.fg.eql(pink));
|
||||
try testing.expect(cell.bg.rgb.eql(pink));
|
||||
try testing.expect(cell.fg.rgb.eql(pink));
|
||||
try testing.expect(cell.char == 'a');
|
||||
try testing.expect(cell.attrs.bold);
|
||||
// position our cursor between the cells
|
||||
@ -6118,17 +6109,15 @@ test "Terminal: eraseDisplay complete" {
|
||||
t.eraseDisplay(testing.allocator, .complete, false);
|
||||
// check they were erased
|
||||
cell = t.screen.getCell(.active, 60, 60);
|
||||
try testing.expect(cell.bg.eql(pink));
|
||||
try testing.expect(cell.fg.eql(.{}));
|
||||
try testing.expect(cell.bg.rgb.eql(pink));
|
||||
try testing.expect(cell.fg == .none);
|
||||
try testing.expect(cell.char == 0);
|
||||
try testing.expect(!cell.attrs.bold);
|
||||
try testing.expect(cell.attrs.has_bg);
|
||||
cell = t.screen.getCell(.active, 0, 0);
|
||||
try testing.expect(cell.bg.eql(pink));
|
||||
try testing.expect(cell.fg.eql(.{}));
|
||||
try testing.expect(cell.bg.rgb.eql(pink));
|
||||
try testing.expect(cell.fg == .none);
|
||||
try testing.expect(cell.char == 0);
|
||||
try testing.expect(!cell.attrs.bold);
|
||||
try testing.expect(cell.attrs.has_bg);
|
||||
}
|
||||
|
||||
test "Terminal: eraseDisplay protected complete" {
|
||||
@ -7041,8 +7030,7 @@ test "Terminal: DECCOLM preserves SGR bg" {
|
||||
defer t.deinit(alloc);
|
||||
|
||||
const pen: Screen.Cell = .{
|
||||
.bg = .{ .r = 0xFF, .g = 0x00, .b = 0x00 },
|
||||
.attrs = .{ .has_bg = true },
|
||||
.bg = .{ .rgb = .{ .r = 0xFF, .g = 0x00, .b = 0x00 } },
|
||||
};
|
||||
|
||||
t.screen.cursor.pen = pen;
|
||||
|
Reference in New Issue
Block a user