diff --git a/src/terminal/stream.zig b/src/terminal/stream.zig index 47a44c57e..0ddfbb5bf 100644 --- a/src/terminal/stream.zig +++ b/src/terminal/stream.zig @@ -571,20 +571,77 @@ pub fn Stream(comptime Handler: type) type { }, ) else log.warn("unimplemented CSI callback: {}", .{action}), - // DECSTBM - Set Top and Bottom Margins - // TODO: test - 'r' => if (action.intermediates.len == 0) { - if (@hasDecl(T, "setTopAndBottomMargin")) switch (action.params.len) { - 0 => try self.handler.setTopAndBottomMargin(0, 0), - 1 => try self.handler.setTopAndBottomMargin(action.params[0], 0), - 2 => try self.handler.setTopAndBottomMargin(action.params[0], action.params[1]), - else => log.warn("invalid DECSTBM command: {}", .{action}), - } else log.warn("unimplemented CSI callback: {}", .{action}); - } else { - log.debug( - "ignoring unimplemented CSI r with intermediates: {s}", - .{action.intermediates}, - ); + 'r' => switch (action.intermediates.len) { + // DECSTBM - Set Top and Bottom Margins + 0 => if (@hasDecl(T, "setTopAndBottomMargin")) { + switch (action.params.len) { + 0 => try self.handler.setTopAndBottomMargin(0, 0), + 1 => try self.handler.setTopAndBottomMargin(action.params[0], 0), + 2 => try self.handler.setTopAndBottomMargin(action.params[0], action.params[1]), + else => log.warn("invalid DECSTBM command: {}", .{action}), + } + } else log.warn( + "unimplemented CSI callback: {}", + .{action}, + ), + + 1 => switch (action.intermediates[0]) { + // Restore Mode + '?' => if (@hasDecl(T, "restoreMode")) { + for (action.params) |mode| { + if (modes.hasSupport(mode)) { + try self.handler.restoreMode( + @enumFromInt(mode), + ); + } else { + log.warn( + "unimplemented restore mode: {}", + .{mode}, + ); + } + } + }, + + else => log.warn( + "unknown CSI s with intermediate: {}", + .{action}, + ), + }, + + else => log.warn( + "ignoring unimplemented CSI s with intermediates: {s}", + .{action}, + ), + }, + + // Save Mode + 's' => switch (action.intermediates.len) { + 1 => switch (action.intermediates[0]) { + '?' => if (@hasDecl(T, "saveMode")) { + for (action.params) |mode| { + if (modes.hasSupport(mode)) { + try self.handler.saveMode( + @enumFromInt(mode), + ); + } else { + log.warn( + "unimplemented save mode: {}", + .{mode}, + ); + } + } + }, + + else => log.warn( + "unknown CSI s with intermediate: {}", + .{action}, + ), + }, + + else => log.warn( + "ignoring unimplemented CSI s with intermediates: {s}", + .{action}, + ), }, // ICH - Insert Blanks diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index ffdffc238..d574bef00 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -1194,6 +1194,20 @@ const StreamHandler = struct { } } + pub fn saveMode(self: *StreamHandler, mode: terminal.Mode) !void { + // log.debug("save mode={}", .{mode}); + self.terminal.modes.save(mode); + } + + pub fn restoreMode(self: *StreamHandler, mode: terminal.Mode) !void { + // For restore mode we have to restore but if we set it, we + // always have to call setMode because setting some modes have + // side effects and we want to make sure we process those. + const v = self.terminal.modes.restore(mode); + // log.debug("restore mode={} v={}", .{ mode, v }); + if (v) try self.setMode(mode, true); + } + pub fn setMode(self: *StreamHandler, mode: terminal.Mode, enabled: bool) !void { // Note: this function doesn't need to grab the render state or // terminal locks because it is only called from process() which