mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-06 07:38:21 +00:00
terminal: make stream processing infallible
The terminal.Stream next/nextSlice functions can now no longer fail. All prior failure modes were fully isolated in the handler `vt` callbacks. As such, vt callbacks are now required to not return an error and handle their own errors somehow. Allowing streams to be fallible before was an incorrect design. It caused problematic scenarios like in `nextSlice` early terminating processing due to handler errors. This should not be possible. There is no safe way to bubble up vt errors through the stream because if nextSlice is called and multiple errors are returned, we can't coalesce them. We could modify that to return a partial result but its just more work for stream that is unnecessary. The handler can do all of this. This work was discovered due to cleanups to prepare for more C APIs. Less errors make C APIs easier to implement! And, it helps clean up our Zig, too.
This commit is contained in:
@@ -23,8 +23,8 @@ pub fn main() !void {
|
||||
|
||||
// Replace \n with \r\n
|
||||
for (buf[0..n]) |byte| {
|
||||
if (byte == '\n') try stream.next('\r');
|
||||
try stream.next(byte);
|
||||
if (byte == '\n') stream.next('\r');
|
||||
stream.next(byte);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,24 +14,24 @@ pub fn main() !void {
|
||||
defer stream.deinit();
|
||||
|
||||
// Basic text with newline
|
||||
try stream.nextSlice("Hello, World!\r\n");
|
||||
stream.nextSlice("Hello, World!\r\n");
|
||||
|
||||
// ANSI color codes: ESC[1;32m = bold green, ESC[0m = reset
|
||||
try stream.nextSlice("\x1b[1;32mGreen Text\x1b[0m\r\n");
|
||||
stream.nextSlice("\x1b[1;32mGreen Text\x1b[0m\r\n");
|
||||
|
||||
// Cursor positioning: ESC[1;1H = move to row 1, column 1
|
||||
try stream.nextSlice("\x1b[1;1HTop-left corner\r\n");
|
||||
stream.nextSlice("\x1b[1;1HTop-left corner\r\n");
|
||||
|
||||
// Cursor movement: ESC[5B = move down 5 lines
|
||||
try stream.nextSlice("\x1b[5B");
|
||||
try stream.nextSlice("Moved down!\r\n");
|
||||
stream.nextSlice("\x1b[5B");
|
||||
stream.nextSlice("Moved down!\r\n");
|
||||
|
||||
// Erase line: ESC[2K = clear entire line
|
||||
try stream.nextSlice("\x1b[2K");
|
||||
try stream.nextSlice("New content\r\n");
|
||||
stream.nextSlice("\x1b[2K");
|
||||
stream.nextSlice("New content\r\n");
|
||||
|
||||
// Multiple lines
|
||||
try stream.nextSlice("Line A\r\nLine B\r\nLine C\r\n");
|
||||
stream.nextSlice("Line A\r\nLine B\r\nLine C\r\n");
|
||||
|
||||
// Get the final terminal state as a plain string
|
||||
const str = try t.plainString(alloc);
|
||||
|
||||
@@ -94,9 +94,9 @@ fn setup(ptr: *anyopaque) Benchmark.Error!void {
|
||||
// Force a style on every single row, which
|
||||
var s = self.terminal.vtStream();
|
||||
defer s.deinit();
|
||||
s.nextSlice("\x1b[48;2;20;40;60m") catch unreachable;
|
||||
for (0..self.terminal.rows - 1) |_| s.nextSlice("hello\r\n") catch unreachable;
|
||||
s.nextSlice("hello") catch unreachable;
|
||||
s.nextSlice("\x1b[48;2;20;40;60m");
|
||||
for (0..self.terminal.rows - 1) |_| s.nextSlice("hello\r\n");
|
||||
s.nextSlice("hello");
|
||||
|
||||
// Setup our terminal state
|
||||
const data_f: std.fs.File = (options.dataFile(
|
||||
@@ -120,10 +120,7 @@ fn setup(ptr: *anyopaque) Benchmark.Error!void {
|
||||
return error.BenchmarkFailed;
|
||||
};
|
||||
if (n == 0) break; // EOF reached
|
||||
stream.nextSlice(buf[0..n]) catch |err| {
|
||||
log.warn("error processing data file chunk err={}", .{err});
|
||||
return error.BenchmarkFailed;
|
||||
};
|
||||
stream.nextSlice(buf[0..n]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,10 +125,7 @@ fn step(ptr: *anyopaque) Benchmark.Error!void {
|
||||
return error.BenchmarkFailed;
|
||||
};
|
||||
if (n == 0) break; // EOF reached
|
||||
self.stream.nextSlice(buf[0..n]) catch |err| {
|
||||
log.warn("error processing data file chunk err={}", .{err});
|
||||
return error.BenchmarkFailed;
|
||||
};
|
||||
self.stream.nextSlice(buf[0..n]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,9 +139,11 @@ const Handler = struct {
|
||||
self: *Handler,
|
||||
comptime action: Stream.Action.Tag,
|
||||
value: Stream.Action.Value(action),
|
||||
) !void {
|
||||
) void {
|
||||
switch (action) {
|
||||
.print => try self.t.print(value.cp),
|
||||
.print => self.t.print(value.cp) catch |err| {
|
||||
log.warn("error processing benchmark print err={}", .{err});
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -850,7 +850,7 @@ test "run iterator" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("ABCD");
|
||||
s.nextSlice("ABCD");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -874,7 +874,7 @@ test "run iterator" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("ABCD EFG");
|
||||
s.nextSlice("ABCD EFG");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -897,7 +897,7 @@ test "run iterator" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("A😃D");
|
||||
s.nextSlice("A😃D");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -922,7 +922,7 @@ test "run iterator" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(bad);
|
||||
s.nextSlice(bad);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -955,8 +955,8 @@ test "run iterator: empty cells with background set" {
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
// Set red background
|
||||
try s.nextSlice("\x1b[48;2;255;0;0m");
|
||||
try s.nextSlice("A");
|
||||
s.nextSlice("\x1b[48;2;255;0;0m");
|
||||
s.nextSlice("A");
|
||||
|
||||
// Get our first row
|
||||
{
|
||||
@@ -1014,7 +1014,7 @@ test "shape" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1053,7 +1053,7 @@ test "shape nerd fonts" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1086,7 +1086,7 @@ test "shape inconsolata ligs" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(">=");
|
||||
s.nextSlice(">=");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1115,7 +1115,7 @@ test "shape inconsolata ligs" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("===");
|
||||
s.nextSlice("===");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1152,7 +1152,7 @@ test "shape monaspace ligs" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("===");
|
||||
s.nextSlice("===");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1190,7 +1190,7 @@ test "shape left-replaced lig in last run" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("!==");
|
||||
s.nextSlice("!==");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1228,7 +1228,7 @@ test "shape left-replaced lig in early run" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("!==X");
|
||||
s.nextSlice("!==X");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1263,7 +1263,7 @@ test "shape U+3C9 with JB Mono" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("\u{03C9} foo");
|
||||
s.nextSlice("\u{03C9} foo");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1300,7 +1300,7 @@ test "shape emoji width" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("👍");
|
||||
s.nextSlice("👍");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1390,7 +1390,7 @@ test "shape variation selector VS15" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1429,7 +1429,7 @@ test "shape variation selector VS16" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1463,9 +1463,9 @@ test "shape with empty cells in between" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("A");
|
||||
try s.nextSlice("\x1b[5C"); // 5 spaces forward
|
||||
try s.nextSlice("B");
|
||||
s.nextSlice("A");
|
||||
s.nextSlice("\x1b[5C"); // 5 spaces forward
|
||||
s.nextSlice("B");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1510,7 +1510,7 @@ test "shape Combining characters" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1560,7 +1560,7 @@ test "shape Devanagari string" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("अपार्टमेंट");
|
||||
s.nextSlice("अपार्टमेंट");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1619,7 +1619,7 @@ test "shape Tai Tham vowels (position differs from advance)" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1680,7 +1680,7 @@ test "shape Tai Tham letters (position.y differs from advance)" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1740,7 +1740,7 @@ test "shape Javanese ligatures" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1803,7 +1803,7 @@ test "shape Chakma vowel sign with ligature (vowel sign renders first)" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1874,7 +1874,7 @@ test "shape Bengali ligatures with out of order vowels" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1929,7 +1929,7 @@ test "shape box glyphs" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1967,7 +1967,7 @@ test "shape selection boundary" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("a1b2c3d4e5");
|
||||
s.nextSlice("a1b2c3d4e5");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -2072,7 +2072,7 @@ test "shape cursor boundary" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("a1b2c3d4e5");
|
||||
s.nextSlice("a1b2c3d4e5");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -2209,7 +2209,7 @@ test "shape cursor boundary and colored emoji" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("👍🏼");
|
||||
s.nextSlice("👍🏼");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -2306,7 +2306,7 @@ test "shape cell attribute change" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(">=");
|
||||
s.nextSlice(">=");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -2332,9 +2332,9 @@ test "shape cell attribute change" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(">");
|
||||
try s.nextSlice("\x1b[1m"); // Bold
|
||||
try s.nextSlice("=");
|
||||
s.nextSlice(">");
|
||||
s.nextSlice("\x1b[1m"); // Bold
|
||||
s.nextSlice("=");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -2361,11 +2361,11 @@ test "shape cell attribute change" {
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
// RGB 1, 2, 3
|
||||
try s.nextSlice("\x1b[38;2;1;2;3m");
|
||||
try s.nextSlice(">");
|
||||
s.nextSlice("\x1b[38;2;1;2;3m");
|
||||
s.nextSlice(">");
|
||||
// RGB 3, 2, 1
|
||||
try s.nextSlice("\x1b[38;2;3;2;1m");
|
||||
try s.nextSlice("=");
|
||||
s.nextSlice("\x1b[38;2;3;2;1m");
|
||||
s.nextSlice("=");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -2392,11 +2392,11 @@ test "shape cell attribute change" {
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
// RGB 1, 2, 3 bg
|
||||
try s.nextSlice("\x1b[48;2;1;2;3m");
|
||||
try s.nextSlice(">");
|
||||
s.nextSlice("\x1b[48;2;1;2;3m");
|
||||
s.nextSlice(">");
|
||||
// RGB 3, 2, 1 bg
|
||||
try s.nextSlice("\x1b[48;2;3;2;1m");
|
||||
try s.nextSlice("=");
|
||||
s.nextSlice("\x1b[48;2;3;2;1m");
|
||||
s.nextSlice("=");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -2423,9 +2423,9 @@ test "shape cell attribute change" {
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
// RGB 1, 2, 3 bg
|
||||
try s.nextSlice("\x1b[48;2;1;2;3m");
|
||||
try s.nextSlice(">");
|
||||
try s.nextSlice("=");
|
||||
s.nextSlice("\x1b[48;2;1;2;3m");
|
||||
s.nextSlice(">");
|
||||
s.nextSlice("=");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -2468,7 +2468,7 @@ test "shape high plane sprite font codepoint" {
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
// U+1FB70: Vertical One Eighth Block-2
|
||||
try s.nextSlice("\u{1FB70}");
|
||||
s.nextSlice("\u{1FB70}");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
|
||||
@@ -448,7 +448,7 @@ test "run iterator" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("ABCD");
|
||||
s.nextSlice("ABCD");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -472,7 +472,7 @@ test "run iterator" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("ABCD EFG");
|
||||
s.nextSlice("ABCD EFG");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -495,7 +495,7 @@ test "run iterator" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("A😃D");
|
||||
s.nextSlice("A😃D");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -533,7 +533,7 @@ test "run iterator: empty cells with background set" {
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
// Set red background and write A
|
||||
try s.nextSlice("\x1b[48;2;255;0;0mA");
|
||||
s.nextSlice("\x1b[48;2;255;0;0mA");
|
||||
|
||||
// Get our first row
|
||||
{
|
||||
@@ -592,7 +592,7 @@ test "shape" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -626,7 +626,7 @@ test "shape inconsolata ligs" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(">=");
|
||||
s.nextSlice(">=");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -655,7 +655,7 @@ test "shape inconsolata ligs" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("===");
|
||||
s.nextSlice("===");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -692,7 +692,7 @@ test "shape monaspace ligs" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("===");
|
||||
s.nextSlice("===");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -732,7 +732,7 @@ test "shape arabic forced LTR" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(@embedFile("testdata/arabic.txt"));
|
||||
s.nextSlice(@embedFile("testdata/arabic.txt"));
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -773,7 +773,7 @@ test "shape emoji width" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("👍");
|
||||
s.nextSlice("👍");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -870,7 +870,7 @@ test "shape variation selector VS15" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -911,7 +911,7 @@ test "shape variation selector VS16" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -950,9 +950,9 @@ test "shape with empty cells in between" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("A");
|
||||
try s.nextSlice("\x1b[5C");
|
||||
try s.nextSlice("B");
|
||||
s.nextSlice("A");
|
||||
s.nextSlice("\x1b[5C");
|
||||
s.nextSlice("B");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -997,7 +997,7 @@ test "shape Combining characters" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1048,7 +1048,7 @@ test "shape Devanagari string" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("अपार्टमेंट");
|
||||
s.nextSlice("अपार्टमेंट");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1111,7 +1111,7 @@ test "shape Tai Tham vowels (position differs from advance)" {
|
||||
|
||||
// var s = t.vtStream();
|
||||
// defer s.deinit();
|
||||
// try s.nextSlice(buf[0..buf_idx]);
|
||||
// s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
// var state: terminal.RenderState = .empty;
|
||||
// defer state.deinit(alloc);
|
||||
@@ -1170,7 +1170,7 @@ test "shape Tibetan characters" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1232,7 +1232,7 @@ test "shape Tai Tham letters (run_offset.y differs from zero)" {
|
||||
|
||||
// var s = t.vtStream();
|
||||
// defer s.deinit();
|
||||
// try s.nextSlice(buf[0..buf_idx]);
|
||||
// s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
// var state: terminal.RenderState = .empty;
|
||||
// defer state.deinit(alloc);
|
||||
@@ -1295,7 +1295,7 @@ test "shape Javanese ligatures" {
|
||||
|
||||
// var s = t.vtStream();
|
||||
// defer s.deinit();
|
||||
// try s.nextSlice(buf[0..buf_idx]);
|
||||
// s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
// var state: terminal.RenderState = .empty;
|
||||
// defer state.deinit(alloc);
|
||||
@@ -1358,7 +1358,7 @@ test "shape Chakma vowel sign with ligature (vowel sign renders first)" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1433,7 +1433,7 @@ test "shape Bengali ligatures with out of order vowels" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1487,7 +1487,7 @@ test "shape box glyphs" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(buf[0..buf_idx]);
|
||||
s.nextSlice(buf[0..buf_idx]);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1526,7 +1526,7 @@ test "shape selection boundary" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("a1b2c3d4e5");
|
||||
s.nextSlice("a1b2c3d4e5");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1631,7 +1631,7 @@ test "shape cursor boundary" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("a1b2c3d4e5");
|
||||
s.nextSlice("a1b2c3d4e5");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1771,7 +1771,7 @@ test "shape cursor boundary and colored emoji" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("👍🏼");
|
||||
s.nextSlice("👍🏼");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1868,7 +1868,7 @@ test "shape cell attribute change" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(">=");
|
||||
s.nextSlice(">=");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1894,9 +1894,9 @@ test "shape cell attribute change" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice(">");
|
||||
try s.nextSlice("\x1b[1m");
|
||||
try s.nextSlice("=");
|
||||
s.nextSlice(">");
|
||||
s.nextSlice("\x1b[1m");
|
||||
s.nextSlice("=");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1923,11 +1923,11 @@ test "shape cell attribute change" {
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
// RGB 1, 2, 3
|
||||
try s.nextSlice("\x1b[38;2;1;2;3m");
|
||||
try s.nextSlice(">");
|
||||
s.nextSlice("\x1b[38;2;1;2;3m");
|
||||
s.nextSlice(">");
|
||||
// RGB 3, 2, 1
|
||||
try s.nextSlice("\x1b[38;2;3;2;1m");
|
||||
try s.nextSlice("=");
|
||||
s.nextSlice("\x1b[38;2;3;2;1m");
|
||||
s.nextSlice("=");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1954,11 +1954,11 @@ test "shape cell attribute change" {
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
// RGB 1, 2, 3 bg
|
||||
try s.nextSlice("\x1b[48;2;1;2;3m");
|
||||
try s.nextSlice(">");
|
||||
s.nextSlice("\x1b[48;2;1;2;3m");
|
||||
s.nextSlice(">");
|
||||
// RGB 3, 2, 1 bg
|
||||
try s.nextSlice("\x1b[48;2;3;2;1m");
|
||||
try s.nextSlice("=");
|
||||
s.nextSlice("\x1b[48;2;3;2;1m");
|
||||
s.nextSlice("=");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1985,9 +1985,9 @@ test "shape cell attribute change" {
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
// RGB 1, 2, 3 bg
|
||||
try s.nextSlice("\x1b[48;2;1;2;3m");
|
||||
try s.nextSlice(">");
|
||||
try s.nextSlice("=");
|
||||
s.nextSlice("\x1b[48;2;1;2;3m");
|
||||
s.nextSlice(">");
|
||||
s.nextSlice("=");
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
|
||||
@@ -54,7 +54,7 @@ pub const Stream = struct {
|
||||
.events = &self.events,
|
||||
};
|
||||
defer self.parser_stream.handler.state = null;
|
||||
try self.parser_stream.nextSlice(data);
|
||||
self.parser_stream.nextSlice(data);
|
||||
}
|
||||
|
||||
pub fn draw(
|
||||
@@ -736,7 +736,7 @@ const VTHandler = struct {
|
||||
self: *VTHandler,
|
||||
comptime action: VTHandler.Stream.Action.Tag,
|
||||
value: VTHandler.Stream.Action.Value(action),
|
||||
) !void {
|
||||
) void {
|
||||
_ = self;
|
||||
_ = value;
|
||||
}
|
||||
|
||||
@@ -528,7 +528,7 @@ test "Cell constraint widths" {
|
||||
// symbol->nothing: 2
|
||||
{
|
||||
t.fullReset();
|
||||
try s.nextSlice("");
|
||||
s.nextSlice("");
|
||||
try state.update(alloc, &t);
|
||||
try testing.expectEqual(2, constraintWidth(
|
||||
state.row_data.get(0).cells.items(.raw),
|
||||
@@ -540,7 +540,7 @@ test "Cell constraint widths" {
|
||||
// symbol->character: 1
|
||||
{
|
||||
t.fullReset();
|
||||
try s.nextSlice("z");
|
||||
s.nextSlice("z");
|
||||
try state.update(alloc, &t);
|
||||
try testing.expectEqual(1, constraintWidth(
|
||||
state.row_data.get(0).cells.items(.raw),
|
||||
@@ -552,7 +552,7 @@ test "Cell constraint widths" {
|
||||
// symbol->space: 2
|
||||
{
|
||||
t.fullReset();
|
||||
try s.nextSlice(" z");
|
||||
s.nextSlice(" z");
|
||||
try state.update(alloc, &t);
|
||||
try testing.expectEqual(2, constraintWidth(
|
||||
state.row_data.get(0).cells.items(.raw),
|
||||
@@ -563,7 +563,7 @@ test "Cell constraint widths" {
|
||||
// symbol->no-break space: 1
|
||||
{
|
||||
t.fullReset();
|
||||
try s.nextSlice("\u{00a0}z");
|
||||
s.nextSlice("\u{00a0}z");
|
||||
try state.update(alloc, &t);
|
||||
try testing.expectEqual(1, constraintWidth(
|
||||
state.row_data.get(0).cells.items(.raw),
|
||||
@@ -575,7 +575,7 @@ test "Cell constraint widths" {
|
||||
// symbol->end of row: 1
|
||||
{
|
||||
t.fullReset();
|
||||
try s.nextSlice(" ");
|
||||
s.nextSlice(" ");
|
||||
try state.update(alloc, &t);
|
||||
try testing.expectEqual(1, constraintWidth(
|
||||
state.row_data.get(0).cells.items(.raw),
|
||||
@@ -587,7 +587,7 @@ test "Cell constraint widths" {
|
||||
// character->symbol: 2
|
||||
{
|
||||
t.fullReset();
|
||||
try s.nextSlice("z");
|
||||
s.nextSlice("z");
|
||||
try state.update(alloc, &t);
|
||||
try testing.expectEqual(2, constraintWidth(
|
||||
state.row_data.get(0).cells.items(.raw),
|
||||
@@ -599,7 +599,7 @@ test "Cell constraint widths" {
|
||||
// symbol->symbol: 1,1
|
||||
{
|
||||
t.fullReset();
|
||||
try s.nextSlice("");
|
||||
s.nextSlice("");
|
||||
try state.update(alloc, &t);
|
||||
try testing.expectEqual(1, constraintWidth(
|
||||
state.row_data.get(0).cells.items(.raw),
|
||||
@@ -616,7 +616,7 @@ test "Cell constraint widths" {
|
||||
// symbol->space->symbol: 2,2
|
||||
{
|
||||
t.fullReset();
|
||||
try s.nextSlice(" ");
|
||||
s.nextSlice(" ");
|
||||
try state.update(alloc, &t);
|
||||
try testing.expectEqual(2, constraintWidth(
|
||||
state.row_data.get(0).cells.items(.raw),
|
||||
@@ -633,7 +633,7 @@ test "Cell constraint widths" {
|
||||
// symbol->powerline: 1 (dedicated test because powerline is special-cased in cellpkg)
|
||||
{
|
||||
t.fullReset();
|
||||
try s.nextSlice("");
|
||||
s.nextSlice("");
|
||||
try state.update(alloc, &t);
|
||||
try testing.expectEqual(1, constraintWidth(
|
||||
state.row_data.get(0).cells.items(.raw),
|
||||
@@ -645,7 +645,7 @@ test "Cell constraint widths" {
|
||||
// powerline->symbol: 2 (dedicated test because powerline is special-cased in cellpkg)
|
||||
{
|
||||
t.fullReset();
|
||||
try s.nextSlice("");
|
||||
s.nextSlice("");
|
||||
try state.update(alloc, &t);
|
||||
try testing.expectEqual(2, constraintWidth(
|
||||
state.row_data.get(0).cells.items(.raw),
|
||||
@@ -657,7 +657,7 @@ test "Cell constraint widths" {
|
||||
// powerline->nothing: 2 (dedicated test because powerline is special-cased in cellpkg)
|
||||
{
|
||||
t.fullReset();
|
||||
try s.nextSlice("");
|
||||
s.nextSlice("");
|
||||
try state.update(alloc, &t);
|
||||
try testing.expectEqual(2, constraintWidth(
|
||||
state.row_data.get(0).cells.items(.raw),
|
||||
@@ -669,7 +669,7 @@ test "Cell constraint widths" {
|
||||
// powerline->space: 2 (dedicated test because powerline is special-cased in cellpkg)
|
||||
{
|
||||
t.fullReset();
|
||||
try s.nextSlice(" z");
|
||||
s.nextSlice(" z");
|
||||
try state.update(alloc, &t);
|
||||
try testing.expectEqual(2, constraintWidth(
|
||||
state.row_data.get(0).cells.items(.raw),
|
||||
|
||||
@@ -148,7 +148,7 @@ test "renderCellMap" {
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
const str = "1ABCD2EFGH\r\n3IJKL";
|
||||
try s.nextSlice(str);
|
||||
s.nextSlice(str);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -201,7 +201,7 @@ test "renderCellMap hover links" {
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
const str = "1ABCD2EFGH\r\n3IJKL";
|
||||
try s.nextSlice(str);
|
||||
s.nextSlice(str);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -279,7 +279,7 @@ test "renderCellMap mods no match" {
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
const str = "1ABCD2EFGH\r\n3IJKL";
|
||||
try s.nextSlice(str);
|
||||
s.nextSlice(str);
|
||||
|
||||
var state: terminal.RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -908,7 +908,7 @@ test "basic text" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("ABCD");
|
||||
s.nextSlice("ABCD");
|
||||
|
||||
var state: RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -944,9 +944,9 @@ test "styled text" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("\x1b[1mA"); // Bold
|
||||
try s.nextSlice("\x1b[0;3mB"); // Italic
|
||||
try s.nextSlice("\x1b[0;4mC"); // Underline
|
||||
s.nextSlice("\x1b[1mA"); // Bold
|
||||
s.nextSlice("\x1b[0;3mB"); // Italic
|
||||
s.nextSlice("\x1b[0;4mC"); // Underline
|
||||
|
||||
var state: RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -990,8 +990,8 @@ test "grapheme" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("A");
|
||||
try s.nextSlice("👨"); // this has a ZWJ
|
||||
s.nextSlice("A");
|
||||
s.nextSlice("👨"); // this has a ZWJ
|
||||
|
||||
var state: RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1037,7 +1037,7 @@ test "cursor state in viewport" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("A\x1b[H");
|
||||
s.nextSlice("A\x1b[H");
|
||||
|
||||
var state: RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1052,14 +1052,14 @@ test "cursor state in viewport" {
|
||||
try testing.expect(state.cursor.style.default());
|
||||
|
||||
// Set a style on the cursor
|
||||
try s.nextSlice("\x1b[1m"); // Bold
|
||||
s.nextSlice("\x1b[1m"); // Bold
|
||||
try state.update(alloc, &t);
|
||||
try testing.expect(!state.cursor.style.default());
|
||||
try testing.expect(state.cursor.style.flags.bold);
|
||||
try s.nextSlice("\x1b[0m"); // Reset style
|
||||
s.nextSlice("\x1b[0m"); // Reset style
|
||||
|
||||
// Move cursor to 2,1
|
||||
try s.nextSlice("\x1b[2;3H");
|
||||
s.nextSlice("\x1b[2;3H");
|
||||
try state.update(alloc, &t);
|
||||
try testing.expectEqual(2, state.cursor.active.x);
|
||||
try testing.expectEqual(1, state.cursor.active.y);
|
||||
@@ -1079,7 +1079,7 @@ test "cursor state out of viewport" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("A\r\nB\r\nC\r\nD\r\n");
|
||||
s.nextSlice("A\r\nB\r\nC\r\nD\r\n");
|
||||
|
||||
var state: RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1139,7 +1139,7 @@ test "dirty state" {
|
||||
}
|
||||
|
||||
// Write to first line
|
||||
try s.nextSlice("A");
|
||||
s.nextSlice("A");
|
||||
try state.update(alloc, &t);
|
||||
try testing.expectEqual(.partial, state.dirty);
|
||||
{
|
||||
@@ -1170,7 +1170,7 @@ test "colors" {
|
||||
try state.update(alloc, &t);
|
||||
|
||||
// Change cursor color
|
||||
try s.nextSlice("\x1b]12;#FF0000\x07");
|
||||
s.nextSlice("\x1b]12;#FF0000\x07");
|
||||
try state.update(alloc, &t);
|
||||
|
||||
const c = state.colors.cursor.?;
|
||||
@@ -1179,7 +1179,7 @@ test "colors" {
|
||||
try testing.expectEqual(0, c.b);
|
||||
|
||||
// Change palette color 0 to White
|
||||
try s.nextSlice("\x1b]4;0;#FFFFFF\x07");
|
||||
s.nextSlice("\x1b]4;0;#FFFFFF\x07");
|
||||
try state.update(alloc, &t);
|
||||
const p0 = state.colors.palette[0];
|
||||
try testing.expectEqual(0xFF, p0.r);
|
||||
@@ -1275,7 +1275,7 @@ test "linkCells" {
|
||||
defer state.deinit(alloc);
|
||||
|
||||
// Create a hyperlink
|
||||
try s.nextSlice("\x1b]8;;http://example.com\x1b\\LINK\x1b]8;;\x1b\\");
|
||||
s.nextSlice("\x1b]8;;http://example.com\x1b\\LINK\x1b]8;;\x1b\\");
|
||||
try state.update(alloc, &t);
|
||||
|
||||
// Query link at 0,0
|
||||
@@ -1306,7 +1306,7 @@ test "string" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("AB");
|
||||
s.nextSlice("AB");
|
||||
|
||||
var state: RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1345,12 +1345,12 @@ test "linkCells with scrollback spanning pages" {
|
||||
const first_page_cap = pages.pages.first.?.data.capacity.rows;
|
||||
|
||||
// Fill first page
|
||||
for (0..first_page_cap - 1) |_| try s.nextSlice("\r\n");
|
||||
for (0..first_page_cap - 1) |_| s.nextSlice("\r\n");
|
||||
|
||||
// Create second page with hyperlink
|
||||
try s.nextSlice("\r\n");
|
||||
try s.nextSlice("\x1b]8;;http://example.com\x1b\\LINK\x1b]8;;\x1b\\");
|
||||
for (0..(tail_rows - 1)) |_| try s.nextSlice("\r\n");
|
||||
s.nextSlice("\r\n");
|
||||
s.nextSlice("\x1b]8;;http://example.com\x1b\\LINK\x1b]8;;\x1b\\");
|
||||
for (0..(tail_rows - 1)) |_| s.nextSlice("\r\n");
|
||||
|
||||
var state: RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1416,7 +1416,7 @@ test "dirty row resets highlights" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("ABC");
|
||||
s.nextSlice("ABC");
|
||||
|
||||
var state: RenderState = .empty;
|
||||
defer state.deinit(alloc);
|
||||
@@ -1451,8 +1451,8 @@ test "dirty row resets highlights" {
|
||||
}
|
||||
|
||||
// Write to row 0 to make it dirty
|
||||
try s.nextSlice("\x1b[H"); // Move to home
|
||||
try s.nextSlice("X");
|
||||
s.nextSlice("\x1b[H"); // Move to home
|
||||
s.nextSlice("X");
|
||||
try state.update(alloc, &t);
|
||||
|
||||
// Verify the highlight was reset on the dirty row
|
||||
|
||||
@@ -853,7 +853,7 @@ test {
|
||||
|
||||
var stream = t.vtStream();
|
||||
defer stream.deinit();
|
||||
try stream.nextSlice("Hello, world");
|
||||
stream.nextSlice("Hello, world");
|
||||
|
||||
var ud: TestUserData = .{};
|
||||
defer ud.deinit();
|
||||
|
||||
@@ -108,7 +108,7 @@ test "simple search" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
|
||||
var search: ActiveSearch = try .init(alloc, "Fizz");
|
||||
defer search.deinit();
|
||||
@@ -148,15 +148,15 @@ test "clear screen and search" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
|
||||
var search: ActiveSearch = try .init(alloc, "Fizz");
|
||||
defer search.deinit();
|
||||
_ = try search.update(&t.screens.active.pages);
|
||||
|
||||
try s.nextSlice("\x1b[2J"); // Clear screen
|
||||
try s.nextSlice("\x1b[H"); // Move cursor home
|
||||
try s.nextSlice("Buzz\r\nFizz\r\nBuzz");
|
||||
s.nextSlice("\x1b[2J"); // Clear screen
|
||||
s.nextSlice("\x1b[H"); // Move cursor home
|
||||
s.nextSlice("Buzz\r\nFizz\r\nBuzz");
|
||||
_ = try search.update(&t.screens.active.pages);
|
||||
|
||||
{
|
||||
|
||||
@@ -141,7 +141,7 @@ test "simple search" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
|
||||
var search: PageListSearch = try .init(
|
||||
alloc,
|
||||
@@ -191,14 +191,14 @@ test "feed multiple pages with matches" {
|
||||
|
||||
// Fill up first page
|
||||
const first_page_rows = t.screens.active.pages.pages.first.?.data.capacity.rows;
|
||||
for (0..first_page_rows - 1) |_| try s.nextSlice("\r\n");
|
||||
try s.nextSlice("Fizz");
|
||||
for (0..first_page_rows - 1) |_| s.nextSlice("\r\n");
|
||||
s.nextSlice("Fizz");
|
||||
try testing.expect(t.screens.active.pages.pages.first == t.screens.active.pages.pages.last);
|
||||
|
||||
// Create second page
|
||||
try s.nextSlice("\r\n");
|
||||
s.nextSlice("\r\n");
|
||||
try testing.expect(t.screens.active.pages.pages.first != t.screens.active.pages.pages.last);
|
||||
try s.nextSlice("Buzz\r\nFizz");
|
||||
s.nextSlice("Buzz\r\nFizz");
|
||||
|
||||
var search: PageListSearch = try .init(
|
||||
alloc,
|
||||
@@ -235,13 +235,13 @@ test "feed multiple pages no matches" {
|
||||
|
||||
// Fill up first page
|
||||
const first_page_rows = t.screens.active.pages.pages.first.?.data.capacity.rows;
|
||||
for (0..first_page_rows - 1) |_| try s.nextSlice("\r\n");
|
||||
try s.nextSlice("Hello");
|
||||
for (0..first_page_rows - 1) |_| s.nextSlice("\r\n");
|
||||
s.nextSlice("Hello");
|
||||
|
||||
// Create second page
|
||||
try s.nextSlice("\r\n");
|
||||
s.nextSlice("\r\n");
|
||||
try testing.expect(t.screens.active.pages.pages.first != t.screens.active.pages.pages.last);
|
||||
try s.nextSlice("World");
|
||||
s.nextSlice("World");
|
||||
|
||||
var search: PageListSearch = try .init(
|
||||
alloc,
|
||||
@@ -275,14 +275,14 @@ test "feed iteratively through multiple matches" {
|
||||
const first_page_rows = t.screens.active.pages.pages.first.?.data.capacity.rows;
|
||||
|
||||
// Fill first page with a match at the end
|
||||
for (0..first_page_rows - 1) |_| try s.nextSlice("\r\n");
|
||||
try s.nextSlice("Page1Test");
|
||||
for (0..first_page_rows - 1) |_| s.nextSlice("\r\n");
|
||||
s.nextSlice("Page1Test");
|
||||
try testing.expect(t.screens.active.pages.pages.first == t.screens.active.pages.pages.last);
|
||||
|
||||
// Create second page with a match
|
||||
try s.nextSlice("\r\n");
|
||||
s.nextSlice("\r\n");
|
||||
try testing.expect(t.screens.active.pages.pages.first != t.screens.active.pages.pages.last);
|
||||
try s.nextSlice("Page2Test");
|
||||
s.nextSlice("Page2Test");
|
||||
|
||||
var search: PageListSearch = try .init(
|
||||
alloc,
|
||||
@@ -316,13 +316,13 @@ test "feed with match spanning page boundary" {
|
||||
const first_page_rows = t.screens.active.pages.pages.first.?.data.capacity.rows;
|
||||
|
||||
// Fill first page ending with "Te"
|
||||
for (0..first_page_rows - 1) |_| try s.nextSlice("\r\n");
|
||||
for (0..t.screens.active.pages.cols - 2) |_| try s.nextSlice("x");
|
||||
try s.nextSlice("Te");
|
||||
for (0..first_page_rows - 1) |_| s.nextSlice("\r\n");
|
||||
for (0..t.screens.active.pages.cols - 2) |_| s.nextSlice("x");
|
||||
s.nextSlice("Te");
|
||||
try testing.expect(t.screens.active.pages.pages.first == t.screens.active.pages.pages.last);
|
||||
|
||||
// Second page starts with "st"
|
||||
try s.nextSlice("st");
|
||||
s.nextSlice("st");
|
||||
try testing.expect(t.screens.active.pages.pages.first != t.screens.active.pages.pages.last);
|
||||
|
||||
var search: PageListSearch = try .init(
|
||||
@@ -370,15 +370,15 @@ test "feed with match spanning page boundary with newline" {
|
||||
const first_page_rows = t.screens.active.pages.pages.first.?.data.capacity.rows;
|
||||
|
||||
// Fill first page ending with "Te"
|
||||
for (0..first_page_rows - 1) |_| try s.nextSlice("\r\n");
|
||||
for (0..t.screens.active.pages.cols - 2) |_| try s.nextSlice("x");
|
||||
try s.nextSlice("Te");
|
||||
for (0..first_page_rows - 1) |_| s.nextSlice("\r\n");
|
||||
for (0..t.screens.active.pages.cols - 2) |_| s.nextSlice("x");
|
||||
s.nextSlice("Te");
|
||||
try testing.expect(t.screens.active.pages.pages.first == t.screens.active.pages.pages.last);
|
||||
|
||||
// Second page starts with "st"
|
||||
try s.nextSlice("\r\n");
|
||||
s.nextSlice("\r\n");
|
||||
try testing.expect(t.screens.active.pages.pages.first != t.screens.active.pages.pages.last);
|
||||
try s.nextSlice("st");
|
||||
s.nextSlice("st");
|
||||
|
||||
var search: PageListSearch = try .init(
|
||||
alloc,
|
||||
|
||||
@@ -827,7 +827,7 @@ test "simple search" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
|
||||
var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz");
|
||||
defer search.deinit();
|
||||
@@ -877,10 +877,10 @@ test "simple search with history" {
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
|
||||
try s.nextSlice("Fizz\r\n");
|
||||
while (list.totalPages() < 3) try s.nextSlice("\r\n");
|
||||
for (0..list.rows) |_| try s.nextSlice("\r\n");
|
||||
try s.nextSlice("hello.");
|
||||
s.nextSlice("Fizz\r\n");
|
||||
while (list.totalPages() < 3) s.nextSlice("\r\n");
|
||||
for (0..list.rows) |_| s.nextSlice("\r\n");
|
||||
s.nextSlice("hello.");
|
||||
|
||||
var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz");
|
||||
defer search.deinit();
|
||||
@@ -917,7 +917,7 @@ test "reload active with history change" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("Fizz\r\n");
|
||||
s.nextSlice("Fizz\r\n");
|
||||
|
||||
// Start up our search which will populate our initial active area.
|
||||
var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz");
|
||||
@@ -930,9 +930,9 @@ test "reload active with history change" {
|
||||
}
|
||||
|
||||
// Grow into two pages so our history pin will move.
|
||||
while (list.totalPages() < 2) try s.nextSlice("\r\n");
|
||||
for (0..list.rows) |_| try s.nextSlice("\r\n");
|
||||
try s.nextSlice("2Fizz");
|
||||
while (list.totalPages() < 2) s.nextSlice("\r\n");
|
||||
for (0..list.rows) |_| s.nextSlice("\r\n");
|
||||
s.nextSlice("2Fizz");
|
||||
|
||||
// Active area changed so reload
|
||||
try search.reloadActive();
|
||||
@@ -969,7 +969,7 @@ test "reload active with history change" {
|
||||
|
||||
// Reset the screen which will make our pin garbage.
|
||||
t.fullReset();
|
||||
try s.nextSlice("WeFizzing");
|
||||
s.nextSlice("WeFizzing");
|
||||
try search.reloadActive();
|
||||
try search.searchAll();
|
||||
|
||||
@@ -998,7 +998,7 @@ test "active change contents" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("Fuzz\r\nBuzz\r\nFizz\r\nBang");
|
||||
s.nextSlice("Fuzz\r\nBuzz\r\nFizz\r\nBang");
|
||||
|
||||
var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz");
|
||||
defer search.deinit();
|
||||
@@ -1006,8 +1006,8 @@ test "active change contents" {
|
||||
try testing.expectEqual(1, search.active_results.items.len);
|
||||
|
||||
// Erase the screen, move our cursor to the top, and change contents.
|
||||
try s.nextSlice("\x1b[2J\x1b[H"); // Clear screen and move home
|
||||
try s.nextSlice("Bang\r\nFizz\r\nHello!");
|
||||
s.nextSlice("\x1b[2J\x1b[H"); // Clear screen and move home
|
||||
s.nextSlice("Bang\r\nFizz\r\nHello!");
|
||||
|
||||
try search.reloadActive();
|
||||
try search.searchAll();
|
||||
@@ -1038,7 +1038,7 @@ test "select next" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
|
||||
var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz");
|
||||
defer search.deinit();
|
||||
@@ -1097,7 +1097,7 @@ test "select in active changes contents completely" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
|
||||
var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz");
|
||||
defer search.deinit();
|
||||
@@ -1118,8 +1118,8 @@ test "select in active changes contents completely" {
|
||||
}
|
||||
|
||||
// Erase the screen, move our cursor to the top, and change contents.
|
||||
try s.nextSlice("\x1b[2J\x1b[H"); // Clear screen and move home
|
||||
try s.nextSlice("Fuzz\r\nFizz\r\nHello!");
|
||||
s.nextSlice("\x1b[2J\x1b[H"); // Clear screen and move home
|
||||
s.nextSlice("Fuzz\r\nFizz\r\nHello!");
|
||||
|
||||
try search.reloadActive();
|
||||
{
|
||||
@@ -1136,8 +1136,8 @@ test "select in active changes contents completely" {
|
||||
}
|
||||
|
||||
// Erase the screen, redraw with same contents.
|
||||
try s.nextSlice("\x1b[2J\x1b[H"); // Clear screen and move home
|
||||
try s.nextSlice("Fuzz\r\nFizz\r\nFizz");
|
||||
s.nextSlice("\x1b[2J\x1b[H"); // Clear screen and move home
|
||||
s.nextSlice("Fuzz\r\nFizz\r\nFizz");
|
||||
|
||||
try search.reloadActive();
|
||||
{
|
||||
@@ -1167,10 +1167,10 @@ test "select into history" {
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
|
||||
try s.nextSlice("Fizz\r\n");
|
||||
while (list.totalPages() < 3) try s.nextSlice("\r\n");
|
||||
for (0..list.rows) |_| try s.nextSlice("\r\n");
|
||||
try s.nextSlice("hello.");
|
||||
s.nextSlice("Fizz\r\n");
|
||||
while (list.totalPages() < 3) s.nextSlice("\r\n");
|
||||
for (0..list.rows) |_| s.nextSlice("\r\n");
|
||||
s.nextSlice("hello.");
|
||||
|
||||
var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz");
|
||||
defer search.deinit();
|
||||
@@ -1191,8 +1191,8 @@ test "select into history" {
|
||||
}
|
||||
|
||||
// Erase the screen, redraw with same contents.
|
||||
try s.nextSlice("\x1b[2J\x1b[H"); // Clear screen and move home
|
||||
try s.nextSlice("yo yo");
|
||||
s.nextSlice("\x1b[2J\x1b[H"); // Clear screen and move home
|
||||
s.nextSlice("yo yo");
|
||||
|
||||
try search.reloadActive();
|
||||
{
|
||||
@@ -1209,7 +1209,7 @@ test "select into history" {
|
||||
}
|
||||
|
||||
// Create some new history by adding more lines.
|
||||
try s.nextSlice("\r\nfizz\r\nfizz\r\nfizz"); // Clear screen and move home
|
||||
s.nextSlice("\r\nfizz\r\nfizz\r\nfizz"); // Clear screen and move home
|
||||
try search.reloadActive();
|
||||
{
|
||||
// Our selection should not move since the history is still not
|
||||
@@ -1233,7 +1233,7 @@ test "select prev" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
|
||||
var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz");
|
||||
defer search.deinit();
|
||||
@@ -1292,7 +1292,7 @@ test "select prev then next" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
|
||||
var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz");
|
||||
defer search.deinit();
|
||||
@@ -1342,10 +1342,10 @@ test "select prev with history" {
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
|
||||
try s.nextSlice("Fizz\r\n");
|
||||
while (list.totalPages() < 3) try s.nextSlice("\r\n");
|
||||
for (0..list.rows) |_| try s.nextSlice("\r\n");
|
||||
try s.nextSlice("Fizz.");
|
||||
s.nextSlice("Fizz\r\n");
|
||||
while (list.totalPages() < 3) s.nextSlice("\r\n");
|
||||
for (0..list.rows) |_| s.nextSlice("\r\n");
|
||||
s.nextSlice("Fizz.");
|
||||
|
||||
var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz");
|
||||
defer search.deinit();
|
||||
@@ -1399,9 +1399,9 @@ test "screen search no scrollback has no history" {
|
||||
// no way to test it using public APIs, but at the time of writing
|
||||
// this test, CSI 22 J (scroll complete) pushes into scrollback
|
||||
// with alt screen.
|
||||
try s.nextSlice("Fizz\r\n");
|
||||
try s.nextSlice("\x1b[22J");
|
||||
try s.nextSlice("hello.");
|
||||
s.nextSlice("Fizz\r\n");
|
||||
s.nextSlice("\x1b[22J");
|
||||
s.nextSlice("hello.");
|
||||
|
||||
var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz");
|
||||
defer search.deinit();
|
||||
@@ -1431,10 +1431,10 @@ test "reloadActive partial history cleanup on appendSlice error" {
|
||||
|
||||
// Write multiple "Fizz" matches that will end up in history.
|
||||
// We need enough content to push "Fizz" entries into scrollback.
|
||||
try s.nextSlice("Fizz\r\nFizz\r\n");
|
||||
while (list.totalPages() < 3) try s.nextSlice("\r\n");
|
||||
for (0..list.rows) |_| try s.nextSlice("\r\n");
|
||||
try s.nextSlice("Fizz.");
|
||||
s.nextSlice("Fizz\r\nFizz\r\n");
|
||||
while (list.totalPages() < 3) s.nextSlice("\r\n");
|
||||
for (0..list.rows) |_| s.nextSlice("\r\n");
|
||||
s.nextSlice("Fizz.");
|
||||
|
||||
// Complete initial search
|
||||
var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz");
|
||||
@@ -1443,9 +1443,9 @@ test "reloadActive partial history cleanup on appendSlice error" {
|
||||
|
||||
// Now trigger reloadActive by adding more content that changes the
|
||||
// active/history boundary. First add more "Fizz" entries to history.
|
||||
try s.nextSlice("\r\nFizz\r\nFizz\r\n");
|
||||
while (list.totalPages() < 4) try s.nextSlice("\r\n");
|
||||
for (0..list.rows) |_| try s.nextSlice("\r\n");
|
||||
s.nextSlice("\r\nFizz\r\nFizz\r\n");
|
||||
while (list.totalPages() < 4) s.nextSlice("\r\n");
|
||||
for (0..list.rows) |_| s.nextSlice("\r\n");
|
||||
|
||||
// Arm the tripwire to fail at appendSlice (after the loop completes).
|
||||
// At this point, there are FlattenedHighlight items in the results list
|
||||
@@ -1478,10 +1478,10 @@ test "reloadActive partial history cleanup on loop append error" {
|
||||
|
||||
// Write multiple "Fizz" matches that will end up in history.
|
||||
// We need enough content to push "Fizz" entries into scrollback.
|
||||
try s.nextSlice("Fizz\r\nFizz\r\n");
|
||||
while (list.totalPages() < 3) try s.nextSlice("\r\n");
|
||||
for (0..list.rows) |_| try s.nextSlice("\r\n");
|
||||
try s.nextSlice("Fizz.");
|
||||
s.nextSlice("Fizz\r\nFizz\r\n");
|
||||
while (list.totalPages() < 3) s.nextSlice("\r\n");
|
||||
for (0..list.rows) |_| s.nextSlice("\r\n");
|
||||
s.nextSlice("Fizz.");
|
||||
|
||||
// Complete initial search
|
||||
var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz");
|
||||
@@ -1490,9 +1490,9 @@ test "reloadActive partial history cleanup on loop append error" {
|
||||
|
||||
// Now trigger reloadActive by adding more content that changes the
|
||||
// active/history boundary. First add more "Fizz" entries to history.
|
||||
try s.nextSlice("\r\nFizz\r\nFizz\r\n");
|
||||
while (list.totalPages() < 4) try s.nextSlice("\r\n");
|
||||
for (0..list.rows) |_| try s.nextSlice("\r\n");
|
||||
s.nextSlice("\r\nFizz\r\nFizz\r\n");
|
||||
while (list.totalPages() < 4) s.nextSlice("\r\n");
|
||||
for (0..list.rows) |_| s.nextSlice("\r\n");
|
||||
|
||||
// Arm the tripwire to fail after the first loop append succeeds.
|
||||
// This leaves at least one FlattenedHighlight in the results list
|
||||
|
||||
@@ -1583,7 +1583,7 @@ test "SlidingWindow single append soft wrapped" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("A\r\nxxboo!\r\nC");
|
||||
s.nextSlice("A\r\nxxboo!\r\nC");
|
||||
|
||||
// We want to test single-page cases.
|
||||
const screen = t.screens.active;
|
||||
@@ -1620,7 +1620,7 @@ test "SlidingWindow single append reversed soft wrapped" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("A\r\nxxboo!\r\nC");
|
||||
s.nextSlice("A\r\nxxboo!\r\nC");
|
||||
|
||||
// We want to test single-page cases.
|
||||
const screen = t.screens.active;
|
||||
|
||||
@@ -223,7 +223,7 @@ test "simple search" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
|
||||
var search: ViewportSearch = try .init(alloc, "Fizz");
|
||||
defer search.deinit();
|
||||
@@ -266,15 +266,15 @@ test "clear screen and search" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
|
||||
var search: ViewportSearch = try .init(alloc, "Fizz");
|
||||
defer search.deinit();
|
||||
try testing.expect(try search.update(&t.screens.active.pages));
|
||||
|
||||
try s.nextSlice("\x1b[2J"); // Clear screen
|
||||
try s.nextSlice("\x1b[H"); // Move cursor home
|
||||
try s.nextSlice("Buzz\r\nFizz\r\nBuzz");
|
||||
s.nextSlice("\x1b[2J"); // Clear screen
|
||||
s.nextSlice("\x1b[H"); // Move cursor home
|
||||
s.nextSlice("Buzz\r\nFizz\r\nBuzz");
|
||||
try testing.expect(try search.update(&t.screens.active.pages));
|
||||
|
||||
{
|
||||
@@ -299,7 +299,7 @@ test "clear screen and search dirty tracking" {
|
||||
|
||||
var s = t.vtStream();
|
||||
defer s.deinit();
|
||||
try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
|
||||
var search: ViewportSearch = try .init(alloc, "Fizz");
|
||||
defer search.deinit();
|
||||
@@ -313,9 +313,9 @@ test "clear screen and search dirty tracking" {
|
||||
// Should not update since nothing changed
|
||||
try testing.expect(!try search.update(&t.screens.active.pages));
|
||||
|
||||
try s.nextSlice("\x1b[2J"); // Clear screen
|
||||
try s.nextSlice("\x1b[H"); // Move cursor home
|
||||
try s.nextSlice("Buzz\r\nFizz\r\nBuzz");
|
||||
s.nextSlice("\x1b[2J"); // Clear screen
|
||||
s.nextSlice("\x1b[H"); // Move cursor home
|
||||
s.nextSlice("Buzz\r\nFizz\r\nBuzz");
|
||||
|
||||
// Should still not update since active area isn't dirty
|
||||
try testing.expect(!try search.update(&t.screens.active.pages));
|
||||
@@ -349,14 +349,14 @@ test "history search, no active area" {
|
||||
|
||||
// Fill up first page
|
||||
const first_page_rows = t.screens.active.pages.pages.first.?.data.capacity.rows;
|
||||
try s.nextSlice("Fizz\r\n");
|
||||
for (1..first_page_rows - 1) |_| try s.nextSlice("\r\n");
|
||||
s.nextSlice("Fizz\r\n");
|
||||
for (1..first_page_rows - 1) |_| s.nextSlice("\r\n");
|
||||
try testing.expect(t.screens.active.pages.pages.first == t.screens.active.pages.pages.last);
|
||||
|
||||
// Create second page
|
||||
try s.nextSlice("\r\n");
|
||||
s.nextSlice("\r\n");
|
||||
try testing.expect(t.screens.active.pages.pages.first != t.screens.active.pages.pages.last);
|
||||
try s.nextSlice("Buzz\r\nFizz");
|
||||
s.nextSlice("Buzz\r\nFizz");
|
||||
|
||||
t.scrollViewport(.top);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,8 @@ const osc_color = @import("osc/parsers/color.zig");
|
||||
const kitty_color = @import("kitty/color.zig");
|
||||
const Terminal = @import("Terminal.zig");
|
||||
|
||||
const log = std.log.scoped(.stream_readonly);
|
||||
|
||||
/// This is a Stream implementation that processes actions against
|
||||
/// a Terminal and updates the Terminal state. It is called "readonly" because
|
||||
/// it only processes actions that modify terminal state, while ignoring
|
||||
@@ -45,6 +47,16 @@ pub const Handler = struct {
|
||||
self: *Handler,
|
||||
comptime action: Action.Tag,
|
||||
value: Action.Value(action),
|
||||
) void {
|
||||
self.vtFallible(action, value) catch |err| {
|
||||
log.warn("error handling VT action action={} err={}", .{ action, err });
|
||||
};
|
||||
}
|
||||
|
||||
inline fn vtFallible(
|
||||
self: *Handler,
|
||||
comptime action: Action.Tag,
|
||||
value: Action.Value(action),
|
||||
) !void {
|
||||
switch (action) {
|
||||
.print => try self.terminal.print(value.cp),
|
||||
@@ -402,7 +414,7 @@ test "basic print" {
|
||||
var s: Stream = .initAlloc(testing.allocator, .init(&t));
|
||||
defer s.deinit();
|
||||
|
||||
try s.nextSlice("Hello");
|
||||
s.nextSlice("Hello");
|
||||
try testing.expectEqual(@as(usize, 5), t.screens.active.cursor.x);
|
||||
try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.y);
|
||||
|
||||
@@ -419,12 +431,12 @@ test "cursor movement" {
|
||||
defer s.deinit();
|
||||
|
||||
// Move cursor using escape sequences
|
||||
try s.nextSlice("Hello\x1B[1;1H");
|
||||
s.nextSlice("Hello\x1B[1;1H");
|
||||
try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.x);
|
||||
try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.y);
|
||||
|
||||
// Move to position 2,3
|
||||
try s.nextSlice("\x1B[2;3H");
|
||||
s.nextSlice("\x1B[2;3H");
|
||||
try testing.expectEqual(@as(usize, 2), t.screens.active.cursor.x);
|
||||
try testing.expectEqual(@as(usize, 1), t.screens.active.cursor.y);
|
||||
}
|
||||
@@ -437,13 +449,13 @@ test "erase operations" {
|
||||
defer s.deinit();
|
||||
|
||||
// Print some text
|
||||
try s.nextSlice("Hello World");
|
||||
s.nextSlice("Hello World");
|
||||
try testing.expectEqual(@as(usize, 11), t.screens.active.cursor.x);
|
||||
try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.y);
|
||||
|
||||
// Move cursor to position 1,6 and erase from cursor to end of line
|
||||
try s.nextSlice("\x1B[1;6H");
|
||||
try s.nextSlice("\x1B[K");
|
||||
s.nextSlice("\x1B[1;6H");
|
||||
s.nextSlice("\x1B[K");
|
||||
|
||||
const str = try t.plainString(testing.allocator);
|
||||
defer testing.allocator.free(str);
|
||||
@@ -457,7 +469,7 @@ test "tabs" {
|
||||
var s: Stream = .initAlloc(testing.allocator, .init(&t));
|
||||
defer s.deinit();
|
||||
|
||||
try s.nextSlice("A\tB");
|
||||
s.nextSlice("A\tB");
|
||||
try testing.expectEqual(@as(usize, 9), t.screens.active.cursor.x);
|
||||
|
||||
const str = try t.plainString(testing.allocator);
|
||||
@@ -474,9 +486,9 @@ test "modes" {
|
||||
|
||||
// Test wraparound mode
|
||||
try testing.expect(t.modes.get(.wraparound));
|
||||
try s.nextSlice("\x1B[?7l"); // Disable wraparound
|
||||
s.nextSlice("\x1B[?7l"); // Disable wraparound
|
||||
try testing.expect(!t.modes.get(.wraparound));
|
||||
try s.nextSlice("\x1B[?7h"); // Enable wraparound
|
||||
s.nextSlice("\x1B[?7h"); // Enable wraparound
|
||||
try testing.expect(t.modes.get(.wraparound));
|
||||
}
|
||||
|
||||
@@ -488,7 +500,7 @@ test "scrolling regions" {
|
||||
defer s.deinit();
|
||||
|
||||
// Set scrolling region from line 5 to 20
|
||||
try s.nextSlice("\x1B[5;20r");
|
||||
s.nextSlice("\x1B[5;20r");
|
||||
try testing.expectEqual(@as(usize, 4), t.scrolling_region.top);
|
||||
try testing.expectEqual(@as(usize, 19), t.scrolling_region.bottom);
|
||||
try testing.expectEqual(@as(usize, 0), t.scrolling_region.left);
|
||||
@@ -503,8 +515,8 @@ test "charsets" {
|
||||
defer s.deinit();
|
||||
|
||||
// Configure G0 as DEC special graphics
|
||||
try s.nextSlice("\x1B(0");
|
||||
try s.nextSlice("`"); // Should print diamond character
|
||||
s.nextSlice("\x1B(0");
|
||||
s.nextSlice("`"); // Should print diamond character
|
||||
|
||||
const str = try t.plainString(testing.allocator);
|
||||
defer testing.allocator.free(str);
|
||||
@@ -519,18 +531,18 @@ test "alt screen" {
|
||||
defer s.deinit();
|
||||
|
||||
// Write to primary screen
|
||||
try s.nextSlice("Primary");
|
||||
s.nextSlice("Primary");
|
||||
try testing.expectEqual(.primary, t.screens.active_key);
|
||||
|
||||
// Switch to alt screen
|
||||
try s.nextSlice("\x1B[?1049h");
|
||||
s.nextSlice("\x1B[?1049h");
|
||||
try testing.expectEqual(.alternate, t.screens.active_key);
|
||||
|
||||
// Write to alt screen
|
||||
try s.nextSlice("Alt");
|
||||
s.nextSlice("Alt");
|
||||
|
||||
// Switch back to primary
|
||||
try s.nextSlice("\x1B[?1049l");
|
||||
s.nextSlice("\x1B[?1049l");
|
||||
try testing.expectEqual(.primary, t.screens.active_key);
|
||||
|
||||
const str = try t.plainString(testing.allocator);
|
||||
@@ -546,20 +558,20 @@ test "cursor save and restore" {
|
||||
defer s.deinit();
|
||||
|
||||
// Move cursor to 10,15
|
||||
try s.nextSlice("\x1B[10;15H");
|
||||
s.nextSlice("\x1B[10;15H");
|
||||
try testing.expectEqual(@as(usize, 14), t.screens.active.cursor.x);
|
||||
try testing.expectEqual(@as(usize, 9), t.screens.active.cursor.y);
|
||||
|
||||
// Save cursor
|
||||
try s.nextSlice("\x1B7");
|
||||
s.nextSlice("\x1B7");
|
||||
|
||||
// Move cursor elsewhere
|
||||
try s.nextSlice("\x1B[1;1H");
|
||||
s.nextSlice("\x1B[1;1H");
|
||||
try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.x);
|
||||
try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.y);
|
||||
|
||||
// Restore cursor
|
||||
try s.nextSlice("\x1B8");
|
||||
s.nextSlice("\x1B8");
|
||||
try testing.expectEqual(@as(usize, 14), t.screens.active.cursor.x);
|
||||
try testing.expectEqual(@as(usize, 9), t.screens.active.cursor.y);
|
||||
}
|
||||
@@ -572,7 +584,7 @@ test "attributes" {
|
||||
defer s.deinit();
|
||||
|
||||
// Set bold and write text
|
||||
try s.nextSlice("\x1B[1mBold\x1B[0m");
|
||||
s.nextSlice("\x1B[1mBold\x1B[0m");
|
||||
|
||||
// Verify we can write attributes - just check the string was written
|
||||
const str = try t.plainString(testing.allocator);
|
||||
@@ -588,7 +600,7 @@ test "DECALN screen alignment" {
|
||||
defer s.deinit();
|
||||
|
||||
// Run DECALN
|
||||
try s.nextSlice("\x1B#8");
|
||||
s.nextSlice("\x1B#8");
|
||||
|
||||
// Verify entire screen is filled with 'E'
|
||||
const str = try t.plainString(testing.allocator);
|
||||
@@ -608,13 +620,13 @@ test "full reset" {
|
||||
defer s.deinit();
|
||||
|
||||
// Make some changes
|
||||
try s.nextSlice("Hello");
|
||||
try s.nextSlice("\x1B[10;20H");
|
||||
try s.nextSlice("\x1B[5;20r"); // Set scroll region
|
||||
try s.nextSlice("\x1B[?7l"); // Disable wraparound
|
||||
s.nextSlice("Hello");
|
||||
s.nextSlice("\x1B[10;20H");
|
||||
s.nextSlice("\x1B[5;20r"); // Set scroll region
|
||||
s.nextSlice("\x1B[?7l"); // Disable wraparound
|
||||
|
||||
// Full reset
|
||||
try s.nextSlice("\x1Bc");
|
||||
s.nextSlice("\x1Bc");
|
||||
|
||||
// Verify reset state
|
||||
try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.x);
|
||||
@@ -632,12 +644,12 @@ test "ignores query actions" {
|
||||
defer s.deinit();
|
||||
|
||||
// These should be ignored without error
|
||||
try s.nextSlice("\x1B[c"); // Device attributes
|
||||
try s.nextSlice("\x1B[5n"); // Device status report
|
||||
try s.nextSlice("\x1B[6n"); // Cursor position report
|
||||
s.nextSlice("\x1B[c"); // Device attributes
|
||||
s.nextSlice("\x1B[5n"); // Device status report
|
||||
s.nextSlice("\x1B[6n"); // Cursor position report
|
||||
|
||||
// Terminal should still be functional
|
||||
try s.nextSlice("Test");
|
||||
s.nextSlice("Test");
|
||||
const str = try t.plainString(testing.allocator);
|
||||
defer testing.allocator.free(str);
|
||||
try testing.expectEqualStrings("Test", str);
|
||||
@@ -654,14 +666,14 @@ test "OSC 4 set and reset palette" {
|
||||
const default_color_0 = t.colors.palette.original[0];
|
||||
|
||||
// Set color 0 to red
|
||||
try s.nextSlice("\x1b]4;0;rgb:ff/00/00\x1b\\");
|
||||
s.nextSlice("\x1b]4;0;rgb:ff/00/00\x1b\\");
|
||||
try testing.expectEqual(@as(u8, 0xff), t.colors.palette.current[0].r);
|
||||
try testing.expectEqual(@as(u8, 0x00), t.colors.palette.current[0].g);
|
||||
try testing.expectEqual(@as(u8, 0x00), t.colors.palette.current[0].b);
|
||||
try testing.expect(t.colors.palette.mask.isSet(0));
|
||||
|
||||
// Reset color 0
|
||||
try s.nextSlice("\x1b]104;0\x1b\\");
|
||||
s.nextSlice("\x1b]104;0\x1b\\");
|
||||
try testing.expectEqual(default_color_0, t.colors.palette.current[0]);
|
||||
try testing.expect(!t.colors.palette.mask.isSet(0));
|
||||
}
|
||||
@@ -674,15 +686,15 @@ test "OSC 104 reset all palette colors" {
|
||||
defer s.deinit();
|
||||
|
||||
// Set multiple colors
|
||||
try s.nextSlice("\x1b]4;0;rgb:ff/00/00\x1b\\");
|
||||
try s.nextSlice("\x1b]4;1;rgb:00/ff/00\x1b\\");
|
||||
try s.nextSlice("\x1b]4;2;rgb:00/00/ff\x1b\\");
|
||||
s.nextSlice("\x1b]4;0;rgb:ff/00/00\x1b\\");
|
||||
s.nextSlice("\x1b]4;1;rgb:00/ff/00\x1b\\");
|
||||
s.nextSlice("\x1b]4;2;rgb:00/00/ff\x1b\\");
|
||||
try testing.expect(t.colors.palette.mask.isSet(0));
|
||||
try testing.expect(t.colors.palette.mask.isSet(1));
|
||||
try testing.expect(t.colors.palette.mask.isSet(2));
|
||||
|
||||
// Reset all palette colors
|
||||
try s.nextSlice("\x1b]104\x1b\\");
|
||||
s.nextSlice("\x1b]104\x1b\\");
|
||||
try testing.expectEqual(t.colors.palette.original[0], t.colors.palette.current[0]);
|
||||
try testing.expectEqual(t.colors.palette.original[1], t.colors.palette.current[1]);
|
||||
try testing.expectEqual(t.colors.palette.original[2], t.colors.palette.current[2]);
|
||||
@@ -702,14 +714,14 @@ test "OSC 10 set and reset foreground color" {
|
||||
try testing.expect(t.colors.foreground.get() == null);
|
||||
|
||||
// Set foreground to red
|
||||
try s.nextSlice("\x1b]10;rgb:ff/00/00\x1b\\");
|
||||
s.nextSlice("\x1b]10;rgb:ff/00/00\x1b\\");
|
||||
const fg = t.colors.foreground.get().?;
|
||||
try testing.expectEqual(@as(u8, 0xff), fg.r);
|
||||
try testing.expectEqual(@as(u8, 0x00), fg.g);
|
||||
try testing.expectEqual(@as(u8, 0x00), fg.b);
|
||||
|
||||
// Reset foreground
|
||||
try s.nextSlice("\x1b]110\x1b\\");
|
||||
s.nextSlice("\x1b]110\x1b\\");
|
||||
try testing.expect(t.colors.foreground.get() == null);
|
||||
}
|
||||
|
||||
@@ -721,14 +733,14 @@ test "OSC 11 set and reset background color" {
|
||||
defer s.deinit();
|
||||
|
||||
// Set background to green
|
||||
try s.nextSlice("\x1b]11;rgb:00/ff/00\x1b\\");
|
||||
s.nextSlice("\x1b]11;rgb:00/ff/00\x1b\\");
|
||||
const bg = t.colors.background.get().?;
|
||||
try testing.expectEqual(@as(u8, 0x00), bg.r);
|
||||
try testing.expectEqual(@as(u8, 0xff), bg.g);
|
||||
try testing.expectEqual(@as(u8, 0x00), bg.b);
|
||||
|
||||
// Reset background
|
||||
try s.nextSlice("\x1b]111\x1b\\");
|
||||
s.nextSlice("\x1b]111\x1b\\");
|
||||
try testing.expect(t.colors.background.get() == null);
|
||||
}
|
||||
|
||||
@@ -740,14 +752,14 @@ test "OSC 12 set and reset cursor color" {
|
||||
defer s.deinit();
|
||||
|
||||
// Set cursor to blue
|
||||
try s.nextSlice("\x1b]12;rgb:00/00/ff\x1b\\");
|
||||
s.nextSlice("\x1b]12;rgb:00/00/ff\x1b\\");
|
||||
const cursor = t.colors.cursor.get().?;
|
||||
try testing.expectEqual(@as(u8, 0x00), cursor.r);
|
||||
try testing.expectEqual(@as(u8, 0x00), cursor.g);
|
||||
try testing.expectEqual(@as(u8, 0xff), cursor.b);
|
||||
|
||||
// Reset cursor
|
||||
try s.nextSlice("\x1b]112\x1b\\");
|
||||
s.nextSlice("\x1b]112\x1b\\");
|
||||
// After reset, cursor might be null (using default)
|
||||
}
|
||||
|
||||
@@ -759,7 +771,7 @@ test "kitty color protocol set palette" {
|
||||
defer s.deinit();
|
||||
|
||||
// Set palette color 5 to magenta using kitty protocol
|
||||
try s.nextSlice("\x1b]21;5=rgb:ff/00/ff\x1b\\");
|
||||
s.nextSlice("\x1b]21;5=rgb:ff/00/ff\x1b\\");
|
||||
try testing.expectEqual(@as(u8, 0xff), t.colors.palette.current[5].r);
|
||||
try testing.expectEqual(@as(u8, 0x00), t.colors.palette.current[5].g);
|
||||
try testing.expectEqual(@as(u8, 0xff), t.colors.palette.current[5].b);
|
||||
@@ -776,10 +788,10 @@ test "kitty color protocol reset palette" {
|
||||
|
||||
// Set and then reset palette color
|
||||
const original = t.colors.palette.original[7];
|
||||
try s.nextSlice("\x1b]21;7=rgb:aa/bb/cc\x1b\\");
|
||||
s.nextSlice("\x1b]21;7=rgb:aa/bb/cc\x1b\\");
|
||||
try testing.expect(t.colors.palette.mask.isSet(7));
|
||||
|
||||
try s.nextSlice("\x1b]21;7=\x1b\\");
|
||||
s.nextSlice("\x1b]21;7=\x1b\\");
|
||||
try testing.expectEqual(original, t.colors.palette.current[7]);
|
||||
try testing.expect(!t.colors.palette.mask.isSet(7));
|
||||
}
|
||||
@@ -792,7 +804,7 @@ test "kitty color protocol set foreground" {
|
||||
defer s.deinit();
|
||||
|
||||
// Set foreground using kitty protocol
|
||||
try s.nextSlice("\x1b]21;foreground=rgb:12/34/56\x1b\\");
|
||||
s.nextSlice("\x1b]21;foreground=rgb:12/34/56\x1b\\");
|
||||
const fg = t.colors.foreground.get().?;
|
||||
try testing.expectEqual(@as(u8, 0x12), fg.r);
|
||||
try testing.expectEqual(@as(u8, 0x34), fg.g);
|
||||
@@ -807,7 +819,7 @@ test "kitty color protocol set background" {
|
||||
defer s.deinit();
|
||||
|
||||
// Set background using kitty protocol
|
||||
try s.nextSlice("\x1b]21;background=rgb:78/9a/bc\x1b\\");
|
||||
s.nextSlice("\x1b]21;background=rgb:78/9a/bc\x1b\\");
|
||||
const bg = t.colors.background.get().?;
|
||||
try testing.expectEqual(@as(u8, 0x78), bg.r);
|
||||
try testing.expectEqual(@as(u8, 0x9a), bg.g);
|
||||
@@ -822,7 +834,7 @@ test "kitty color protocol set cursor" {
|
||||
defer s.deinit();
|
||||
|
||||
// Set cursor using kitty protocol
|
||||
try s.nextSlice("\x1b]21;cursor=rgb:de/f0/12\x1b\\");
|
||||
s.nextSlice("\x1b]21;cursor=rgb:de/f0/12\x1b\\");
|
||||
const cursor = t.colors.cursor.get().?;
|
||||
try testing.expectEqual(@as(u8, 0xde), cursor.r);
|
||||
try testing.expectEqual(@as(u8, 0xf0), cursor.g);
|
||||
@@ -837,10 +849,10 @@ test "kitty color protocol reset foreground" {
|
||||
defer s.deinit();
|
||||
|
||||
// Set and reset foreground
|
||||
try s.nextSlice("\x1b]21;foreground=rgb:11/22/33\x1b\\");
|
||||
s.nextSlice("\x1b]21;foreground=rgb:11/22/33\x1b\\");
|
||||
try testing.expect(t.colors.foreground.get() != null);
|
||||
|
||||
try s.nextSlice("\x1b]21;foreground=\x1b\\");
|
||||
s.nextSlice("\x1b]21;foreground=\x1b\\");
|
||||
// After reset, should be unset
|
||||
try testing.expect(t.colors.foreground.get() == null);
|
||||
}
|
||||
@@ -856,17 +868,17 @@ test "palette dirty flag set on color change" {
|
||||
t.flags.dirty.palette = false;
|
||||
|
||||
// Setting palette color should set dirty flag
|
||||
try s.nextSlice("\x1b]4;0;rgb:ff/00/00\x1b\\");
|
||||
s.nextSlice("\x1b]4;0;rgb:ff/00/00\x1b\\");
|
||||
try testing.expect(t.flags.dirty.palette);
|
||||
|
||||
// Clear and test reset
|
||||
t.flags.dirty.palette = false;
|
||||
try s.nextSlice("\x1b]104;0\x1b\\");
|
||||
s.nextSlice("\x1b]104;0\x1b\\");
|
||||
try testing.expect(t.flags.dirty.palette);
|
||||
|
||||
// Clear and test kitty protocol
|
||||
t.flags.dirty.palette = false;
|
||||
try s.nextSlice("\x1b]21;1=rgb:00/ff/00\x1b\\");
|
||||
s.nextSlice("\x1b]21;1=rgb:00/ff/00\x1b\\");
|
||||
try testing.expect(t.flags.dirty.palette);
|
||||
}
|
||||
|
||||
@@ -877,8 +889,8 @@ test "semantic prompt fresh line" {
|
||||
var s: Stream = .initAlloc(testing.allocator, .init(&t));
|
||||
defer s.deinit();
|
||||
|
||||
try s.nextSlice("Hello");
|
||||
try s.nextSlice("\x1b]133;L\x07");
|
||||
s.nextSlice("Hello");
|
||||
s.nextSlice("\x1b]133;L\x07");
|
||||
try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.x);
|
||||
try testing.expectEqual(@as(usize, 1), t.screens.active.cursor.y);
|
||||
}
|
||||
@@ -891,8 +903,8 @@ test "semantic prompt fresh line new prompt" {
|
||||
defer s.deinit();
|
||||
|
||||
// Write some text and then send OSC 133;A (fresh_line_new_prompt)
|
||||
try s.nextSlice("Hello");
|
||||
try s.nextSlice("\x1b]133;A\x07");
|
||||
s.nextSlice("Hello");
|
||||
s.nextSlice("\x1b]133;A\x07");
|
||||
|
||||
// Should do a fresh line (carriage return + index)
|
||||
try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.x);
|
||||
@@ -902,8 +914,8 @@ test "semantic prompt fresh line new prompt" {
|
||||
try testing.expectEqual(.prompt, t.screens.active.cursor.semantic_content);
|
||||
|
||||
// Test with redraw option
|
||||
try s.nextSlice("prompt$ ");
|
||||
try s.nextSlice("\x1b]133;A;redraw=1\x07");
|
||||
s.nextSlice("prompt$ ");
|
||||
s.nextSlice("\x1b]133;A;redraw=1\x07");
|
||||
try testing.expect(t.flags.shell_redraws_prompt == .true);
|
||||
}
|
||||
|
||||
@@ -915,12 +927,12 @@ test "semantic prompt end of input, then start output" {
|
||||
defer s.deinit();
|
||||
|
||||
// Write some text and then send OSC 133;A (fresh_line_new_prompt)
|
||||
try s.nextSlice("Hello");
|
||||
try s.nextSlice("\x1b]133;A\x07");
|
||||
try s.nextSlice("prompt$ ");
|
||||
try s.nextSlice("\x1b]133;B\x07");
|
||||
s.nextSlice("Hello");
|
||||
s.nextSlice("\x1b]133;A\x07");
|
||||
s.nextSlice("prompt$ ");
|
||||
s.nextSlice("\x1b]133;B\x07");
|
||||
try testing.expectEqual(.input, t.screens.active.cursor.semantic_content);
|
||||
try s.nextSlice("\x1b]133;C\x07");
|
||||
s.nextSlice("\x1b]133;C\x07");
|
||||
try testing.expectEqual(.output, t.screens.active.cursor.semantic_content);
|
||||
}
|
||||
|
||||
@@ -932,10 +944,10 @@ test "semantic prompt prompt_start" {
|
||||
defer s.deinit();
|
||||
|
||||
// Write some text
|
||||
try s.nextSlice("Hello");
|
||||
s.nextSlice("Hello");
|
||||
|
||||
// OSC 133;P marks the start of a prompt (without fresh line behavior)
|
||||
try s.nextSlice("\x1b]133;P\x07");
|
||||
s.nextSlice("\x1b]133;P\x07");
|
||||
try testing.expectEqual(.prompt, t.screens.active.cursor.semantic_content);
|
||||
try testing.expectEqual(@as(usize, 5), t.screens.active.cursor.x);
|
||||
try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.y);
|
||||
@@ -949,8 +961,8 @@ test "semantic prompt new_command" {
|
||||
defer s.deinit();
|
||||
|
||||
// Write some text
|
||||
try s.nextSlice("Hello");
|
||||
try s.nextSlice("\x1b]133;N\x07");
|
||||
s.nextSlice("Hello");
|
||||
s.nextSlice("\x1b]133;N\x07");
|
||||
|
||||
// Should behave like fresh_line_new_prompt - cursor moves to column 0
|
||||
// on next line since we had content
|
||||
@@ -967,7 +979,7 @@ test "semantic prompt new_command at column zero" {
|
||||
defer s.deinit();
|
||||
|
||||
// OSC 133;N when already at column 0 should stay on same line
|
||||
try s.nextSlice("\x1b]133;N\x07");
|
||||
s.nextSlice("\x1b]133;N\x07");
|
||||
try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.x);
|
||||
try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.y);
|
||||
try testing.expectEqual(.prompt, t.screens.active.cursor.semantic_content);
|
||||
@@ -981,11 +993,11 @@ test "semantic prompt end_prompt_start_input_terminate_eol clears on linefeed" {
|
||||
defer s.deinit();
|
||||
|
||||
// Set input terminated by EOL
|
||||
try s.nextSlice("\x1b]133;I\x07");
|
||||
s.nextSlice("\x1b]133;I\x07");
|
||||
try testing.expectEqual(.input, t.screens.active.cursor.semantic_content);
|
||||
|
||||
// Linefeed should reset semantic content to output
|
||||
try s.nextSlice("\n");
|
||||
s.nextSlice("\n");
|
||||
try testing.expectEqual(.output, t.screens.active.cursor.semantic_content);
|
||||
}
|
||||
|
||||
@@ -1002,5 +1014,5 @@ test "stream: CSI W with intermediate but no params" {
|
||||
var s: Stream = .initAlloc(testing.allocator, .init(&t));
|
||||
defer s.deinit();
|
||||
|
||||
try s.nextSlice("\x1b[?W");
|
||||
s.nextSlice("\x1b[?W");
|
||||
}
|
||||
|
||||
@@ -1053,10 +1053,7 @@ pub const Viewer = struct {
|
||||
// correct but we'll get the active contents soon.
|
||||
var stream = t.vtStream();
|
||||
defer stream.deinit();
|
||||
stream.nextSlice(content) catch |err| {
|
||||
log.info("failed to process pane history for pane id={}: {}", .{ id, err });
|
||||
return err;
|
||||
};
|
||||
stream.nextSlice(content);
|
||||
|
||||
// Populate the active area to be empty since this is only history.
|
||||
// We'll fill it with blanks and move the cursor to the top-left.
|
||||
@@ -1097,10 +1094,7 @@ pub const Viewer = struct {
|
||||
|
||||
var stream = t.vtStream();
|
||||
defer stream.deinit();
|
||||
stream.nextSlice(content) catch |err| {
|
||||
log.info("failed to process pane visible for pane id={}: {}", .{ id, err });
|
||||
return err;
|
||||
};
|
||||
stream.nextSlice(content);
|
||||
}
|
||||
|
||||
fn receivedOutput(
|
||||
@@ -1117,10 +1111,7 @@ pub const Viewer = struct {
|
||||
|
||||
var stream = t.vtStream();
|
||||
defer stream.deinit();
|
||||
stream.nextSlice(data) catch |err| {
|
||||
log.info("failed to process output for pane id={}: {}", .{ id, err });
|
||||
return err;
|
||||
};
|
||||
stream.nextSlice(data);
|
||||
}
|
||||
|
||||
fn initLayout(
|
||||
|
||||
@@ -721,12 +721,10 @@ fn processOutputLocked(self: *Termio, buf: []const u8) void {
|
||||
log.err("error recording pty read in inspector err={}", .{err});
|
||||
};
|
||||
|
||||
self.terminal_stream.next(byte) catch |err|
|
||||
log.err("error processing terminal data: {}", .{err});
|
||||
self.terminal_stream.next(byte);
|
||||
}
|
||||
} else {
|
||||
self.terminal_stream.nextSlice(buf) catch |err|
|
||||
log.err("error processing terminal data: {}", .{err});
|
||||
self.terminal_stream.nextSlice(buf);
|
||||
}
|
||||
|
||||
// If our stream handling caused messages to be sent to the mailbox
|
||||
|
||||
@@ -176,6 +176,16 @@ pub const StreamHandler = struct {
|
||||
self: *StreamHandler,
|
||||
comptime action: Stream.Action.Tag,
|
||||
value: Stream.Action.Value(action),
|
||||
) void {
|
||||
self.vtFallible(action, value) catch |err| {
|
||||
log.warn("error handling VT action action={} err={}", .{ action, err });
|
||||
};
|
||||
}
|
||||
|
||||
inline fn vtFallible(
|
||||
self: *StreamHandler,
|
||||
comptime action: Stream.Action.Tag,
|
||||
value: Stream.Action.Value(action),
|
||||
) !void {
|
||||
// The branch hints here are based on real world data
|
||||
// which indicates that the most common actions are:
|
||||
|
||||
@@ -43,11 +43,9 @@ pub export fn zig_fuzz_test(
|
||||
|
||||
if (mode & 1 == 0) {
|
||||
// Slice path — exercises SIMD fast-path if enabled
|
||||
stream.nextSlice(data) catch |err|
|
||||
std.debug.panic("nextSlice: {}", .{err});
|
||||
stream.nextSlice(data);
|
||||
} else {
|
||||
// Scalar path — exercises byte-at-a-time UTF-8 decoding
|
||||
for (data) |byte| _ = stream.next(byte) catch |err|
|
||||
std.debug.panic("next: {}", .{err});
|
||||
for (data) |byte| stream.next(byte);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user