terminal: parse and handle save/restore mode (CSI ? s, CSI ? r)

This commit is contained in:
Mitchell Hashimoto
2023-08-15 11:43:07 -07:00
parent 951aa00c63
commit 06f82ad713
2 changed files with 85 additions and 14 deletions

View File

@ -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

View File

@ -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