Commit ce8b2bd
Jay Hemnani
·
2026-10-16 09:27:21 -0400 EDT
parent 36e024e
fix: keep UTF-8 text in run and tail output (#274) stripAnsi fed each byte to the bare VT parser, which expects decoded input. It dropped every non-ASCII byte, and a UTF-8 continuation byte in the C1 range (Ý is C3 9D, 0x9D is the 8-bit OSC introducer) started a sequence that swallowed the text after it. Pass bytes >= 0x80 through when the parser is not inside a sequence.
1 files changed,
+20,
-0
+20,
-0
| ... | ... | @@ -493,6 +493,11 @@ pub fn stripAnsi(alloc: std.mem.Allocator, data: []const u8) ![]const u8 { | |
| 493 | 493 | ||
| 494 | 494 | var parser = ghostty_vt.Parser.init(); | |
| 495 | 495 | for (data) |c| { | |
| 496 | + | // Bytes >= 0x80 outside a sequence are UTF-8 text, not C1 controls. | |
| 497 | + | if (c >= 0x80 and parser.state == .ground) { | |
| 498 | + | result.append(alloc, c) catch unreachable; | |
| 499 | + | continue; | |
| 500 | + | } | |
| 496 | 501 | const actions = parser.next(c); | |
| 497 | 502 | for (actions) |action_opt| { | |
| 498 | 503 | const action = action_opt orelse continue; |
| ... | ... | @@ -2294,6 +2299,21 @@ test "stripAnsi: only escape sequences" { | |
| 2294 | 2299 | try testing.expectEqualStrings("", result); | |
| 2295 | 2300 | } | |
| 2296 | 2301 | ||
| 2302 | + | test "stripAnsi: keeps UTF-8 text" { | |
| 2303 | + | const alloc = testing.allocator; | |
| 2304 | + | const result = try stripAnsi(alloc, "\x1b[1mcafé\x1b[0m – 日本 🎉\n"); | |
| 2305 | + | defer alloc.free(result); | |
| 2306 | + | try testing.expectEqualStrings("café – 日本 🎉\n", result); | |
| 2307 | + | } | |
| 2308 | + | ||
| 2309 | + | test "stripAnsi: UTF-8 bytes do not start escape sequences" { | |
| 2310 | + | const alloc = testing.allocator; | |
| 2311 | + | // Ý is C3 9D, and 0x9D on its own is the 8-bit OSC introducer | |
| 2312 | + | const result = try stripAnsi(alloc, "Ýmir\nline two\n"); | |
| 2313 | + | defer alloc.free(result); | |
| 2314 | + | try testing.expectEqualStrings("Ýmir\nline two\n", result); | |
| 2315 | + | } | |
| 2316 | + | ||
| 2297 | 2317 | test "isUserInput: kitty keyboard status reply is a terminal response" { | |
| 2298 | 2318 | // CSI ? flags u answers the program's CSI ? u query; no key was pressed | |
| 2299 | 2319 | try testing.expect(!isUserInput("\x1b[?1u")); |