Zig's KeyEvent.utf8 and the embedded API's key/preedit text are byte slices passed through to key encoding and the pty; the port converted them lossily to UTF-8. - KeyEvent.utf8 is &[u8] end to end (ghostty-input encoder, core, ghostty-lib C API, libghostty-vt key events, GTK callers). Where Zig validates with Utf8View (alternates, modify-other-keys, ctrl CSI-u, associated text, binding unicode lookup) invalid text takes the same "no UTF-8" fallback. - Invalid preedit UTF-8 behaves like Zig's `try Utf8View.init`: the prior preedit is cleared and marked dirty, the callback returns an error (logged by the C API) and no preedit is set. - The inspector key widget shows invalid key text lossily, display only. Test Plan: - cargo test --workspace --no-fail-fast (3407 passed) - cargo test -p ghostty-lib --features test-platform (C-API key text 0xff 0xfe reaches the pty unchanged) - just check-macos (both), just check-windows, just check-wasm
1.9 KiB
1.9 KiB
Z10: byte-typed key text and preedit
KeyEvent.utf8 is now &[u8] (Zig []const u8) end to end; the Z9 "documented limit" for C key text / preedit is gone.
ghostty-input:KeyEvent.utf8: &[u8];key_encodewrites the bytes unchanged. Where Zig validates withUtf8View.init ... catch(plain-text control scan, kitty alternates, modify-other-keys, ctrl CSI-u, kitty associated text, binding unicode lookup) invalid UTF-8 takes the same "no UTF-8" fallback (utf8_chars). Legacy/kitty "send text directly" paths write the raw bytes.ghostty-core:OwnedKeyEvent.utf8: Vec<u8>;Surface::preedit_callback(Option<&[u8]>)(and theRuntimeSurfacetrait inghostty-apprt). Preedit bytes are decoded lossily (U+FFFD) for the renderer codepoints only. Deviation: Zig returns an error on invalid preedit; we render replacement chars instead (no panic).ghostty-lib:ghostty_surface_keycopiestextas raw bytes;ghostty_surface_preeditpasses bytes.ghostty_surface_textwas already bytes.ghostty-vt-capi:ghostty_key_event_*no longer truncates invalid UTF-8 to its valid prefix; passes bytes through.- Inspector key widget shows invalid text lossily (display only). GTK callers pass
as_bytes()of valid UTF-8. - Tests:
ghostty-lib/tests/surface.rs::key_text_and_preedit_are_bytes_not_lossy_utf8(key textff fereaches the pty),ghostty-core/tests/e2e_ime.rs::preedit_with_invalid_utf8_is_replaced_for_display_only,ghostty-inputinvalid_utf8_*encoder tests. Existing tests only changed mechanically ("x"->"x".as_bytes()).
Orchestrator follow-up
Preedit with invalid UTF-8 now matches Zig exactly instead of rendering
U+FFFD: preedit_callback clears the prior preedit, marks it dirty and
returns an error (Zig: try std.unicode.Utf8View.init(text)); the C API
logs it like embedded.zig. Test: preedit_with_invalid_utf8_is_an_error_and_clears_prior.