mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
Merge pull request #160 from mitchellh/cbt
CSI for tab forward/back (CBT/CHT)
This commit is contained in:
@ -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);
|
||||||
|
@ -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) {
|
||||||
|
@ -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 {
|
||||||
|
Reference in New Issue
Block a user