implement delete line

This commit is contained in:
Mitchell Hashimoto
2022-05-11 17:53:55 -07:00
parent 12ee4ea7e8
commit 8a0d7a3494
3 changed files with 117 additions and 1 deletions

14
conformance/csi_dl.zig Normal file
View File

@ -0,0 +1,14 @@
//! Delete Line (DL) - Esc [ M
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
try stdout.print("A\nB\nC\nD", .{});
try stdout.print("\x1B[2A", .{}); // cursor up
try stdout.print("\x1B[M", .{});
try stdout.print("E\n", .{});
try stdout.print("\x1B[B", .{});
// const stdin = std.io.getStdIn().reader();
// _ = try stdin.readByte();
}

View File

@ -394,6 +394,45 @@ pub fn linefeed(self: *Terminal, alloc: Allocator) void {
self.cursor.y += 1; self.cursor.y += 1;
} }
/// Removes amount lines from the current cursor row down. The remaining lines
/// to the bottom margin are shifted up and space from the bottom margin up is
/// filled with empty lines.
///
/// If the current cursor position is outside of the current scroll region it
/// does nothing. If amount is greater than the remaining number of lines in the
/// scrolling region it is adjusted down.
///
/// In left and right margin mode the margins are respected; lines are only
/// scrolled in the scroll region.
///
/// If the cell movement splits a multi cell character that character cleared,
/// by replacing it by spaces, keeping its current attributes. All other
/// cleared space is colored according to the current SGR state.
///
/// Moves the cursor to the left margin.
pub fn deleteLines(self: *Terminal, alloc: Allocator, count: usize) void {
// TODO: scroll region bounds
// Move the cursor to the left margin
self.cursor.x = 0;
// Remaining number of lines in the scrolling region
const rem = self.scrolling_region.bottom - self.cursor.y;
// If the count is more than our remaining lines, we adjust down.
const count2 = @minimum(count, rem);
// Scroll up the count amount.
var i: usize = 0;
while (i < count2) : (i += 1) {
self.scrollUpRegion(
alloc,
self.cursor.y,
self.scrolling_region.bottom,
);
}
}
/// Scroll the text up by one row. /// Scroll the text up by one row.
pub fn scrollUp(self: *Terminal, alloc: Allocator) void { pub fn scrollUp(self: *Terminal, alloc: Allocator) void {
const tracy = trace(@src()); const tracy = trace(@src());
@ -414,6 +453,38 @@ pub fn scrollUp(self: *Terminal, alloc: Allocator) void {
self.screen.items.len -= 1; self.screen.items.len -= 1;
} }
/// Scroll the given region up.
///
/// Top and bottom are 0-indexed.
fn scrollUpRegion(
self: *Terminal,
alloc: Allocator,
top: usize,
bottom: usize,
) void {
const tracy = trace(@src());
defer tracy.end();
// If we have no items, scrolling does nothing.
if (self.screen.items.len <= top) return;
// Clear the first line
self.screen.items[top].deinit(alloc);
// Only go to the end of the region OR the end of our lines.
const end = @minimum(bottom, self.screen.items.len - 1);
var i: usize = top;
while (i < end) : (i += 1) {
self.screen.items[i] = self.screen.items[i + 1];
}
// Blank our last line if we have space.
if (i < self.screen.items.len) {
self.screen.items[i] = .{};
}
}
/// Scroll the text down by one row. /// Scroll the text down by one row.
/// TODO: test /// TODO: test
pub fn scrollDown(self: *Terminal, alloc: Allocator) !void { pub fn scrollDown(self: *Terminal, alloc: Allocator) !void {
@ -602,3 +673,34 @@ test "Terminal: setScrollingRegion" {
try testing.expectEqual(@as(usize, 0), t.scrolling_region.top); try testing.expectEqual(@as(usize, 0), t.scrolling_region.top);
try testing.expectEqual(@as(usize, t.rows - 1), t.scrolling_region.bottom); try testing.expectEqual(@as(usize, t.rows - 1), t.scrolling_region.bottom);
} }
test "Terminal: setScrollingRegion" {
const alloc = testing.allocator;
var t = try init(alloc, 80, 80);
defer t.deinit(alloc);
// Initial value
try t.print(alloc, 'A');
t.carriageReturn();
t.linefeed(alloc);
try t.print(alloc, 'B');
t.carriageReturn();
t.linefeed(alloc);
try t.print(alloc, 'C');
t.carriageReturn();
t.linefeed(alloc);
try t.print(alloc, 'D');
t.cursorUp(2);
t.deleteLines(alloc, 1);
try t.print(alloc, 'E');
t.carriageReturn();
t.linefeed(alloc);
{
var str = try t.plainString(testing.allocator);
defer testing.allocator.free(str);
try testing.expectEqualStrings("A\nE\nD\n", str);
}
}

View File

@ -47,7 +47,7 @@ pub fn Stream(comptime Handler: type) type {
//log.debug("char: {}", .{c}); //log.debug("char: {}", .{c});
const actions = self.parser.next(c); const actions = self.parser.next(c);
for (actions) |action_opt| { for (actions) |action_opt| {
//if (action_opt) |action| log.info("action: {}", .{action}); if (action_opt) |action| log.info("action: {}", .{action});
switch (action_opt orelse continue) { switch (action_opt orelse continue) {
.print => |p| if (@hasDecl(T, "print")) try self.handler.print(p), .print => |p| if (@hasDecl(T, "print")) try self.handler.print(p),
.execute => |code| try self.execute(code), .execute => |code| try self.execute(code),