diff --git a/src/terminal/osc.zig b/src/terminal/osc.zig index 03d3baf99..c8f42b66a 100644 --- a/src/terminal/osc.zig +++ b/src/terminal/osc.zig @@ -584,6 +584,28 @@ test "OSC: change_window_title with 2" { try testing.expectEqualStrings("ab", cmd.change_window_title); } +test "OSC: change_window_title with utf8" { + const testing = std.testing; + + var p: Parser = .{}; + p.next('2'); + p.next(';'); + // '—' EM DASH U+2014 (E2 80 94) + p.next(0xE2); + p.next(0x80); + p.next(0x94); + + p.next(' '); + // '‐' HYPHEN U+2010 (E2 80 90) + // Intententionally chosen to conflict with the 0x90 C1 control + p.next(0xE2); + p.next(0x80); + p.next(0x90); + const cmd = p.end(null).?; + try testing.expect(cmd == .change_window_title); + try testing.expectEqualStrings("— ‐", cmd.change_window_title); +} + test "OSC: prompt_start" { const testing = std.testing; diff --git a/src/terminal/parse_table.zig b/src/terminal/parse_table.zig index 094128cc7..e7542b062 100644 --- a/src/terminal/parse_table.zig +++ b/src/terminal/parse_table.zig @@ -345,7 +345,7 @@ fn genTable() Table { range(&result, 0, 0x06, source, source, .ignore); range(&result, 0x08, 0x17, source, source, .ignore); range(&result, 0x1C, 0x1F, source, source, .ignore); - range(&result, 0x20, 0x7F, source, source, .osc_put); + range(&result, 0x20, 0xFF, source, source, .osc_put); // XTerm accepts either BEL or ST for terminating OSC // sequences, and when returning information, uses the same @@ -381,7 +381,12 @@ fn single(t: *OptionalTable, c: u8, s0: State, s1: State, a: Action) void { fn range(t: *OptionalTable, from: u8, to: u8, s0: State, s1: State, a: Action) void { var i = from; - while (i <= to) : (i += 1) single(t, i, s0, s1, a); + while (i <= to) : (i += 1) { + single(t, i, s0, s1, a); + // If 'to' is 0xFF, our next pass will overflow. Return early to prevent + // the loop from executing it's continue expression + if (i == to) break; + } } fn transition(state: State, action: Action) Transition {