terminal/new: decaln

This commit is contained in:
Mitchell Hashimoto
2024-02-26 14:17:16 -08:00
parent d38e075a7c
commit dfd46a850b
3 changed files with 130 additions and 0 deletions

View File

@ -4521,6 +4521,7 @@ test "Terminal: index inside left/right margin" {
}
}
// X
test "Terminal: DECALN" {
const alloc = testing.allocator;
var t = try init(alloc, 2, 2);
@ -4543,6 +4544,7 @@ test "Terminal: DECALN" {
}
}
// X
test "Terminal: decaln reset margins" {
const alloc = testing.allocator;
var t = try init(alloc, 3, 3);
@ -4561,6 +4563,7 @@ test "Terminal: decaln reset margins" {
}
}
// X
test "Terminal: decaln preserves color" {
const alloc = testing.allocator;
var t = try init(alloc, 3, 3);

View File

@ -394,6 +394,11 @@ pub fn setAttribute(self: *Screen, attr: sgr.Attribute) !void {
.unknown => return,
}
try self.manualStyleUpdate();
}
/// Call this whenever you manually change the cursor style.
pub fn manualStyleUpdate(self: *Screen) !void {
var page = &self.cursor.page_offset.page.data;
// Remove our previous style if is unused.

View File

@ -1333,6 +1333,59 @@ fn blankCells(
@memset(cells, self.blankCell());
}
/// Resets all margins and fills the whole screen with the character 'E'
///
/// Sets the cursor to the top left corner.
pub fn decaln(self: *Terminal) !void {
// TODO: erase display to gc graphemes, styles
// Clear our stylistic attributes. This is the only thing that can
// fail so we do it first so we can undo it.
const old_style = self.screen.cursor.style;
self.screen.cursor.style = .{
.bg_color = self.screen.cursor.style.bg_color,
.fg_color = self.screen.cursor.style.fg_color,
// TODO: protected attribute
// .protected = self.screen.cursor.pen.attrs.protected,
};
errdefer self.screen.cursor.style = old_style;
try self.screen.manualStyleUpdate();
// Reset margins, also sets cursor to top-left
self.scrolling_region = .{
.top = 0,
.bottom = self.rows - 1,
.left = 0,
.right = self.cols - 1,
};
// Origin mode is disabled
self.modes.set(.origin, false);
// Move our cursor to the top-left
self.setCursorPos(1, 1);
// Fill with Es, does not move cursor.
// TODO: cursor across pages
var page = &self.screen.cursor.page_offset.page.data;
const rows: [*]Row = @ptrCast(self.screen.cursor.page_row);
for (0..self.rows) |y| {
const row: *Row = @ptrCast(rows + y);
const cells = page.getCells(row);
@memset(cells, .{
.content_tag = .codepoint,
.content = .{ .codepoint = 'E' },
.style_id = self.screen.cursor.style_id,
});
// If we have a ref-counted style, increase
if (self.screen.cursor.style_ref) |ref| {
ref.* += @intCast(cells.len);
row.styled = true;
}
}
}
/// Set a style attribute.
pub fn setAttribute(self: *Terminal, attr: sgr.Attribute) !void {
try self.screen.setAttribute(attr);
@ -4586,3 +4639,72 @@ test "Terminal: print with style marks the row as styled" {
try testing.expect(list_cell.row.styled);
}
}
test "Terminal: DECALN" {
const alloc = testing.allocator;
var t = try init(alloc, 2, 2);
defer t.deinit(alloc);
// Initial value
try t.print('A');
t.carriageReturn();
try t.linefeed();
try t.print('B');
try t.decaln();
try testing.expectEqual(@as(usize, 0), t.screen.cursor.y);
try testing.expectEqual(@as(usize, 0), t.screen.cursor.x);
{
const str = try t.plainString(testing.allocator);
defer testing.allocator.free(str);
try testing.expectEqualStrings("EE\nEE", str);
}
}
test "Terminal: decaln reset margins" {
const alloc = testing.allocator;
var t = try init(alloc, 3, 3);
defer t.deinit(alloc);
// Initial value
t.modes.set(.origin, true);
t.setTopAndBottomMargin(2, 3);
try t.decaln();
t.scrollDown(1);
{
const str = try t.plainString(testing.allocator);
defer testing.allocator.free(str);
try testing.expectEqualStrings("\nEEE\nEEE", str);
}
}
test "Terminal: decaln preserves color" {
const alloc = testing.allocator;
var t = try init(alloc, 3, 3);
defer t.deinit(alloc);
// Initial value
try t.setAttribute(.{ .direct_color_bg = .{ .r = 0xFF, .g = 0, .b = 0 } });
t.modes.set(.origin, true);
t.setTopAndBottomMargin(2, 3);
try t.decaln();
t.scrollDown(1);
{
const str = try t.plainString(testing.allocator);
defer testing.allocator.free(str);
try testing.expectEqualStrings("\nEEE\nEEE", 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);
}
}