save and restore cursor

This commit is contained in:
Mitchell Hashimoto
2022-06-25 10:56:41 -07:00
parent fb6800c8ce
commit 245b9642f9
3 changed files with 47 additions and 3 deletions

View File

@ -781,3 +781,11 @@ pub fn tabClear(self: *Window, cmd: terminal.TabClear) !void {
pub fn tabSet(self: *Window) !void { pub fn tabSet(self: *Window) !void {
self.terminal.tabSet(); self.terminal.tabSet();
} }
pub fn saveCursor(self: *Window) !void {
self.terminal.saveCursor();
}
pub fn restoreCursor(self: *Window) !void {
self.terminal.restoreCursor();
}

View File

@ -28,6 +28,9 @@ screen: Screen,
/// Cursor position. /// Cursor position.
cursor: Cursor, cursor: Cursor,
/// Saved cursor saved with DECSC (ESC 7).
saved_cursor: Cursor,
/// Where the tabstops are. /// Where the tabstops are.
tabstops: Tabstops, tabstops: Tabstops,
@ -53,8 +56,8 @@ const ScrollingRegion = struct {
/// Cursor represents the cursor state. /// Cursor represents the cursor state.
const Cursor = struct { const Cursor = struct {
// x, y where the cursor currently exists (0-indexed). // x, y where the cursor currently exists (0-indexed).
x: usize, x: usize = 0,
y: usize, y: usize = 0,
// pen is the current cell styling to apply to new cells. // pen is the current cell styling to apply to new cells.
pen: Screen.Cell = .{ .char = 0 }, pen: Screen.Cell = .{ .char = 0 },
@ -66,7 +69,8 @@ pub fn init(alloc: Allocator, cols: usize, rows: usize) !Terminal {
.cols = cols, .cols = cols,
.rows = rows, .rows = rows,
.screen = try Screen.init(alloc, rows, cols), .screen = try Screen.init(alloc, rows, cols),
.cursor = .{ .x = 0, .y = 0 }, .cursor = .{},
.saved_cursor = .{},
.tabstops = try Tabstops.init(alloc, cols, TABSTOP_INTERVAL), .tabstops = try Tabstops.init(alloc, cols, TABSTOP_INTERVAL),
.scrolling_region = .{ .scrolling_region = .{
.top = 0, .top = 0,
@ -119,6 +123,23 @@ pub fn plainString(self: Terminal, alloc: Allocator) ![]const u8 {
return try self.screen.testString(alloc); 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 /// TODO: test
pub fn setAttribute(self: *Terminal, attr: sgr.Attribute) !void { pub fn setAttribute(self: *Terminal, attr: sgr.Attribute) !void {
switch (attr) { switch (attr) {

View File

@ -379,8 +379,23 @@ pub fn Stream(comptime Handler: type) type {
action: Parser.Action.ESC, action: Parser.Action.ESC,
) !void { ) !void {
switch (action.final) { 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: { '8' => blk: {
switch (action.intermediates.len) { 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]) { 1 => switch (action.intermediates[0]) {
// DECALN - Fill Screen with E // DECALN - Fill Screen with E
'#' => if (@hasDecl(T, "decaln")) { '#' => if (@hasDecl(T, "decaln")) {