mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
terminal/new: erase according to bg sgr
This commit is contained in:
@ -4373,6 +4373,7 @@ test "Terminal: index bottom of primary screen" {
|
||||
}
|
||||
}
|
||||
|
||||
// X
|
||||
test "Terminal: index bottom of primary screen background sgr" {
|
||||
const alloc = testing.allocator;
|
||||
var t = try init(alloc, 5, 5);
|
||||
@ -5241,6 +5242,7 @@ test "Terminal: eraseChars beyond screen edge" {
|
||||
}
|
||||
}
|
||||
|
||||
// X
|
||||
test "Terminal: eraseChars preserves background sgr" {
|
||||
const alloc = testing.allocator;
|
||||
var t = try init(alloc, 10, 10);
|
||||
|
@ -8,6 +8,7 @@ const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const point = @import("point.zig");
|
||||
const pagepkg = @import("page.zig");
|
||||
const stylepkg = @import("style.zig");
|
||||
const size = @import("size.zig");
|
||||
const OffsetBuf = size.OffsetBuf;
|
||||
const Page = pagepkg.Page;
|
||||
@ -488,13 +489,24 @@ const Cell = struct {
|
||||
row_idx: usize,
|
||||
col_idx: usize,
|
||||
|
||||
/// Get the cell style.
|
||||
///
|
||||
/// Not meant for non-test usage since this is inefficient.
|
||||
pub fn style(self: Cell) stylepkg.Style {
|
||||
if (self.cell.style_id == stylepkg.default_id) return .{};
|
||||
return self.page.data.styles.lookupId(
|
||||
self.page.data.memory,
|
||||
self.cell.style_id,
|
||||
).?.*;
|
||||
}
|
||||
|
||||
/// Gets the screen point for the given cell.
|
||||
///
|
||||
/// This is REALLY expensive/slow so it isn't pub. This was built
|
||||
/// for debugging and tests. If you have a need for this outside of
|
||||
/// this file then consider a different approach and ask yourself very
|
||||
/// carefully if you really need this.
|
||||
fn screenPoint(self: Cell) point.Point {
|
||||
pub fn screenPoint(self: Cell) point.Point {
|
||||
var x: usize = self.col_idx;
|
||||
var y: usize = self.row_idx;
|
||||
var page = self.page;
|
||||
|
@ -199,10 +199,10 @@ pub fn cursorAbsolute(self: *Screen, x: size.CellCountInt, y: size.CellCountInt)
|
||||
pub fn cursorDownScroll(self: *Screen) !void {
|
||||
assert(self.cursor.y == self.pages.rows - 1);
|
||||
|
||||
// If we have cap space in our current cursor page then we can take
|
||||
// a fast path: update the size, recalculate the row/cell cursor pointers.
|
||||
const cursor_page = self.cursor.page_offset.page;
|
||||
if (cursor_page.data.capacity.rows > cursor_page.data.size.rows) {
|
||||
// If we have cap space in our current cursor page then we can take
|
||||
// a fast path: update the size, recalculate the row/cell cursor pointers.
|
||||
cursor_page.data.size.rows += 1;
|
||||
|
||||
const page_offset = self.cursor.page_offset.forward(1).?;
|
||||
@ -210,12 +210,8 @@ pub fn cursorDownScroll(self: *Screen) !void {
|
||||
self.cursor.page_offset = page_offset;
|
||||
self.cursor.page_row = page_rac.row;
|
||||
self.cursor.page_cell = page_rac.cell;
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
// No space, we need to allocate a new page and move the cursor to it.
|
||||
// TODO: copy style over
|
||||
|
||||
const new_page = try self.pages.grow();
|
||||
assert(new_page.data.size.rows == 0);
|
||||
new_page.data.size.rows = 1;
|
||||
@ -227,6 +223,17 @@ pub fn cursorDownScroll(self: *Screen) !void {
|
||||
self.cursor.page_offset = page_offset;
|
||||
self.cursor.page_row = page_rac.row;
|
||||
self.cursor.page_cell = page_rac.cell;
|
||||
}
|
||||
|
||||
// The newly created line needs to be styled according to the bg color
|
||||
// if it is set.
|
||||
if (self.cursor.style_id != style.default_id) {
|
||||
if (self.cursor.style.bgCell()) |blank_cell| {
|
||||
const cell_current: [*]pagepkg.Cell = @ptrCast(self.cursor.page_cell);
|
||||
const cells = cell_current - self.cursor.x;
|
||||
@memset(cells[0..self.pages.cols], blank_cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Options for scrolling the viewport of the terminal grid. The reason
|
||||
|
@ -1084,6 +1084,8 @@ pub fn insertLines(self: *Terminal, count: usize) void {
|
||||
}
|
||||
}
|
||||
|
||||
// Inserted lines should keep our bg color
|
||||
const blank_cell = self.blankCell();
|
||||
for (0..adjusted_count) |i| {
|
||||
const row: *Row = @ptrCast(top + i);
|
||||
|
||||
@ -1100,8 +1102,7 @@ pub fn insertLines(self: *Terminal, count: usize) void {
|
||||
assert(!row.grapheme);
|
||||
}
|
||||
|
||||
// TODO: cells should keep bg style of pen
|
||||
@memset(cells, .{});
|
||||
@memset(cells, blank_cell);
|
||||
}
|
||||
|
||||
// Move the cursor to the left margin. But importantly this also
|
||||
@ -1177,6 +1178,7 @@ pub fn deleteLines(self: *Terminal, count_req: usize) void {
|
||||
}
|
||||
|
||||
const bottom: [*]Row = top + (rem - 1);
|
||||
const blank_cell = self.blankCell();
|
||||
while (@intFromPtr(y) <= @intFromPtr(bottom)) : (y += 1) {
|
||||
const row: *Row = @ptrCast(y);
|
||||
|
||||
@ -1193,8 +1195,7 @@ pub fn deleteLines(self: *Terminal, count_req: usize) void {
|
||||
assert(!row.grapheme);
|
||||
}
|
||||
|
||||
// TODO: cells should keep bg style of pen
|
||||
@memset(cells, .{});
|
||||
@memset(cells, blank_cell);
|
||||
}
|
||||
|
||||
// Move the cursor to the left margin. But importantly this also
|
||||
@ -1230,9 +1231,8 @@ pub fn eraseChars(self: *Terminal, count_req: usize) void {
|
||||
};
|
||||
|
||||
// Clear the cells
|
||||
// TODO: clear with current bg color
|
||||
const cells: [*]Cell = @ptrCast(self.screen.cursor.page_cell);
|
||||
@memset(cells[0..end], .{});
|
||||
@memset(cells[0..end], self.blankCell());
|
||||
|
||||
// This resets the soft-wrap of this line
|
||||
self.screen.cursor.page_row.wrap = false;
|
||||
@ -1275,6 +1275,13 @@ pub fn plainString(self: *Terminal, alloc: Allocator) ![]const u8 {
|
||||
return try self.screen.dumpStringAlloc(alloc, .{ .viewport = .{} });
|
||||
}
|
||||
|
||||
/// Returns the blank cell to use when doing terminal operations that
|
||||
/// require preserving the bg color.
|
||||
fn blankCell(self: *const Terminal) Cell {
|
||||
if (self.screen.cursor.style_id == style.default_id) return .{};
|
||||
return self.screen.cursor.style.bgCell() orelse .{};
|
||||
}
|
||||
|
||||
test "Terminal: input with no control characters" {
|
||||
const alloc = testing.allocator;
|
||||
var t = try init(alloc, 40, 40);
|
||||
@ -2475,6 +2482,44 @@ test "Terminal: insertLines simple" {
|
||||
}
|
||||
}
|
||||
|
||||
test "Terminal: insertLines colors with bg color" {
|
||||
const alloc = testing.allocator;
|
||||
var t = try init(alloc, 5, 5);
|
||||
defer t.deinit(alloc);
|
||||
|
||||
try t.printString("ABC");
|
||||
t.carriageReturn();
|
||||
try t.linefeed();
|
||||
try t.printString("DEF");
|
||||
t.carriageReturn();
|
||||
try t.linefeed();
|
||||
try t.printString("GHI");
|
||||
t.setCursorPos(2, 2);
|
||||
|
||||
try t.setAttribute(.{ .direct_color_bg = .{
|
||||
.r = 0xFF,
|
||||
.g = 0,
|
||||
.b = 0,
|
||||
} });
|
||||
t.insertLines(1);
|
||||
|
||||
{
|
||||
const str = try t.plainString(testing.allocator);
|
||||
defer testing.allocator.free(str);
|
||||
try testing.expectEqualStrings("ABC\n\nDEF\nGHI", str);
|
||||
}
|
||||
|
||||
for (0..t.cols) |x| {
|
||||
const list_cell = t.screen.pages.getCell(.{ .active = .{ .x = x, .y = 1 } }).?;
|
||||
try testing.expect(list_cell.cell.content_tag == .bg_color_rgb);
|
||||
try testing.expectEqual(Cell.RGB{
|
||||
.r = 0xFF,
|
||||
.g = 0,
|
||||
.b = 0,
|
||||
}, list_cell.cell.content.color_rgb);
|
||||
}
|
||||
}
|
||||
|
||||
test "Terminal: insertLines outside of scroll region" {
|
||||
const alloc = testing.allocator;
|
||||
var t = try init(alloc, 5, 5);
|
||||
@ -2958,6 +3003,45 @@ test "Terminal: eraseChars resets wrap" {
|
||||
}
|
||||
}
|
||||
|
||||
test "Terminal: eraseChars preserves background sgr" {
|
||||
const alloc = testing.allocator;
|
||||
var t = try init(alloc, 10, 10);
|
||||
defer t.deinit(alloc);
|
||||
|
||||
for ("ABC") |c| try t.print(c);
|
||||
t.setCursorPos(1, 1);
|
||||
try t.setAttribute(.{ .direct_color_bg = .{
|
||||
.r = 0xFF,
|
||||
.g = 0,
|
||||
.b = 0,
|
||||
} });
|
||||
t.eraseChars(2);
|
||||
|
||||
{
|
||||
const str = try t.plainString(testing.allocator);
|
||||
defer testing.allocator.free(str);
|
||||
try testing.expectEqualStrings(" C", str);
|
||||
{
|
||||
const list_cell = t.screen.pages.getCell(.{ .active = .{ .x = 0, .y = 0 } }).?;
|
||||
try testing.expect(list_cell.cell.content_tag == .bg_color_rgb);
|
||||
try testing.expectEqual(Cell.RGB{
|
||||
.r = 0xFF,
|
||||
.g = 0,
|
||||
.b = 0,
|
||||
}, list_cell.cell.content.color_rgb);
|
||||
}
|
||||
{
|
||||
const list_cell = t.screen.pages.getCell(.{ .active = .{ .x = 1, .y = 0 } }).?;
|
||||
try testing.expect(list_cell.cell.content_tag == .bg_color_rgb);
|
||||
try testing.expectEqual(Cell.RGB{
|
||||
.r = 0xFF,
|
||||
.g = 0,
|
||||
.b = 0,
|
||||
}, list_cell.cell.content.color_rgb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test "Terminal: reverseIndex" {
|
||||
const alloc = testing.allocator;
|
||||
var t = try init(alloc, 2, 5);
|
||||
@ -3231,6 +3315,36 @@ test "Terminal: index bottom of primary screen" {
|
||||
}
|
||||
}
|
||||
|
||||
test "Terminal: index bottom of primary screen background sgr" {
|
||||
const alloc = testing.allocator;
|
||||
var t = try init(alloc, 5, 5);
|
||||
defer t.deinit(alloc);
|
||||
|
||||
t.setCursorPos(5, 1);
|
||||
try t.print('A');
|
||||
try t.setAttribute(.{ .direct_color_bg = .{
|
||||
.r = 0xFF,
|
||||
.g = 0,
|
||||
.b = 0,
|
||||
} });
|
||||
try t.index();
|
||||
|
||||
{
|
||||
const str = try t.plainString(testing.allocator);
|
||||
defer testing.allocator.free(str);
|
||||
try testing.expectEqualStrings("\n\n\nA", str);
|
||||
for (0..5) |x| {
|
||||
const list_cell = t.screen.pages.getCell(.{ .active = .{ .x = x, .y = 4 } }).?;
|
||||
try testing.expect(list_cell.cell.content_tag == .bg_color_rgb);
|
||||
try testing.expectEqual(Cell.RGB{
|
||||
.r = 0xFF,
|
||||
.g = 0,
|
||||
.b = 0,
|
||||
}, list_cell.cell.content.color_rgb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test "Terminal: index inside scroll region" {
|
||||
const alloc = testing.allocator;
|
||||
var t = try init(alloc, 5, 5);
|
||||
@ -3794,6 +3908,44 @@ test "Terminal: deleteLines simple" {
|
||||
}
|
||||
}
|
||||
|
||||
test "Terminal: deleteLines colors with bg color" {
|
||||
const alloc = testing.allocator;
|
||||
var t = try init(alloc, 5, 5);
|
||||
defer t.deinit(alloc);
|
||||
|
||||
try t.printString("ABC");
|
||||
t.carriageReturn();
|
||||
try t.linefeed();
|
||||
try t.printString("DEF");
|
||||
t.carriageReturn();
|
||||
try t.linefeed();
|
||||
try t.printString("GHI");
|
||||
t.setCursorPos(2, 2);
|
||||
|
||||
try t.setAttribute(.{ .direct_color_bg = .{
|
||||
.r = 0xFF,
|
||||
.g = 0,
|
||||
.b = 0,
|
||||
} });
|
||||
t.deleteLines(1);
|
||||
|
||||
{
|
||||
const str = try t.plainString(testing.allocator);
|
||||
defer testing.allocator.free(str);
|
||||
try testing.expectEqualStrings("ABC\nGHI", str);
|
||||
}
|
||||
|
||||
for (0..t.cols) |x| {
|
||||
const list_cell = t.screen.pages.getCell(.{ .active = .{ .x = x, .y = 4 } }).?;
|
||||
try testing.expect(list_cell.cell.content_tag == .bg_color_rgb);
|
||||
try testing.expectEqual(Cell.RGB{
|
||||
.r = 0xFF,
|
||||
.g = 0,
|
||||
.b = 0,
|
||||
}, list_cell.cell.content.color_rgb);
|
||||
}
|
||||
}
|
||||
|
||||
test "Terminal: deleteLines (legacy)" {
|
||||
const alloc = testing.allocator;
|
||||
var t = try init(alloc, 80, 80);
|
||||
|
@ -51,6 +51,25 @@ pub const Style = struct {
|
||||
return std.mem.eql(u8, std.mem.asBytes(&self), def);
|
||||
}
|
||||
|
||||
/// Returns a bg-color only cell from this style, if it exists.
|
||||
pub fn bgCell(self: Style) ?page.Cell {
|
||||
return switch (self.bg_color) {
|
||||
.none => null,
|
||||
.palette => |idx| .{
|
||||
.content_tag = .bg_color_palette,
|
||||
.content = .{ .color_palette = idx },
|
||||
},
|
||||
.rgb => |rgb| .{
|
||||
.content_tag = .bg_color_rgb,
|
||||
.content = .{ .color_rgb = .{
|
||||
.r = rgb.r,
|
||||
.g = rgb.g,
|
||||
.b = rgb.b,
|
||||
} },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
test {
|
||||
// The size of the struct so we can be aware of changes.
|
||||
const testing = std.testing;
|
||||
|
Reference in New Issue
Block a user