widgets(terminal): handle horizontal tabs

This commit is contained in:
Tim Culverhouse 2024-06-10 06:37:10 -05:00
parent 1c5ecae8f0
commit c14a100eed
2 changed files with 52 additions and 12 deletions

View file

@ -332,6 +332,19 @@ pub fn cursorLeft(self: *Screen, n: usize) void {
self.cursor.col = self.cursor.col -| n;
}
pub fn cursorRight(self: *Screen, n: usize) void {
if (self.withinScrollingRegion())
self.cursor.col = @min(
self.cursor.col + n,
self.scrolling_region.right,
)
else
self.cursor.col = @min(
self.cursor.col + n,
self.width,
);
}
pub fn cursorDown(self: *Screen, n: usize) void {
self.cursor.pending_wrap = false;
if (self.withinScrollingRegion())

View file

@ -67,6 +67,8 @@ should_quit: bool = false,
mode: Mode = .{},
tab_stops: std.ArrayList(u16),
event_queue: Queue = .{},
/// initialize a Terminal. This sets the size of the underlying pty and allocates the sizes of the
@ -85,6 +87,11 @@ pub fn init(
.env_map = env,
.pty = pty,
};
var tabs = try std.ArrayList(u16).initCapacity(allocator, opts.winsize.cols / 8);
var col: u16 = 0;
while (col < opts.winsize.cols) : (col += 8) {
try tabs.append(col);
}
return .{
.allocator = allocator,
.pty = pty,
@ -94,6 +101,7 @@ pub fn init(
.back_screen_pri = try Screen.init(allocator, opts.winsize.cols, opts.winsize.rows + opts.scrollback_size),
.back_screen_alt = try Screen.init(allocator, opts.winsize.cols, opts.winsize.rows),
.unicode = unicode,
.tab_stops = tabs,
};
}
@ -124,6 +132,7 @@ pub fn deinit(self: *Terminal) void {
self.front_screen.deinit(self.allocator);
self.back_screen_pri.deinit(self.allocator);
self.back_screen_alt.deinit(self.allocator);
self.tab_stops.deinit();
}
pub fn spawn(self: *Terminal) !void {
@ -275,17 +284,7 @@ fn run(self: *Terminal) !void {
self.back_screen.cursor.pending_wrap = false;
var iter = seq.iterator(u16);
const delta = iter.next() orelse 1;
const within = self.back_screen.withinScrollingRegion();
if (within)
self.back_screen.cursor.col = @min(
self.back_screen.cursor.col + delta,
self.back_screen.scrolling_region.right,
)
else
self.back_screen.cursor.col = @min(
self.back_screen.cursor.col + delta,
self.back_screen.width,
);
self.back_screen.cursorRight(delta);
},
// Cursor Left
'D', 'j' => {
@ -307,6 +306,13 @@ fn run(self: *Terminal) !void {
self.back_screen.cursorUp(delta);
self.carriageReturn();
},
// Horizontal Positional Absolute
'G', '`' => {
var iter = seq.iterator(u16);
const col = iter.next() orelse 1;
self.back_screen.cursor.col = col -| 1;
},
// Cursor Absolute Position
'H', 'f' => {
var iter = seq.iterator(u16);
const row = iter.next() orelse 1;
@ -314,6 +320,11 @@ fn run(self: *Terminal) !void {
self.back_screen.cursor.col = col -| 1;
self.back_screen.cursor.row = row -| 1;
},
'I' => {
var iter = seq.iterator(u16);
const n = iter.next() orelse 1;
self.horizontalTab(n);
},
'K' => {
// TODO selective erase (private_marker == '?')
var iter = seq.iterator(u8);
@ -392,7 +403,7 @@ inline fn handleC0(self: *Terminal, b: ansi.C0) !void {
.ENQ => {},
.BEL => self.event_queue.push(.bell),
.BS => self.back_screen.cursorLeft(1),
.HT => {}, // TODO: HT
.HT => self.horizontalTab(1),
.LF, .VT, .FF => try self.back_screen.index(),
.CR => self.carriageReturn(),
.SO => {}, // TODO: Charset shift out
@ -444,3 +455,19 @@ pub fn carriageReturn(self: *Terminal) void {
else
0;
}
pub fn horizontalTab(self: *Terminal, n: usize) void {
// Get the current cursor position
const col = self.back_screen.cursor.col;
// Find desired final position
var i: usize = 0;
const final = for (self.tab_stops.items) |ts| {
if (ts <= col) continue;
i += 1;
if (i == n) break ts;
} else self.back_screen.width - 1;
// Move right the delta
self.back_screen.cursorRight(final - col);
}