macOS: switching input source during CJK composition inserts the uncommitted text instead of sending it as keys (breaks nvim normal mode) #13193
-
Issue DescriptionIn nvim normal mode, while typing with a CJK system input method and the composition is still uncommitted (characters typed, no candidate picked yet), switching the input method (Caps Lock or Fn) inserts the uncommitted characters directly into the buffer. In other words, text gets inserted while I'm in normal mode. On other terminals (Terminal.app, WezTerm, etc.) the uncommitted characters are instead sent as key events, so nvim reads them as normal-mode commands. Example: type jjjj, then switch input method: on other terminals the cursor moves down four lines, while on Ghostty jjjj gets inserted into the buffer. Expected BehaviorOn an input-method switch, the uncommitted characters should reach nvim as normal key input, so nvim interprets them in its current mode. In normal mode that means they run as commands, the same as Terminal.app and WezTerm. wezterm2026-07-05.12.29.23.movActual BehaviorIn nvim normal mode, while typing with a CJK system input method and the composition is still uncommitted (characters typed, no candidate picked yet), switching the input method (Caps Lock or Fn) inserts the uncommitted characters directly into the buffer. In other words, text gets inserted while I'm in normal mode. 2026-07-05.12.26.27.movReproduction Steps
Result: jjj gets inserted into the buffer. Ghostty LogsNo response Ghostty VersionOS Version InformationDarwin Kernel Version 25.5.0 macOS Tahoe 26.5.1 (25F80) arm64 (Linux only) Display ServerNone (Linux only) Desktop Environment/Window ManagerNo response Minimal Ghostty Configuration--config-default-files=falseAdditional Relevant Configurationneovim with any version( I tried in 0.10.* ~ 0.12.*, all repro ) I acknowledge that:
|
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 4 replies
-
|
I've read the code. I think the root cause is that switching the input source commits the preedit through the text path (ghostty_surface_text) instead of the key path (ghostty_surface_key). Ghostty sends input to the pty two ways:
Normal preedit commits happen inside keyDown and use the key path. committedPreeditTextAction (SurfaceView_AppKit.swift:1492) sends the committed text via ghostty_surface_key, so nvim interprets it per mode. That part is correct. When you switch input source mid-composition, the IME force-commits the preedit by calling insertText outside a keyDown. keyTextAccumulator is nil, so it falls through to sendText (SurfaceView_AppKit.swift:2056) → ghostty_surface_text (Ghostty.Surface.swift:41). The uncommitted reading goes out as pasted text and nvim inserts it, instead of going out as keys nvim would interpret. That's jjjj getting inserted vs. jjjj moving the cursor down. I haven't built it to confirm the exact runtime call, but the two paths match the observed behavior. A fix would likely route the out-of-keyDown preedit commit through the key path, the way committedPreeditTextAction already does, instead of sendText, with a guard so genuine text insertion (dictation, emoji viewer) still uses ghostty_surface_text. |
Beta Was this translation helpful? Give feedback.
-
|
duplicate of #12278 |
Beta Was this translation helpful? Give feedback.
#13195