implement CSI ESC [ <n> b for repeating previously printed char

This commit is contained in:
Mitchell Hashimoto
2022-11-13 22:07:40 -08:00
parent feccd550c3
commit 99224ae2c0
3 changed files with 38 additions and 5 deletions

View File

@ -60,6 +60,10 @@ scrolling_region: ScrollingRegion,
/// The charset state /// The charset state
charset: CharsetState = .{}, charset: CharsetState = .{},
/// The previous printed character. This is used for the repeat previous
/// char CSI (ESC [ <n> b).
previous_char: ?u21 = null,
/// Modes - This isn't exhaustive, since some modes (i.e. cursor origin) /// Modes - This isn't exhaustive, since some modes (i.e. cursor origin)
/// are applied to the cursor and others aren't boolean yes/no. /// are applied to the cursor and others aren't boolean yes/no.
modes: packed struct { modes: packed struct {
@ -571,6 +575,9 @@ pub fn print(self: *Terminal, c: u21) !void {
return; return;
} }
// We have a printable character, save it
self.previous_char = c;
// If we're soft-wrapping, then handle that first. // If we're soft-wrapping, then handle that first.
if (self.screen.cursor.pending_wrap and self.modes.autowrap) if (self.screen.cursor.pending_wrap and self.modes.autowrap)
try self.printWrap(); try self.printWrap();
@ -699,6 +706,15 @@ fn clearWideSpacerHead(self: *Terminal) void {
cell.attrs.wide_spacer_head = false; cell.attrs.wide_spacer_head = false;
} }
/// Print the previous printed character a repeated amount of times.
pub fn printRepeat(self: *Terminal, count: usize) !void {
// TODO: test
if (self.previous_char) |c| {
var i: usize = 0;
while (i < count) : (i += 1) try self.print(c);
}
}
/// Resets all margins and fills the whole screen with the character 'E' /// Resets all margins and fills the whole screen with the character 'E'
/// ///
/// Sets the cursor to the top left corner. /// Sets the cursor to the top left corner.
@ -1353,6 +1369,7 @@ pub fn fullReset(self: *Terminal) void {
self.screen.cursor = .{}; self.screen.cursor = .{};
self.screen.saved_cursor = .{}; self.screen.saved_cursor = .{};
self.scrolling_region = .{ .top = 0, .bottom = self.rows - 1 }; self.scrolling_region = .{ .top = 0, .bottom = self.rows - 1 };
self.previous_char = null;
} }
test "Terminal: input with no control characters" { test "Terminal: input with no control characters" {

View File

@ -314,6 +314,18 @@ pub fn Stream(comptime Handler: type) type {
}, },
) else log.warn("unimplemented CSI callback: {}", .{action}), ) else log.warn("unimplemented CSI callback: {}", .{action}),
// Repeat Previous Char (REP)
'b' => if (@hasDecl(T, "printRepeat")) try self.handler.printRepeat(
switch (action.params.len) {
0 => 1,
1 => action.params[0],
else => {
log.warn("invalid print repeat command: {}", .{action});
return;
},
},
) else log.warn("unimplemented CSI callback: {}", .{action}),
// c - Device Attributes (DA1) // c - Device Attributes (DA1)
'c' => if (@hasDecl(T, "deviceAttributes")) { 'c' => if (@hasDecl(T, "deviceAttributes")) {
const req: ansi.DeviceAttributeReq = switch (action.intermediates.len) { const req: ansi.DeviceAttributeReq = switch (action.intermediates.len) {
@ -408,11 +420,6 @@ pub fn Stream(comptime Handler: type) type {
else => log.warn("invalid DECSTBM command: {}", .{action}), else => log.warn("invalid DECSTBM command: {}", .{action}),
} else log.warn("unimplemented CSI callback: {}", .{action}), } else log.warn("unimplemented CSI callback: {}", .{action}),
else => if (@hasDecl(T, "csiUnimplemented"))
try self.handler.csiUnimplemented(action)
else
log.warn("unimplemented CSI action: {}", .{action}),
// ICH - Insert Blanks // ICH - Insert Blanks
// TODO: test // TODO: test
'@' => if (@hasDecl(T, "insertBlanks")) switch (action.params.len) { '@' => if (@hasDecl(T, "insertBlanks")) switch (action.params.len) {
@ -440,6 +447,11 @@ pub fn Stream(comptime Handler: type) type {
if (!success) log.warn("unimplemented CSI callback: {}", .{action}); if (!success) log.warn("unimplemented CSI callback: {}", .{action});
}, },
else => if (@hasDecl(T, "csiUnimplemented"))
try self.handler.csiUnimplemented(action)
else
log.warn("unimplemented CSI action: {}", .{action}),
} }
} }

View File

@ -478,6 +478,10 @@ const StreamHandler = struct {
try self.terminal.print(ch); try self.terminal.print(ch);
} }
pub fn printRepeat(self: *StreamHandler, count: usize) !void {
try self.terminal.printRepeat(count);
}
pub fn bell(self: StreamHandler) !void { pub fn bell(self: StreamHandler) !void {
_ = self; _ = self;
log.info("BELL", .{}); log.info("BELL", .{});