terminal: change OSC parser to explicit init to set undefined

This works around: https://github.com/ziglang/zig/issues/19148
This lets our `test-valgrind` command catch some issues. We'll have to
follow this pattern in more places but I want to do it incrementally so
things keep passing.

I **do not** want to blindly follow this pattern everywhere. I want to
start by focusing in only on the structs that set `undefined` as default
fields that we're also about to test in isolation with Valgrind. Its
just too much noise otherwise and not a general style I'm sure of; it's
worth it for Valgrind though.
pull/8304/head
Mitchell Hashimoto 2025-08-20 12:06:09 -07:00
parent b3a80f2e47
commit 131f170f89
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
9 changed files with 222 additions and 186 deletions

View File

@ -22,7 +22,6 @@ jobs:
- build-macos-matrix - build-macos-matrix
- build-windows - build-windows
- flatpak-check-zig-cache - flatpak-check-zig-cache
- flatpak
- test - test
- test-gtk - test-gtk
- test-gtk-ng - test-gtk-ng
@ -1013,28 +1012,29 @@ jobs:
- name: Check Flatpak Zig Dependencies - name: Check Flatpak Zig Dependencies
run: nix develop -c ./flatpak/build-support/check-zig-cache.sh run: nix develop -c ./flatpak/build-support/check-zig-cache.sh
flatpak: # Disabled until we update to Zig 0.15 or if we can pin this to Zig 0.14
if: github.repository == 'ghostty-org/ghostty' # flatpak:
name: "Flatpak" # if: github.repository == 'ghostty-org/ghostty'
container: # name: "Flatpak"
image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-47 # container:
options: --privileged # image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-47
strategy: # options: --privileged
fail-fast: false # strategy:
matrix: # fail-fast: false
variant: # matrix:
- arch: x86_64 # variant:
runner: namespace-profile-ghostty-md # - arch: x86_64
- arch: aarch64 # runner: namespace-profile-ghostty-md
runner: namespace-profile-ghostty-md-arm64 # - arch: aarch64
runs-on: ${{ matrix.variant.runner }} # runner: namespace-profile-ghostty-md-arm64
needs: [flatpak-check-zig-cache, test] # runs-on: ${{ matrix.variant.runner }}
steps: # needs: [flatpak-check-zig-cache, test]
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 # steps:
- uses: flatpak/flatpak-github-actions/flatpak-builder@10a3c29f0162516f0f68006be14c92f34bd4fa6c # v6.5 # - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with: # - uses: flatpak/flatpak-github-actions/flatpak-builder@10a3c29f0162516f0f68006be14c92f34bd4fa6c # v6.5
bundle: com.mitchellh.ghostty # with:
manifest-path: flatpak/com.mitchellh.ghostty.yml # bundle: com.mitchellh.ghostty
cache-key: flatpak-builder-${{ github.sha }} # manifest-path: flatpak/com.mitchellh.ghostty.yml
arch: ${{ matrix.variant.arch }} # cache-key: flatpak-builder-${{ github.sha }}
verbose: true # arch: ${{ matrix.variant.arch }}
# verbose: true

View File

@ -77,7 +77,7 @@ fn step(ptr: *anyopaque) Benchmark.Error!void {
const f = self.data_f orelse return; const f = self.data_f orelse return;
var r = std.io.bufferedReader(f.reader()); var r = std.io.bufferedReader(f.reader());
var p: terminalpkg.Parser = .{}; var p: terminalpkg.Parser = .init();
var buf: [4096]u8 = undefined; var buf: [4096]u8 = undefined;
while (true) { while (true) {

View File

@ -62,7 +62,7 @@ pub fn create(
.cols = opts.@"terminal-cols", .cols = opts.@"terminal-cols",
}), }),
.handler = .{ .t = &ptr.terminal }, .handler = .{ .t = &ptr.terminal },
.stream = .{ .handler = &ptr.handler }, .stream = .init(&ptr.handler),
}; };
return ptr; return ptr;

View File

@ -172,13 +172,10 @@ pub fn init(surface: *Surface) !Inspector {
.surface = surface, .surface = surface,
.key_events = key_buf, .key_events = key_buf,
.vt_events = vt_events, .vt_events = vt_events,
.vt_stream = .{ .vt_stream = stream: {
.handler = vt_handler, var s: inspector.termio.Stream = .init(vt_handler);
.parser = .{ s.parser.osc_parser.alloc = surface.alloc;
.osc_parser = .{ break :stream s;
.alloc = surface.alloc,
},
},
}, },
}; };
} }

View File

@ -196,7 +196,7 @@ test "OSC generator valid" {
}; };
for (0..50) |_| { for (0..50) |_| {
const seq = try gen.next(&buf); const seq = try gen.next(&buf);
var parser: terminal.osc.Parser = .{}; var parser: terminal.osc.Parser = .init();
for (seq[2 .. seq.len - 1]) |c| parser.next(c); for (seq[2 .. seq.len - 1]) |c| parser.next(c);
try testing.expect(parser.end(null) != null); try testing.expect(parser.end(null) != null);
} }
@ -214,7 +214,7 @@ test "OSC generator invalid" {
}; };
for (0..50) |_| { for (0..50) |_| {
const seq = try gen.next(&buf); const seq = try gen.next(&buf);
var parser: terminal.osc.Parser = .{}; var parser: terminal.osc.Parser = .init();
for (seq[2 .. seq.len - 1]) |c| parser.next(c); for (seq[2 .. seq.len - 1]) |c| parser.next(c);
try testing.expect(parser.end(null) == null); try testing.expect(parser.end(null) == null);
} }

View File

@ -223,10 +223,12 @@ param_acc: u16 = 0,
param_acc_idx: u8 = 0, param_acc_idx: u8 = 0,
/// Parser for OSC sequences /// Parser for OSC sequences
osc_parser: osc.Parser = .{}, osc_parser: osc.Parser,
pub fn init() Parser { pub fn init() Parser {
return .{}; return .{
.osc_parser = .init(),
};
} }
pub fn deinit(self: *Parser) void { pub fn deinit(self: *Parser) void {

View File

@ -282,23 +282,23 @@ pub const Parser = struct {
/// Optional allocator used to accept data longer than MAX_BUF. /// Optional allocator used to accept data longer than MAX_BUF.
/// This only applies to some commands (e.g. OSC 52) that can /// This only applies to some commands (e.g. OSC 52) that can
/// reasonably exceed MAX_BUF. /// reasonably exceed MAX_BUF.
alloc: ?Allocator = null, alloc: ?Allocator,
/// Current state of the parser. /// Current state of the parser.
state: State = .empty, state: State,
/// Current command of the parser, this accumulates. /// Current command of the parser, this accumulates.
command: Command = undefined, command: Command,
/// Buffer that stores the input we see for a single OSC command. /// Buffer that stores the input we see for a single OSC command.
/// Slices in Command are offsets into this buffer. /// Slices in Command are offsets into this buffer.
buf: [MAX_BUF]u8 = undefined, buf: [MAX_BUF]u8,
buf_start: usize = 0, buf_start: usize,
buf_idx: usize = 0, buf_idx: usize,
buf_dynamic: ?*std.ArrayListUnmanaged(u8) = null, buf_dynamic: ?*std.ArrayListUnmanaged(u8),
/// True when a command is complete/valid to return. /// True when a command is complete/valid to return.
complete: bool = false, complete: bool,
/// Temporary state that is dependent on the current state. /// Temporary state that is dependent on the current state.
temp_state: union { temp_state: union {
@ -310,7 +310,7 @@ pub const Parser = struct {
/// Temporary state for key/value pairs /// Temporary state for key/value pairs
key: []const u8, key: []const u8,
} = undefined, },
// Maximum length of a single OSC command. This is the full OSC command // Maximum length of a single OSC command. This is the full OSC command
// sequence length (excluding ESC ]). This is arbitrary, I couldn't find // sequence length (excluding ESC ]). This is arbitrary, I couldn't find
@ -429,6 +429,38 @@ pub const Parser = struct {
conemu_progress_value, conemu_progress_value,
}; };
pub fn init() Parser {
var result: Parser = .{
.alloc = null,
.state = .empty,
.buf_start = 0,
.buf_idx = 0,
.buf_dynamic = null,
.complete = false,
// Keeping all our undefined values together so we can
// visually easily duplicate them in the Valgrind check below.
.command = undefined,
.buf = undefined,
.temp_state = undefined,
};
if (std.valgrind.runningOnValgrind() > 0) {
// Initialize our undefined fields so Valgrind can catch it.
// https://github.com/ziglang/zig/issues/19148
result.command = undefined;
result.buf = undefined;
result.temp_state = undefined;
}
return result;
}
pub fn initAlloc(alloc: Allocator) Parser {
var result: Parser = .init();
result.alloc = alloc;
return result;
}
/// This must be called to clean up any allocated memory. /// This must be called to clean up any allocated memory.
pub fn deinit(self: *Parser) void { pub fn deinit(self: *Parser) void {
self.reset(); self.reset();
@ -1590,7 +1622,7 @@ pub const Parser = struct {
test "OSC: change_window_title" { test "OSC: change_window_title" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
p.next('0'); p.next('0');
p.next(';'); p.next(';');
p.next('a'); p.next('a');
@ -1603,7 +1635,7 @@ test "OSC: change_window_title" {
test "OSC: change_window_title with 2" { test "OSC: change_window_title with 2" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
p.next('2'); p.next('2');
p.next(';'); p.next(';');
p.next('a'); p.next('a');
@ -1616,7 +1648,7 @@ test "OSC: change_window_title with 2" {
test "OSC: change_window_title with utf8" { test "OSC: change_window_title with utf8" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
p.next('2'); p.next('2');
p.next(';'); p.next(';');
// '—' EM DASH U+2014 (E2 80 94) // '—' EM DASH U+2014 (E2 80 94)
@ -1638,7 +1670,7 @@ test "OSC: change_window_title with utf8" {
test "OSC: change_window_title empty" { test "OSC: change_window_title empty" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
p.next('2'); p.next('2');
p.next(';'); p.next(';');
const cmd = p.end(null).?; const cmd = p.end(null).?;
@ -1649,7 +1681,7 @@ test "OSC: change_window_title empty" {
test "OSC: change_window_icon" { test "OSC: change_window_icon" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
p.next('1'); p.next('1');
p.next(';'); p.next(';');
p.next('a'); p.next('a');
@ -1662,7 +1694,7 @@ test "OSC: change_window_icon" {
test "OSC: prompt_start" { test "OSC: prompt_start" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "133;A"; const input = "133;A";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -1676,7 +1708,7 @@ test "OSC: prompt_start" {
test "OSC: prompt_start with single option" { test "OSC: prompt_start with single option" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "133;A;aid=14"; const input = "133;A;aid=14";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -1689,7 +1721,7 @@ test "OSC: prompt_start with single option" {
test "OSC: prompt_start with redraw disabled" { test "OSC: prompt_start with redraw disabled" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "133;A;redraw=0"; const input = "133;A;redraw=0";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -1702,7 +1734,7 @@ test "OSC: prompt_start with redraw disabled" {
test "OSC: prompt_start with redraw invalid value" { test "OSC: prompt_start with redraw invalid value" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "133;A;redraw=42"; const input = "133;A;redraw=42";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -1716,7 +1748,7 @@ test "OSC: prompt_start with redraw invalid value" {
test "OSC: prompt_start with continuation" { test "OSC: prompt_start with continuation" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "133;A;k=c"; const input = "133;A;k=c";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -1729,7 +1761,7 @@ test "OSC: prompt_start with continuation" {
test "OSC: prompt_start with secondary" { test "OSC: prompt_start with secondary" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "133;A;k=s"; const input = "133;A;k=s";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -1742,7 +1774,7 @@ test "OSC: prompt_start with secondary" {
test "OSC: end_of_command no exit code" { test "OSC: end_of_command no exit code" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "133;D"; const input = "133;D";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -1754,7 +1786,7 @@ test "OSC: end_of_command no exit code" {
test "OSC: end_of_command with exit code" { test "OSC: end_of_command with exit code" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "133;D;25"; const input = "133;D;25";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -1767,7 +1799,7 @@ test "OSC: end_of_command with exit code" {
test "OSC: prompt_end" { test "OSC: prompt_end" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "133;B"; const input = "133;B";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -1779,7 +1811,7 @@ test "OSC: prompt_end" {
test "OSC: end_of_input" { test "OSC: end_of_input" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "133;C"; const input = "133;C";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -1791,7 +1823,7 @@ test "OSC: end_of_input" {
test "OSC: OSC110: reset foreground color" { test "OSC: OSC110: reset foreground color" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "110"; const input = "110";
@ -1817,7 +1849,7 @@ test "OSC: OSC110: reset foreground color" {
test "OSC: OSC111: reset background color" { test "OSC: OSC111: reset background color" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "111"; const input = "111";
@ -1843,7 +1875,7 @@ test "OSC: OSC111: reset background color" {
test "OSC: OSC112: reset cursor color" { test "OSC: OSC112: reset cursor color" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "112"; const input = "112";
@ -1869,7 +1901,7 @@ test "OSC: OSC112: reset cursor color" {
test "OSC: OSC112: reset cursor color with semicolon" { test "OSC: OSC112: reset cursor color with semicolon" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "112;"; const input = "112;";
@ -1896,7 +1928,7 @@ test "OSC: OSC112: reset cursor color with semicolon" {
test "OSC: get/set clipboard" { test "OSC: get/set clipboard" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "52;s;?"; const input = "52;s;?";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -1910,7 +1942,7 @@ test "OSC: get/set clipboard" {
test "OSC: get/set clipboard (optional parameter)" { test "OSC: get/set clipboard (optional parameter)" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "52;;?"; const input = "52;;?";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -1924,7 +1956,7 @@ test "OSC: get/set clipboard (optional parameter)" {
test "OSC: get/set clipboard with allocator" { test "OSC: get/set clipboard with allocator" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "52;s;?"; const input = "52;s;?";
@ -1939,7 +1971,7 @@ test "OSC: get/set clipboard with allocator" {
test "OSC: clear clipboard" { test "OSC: clear clipboard" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .init();
defer p.deinit(); defer p.deinit();
const input = "52;;"; const input = "52;;";
@ -1954,7 +1986,7 @@ test "OSC: clear clipboard" {
test "OSC: report pwd" { test "OSC: report pwd" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "7;file:///tmp/example"; const input = "7;file:///tmp/example";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -1967,7 +1999,7 @@ test "OSC: report pwd" {
test "OSC: report pwd empty" { test "OSC: report pwd empty" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "7;"; const input = "7;";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -1979,7 +2011,7 @@ test "OSC: report pwd empty" {
test "OSC: pointer cursor" { test "OSC: pointer cursor" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "22;pointer"; const input = "22;pointer";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -1992,7 +2024,7 @@ test "OSC: pointer cursor" {
test "OSC: longer than buffer" { test "OSC: longer than buffer" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "0;" ++ "a" ** (Parser.MAX_BUF + 2); const input = "0;" ++ "a" ** (Parser.MAX_BUF + 2);
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2004,7 +2036,7 @@ test "OSC: longer than buffer" {
test "OSC: OSC10: report foreground color" { test "OSC: OSC10: report foreground color" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "10;?"; const input = "10;?";
@ -2032,7 +2064,7 @@ test "OSC: OSC10: report foreground color" {
test "OSC: OSC10: set foreground color" { test "OSC: OSC10: set foreground color" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "10;rgbi:0.0/0.5/1.0"; const input = "10;rgbi:0.0/0.5/1.0";
@ -2062,7 +2094,7 @@ test "OSC: OSC10: set foreground color" {
test "OSC: OSC11: report background color" { test "OSC: OSC11: report background color" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "11;?"; const input = "11;?";
@ -2090,7 +2122,7 @@ test "OSC: OSC11: report background color" {
test "OSC: OSC11: set background color" { test "OSC: OSC11: set background color" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "11;rgb:f/ff/ffff"; const input = "11;rgb:f/ff/ffff";
@ -2120,7 +2152,7 @@ test "OSC: OSC11: set background color" {
test "OSC: OSC12: report cursor color" { test "OSC: OSC12: report cursor color" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "12;?"; const input = "12;?";
@ -2148,7 +2180,7 @@ test "OSC: OSC12: report cursor color" {
test "OSC: OSC12: set cursor color" { test "OSC: OSC12: set cursor color" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "12;rgb:f/ff/ffff"; const input = "12;rgb:f/ff/ffff";
@ -2178,7 +2210,7 @@ test "OSC: OSC12: set cursor color" {
test "OSC: OSC4: get palette color 1" { test "OSC: OSC4: get palette color 1" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "4;1;?"; const input = "4;1;?";
@ -2204,7 +2236,7 @@ test "OSC: OSC4: get palette color 1" {
test "OSC: OSC4: get palette color 2" { test "OSC: OSC4: get palette color 2" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "4;1;?;2;?"; const input = "4;1;?;2;?";
@ -2238,7 +2270,7 @@ test "OSC: OSC4: get palette color 2" {
test "OSC: OSC4: set palette color 1" { test "OSC: OSC4: set palette color 1" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "4;17;rgb:aa/bb/cc"; const input = "4;17;rgb:aa/bb/cc";
@ -2267,7 +2299,7 @@ test "OSC: OSC4: set palette color 1" {
test "OSC: OSC4: set palette color 2" { test "OSC: OSC4: set palette color 2" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "4;17;rgb:aa/bb/cc;1;rgb:00/11/22"; const input = "4;17;rgb:aa/bb/cc;1;rgb:00/11/22";
@ -2308,7 +2340,7 @@ test "OSC: OSC4: set palette color 2" {
test "OSC: OSC4: get with invalid index 1" { test "OSC: OSC4: get with invalid index 1" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "4;1111;?;1;?"; const input = "4;1111;?;1;?";
@ -2333,7 +2365,7 @@ test "OSC: OSC4: get with invalid index 1" {
test "OSC: OSC4: get with invalid index 2" { test "OSC: OSC4: get with invalid index 2" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "4;5;?;1111;?;1;?"; const input = "4;5;?;1111;?;1;?";
@ -2367,7 +2399,7 @@ test "OSC: OSC4: get with invalid index 2" {
test "OSC: OSC4: multiple get 8a" { test "OSC: OSC4: multiple get 8a" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "4;0;?;1;?;2;?;3;?;4;?;5;?;6;?;7;?"; const input = "4;0;?;1;?;2;?;3;?;4;?;5;?;6;?;7;?";
@ -2449,7 +2481,7 @@ test "OSC: OSC4: multiple get 8a" {
test "OSC: OSC4: multiple get 8b" { test "OSC: OSC4: multiple get 8b" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "4;8;?;9;?;10;?;11;?;12;?;13;?;14;?;15;?"; const input = "4;8;?;9;?;10;?;11;?;12;?;13;?;14;?;15;?";
@ -2530,7 +2562,7 @@ test "OSC: OSC4: multiple get 8b" {
test "OSC: OSC4: set with invalid index" { test "OSC: OSC4: set with invalid index" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "4;256;#ffffff;1;#aabbcc"; const input = "4;256;#ffffff;1;#aabbcc";
@ -2559,7 +2591,7 @@ test "OSC: OSC4: set with invalid index" {
test "OSC: OSC4: mix get/set palette color" { test "OSC: OSC4: mix get/set palette color" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "4;17;rgb:aa/bb/cc;254;?"; const input = "4;17;rgb:aa/bb/cc;254;?";
@ -2596,7 +2628,7 @@ test "OSC: OSC4: mix get/set palette color" {
test "OSC: OSC4: incomplete color/spec 1" { test "OSC: OSC4: incomplete color/spec 1" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "4;17"; const input = "4;17";
@ -2613,7 +2645,7 @@ test "OSC: OSC4: incomplete color/spec 1" {
test "OSC: OSC4: incomplete color/spec 2" { test "OSC: OSC4: incomplete color/spec 2" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "4;17;?;42"; const input = "4;17;?;42";
@ -2638,7 +2670,7 @@ test "OSC: OSC4: incomplete color/spec 2" {
test "OSC: OSC104: reset palette color 1" { test "OSC: OSC104: reset palette color 1" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "104;17"; const input = "104;17";
@ -2663,7 +2695,7 @@ test "OSC: OSC104: reset palette color 1" {
test "OSC: OSC104: reset palette color 2" { test "OSC: OSC104: reset palette color 2" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "104;17;111"; const input = "104;17;111";
@ -2696,7 +2728,7 @@ test "OSC: OSC104: reset palette color 2" {
test "OSC: OSC104: invalid palette index" { test "OSC: OSC104: invalid palette index" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "104;ffff;111"; const input = "104;ffff;111";
@ -2721,7 +2753,7 @@ test "OSC: OSC104: invalid palette index" {
test "OSC: OSC104: empty palette index" { test "OSC: OSC104: empty palette index" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "104;;111"; const input = "104;;111";
@ -2746,7 +2778,7 @@ test "OSC: OSC104: empty palette index" {
test "OSC: conemu sleep" { test "OSC: conemu sleep" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;1;420"; const input = "9;1;420";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2760,7 +2792,7 @@ test "OSC: conemu sleep" {
test "OSC: conemu sleep with no value default to 100ms" { test "OSC: conemu sleep with no value default to 100ms" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;1;"; const input = "9;1;";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2774,7 +2806,7 @@ test "OSC: conemu sleep with no value default to 100ms" {
test "OSC: conemu sleep cannot exceed 10000ms" { test "OSC: conemu sleep cannot exceed 10000ms" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;1;12345"; const input = "9;1;12345";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2788,7 +2820,7 @@ test "OSC: conemu sleep cannot exceed 10000ms" {
test "OSC: conemu sleep invalid input" { test "OSC: conemu sleep invalid input" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;1;foo"; const input = "9;1;foo";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2802,7 +2834,7 @@ test "OSC: conemu sleep invalid input" {
test "OSC: show desktop notification" { test "OSC: show desktop notification" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;Hello world"; const input = "9;Hello world";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2816,7 +2848,7 @@ test "OSC: show desktop notification" {
test "OSC: show desktop notification with title" { test "OSC: show desktop notification with title" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "777;notify;Title;Body"; const input = "777;notify;Title;Body";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2830,7 +2862,7 @@ test "OSC: show desktop notification with title" {
test "OSC: conemu message box" { test "OSC: conemu message box" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;2;hello world"; const input = "9;2;hello world";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2843,7 +2875,7 @@ test "OSC: conemu message box" {
test "OSC: conemu message box invalid input" { test "OSC: conemu message box invalid input" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;2"; const input = "9;2";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2855,7 +2887,7 @@ test "OSC: conemu message box invalid input" {
test "OSC: conemu message box empty message" { test "OSC: conemu message box empty message" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;2;"; const input = "9;2;";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2868,7 +2900,7 @@ test "OSC: conemu message box empty message" {
test "OSC: conemu message box spaces only message" { test "OSC: conemu message box spaces only message" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;2; "; const input = "9;2; ";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2881,7 +2913,7 @@ test "OSC: conemu message box spaces only message" {
test "OSC: conemu change tab title" { test "OSC: conemu change tab title" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;3;foo bar"; const input = "9;3;foo bar";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2894,7 +2926,7 @@ test "OSC: conemu change tab title" {
test "OSC: conemu change tab reset title" { test "OSC: conemu change tab reset title" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;3;"; const input = "9;3;";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2908,7 +2940,7 @@ test "OSC: conemu change tab reset title" {
test "OSC: conemu change tab spaces only title" { test "OSC: conemu change tab spaces only title" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;3; "; const input = "9;3; ";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2922,7 +2954,7 @@ test "OSC: conemu change tab spaces only title" {
test "OSC: conemu change tab invalid input" { test "OSC: conemu change tab invalid input" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;3"; const input = "9;3";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2934,7 +2966,7 @@ test "OSC: conemu change tab invalid input" {
test "OSC: OSC9 progress set" { test "OSC: OSC9 progress set" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;4;1;100"; const input = "9;4;1;100";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2948,7 +2980,7 @@ test "OSC: OSC9 progress set" {
test "OSC: OSC9 progress set overflow" { test "OSC: OSC9 progress set overflow" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;4;1;900"; const input = "9;4;1;900";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2962,7 +2994,7 @@ test "OSC: OSC9 progress set overflow" {
test "OSC: OSC9 progress set single digit" { test "OSC: OSC9 progress set single digit" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;4;1;9"; const input = "9;4;1;9";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2976,7 +3008,7 @@ test "OSC: OSC9 progress set single digit" {
test "OSC: OSC9 progress set double digit" { test "OSC: OSC9 progress set double digit" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;4;1;94"; const input = "9;4;1;94";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -2990,7 +3022,7 @@ test "OSC: OSC9 progress set double digit" {
test "OSC: OSC9 progress set extra semicolon ignored" { test "OSC: OSC9 progress set extra semicolon ignored" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;4;1;100"; const input = "9;4;1;100";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3004,7 +3036,7 @@ test "OSC: OSC9 progress set extra semicolon ignored" {
test "OSC: OSC9 progress remove with no progress" { test "OSC: OSC9 progress remove with no progress" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;4;0;"; const input = "9;4;0;";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3018,7 +3050,7 @@ test "OSC: OSC9 progress remove with no progress" {
test "OSC: OSC9 progress remove with double semicolon" { test "OSC: OSC9 progress remove with double semicolon" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;4;0;;"; const input = "9;4;0;;";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3032,7 +3064,7 @@ test "OSC: OSC9 progress remove with double semicolon" {
test "OSC: OSC9 progress remove ignores progress" { test "OSC: OSC9 progress remove ignores progress" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;4;0;100"; const input = "9;4;0;100";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3046,7 +3078,7 @@ test "OSC: OSC9 progress remove ignores progress" {
test "OSC: OSC9 progress remove extra semicolon" { test "OSC: OSC9 progress remove extra semicolon" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;4;0;100;"; const input = "9;4;0;100;";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3059,7 +3091,7 @@ test "OSC: OSC9 progress remove extra semicolon" {
test "OSC: OSC9 progress error" { test "OSC: OSC9 progress error" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;4;2"; const input = "9;4;2";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3073,7 +3105,7 @@ test "OSC: OSC9 progress error" {
test "OSC: OSC9 progress error with progress" { test "OSC: OSC9 progress error with progress" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;4;2;100"; const input = "9;4;2;100";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3087,7 +3119,7 @@ test "OSC: OSC9 progress error with progress" {
test "OSC: OSC9 progress pause" { test "OSC: OSC9 progress pause" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;4;4"; const input = "9;4;4";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3101,7 +3133,7 @@ test "OSC: OSC9 progress pause" {
test "OSC: OSC9 progress pause with progress" { test "OSC: OSC9 progress pause with progress" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;4;4;100"; const input = "9;4;4;100";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3115,7 +3147,7 @@ test "OSC: OSC9 progress pause with progress" {
test "OSC: OSC9 conemu wait input" { test "OSC: OSC9 conemu wait input" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;5"; const input = "9;5";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3127,7 +3159,7 @@ test "OSC: OSC9 conemu wait input" {
test "OSC: OSC9 conemu wait ignores trailing characters" { test "OSC: OSC9 conemu wait ignores trailing characters" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "9;5;foo"; const input = "9;5;foo";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3139,7 +3171,7 @@ test "OSC: OSC9 conemu wait ignores trailing characters" {
test "OSC: empty param" { test "OSC: empty param" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "4;;"; const input = "4;;";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3151,7 +3183,7 @@ test "OSC: empty param" {
test "OSC: hyperlink" { test "OSC: hyperlink" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "8;;http://example.com"; const input = "8;;http://example.com";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3164,7 +3196,7 @@ test "OSC: hyperlink" {
test "OSC: hyperlink with id set" { test "OSC: hyperlink with id set" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "8;id=foo;http://example.com"; const input = "8;id=foo;http://example.com";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3178,7 +3210,7 @@ test "OSC: hyperlink with id set" {
test "OSC: hyperlink with empty id" { test "OSC: hyperlink with empty id" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "8;id=;http://example.com"; const input = "8;id=;http://example.com";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3192,7 +3224,7 @@ test "OSC: hyperlink with empty id" {
test "OSC: hyperlink with incomplete key" { test "OSC: hyperlink with incomplete key" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "8;id;http://example.com"; const input = "8;id;http://example.com";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3206,7 +3238,7 @@ test "OSC: hyperlink with incomplete key" {
test "OSC: hyperlink with empty key" { test "OSC: hyperlink with empty key" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "8;=value;http://example.com"; const input = "8;=value;http://example.com";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3220,7 +3252,7 @@ test "OSC: hyperlink with empty key" {
test "OSC: hyperlink with empty key and id" { test "OSC: hyperlink with empty key and id" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "8;=value:id=foo;http://example.com"; const input = "8;=value:id=foo;http://example.com";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3234,7 +3266,7 @@ test "OSC: hyperlink with empty key and id" {
test "OSC: hyperlink with empty uri" { test "OSC: hyperlink with empty uri" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "8;id=foo;"; const input = "8;id=foo;";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3246,7 +3278,7 @@ test "OSC: hyperlink with empty uri" {
test "OSC: hyperlink end" { test "OSC: hyperlink end" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
const input = "8;;"; const input = "8;;";
for (input) |ch| p.next(ch); for (input) |ch| p.next(ch);
@ -3259,7 +3291,7 @@ test "OSC: kitty color protocol" {
const testing = std.testing; const testing = std.testing;
const Kind = kitty.color.Kind; const Kind = kitty.color.Kind;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "21;foreground=?;background=rgb:f0/f8/ff;cursor=aliceblue;cursor_text;visual_bell=;selection_foreground=#xxxyyzz;selection_background=?;selection_background=#aabbcc;2=?;3=rgbi:1.0/1.0/1.0"; const input = "21;foreground=?;background=rgb:f0/f8/ff;cursor=aliceblue;cursor_text;visual_bell=;selection_foreground=#xxxyyzz;selection_background=?;selection_background=#aabbcc;2=?;3=rgbi:1.0/1.0/1.0";
@ -3330,7 +3362,7 @@ test "OSC: kitty color protocol" {
test "OSC: kitty color protocol without allocator" { test "OSC: kitty color protocol without allocator" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{}; var p: Parser = .init();
defer p.deinit(); defer p.deinit();
const input = "21;foreground=?"; const input = "21;foreground=?";
@ -3341,7 +3373,7 @@ test "OSC: kitty color protocol without allocator" {
test "OSC: kitty color protocol double reset" { test "OSC: kitty color protocol double reset" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "21;foreground=?;background=rgb:f0/f8/ff;cursor=aliceblue;cursor_text;visual_bell=;selection_foreground=#xxxyyzz;selection_background=?;selection_background=#aabbcc;2=?;3=rgbi:1.0/1.0/1.0"; const input = "21;foreground=?;background=rgb:f0/f8/ff;cursor=aliceblue;cursor_text;visual_bell=;selection_foreground=#xxxyyzz;selection_background=?;selection_background=#aabbcc;2=?;3=rgbi:1.0/1.0/1.0";
@ -3357,7 +3389,7 @@ test "OSC: kitty color protocol double reset" {
test "OSC: kitty color protocol reset after invalid" { test "OSC: kitty color protocol reset after invalid" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "21;foreground=?;background=rgb:f0/f8/ff;cursor=aliceblue;cursor_text;visual_bell=;selection_foreground=#xxxyyzz;selection_background=?;selection_background=#aabbcc;2=?;3=rgbi:1.0/1.0/1.0"; const input = "21;foreground=?;background=rgb:f0/f8/ff;cursor=aliceblue;cursor_text;visual_bell=;selection_foreground=#xxxyyzz;selection_background=?;selection_background=#aabbcc;2=?;3=rgbi:1.0/1.0/1.0";
@ -3378,7 +3410,7 @@ test "OSC: kitty color protocol reset after invalid" {
test "OSC: kitty color protocol no key" { test "OSC: kitty color protocol no key" {
const testing = std.testing; const testing = std.testing;
var p: Parser = .{ .alloc = testing.allocator }; var p: Parser = .initAlloc(testing.allocator);
defer p.deinit(); defer p.deinit();
const input = "21;"; const input = "21;";

View File

@ -47,8 +47,16 @@ pub fn Stream(comptime Handler: type) type {
}; };
handler: Handler, handler: Handler,
parser: Parser = .{}, parser: Parser,
utf8decoder: UTF8Decoder = .{}, utf8decoder: UTF8Decoder,
pub fn init(h: Handler) Self {
return .{
.handler = h,
.parser = .init(),
.utf8decoder = .{},
};
}
pub fn deinit(self: *Self) void { pub fn deinit(self: *Self) void {
self.parser.deinit(); self.parser.deinit();
@ -1842,7 +1850,7 @@ test "stream: print" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.next('x'); try s.next('x');
try testing.expectEqual(@as(u21, 'x'), s.handler.c.?); try testing.expectEqual(@as(u21, 'x'), s.handler.c.?);
} }
@ -1856,7 +1864,7 @@ test "simd: print invalid utf-8" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice(&.{0xFF}); try s.nextSlice(&.{0xFF});
try testing.expectEqual(@as(u21, 0xFFFD), s.handler.c.?); try testing.expectEqual(@as(u21, 0xFFFD), s.handler.c.?);
} }
@ -1870,7 +1878,7 @@ test "simd: complete incomplete utf-8" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice(&.{0xE0}); // 3 byte try s.nextSlice(&.{0xE0}); // 3 byte
try testing.expect(s.handler.c == null); try testing.expect(s.handler.c == null);
try s.nextSlice(&.{0xA0}); // still incomplete try s.nextSlice(&.{0xA0}); // still incomplete
@ -1888,7 +1896,7 @@ test "stream: cursor right (CUF)" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1B[C"); try s.nextSlice("\x1B[C");
try testing.expectEqual(@as(u16, 1), s.handler.amount); try testing.expectEqual(@as(u16, 1), s.handler.amount);
@ -1913,7 +1921,7 @@ test "stream: dec set mode (SM) and reset mode (RM)" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1B[?6h"); try s.nextSlice("\x1B[?6h");
try testing.expectEqual(@as(modes.Mode, .origin), s.handler.mode); try testing.expectEqual(@as(modes.Mode, .origin), s.handler.mode);
@ -1935,7 +1943,7 @@ test "stream: ansi set mode (SM) and reset mode (RM)" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1B[4h"); try s.nextSlice("\x1B[4h");
try testing.expectEqual(@as(modes.Mode, .insert), s.handler.mode.?); try testing.expectEqual(@as(modes.Mode, .insert), s.handler.mode.?);
@ -1957,7 +1965,7 @@ test "stream: ansi set mode (SM) and reset mode (RM) with unknown value" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1B[6h"); try s.nextSlice("\x1B[6h");
try testing.expect(s.handler.mode == null); try testing.expect(s.handler.mode == null);
@ -1977,7 +1985,7 @@ test "stream: restore mode" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
for ("\x1B[?42r") |c| try s.next(c); for ("\x1B[?42r") |c| try s.next(c);
try testing.expect(!s.handler.called); try testing.expect(!s.handler.called);
} }
@ -1992,7 +2000,7 @@ test "stream: pop kitty keyboard with no params defaults to 1" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
for ("\x1B[<u") |c| try s.next(c); for ("\x1B[<u") |c| try s.next(c);
try testing.expectEqual(@as(u16, 1), s.handler.n); try testing.expectEqual(@as(u16, 1), s.handler.n);
} }
@ -2007,7 +2015,7 @@ test "stream: DECSCA" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
{ {
for ("\x1B[\"q") |c| try s.next(c); for ("\x1B[\"q") |c| try s.next(c);
try testing.expectEqual(ansi.ProtectedMode.off, s.handler.v.?); try testing.expectEqual(ansi.ProtectedMode.off, s.handler.v.?);
@ -2042,7 +2050,7 @@ test "stream: DECED, DECSED" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
{ {
for ("\x1B[?J") |c| try s.next(c); for ("\x1B[?J") |c| try s.next(c);
try testing.expectEqual(csi.EraseDisplay.below, s.handler.mode.?); try testing.expectEqual(csi.EraseDisplay.below, s.handler.mode.?);
@ -2118,7 +2126,7 @@ test "stream: DECEL, DECSEL" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
{ {
for ("\x1B[?K") |c| try s.next(c); for ("\x1B[?K") |c| try s.next(c);
try testing.expectEqual(csi.EraseLine.right, s.handler.mode.?); try testing.expectEqual(csi.EraseLine.right, s.handler.mode.?);
@ -2177,7 +2185,7 @@ test "stream: DECSCUSR" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1B[ q"); try s.nextSlice("\x1B[ q");
try testing.expect(s.handler.style.? == .default); try testing.expect(s.handler.style.? == .default);
@ -2198,7 +2206,7 @@ test "stream: DECSCUSR without space" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1B[q"); try s.nextSlice("\x1B[q");
try testing.expect(s.handler.style == null); try testing.expect(s.handler.style == null);
@ -2215,7 +2223,7 @@ test "stream: XTSHIFTESCAPE" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1B[>2s"); try s.nextSlice("\x1B[>2s");
try testing.expect(s.handler.escape == null); try testing.expect(s.handler.escape == null);
@ -2245,13 +2253,13 @@ test "stream: change window title with invalid utf-8" {
}; };
{ {
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1b]2;abc\x1b\\"); try s.nextSlice("\x1b]2;abc\x1b\\");
try testing.expect(s.handler.seen); try testing.expect(s.handler.seen);
} }
{ {
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1b]2;abc\xc0\x1b\\"); try s.nextSlice("\x1b]2;abc\xc0\x1b\\");
try testing.expect(!s.handler.seen); try testing.expect(!s.handler.seen);
} }
@ -2268,7 +2276,7 @@ test "stream: insert characters" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
for ("\x1B[42@") |c| try s.next(c); for ("\x1B[42@") |c| try s.next(c);
try testing.expect(s.handler.called); try testing.expect(s.handler.called);
@ -2294,7 +2302,7 @@ test "stream: SCOSC" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
for ("\x1B[s") |c| try s.next(c); for ("\x1B[s") |c| try s.next(c);
try testing.expect(s.handler.called); try testing.expect(s.handler.called);
} }
@ -2309,7 +2317,7 @@ test "stream: SCORC" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
for ("\x1B[u") |c| try s.next(c); for ("\x1B[u") |c| try s.next(c);
try testing.expect(s.handler.called); try testing.expect(s.handler.called);
} }
@ -2323,7 +2331,7 @@ test "stream: too many csi params" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; 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"); try s.nextSlice("\x1B[1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1C");
} }
@ -2335,7 +2343,7 @@ test "stream: csi param too long" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1B[1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111C"); try s.nextSlice("\x1B[1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111C");
} }
@ -2348,7 +2356,7 @@ test "stream: send report with CSI t" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1b[14t"); try s.nextSlice("\x1b[14t");
try testing.expectEqual(csi.SizeReportStyle.csi_14_t, s.handler.style); try testing.expectEqual(csi.SizeReportStyle.csi_14_t, s.handler.style);
@ -2372,7 +2380,7 @@ test "stream: invalid CSI t" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1b[19t"); try s.nextSlice("\x1b[19t");
try testing.expectEqual(null, s.handler.style); try testing.expectEqual(null, s.handler.style);
@ -2387,7 +2395,7 @@ test "stream: CSI t push title" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1b[22;0t"); try s.nextSlice("\x1b[22;0t");
try testing.expectEqual(csi.TitlePushPop{ try testing.expectEqual(csi.TitlePushPop{
@ -2405,7 +2413,7 @@ test "stream: CSI t push title with explicit window" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1b[22;2t"); try s.nextSlice("\x1b[22;2t");
try testing.expectEqual(csi.TitlePushPop{ try testing.expectEqual(csi.TitlePushPop{
@ -2423,7 +2431,7 @@ test "stream: CSI t push title with explicit icon" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1b[22;1t"); try s.nextSlice("\x1b[22;1t");
try testing.expectEqual(null, s.handler.op); try testing.expectEqual(null, s.handler.op);
@ -2438,7 +2446,7 @@ test "stream: CSI t push title with index" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1b[22;0;5t"); try s.nextSlice("\x1b[22;0;5t");
try testing.expectEqual(csi.TitlePushPop{ try testing.expectEqual(csi.TitlePushPop{
@ -2456,7 +2464,7 @@ test "stream: CSI t pop title" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1b[23;0t"); try s.nextSlice("\x1b[23;0t");
try testing.expectEqual(csi.TitlePushPop{ try testing.expectEqual(csi.TitlePushPop{
@ -2474,7 +2482,7 @@ test "stream: CSI t pop title with explicit window" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1b[23;2t"); try s.nextSlice("\x1b[23;2t");
try testing.expectEqual(csi.TitlePushPop{ try testing.expectEqual(csi.TitlePushPop{
@ -2492,7 +2500,7 @@ test "stream: CSI t pop title with explicit icon" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1b[23;1t"); try s.nextSlice("\x1b[23;1t");
try testing.expectEqual(null, s.handler.op); try testing.expectEqual(null, s.handler.op);
@ -2507,7 +2515,7 @@ test "stream: CSI t pop title with index" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1b[23;0;5t"); try s.nextSlice("\x1b[23;0;5t");
try testing.expectEqual(csi.TitlePushPop{ try testing.expectEqual(csi.TitlePushPop{
@ -2525,7 +2533,7 @@ test "stream CSI W clear tab stops" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1b[2W"); try s.nextSlice("\x1b[2W");
try testing.expectEqual(csi.TabClear.current, s.handler.op.?); try testing.expectEqual(csi.TabClear.current, s.handler.op.?);
@ -2543,7 +2551,7 @@ test "stream CSI W tab set" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1b[W"); try s.nextSlice("\x1b[W");
try testing.expect(s.handler.called); try testing.expect(s.handler.called);
@ -2570,7 +2578,7 @@ test "stream CSI ? W reset tab stops" {
} }
}; };
var s: Stream(H) = .{ .handler = .{} }; var s: Stream(H) = .init(.{});
try s.nextSlice("\x1b[?2W"); try s.nextSlice("\x1b[?2W");
try testing.expect(!s.handler.reset); try testing.expect(!s.handler.reset);

View File

@ -313,15 +313,12 @@ pub fn init(self: *Termio, alloc: Allocator, opts: termio.Options) !void {
.size = opts.size, .size = opts.size,
.backend = backend, .backend = backend,
.mailbox = opts.mailbox, .mailbox = opts.mailbox,
.terminal_stream = .{ .terminal_stream = stream: {
.handler = handler, var s: terminalpkg.Stream(StreamHandler) = .init(handler);
.parser = .{ // Populate the OSC parser allocator (optional) because
.osc_parser = .{ // we want to support large OSC payloads such as OSC 52.
// Populate the OSC parser allocator (optional) because s.parser.osc_parser.alloc = alloc;
// we want to support large OSC payloads such as OSC 52. break :stream s;
.alloc = alloc,
},
},
}, },
.thread_enter_state = thread_enter_state, .thread_enter_state = thread_enter_state,
}; };