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