Merge pull request #160 from mitchellh/cbt

CSI for tab forward/back (CBT/CHT)
This commit is contained in:
Mitchell Hashimoto
2023-06-25 10:01:21 -07:00
committed by GitHub
3 changed files with 77 additions and 3 deletions

View File

@ -1226,6 +1226,21 @@ pub fn horizontalTab(self: *Terminal) !void {
} }
} }
// Same as horizontalTab but moves to the previous tabstop instead of the next.
pub fn horizontalTabBack(self: *Terminal) !void {
const tracy = trace(@src());
defer tracy.end();
while (true) {
// If we're already at the edge of the screen, then we're done.
if (self.screen.cursor.x == 0) return;
// Move the cursor left
self.screen.cursor.x -= 1;
if (self.tabstops.get(self.screen.cursor.x)) return;
}
}
/// Clear tab stops. /// Clear tab stops.
/// TODO: test /// TODO: test
pub fn tabClear(self: *Terminal, cmd: csi.TabClear) void { pub fn tabClear(self: *Terminal, cmd: csi.TabClear) void {
@ -1806,6 +1821,29 @@ test "Terminal: horizontal tabs" {
try testing.expectEqual(@as(usize, 19), t.screen.cursor.x); try testing.expectEqual(@as(usize, 19), t.screen.cursor.x);
} }
test "Terminal: horizontal tabs back" {
const alloc = testing.allocator;
var t = try init(alloc, 20, 5);
defer t.deinit(alloc);
// Edge of screen
t.screen.cursor.x = 19;
// HT
try t.horizontalTabBack();
try testing.expectEqual(@as(usize, 15), t.screen.cursor.x);
// HT
try t.horizontalTabBack();
try testing.expectEqual(@as(usize, 7), t.screen.cursor.x);
// HT
try t.horizontalTabBack();
try testing.expectEqual(@as(usize, 0), t.screen.cursor.x);
try t.horizontalTabBack();
try testing.expectEqual(@as(usize, 0), t.screen.cursor.x);
}
test "Terminal: setCursorPosition" { test "Terminal: setCursorPosition" {
var t = try init(testing.allocator, 80, 80); var t = try init(testing.allocator, 80, 80);
defer t.deinit(testing.allocator); defer t.deinit(testing.allocator);

View File

@ -92,7 +92,7 @@ pub fn Stream(comptime Handler: type) type {
log.warn("unimplemented execute: {x}", .{c}), log.warn("unimplemented execute: {x}", .{c}),
.HT => if (@hasDecl(T, "horizontalTab")) .HT => if (@hasDecl(T, "horizontalTab"))
try self.handler.horizontalTab() try self.handler.horizontalTab(1)
else else
log.warn("unimplemented execute: {x}", .{c}), log.warn("unimplemented execute: {x}", .{c}),
@ -205,6 +205,18 @@ pub fn Stream(comptime Handler: type) type {
else => log.warn("invalid CUP command: {}", .{action}), else => log.warn("invalid CUP command: {}", .{action}),
} else log.warn("unimplemented CSI callback: {}", .{action}), } else log.warn("unimplemented CSI callback: {}", .{action}),
// CHT - Cursor Horizontal Tabulation
'I' => if (@hasDecl(T, "horizontalTab")) try self.handler.horizontalTab(
switch (action.params.len) {
0 => 1,
1 => action.params[0],
else => {
log.warn("invalid horizontal tab command: {}", .{action});
return;
},
},
) else log.warn("unimplemented CSI callback: {}", .{action}),
// Erase Display // Erase Display
// TODO: test // TODO: test
'J' => if (@hasDecl(T, "eraseDisplay")) try self.handler.eraseDisplay( 'J' => if (@hasDecl(T, "eraseDisplay")) try self.handler.eraseDisplay(
@ -316,6 +328,18 @@ pub fn Stream(comptime Handler: type) type {
}, },
) else log.warn("unimplemented CSI callback: {}", .{action}), ) else log.warn("unimplemented CSI callback: {}", .{action}),
// CHT - Cursor Horizontal Tabulation Back
'Z' => if (@hasDecl(T, "horizontalTabBack")) try self.handler.horizontalTabBack(
switch (action.params.len) {
0 => 1,
1 => action.params[0],
else => {
log.warn("invalid horizontal tab back command: {}", .{action});
return;
},
},
) else log.warn("unimplemented CSI callback: {}", .{action}),
// Repeat Previous Char (REP) // Repeat Previous Char (REP)
'b' => if (@hasDecl(T, "printRepeat")) try self.handler.printRepeat( 'b' => if (@hasDecl(T, "printRepeat")) try self.handler.printRepeat(
switch (action.params.len) { switch (action.params.len) {

View File

@ -959,8 +959,20 @@ const StreamHandler = struct {
self.terminal.backspace(); self.terminal.backspace();
} }
pub fn horizontalTab(self: *StreamHandler) !void { pub fn horizontalTab(self: *StreamHandler, count: u16) !void {
try self.terminal.horizontalTab(); for (0..count) |_| {
const x = self.terminal.screen.cursor.x;
try self.terminal.horizontalTab();
if (x == self.terminal.screen.cursor.x) break;
}
}
pub fn horizontalTabBack(self: *StreamHandler, count: u16) !void {
for (0..count) |_| {
const x = self.terminal.screen.cursor.x;
try self.terminal.horizontalTabBack();
if (x == self.terminal.screen.cursor.x) break;
}
} }
pub fn linefeed(self: *StreamHandler) !void { pub fn linefeed(self: *StreamHandler) !void {