CUP full implementation with tests

This commit is contained in:
Mitchell Hashimoto
2022-05-08 20:08:44 -07:00
parent 7e77c6b369
commit 68aca98ba8

View File

@ -139,13 +139,13 @@ fn csiDispatch(
action: Parser.Action.CSI, action: Parser.Action.CSI,
) !void { ) !void {
switch (action.final) { switch (action.final) {
// Set Cursor Position (TODO: docs) // CUP - Set Cursor Position.
'H' => { 'H' => {
switch (action.params.len) { switch (action.params.len) {
0 => try self.setCursorPosition(1, 1), 0 => try self.setCursorPosition(1, 1),
1 => try self.setCursorPosition(action.params[0], 1), 1 => try self.setCursorPosition(action.params[0], 1),
2 => try self.setCursorPosition(action.params[0], action.params[1]), 2 => try self.setCursorPosition(action.params[0], action.params[1]),
else => log.warn("unimplemented CSI: {}", .{csi}), else => log.warn("unimplemented CSI: {}", .{action}),
} }
}, },
@ -155,7 +155,7 @@ fn csiDispatch(
1 => mode: { 1 => mode: {
// TODO: use meta to get enum max // TODO: use meta to get enum max
if (action.params[0] > 3) { if (action.params[0] > 3) {
log.warn("invalid erase display command: {}", .{csi}); log.warn("invalid erase display command: {}", .{action});
return; return;
} }
@ -165,12 +165,12 @@ fn csiDispatch(
); );
}, },
else => { else => {
log.warn("invalid erase display command: {}", .{csi}); log.warn("invalid erase display command: {}", .{action});
return; return;
}, },
}), }),
else => log.warn("unimplemented CSI: {}", .{csi}), else => log.warn("unimplemented CSI: {}", .{action}),
} }
} }
@ -213,14 +213,18 @@ pub fn bell(self: *Terminal) void {
log.info("bell", .{}); log.info("bell", .{});
} }
/// Set the cursor position. Row and column are 1-based. // Set Cursor Position. Move cursor to the position indicated
/// TODO: test // by row and column (1-indexed). If column is 0, it is adjusted to 1.
// If column is greater than the right-most column it is adjusted to
// the right-most column. If row is 0, it is adjusted to 1. If row is
// greater than the bottom-most row it is adjusted to the bottom-most
// row.
pub fn setCursorPosition(self: *Terminal, row: usize, col: usize) !void { pub fn setCursorPosition(self: *Terminal, row: usize, col: usize) !void {
const tracy = trace(@src()); const tracy = trace(@src());
defer tracy.end(); defer tracy.end();
self.cursor.x = col - 1; self.cursor.x = @minimum(self.cols, col) -| 1;
self.cursor.y = row - 1; self.cursor.y = @minimum(self.rows, row) -| 1;
} }
/// Erase the display. /// Erase the display.
@ -392,3 +396,46 @@ test "Terminal: horizontal tabs" {
try t.append(testing.allocator, "\t"); try t.append(testing.allocator, "\t");
try testing.expectEqual(@as(usize, 16), t.cursor.x); try testing.expectEqual(@as(usize, 16), t.cursor.x);
} }
test "Terminal: CUP (ESC [ H)" {
var t = try init(testing.allocator, 80, 80);
defer t.deinit(testing.allocator);
// X, Y both specified
try t.append(testing.allocator, "\x1B[5;10H");
try testing.expectEqual(@as(usize, 4), t.cursor.y);
try testing.expectEqual(@as(usize, 9), t.cursor.x);
// Y only
try t.append(testing.allocator, "\x1B[5H");
try testing.expectEqual(@as(usize, 4), t.cursor.y);
try testing.expectEqual(@as(usize, 0), t.cursor.x);
// 0, 0 default
try t.append(testing.allocator, "\x1B[H");
try testing.expectEqual(@as(usize, 0), t.cursor.y);
try testing.expectEqual(@as(usize, 0), t.cursor.x);
// invalid
try t.append(testing.allocator, "\x1B[1;2;3H");
try testing.expectEqual(@as(usize, 0), t.cursor.y);
try testing.expectEqual(@as(usize, 0), t.cursor.x);
}
test "Terminal: setCursorPosition" {
var t = try init(testing.allocator, 80, 80);
defer t.deinit(testing.allocator);
try testing.expectEqual(@as(usize, 0), t.cursor.x);
try testing.expectEqual(@as(usize, 0), t.cursor.y);
// Setting it to 0 should keep it zero (1 based)
try t.setCursorPosition(0, 0);
try testing.expectEqual(@as(usize, 0), t.cursor.x);
try testing.expectEqual(@as(usize, 0), t.cursor.y);
// Should clamp to size
try t.setCursorPosition(81, 81);
try testing.expectEqual(@as(usize, 79), t.cursor.x);
try testing.expectEqual(@as(usize, 79), t.cursor.y);
}