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