From 0cd57fe0f5e00303c80f8b0fe8add0805671c97c Mon Sep 17 00:00:00 2001 From: Tim Culverhouse Date: Mon, 10 Jun 2024 08:59:00 -0500 Subject: [PATCH] widgets(terminal): implement many more CSI seqs --- src/widgets/terminal/Screen.zig | 63 ++++++++++++++++++++++++- src/widgets/terminal/Terminal.zig | 77 +++++++++++++++++++++++++++++-- 2 files changed, 134 insertions(+), 6 deletions(-) diff --git a/src/widgets/terminal/Screen.zig b/src/widgets/terminal/Screen.zig index ddc9531..267a5b4 100644 --- a/src/widgets/terminal/Screen.zig +++ b/src/widgets/terminal/Screen.zig @@ -368,7 +368,27 @@ pub fn eraseRight(self: *Screen) void { } } -/// delete n lines from te bottom of te scrolling region +pub fn eraseLeft(self: *Screen) void { + self.cursor.pending_wrap = false; + const start = self.cursor.row * self.width; + const end = start + self.cursor.col; + var i = start; + while (i < end) : (i += 1) { + self.buf[i].erase(self.cursor.style.bg); + } +} + +pub fn eraseLine(self: *Screen) void { + self.cursor.pending_wrap = false; + const start = self.cursor.row * self.width; + const end = start + self.width; + var i = start; + while (i < end) : (i += 1) { + self.buf[i].erase(self.cursor.style.bg); + } +} + +/// delete n lines from the bottom of the scrolling region pub fn deleteLine(self: *Screen, n: usize) !void { if (n == 0) return; @@ -419,3 +439,44 @@ pub fn insertLine(self: *Screen, n: usize) !void { } } } + +pub fn eraseBelow(self: *Screen) void { + self.eraseRight(); + // start is the first column of the row below us + const start = (self.cursor.row * self.width) + (self.width); + var i = start; + while (i < self.buf.len) : (i += 1) { + self.buf[i].erase(self.cursor.style.bg); + } +} + +pub fn eraseAbove(self: *Screen) void { + self.eraseLeft(); + // start is the first column of the row below us + const start: usize = 0; + const end = self.cursor.row * self.width; + var i = start; + while (i < end) : (i += 1) { + self.buf[i].erase(self.cursor.style.bg); + } +} + +pub fn eraseAll(self: *Screen) void { + var i: usize = 0; + while (i < self.buf.len) : (i += 1) { + self.buf[i].erase(self.cursor.style.bg); + } +} + +pub fn deleteCharacters(self: *Screen, n: usize) !void { + if (!self.withinScrollingRegion()) return; + + self.cursor.pending_wrap = false; + var col = self.cursor.col; + while (col <= self.scrolling_region.right) : (col += 1) { + if (col + n <= self.scrolling_region.right) + try self.buf[col].copyFrom(self.buf[col + n]) + else + self.buf[col].erase(self.cursor.style.bg); + } +} diff --git a/src/widgets/terminal/Terminal.zig b/src/widgets/terminal/Terminal.zig index e01a555..bd3a8f5 100644 --- a/src/widgets/terminal/Terminal.zig +++ b/src/widgets/terminal/Terminal.zig @@ -332,9 +332,9 @@ fn run(self: *Terminal) !void { var iter = seq.iterator(u16); const kind = iter.next() orelse 0; switch (kind) { - 0 => {}, - 1 => {}, - 2 => {}, + 0 => self.back_screen.eraseBelow(), + 1 => self.back_screen.eraseAbove(), + 2 => self.back_screen.eraseAll(), 3 => {}, else => {}, } @@ -346,21 +346,88 @@ fn run(self: *Terminal) !void { const ps = iter.next() orelse 0; switch (ps) { 0 => self.back_screen.eraseRight(), - 1 => {}, - 2 => {}, + 1 => self.back_screen.eraseLeft(), + 2 => self.back_screen.eraseLine(), else => continue, } }, + // Insert Lines 'L' => { var iter = seq.iterator(u16); const n = iter.next() orelse 1; try self.back_screen.insertLine(n); }, + // Delete Lines 'M' => { var iter = seq.iterator(u16); const n = iter.next() orelse 1; try self.back_screen.deleteLine(n); }, + // Delete Character + 'P' => { + var iter = seq.iterator(u16); + const n = iter.next() orelse 1; + try self.back_screen.deleteCharacters(n); + }, + // Scroll Up + 'S' => { + var iter = seq.iterator(u16); + const n = iter.next() orelse 1; + const cur_row = self.back_screen.cursor.row; + const cur_col = self.back_screen.cursor.col; + const wrap = self.back_screen.cursor.pending_wrap; + defer { + self.back_screen.cursor.row = cur_row; + self.back_screen.cursor.col = cur_col; + self.back_screen.cursor.pending_wrap = wrap; + } + self.back_screen.cursor.col = self.back_screen.scrolling_region.left; + self.back_screen.cursor.row = self.back_screen.scrolling_region.top; + try self.back_screen.deleteLine(n); + }, + // Scroll Down + 'T' => { + var iter = seq.iterator(u16); + const n = iter.next() orelse 1; + const cur_row = self.back_screen.cursor.row; + const cur_col = self.back_screen.cursor.col; + const wrap = self.back_screen.cursor.pending_wrap; + defer { + self.back_screen.cursor.row = cur_row; + self.back_screen.cursor.col = cur_col; + self.back_screen.cursor.pending_wrap = wrap; + } + self.back_screen.cursor.col = self.back_screen.scrolling_region.left; + self.back_screen.cursor.row = self.back_screen.scrolling_region.top; + try self.back_screen.insertLine(n); + }, + 'W' => {}, // TODO: Tab control + 'X' => { + self.back_screen.cursor.pending_wrap = false; + var iter = seq.iterator(u16); + const n = iter.next() orelse 1; + const start = self.back_screen.cursor.row * self.back_screen.width + self.back_screen.cursor.col; + const end = @max( + self.back_screen.cursor.row * self.back_screen.width + self.back_screen.width, + n, + ); + var i: usize = start; + while (i < end) : (i += 1) { + self.back_screen.buf[i].erase(self.back_screen.cursor.style.bg); + } + }, + 'Z' => {}, // TODO: Back tab + // + // Cursor Vertial Position Aboslute + 'd' => { + var iter = seq.iterator(u16); + const n = iter.next() orelse 1; + self.back_screen.cursor.pending_wrap = false; + self.back_screen.cursor.row = @min( + self.back_screen.height -| 1, + n -| 1, + ); + }, 'h', 'l' => { var iter = seq.iterator(u16); const mode = iter.next() orelse continue;