From cbd6505d25b0ce8f5ebda6b8be7a97749db4df18 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 28 Apr 2022 21:18:27 -0700 Subject: [PATCH] terminal: scrolling --- src/main.zig | 1 + src/terminal/Terminal.zig | 31 ++++++++++++++++++++++++++++--- src/terminal/main.zig | 11 +++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 src/terminal/main.zig diff --git a/src/main.zig b/src/main.zig index 557aa85fb..2c0aaa023 100644 --- a/src/main.zig +++ b/src/main.zig @@ -30,4 +30,5 @@ test { // Libraries _ = @import("segmented_pool.zig"); _ = @import("libuv/main.zig"); + _ = @import("terminal/main.zig"); } diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index e0525cd73..5f282dd86 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -140,7 +140,7 @@ fn execute(self: *Terminal, alloc: Allocator, c: u8) !void { .BEL => self.bell(), .BS => self.backspace(), .HT => try self.horizontal_tab(alloc), - .LF => self.linefeed(), + .LF => self.linefeed(alloc), .CR => self.carriage_return(), } } @@ -176,11 +176,36 @@ pub fn carriage_return(self: *Terminal) void { } /// Linefeed moves the cursor to the next line. -pub fn linefeed(self: *Terminal) void { - // TODO: end of screen +pub fn linefeed(self: *Terminal, alloc: Allocator) void { + // If we're at the end of the screen, scroll up. This is surprisingly + // common because most terminals live with a full screen so we do this + // check first. + if (self.cursor.y == self.rows - 1) { + self.scroll_up(alloc); + return; + } + + // Increase cursor by 1 self.cursor.y += 1; } +/// Scroll the text up by one row. +pub fn scroll_up(self: *Terminal, alloc: Allocator) void { + // TODO: this is horribly expensive. we need to optimize the screen repr + + // If we have no items, scrolling does nothing. + if (self.screen.items.len == 0) return; + + // Clear the first line + self.screen.items[0].deinit(alloc); + + var i: usize = 0; + while (i < self.screen.items.len - 1) : (i += 1) { + self.screen.items[i] = self.screen.items[i + 1]; + } + self.screen.items.len -= 1; +} + fn getOrPutCell(self: *Terminal, alloc: Allocator, x: usize, y: usize) !*Cell { // If we don't have enough lines to get to y, then add it. if (self.screen.items.len < y + 1) { diff --git a/src/terminal/main.zig b/src/terminal/main.zig new file mode 100644 index 000000000..43ea9fd83 --- /dev/null +++ b/src/terminal/main.zig @@ -0,0 +1,11 @@ +pub const Terminal = @import("Terminal.zig"); + +// Not exported because they're just used for tests. + +test { + _ = Terminal; + + _ = @import("parse_table.zig"); + _ = @import("Parser.zig"); + _ = @import("Tabstops.zig"); +}