From 2044e5030ffaadf0361a2f4fca040b77408db0b5 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 13 Mar 2026 13:14:03 -0700 Subject: [PATCH] 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. --- example/zig-formatter/src/main.zig | 4 +- example/zig-vt-stream/src/main.zig | 16 +- src/benchmark/ScreenClone.zig | 11 +- src/benchmark/TerminalStream.zig | 11 +- src/font/shaper/coretext.zig | 94 ++-- src/font/shaper/harfbuzz.zig | 84 ++-- src/inspector/widgets/termio.zig | 4 +- src/renderer/cell.zig | 24 +- src/renderer/link.zig | 6 +- src/terminal/formatter.zig | 314 ++++++------ src/terminal/render.zig | 46 +- src/terminal/search/Thread.zig | 2 +- src/terminal/search/active.zig | 10 +- src/terminal/search/pagelist.zig | 44 +- src/terminal/search/screen.zig | 98 ++-- src/terminal/search/sliding_window.zig | 4 +- src/terminal/search/viewport.zig | 26 +- src/terminal/stream.zig | 580 ++++++++++++----------- src/terminal/stream_readonly.zig | 158 +++--- src/terminal/tmux/viewer.zig | 15 +- src/termio/Termio.zig | 6 +- src/termio/stream_handler.zig | 10 + test/fuzz-libghostty/src/fuzz_stream.zig | 6 +- 23 files changed, 791 insertions(+), 782 deletions(-) diff --git a/example/zig-formatter/src/main.zig b/example/zig-formatter/src/main.zig index ad101dbf1..df21a2046 100644 --- a/example/zig-formatter/src/main.zig +++ b/example/zig-formatter/src/main.zig @@ -23,8 +23,8 @@ pub fn main() !void { // Replace \n with \r\n for (buf[0..n]) |byte| { - if (byte == '\n') try stream.next('\r'); - try stream.next(byte); + if (byte == '\n') stream.next('\r'); + stream.next(byte); } } diff --git a/example/zig-vt-stream/src/main.zig b/example/zig-vt-stream/src/main.zig index 8fd438b70..87d8857dd 100644 --- a/example/zig-vt-stream/src/main.zig +++ b/example/zig-vt-stream/src/main.zig @@ -14,24 +14,24 @@ pub fn main() !void { defer stream.deinit(); // Basic text with newline - try stream.nextSlice("Hello, World!\r\n"); + stream.nextSlice("Hello, World!\r\n"); // ANSI color codes: ESC[1;32m = bold green, ESC[0m = reset - try stream.nextSlice("\x1b[1;32mGreen Text\x1b[0m\r\n"); + stream.nextSlice("\x1b[1;32mGreen Text\x1b[0m\r\n"); // Cursor positioning: ESC[1;1H = move to row 1, column 1 - try stream.nextSlice("\x1b[1;1HTop-left corner\r\n"); + stream.nextSlice("\x1b[1;1HTop-left corner\r\n"); // Cursor movement: ESC[5B = move down 5 lines - try stream.nextSlice("\x1b[5B"); - try stream.nextSlice("Moved down!\r\n"); + stream.nextSlice("\x1b[5B"); + stream.nextSlice("Moved down!\r\n"); // Erase line: ESC[2K = clear entire line - try stream.nextSlice("\x1b[2K"); - try stream.nextSlice("New content\r\n"); + stream.nextSlice("\x1b[2K"); + stream.nextSlice("New content\r\n"); // Multiple lines - try stream.nextSlice("Line A\r\nLine B\r\nLine C\r\n"); + stream.nextSlice("Line A\r\nLine B\r\nLine C\r\n"); // Get the final terminal state as a plain string const str = try t.plainString(alloc); diff --git a/src/benchmark/ScreenClone.zig b/src/benchmark/ScreenClone.zig index 380379bc3..108eaa0c6 100644 --- a/src/benchmark/ScreenClone.zig +++ b/src/benchmark/ScreenClone.zig @@ -94,9 +94,9 @@ fn setup(ptr: *anyopaque) Benchmark.Error!void { // Force a style on every single row, which var s = self.terminal.vtStream(); defer s.deinit(); - s.nextSlice("\x1b[48;2;20;40;60m") catch unreachable; - for (0..self.terminal.rows - 1) |_| s.nextSlice("hello\r\n") catch unreachable; - s.nextSlice("hello") catch unreachable; + s.nextSlice("\x1b[48;2;20;40;60m"); + for (0..self.terminal.rows - 1) |_| s.nextSlice("hello\r\n"); + s.nextSlice("hello"); // Setup our terminal state const data_f: std.fs.File = (options.dataFile( @@ -120,10 +120,7 @@ fn setup(ptr: *anyopaque) Benchmark.Error!void { return error.BenchmarkFailed; }; if (n == 0) break; // EOF reached - stream.nextSlice(buf[0..n]) catch |err| { - log.warn("error processing data file chunk err={}", .{err}); - return error.BenchmarkFailed; - }; + stream.nextSlice(buf[0..n]); } } diff --git a/src/benchmark/TerminalStream.zig b/src/benchmark/TerminalStream.zig index 7cf28217f..1cac656e2 100644 --- a/src/benchmark/TerminalStream.zig +++ b/src/benchmark/TerminalStream.zig @@ -125,10 +125,7 @@ fn step(ptr: *anyopaque) Benchmark.Error!void { return error.BenchmarkFailed; }; if (n == 0) break; // EOF reached - self.stream.nextSlice(buf[0..n]) catch |err| { - log.warn("error processing data file chunk err={}", .{err}); - return error.BenchmarkFailed; - }; + self.stream.nextSlice(buf[0..n]); } } @@ -142,9 +139,11 @@ const Handler = struct { self: *Handler, comptime action: Stream.Action.Tag, value: Stream.Action.Value(action), - ) !void { + ) void { switch (action) { - .print => try self.t.print(value.cp), + .print => self.t.print(value.cp) catch |err| { + log.warn("error processing benchmark print err={}", .{err}); + }, else => {}, } } diff --git a/src/font/shaper/coretext.zig b/src/font/shaper/coretext.zig index 5a8a6ccbf..ff7c6d9d3 100644 --- a/src/font/shaper/coretext.zig +++ b/src/font/shaper/coretext.zig @@ -850,7 +850,7 @@ test "run iterator" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("ABCD"); + s.nextSlice("ABCD"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -874,7 +874,7 @@ test "run iterator" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("ABCD EFG"); + s.nextSlice("ABCD EFG"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -897,7 +897,7 @@ test "run iterator" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("A😃D"); + s.nextSlice("A😃D"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -922,7 +922,7 @@ test "run iterator" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(bad); + s.nextSlice(bad); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -955,8 +955,8 @@ test "run iterator: empty cells with background set" { var s = t.vtStream(); defer s.deinit(); // Set red background - try s.nextSlice("\x1b[48;2;255;0;0m"); - try s.nextSlice("A"); + s.nextSlice("\x1b[48;2;255;0;0m"); + s.nextSlice("A"); // Get our first row { @@ -1014,7 +1014,7 @@ test "shape" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1053,7 +1053,7 @@ test "shape nerd fonts" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1086,7 +1086,7 @@ test "shape inconsolata ligs" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(">="); + s.nextSlice(">="); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1115,7 +1115,7 @@ test "shape inconsolata ligs" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("==="); + s.nextSlice("==="); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1152,7 +1152,7 @@ test "shape monaspace ligs" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("==="); + s.nextSlice("==="); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1190,7 +1190,7 @@ test "shape left-replaced lig in last run" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("!=="); + s.nextSlice("!=="); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1228,7 +1228,7 @@ test "shape left-replaced lig in early run" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("!==X"); + s.nextSlice("!==X"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1263,7 +1263,7 @@ test "shape U+3C9 with JB Mono" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("\u{03C9} foo"); + s.nextSlice("\u{03C9} foo"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1300,7 +1300,7 @@ test "shape emoji width" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("👍"); + s.nextSlice("👍"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1390,7 +1390,7 @@ test "shape variation selector VS15" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1429,7 +1429,7 @@ test "shape variation selector VS16" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1463,9 +1463,9 @@ test "shape with empty cells in between" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("A"); - try s.nextSlice("\x1b[5C"); // 5 spaces forward - try s.nextSlice("B"); + s.nextSlice("A"); + s.nextSlice("\x1b[5C"); // 5 spaces forward + s.nextSlice("B"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1510,7 +1510,7 @@ test "shape Combining characters" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1560,7 +1560,7 @@ test "shape Devanagari string" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("अपार्टमेंट"); + s.nextSlice("अपार्टमेंट"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1619,7 +1619,7 @@ test "shape Tai Tham vowels (position differs from advance)" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1680,7 +1680,7 @@ test "shape Tai Tham letters (position.y differs from advance)" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1740,7 +1740,7 @@ test "shape Javanese ligatures" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1803,7 +1803,7 @@ test "shape Chakma vowel sign with ligature (vowel sign renders first)" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1874,7 +1874,7 @@ test "shape Bengali ligatures with out of order vowels" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1929,7 +1929,7 @@ test "shape box glyphs" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1967,7 +1967,7 @@ test "shape selection boundary" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("a1b2c3d4e5"); + s.nextSlice("a1b2c3d4e5"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -2072,7 +2072,7 @@ test "shape cursor boundary" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("a1b2c3d4e5"); + s.nextSlice("a1b2c3d4e5"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -2209,7 +2209,7 @@ test "shape cursor boundary and colored emoji" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("👍🏼"); + s.nextSlice("👍🏼"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -2306,7 +2306,7 @@ test "shape cell attribute change" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(">="); + s.nextSlice(">="); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -2332,9 +2332,9 @@ test "shape cell attribute change" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(">"); - try s.nextSlice("\x1b[1m"); // Bold - try s.nextSlice("="); + s.nextSlice(">"); + s.nextSlice("\x1b[1m"); // Bold + s.nextSlice("="); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -2361,11 +2361,11 @@ test "shape cell attribute change" { var s = t.vtStream(); defer s.deinit(); // RGB 1, 2, 3 - try s.nextSlice("\x1b[38;2;1;2;3m"); - try s.nextSlice(">"); + s.nextSlice("\x1b[38;2;1;2;3m"); + s.nextSlice(">"); // RGB 3, 2, 1 - try s.nextSlice("\x1b[38;2;3;2;1m"); - try s.nextSlice("="); + s.nextSlice("\x1b[38;2;3;2;1m"); + s.nextSlice("="); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -2392,11 +2392,11 @@ test "shape cell attribute change" { var s = t.vtStream(); defer s.deinit(); // RGB 1, 2, 3 bg - try s.nextSlice("\x1b[48;2;1;2;3m"); - try s.nextSlice(">"); + s.nextSlice("\x1b[48;2;1;2;3m"); + s.nextSlice(">"); // RGB 3, 2, 1 bg - try s.nextSlice("\x1b[48;2;3;2;1m"); - try s.nextSlice("="); + s.nextSlice("\x1b[48;2;3;2;1m"); + s.nextSlice("="); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -2423,9 +2423,9 @@ test "shape cell attribute change" { var s = t.vtStream(); defer s.deinit(); // RGB 1, 2, 3 bg - try s.nextSlice("\x1b[48;2;1;2;3m"); - try s.nextSlice(">"); - try s.nextSlice("="); + s.nextSlice("\x1b[48;2;1;2;3m"); + s.nextSlice(">"); + s.nextSlice("="); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -2468,7 +2468,7 @@ test "shape high plane sprite font codepoint" { var s = t.vtStream(); defer s.deinit(); // U+1FB70: Vertical One Eighth Block-2 - try s.nextSlice("\u{1FB70}"); + s.nextSlice("\u{1FB70}"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); diff --git a/src/font/shaper/harfbuzz.zig b/src/font/shaper/harfbuzz.zig index 30e1d0544..d17df4b1e 100644 --- a/src/font/shaper/harfbuzz.zig +++ b/src/font/shaper/harfbuzz.zig @@ -448,7 +448,7 @@ test "run iterator" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("ABCD"); + s.nextSlice("ABCD"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -472,7 +472,7 @@ test "run iterator" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("ABCD EFG"); + s.nextSlice("ABCD EFG"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -495,7 +495,7 @@ test "run iterator" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("A😃D"); + s.nextSlice("A😃D"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -533,7 +533,7 @@ test "run iterator: empty cells with background set" { var s = t.vtStream(); defer s.deinit(); // Set red background and write A - try s.nextSlice("\x1b[48;2;255;0;0mA"); + s.nextSlice("\x1b[48;2;255;0;0mA"); // Get our first row { @@ -592,7 +592,7 @@ test "shape" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -626,7 +626,7 @@ test "shape inconsolata ligs" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(">="); + s.nextSlice(">="); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -655,7 +655,7 @@ test "shape inconsolata ligs" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("==="); + s.nextSlice("==="); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -692,7 +692,7 @@ test "shape monaspace ligs" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("==="); + s.nextSlice("==="); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -732,7 +732,7 @@ test "shape arabic forced LTR" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(@embedFile("testdata/arabic.txt")); + s.nextSlice(@embedFile("testdata/arabic.txt")); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -773,7 +773,7 @@ test "shape emoji width" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("👍"); + s.nextSlice("👍"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -870,7 +870,7 @@ test "shape variation selector VS15" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -911,7 +911,7 @@ test "shape variation selector VS16" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -950,9 +950,9 @@ test "shape with empty cells in between" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("A"); - try s.nextSlice("\x1b[5C"); - try s.nextSlice("B"); + s.nextSlice("A"); + s.nextSlice("\x1b[5C"); + s.nextSlice("B"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -997,7 +997,7 @@ test "shape Combining characters" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1048,7 +1048,7 @@ test "shape Devanagari string" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("अपार्टमेंट"); + s.nextSlice("अपार्टमेंट"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1111,7 +1111,7 @@ test "shape Tai Tham vowels (position differs from advance)" { // var s = t.vtStream(); // defer s.deinit(); - // try s.nextSlice(buf[0..buf_idx]); + // s.nextSlice(buf[0..buf_idx]); // var state: terminal.RenderState = .empty; // defer state.deinit(alloc); @@ -1170,7 +1170,7 @@ test "shape Tibetan characters" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1232,7 +1232,7 @@ test "shape Tai Tham letters (run_offset.y differs from zero)" { // var s = t.vtStream(); // defer s.deinit(); - // try s.nextSlice(buf[0..buf_idx]); + // s.nextSlice(buf[0..buf_idx]); // var state: terminal.RenderState = .empty; // defer state.deinit(alloc); @@ -1295,7 +1295,7 @@ test "shape Javanese ligatures" { // var s = t.vtStream(); // defer s.deinit(); - // try s.nextSlice(buf[0..buf_idx]); + // s.nextSlice(buf[0..buf_idx]); // var state: terminal.RenderState = .empty; // defer state.deinit(alloc); @@ -1358,7 +1358,7 @@ test "shape Chakma vowel sign with ligature (vowel sign renders first)" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1433,7 +1433,7 @@ test "shape Bengali ligatures with out of order vowels" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1487,7 +1487,7 @@ test "shape box glyphs" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(buf[0..buf_idx]); + s.nextSlice(buf[0..buf_idx]); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1526,7 +1526,7 @@ test "shape selection boundary" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("a1b2c3d4e5"); + s.nextSlice("a1b2c3d4e5"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1631,7 +1631,7 @@ test "shape cursor boundary" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("a1b2c3d4e5"); + s.nextSlice("a1b2c3d4e5"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1771,7 +1771,7 @@ test "shape cursor boundary and colored emoji" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("👍🏼"); + s.nextSlice("👍🏼"); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1868,7 +1868,7 @@ test "shape cell attribute change" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(">="); + s.nextSlice(">="); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1894,9 +1894,9 @@ test "shape cell attribute change" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice(">"); - try s.nextSlice("\x1b[1m"); - try s.nextSlice("="); + s.nextSlice(">"); + s.nextSlice("\x1b[1m"); + s.nextSlice("="); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1923,11 +1923,11 @@ test "shape cell attribute change" { var s = t.vtStream(); defer s.deinit(); // RGB 1, 2, 3 - try s.nextSlice("\x1b[38;2;1;2;3m"); - try s.nextSlice(">"); + s.nextSlice("\x1b[38;2;1;2;3m"); + s.nextSlice(">"); // RGB 3, 2, 1 - try s.nextSlice("\x1b[38;2;3;2;1m"); - try s.nextSlice("="); + s.nextSlice("\x1b[38;2;3;2;1m"); + s.nextSlice("="); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1954,11 +1954,11 @@ test "shape cell attribute change" { var s = t.vtStream(); defer s.deinit(); // RGB 1, 2, 3 bg - try s.nextSlice("\x1b[48;2;1;2;3m"); - try s.nextSlice(">"); + s.nextSlice("\x1b[48;2;1;2;3m"); + s.nextSlice(">"); // RGB 3, 2, 1 bg - try s.nextSlice("\x1b[48;2;3;2;1m"); - try s.nextSlice("="); + s.nextSlice("\x1b[48;2;3;2;1m"); + s.nextSlice("="); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -1985,9 +1985,9 @@ test "shape cell attribute change" { var s = t.vtStream(); defer s.deinit(); // RGB 1, 2, 3 bg - try s.nextSlice("\x1b[48;2;1;2;3m"); - try s.nextSlice(">"); - try s.nextSlice("="); + s.nextSlice("\x1b[48;2;1;2;3m"); + s.nextSlice(">"); + s.nextSlice("="); var state: terminal.RenderState = .empty; defer state.deinit(alloc); diff --git a/src/inspector/widgets/termio.zig b/src/inspector/widgets/termio.zig index a6c8f6081..b721d9422 100644 --- a/src/inspector/widgets/termio.zig +++ b/src/inspector/widgets/termio.zig @@ -54,7 +54,7 @@ pub const Stream = struct { .events = &self.events, }; defer self.parser_stream.handler.state = null; - try self.parser_stream.nextSlice(data); + self.parser_stream.nextSlice(data); } pub fn draw( @@ -736,7 +736,7 @@ const VTHandler = struct { self: *VTHandler, comptime action: VTHandler.Stream.Action.Tag, value: VTHandler.Stream.Action.Value(action), - ) !void { + ) void { _ = self; _ = value; } diff --git a/src/renderer/cell.zig b/src/renderer/cell.zig index 5ea5b7ab0..196ebb175 100644 --- a/src/renderer/cell.zig +++ b/src/renderer/cell.zig @@ -528,7 +528,7 @@ test "Cell constraint widths" { // symbol->nothing: 2 { t.fullReset(); - try s.nextSlice(""); + s.nextSlice(""); try state.update(alloc, &t); try testing.expectEqual(2, constraintWidth( state.row_data.get(0).cells.items(.raw), @@ -540,7 +540,7 @@ test "Cell constraint widths" { // symbol->character: 1 { t.fullReset(); - try s.nextSlice("z"); + s.nextSlice("z"); try state.update(alloc, &t); try testing.expectEqual(1, constraintWidth( state.row_data.get(0).cells.items(.raw), @@ -552,7 +552,7 @@ test "Cell constraint widths" { // symbol->space: 2 { t.fullReset(); - try s.nextSlice(" z"); + s.nextSlice(" z"); try state.update(alloc, &t); try testing.expectEqual(2, constraintWidth( state.row_data.get(0).cells.items(.raw), @@ -563,7 +563,7 @@ test "Cell constraint widths" { // symbol->no-break space: 1 { t.fullReset(); - try s.nextSlice("\u{00a0}z"); + s.nextSlice("\u{00a0}z"); try state.update(alloc, &t); try testing.expectEqual(1, constraintWidth( state.row_data.get(0).cells.items(.raw), @@ -575,7 +575,7 @@ test "Cell constraint widths" { // symbol->end of row: 1 { t.fullReset(); - try s.nextSlice(" "); + s.nextSlice(" "); try state.update(alloc, &t); try testing.expectEqual(1, constraintWidth( state.row_data.get(0).cells.items(.raw), @@ -587,7 +587,7 @@ test "Cell constraint widths" { // character->symbol: 2 { t.fullReset(); - try s.nextSlice("z"); + s.nextSlice("z"); try state.update(alloc, &t); try testing.expectEqual(2, constraintWidth( state.row_data.get(0).cells.items(.raw), @@ -599,7 +599,7 @@ test "Cell constraint widths" { // symbol->symbol: 1,1 { t.fullReset(); - try s.nextSlice(""); + s.nextSlice(""); try state.update(alloc, &t); try testing.expectEqual(1, constraintWidth( state.row_data.get(0).cells.items(.raw), @@ -616,7 +616,7 @@ test "Cell constraint widths" { // symbol->space->symbol: 2,2 { t.fullReset(); - try s.nextSlice(" "); + s.nextSlice(" "); try state.update(alloc, &t); try testing.expectEqual(2, constraintWidth( state.row_data.get(0).cells.items(.raw), @@ -633,7 +633,7 @@ test "Cell constraint widths" { // symbol->powerline: 1 (dedicated test because powerline is special-cased in cellpkg) { t.fullReset(); - try s.nextSlice(""); + s.nextSlice(""); try state.update(alloc, &t); try testing.expectEqual(1, constraintWidth( state.row_data.get(0).cells.items(.raw), @@ -645,7 +645,7 @@ test "Cell constraint widths" { // powerline->symbol: 2 (dedicated test because powerline is special-cased in cellpkg) { t.fullReset(); - try s.nextSlice(""); + s.nextSlice(""); try state.update(alloc, &t); try testing.expectEqual(2, constraintWidth( state.row_data.get(0).cells.items(.raw), @@ -657,7 +657,7 @@ test "Cell constraint widths" { // powerline->nothing: 2 (dedicated test because powerline is special-cased in cellpkg) { t.fullReset(); - try s.nextSlice(""); + s.nextSlice(""); try state.update(alloc, &t); try testing.expectEqual(2, constraintWidth( state.row_data.get(0).cells.items(.raw), @@ -669,7 +669,7 @@ test "Cell constraint widths" { // powerline->space: 2 (dedicated test because powerline is special-cased in cellpkg) { t.fullReset(); - try s.nextSlice(" z"); + s.nextSlice(" z"); try state.update(alloc, &t); try testing.expectEqual(2, constraintWidth( state.row_data.get(0).cells.items(.raw), diff --git a/src/renderer/link.zig b/src/renderer/link.zig index 74df3e596..c5de61574 100644 --- a/src/renderer/link.zig +++ b/src/renderer/link.zig @@ -148,7 +148,7 @@ test "renderCellMap" { var s = t.vtStream(); defer s.deinit(); const str = "1ABCD2EFGH\r\n3IJKL"; - try s.nextSlice(str); + s.nextSlice(str); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -201,7 +201,7 @@ test "renderCellMap hover links" { var s = t.vtStream(); defer s.deinit(); const str = "1ABCD2EFGH\r\n3IJKL"; - try s.nextSlice(str); + s.nextSlice(str); var state: terminal.RenderState = .empty; defer state.deinit(alloc); @@ -279,7 +279,7 @@ test "renderCellMap mods no match" { var s = t.vtStream(); defer s.deinit(); const str = "1ABCD2EFGH\r\n3IJKL"; - try s.nextSlice(str); + s.nextSlice(str); var state: terminal.RenderState = .empty; defer state.deinit(alloc); diff --git a/src/terminal/formatter.zig b/src/terminal/formatter.zig index 062e3969a..f3b503d29 100644 --- a/src/terminal/formatter.zig +++ b/src/terminal/formatter.zig @@ -1593,7 +1593,7 @@ test "Page plain single line" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello, world"); + s.nextSlice("hello, world"); // Verify we have only a single page const pages = &t.screens.active.pages; @@ -1640,7 +1640,7 @@ test "Page plain single line soft-wrapped unwrapped" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello!"); + s.nextSlice("hello!"); // Verify we have only a single page const pages = &t.screens.active.pages; @@ -1710,7 +1710,7 @@ test "Page plain single wide char" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("1A⚡"); + s.nextSlice("1A⚡"); // Verify we have only a single page const pages = &t.screens.active.pages; @@ -1801,7 +1801,7 @@ test "Page plain single wide char soft-wrapped unwrapped" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("1A⚡"); + s.nextSlice("1A⚡"); // Verify we have only a single page const pages = &t.screens.active.pages; @@ -1918,7 +1918,7 @@ test "Page plain multiline" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello\r\nworld"); + s.nextSlice("hello\r\nworld"); // Verify we have only a single page const pages = &t.screens.active.pages; @@ -1969,7 +1969,7 @@ test "Page plain multiline rectangle" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello\r\nworld"); + s.nextSlice("hello\r\nworld"); // Verify we have only a single page const pages = &t.screens.active.pages; @@ -2023,7 +2023,7 @@ test "Page plain multi blank lines" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello\r\n\r\n\r\nworld"); + s.nextSlice("hello\r\n\r\n\r\nworld"); // Verify we have only a single page const pages = &t.screens.active.pages; @@ -2076,7 +2076,7 @@ test "Page plain trailing blank lines" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello\r\nworld\r\n\r\n"); + s.nextSlice("hello\r\nworld\r\n\r\n"); // Verify we have only a single page const pages = &t.screens.active.pages; @@ -2129,7 +2129,7 @@ test "Page plain trailing whitespace" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello \r\nworld "); + s.nextSlice("hello \r\nworld "); // Verify we have only a single page const pages = &t.screens.active.pages; @@ -2182,7 +2182,7 @@ test "Page plain trailing whitespace no trim" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello \r\nworld "); + s.nextSlice("hello \r\nworld "); // Verify we have only a single page const pages = &t.screens.active.pages; @@ -2238,7 +2238,7 @@ test "Page plain with prior trailing state rows" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello"); + s.nextSlice("hello"); const pages = &t.screens.active.pages; try testing.expect(pages.pages.first != null); @@ -2284,7 +2284,7 @@ test "Page plain with prior trailing state cells no wrapped line" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello"); + s.nextSlice("hello"); const pages = &t.screens.active.pages; try testing.expect(pages.pages.first != null); @@ -2329,7 +2329,7 @@ test "Page plain with prior trailing state cells with wrap continuation" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("world"); + s.nextSlice("world"); const pages = &t.screens.active.pages; try testing.expect(pages.pages.first != null); @@ -2383,7 +2383,7 @@ test "Page plain soft-wrapped without unwrap" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello world test"); + s.nextSlice("hello world test"); const pages = &t.screens.active.pages; try testing.expect(pages.pages.first != null); @@ -2432,7 +2432,7 @@ test "Page plain soft-wrapped with unwrap" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello world test"); + s.nextSlice("hello world test"); const pages = &t.screens.active.pages; try testing.expect(pages.pages.first != null); @@ -2480,7 +2480,7 @@ test "Page plain soft-wrapped 3 lines without unwrap" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello world this is a test"); + s.nextSlice("hello world this is a test"); const pages = &t.screens.active.pages; try testing.expect(pages.pages.first != null); @@ -2534,7 +2534,7 @@ test "Page plain soft-wrapped 3 lines with unwrap" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello world this is a test"); + s.nextSlice("hello world this is a test"); const pages = &t.screens.active.pages; try testing.expect(pages.pages.first != null); @@ -2586,7 +2586,7 @@ test "Page plain start_y subset" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello\r\nworld\r\ntest"); + s.nextSlice("hello\r\nworld\r\ntest"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -2633,7 +2633,7 @@ test "Page plain end_y subset" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello\r\nworld\r\ntest"); + s.nextSlice("hello\r\nworld\r\ntest"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -2680,7 +2680,7 @@ test "Page plain start_y and end_y range" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello\r\nworld\r\ntest\r\nfoo"); + s.nextSlice("hello\r\nworld\r\ntest\r\nfoo"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -2728,7 +2728,7 @@ test "Page plain start_y out of bounds" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello"); + s.nextSlice("hello"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -2766,7 +2766,7 @@ test "Page plain end_y greater than rows" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello"); + s.nextSlice("hello"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -2809,7 +2809,7 @@ test "Page plain end_y less than start_y" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello"); + s.nextSlice("hello"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -2848,7 +2848,7 @@ test "Page plain start_x on first row only" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello world"); + s.nextSlice("hello world"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -2890,7 +2890,7 @@ test "Page plain end_x on last row only" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("first line\r\nsecond line\r\nthird line"); + s.nextSlice("first line\r\nsecond line\r\nthird line"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -2943,7 +2943,7 @@ test "Page plain start_x and end_x multiline" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello world\r\ntest case\r\nfoo bar"); + s.nextSlice("hello world\r\ntest case\r\nfoo bar"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -3000,7 +3000,7 @@ test "Page plain start_x out of bounds" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello"); + s.nextSlice("hello"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -3038,7 +3038,7 @@ test "Page plain end_x greater than cols" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello"); + s.nextSlice("hello"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -3080,7 +3080,7 @@ test "Page plain end_x less than start_x single row" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello"); + s.nextSlice("hello"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -3120,7 +3120,7 @@ test "Page plain start_y non-zero ignores trailing state" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello\r\nworld"); + s.nextSlice("hello\r\nworld"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -3164,7 +3164,7 @@ test "Page plain start_x non-zero ignores trailing state" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello world"); + s.nextSlice("hello world"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -3208,7 +3208,7 @@ test "Page plain start_y and start_x zero uses trailing state" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello"); + s.nextSlice("hello"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -3255,7 +3255,7 @@ test "Page plain single line with styling" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello, \x1b[1mworld\x1b[0m"); + s.nextSlice("hello, \x1b[1mworld\x1b[0m"); // Verify we have only a single page const pages = &t.screens.active.pages; @@ -3301,7 +3301,7 @@ test "Page VT single line plain text" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello"); + s.nextSlice("hello"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -3340,7 +3340,7 @@ test "Page VT single line with bold" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("\x1b[1mhello\x1b[0m"); + s.nextSlice("\x1b[1mhello\x1b[0m"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -3386,7 +3386,7 @@ test "Page VT multiple styles" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("\x1b[1mhello \x1b[3mworld\x1b[0m"); + s.nextSlice("\x1b[1mhello \x1b[3mworld\x1b[0m"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -3421,7 +3421,7 @@ test "Page VT with foreground color" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("\x1b[31mred\x1b[0m"); + s.nextSlice("\x1b[31mred\x1b[0m"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -3467,7 +3467,7 @@ test "Page VT with background and foreground colors" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello"); + s.nextSlice("hello"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -3504,7 +3504,7 @@ test "Page VT multi-line with styles" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("\x1b[1mfirst\x1b[0m\r\n\x1b[3msecond\x1b[0m"); + s.nextSlice("\x1b[1mfirst\x1b[0m\r\n\x1b[3msecond\x1b[0m"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -3541,7 +3541,7 @@ test "Page VT duplicate style not emitted twice" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("\x1b[1mhel\x1b[1mlo\x1b[0m"); + s.nextSlice("\x1b[1mhel\x1b[1mlo\x1b[0m"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -3576,7 +3576,7 @@ test "PageList plain single line" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello, world"); + s.nextSlice("hello, world"); var pin_map: std.ArrayList(Pin) = .empty; defer pin_map.deinit(alloc); @@ -3616,18 +3616,18 @@ test "PageList plain spanning two pages" { const first_page_rows = pages.pages.first.?.data.capacity.rows; // Fill the first page almost completely - for (0..first_page_rows - 1) |_| try s.nextSlice("\r\n"); - try s.nextSlice("page one"); + for (0..first_page_rows - 1) |_| s.nextSlice("\r\n"); + s.nextSlice("page one"); // Verify we're still on one page try testing.expect(pages.pages.first == pages.pages.last); // Add one more newline to push content to a second page - try s.nextSlice("\r\n"); + s.nextSlice("\r\n"); try testing.expect(pages.pages.first != pages.pages.last); // Write content on the second page - try s.nextSlice("page two"); + s.nextSlice("page two"); // Format the entire PageList var pin_map: std.ArrayList(Pin) = .empty; @@ -3689,8 +3689,8 @@ test "PageList soft-wrapped line spanning two pages without unwrap" { const first_page_rows = pages.pages.first.?.data.capacity.rows; // Fill the first page with soft-wrapped content - for (0..first_page_rows - 1) |_| try s.nextSlice("\r\n"); - try s.nextSlice("hello world test"); + for (0..first_page_rows - 1) |_| s.nextSlice("\r\n"); + s.nextSlice("hello world test"); // Verify we're on two pages due to wrapping try testing.expect(pages.pages.first != pages.pages.last); @@ -3753,8 +3753,8 @@ test "PageList soft-wrapped line spanning two pages with unwrap" { const first_page_rows = pages.pages.first.?.data.capacity.rows; // Fill the first page with soft-wrapped content - for (0..first_page_rows - 1) |_| try s.nextSlice("\r\n"); - try s.nextSlice("hello world test"); + for (0..first_page_rows - 1) |_| s.nextSlice("\r\n"); + s.nextSlice("hello world test"); // Verify we're on two pages due to wrapping try testing.expect(pages.pages.first != pages.pages.last); @@ -3814,18 +3814,18 @@ test "PageList VT spanning two pages" { const first_page_rows = pages.pages.first.?.data.capacity.rows; // Fill the first page almost completely - for (0..first_page_rows - 1) |_| try s.nextSlice("\r\n"); - try s.nextSlice("\x1b[1mpage one"); + for (0..first_page_rows - 1) |_| s.nextSlice("\r\n"); + s.nextSlice("\x1b[1mpage one"); // Verify we're still on one page try testing.expect(pages.pages.first == pages.pages.last); // Add one more newline to push content to a second page - try s.nextSlice("\r\n"); + s.nextSlice("\r\n"); try testing.expect(pages.pages.first != pages.pages.last); // New content is still styled - try s.nextSlice("page two"); + s.nextSlice("page two"); // Format the entire PageList with VT var pin_map: std.ArrayList(Pin) = .empty; @@ -3870,7 +3870,7 @@ test "PageList plain with x offset on single page" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello world\r\ntest case\r\nfoo bar"); + s.nextSlice("hello world\r\ntest case\r\nfoo bar"); const pages = &t.screens.active.pages; const node = pages.pages.first.?; @@ -3920,17 +3920,17 @@ test "PageList plain with x offset spanning two pages" { const first_page_rows = pages.pages.first.?.data.capacity.rows; // Fill first page almost completely - for (0..first_page_rows - 1) |_| try s.nextSlice("\r\n"); - try s.nextSlice("hello world"); + for (0..first_page_rows - 1) |_| s.nextSlice("\r\n"); + s.nextSlice("hello world"); // Verify we're still on one page try testing.expect(pages.pages.first == pages.pages.last); // Push to second page - try s.nextSlice("\r\n"); + s.nextSlice("\r\n"); try testing.expect(pages.pages.first != pages.pages.last); - try s.nextSlice("foo bar test"); + s.nextSlice("foo bar test"); const first_node = pages.pages.first.?; const last_node = pages.pages.last.?; @@ -3986,7 +3986,7 @@ test "PageList plain with start_x only" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello world"); + s.nextSlice("hello world"); const pages = &t.screens.active.pages; const node = pages.pages.first.?; @@ -4027,7 +4027,7 @@ test "PageList plain with end_x only" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello world\r\ntest"); + s.nextSlice("hello world\r\ntest"); const pages = &t.screens.active.pages; const node = pages.pages.first.?; @@ -4080,11 +4080,11 @@ test "PageList plain rectangle basic" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Lorem ipsum dolor\r\n"); - try s.nextSlice("sit amet, consectetur\r\n"); - try s.nextSlice("adipiscing elit, sed do\r\n"); - try s.nextSlice("eiusmod tempor incididunt\r\n"); - try s.nextSlice("ut labore et dolore"); + s.nextSlice("Lorem ipsum dolor\r\n"); + s.nextSlice("sit amet, consectetur\r\n"); + s.nextSlice("adipiscing elit, sed do\r\n"); + s.nextSlice("eiusmod tempor incididunt\r\n"); + s.nextSlice("ut labore et dolore"); const pages = &t.screens.active.pages; @@ -4120,11 +4120,11 @@ test "PageList plain rectangle with EOL" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Lorem ipsum dolor\r\n"); - try s.nextSlice("sit amet, consectetur\r\n"); - try s.nextSlice("adipiscing elit, sed do\r\n"); - try s.nextSlice("eiusmod tempor incididunt\r\n"); - try s.nextSlice("ut labore et dolore"); + s.nextSlice("Lorem ipsum dolor\r\n"); + s.nextSlice("sit amet, consectetur\r\n"); + s.nextSlice("adipiscing elit, sed do\r\n"); + s.nextSlice("eiusmod tempor incididunt\r\n"); + s.nextSlice("ut labore et dolore"); const pages = &t.screens.active.pages; @@ -4162,14 +4162,14 @@ test "PageList plain rectangle more complex with breaks" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Lorem ipsum dolor\r\n"); - try s.nextSlice("sit amet, consectetur\r\n"); - try s.nextSlice("adipiscing elit, sed do\r\n"); - try s.nextSlice("eiusmod tempor incididunt\r\n"); - try s.nextSlice("ut labore et dolore\r\n"); - try s.nextSlice("\r\n"); - try s.nextSlice("magna aliqua. Ut enim\r\n"); - try s.nextSlice("ad minim veniam, quis"); + s.nextSlice("Lorem ipsum dolor\r\n"); + s.nextSlice("sit amet, consectetur\r\n"); + s.nextSlice("adipiscing elit, sed do\r\n"); + s.nextSlice("eiusmod tempor incididunt\r\n"); + s.nextSlice("ut labore et dolore\r\n"); + s.nextSlice("\r\n"); + s.nextSlice("magna aliqua. Ut enim\r\n"); + s.nextSlice("ad minim veniam, quis"); const pages = &t.screens.active.pages; @@ -4208,7 +4208,7 @@ test "TerminalFormatter plain no selection" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello\r\nworld"); + s.nextSlice("hello\r\nworld"); const formatter: TerminalFormatter = .init(&t, .plain); @@ -4233,10 +4233,10 @@ test "TerminalFormatter vt with palette" { defer s.deinit(); // Modify some palette colors using VT sequences - try s.nextSlice("\x1b]4;0;rgb:12/34/56\x1b\\"); - try s.nextSlice("\x1b]4;1;rgb:ab/cd/ef\x1b\\"); - try s.nextSlice("\x1b]4;255;rgb:ff/00/ff\x1b\\"); - try s.nextSlice("test"); + s.nextSlice("\x1b]4;0;rgb:12/34/56\x1b\\"); + s.nextSlice("\x1b]4;1;rgb:ab/cd/ef\x1b\\"); + s.nextSlice("\x1b]4;255;rgb:ff/00/ff\x1b\\"); + s.nextSlice("test"); const formatter: TerminalFormatter = .init(&t, .vt); @@ -4253,7 +4253,7 @@ test "TerminalFormatter vt with palette" { var s2 = t2.vtStream(); defer s2.deinit(); - try s2.nextSlice(output); + s2.nextSlice(output); // Verify the palettes match try testing.expectEqual(t.colors.palette.current[0], t2.colors.palette.current[0]); @@ -4277,7 +4277,7 @@ test "TerminalFormatter with selection" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("line1\r\nline2\r\nline3"); + s.nextSlice("line1\r\nline2\r\nline3"); var formatter: TerminalFormatter = .init(&t, .plain); formatter.content = .{ .selection = .init( @@ -4306,7 +4306,7 @@ test "TerminalFormatter plain with pin_map" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello, world"); + s.nextSlice("hello, world"); var pin_map: std.ArrayList(Pin) = .empty; defer pin_map.deinit(alloc); @@ -4343,7 +4343,7 @@ test "TerminalFormatter plain multiline with pin_map" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello\r\nworld"); + s.nextSlice("hello\r\nworld"); var pin_map: std.ArrayList(Pin) = .empty; defer pin_map.deinit(alloc); @@ -4392,8 +4392,8 @@ test "TerminalFormatter vt with palette and pin_map" { defer s.deinit(); // Modify some palette colors using VT sequences - try s.nextSlice("\x1b]4;0;rgb:12/34/56\x1b\\"); - try s.nextSlice("test"); + s.nextSlice("\x1b]4;0;rgb:12/34/56\x1b\\"); + s.nextSlice("test"); var pin_map: std.ArrayList(Pin) = .empty; defer pin_map.deinit(alloc); @@ -4428,7 +4428,7 @@ test "TerminalFormatter with selection and pin_map" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("line1\r\nline2\r\nline3"); + s.nextSlice("line1\r\nline2\r\nline3"); var pin_map: std.ArrayList(Pin) = .empty; defer pin_map.deinit(alloc); @@ -4472,7 +4472,7 @@ test "Screen plain single line" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello, world"); + s.nextSlice("hello, world"); var pin_map: std.ArrayList(Pin) = .empty; defer pin_map.deinit(alloc); @@ -4509,7 +4509,7 @@ test "Screen plain multiline" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello\r\nworld"); + s.nextSlice("hello\r\nworld"); var pin_map: std.ArrayList(Pin) = .empty; defer pin_map.deinit(alloc); @@ -4557,7 +4557,7 @@ test "Screen plain with selection" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("line1\r\nline2\r\nline3"); + s.nextSlice("line1\r\nline2\r\nline3"); var pin_map: std.ArrayList(Pin) = .empty; defer pin_map.deinit(alloc); @@ -4602,7 +4602,7 @@ test "Screen vt with cursor position" { defer s.deinit(); // Position cursor at a specific location - try s.nextSlice("hello\r\nworld"); + s.nextSlice("hello\r\nworld"); var pin_map: std.ArrayList(Pin) = .empty; defer pin_map.deinit(alloc); @@ -4624,7 +4624,7 @@ test "Screen vt with cursor position" { var s2 = t2.vtStream(); defer s2.deinit(); - try s2.nextSlice(output); + s2.nextSlice(output); // Verify cursor positions match try testing.expectEqual(t.screens.active.cursor.x, t2.screens.active.cursor.x); @@ -4661,7 +4661,7 @@ test "Screen vt with style" { defer s.deinit(); // Set some style attributes - try s.nextSlice("\x1b[1;31mhello"); + s.nextSlice("\x1b[1;31mhello"); var pin_map: std.ArrayList(Pin) = .empty; defer pin_map.deinit(alloc); @@ -4683,7 +4683,7 @@ test "Screen vt with style" { var s2 = t2.vtStream(); defer s2.deinit(); - try s2.nextSlice(output); + s2.nextSlice(output); // Verify styles match try testing.expect(t.screens.active.cursor.style.eql(t2.screens.active.cursor.style)); @@ -4713,7 +4713,7 @@ test "Screen vt with hyperlink" { defer s.deinit(); // Set a hyperlink - try s.nextSlice("\x1b]8;;http://example.com\x1b\\hello"); + s.nextSlice("\x1b]8;;http://example.com\x1b\\hello"); var pin_map: std.ArrayList(Pin) = .empty; defer pin_map.deinit(alloc); @@ -4735,7 +4735,7 @@ test "Screen vt with hyperlink" { var s2 = t2.vtStream(); defer s2.deinit(); - try s2.nextSlice(output); + s2.nextSlice(output); // Verify hyperlinks match const has_link1 = t.screens.active.cursor.hyperlink != null; @@ -4773,7 +4773,7 @@ test "Screen vt with protection" { defer s.deinit(); // Enable protection mode - try s.nextSlice("\x1b[1\"qhello"); + s.nextSlice("\x1b[1\"qhello"); var pin_map: std.ArrayList(Pin) = .empty; defer pin_map.deinit(alloc); @@ -4795,7 +4795,7 @@ test "Screen vt with protection" { var s2 = t2.vtStream(); defer s2.deinit(); - try s2.nextSlice(output); + s2.nextSlice(output); // Verify protection state matches try testing.expectEqual(t.screens.active.cursor.protected, t2.screens.active.cursor.protected); @@ -4825,7 +4825,7 @@ test "Screen vt with kitty keyboard" { defer s.deinit(); // Set kitty keyboard flags (disambiguate + report_events = 3) - try s.nextSlice("\x1b[=3;1uhello"); + s.nextSlice("\x1b[=3;1uhello"); var pin_map: std.ArrayList(Pin) = .empty; defer pin_map.deinit(alloc); @@ -4847,7 +4847,7 @@ test "Screen vt with kitty keyboard" { var s2 = t2.vtStream(); defer s2.deinit(); - try s2.nextSlice(output); + s2.nextSlice(output); // Verify kitty keyboard state matches const flags1 = t.screens.active.kitty_keyboard.current().int(); @@ -4879,7 +4879,7 @@ test "Screen vt with charsets" { defer s.deinit(); // Set G0 to DEC special and shift to G1 - try s.nextSlice("\x1b(0\x0ehello"); + s.nextSlice("\x1b(0\x0ehello"); var pin_map: std.ArrayList(Pin) = .empty; defer pin_map.deinit(alloc); @@ -4901,7 +4901,7 @@ test "Screen vt with charsets" { var s2 = t2.vtStream(); defer s2.deinit(); - try s2.nextSlice(output); + s2.nextSlice(output); // Verify charset state matches try testing.expectEqual(t.screens.active.charset.gl, t2.screens.active.charset.gl); @@ -4936,7 +4936,7 @@ test "Terminal vt with scrolling region" { defer s.deinit(); // Set scrolling region: top=5, bottom=20 - try s.nextSlice("\x1b[6;21rhello"); + s.nextSlice("\x1b[6;21rhello"); var formatter: TerminalFormatter = .init(&t, .vt); formatter.extra.scrolling_region = true; @@ -4954,7 +4954,7 @@ test "Terminal vt with scrolling region" { var s2 = t2.vtStream(); defer s2.deinit(); - try s2.nextSlice(output); + s2.nextSlice(output); // Verify scrolling regions match try testing.expectEqual(t.scrolling_region.top, t2.scrolling_region.top); @@ -4980,10 +4980,10 @@ test "Terminal vt with modes" { defer s.deinit(); // Enable some modes that differ from defaults - try s.nextSlice("\x1b[?2004h"); // Bracketed paste - try s.nextSlice("\x1b[?1000h"); // Mouse event normal - try s.nextSlice("\x1b[?7l"); // Disable wraparound (default is true) - try s.nextSlice("hello"); + s.nextSlice("\x1b[?2004h"); // Bracketed paste + s.nextSlice("\x1b[?1000h"); // Mouse event normal + s.nextSlice("\x1b[?7l"); // Disable wraparound (default is true) + s.nextSlice("hello"); var formatter: TerminalFormatter = .init(&t, .vt); formatter.extra.modes = true; @@ -5001,7 +5001,7 @@ test "Terminal vt with modes" { var s2 = t2.vtStream(); defer s2.deinit(); - try s2.nextSlice(output); + s2.nextSlice(output); // Verify modes match try testing.expectEqual(t.modes.get(.bracketed_paste), t2.modes.get(.bracketed_paste)); @@ -5026,11 +5026,11 @@ test "Terminal vt with tabstops" { defer s.deinit(); // Clear all tabs and set custom tabstops - try s.nextSlice("\x1b[3g"); // Clear all tabs - try s.nextSlice("\x1b[5G\x1bH"); // Set tab at column 5 - try s.nextSlice("\x1b[15G\x1bH"); // Set tab at column 15 - try s.nextSlice("\x1b[30G\x1bH"); // Set tab at column 30 - try s.nextSlice("hello"); + s.nextSlice("\x1b[3g"); // Clear all tabs + s.nextSlice("\x1b[5G\x1bH"); // Set tab at column 5 + s.nextSlice("\x1b[15G\x1bH"); // Set tab at column 15 + s.nextSlice("\x1b[30G\x1bH"); // Set tab at column 30 + s.nextSlice("hello"); var formatter: TerminalFormatter = .init(&t, .vt); formatter.extra.tabstops = true; @@ -5048,7 +5048,7 @@ test "Terminal vt with tabstops" { var s2 = t2.vtStream(); defer s2.deinit(); - try s2.nextSlice(output); + s2.nextSlice(output); // Verify tabstops match (columns are 0-indexed in the API) try testing.expectEqual(t.tabstops.get(4), t2.tabstops.get(4)); @@ -5077,8 +5077,8 @@ test "Terminal vt with keyboard modes" { defer s.deinit(); // Set modify other keys mode 2 - try s.nextSlice("\x1b[>4;2m"); - try s.nextSlice("hello"); + s.nextSlice("\x1b[>4;2m"); + s.nextSlice("hello"); var formatter: TerminalFormatter = .init(&t, .vt); formatter.extra.keyboard = true; @@ -5096,7 +5096,7 @@ test "Terminal vt with keyboard modes" { var s2 = t2.vtStream(); defer s2.deinit(); - try s2.nextSlice(output); + s2.nextSlice(output); // Verify keyboard mode matches try testing.expectEqual(t.flags.modify_other_keys_2, t2.flags.modify_other_keys_2); @@ -5120,7 +5120,7 @@ test "Terminal vt with pwd" { defer s.deinit(); // Set pwd using OSC 7 - try s.nextSlice("\x1b]7;file://host/home/user\x1b\\hello"); + s.nextSlice("\x1b]7;file://host/home/user\x1b\\hello"); var formatter: TerminalFormatter = .init(&t, .vt); formatter.extra.pwd = true; @@ -5138,7 +5138,7 @@ test "Terminal vt with pwd" { var s2 = t2.vtStream(); defer s2.deinit(); - try s2.nextSlice(output); + s2.nextSlice(output); // Verify pwd matches try testing.expectEqualStrings(t.pwd.items, t2.pwd.items); @@ -5161,7 +5161,7 @@ test "Page html with multiple styles" { defer s.deinit(); // Set bold, then italic, then reset - try s.nextSlice("\x1b[1mbold\x1b[3mitalic\x1b[0mnormal"); + s.nextSlice("\x1b[1mbold\x1b[3mitalic\x1b[0mnormal"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5196,7 +5196,7 @@ test "Page html plain text" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello, world"); + s.nextSlice("hello, world"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5229,7 +5229,7 @@ test "Page html with colors" { defer s.deinit(); // Set red foreground, blue background - try s.nextSlice("\x1b[31;44mcolored"); + s.nextSlice("\x1b[31;44mcolored"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5263,10 +5263,10 @@ test "TerminalFormatter html with palette" { defer s.deinit(); // Modify some palette colors - try s.nextSlice("\x1b]4;0;rgb:12/34/56\x1b\\"); - try s.nextSlice("\x1b]4;1;rgb:ab/cd/ef\x1b\\"); - try s.nextSlice("\x1b]4;255;rgb:ff/00/ff\x1b\\"); - try s.nextSlice("test"); + s.nextSlice("\x1b]4;0;rgb:12/34/56\x1b\\"); + s.nextSlice("\x1b]4;1;rgb:ab/cd/ef\x1b\\"); + s.nextSlice("\x1b]4;255;rgb:ff/00/ff\x1b\\"); + s.nextSlice("test"); var formatter: TerminalFormatter = .init(&t, .{ .emit = .html }); formatter.extra.palette = true; @@ -5299,7 +5299,7 @@ test "Page html with background and foreground colors" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello"); + s.nextSlice("hello"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5334,7 +5334,7 @@ test "Page html with escaping" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("&\"'text"); + s.nextSlice("&\"'text"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5405,7 +5405,7 @@ test "Page html with unicode as numeric entities" { defer s.deinit(); // Box drawing characters that caused issue #9426 - try s.nextSlice("╰─ ❯"); + s.nextSlice("╰─ ❯"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5438,7 +5438,7 @@ test "Page html ascii characters unchanged" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello world"); + s.nextSlice("hello world"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5470,7 +5470,7 @@ test "Page html mixed ascii and unicode" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("test ╰─❯ ok"); + s.nextSlice("test ╰─❯ ok"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5503,8 +5503,8 @@ test "Page VT with palette option emits RGB" { defer s.deinit(); // Set a custom palette color and use it - try s.nextSlice("\x1b]4;1;rgb:ab/cd/ef\x1b\\"); - try s.nextSlice("\x1b[31mred"); + s.nextSlice("\x1b]4;1;rgb:ab/cd/ef\x1b\\"); + s.nextSlice("\x1b[31mred"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5547,8 +5547,8 @@ test "Page html with palette option emits RGB" { defer s.deinit(); // Set a custom palette color and use it - try s.nextSlice("\x1b]4;1;rgb:ab/cd/ef\x1b\\"); - try s.nextSlice("\x1b[31mred"); + s.nextSlice("\x1b]4;1;rgb:ab/cd/ef\x1b\\"); + s.nextSlice("\x1b[31mred"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5601,7 +5601,7 @@ test "Page VT style reset properly closes styles" { defer s.deinit(); // Set bold, then reset with SGR 0 - try s.nextSlice("\x1b[1mbold\x1b[0mnormal"); + s.nextSlice("\x1b[1mbold\x1b[0mnormal"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5631,7 +5631,7 @@ test "Page codepoint_map single replacement" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello world"); + s.nextSlice("hello world"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5690,7 +5690,7 @@ test "Page codepoint_map conflicting replacement prefers last" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello"); + s.nextSlice("hello"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5732,7 +5732,7 @@ test "Page codepoint_map replace with string" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello"); + s.nextSlice("hello"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5788,7 +5788,7 @@ test "Page codepoint_map range replacement" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("abcdefg"); + s.nextSlice("abcdefg"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5826,7 +5826,7 @@ test "Page codepoint_map multiple ranges" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello world"); + s.nextSlice("hello world"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5870,7 +5870,7 @@ test "Page codepoint_map unicode replacement" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello ⚡ world"); + s.nextSlice("hello ⚡ world"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5935,7 +5935,7 @@ test "Page codepoint_map with styled formats" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("\x1b[31mred text\x1b[0m"); + s.nextSlice("\x1b[31mred text\x1b[0m"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -5976,7 +5976,7 @@ test "Page codepoint_map empty map" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("hello world"); + s.nextSlice("hello world"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -6016,9 +6016,9 @@ test "Page VT background color on trailing blank cells" { // Simulate a TUI row: "CPU:" with text, then trailing cells with red background // to end of line (no text after the colored region). // \x1b[41m sets red background, then EL fills rest of row with that bg. - try s.nextSlice("CPU:\x1b[41m\x1b[K"); + s.nextSlice("CPU:\x1b[41m\x1b[K"); // Reset colors and move to next line with different content - try s.nextSlice("\x1b[0m\r\nline2"); + s.nextSlice("\x1b[0m\r\nline2"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -6065,7 +6065,7 @@ test "Page HTML with hyperlinks" { defer s.deinit(); // Start a hyperlink, write some text, end it - try s.nextSlice("\x1b]8;;https://example.com\x1b\\link text\x1b]8;;\x1b\\ normal"); + s.nextSlice("\x1b]8;;https://example.com\x1b\\link text\x1b]8;;\x1b\\ normal"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -6099,8 +6099,8 @@ test "Page HTML with multiple hyperlinks" { defer s.deinit(); // Two different hyperlinks - try s.nextSlice("\x1b]8;;https://first.com\x1b\\first\x1b]8;;\x1b\\ "); - try s.nextSlice("\x1b]8;;https://second.com\x1b\\second\x1b]8;;\x1b\\"); + s.nextSlice("\x1b]8;;https://first.com\x1b\\first\x1b]8;;\x1b\\ "); + s.nextSlice("\x1b]8;;https://second.com\x1b\\second\x1b]8;;\x1b\\"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -6136,7 +6136,7 @@ test "Page HTML with hyperlink escaping" { defer s.deinit(); // URL with special characters that need escaping - try s.nextSlice("\x1b]8;;https://example.com?a=1&b=2\x1b\\link\x1b]8;;\x1b\\"); + s.nextSlice("\x1b]8;;https://example.com?a=1&b=2\x1b\\link\x1b]8;;\x1b\\"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -6170,7 +6170,7 @@ test "Page HTML with styled hyperlink" { defer s.deinit(); // Bold hyperlink - try s.nextSlice("\x1b]8;;https://example.com\x1b\\\x1b[1mbold link\x1b[0m\x1b]8;;\x1b\\"); + s.nextSlice("\x1b]8;;https://example.com\x1b\\\x1b[1mbold link\x1b[0m\x1b]8;;\x1b\\"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -6205,7 +6205,7 @@ test "Page HTML hyperlink closes style before anchor" { defer s.deinit(); // Styled hyperlink followed by plain text - try s.nextSlice("\x1b]8;;https://example.com\x1b\\\x1b[1mbold\x1b[0m plain"); + s.nextSlice("\x1b]8;;https://example.com\x1b\\\x1b[1mbold\x1b[0m plain"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; @@ -6239,7 +6239,7 @@ test "Page HTML hyperlink point map maps closing to previous cell" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("\x1b]8;;https://example.com\x1b\\link\x1b]8;;\x1b\\ normal"); + s.nextSlice("\x1b]8;;https://example.com\x1b\\link\x1b]8;;\x1b\\ normal"); const pages = &t.screens.active.pages; const page = &pages.pages.last.?.data; diff --git a/src/terminal/render.zig b/src/terminal/render.zig index 2332866ac..8ce77061d 100644 --- a/src/terminal/render.zig +++ b/src/terminal/render.zig @@ -908,7 +908,7 @@ test "basic text" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("ABCD"); + s.nextSlice("ABCD"); var state: RenderState = .empty; defer state.deinit(alloc); @@ -944,9 +944,9 @@ test "styled text" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("\x1b[1mA"); // Bold - try s.nextSlice("\x1b[0;3mB"); // Italic - try s.nextSlice("\x1b[0;4mC"); // Underline + s.nextSlice("\x1b[1mA"); // Bold + s.nextSlice("\x1b[0;3mB"); // Italic + s.nextSlice("\x1b[0;4mC"); // Underline var state: RenderState = .empty; defer state.deinit(alloc); @@ -990,8 +990,8 @@ test "grapheme" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("A"); - try s.nextSlice("👨‍"); // this has a ZWJ + s.nextSlice("A"); + s.nextSlice("👨‍"); // this has a ZWJ var state: RenderState = .empty; defer state.deinit(alloc); @@ -1037,7 +1037,7 @@ test "cursor state in viewport" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("A\x1b[H"); + s.nextSlice("A\x1b[H"); var state: RenderState = .empty; defer state.deinit(alloc); @@ -1052,14 +1052,14 @@ test "cursor state in viewport" { try testing.expect(state.cursor.style.default()); // Set a style on the cursor - try s.nextSlice("\x1b[1m"); // Bold + s.nextSlice("\x1b[1m"); // Bold try state.update(alloc, &t); try testing.expect(!state.cursor.style.default()); try testing.expect(state.cursor.style.flags.bold); - try s.nextSlice("\x1b[0m"); // Reset style + s.nextSlice("\x1b[0m"); // Reset style // Move cursor to 2,1 - try s.nextSlice("\x1b[2;3H"); + s.nextSlice("\x1b[2;3H"); try state.update(alloc, &t); try testing.expectEqual(2, state.cursor.active.x); try testing.expectEqual(1, state.cursor.active.y); @@ -1079,7 +1079,7 @@ test "cursor state out of viewport" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("A\r\nB\r\nC\r\nD\r\n"); + s.nextSlice("A\r\nB\r\nC\r\nD\r\n"); var state: RenderState = .empty; defer state.deinit(alloc); @@ -1139,7 +1139,7 @@ test "dirty state" { } // Write to first line - try s.nextSlice("A"); + s.nextSlice("A"); try state.update(alloc, &t); try testing.expectEqual(.partial, state.dirty); { @@ -1170,7 +1170,7 @@ test "colors" { try state.update(alloc, &t); // Change cursor color - try s.nextSlice("\x1b]12;#FF0000\x07"); + s.nextSlice("\x1b]12;#FF0000\x07"); try state.update(alloc, &t); const c = state.colors.cursor.?; @@ -1179,7 +1179,7 @@ test "colors" { try testing.expectEqual(0, c.b); // Change palette color 0 to White - try s.nextSlice("\x1b]4;0;#FFFFFF\x07"); + s.nextSlice("\x1b]4;0;#FFFFFF\x07"); try state.update(alloc, &t); const p0 = state.colors.palette[0]; try testing.expectEqual(0xFF, p0.r); @@ -1275,7 +1275,7 @@ test "linkCells" { defer state.deinit(alloc); // Create a hyperlink - try s.nextSlice("\x1b]8;;http://example.com\x1b\\LINK\x1b]8;;\x1b\\"); + s.nextSlice("\x1b]8;;http://example.com\x1b\\LINK\x1b]8;;\x1b\\"); try state.update(alloc, &t); // Query link at 0,0 @@ -1306,7 +1306,7 @@ test "string" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("AB"); + s.nextSlice("AB"); var state: RenderState = .empty; defer state.deinit(alloc); @@ -1345,12 +1345,12 @@ test "linkCells with scrollback spanning pages" { const first_page_cap = pages.pages.first.?.data.capacity.rows; // Fill first page - for (0..first_page_cap - 1) |_| try s.nextSlice("\r\n"); + for (0..first_page_cap - 1) |_| s.nextSlice("\r\n"); // Create second page with hyperlink - try s.nextSlice("\r\n"); - try s.nextSlice("\x1b]8;;http://example.com\x1b\\LINK\x1b]8;;\x1b\\"); - for (0..(tail_rows - 1)) |_| try s.nextSlice("\r\n"); + s.nextSlice("\r\n"); + s.nextSlice("\x1b]8;;http://example.com\x1b\\LINK\x1b]8;;\x1b\\"); + for (0..(tail_rows - 1)) |_| s.nextSlice("\r\n"); var state: RenderState = .empty; defer state.deinit(alloc); @@ -1416,7 +1416,7 @@ test "dirty row resets highlights" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("ABC"); + s.nextSlice("ABC"); var state: RenderState = .empty; defer state.deinit(alloc); @@ -1451,8 +1451,8 @@ test "dirty row resets highlights" { } // Write to row 0 to make it dirty - try s.nextSlice("\x1b[H"); // Move to home - try s.nextSlice("X"); + s.nextSlice("\x1b[H"); // Move to home + s.nextSlice("X"); try state.update(alloc, &t); // Verify the highlight was reset on the dirty row diff --git a/src/terminal/search/Thread.zig b/src/terminal/search/Thread.zig index 3f5377417..fa09af5f0 100644 --- a/src/terminal/search/Thread.zig +++ b/src/terminal/search/Thread.zig @@ -853,7 +853,7 @@ test { var stream = t.vtStream(); defer stream.deinit(); - try stream.nextSlice("Hello, world"); + stream.nextSlice("Hello, world"); var ud: TestUserData = .{}; defer ud.deinit(); diff --git a/src/terminal/search/active.zig b/src/terminal/search/active.zig index 236f4c7a6..692a10e12 100644 --- a/src/terminal/search/active.zig +++ b/src/terminal/search/active.zig @@ -108,7 +108,7 @@ test "simple search" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); + s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); var search: ActiveSearch = try .init(alloc, "Fizz"); defer search.deinit(); @@ -148,15 +148,15 @@ test "clear screen and search" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); + s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); var search: ActiveSearch = try .init(alloc, "Fizz"); defer search.deinit(); _ = try search.update(&t.screens.active.pages); - try s.nextSlice("\x1b[2J"); // Clear screen - try s.nextSlice("\x1b[H"); // Move cursor home - try s.nextSlice("Buzz\r\nFizz\r\nBuzz"); + s.nextSlice("\x1b[2J"); // Clear screen + s.nextSlice("\x1b[H"); // Move cursor home + s.nextSlice("Buzz\r\nFizz\r\nBuzz"); _ = try search.update(&t.screens.active.pages); { diff --git a/src/terminal/search/pagelist.zig b/src/terminal/search/pagelist.zig index 4bfd241e7..f76ad4e4b 100644 --- a/src/terminal/search/pagelist.zig +++ b/src/terminal/search/pagelist.zig @@ -141,7 +141,7 @@ test "simple search" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); + s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); var search: PageListSearch = try .init( alloc, @@ -191,14 +191,14 @@ test "feed multiple pages with matches" { // Fill up first page const first_page_rows = t.screens.active.pages.pages.first.?.data.capacity.rows; - for (0..first_page_rows - 1) |_| try s.nextSlice("\r\n"); - try s.nextSlice("Fizz"); + for (0..first_page_rows - 1) |_| s.nextSlice("\r\n"); + s.nextSlice("Fizz"); try testing.expect(t.screens.active.pages.pages.first == t.screens.active.pages.pages.last); // Create second page - try s.nextSlice("\r\n"); + s.nextSlice("\r\n"); try testing.expect(t.screens.active.pages.pages.first != t.screens.active.pages.pages.last); - try s.nextSlice("Buzz\r\nFizz"); + s.nextSlice("Buzz\r\nFizz"); var search: PageListSearch = try .init( alloc, @@ -235,13 +235,13 @@ test "feed multiple pages no matches" { // Fill up first page const first_page_rows = t.screens.active.pages.pages.first.?.data.capacity.rows; - for (0..first_page_rows - 1) |_| try s.nextSlice("\r\n"); - try s.nextSlice("Hello"); + for (0..first_page_rows - 1) |_| s.nextSlice("\r\n"); + s.nextSlice("Hello"); // Create second page - try s.nextSlice("\r\n"); + s.nextSlice("\r\n"); try testing.expect(t.screens.active.pages.pages.first != t.screens.active.pages.pages.last); - try s.nextSlice("World"); + s.nextSlice("World"); var search: PageListSearch = try .init( alloc, @@ -275,14 +275,14 @@ test "feed iteratively through multiple matches" { const first_page_rows = t.screens.active.pages.pages.first.?.data.capacity.rows; // Fill first page with a match at the end - for (0..first_page_rows - 1) |_| try s.nextSlice("\r\n"); - try s.nextSlice("Page1Test"); + for (0..first_page_rows - 1) |_| s.nextSlice("\r\n"); + s.nextSlice("Page1Test"); try testing.expect(t.screens.active.pages.pages.first == t.screens.active.pages.pages.last); // Create second page with a match - try s.nextSlice("\r\n"); + s.nextSlice("\r\n"); try testing.expect(t.screens.active.pages.pages.first != t.screens.active.pages.pages.last); - try s.nextSlice("Page2Test"); + s.nextSlice("Page2Test"); var search: PageListSearch = try .init( alloc, @@ -316,13 +316,13 @@ test "feed with match spanning page boundary" { const first_page_rows = t.screens.active.pages.pages.first.?.data.capacity.rows; // Fill first page ending with "Te" - for (0..first_page_rows - 1) |_| try s.nextSlice("\r\n"); - for (0..t.screens.active.pages.cols - 2) |_| try s.nextSlice("x"); - try s.nextSlice("Te"); + for (0..first_page_rows - 1) |_| s.nextSlice("\r\n"); + for (0..t.screens.active.pages.cols - 2) |_| s.nextSlice("x"); + s.nextSlice("Te"); try testing.expect(t.screens.active.pages.pages.first == t.screens.active.pages.pages.last); // Second page starts with "st" - try s.nextSlice("st"); + s.nextSlice("st"); try testing.expect(t.screens.active.pages.pages.first != t.screens.active.pages.pages.last); var search: PageListSearch = try .init( @@ -370,15 +370,15 @@ test "feed with match spanning page boundary with newline" { const first_page_rows = t.screens.active.pages.pages.first.?.data.capacity.rows; // Fill first page ending with "Te" - for (0..first_page_rows - 1) |_| try s.nextSlice("\r\n"); - for (0..t.screens.active.pages.cols - 2) |_| try s.nextSlice("x"); - try s.nextSlice("Te"); + for (0..first_page_rows - 1) |_| s.nextSlice("\r\n"); + for (0..t.screens.active.pages.cols - 2) |_| s.nextSlice("x"); + s.nextSlice("Te"); try testing.expect(t.screens.active.pages.pages.first == t.screens.active.pages.pages.last); // Second page starts with "st" - try s.nextSlice("\r\n"); + s.nextSlice("\r\n"); try testing.expect(t.screens.active.pages.pages.first != t.screens.active.pages.pages.last); - try s.nextSlice("st"); + s.nextSlice("st"); var search: PageListSearch = try .init( alloc, diff --git a/src/terminal/search/screen.zig b/src/terminal/search/screen.zig index ca2a5a894..e98ecd958 100644 --- a/src/terminal/search/screen.zig +++ b/src/terminal/search/screen.zig @@ -827,7 +827,7 @@ test "simple search" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); + s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz"); defer search.deinit(); @@ -877,10 +877,10 @@ test "simple search with history" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Fizz\r\n"); - while (list.totalPages() < 3) try s.nextSlice("\r\n"); - for (0..list.rows) |_| try s.nextSlice("\r\n"); - try s.nextSlice("hello."); + s.nextSlice("Fizz\r\n"); + while (list.totalPages() < 3) s.nextSlice("\r\n"); + for (0..list.rows) |_| s.nextSlice("\r\n"); + s.nextSlice("hello."); var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz"); defer search.deinit(); @@ -917,7 +917,7 @@ test "reload active with history change" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Fizz\r\n"); + s.nextSlice("Fizz\r\n"); // Start up our search which will populate our initial active area. var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz"); @@ -930,9 +930,9 @@ test "reload active with history change" { } // Grow into two pages so our history pin will move. - while (list.totalPages() < 2) try s.nextSlice("\r\n"); - for (0..list.rows) |_| try s.nextSlice("\r\n"); - try s.nextSlice("2Fizz"); + while (list.totalPages() < 2) s.nextSlice("\r\n"); + for (0..list.rows) |_| s.nextSlice("\r\n"); + s.nextSlice("2Fizz"); // Active area changed so reload try search.reloadActive(); @@ -969,7 +969,7 @@ test "reload active with history change" { // Reset the screen which will make our pin garbage. t.fullReset(); - try s.nextSlice("WeFizzing"); + s.nextSlice("WeFizzing"); try search.reloadActive(); try search.searchAll(); @@ -998,7 +998,7 @@ test "active change contents" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Fuzz\r\nBuzz\r\nFizz\r\nBang"); + s.nextSlice("Fuzz\r\nBuzz\r\nFizz\r\nBang"); var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz"); defer search.deinit(); @@ -1006,8 +1006,8 @@ test "active change contents" { try testing.expectEqual(1, search.active_results.items.len); // Erase the screen, move our cursor to the top, and change contents. - try s.nextSlice("\x1b[2J\x1b[H"); // Clear screen and move home - try s.nextSlice("Bang\r\nFizz\r\nHello!"); + s.nextSlice("\x1b[2J\x1b[H"); // Clear screen and move home + s.nextSlice("Bang\r\nFizz\r\nHello!"); try search.reloadActive(); try search.searchAll(); @@ -1038,7 +1038,7 @@ test "select next" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); + s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz"); defer search.deinit(); @@ -1097,7 +1097,7 @@ test "select in active changes contents completely" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); + s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz"); defer search.deinit(); @@ -1118,8 +1118,8 @@ test "select in active changes contents completely" { } // Erase the screen, move our cursor to the top, and change contents. - try s.nextSlice("\x1b[2J\x1b[H"); // Clear screen and move home - try s.nextSlice("Fuzz\r\nFizz\r\nHello!"); + s.nextSlice("\x1b[2J\x1b[H"); // Clear screen and move home + s.nextSlice("Fuzz\r\nFizz\r\nHello!"); try search.reloadActive(); { @@ -1136,8 +1136,8 @@ test "select in active changes contents completely" { } // Erase the screen, redraw with same contents. - try s.nextSlice("\x1b[2J\x1b[H"); // Clear screen and move home - try s.nextSlice("Fuzz\r\nFizz\r\nFizz"); + s.nextSlice("\x1b[2J\x1b[H"); // Clear screen and move home + s.nextSlice("Fuzz\r\nFizz\r\nFizz"); try search.reloadActive(); { @@ -1167,10 +1167,10 @@ test "select into history" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Fizz\r\n"); - while (list.totalPages() < 3) try s.nextSlice("\r\n"); - for (0..list.rows) |_| try s.nextSlice("\r\n"); - try s.nextSlice("hello."); + s.nextSlice("Fizz\r\n"); + while (list.totalPages() < 3) s.nextSlice("\r\n"); + for (0..list.rows) |_| s.nextSlice("\r\n"); + s.nextSlice("hello."); var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz"); defer search.deinit(); @@ -1191,8 +1191,8 @@ test "select into history" { } // Erase the screen, redraw with same contents. - try s.nextSlice("\x1b[2J\x1b[H"); // Clear screen and move home - try s.nextSlice("yo yo"); + s.nextSlice("\x1b[2J\x1b[H"); // Clear screen and move home + s.nextSlice("yo yo"); try search.reloadActive(); { @@ -1209,7 +1209,7 @@ test "select into history" { } // Create some new history by adding more lines. - try s.nextSlice("\r\nfizz\r\nfizz\r\nfizz"); // Clear screen and move home + s.nextSlice("\r\nfizz\r\nfizz\r\nfizz"); // Clear screen and move home try search.reloadActive(); { // Our selection should not move since the history is still not @@ -1233,7 +1233,7 @@ test "select prev" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); + s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz"); defer search.deinit(); @@ -1292,7 +1292,7 @@ test "select prev then next" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); + s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz"); defer search.deinit(); @@ -1342,10 +1342,10 @@ test "select prev with history" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Fizz\r\n"); - while (list.totalPages() < 3) try s.nextSlice("\r\n"); - for (0..list.rows) |_| try s.nextSlice("\r\n"); - try s.nextSlice("Fizz."); + s.nextSlice("Fizz\r\n"); + while (list.totalPages() < 3) s.nextSlice("\r\n"); + for (0..list.rows) |_| s.nextSlice("\r\n"); + s.nextSlice("Fizz."); var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz"); defer search.deinit(); @@ -1399,9 +1399,9 @@ test "screen search no scrollback has no history" { // no way to test it using public APIs, but at the time of writing // this test, CSI 22 J (scroll complete) pushes into scrollback // with alt screen. - try s.nextSlice("Fizz\r\n"); - try s.nextSlice("\x1b[22J"); - try s.nextSlice("hello."); + s.nextSlice("Fizz\r\n"); + s.nextSlice("\x1b[22J"); + s.nextSlice("hello."); var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz"); defer search.deinit(); @@ -1431,10 +1431,10 @@ test "reloadActive partial history cleanup on appendSlice error" { // Write multiple "Fizz" matches that will end up in history. // We need enough content to push "Fizz" entries into scrollback. - try s.nextSlice("Fizz\r\nFizz\r\n"); - while (list.totalPages() < 3) try s.nextSlice("\r\n"); - for (0..list.rows) |_| try s.nextSlice("\r\n"); - try s.nextSlice("Fizz."); + s.nextSlice("Fizz\r\nFizz\r\n"); + while (list.totalPages() < 3) s.nextSlice("\r\n"); + for (0..list.rows) |_| s.nextSlice("\r\n"); + s.nextSlice("Fizz."); // Complete initial search var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz"); @@ -1443,9 +1443,9 @@ test "reloadActive partial history cleanup on appendSlice error" { // Now trigger reloadActive by adding more content that changes the // active/history boundary. First add more "Fizz" entries to history. - try s.nextSlice("\r\nFizz\r\nFizz\r\n"); - while (list.totalPages() < 4) try s.nextSlice("\r\n"); - for (0..list.rows) |_| try s.nextSlice("\r\n"); + s.nextSlice("\r\nFizz\r\nFizz\r\n"); + while (list.totalPages() < 4) s.nextSlice("\r\n"); + for (0..list.rows) |_| s.nextSlice("\r\n"); // Arm the tripwire to fail at appendSlice (after the loop completes). // At this point, there are FlattenedHighlight items in the results list @@ -1478,10 +1478,10 @@ test "reloadActive partial history cleanup on loop append error" { // Write multiple "Fizz" matches that will end up in history. // We need enough content to push "Fizz" entries into scrollback. - try s.nextSlice("Fizz\r\nFizz\r\n"); - while (list.totalPages() < 3) try s.nextSlice("\r\n"); - for (0..list.rows) |_| try s.nextSlice("\r\n"); - try s.nextSlice("Fizz."); + s.nextSlice("Fizz\r\nFizz\r\n"); + while (list.totalPages() < 3) s.nextSlice("\r\n"); + for (0..list.rows) |_| s.nextSlice("\r\n"); + s.nextSlice("Fizz."); // Complete initial search var search: ScreenSearch = try .init(alloc, t.screens.active, "Fizz"); @@ -1490,9 +1490,9 @@ test "reloadActive partial history cleanup on loop append error" { // Now trigger reloadActive by adding more content that changes the // active/history boundary. First add more "Fizz" entries to history. - try s.nextSlice("\r\nFizz\r\nFizz\r\n"); - while (list.totalPages() < 4) try s.nextSlice("\r\n"); - for (0..list.rows) |_| try s.nextSlice("\r\n"); + s.nextSlice("\r\nFizz\r\nFizz\r\n"); + while (list.totalPages() < 4) s.nextSlice("\r\n"); + for (0..list.rows) |_| s.nextSlice("\r\n"); // Arm the tripwire to fail after the first loop append succeeds. // This leaves at least one FlattenedHighlight in the results list diff --git a/src/terminal/search/sliding_window.zig b/src/terminal/search/sliding_window.zig index c3c29e085..93a606fda 100644 --- a/src/terminal/search/sliding_window.zig +++ b/src/terminal/search/sliding_window.zig @@ -1583,7 +1583,7 @@ test "SlidingWindow single append soft wrapped" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("A\r\nxxboo!\r\nC"); + s.nextSlice("A\r\nxxboo!\r\nC"); // We want to test single-page cases. const screen = t.screens.active; @@ -1620,7 +1620,7 @@ test "SlidingWindow single append reversed soft wrapped" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("A\r\nxxboo!\r\nC"); + s.nextSlice("A\r\nxxboo!\r\nC"); // We want to test single-page cases. const screen = t.screens.active; diff --git a/src/terminal/search/viewport.zig b/src/terminal/search/viewport.zig index f5e6c8601..35dd93315 100644 --- a/src/terminal/search/viewport.zig +++ b/src/terminal/search/viewport.zig @@ -223,7 +223,7 @@ test "simple search" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); + s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); var search: ViewportSearch = try .init(alloc, "Fizz"); defer search.deinit(); @@ -266,15 +266,15 @@ test "clear screen and search" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); + s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); var search: ViewportSearch = try .init(alloc, "Fizz"); defer search.deinit(); try testing.expect(try search.update(&t.screens.active.pages)); - try s.nextSlice("\x1b[2J"); // Clear screen - try s.nextSlice("\x1b[H"); // Move cursor home - try s.nextSlice("Buzz\r\nFizz\r\nBuzz"); + s.nextSlice("\x1b[2J"); // Clear screen + s.nextSlice("\x1b[H"); // Move cursor home + s.nextSlice("Buzz\r\nFizz\r\nBuzz"); try testing.expect(try search.update(&t.screens.active.pages)); { @@ -299,7 +299,7 @@ test "clear screen and search dirty tracking" { var s = t.vtStream(); defer s.deinit(); - try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); + s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang"); var search: ViewportSearch = try .init(alloc, "Fizz"); defer search.deinit(); @@ -313,9 +313,9 @@ test "clear screen and search dirty tracking" { // Should not update since nothing changed try testing.expect(!try search.update(&t.screens.active.pages)); - try s.nextSlice("\x1b[2J"); // Clear screen - try s.nextSlice("\x1b[H"); // Move cursor home - try s.nextSlice("Buzz\r\nFizz\r\nBuzz"); + s.nextSlice("\x1b[2J"); // Clear screen + s.nextSlice("\x1b[H"); // Move cursor home + s.nextSlice("Buzz\r\nFizz\r\nBuzz"); // Should still not update since active area isn't dirty try testing.expect(!try search.update(&t.screens.active.pages)); @@ -349,14 +349,14 @@ test "history search, no active area" { // Fill up first page const first_page_rows = t.screens.active.pages.pages.first.?.data.capacity.rows; - try s.nextSlice("Fizz\r\n"); - for (1..first_page_rows - 1) |_| try s.nextSlice("\r\n"); + s.nextSlice("Fizz\r\n"); + for (1..first_page_rows - 1) |_| s.nextSlice("\r\n"); try testing.expect(t.screens.active.pages.pages.first == t.screens.active.pages.pages.last); // Create second page - try s.nextSlice("\r\n"); + s.nextSlice("\r\n"); try testing.expect(t.screens.active.pages.pages.first != t.screens.active.pages.pages.last); - try s.nextSlice("Buzz\r\nFizz"); + s.nextSlice("Buzz\r\nFizz"); t.scrollViewport(.top); diff --git a/src/terminal/stream.zig b/src/terminal/stream.zig index e89c73e66..5f83128a9 100644 --- a/src/terminal/stream.zig +++ b/src/terminal/stream.zig @@ -406,7 +406,7 @@ pub const Action = union(Key) { /// Returns a type that can process a stream of tty control characters. /// This will call the `vt` function on type T with the following signature: /// -/// fn(comptime action: Action.Key, value: Action.Value(action)) !void +/// fn(comptime action: Action.Key, value: Action.Value(action)) void /// /// The handler type T can choose to react to whatever actions it cares /// about in its pursuit of implementing a terminal emulator or other @@ -468,11 +468,11 @@ pub fn Stream(comptime Handler: type) type { } /// Process a string of characters. - pub inline fn nextSlice(self: *Self, input: []const u8) !void { + pub inline fn nextSlice(self: *Self, input: []const u8) void { // Disable SIMD optimizations if build requests it or if our // manual debug mode is on. if (comptime debug or !build_options.simd) { - for (input) |c| try self.next(c); + for (input) |c| self.next(c); return; } @@ -485,13 +485,17 @@ pub fn Stream(comptime Handler: type) type { var i: usize = 0; while (true) { const len = @min(cp_buf.len, input.len - i); - try self.nextSliceCapped(input[i .. i + len], &cp_buf); + self.nextSliceCapped(input[i .. i + len], &cp_buf); i += len; if (i >= input.len) break; } } - inline fn nextSliceCapped(self: *Self, input: []const u8, cp_buf: []u32) !void { + inline fn nextSliceCapped( + self: *Self, + input: []const u8, + cp_buf: []u32, + ) void { assert(input.len <= cp_buf.len); var offset: usize = 0; @@ -500,7 +504,7 @@ pub fn Stream(comptime Handler: type) type { // a code sequence, we continue until it's not. while (self.utf8decoder.state != 0) { if (offset >= input.len) return; - try self.nextUtf8(input[offset]); + self.nextUtf8(input[offset]); offset += 1; } if (offset >= input.len) return; @@ -508,9 +512,9 @@ pub fn Stream(comptime Handler: type) type { // If we're not in the ground state then we process until // we are. This can happen if the last chunk of input put us // in the middle of a control sequence. - offset += try self.consumeUntilGround(input[offset..]); + offset += self.consumeUntilGround(input[offset..]); if (offset >= input.len) return; - offset += try self.consumeAllEscapes(input[offset..]); + offset += self.consumeAllEscapes(input[offset..]); // If we're in the ground state then we can use SIMD to process // input until we see an ESC (0x1B), since all other characters @@ -519,9 +523,9 @@ pub fn Stream(comptime Handler: type) type { const res = simd.vt.utf8DecodeUntilControlSeq(input[offset..], cp_buf); for (cp_buf[0..res.decoded]) |cp| { if (cp <= 0xF) { - try self.execute(@intCast(cp)); + self.execute(@intCast(cp)); } else { - try self.print(@intCast(cp)); + self.print(@intCast(cp)); } } // Consume the bytes we just processed. @@ -534,12 +538,12 @@ pub fn Stream(comptime Handler: type) type { // to the scalar parser. if (input[offset] != 0x1B) { const rem = input[offset..]; - for (rem) |c| try self.nextUtf8(c); + for (rem) |c| self.nextUtf8(c); return; } // Process control sequences until we run out. - offset += try self.consumeAllEscapes(input[offset..]); + offset += self.consumeAllEscapes(input[offset..]); } } @@ -548,13 +552,13 @@ pub fn Stream(comptime Handler: type) type { /// /// Expects input to start with 0x1B, use consumeUntilGround first /// if the stream may be in the middle of an escape sequence. - inline fn consumeAllEscapes(self: *Self, input: []const u8) !usize { + inline fn consumeAllEscapes(self: *Self, input: []const u8) usize { var offset: usize = 0; while (input[offset] == 0x1B) { self.parser.state = .escape; self.parser.clear(); offset += 1; - offset += try self.consumeUntilGround(input[offset..]); + offset += self.consumeUntilGround(input[offset..]); if (offset >= input.len) return input.len; } return offset; @@ -562,11 +566,11 @@ pub fn Stream(comptime Handler: type) type { /// Parses escape sequences until the parser reaches the ground state. /// Returns the number of bytes consumed from the provided input. - inline fn consumeUntilGround(self: *Self, input: []const u8) !usize { + inline fn consumeUntilGround(self: *Self, input: []const u8) usize { var offset: usize = 0; while (self.parser.state != .ground) { if (offset >= input.len) return input.len; - try self.nextNonUtf8(input[offset]); + self.nextNonUtf8(input[offset]); offset += 1; } return offset; @@ -575,27 +579,27 @@ pub fn Stream(comptime Handler: type) type { /// Like nextSlice but takes one byte and is necessarily a scalar /// operation that can't use SIMD. Prefer nextSlice if you can and /// try to get multiple bytes at once. - pub inline fn next(self: *Self, c: u8) !void { + pub inline fn next(self: *Self, c: u8) void { // The scalar path can be responsible for decoding UTF-8. if (self.parser.state == .ground) { - try self.nextUtf8(c); + self.nextUtf8(c); return; } - try self.nextNonUtf8(c); + self.nextNonUtf8(c); } /// Process the next byte and print as necessary. /// /// This assumes we're in the UTF-8 decoding state. If we may not /// be in the UTF-8 decoding state call nextSlice or next. - inline fn nextUtf8(self: *Self, c: u8) !void { + inline fn nextUtf8(self: *Self, c: u8) void { assert(self.parser.state == .ground); const res = self.utf8decoder.next(c); const consumed = res[1]; if (res[0]) |codepoint| { - try self.handleCodepoint(codepoint); + self.handleCodepoint(codepoint); } if (!consumed) { // We optimize for the scenario where the text being @@ -608,7 +612,7 @@ pub fn Stream(comptime Handler: type) type { // to not consume the byte twice in a row. assert(retry[1] == true); if (retry[0]) |codepoint| { - try self.handleCodepoint(codepoint); + self.handleCodepoint(codepoint); } } } @@ -617,7 +621,7 @@ pub fn Stream(comptime Handler: type) type { /// /// This function is abstracted this way to handle the case where /// the decoder emits a 0x1B after rejecting an ill-formed sequence. - inline fn handleCodepoint(self: *Self, c: u21) !void { + inline fn handleCodepoint(self: *Self, c: u21) void { // We need to increase the eval branch limit because a lot of // tests end up running almost completely at comptime due to // a chain of inline functions. @@ -626,7 +630,7 @@ pub fn Stream(comptime Handler: type) type { // C0 control if (c <= 0xF) { @branchHint(.unlikely); - try self.execute(@intCast(c)); + self.execute(@intCast(c)); return; } // ESC @@ -635,14 +639,14 @@ pub fn Stream(comptime Handler: type) type { self.parser.clear(); return; } - try self.print(@intCast(c)); + self.print(@intCast(c)); } /// Process the next character and call any callbacks if necessary. /// /// This assumes that we're not in the UTF-8 decoding state. If /// we may be in the UTF-8 decoding state call nextSlice or next. - fn nextNonUtf8(self: *Self, c: u8) !void { + fn nextNonUtf8(self: *Self, c: u8) void { assert(self.parser.state != .ground); // Fast path for CSI entry. @@ -659,7 +663,7 @@ pub fn Stream(comptime Handler: type) type { @branchHint(.likely); switch (c) { // A C0 escape (yes, this is valid): - 0x00...0x0F => try self.execute(c), + 0x00...0x0F => self.execute(c), // We ignore C0 escapes > 0xF since execute // doesn't have processing for them anyway: 0x10...0x17, 0x19, 0x1C...0x1F => {}, @@ -725,32 +729,32 @@ pub fn Stream(comptime Handler: type) type { } switch (action) { - .print => |p| try self.print(p), - .execute => |code| try self.execute(code), - .csi_dispatch => |csi_action| try self.csiDispatch(csi_action), - .esc_dispatch => |esc| try self.escDispatch(esc), - .osc_dispatch => |cmd| try self.oscDispatch(cmd), - .dcs_hook => |dcs| try self.handler.vt(.dcs_hook, dcs), - .dcs_put => |code| try self.handler.vt(.dcs_put, code), - .dcs_unhook => try self.handler.vt(.dcs_unhook, {}), - .apc_start => try self.handler.vt(.apc_start, {}), - .apc_put => |code| try self.handler.vt(.apc_put, code), - .apc_end => try self.handler.vt(.apc_end, {}), + .print => |p| self.print(p), + .execute => |code| self.execute(code), + .csi_dispatch => |csi_action| self.csiDispatch(csi_action), + .esc_dispatch => |esc| self.escDispatch(esc), + .osc_dispatch => |cmd| self.oscDispatch(cmd), + .dcs_hook => |dcs| self.handler.vt(.dcs_hook, dcs), + .dcs_put => |code| self.handler.vt(.dcs_put, code), + .dcs_unhook => self.handler.vt(.dcs_unhook, {}), + .apc_start => self.handler.vt(.apc_start, {}), + .apc_put => |code| self.handler.vt(.apc_put, code), + .apc_end => self.handler.vt(.apc_end, {}), } } } - pub inline fn print(self: *Self, c: u21) !void { - try self.handler.vt(.print, .{ .cp = c }); + inline fn print(self: *Self, c: u21) void { + self.handler.vt(.print, .{ .cp = c }); } - pub inline fn execute(self: *Self, c: u8) !void { + inline fn execute(self: *Self, c: u8) void { // If the character is > 0x7F, it's a C1 (8-bit) control, // which is strictly equivalent to `ESC` plus `c - 0x40`. if (c > 0x7F) { @branchHint(.unlikely); log.info("executing C1 0x{x} as ESC {c}", .{ c, c - 0x40 }); - try self.escDispatch(.{ + self.escDispatch(.{ .intermediates = &.{}, .final = c - 0x40, }); @@ -763,20 +767,20 @@ pub fn Stream(comptime Handler: type) type { // We ignore SOH/STX: https://github.com/microsoft/terminal/issues/10786 .NUL, .SOH, .STX => {}, - .ENQ => try self.handler.vt(.enquiry, {}), - .BEL => try self.handler.vt(.bell, {}), - .BS => try self.handler.vt(.backspace, {}), - .HT => try self.handler.vt(.horizontal_tab, 1), - .LF, .VT, .FF => try self.handler.vt(.linefeed, {}), - .CR => try self.handler.vt(.carriage_return, {}), - .SO => try self.handler.vt(.invoke_charset, .{ .bank = .GL, .charset = .G1, .locking = false }), - .SI => try self.handler.vt(.invoke_charset, .{ .bank = .GL, .charset = .G0, .locking = false }), + .ENQ => self.handler.vt(.enquiry, {}), + .BEL => self.handler.vt(.bell, {}), + .BS => self.handler.vt(.backspace, {}), + .HT => self.handler.vt(.horizontal_tab, 1), + .LF, .VT, .FF => self.handler.vt(.linefeed, {}), + .CR => self.handler.vt(.carriage_return, {}), + .SO => self.handler.vt(.invoke_charset, .{ .bank = .GL, .charset = .G1, .locking = false }), + .SI => self.handler.vt(.invoke_charset, .{ .bank = .GL, .charset = .G0, .locking = false }), else => log.warn("invalid C0 character, ignoring: 0x{x}", .{c}), } } - inline fn csiDispatch(self: *Self, input: Parser.Action.CSI) !void { + inline fn csiDispatch(self: *Self, input: Parser.Action.CSI) void { // The branch hints here are based on real world data // which indicates that the most common CSI finals are: // @@ -806,7 +810,7 @@ pub fn Stream(comptime Handler: type) type { 'A', 'k' => { @branchHint(.likely); switch (input.intermediates.len) { - 0 => try self.handler.vt(.cursor_up, .{ + 0 => self.handler.vt(.cursor_up, .{ .value = switch (input.params.len) { 0 => 1, 1 => input.params[0], @@ -827,7 +831,7 @@ pub fn Stream(comptime Handler: type) type { // CUD - Cursor Down 'B' => switch (input.intermediates.len) { - 0 => try self.handler.vt(.cursor_down, .{ + 0 => self.handler.vt(.cursor_down, .{ .value = switch (input.params.len) { 0 => 1, 1 => input.params[0], @@ -849,7 +853,7 @@ pub fn Stream(comptime Handler: type) type { 'C' => { @branchHint(.likely); switch (input.intermediates.len) { - 0 => try self.handler.vt(.cursor_right, .{ + 0 => self.handler.vt(.cursor_right, .{ .value = switch (input.params.len) { 0 => 1, 1 => input.params[0], @@ -870,7 +874,7 @@ pub fn Stream(comptime Handler: type) type { // CUB - Cursor Left 'D', 'j' => switch (input.intermediates.len) { - 0 => try self.handler.vt(.cursor_left, .{ + 0 => self.handler.vt(.cursor_left, .{ .value = switch (input.params.len) { 0 => 1, 1 => input.params[0], @@ -891,7 +895,7 @@ pub fn Stream(comptime Handler: type) type { // CNL - Cursor Next Line 'E' => switch (input.intermediates.len) { 0 => { - try self.handler.vt(.cursor_down, .{ + self.handler.vt(.cursor_down, .{ .value = switch (input.params.len) { 0 => 1, 1 => input.params[0], @@ -902,7 +906,7 @@ pub fn Stream(comptime Handler: type) type { }, }, }); - try self.handler.vt(.carriage_return, {}); + self.handler.vt(.carriage_return, {}); }, else => log.warn( @@ -914,7 +918,7 @@ pub fn Stream(comptime Handler: type) type { // CPL - Cursor Previous Line 'F' => switch (input.intermediates.len) { 0 => { - try self.handler.vt(.cursor_up, .{ + self.handler.vt(.cursor_up, .{ .value = switch (input.params.len) { 0 => 1, 1 => input.params[0], @@ -925,7 +929,7 @@ pub fn Stream(comptime Handler: type) type { }, }, }); - try self.handler.vt(.carriage_return, {}); + self.handler.vt(.carriage_return, {}); }, else => log.warn( @@ -937,7 +941,7 @@ pub fn Stream(comptime Handler: type) type { // HPA - Cursor Horizontal Position Absolute // TODO: test 'G', '`' => switch (input.intermediates.len) { - 0 => try self.handler.vt(.cursor_col, .{ + 0 => self.handler.vt(.cursor_col, .{ .value = switch (input.params.len) { 0 => 1, 1 => input.params[0], @@ -971,7 +975,7 @@ pub fn Stream(comptime Handler: type) type { return; }, }; - try self.handler.vt(.cursor_pos, pos); + self.handler.vt(.cursor_pos, pos); }, else => log.warn( @@ -983,7 +987,7 @@ pub fn Stream(comptime Handler: type) type { // CHT - Cursor Horizontal Tabulation 'I' => switch (input.intermediates.len) { - 0 => try self.handler.vt(.horizontal_tab, switch (input.params.len) { + 0 => self.handler.vt(.horizontal_tab, switch (input.params.len) { 0 => 1, 1 => input.params[0], else => { @@ -1023,11 +1027,11 @@ pub fn Stream(comptime Handler: type) type { }; switch (mode) { - .below => try self.handler.vt(.erase_display_below, protected), - .above => try self.handler.vt(.erase_display_above, protected), - .complete => try self.handler.vt(.erase_display_complete, protected), - .scrollback => try self.handler.vt(.erase_display_scrollback, protected), - .scroll_complete => try self.handler.vt(.erase_display_scroll_complete, protected), + .below => self.handler.vt(.erase_display_below, protected), + .above => self.handler.vt(.erase_display_above, protected), + .complete => self.handler.vt(.erase_display_complete, protected), + .scrollback => self.handler.vt(.erase_display_scrollback, protected), + .scroll_complete => self.handler.vt(.erase_display_scroll_complete, protected), } }, @@ -1059,10 +1063,10 @@ pub fn Stream(comptime Handler: type) type { }; switch (mode) { - .right => try self.handler.vt(.erase_line_right, protected), - .left => try self.handler.vt(.erase_line_left, protected), - .complete => try self.handler.vt(.erase_line_complete, protected), - .right_unless_pending_wrap => try self.handler.vt(.erase_line_right_unless_pending_wrap, protected), + .right => self.handler.vt(.erase_line_right, protected), + .left => self.handler.vt(.erase_line_left, protected), + .complete => self.handler.vt(.erase_line_complete, protected), + .right_unless_pending_wrap => self.handler.vt(.erase_line_right_unless_pending_wrap, protected), _ => { @branchHint(.unlikely); log.warn("invalid erase line mode: {}", .{mode}); @@ -1073,7 +1077,7 @@ pub fn Stream(comptime Handler: type) type { // IL - Insert Lines // TODO: test 'L' => switch (input.intermediates.len) { - 0 => try self.handler.vt(.insert_lines, switch (input.params.len) { + 0 => self.handler.vt(.insert_lines, switch (input.params.len) { 0 => 1, 1 => input.params[0], else => { @@ -1091,7 +1095,7 @@ pub fn Stream(comptime Handler: type) type { // DL - Delete Lines // TODO: test 'M' => switch (input.intermediates.len) { - 0 => try self.handler.vt(.delete_lines, switch (input.params.len) { + 0 => self.handler.vt(.delete_lines, switch (input.params.len) { 0 => 1, 1 => input.params[0], else => { @@ -1108,7 +1112,7 @@ pub fn Stream(comptime Handler: type) type { // Delete Character (DCH) 'P' => switch (input.intermediates.len) { - 0 => try self.handler.vt(.delete_chars, switch (input.params.len) { + 0 => self.handler.vt(.delete_chars, switch (input.params.len) { 0 => 1, 1 => input.params[0], else => { @@ -1126,7 +1130,7 @@ pub fn Stream(comptime Handler: type) type { // Scroll Up (SD) 'S' => switch (input.intermediates.len) { - 0 => try self.handler.vt(.scroll_up, switch (input.params.len) { + 0 => self.handler.vt(.scroll_up, switch (input.params.len) { 0 => 1, 1 => input.params[0], else => { @@ -1143,7 +1147,7 @@ pub fn Stream(comptime Handler: type) type { // Scroll Down (SD) 'T' => switch (input.intermediates.len) { - 0 => try self.handler.vt(.scroll_down, switch (input.params.len) { + 0 => self.handler.vt(.scroll_down, switch (input.params.len) { 0 => 1, 1 => input.params[0], else => { @@ -1164,7 +1168,7 @@ pub fn Stream(comptime Handler: type) type { if (input.params.len == 0 or (input.params.len == 1 and input.params[0] == 0)) { - try self.handler.vt(.tab_set, {}); + self.handler.vt(.tab_set, {}); return; } @@ -1174,9 +1178,9 @@ pub fn Stream(comptime Handler: type) type { 1 => switch (input.params[0]) { 0 => unreachable, - 2 => try self.handler.vt(.tab_clear_current, {}), + 2 => self.handler.vt(.tab_clear_current, {}), - 5 => try self.handler.vt(.tab_clear_all, {}), + 5 => self.handler.vt(.tab_clear_all, {}), else => {}, }, @@ -1192,7 +1196,7 @@ pub fn Stream(comptime Handler: type) type { input.params.len == 1 and input.params[0] == 5) { - try self.handler.vt(.tab_reset, {}); + self.handler.vt(.tab_reset, {}); } else log.warn("invalid cursor tabulation control: {f}", .{input}), else => log.warn( @@ -1205,7 +1209,7 @@ pub fn Stream(comptime Handler: type) type { 'X' => { @branchHint(.likely); switch (input.intermediates.len) { - 0 => try self.handler.vt(.erase_chars, switch (input.params.len) { + 0 => self.handler.vt(.erase_chars, switch (input.params.len) { 0 => 1, 1 => input.params[0], else => { @@ -1224,7 +1228,7 @@ pub fn Stream(comptime Handler: type) type { // CHT - Cursor Horizontal Tabulation Back 'Z' => switch (input.intermediates.len) { - 0 => try self.handler.vt(.horizontal_tab_back, switch (input.params.len) { + 0 => self.handler.vt(.horizontal_tab_back, switch (input.params.len) { 0 => 1, 1 => input.params[0], else => { @@ -1241,7 +1245,7 @@ pub fn Stream(comptime Handler: type) type { // HPR - Cursor Horizontal Position Relative 'a' => switch (input.intermediates.len) { - 0 => try self.handler.vt(.cursor_col_relative, .{ + 0 => self.handler.vt(.cursor_col_relative, .{ .value = switch (input.params.len) { 0 => 1, 1 => input.params[0], @@ -1260,7 +1264,7 @@ pub fn Stream(comptime Handler: type) type { // Repeat Previous Char (REP) 'b' => switch (input.intermediates.len) { - 0 => try self.handler.vt(.print_repeat, switch (input.params.len) { + 0 => self.handler.vt(.print_repeat, switch (input.params.len) { 0 => 1, 1 => input.params[0], else => { @@ -1288,7 +1292,7 @@ pub fn Stream(comptime Handler: type) type { }; if (req) |r| { - try self.handler.vt(.device_attributes, r); + self.handler.vt(.device_attributes, r); } else { log.warn("invalid device attributes command: {f}", .{input}); return; @@ -1297,7 +1301,7 @@ pub fn Stream(comptime Handler: type) type { // VPA - Cursor Vertical Position Absolute 'd' => switch (input.intermediates.len) { - 0 => try self.handler.vt(.cursor_row, .{ + 0 => self.handler.vt(.cursor_row, .{ .value = switch (input.params.len) { 0 => 1, 1 => input.params[0], @@ -1316,7 +1320,7 @@ pub fn Stream(comptime Handler: type) type { // VPR - Cursor Vertical Position Relative 'e' => switch (input.intermediates.len) { - 0 => try self.handler.vt(.cursor_row_relative, .{ + 0 => self.handler.vt(.cursor_row_relative, .{ .value = switch (input.params.len) { 0 => 1, 1 => input.params[0], @@ -1348,8 +1352,8 @@ pub fn Stream(comptime Handler: type) type { }, }; switch (mode) { - .current => try self.handler.vt(.tab_clear_current, {}), - .all => try self.handler.vt(.tab_clear_all, {}), + .current => self.handler.vt(.tab_clear_current, {}), + .all => self.handler.vt(.tab_clear_all, {}), _ => log.warn("unknown tab clear mode: {}", .{mode}), } }, @@ -1374,7 +1378,7 @@ pub fn Stream(comptime Handler: type) type { for (input.params) |mode_int| { if (modes.modeFromInt(mode_int, ansi_mode)) |mode| { - try self.handler.vt(.set_mode, .{ .mode = mode }); + self.handler.vt(.set_mode, .{ .mode = mode }); } else { log.warn("unimplemented mode: {}", .{mode_int}); } @@ -1395,7 +1399,7 @@ pub fn Stream(comptime Handler: type) type { for (input.params) |mode_int| { if (modes.modeFromInt(mode_int, ansi_mode)) |mode| { - try self.handler.vt(.reset_mode, .{ .mode = mode }); + self.handler.vt(.reset_mode, .{ .mode = mode }); } else { log.warn("unimplemented mode: {}", .{mode_int}); } @@ -1416,7 +1420,7 @@ pub fn Stream(comptime Handler: type) type { }; while (p.next()) |attr| { // log.info("SGR attribute: {}", .{attr}); - try self.handler.vt(.set_attribute, attr); + self.handler.vt(.set_attribute, attr); } }, @@ -1424,7 +1428,7 @@ pub fn Stream(comptime Handler: type) type { '>' => blk: { if (input.params.len == 0) { // Reset - try self.handler.vt(.modify_key_format, .legacy); + self.handler.vt(.modify_key_format, .legacy); break :blk; } @@ -1463,7 +1467,7 @@ pub fn Stream(comptime Handler: type) type { } } - try self.handler.vt(.modify_key_format, format); + self.handler.vt(.modify_key_format, format); }, else => log.warn( @@ -1510,7 +1514,7 @@ pub fn Stream(comptime Handler: type) type { return; }; - try self.handler.vt(.device_status, .{ .request = req }); + self.handler.vt(.device_status, .{ .request = req }); return; } @@ -1524,7 +1528,7 @@ pub fn Stream(comptime Handler: type) type { // control what exactly is being disabled. However, we // only support reverting back to modify other keys in // numeric except format. - try self.handler.vt(.modify_key_format, .other_keys_numeric_except); + self.handler.vt(.modify_key_format, .other_keys_numeric_except); }, else => log.warn( @@ -1566,9 +1570,9 @@ pub fn Stream(comptime Handler: type) type { const mode_raw = input.params[0]; const mode = modes.modeFromInt(mode_raw, ansi_mode); if (mode) |m| { - try self.handler.vt(.request_mode, .{ .mode = m }); + self.handler.vt(.request_mode, .{ .mode = m }); } else { - try self.handler.vt(.request_mode_unknown, .{ + self.handler.vt(.request_mode_unknown, .{ .mode = mode_raw, .ansi = ansi_mode, }); @@ -1606,7 +1610,7 @@ pub fn Stream(comptime Handler: type) type { return; }, }; - try self.handler.vt(.cursor_style, style); + self.handler.vt(.cursor_style, style); }, // DECSCA @@ -1627,14 +1631,14 @@ pub fn Stream(comptime Handler: type) type { }; switch (mode) { - .off => try self.handler.vt(.protected_mode_off, {}), - .iso => try self.handler.vt(.protected_mode_iso, {}), - .dec => try self.handler.vt(.protected_mode_dec, {}), + .off => self.handler.vt(.protected_mode_off, {}), + .iso => self.handler.vt(.protected_mode_iso, {}), + .dec => self.handler.vt(.protected_mode_dec, {}), } }, // XTVERSION - '>' => try self.handler.vt(.xtversion, {}), + '>' => self.handler.vt(.xtversion, {}), else => { log.warn( "ignoring unimplemented CSI q with intermediates: {s}", @@ -1654,9 +1658,9 @@ pub fn Stream(comptime Handler: type) type { switch (input.intermediates.len) { // DECSTBM - Set Top and Bottom Margins 0 => switch (input.params.len) { - 0 => try self.handler.vt(.top_and_bottom_margin, .{ .top_left = 0, .bottom_right = 0 }), - 1 => try self.handler.vt(.top_and_bottom_margin, .{ .top_left = input.params[0], .bottom_right = 0 }), - 2 => try self.handler.vt(.top_and_bottom_margin, .{ .top_left = input.params[0], .bottom_right = input.params[1] }), + 0 => self.handler.vt(.top_and_bottom_margin, .{ .top_left = 0, .bottom_right = 0 }), + 1 => self.handler.vt(.top_and_bottom_margin, .{ .top_left = input.params[0], .bottom_right = 0 }), + 2 => self.handler.vt(.top_and_bottom_margin, .{ .top_left = input.params[0], .bottom_right = input.params[1] }), else => { @branchHint(.unlikely); log.warn("invalid DECSTBM command: {f}", .{input}); @@ -1668,7 +1672,7 @@ pub fn Stream(comptime Handler: type) type { '?' => { for (input.params) |mode_int| { if (modes.modeFromInt(mode_int, false)) |mode| { - try self.handler.vt(.restore_mode, .{ .mode = mode }); + self.handler.vt(.restore_mode, .{ .mode = mode }); } else { log.warn( "unimplemented restore mode: {}", @@ -1698,9 +1702,9 @@ pub fn Stream(comptime Handler: type) type { // to our handler to do the proper logic. If mode 69 // is set, then we should invoke DECSLRM, otherwise // we should invoke SC. - 0 => try self.handler.vt(.left_and_right_margin_ambiguous, {}), - 1 => try self.handler.vt(.left_and_right_margin, .{ .top_left = input.params[0], .bottom_right = 0 }), - 2 => try self.handler.vt(.left_and_right_margin, .{ .top_left = input.params[0], .bottom_right = input.params[1] }), + 0 => self.handler.vt(.left_and_right_margin_ambiguous, {}), + 1 => self.handler.vt(.left_and_right_margin, .{ .top_left = input.params[0], .bottom_right = 0 }), + 2 => self.handler.vt(.left_and_right_margin, .{ .top_left = input.params[0], .bottom_right = input.params[1] }), else => log.warn("invalid DECSLRM command: {f}", .{input}), }, @@ -1708,7 +1712,7 @@ pub fn Stream(comptime Handler: type) type { '?' => { for (input.params) |mode_int| { if (modes.modeFromInt(mode_int, false)) |mode| { - try self.handler.vt(.save_mode, .{ .mode = mode }); + self.handler.vt(.save_mode, .{ .mode = mode }); } else { log.warn( "unimplemented save mode: {}", @@ -1736,7 +1740,7 @@ pub fn Stream(comptime Handler: type) type { }, }; - try self.handler.vt(.mouse_shift_capture, capture); + self.handler.vt(.mouse_shift_capture, capture); }, else => log.warn( @@ -1758,28 +1762,28 @@ pub fn Stream(comptime Handler: type) type { switch (input.params[0]) { 14 => if (input.params.len == 1) { // report the text area size in pixels - try self.handler.vt(.size_report, .csi_14_t); + self.handler.vt(.size_report, .csi_14_t); } else log.warn( "ignoring CSI 14 t with extra parameters: {f}", .{input}, ), 16 => if (input.params.len == 1) { // report cell size in pixels - try self.handler.vt(.size_report, .csi_16_t); + self.handler.vt(.size_report, .csi_16_t); } else log.warn( "ignoring CSI 16 t with extra parameters: {f}", .{input}, ), 18 => if (input.params.len == 1) { // report screen size in characters - try self.handler.vt(.size_report, .csi_18_t); + self.handler.vt(.size_report, .csi_18_t); } else log.warn( "ignoring CSI 18 t with extra parameters: {f}", .{input}, ), 21 => if (input.params.len == 1) { // report window title - try self.handler.vt(.size_report, .csi_21_t); + self.handler.vt(.size_report, .csi_21_t); } else log.warn( "ignoring CSI 21 t with extra parameters: {f}", .{input}, @@ -1796,8 +1800,8 @@ pub fn Stream(comptime Handler: type) type { else 0; switch (number) { - 22 => try self.handler.vt(.title_push, index), - 23 => try self.handler.vt(.title_pop, index), + 22 => self.handler.vt(.title_push, index), + 23 => self.handler.vt(.title_pop, index), else => @compileError("unreachable"), } } else log.warn( @@ -1821,11 +1825,11 @@ pub fn Stream(comptime Handler: type) type { }, 'u' => switch (input.intermediates.len) { - 0 => try self.handler.vt(.restore_cursor, {}), + 0 => self.handler.vt(.restore_cursor, {}), // Kitty keyboard protocol 1 => switch (input.intermediates[0]) { - '?' => try self.handler.vt(.kitty_keyboard_query, {}), + '?' => self.handler.vt(.kitty_keyboard_query, {}), '>' => push: { const flags: u5 = if (input.params.len == 1) @@ -1836,7 +1840,7 @@ pub fn Stream(comptime Handler: type) type { else 0; - try self.handler.vt(.kitty_keyboard_push, .{ .flags = @as(kitty.KeyFlags, @bitCast(flags)) }); + self.handler.vt(.kitty_keyboard_push, .{ .flags = @as(kitty.KeyFlags, @bitCast(flags)) }); }, '<' => { @@ -1845,7 +1849,7 @@ pub fn Stream(comptime Handler: type) type { else 1; - try self.handler.vt(.kitty_keyboard_pop, number); + self.handler.vt(.kitty_keyboard_pop, number); }, '=' => set: { @@ -1874,9 +1878,9 @@ pub fn Stream(comptime Handler: type) type { const kitty_flags: streampkg.Action.KittyKeyboardFlags = .{ .flags = @as(kitty.KeyFlags, @bitCast(flags)) }; switch (action_tag) { - .kitty_keyboard_set => try self.handler.vt(.kitty_keyboard_set, kitty_flags), - .kitty_keyboard_set_or => try self.handler.vt(.kitty_keyboard_set_or, kitty_flags), - .kitty_keyboard_set_not => try self.handler.vt(.kitty_keyboard_set_not, kitty_flags), + .kitty_keyboard_set => self.handler.vt(.kitty_keyboard_set, kitty_flags), + .kitty_keyboard_set_or => self.handler.vt(.kitty_keyboard_set_or, kitty_flags), + .kitty_keyboard_set_not => self.handler.vt(.kitty_keyboard_set_not, kitty_flags), else => unreachable, } }, @@ -1895,7 +1899,7 @@ pub fn Stream(comptime Handler: type) type { // ICH - Insert Blanks '@' => switch (input.intermediates.len) { - 0 => try self.handler.vt(.insert_blanks, switch (input.params.len) { + 0 => self.handler.vt(.insert_blanks, switch (input.params.len) { 0 => 1, 1 => @max(1, input.params[0]), else => { @@ -1932,14 +1936,14 @@ pub fn Stream(comptime Handler: type) type { }, }; - try self.handler.vt(.active_status_display, display); + self.handler.vt(.active_status_display, display); }, else => log.warn("unimplemented CSI action: {f}", .{input}), } } - inline fn oscDispatch(self: *Self, cmd: osc.Command) !void { + inline fn oscDispatch(self: *Self, cmd: osc.Command) void { // The branch hints here are based on real world data // which indicates that the most common OSC commands are: // @@ -1965,7 +1969,7 @@ pub fn Stream(comptime Handler: type) type { switch (cmd) { .semantic_prompt => |sp| { @branchHint(.likely); - try self.handler.vt(.semantic_prompt, sp); + self.handler.vt(.semantic_prompt, sp); }, .change_window_title => |title| { @@ -1976,7 +1980,7 @@ pub fn Stream(comptime Handler: type) type { return; } - try self.handler.vt(.window_title, .{ .title = title }); + self.handler.vt(.window_title, .{ .title = title }); }, .change_window_icon => |icon| { @@ -1985,7 +1989,7 @@ pub fn Stream(comptime Handler: type) type { }, .clipboard_contents => |clip| { - try self.handler.vt(.clipboard_contents, .{ + self.handler.vt(.clipboard_contents, .{ .kind = clip.kind, .data = clip.data, }); @@ -1993,7 +1997,7 @@ pub fn Stream(comptime Handler: type) type { .report_pwd => |v| { @branchHint(.likely); - try self.handler.vt(.report_pwd, .{ .url = v.value }); + self.handler.vt(.report_pwd, .{ .url = v.value }); }, .mouse_shape => |v| { @@ -2003,12 +2007,12 @@ pub fn Stream(comptime Handler: type) type { return; }; - try self.handler.vt(.mouse_shape, shape); + self.handler.vt(.mouse_shape, shape); }, .color_operation => |v| { @branchHint(.likely); - try self.handler.vt(.color_operation, .{ + self.handler.vt(.color_operation, .{ .op = v.op, .requests = v.requests, .terminator = v.terminator, @@ -2016,11 +2020,11 @@ pub fn Stream(comptime Handler: type) type { }, .kitty_color_protocol => |v| { - try self.handler.vt(.kitty_color_report, v); + self.handler.vt(.kitty_color_report, v); }, .show_desktop_notification => |v| { - try self.handler.vt(.show_desktop_notification, .{ + self.handler.vt(.show_desktop_notification, .{ .title = v.title, .body = v.body, }); @@ -2028,7 +2032,7 @@ pub fn Stream(comptime Handler: type) type { .hyperlink_start => |v| { @branchHint(.likely); - try self.handler.vt(.start_hyperlink, .{ + self.handler.vt(.start_hyperlink, .{ .uri = v.uri, .id = v.id, }); @@ -2036,11 +2040,11 @@ pub fn Stream(comptime Handler: type) type { .hyperlink_end => { @branchHint(.likely); - try self.handler.vt(.end_hyperlink, {}); + self.handler.vt(.end_hyperlink, {}); }, .conemu_progress_report => |v| { - try self.handler.vt(.progress_report, v); + self.handler.vt(.progress_report, v); }, .conemu_sleep, @@ -2072,7 +2076,7 @@ pub fn Stream(comptime Handler: type) type { self: *Self, intermediates: []const u8, set: charsets.Charset, - ) !void { + ) void { if (intermediates.len != 1) { log.warn("invalid charset intermediate: {any}", .{intermediates}); return; @@ -2092,7 +2096,7 @@ pub fn Stream(comptime Handler: type) type { }, }; - try self.handler.vt(.configure_charset, .{ + self.handler.vt(.configure_charset, .{ .slot = slot, .charset = set, }); @@ -2101,7 +2105,7 @@ pub fn Stream(comptime Handler: type) type { inline fn escDispatch( self: *Self, action: Parser.Action.ESC, - ) !void { + ) void { // The branch hints here are based on real world data // which indicates that the most common ESC finals are: // @@ -2129,19 +2133,19 @@ pub fn Stream(comptime Handler: type) type { // Charsets 'B' => { @branchHint(.likely); - try self.configureCharset(action.intermediates, .ascii); + self.configureCharset(action.intermediates, .ascii); }, - 'A' => try self.configureCharset(action.intermediates, .british), + 'A' => self.configureCharset(action.intermediates, .british), '0' => { @branchHint(.likely); - try self.configureCharset(action.intermediates, .dec_special); + self.configureCharset(action.intermediates, .dec_special); }, // DECSC - Save Cursor '7' => { @branchHint(.likely); switch (action.intermediates.len) { - 0 => try self.handler.vt(.save_cursor, {}), + 0 => self.handler.vt(.save_cursor, {}), else => { @branchHint(.unlikely); log.warn("invalid command: {f}", .{action}); @@ -2155,14 +2159,14 @@ pub fn Stream(comptime Handler: type) type { switch (action.intermediates.len) { // DECRC - Restore Cursor 0 => { - try self.handler.vt(.restore_cursor, {}); + self.handler.vt(.restore_cursor, {}); break :blk {}; }, 1 => switch (action.intermediates[0]) { // DECALN - Fill Screen with E '#' => { - try self.handler.vt(.decaln, {}); + self.handler.vt(.decaln, {}); break :blk {}; }, @@ -2177,7 +2181,7 @@ pub fn Stream(comptime Handler: type) type { // IND - Index 'D' => switch (action.intermediates.len) { - 0 => try self.handler.vt(.index, {}), + 0 => self.handler.vt(.index, {}), else => { @branchHint(.unlikely); log.warn("invalid index command: {f}", .{action}); @@ -2187,7 +2191,7 @@ pub fn Stream(comptime Handler: type) type { // NEL - Next Line 'E' => switch (action.intermediates.len) { - 0 => try self.handler.vt(.next_line, {}), + 0 => self.handler.vt(.next_line, {}), else => { @branchHint(.unlikely); log.warn("invalid next line command: {f}", .{action}); @@ -2197,7 +2201,7 @@ pub fn Stream(comptime Handler: type) type { // HTS - Horizontal Tab Set 'H' => switch (action.intermediates.len) { - 0 => try self.handler.vt(.tab_set, {}), + 0 => self.handler.vt(.tab_set, {}), else => { @branchHint(.unlikely); log.warn("invalid tab set command: {f}", .{action}); @@ -2209,7 +2213,7 @@ pub fn Stream(comptime Handler: type) type { 'M' => { @branchHint(.likely); switch (action.intermediates.len) { - 0 => try self.handler.vt(.reverse_index, {}), + 0 => self.handler.vt(.reverse_index, {}), else => { @branchHint(.unlikely); log.warn("invalid reverse index command: {f}", .{action}); @@ -2220,7 +2224,7 @@ pub fn Stream(comptime Handler: type) type { // SS2 - Single Shift 2 'N' => switch (action.intermediates.len) { - 0 => try self.handler.vt(.invoke_charset, .{ + 0 => self.handler.vt(.invoke_charset, .{ .bank = .GL, .charset = .G2, .locking = true, @@ -2234,7 +2238,7 @@ pub fn Stream(comptime Handler: type) type { // SS3 - Single Shift 3 'O' => switch (action.intermediates.len) { - 0 => try self.handler.vt(.invoke_charset, .{ + 0 => self.handler.vt(.invoke_charset, .{ .bank = .GL, .charset = .G3, .locking = true, @@ -2248,24 +2252,24 @@ pub fn Stream(comptime Handler: type) type { // SPA - Start of Guarded Area 'V' => switch (action.intermediates.len) { - 0 => try self.handler.vt(.protected_mode_iso, {}), + 0 => self.handler.vt(.protected_mode_iso, {}), else => log.warn("unimplemented ESC callback: {f}", .{action}), }, // EPA - End of Guarded Area 'W' => switch (action.intermediates.len) { - 0 => try self.handler.vt(.protected_mode_off, {}), + 0 => self.handler.vt(.protected_mode_off, {}), else => log.warn("unimplemented ESC callback: {f}", .{action}), }, // DECID 'Z' => if (action.intermediates.len == 0) { - try self.handler.vt(.device_attributes, .primary); + self.handler.vt(.device_attributes, .primary); } else log.warn("unimplemented ESC callback: {f}", .{action}), // RIS - Full Reset 'c' => switch (action.intermediates.len) { - 0 => try self.handler.vt(.full_reset, {}), + 0 => self.handler.vt(.full_reset, {}), else => { log.warn("invalid full reset command: {f}", .{action}); return; @@ -2274,7 +2278,7 @@ pub fn Stream(comptime Handler: type) type { // LS2 - Locking Shift 2 'n' => switch (action.intermediates.len) { - 0 => try self.handler.vt(.invoke_charset, .{ + 0 => self.handler.vt(.invoke_charset, .{ .bank = .GL, .charset = .G2, .locking = false, @@ -2288,7 +2292,7 @@ pub fn Stream(comptime Handler: type) type { // LS3 - Locking Shift 3 'o' => switch (action.intermediates.len) { - 0 => try self.handler.vt(.invoke_charset, .{ + 0 => self.handler.vt(.invoke_charset, .{ .bank = .GL, .charset = .G3, .locking = false, @@ -2302,7 +2306,7 @@ pub fn Stream(comptime Handler: type) type { // LS1R - Locking Shift 1 Right '~' => switch (action.intermediates.len) { - 0 => try self.handler.vt(.invoke_charset, .{ + 0 => self.handler.vt(.invoke_charset, .{ .bank = .GR, .charset = .G1, .locking = false, @@ -2316,7 +2320,7 @@ pub fn Stream(comptime Handler: type) type { // LS2R - Locking Shift 2 Right '}' => switch (action.intermediates.len) { - 0 => try self.handler.vt(.invoke_charset, .{ + 0 => self.handler.vt(.invoke_charset, .{ .bank = .GR, .charset = .G2, .locking = false, @@ -2330,7 +2334,7 @@ pub fn Stream(comptime Handler: type) type { // LS3R - Locking Shift 3 Right '|' => switch (action.intermediates.len) { - 0 => try self.handler.vt(.invoke_charset, .{ + 0 => self.handler.vt(.invoke_charset, .{ .bank = .GR, .charset = .G3, .locking = false, @@ -2346,7 +2350,7 @@ pub fn Stream(comptime Handler: type) type { '=' => { @branchHint(.likely); switch (action.intermediates.len) { - 0 => try self.handler.vt(.set_mode, .{ .mode = .keypad_keys }), + 0 => self.handler.vt(.set_mode, .{ .mode = .keypad_keys }), else => log.warn("unimplemented setMode: {f}", .{action}), } }, @@ -2355,7 +2359,7 @@ pub fn Stream(comptime Handler: type) type { '>' => { @branchHint(.likely); switch (action.intermediates.len) { - 0 => try self.handler.vt(.reset_mode, .{ .mode = .keypad_keys }), + 0 => self.handler.vt(.reset_mode, .{ .mode = .keypad_keys }), else => log.warn("unimplemented setMode: {f}", .{action}), } }, @@ -2386,7 +2390,7 @@ test "stream: print" { self: *@This(), comptime action: Action.Tag, value: Action.Value(action), - ) !void { + ) void { switch (action) { .print => self.c = value.cp, else => {}, @@ -2395,7 +2399,7 @@ test "stream: print" { }; var s: Stream(H) = .init(.{}); - try s.next('x'); + s.next('x'); try testing.expectEqual(@as(u21, 'x'), s.handler.c.?); } @@ -2407,7 +2411,7 @@ test "simd: print invalid utf-8" { self: *@This(), comptime action: Action.Tag, value: Action.Value(action), - ) !void { + ) void { switch (action) { .print => self.c = value.cp, else => {}, @@ -2416,7 +2420,7 @@ test "simd: print invalid utf-8" { }; var s: Stream(H) = .init(.{}); - try s.nextSlice(&.{0xFF}); + s.nextSlice(&.{0xFF}); try testing.expectEqual(@as(u21, 0xFFFD), s.handler.c.?); } @@ -2428,7 +2432,7 @@ test "simd: complete incomplete utf-8" { self: *@This(), comptime action: Action.Tag, value: Action.Value(action), - ) !void { + ) void { switch (action) { .print => self.c = value.cp, else => {}, @@ -2437,11 +2441,11 @@ test "simd: complete incomplete utf-8" { }; var s: Stream(H) = .init(.{}); - try s.nextSlice(&.{0xE0}); // 3 byte + s.nextSlice(&.{0xE0}); // 3 byte try testing.expect(s.handler.c == null); - try s.nextSlice(&.{0xA0}); // still incomplete + s.nextSlice(&.{0xA0}); // still incomplete try testing.expect(s.handler.c == null); - try s.nextSlice(&.{0x80}); + s.nextSlice(&.{0x80}); try testing.expectEqual(@as(u21, 0x800), s.handler.c.?); } @@ -2453,7 +2457,7 @@ test "stream: cursor right (CUF)" { self: *@This(), comptime action: Action.Tag, value: Action.Value(action), - ) !void { + ) void { switch (action) { .cursor_right => self.amount = value.value, else => {}, @@ -2462,18 +2466,18 @@ test "stream: cursor right (CUF)" { }; var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1B[C"); + s.nextSlice("\x1B[C"); try testing.expectEqual(@as(u16, 1), s.handler.amount); - try s.nextSlice("\x1B[5C"); + s.nextSlice("\x1B[5C"); try testing.expectEqual(@as(u16, 5), s.handler.amount); s.handler.amount = 0; - try s.nextSlice("\x1B[5;4C"); + s.nextSlice("\x1B[5;4C"); try testing.expectEqual(@as(u16, 0), s.handler.amount); s.handler.amount = 0; - try s.nextSlice("\x1b[?3C"); + s.nextSlice("\x1b[?3C"); try testing.expectEqual(@as(u16, 0), s.handler.amount); } @@ -2485,7 +2489,7 @@ test "stream: dec set mode (SM) and reset mode (RM)" { self: *@This(), comptime action: Action.Tag, value: Action.Value(action), - ) !void { + ) void { switch (action) { .set_mode => self.mode = value.mode, .reset_mode => self.mode = @as(modes.Mode, @enumFromInt(1)), @@ -2495,14 +2499,14 @@ test "stream: dec set mode (SM) and reset mode (RM)" { }; var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1B[?6h"); + s.nextSlice("\x1B[?6h"); try testing.expectEqual(@as(modes.Mode, .origin), s.handler.mode); - try s.nextSlice("\x1B[?6l"); + s.nextSlice("\x1B[?6l"); try testing.expectEqual(@as(modes.Mode, @enumFromInt(1)), s.handler.mode); s.handler.mode = @as(modes.Mode, @enumFromInt(1)); - try s.nextSlice("\x1B[6 h"); + s.nextSlice("\x1B[6 h"); try testing.expectEqual(@as(modes.Mode, @enumFromInt(1)), s.handler.mode); } @@ -2514,7 +2518,7 @@ test "stream: ansi set mode (SM) and reset mode (RM)" { self: *@This(), comptime action: Action.Tag, value: Action.Value(action), - ) !void { + ) void { switch (action) { .set_mode => self.mode = value.mode, .reset_mode => self.mode = null, @@ -2524,14 +2528,14 @@ test "stream: ansi set mode (SM) and reset mode (RM)" { }; var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1B[4h"); + s.nextSlice("\x1B[4h"); try testing.expectEqual(@as(modes.Mode, .insert), s.handler.mode.?); - try s.nextSlice("\x1B[4l"); + s.nextSlice("\x1B[4l"); try testing.expect(s.handler.mode == null); s.handler.mode = null; - try s.nextSlice("\x1B[>5h"); + s.nextSlice("\x1B[>5h"); try testing.expect(s.handler.mode == null); } @@ -2548,17 +2552,17 @@ test "stream: ansi set mode (SM) and reset mode (RM) with unknown value" { self: *@This(), comptime action: Action.Tag, value: Action.Value(action), - ) !void { + ) void { _ = self; _ = value; } }; var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1B[6h"); + s.nextSlice("\x1B[6h"); try testing.expect(s.handler.mode == null); - try s.nextSlice("\x1B[6l"); + s.nextSlice("\x1B[6l"); try testing.expect(s.handler.mode == null); } @@ -2571,7 +2575,7 @@ test "stream: restore mode" { self: *Self, comptime action: Stream(Self).Action.Tag, value: Stream(Self).Action.Value(action), - ) !void { + ) void { _ = value; switch (action) { .top_and_bottom_margin => self.called = true, @@ -2581,7 +2585,7 @@ test "stream: restore mode" { }; var s: Stream(H) = .init(.{}); - for ("\x1B[?42r") |c| try s.next(c); + for ("\x1B[?42r") |c| s.next(c); try testing.expect(!s.handler.called); } @@ -2594,7 +2598,7 @@ test "stream: pop kitty keyboard with no params defaults to 1" { self: *Self, comptime action: streampkg.Action.Tag, value: streampkg.Action.Value(action), - ) !void { + ) void { switch (action) { .kitty_keyboard_pop => self.n = value, else => {}, @@ -2603,7 +2607,7 @@ test "stream: pop kitty keyboard with no params defaults to 1" { }; var s: Stream(H) = .init(.{}); - for ("\x1B[ self.v = .off, @@ -2629,19 +2633,19 @@ test "stream: DECSCA" { var s: Stream(H) = .init(.{}); { - for ("\x1B[\"q") |c| try s.next(c); + for ("\x1B[\"q") |c| s.next(c); try testing.expectEqual(ansi.ProtectedMode.off, s.handler.v.?); } { - for ("\x1B[0\"q") |c| try s.next(c); + for ("\x1B[0\"q") |c| s.next(c); try testing.expectEqual(ansi.ProtectedMode.off, s.handler.v.?); } { - for ("\x1B[2\"q") |c| try s.next(c); + for ("\x1B[2\"q") |c| s.next(c); try testing.expectEqual(ansi.ProtectedMode.off, s.handler.v.?); } { - for ("\x1B[1\"q") |c| try s.next(c); + for ("\x1B[1\"q") |c| s.next(c); try testing.expectEqual(ansi.ProtectedMode.dec, s.handler.v.?); } } @@ -2656,7 +2660,7 @@ test "stream: DECED, DECSED" { self: *Self, comptime action: anytype, value: anytype, - ) !void { + ) void { switch (action) { .erase_display_below => { self.mode = .below; @@ -2685,59 +2689,59 @@ test "stream: DECED, DECSED" { var s: Stream(H) = .init(.{}); { - for ("\x1B[?J") |c| try s.next(c); + for ("\x1B[?J") |c| s.next(c); try testing.expectEqual(csi.EraseDisplay.below, s.handler.mode.?); try testing.expect(s.handler.protected.?); } { - for ("\x1B[?0J") |c| try s.next(c); + for ("\x1B[?0J") |c| s.next(c); try testing.expectEqual(csi.EraseDisplay.below, s.handler.mode.?); try testing.expect(s.handler.protected.?); } { - for ("\x1B[?1J") |c| try s.next(c); + for ("\x1B[?1J") |c| s.next(c); try testing.expectEqual(csi.EraseDisplay.above, s.handler.mode.?); try testing.expect(s.handler.protected.?); } { - for ("\x1B[?2J") |c| try s.next(c); + for ("\x1B[?2J") |c| s.next(c); try testing.expectEqual(csi.EraseDisplay.complete, s.handler.mode.?); try testing.expect(s.handler.protected.?); } { - for ("\x1B[?3J") |c| try s.next(c); + for ("\x1B[?3J") |c| s.next(c); try testing.expectEqual(csi.EraseDisplay.scrollback, s.handler.mode.?); try testing.expect(s.handler.protected.?); } { - for ("\x1B[J") |c| try s.next(c); + for ("\x1B[J") |c| s.next(c); try testing.expectEqual(csi.EraseDisplay.below, s.handler.mode.?); try testing.expect(!s.handler.protected.?); } { - for ("\x1B[0J") |c| try s.next(c); + for ("\x1B[0J") |c| s.next(c); try testing.expectEqual(csi.EraseDisplay.below, s.handler.mode.?); try testing.expect(!s.handler.protected.?); } { - for ("\x1B[1J") |c| try s.next(c); + for ("\x1B[1J") |c| s.next(c); try testing.expectEqual(csi.EraseDisplay.above, s.handler.mode.?); try testing.expect(!s.handler.protected.?); } { - for ("\x1B[2J") |c| try s.next(c); + for ("\x1B[2J") |c| s.next(c); try testing.expectEqual(csi.EraseDisplay.complete, s.handler.mode.?); try testing.expect(!s.handler.protected.?); } { - for ("\x1B[3J") |c| try s.next(c); + for ("\x1B[3J") |c| s.next(c); try testing.expectEqual(csi.EraseDisplay.scrollback, s.handler.mode.?); try testing.expect(!s.handler.protected.?); } { // Invalid and ignored by the handler - for ("\x1B[>0J") |c| try s.next(c); + for ("\x1B[>0J") |c| s.next(c); try testing.expectEqual(csi.EraseDisplay.scrollback, s.handler.mode.?); try testing.expect(!s.handler.protected.?); } @@ -2753,7 +2757,7 @@ test "stream: DECEL, DECSEL" { self: *Self, comptime action: anytype, value: anytype, - ) !void { + ) void { switch (action) { .erase_line_right => { self.mode = .right; @@ -2778,49 +2782,49 @@ test "stream: DECEL, DECSEL" { var s: Stream(H) = .init(.{}); { - for ("\x1B[?K") |c| try s.next(c); + for ("\x1B[?K") |c| s.next(c); try testing.expectEqual(csi.EraseLine.right, s.handler.mode.?); try testing.expect(s.handler.protected.?); } { - for ("\x1B[?0K") |c| try s.next(c); + for ("\x1B[?0K") |c| s.next(c); try testing.expectEqual(csi.EraseLine.right, s.handler.mode.?); try testing.expect(s.handler.protected.?); } { - for ("\x1B[?1K") |c| try s.next(c); + for ("\x1B[?1K") |c| s.next(c); try testing.expectEqual(csi.EraseLine.left, s.handler.mode.?); try testing.expect(s.handler.protected.?); } { - for ("\x1B[?2K") |c| try s.next(c); + for ("\x1B[?2K") |c| s.next(c); try testing.expectEqual(csi.EraseLine.complete, s.handler.mode.?); try testing.expect(s.handler.protected.?); } { - for ("\x1B[K") |c| try s.next(c); + for ("\x1B[K") |c| s.next(c); try testing.expectEqual(csi.EraseLine.right, s.handler.mode.?); try testing.expect(!s.handler.protected.?); } { - for ("\x1B[0K") |c| try s.next(c); + for ("\x1B[0K") |c| s.next(c); try testing.expectEqual(csi.EraseLine.right, s.handler.mode.?); try testing.expect(!s.handler.protected.?); } { - for ("\x1B[1K") |c| try s.next(c); + for ("\x1B[1K") |c| s.next(c); try testing.expectEqual(csi.EraseLine.left, s.handler.mode.?); try testing.expect(!s.handler.protected.?); } { - for ("\x1B[2K") |c| try s.next(c); + for ("\x1B[2K") |c| s.next(c); try testing.expectEqual(csi.EraseLine.complete, s.handler.mode.?); try testing.expect(!s.handler.protected.?); } { // Invalid and ignored by the handler - for ("\x1B[<1K") |c| try s.next(c); + for ("\x1B[<1K") |c| s.next(c); try testing.expectEqual(csi.EraseLine.complete, s.handler.mode.?); try testing.expect(!s.handler.protected.?); } @@ -2834,7 +2838,7 @@ test "stream: DECSCUSR" { self: *@This(), comptime action: Stream(@This()).Action.Tag, value: Stream(@This()).Action.Value(action), - ) !void { + ) void { switch (action) { .cursor_style => self.style = value, else => {}, @@ -2843,14 +2847,14 @@ test "stream: DECSCUSR" { }; var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1B[ q"); + s.nextSlice("\x1B[ q"); try testing.expect(s.handler.style.? == .default); - try s.nextSlice("\x1B[1 q"); + s.nextSlice("\x1B[1 q"); try testing.expect(s.handler.style.? == .blinking_block); // Invalid and ignored by the handler - try s.nextSlice("\x1B[?0 q"); + s.nextSlice("\x1B[?0 q"); try testing.expect(s.handler.style.? == .blinking_block); } @@ -2862,7 +2866,7 @@ test "stream: DECSCUSR without space" { self: *@This(), comptime action: Stream(@This()).Action.Tag, value: Stream(@This()).Action.Value(action), - ) !void { + ) void { switch (action) { .cursor_style => self.style = value, else => {}, @@ -2871,10 +2875,10 @@ test "stream: DECSCUSR without space" { }; var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1B[q"); + s.nextSlice("\x1B[q"); try testing.expect(s.handler.style == null); - try s.nextSlice("\x1B[1q"); + s.nextSlice("\x1B[1q"); try testing.expect(s.handler.style == null); } @@ -2886,7 +2890,7 @@ test "stream: XTSHIFTESCAPE" { self: *@This(), comptime action: streampkg.Action.Tag, value: streampkg.Action.Value(action), - ) !void { + ) void { switch (action) { .mouse_shift_capture => self.escape = value, else => {}, @@ -2895,20 +2899,20 @@ test "stream: XTSHIFTESCAPE" { }; var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1B[>2s"); + s.nextSlice("\x1B[>2s"); try testing.expect(s.handler.escape == null); - try s.nextSlice("\x1B[>s"); + s.nextSlice("\x1B[>s"); try testing.expect(s.handler.escape.? == false); - try s.nextSlice("\x1B[>0s"); + s.nextSlice("\x1B[>0s"); try testing.expect(s.handler.escape.? == false); - try s.nextSlice("\x1B[>1s"); + s.nextSlice("\x1B[>1s"); try testing.expect(s.handler.escape.? == true); // Invalid and ignored by the handler - try s.nextSlice("\x1B[1 s"); + s.nextSlice("\x1B[1 s"); try testing.expect(s.handler.escape.? == true); } @@ -2920,7 +2924,7 @@ test "stream: change window title with invalid utf-8" { self: *@This(), comptime action: anytype, value: anytype, - ) !void { + ) void { _ = value; switch (action) { .window_title => self.seen = true, @@ -2931,13 +2935,13 @@ test "stream: change window title with invalid utf-8" { { var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1b]2;abc\x1b\\"); + s.nextSlice("\x1b]2;abc\x1b\\"); try testing.expect(s.handler.seen); } { var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1b]2;abc\xc0\x1b\\"); + s.nextSlice("\x1b]2;abc\xc0\x1b\\"); try testing.expect(!s.handler.seen); } } @@ -2951,7 +2955,7 @@ test "stream: insert characters" { self: *Self, comptime action: anytype, value: anytype, - ) !void { + ) void { _ = value; switch (action) { .insert_blanks => self.called = true, @@ -2961,11 +2965,11 @@ test "stream: insert characters" { }; var s: Stream(H) = .init(.{}); - for ("\x1B[42@") |c| try s.next(c); + for ("\x1B[42@") |c| s.next(c); try testing.expect(s.handler.called); s.handler.called = false; - for ("\x1B[?42@") |c| try s.next(c); + for ("\x1B[?42@") |c| s.next(c); try testing.expect(!s.handler.called); } @@ -2978,7 +2982,7 @@ test "stream: insert characters explicit zero clamps to 1" { self: *Self, comptime action: anytype, value: anytype, - ) !void { + ) void { switch (action) { .insert_blanks => self.value = value, else => {}, @@ -2987,7 +2991,7 @@ test "stream: insert characters explicit zero clamps to 1" { }; var s: Stream(H) = .init(.{}); - for ("\x1B[0@") |c| try s.next(c); + for ("\x1B[0@") |c| s.next(c); try testing.expectEqual(@as(usize, 1), s.handler.value.?); } @@ -3000,7 +3004,7 @@ test "stream: SCOSC" { self: *Self, comptime action: Stream(Self).Action.Tag, value: Stream(Self).Action.Value(action), - ) !void { + ) void { _ = value; switch (action) { .left_and_right_margin => @panic("bad"), @@ -3011,7 +3015,7 @@ test "stream: SCOSC" { }; var s: Stream(H) = .init(.{}); - for ("\x1B[s") |c| try s.next(c); + for ("\x1B[s") |c| s.next(c); try testing.expect(s.handler.called); } @@ -3024,7 +3028,7 @@ test "stream: SCORC" { self: *Self, comptime action: streampkg.Action.Tag, value: streampkg.Action.Value(action), - ) !void { + ) void { _ = value; switch (action) { .restore_cursor => self.called = true, @@ -3034,7 +3038,7 @@ test "stream: SCORC" { }; var s: Stream(H) = .init(.{}); - for ("\x1B[u") |c| try s.next(c); + for ("\x1B[u") |c| s.next(c); try testing.expect(s.handler.called); } @@ -3044,7 +3048,7 @@ test "stream: too many csi params" { self: *@This(), comptime action: anytype, value: anytype, - ) !void { + ) void { _ = self; _ = value; switch (action) { @@ -3055,7 +3059,7 @@ test "stream: too many csi params" { }; var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1B[1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1C"); + s.nextSlice("\x1B[1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1C"); } test "stream: csi param too long" { @@ -3064,7 +3068,7 @@ test "stream: csi param too long" { self: *@This(), comptime action: anytype, value: anytype, - ) !void { + ) void { _ = self; _ = action; _ = value; @@ -3072,7 +3076,7 @@ test "stream: csi param too long" { }; var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1B[1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111C"); + s.nextSlice("\x1B[1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111C"); } test "stream: send report with CSI t" { @@ -3083,7 +3087,7 @@ test "stream: send report with CSI t" { self: *@This(), comptime action: streampkg.Action.Tag, value: streampkg.Action.Value(action), - ) !void { + ) void { switch (action) { .size_report => self.style = value, else => {}, @@ -3093,16 +3097,16 @@ test "stream: send report with CSI t" { var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1b[14t"); + s.nextSlice("\x1b[14t"); try testing.expectEqual(csi.SizeReportStyle.csi_14_t, s.handler.style); - try s.nextSlice("\x1b[16t"); + s.nextSlice("\x1b[16t"); try testing.expectEqual(csi.SizeReportStyle.csi_16_t, s.handler.style); - try s.nextSlice("\x1b[18t"); + s.nextSlice("\x1b[18t"); try testing.expectEqual(csi.SizeReportStyle.csi_18_t, s.handler.style); - try s.nextSlice("\x1b[21t"); + s.nextSlice("\x1b[21t"); try testing.expectEqual(csi.SizeReportStyle.csi_21_t, s.handler.style); } @@ -3118,7 +3122,7 @@ test "stream: invalid CSI t" { self: *@This(), comptime action: anytype, value: anytype, - ) !void { + ) void { _ = self; _ = action; _ = value; @@ -3127,7 +3131,7 @@ test "stream: invalid CSI t" { var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1b[19t"); + s.nextSlice("\x1b[19t"); try testing.expectEqual(null, s.handler.style); } @@ -3139,7 +3143,7 @@ test "stream: CSI t push title" { self: *@This(), comptime action: streampkg.Action.Tag, value: streampkg.Action.Value(action), - ) !void { + ) void { switch (action) { .title_push => self.index = value, else => {}, @@ -3149,7 +3153,7 @@ test "stream: CSI t push title" { var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1b[22;0t"); + s.nextSlice("\x1b[22;0t"); try testing.expectEqual(@as(u16, 0), s.handler.index.?); } @@ -3161,7 +3165,7 @@ test "stream: CSI t push title with explicit window" { self: *@This(), comptime action: streampkg.Action.Tag, value: streampkg.Action.Value(action), - ) !void { + ) void { switch (action) { .title_push => self.index = value, else => {}, @@ -3171,7 +3175,7 @@ test "stream: CSI t push title with explicit window" { var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1b[22;2t"); + s.nextSlice("\x1b[22;2t"); try testing.expectEqual(@as(u16, 0), s.handler.index.?); } @@ -3183,7 +3187,7 @@ test "stream: CSI t push title with explicit icon" { self: *@This(), comptime action: streampkg.Action.Tag, value: streampkg.Action.Value(action), - ) !void { + ) void { switch (action) { .title_push => self.index = value, else => {}, @@ -3193,7 +3197,7 @@ test "stream: CSI t push title with explicit icon" { var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1b[22;1t"); + s.nextSlice("\x1b[22;1t"); try testing.expectEqual(null, s.handler.index); } @@ -3205,7 +3209,7 @@ test "stream: CSI t push title with index" { self: *@This(), comptime action: streampkg.Action.Tag, value: streampkg.Action.Value(action), - ) !void { + ) void { switch (action) { .title_push => self.index = value, else => {}, @@ -3215,7 +3219,7 @@ test "stream: CSI t push title with index" { var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1b[22;0;5t"); + s.nextSlice("\x1b[22;0;5t"); try testing.expectEqual(@as(u16, 5), s.handler.index.?); } @@ -3227,7 +3231,7 @@ test "stream: CSI t pop title" { self: *@This(), comptime action: streampkg.Action.Tag, value: streampkg.Action.Value(action), - ) !void { + ) void { switch (action) { .title_pop => self.index = value, else => {}, @@ -3237,7 +3241,7 @@ test "stream: CSI t pop title" { var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1b[23;0t"); + s.nextSlice("\x1b[23;0t"); try testing.expectEqual(@as(u16, 0), s.handler.index.?); } @@ -3249,7 +3253,7 @@ test "stream: CSI t pop title with explicit window" { self: *@This(), comptime action: streampkg.Action.Tag, value: streampkg.Action.Value(action), - ) !void { + ) void { switch (action) { .title_pop => self.index = value, else => {}, @@ -3259,7 +3263,7 @@ test "stream: CSI t pop title with explicit window" { var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1b[23;2t"); + s.nextSlice("\x1b[23;2t"); try testing.expectEqual(@as(u16, 0), s.handler.index.?); } @@ -3271,7 +3275,7 @@ test "stream: CSI t pop title with explicit icon" { self: *@This(), comptime action: streampkg.Action.Tag, value: streampkg.Action.Value(action), - ) !void { + ) void { switch (action) { .title_pop => self.index = value, else => {}, @@ -3281,7 +3285,7 @@ test "stream: CSI t pop title with explicit icon" { var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1b[23;1t"); + s.nextSlice("\x1b[23;1t"); try testing.expectEqual(null, s.handler.index); } @@ -3293,7 +3297,7 @@ test "stream: CSI t pop title with index" { self: *@This(), comptime action: streampkg.Action.Tag, value: streampkg.Action.Value(action), - ) !void { + ) void { switch (action) { .title_pop => self.index = value, else => {}, @@ -3303,7 +3307,7 @@ test "stream: CSI t pop title with index" { var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1b[23;0;5t"); + s.nextSlice("\x1b[23;0;5t"); try testing.expectEqual(@as(u16, 5), s.handler.index.?); } @@ -3315,7 +3319,7 @@ test "stream CSI W clear tab stops" { self: *@This(), comptime action: anytype, value: anytype, - ) !void { + ) void { _ = value; self.action = action; } @@ -3323,10 +3327,10 @@ test "stream CSI W clear tab stops" { var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1b[2W"); + s.nextSlice("\x1b[2W"); try testing.expectEqual(Action.Key.tab_clear_current, s.handler.action.?); - try s.nextSlice("\x1b[5W"); + s.nextSlice("\x1b[5W"); try testing.expectEqual(Action.Key.tab_clear_all, s.handler.action.?); } @@ -3338,7 +3342,7 @@ test "stream CSI W tab set" { self: *@This(), comptime action: anytype, value: anytype, - ) !void { + ) void { _ = value; self.action = action; } @@ -3346,19 +3350,19 @@ test "stream CSI W tab set" { var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1b[W"); + s.nextSlice("\x1b[W"); try testing.expectEqual(Action.Key.tab_set, s.handler.action.?); s.handler.action = null; - try s.nextSlice("\x1b[0W"); + s.nextSlice("\x1b[0W"); try testing.expectEqual(Action.Key.tab_set, s.handler.action.?); s.handler.action = null; - try s.nextSlice("\x1b[>W"); + s.nextSlice("\x1b[>W"); try testing.expect(s.handler.action == null); s.handler.action = null; - try s.nextSlice("\x1b[99W"); + s.nextSlice("\x1b[99W"); try testing.expect(s.handler.action == null); } @@ -3370,7 +3374,7 @@ test "stream CSI ? W reset tab stops" { self: *@This(), comptime action: anytype, value: anytype, - ) !void { + ) void { _ = value; self.action = action; } @@ -3378,15 +3382,15 @@ test "stream CSI ? W reset tab stops" { var s: Stream(H) = .init(.{}); - try s.nextSlice("\x1b[?2W"); + s.nextSlice("\x1b[?2W"); try testing.expect(s.handler.action == null); - try s.nextSlice("\x1b[?5W"); + s.nextSlice("\x1b[?5W"); try testing.expectEqual(Action.Key.tab_reset, s.handler.action.?); // Invalid and ignored by the handler s.handler.action = null; - try s.nextSlice("\x1b[?1;2;3W"); + s.nextSlice("\x1b[?1;2;3W"); try testing.expect(s.handler.action == null); } @@ -3399,7 +3403,7 @@ test "stream: SGR with 17+ parameters for underline color" { self: *@This(), comptime action: anytype, value: anytype, - ) !void { + ) void { switch (action) { .set_attribute => { self.attrs = value; @@ -3414,7 +3418,7 @@ test "stream: SGR with 17+ parameters for underline color" { // Kakoune-style SGR with underline color as 17th parameter // This tests the fix where param 17 was being dropped - try s.nextSlice("\x1b[4:3;38;2;51;51;51;48;2;170;170;170;58;2;255;97;136;0m"); + s.nextSlice("\x1b[4:3;38;2;51;51;51;48;2;170;170;170;58;2;255;97;136;0m"); try testing.expect(s.handler.called); } @@ -3429,7 +3433,7 @@ test "stream: tab clear with overflowing param" { self: *@This(), comptime action: Action.Tag, value: Action.Value(action), - ) !void { + ) void { _ = value; switch (action) { .tab_clear_current, .tab_clear_all => self.called = true, @@ -3441,5 +3445,5 @@ test "stream: tab clear with overflowing param" { var s: Stream(H) = .init(.{}); // This is the exact input from the fuzz crash (minus the mode byte): // CSI with a huge numeric param that saturates to 65535, followed by 'g'. - try s.nextSlice("\x1b[388888888888888888888888888888888888g\x1b[0m"); + s.nextSlice("\x1b[388888888888888888888888888888888888g\x1b[0m"); } diff --git a/src/terminal/stream_readonly.zig b/src/terminal/stream_readonly.zig index 5b97bebfa..a3e98c8e0 100644 --- a/src/terminal/stream_readonly.zig +++ b/src/terminal/stream_readonly.zig @@ -8,6 +8,8 @@ const osc_color = @import("osc/parsers/color.zig"); const kitty_color = @import("kitty/color.zig"); const Terminal = @import("Terminal.zig"); +const log = std.log.scoped(.stream_readonly); + /// This is a Stream implementation that processes actions against /// a Terminal and updates the Terminal state. It is called "readonly" because /// it only processes actions that modify terminal state, while ignoring @@ -45,6 +47,16 @@ pub const Handler = struct { self: *Handler, comptime action: Action.Tag, value: Action.Value(action), + ) void { + self.vtFallible(action, value) catch |err| { + log.warn("error handling VT action action={} err={}", .{ action, err }); + }; + } + + inline fn vtFallible( + self: *Handler, + comptime action: Action.Tag, + value: Action.Value(action), ) !void { switch (action) { .print => try self.terminal.print(value.cp), @@ -402,7 +414,7 @@ test "basic print" { var s: Stream = .initAlloc(testing.allocator, .init(&t)); defer s.deinit(); - try s.nextSlice("Hello"); + s.nextSlice("Hello"); try testing.expectEqual(@as(usize, 5), t.screens.active.cursor.x); try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.y); @@ -419,12 +431,12 @@ test "cursor movement" { defer s.deinit(); // Move cursor using escape sequences - try s.nextSlice("Hello\x1B[1;1H"); + s.nextSlice("Hello\x1B[1;1H"); try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.x); try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.y); // Move to position 2,3 - try s.nextSlice("\x1B[2;3H"); + s.nextSlice("\x1B[2;3H"); try testing.expectEqual(@as(usize, 2), t.screens.active.cursor.x); try testing.expectEqual(@as(usize, 1), t.screens.active.cursor.y); } @@ -437,13 +449,13 @@ test "erase operations" { defer s.deinit(); // Print some text - try s.nextSlice("Hello World"); + s.nextSlice("Hello World"); try testing.expectEqual(@as(usize, 11), t.screens.active.cursor.x); try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.y); // Move cursor to position 1,6 and erase from cursor to end of line - try s.nextSlice("\x1B[1;6H"); - try s.nextSlice("\x1B[K"); + s.nextSlice("\x1B[1;6H"); + s.nextSlice("\x1B[K"); const str = try t.plainString(testing.allocator); defer testing.allocator.free(str); @@ -457,7 +469,7 @@ test "tabs" { var s: Stream = .initAlloc(testing.allocator, .init(&t)); defer s.deinit(); - try s.nextSlice("A\tB"); + s.nextSlice("A\tB"); try testing.expectEqual(@as(usize, 9), t.screens.active.cursor.x); const str = try t.plainString(testing.allocator); @@ -474,9 +486,9 @@ test "modes" { // Test wraparound mode try testing.expect(t.modes.get(.wraparound)); - try s.nextSlice("\x1B[?7l"); // Disable wraparound + s.nextSlice("\x1B[?7l"); // Disable wraparound try testing.expect(!t.modes.get(.wraparound)); - try s.nextSlice("\x1B[?7h"); // Enable wraparound + s.nextSlice("\x1B[?7h"); // Enable wraparound try testing.expect(t.modes.get(.wraparound)); } @@ -488,7 +500,7 @@ test "scrolling regions" { defer s.deinit(); // Set scrolling region from line 5 to 20 - try s.nextSlice("\x1B[5;20r"); + s.nextSlice("\x1B[5;20r"); try testing.expectEqual(@as(usize, 4), t.scrolling_region.top); try testing.expectEqual(@as(usize, 19), t.scrolling_region.bottom); try testing.expectEqual(@as(usize, 0), t.scrolling_region.left); @@ -503,8 +515,8 @@ test "charsets" { defer s.deinit(); // Configure G0 as DEC special graphics - try s.nextSlice("\x1B(0"); - try s.nextSlice("`"); // Should print diamond character + s.nextSlice("\x1B(0"); + s.nextSlice("`"); // Should print diamond character const str = try t.plainString(testing.allocator); defer testing.allocator.free(str); @@ -519,18 +531,18 @@ test "alt screen" { defer s.deinit(); // Write to primary screen - try s.nextSlice("Primary"); + s.nextSlice("Primary"); try testing.expectEqual(.primary, t.screens.active_key); // Switch to alt screen - try s.nextSlice("\x1B[?1049h"); + s.nextSlice("\x1B[?1049h"); try testing.expectEqual(.alternate, t.screens.active_key); // Write to alt screen - try s.nextSlice("Alt"); + s.nextSlice("Alt"); // Switch back to primary - try s.nextSlice("\x1B[?1049l"); + s.nextSlice("\x1B[?1049l"); try testing.expectEqual(.primary, t.screens.active_key); const str = try t.plainString(testing.allocator); @@ -546,20 +558,20 @@ test "cursor save and restore" { defer s.deinit(); // Move cursor to 10,15 - try s.nextSlice("\x1B[10;15H"); + s.nextSlice("\x1B[10;15H"); try testing.expectEqual(@as(usize, 14), t.screens.active.cursor.x); try testing.expectEqual(@as(usize, 9), t.screens.active.cursor.y); // Save cursor - try s.nextSlice("\x1B7"); + s.nextSlice("\x1B7"); // Move cursor elsewhere - try s.nextSlice("\x1B[1;1H"); + s.nextSlice("\x1B[1;1H"); try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.x); try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.y); // Restore cursor - try s.nextSlice("\x1B8"); + s.nextSlice("\x1B8"); try testing.expectEqual(@as(usize, 14), t.screens.active.cursor.x); try testing.expectEqual(@as(usize, 9), t.screens.active.cursor.y); } @@ -572,7 +584,7 @@ test "attributes" { defer s.deinit(); // Set bold and write text - try s.nextSlice("\x1B[1mBold\x1B[0m"); + s.nextSlice("\x1B[1mBold\x1B[0m"); // Verify we can write attributes - just check the string was written const str = try t.plainString(testing.allocator); @@ -588,7 +600,7 @@ test "DECALN screen alignment" { defer s.deinit(); // Run DECALN - try s.nextSlice("\x1B#8"); + s.nextSlice("\x1B#8"); // Verify entire screen is filled with 'E' const str = try t.plainString(testing.allocator); @@ -608,13 +620,13 @@ test "full reset" { defer s.deinit(); // Make some changes - try s.nextSlice("Hello"); - try s.nextSlice("\x1B[10;20H"); - try s.nextSlice("\x1B[5;20r"); // Set scroll region - try s.nextSlice("\x1B[?7l"); // Disable wraparound + s.nextSlice("Hello"); + s.nextSlice("\x1B[10;20H"); + s.nextSlice("\x1B[5;20r"); // Set scroll region + s.nextSlice("\x1B[?7l"); // Disable wraparound // Full reset - try s.nextSlice("\x1Bc"); + s.nextSlice("\x1Bc"); // Verify reset state try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.x); @@ -632,12 +644,12 @@ test "ignores query actions" { defer s.deinit(); // These should be ignored without error - try s.nextSlice("\x1B[c"); // Device attributes - try s.nextSlice("\x1B[5n"); // Device status report - try s.nextSlice("\x1B[6n"); // Cursor position report + s.nextSlice("\x1B[c"); // Device attributes + s.nextSlice("\x1B[5n"); // Device status report + s.nextSlice("\x1B[6n"); // Cursor position report // Terminal should still be functional - try s.nextSlice("Test"); + s.nextSlice("Test"); const str = try t.plainString(testing.allocator); defer testing.allocator.free(str); try testing.expectEqualStrings("Test", str); @@ -654,14 +666,14 @@ test "OSC 4 set and reset palette" { const default_color_0 = t.colors.palette.original[0]; // Set color 0 to red - try s.nextSlice("\x1b]4;0;rgb:ff/00/00\x1b\\"); + s.nextSlice("\x1b]4;0;rgb:ff/00/00\x1b\\"); try testing.expectEqual(@as(u8, 0xff), t.colors.palette.current[0].r); try testing.expectEqual(@as(u8, 0x00), t.colors.palette.current[0].g); try testing.expectEqual(@as(u8, 0x00), t.colors.palette.current[0].b); try testing.expect(t.colors.palette.mask.isSet(0)); // Reset color 0 - try s.nextSlice("\x1b]104;0\x1b\\"); + s.nextSlice("\x1b]104;0\x1b\\"); try testing.expectEqual(default_color_0, t.colors.palette.current[0]); try testing.expect(!t.colors.palette.mask.isSet(0)); } @@ -674,15 +686,15 @@ test "OSC 104 reset all palette colors" { defer s.deinit(); // Set multiple colors - try s.nextSlice("\x1b]4;0;rgb:ff/00/00\x1b\\"); - try s.nextSlice("\x1b]4;1;rgb:00/ff/00\x1b\\"); - try s.nextSlice("\x1b]4;2;rgb:00/00/ff\x1b\\"); + s.nextSlice("\x1b]4;0;rgb:ff/00/00\x1b\\"); + s.nextSlice("\x1b]4;1;rgb:00/ff/00\x1b\\"); + s.nextSlice("\x1b]4;2;rgb:00/00/ff\x1b\\"); try testing.expect(t.colors.palette.mask.isSet(0)); try testing.expect(t.colors.palette.mask.isSet(1)); try testing.expect(t.colors.palette.mask.isSet(2)); // Reset all palette colors - try s.nextSlice("\x1b]104\x1b\\"); + s.nextSlice("\x1b]104\x1b\\"); try testing.expectEqual(t.colors.palette.original[0], t.colors.palette.current[0]); try testing.expectEqual(t.colors.palette.original[1], t.colors.palette.current[1]); try testing.expectEqual(t.colors.palette.original[2], t.colors.palette.current[2]); @@ -702,14 +714,14 @@ test "OSC 10 set and reset foreground color" { try testing.expect(t.colors.foreground.get() == null); // Set foreground to red - try s.nextSlice("\x1b]10;rgb:ff/00/00\x1b\\"); + s.nextSlice("\x1b]10;rgb:ff/00/00\x1b\\"); const fg = t.colors.foreground.get().?; try testing.expectEqual(@as(u8, 0xff), fg.r); try testing.expectEqual(@as(u8, 0x00), fg.g); try testing.expectEqual(@as(u8, 0x00), fg.b); // Reset foreground - try s.nextSlice("\x1b]110\x1b\\"); + s.nextSlice("\x1b]110\x1b\\"); try testing.expect(t.colors.foreground.get() == null); } @@ -721,14 +733,14 @@ test "OSC 11 set and reset background color" { defer s.deinit(); // Set background to green - try s.nextSlice("\x1b]11;rgb:00/ff/00\x1b\\"); + s.nextSlice("\x1b]11;rgb:00/ff/00\x1b\\"); const bg = t.colors.background.get().?; try testing.expectEqual(@as(u8, 0x00), bg.r); try testing.expectEqual(@as(u8, 0xff), bg.g); try testing.expectEqual(@as(u8, 0x00), bg.b); // Reset background - try s.nextSlice("\x1b]111\x1b\\"); + s.nextSlice("\x1b]111\x1b\\"); try testing.expect(t.colors.background.get() == null); } @@ -740,14 +752,14 @@ test "OSC 12 set and reset cursor color" { defer s.deinit(); // Set cursor to blue - try s.nextSlice("\x1b]12;rgb:00/00/ff\x1b\\"); + s.nextSlice("\x1b]12;rgb:00/00/ff\x1b\\"); const cursor = t.colors.cursor.get().?; try testing.expectEqual(@as(u8, 0x00), cursor.r); try testing.expectEqual(@as(u8, 0x00), cursor.g); try testing.expectEqual(@as(u8, 0xff), cursor.b); // Reset cursor - try s.nextSlice("\x1b]112\x1b\\"); + s.nextSlice("\x1b]112\x1b\\"); // After reset, cursor might be null (using default) } @@ -759,7 +771,7 @@ test "kitty color protocol set palette" { defer s.deinit(); // Set palette color 5 to magenta using kitty protocol - try s.nextSlice("\x1b]21;5=rgb:ff/00/ff\x1b\\"); + s.nextSlice("\x1b]21;5=rgb:ff/00/ff\x1b\\"); try testing.expectEqual(@as(u8, 0xff), t.colors.palette.current[5].r); try testing.expectEqual(@as(u8, 0x00), t.colors.palette.current[5].g); try testing.expectEqual(@as(u8, 0xff), t.colors.palette.current[5].b); @@ -776,10 +788,10 @@ test "kitty color protocol reset palette" { // Set and then reset palette color const original = t.colors.palette.original[7]; - try s.nextSlice("\x1b]21;7=rgb:aa/bb/cc\x1b\\"); + s.nextSlice("\x1b]21;7=rgb:aa/bb/cc\x1b\\"); try testing.expect(t.colors.palette.mask.isSet(7)); - try s.nextSlice("\x1b]21;7=\x1b\\"); + s.nextSlice("\x1b]21;7=\x1b\\"); try testing.expectEqual(original, t.colors.palette.current[7]); try testing.expect(!t.colors.palette.mask.isSet(7)); } @@ -792,7 +804,7 @@ test "kitty color protocol set foreground" { defer s.deinit(); // Set foreground using kitty protocol - try s.nextSlice("\x1b]21;foreground=rgb:12/34/56\x1b\\"); + s.nextSlice("\x1b]21;foreground=rgb:12/34/56\x1b\\"); const fg = t.colors.foreground.get().?; try testing.expectEqual(@as(u8, 0x12), fg.r); try testing.expectEqual(@as(u8, 0x34), fg.g); @@ -807,7 +819,7 @@ test "kitty color protocol set background" { defer s.deinit(); // Set background using kitty protocol - try s.nextSlice("\x1b]21;background=rgb:78/9a/bc\x1b\\"); + s.nextSlice("\x1b]21;background=rgb:78/9a/bc\x1b\\"); const bg = t.colors.background.get().?; try testing.expectEqual(@as(u8, 0x78), bg.r); try testing.expectEqual(@as(u8, 0x9a), bg.g); @@ -822,7 +834,7 @@ test "kitty color protocol set cursor" { defer s.deinit(); // Set cursor using kitty protocol - try s.nextSlice("\x1b]21;cursor=rgb:de/f0/12\x1b\\"); + s.nextSlice("\x1b]21;cursor=rgb:de/f0/12\x1b\\"); const cursor = t.colors.cursor.get().?; try testing.expectEqual(@as(u8, 0xde), cursor.r); try testing.expectEqual(@as(u8, 0xf0), cursor.g); @@ -837,10 +849,10 @@ test "kitty color protocol reset foreground" { defer s.deinit(); // Set and reset foreground - try s.nextSlice("\x1b]21;foreground=rgb:11/22/33\x1b\\"); + s.nextSlice("\x1b]21;foreground=rgb:11/22/33\x1b\\"); try testing.expect(t.colors.foreground.get() != null); - try s.nextSlice("\x1b]21;foreground=\x1b\\"); + s.nextSlice("\x1b]21;foreground=\x1b\\"); // After reset, should be unset try testing.expect(t.colors.foreground.get() == null); } @@ -856,17 +868,17 @@ test "palette dirty flag set on color change" { t.flags.dirty.palette = false; // Setting palette color should set dirty flag - try s.nextSlice("\x1b]4;0;rgb:ff/00/00\x1b\\"); + s.nextSlice("\x1b]4;0;rgb:ff/00/00\x1b\\"); try testing.expect(t.flags.dirty.palette); // Clear and test reset t.flags.dirty.palette = false; - try s.nextSlice("\x1b]104;0\x1b\\"); + s.nextSlice("\x1b]104;0\x1b\\"); try testing.expect(t.flags.dirty.palette); // Clear and test kitty protocol t.flags.dirty.palette = false; - try s.nextSlice("\x1b]21;1=rgb:00/ff/00\x1b\\"); + s.nextSlice("\x1b]21;1=rgb:00/ff/00\x1b\\"); try testing.expect(t.flags.dirty.palette); } @@ -877,8 +889,8 @@ test "semantic prompt fresh line" { var s: Stream = .initAlloc(testing.allocator, .init(&t)); defer s.deinit(); - try s.nextSlice("Hello"); - try s.nextSlice("\x1b]133;L\x07"); + s.nextSlice("Hello"); + s.nextSlice("\x1b]133;L\x07"); try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.x); try testing.expectEqual(@as(usize, 1), t.screens.active.cursor.y); } @@ -891,8 +903,8 @@ test "semantic prompt fresh line new prompt" { defer s.deinit(); // Write some text and then send OSC 133;A (fresh_line_new_prompt) - try s.nextSlice("Hello"); - try s.nextSlice("\x1b]133;A\x07"); + s.nextSlice("Hello"); + s.nextSlice("\x1b]133;A\x07"); // Should do a fresh line (carriage return + index) try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.x); @@ -902,8 +914,8 @@ test "semantic prompt fresh line new prompt" { try testing.expectEqual(.prompt, t.screens.active.cursor.semantic_content); // Test with redraw option - try s.nextSlice("prompt$ "); - try s.nextSlice("\x1b]133;A;redraw=1\x07"); + s.nextSlice("prompt$ "); + s.nextSlice("\x1b]133;A;redraw=1\x07"); try testing.expect(t.flags.shell_redraws_prompt == .true); } @@ -915,12 +927,12 @@ test "semantic prompt end of input, then start output" { defer s.deinit(); // Write some text and then send OSC 133;A (fresh_line_new_prompt) - try s.nextSlice("Hello"); - try s.nextSlice("\x1b]133;A\x07"); - try s.nextSlice("prompt$ "); - try s.nextSlice("\x1b]133;B\x07"); + s.nextSlice("Hello"); + s.nextSlice("\x1b]133;A\x07"); + s.nextSlice("prompt$ "); + s.nextSlice("\x1b]133;B\x07"); try testing.expectEqual(.input, t.screens.active.cursor.semantic_content); - try s.nextSlice("\x1b]133;C\x07"); + s.nextSlice("\x1b]133;C\x07"); try testing.expectEqual(.output, t.screens.active.cursor.semantic_content); } @@ -932,10 +944,10 @@ test "semantic prompt prompt_start" { defer s.deinit(); // Write some text - try s.nextSlice("Hello"); + s.nextSlice("Hello"); // OSC 133;P marks the start of a prompt (without fresh line behavior) - try s.nextSlice("\x1b]133;P\x07"); + s.nextSlice("\x1b]133;P\x07"); try testing.expectEqual(.prompt, t.screens.active.cursor.semantic_content); try testing.expectEqual(@as(usize, 5), t.screens.active.cursor.x); try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.y); @@ -949,8 +961,8 @@ test "semantic prompt new_command" { defer s.deinit(); // Write some text - try s.nextSlice("Hello"); - try s.nextSlice("\x1b]133;N\x07"); + s.nextSlice("Hello"); + s.nextSlice("\x1b]133;N\x07"); // Should behave like fresh_line_new_prompt - cursor moves to column 0 // on next line since we had content @@ -967,7 +979,7 @@ test "semantic prompt new_command at column zero" { defer s.deinit(); // OSC 133;N when already at column 0 should stay on same line - try s.nextSlice("\x1b]133;N\x07"); + s.nextSlice("\x1b]133;N\x07"); try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.x); try testing.expectEqual(@as(usize, 0), t.screens.active.cursor.y); try testing.expectEqual(.prompt, t.screens.active.cursor.semantic_content); @@ -981,11 +993,11 @@ test "semantic prompt end_prompt_start_input_terminate_eol clears on linefeed" { defer s.deinit(); // Set input terminated by EOL - try s.nextSlice("\x1b]133;I\x07"); + s.nextSlice("\x1b]133;I\x07"); try testing.expectEqual(.input, t.screens.active.cursor.semantic_content); // Linefeed should reset semantic content to output - try s.nextSlice("\n"); + s.nextSlice("\n"); try testing.expectEqual(.output, t.screens.active.cursor.semantic_content); } @@ -1002,5 +1014,5 @@ test "stream: CSI W with intermediate but no params" { var s: Stream = .initAlloc(testing.allocator, .init(&t)); defer s.deinit(); - try s.nextSlice("\x1b[?W"); + s.nextSlice("\x1b[?W"); } diff --git a/src/terminal/tmux/viewer.zig b/src/terminal/tmux/viewer.zig index 62a0f1d00..585c95403 100644 --- a/src/terminal/tmux/viewer.zig +++ b/src/terminal/tmux/viewer.zig @@ -1053,10 +1053,7 @@ pub const Viewer = struct { // correct but we'll get the active contents soon. var stream = t.vtStream(); defer stream.deinit(); - stream.nextSlice(content) catch |err| { - log.info("failed to process pane history for pane id={}: {}", .{ id, err }); - return err; - }; + stream.nextSlice(content); // Populate the active area to be empty since this is only history. // We'll fill it with blanks and move the cursor to the top-left. @@ -1097,10 +1094,7 @@ pub const Viewer = struct { var stream = t.vtStream(); defer stream.deinit(); - stream.nextSlice(content) catch |err| { - log.info("failed to process pane visible for pane id={}: {}", .{ id, err }); - return err; - }; + stream.nextSlice(content); } fn receivedOutput( @@ -1117,10 +1111,7 @@ pub const Viewer = struct { var stream = t.vtStream(); defer stream.deinit(); - stream.nextSlice(data) catch |err| { - log.info("failed to process output for pane id={}: {}", .{ id, err }); - return err; - }; + stream.nextSlice(data); } fn initLayout( diff --git a/src/termio/Termio.zig b/src/termio/Termio.zig index dcd0d8cf7..8d0f5e2c4 100644 --- a/src/termio/Termio.zig +++ b/src/termio/Termio.zig @@ -721,12 +721,10 @@ fn processOutputLocked(self: *Termio, buf: []const u8) void { log.err("error recording pty read in inspector err={}", .{err}); }; - self.terminal_stream.next(byte) catch |err| - log.err("error processing terminal data: {}", .{err}); + self.terminal_stream.next(byte); } } else { - self.terminal_stream.nextSlice(buf) catch |err| - log.err("error processing terminal data: {}", .{err}); + self.terminal_stream.nextSlice(buf); } // If our stream handling caused messages to be sent to the mailbox diff --git a/src/termio/stream_handler.zig b/src/termio/stream_handler.zig index 8c1b5b8ab..fd17d299d 100644 --- a/src/termio/stream_handler.zig +++ b/src/termio/stream_handler.zig @@ -176,6 +176,16 @@ pub const StreamHandler = struct { self: *StreamHandler, comptime action: Stream.Action.Tag, value: Stream.Action.Value(action), + ) void { + self.vtFallible(action, value) catch |err| { + log.warn("error handling VT action action={} err={}", .{ action, err }); + }; + } + + inline fn vtFallible( + self: *StreamHandler, + comptime action: Stream.Action.Tag, + value: Stream.Action.Value(action), ) !void { // The branch hints here are based on real world data // which indicates that the most common actions are: diff --git a/test/fuzz-libghostty/src/fuzz_stream.zig b/test/fuzz-libghostty/src/fuzz_stream.zig index 17f63766f..ec47e90fe 100644 --- a/test/fuzz-libghostty/src/fuzz_stream.zig +++ b/test/fuzz-libghostty/src/fuzz_stream.zig @@ -43,11 +43,9 @@ pub export fn zig_fuzz_test( if (mode & 1 == 0) { // Slice path — exercises SIMD fast-path if enabled - stream.nextSlice(data) catch |err| - std.debug.panic("nextSlice: {}", .{err}); + stream.nextSlice(data); } else { // Scalar path — exercises byte-at-a-time UTF-8 decoding - for (data) |byte| _ = stream.next(byte) catch |err| - std.debug.panic("next: {}", .{err}); + for (data) |byte| stream.next(byte); } }