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
|
// 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