From 245b9642f932124294012754bae61f26e3db3b69 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 25 Jun 2022 10:56:41 -0700 Subject: [PATCH] save and restore cursor --- src/Window.zig | 8 ++++++++ src/terminal/Terminal.zig | 27 ++++++++++++++++++++++++--- src/terminal/stream.zig | 15 +++++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/Window.zig b/src/Window.zig index 46b4780e2..8f85a4b3d 100644 --- a/src/Window.zig +++ b/src/Window.zig @@ -781,3 +781,11 @@ pub fn tabClear(self: *Window, cmd: terminal.TabClear) !void { pub fn tabSet(self: *Window) !void { self.terminal.tabSet(); } + +pub fn saveCursor(self: *Window) !void { + self.terminal.saveCursor(); +} + +pub fn restoreCursor(self: *Window) !void { + self.terminal.restoreCursor(); +} diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index 0f8695c9c..3e3c8c6a1 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -28,6 +28,9 @@ screen: Screen, /// Cursor position. cursor: Cursor, +/// Saved cursor saved with DECSC (ESC 7). +saved_cursor: Cursor, + /// Where the tabstops are. tabstops: Tabstops, @@ -53,8 +56,8 @@ const ScrollingRegion = struct { /// Cursor represents the cursor state. const Cursor = struct { // x, y where the cursor currently exists (0-indexed). - x: usize, - y: usize, + x: usize = 0, + y: usize = 0, // pen is the current cell styling to apply to new cells. pen: Screen.Cell = .{ .char = 0 }, @@ -66,7 +69,8 @@ pub fn init(alloc: Allocator, cols: usize, rows: usize) !Terminal { .cols = cols, .rows = rows, .screen = try Screen.init(alloc, rows, cols), - .cursor = .{ .x = 0, .y = 0 }, + .cursor = .{}, + .saved_cursor = .{}, .tabstops = try Tabstops.init(alloc, cols, TABSTOP_INTERVAL), .scrolling_region = .{ .top = 0, @@ -119,6 +123,23 @@ pub fn plainString(self: Terminal, alloc: Allocator) ![]const u8 { return try self.screen.testString(alloc); } +/// Save cursor position and further state. +/// +/// The primary and alternate screen have distinct save state. One saved state +/// is kept per screen (main / alternative). If for the current screen state +/// was already saved it is overwritten. +pub fn saveCursor(self: *Terminal) void { + self.saved_cursor = self.cursor; +} + +/// Restore cursor position and other state. +/// +/// The primary and alternate screen have distinct save state. +/// If no save was done before values are reset to their initial values. +pub fn restoreCursor(self: *Terminal) void { + self.cursor = self.saved_cursor; +} + /// TODO: test pub fn setAttribute(self: *Terminal, attr: sgr.Attribute) !void { switch (attr) { diff --git a/src/terminal/stream.zig b/src/terminal/stream.zig index 2958de0c0..b1c6161b3 100644 --- a/src/terminal/stream.zig +++ b/src/terminal/stream.zig @@ -379,8 +379,23 @@ pub fn Stream(comptime Handler: type) type { action: Parser.Action.ESC, ) !void { switch (action.final) { + // DECSC - Save Cursor + '7' => if (@hasDecl(T, "saveCursor")) switch (action.intermediates.len) { + 0 => try self.handler.saveCursor(), + else => { + log.warn("invalid command: {}", .{action}); + return; + }, + } else log.warn("unimplemented ESC callback: {}", .{action}), + '8' => blk: { switch (action.intermediates.len) { + // DECRC - Restore Cursor + 0 => if (@hasDecl(T, "restoreCursor")) { + try self.handler.restoreCursor(); + break :blk {}; + } else log.warn("unimplemented restore cursor callback: {}", .{action}), + 1 => switch (action.intermediates[0]) { // DECALN - Fill Screen with E '#' => if (@hasDecl(T, "decaln")) {