Skip to content

Fix CJK IME marked text commit handling - #4483

Closed
knu wants to merge 3 commits into
manaflow-ai:mainfrom
knu:fix-cjk-ime-marked-commit
Closed

knu wants to merge 3 commits into
manaflow-ai:mainfrom
knu:fix-cjk-ime-marked-commit

Conversation

@knu

@knu knu commented May 21, 2026 •

Copy link
Copy Markdown

Summary

Send the text committed by IME interpretation when marked text is active, instead of dropping it and forwarding only the original key event to the terminal.

Covers Japanese IME commit paths triggered by control-key shortcuts, including both full and partial preedit commits.

Testing

Included in this PR.

Demo Video

For UI or behavior changes, include a short demo video (GitHub upload, Loom, or other direct link).

  • Video URL or attachment:

Before:
before
Committed text is unexpectedly lost, and the trigger shortcut (Ctrl+J) leaks to the terminal.

After:
after
Committed text is properly sent to the terminal, and the trigger shortcut (Ctrl+J) is consumed in IME.

Review Trigger (Copy/Paste as PR comment)

@codex review
@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

Checklist

  • I tested the change locally
  • I added or updated tests for behavior changes
  • I updated docs/changelog if needed
  • I requested bot reviews after my latest commit (copy/paste block above or equivalent)
  • All code review bot comments are resolved
  • All human review comments are resolved

View with Codesmith Autofix with Codesmith
Need help on this PR? Tag @codesmith with what you need. Autofix is disabled.


Summary by cubic

Fixes CJK IME commit handling so committed text is sent to the terminal and the trigger shortcut is fully consumed (down and up). Also restores legacy config fallback: load legacy config when config.ghostty is missing or empty.

  • Bug Fixes
    • Send IME-committed text via a synthetic text event (keyCode 0, no mods) when marked text is active; mark the trigger as IME-consumed so keyDown/keyUp don’t leak to the terminal.
    • Preserve remaining preedit segments after partial commits; add tests covering Ctrl+J commit and its keyUp.
    • Load legacy config if config.ghostty is absent or empty and the legacy file is non-empty; update discovery logic and tests.

Written for commit 1dc3a1f. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes

    • Improved IME composition handling so committed text chunks are properly routed and sent during marked/preedit input.
    • Prevented a spurious nil-text fallback key event from being emitted while IME composition is active, preserving preedit state.
  • Tests

    • Added a test validating that Control+J commits only the IME-committed text and does not produce extra key events during marked text sessions.

Review Change Stack

@vercel

vercel Bot commented May 21, 2026

Copy link
Copy Markdown

@knu is attempting to deploy a commit to the Manaflow Team on Vercel.

A member of the Team first needs to authorize it.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@coderabbitai

coderabbitai Bot commented May 21, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

When marked/preedit IME text is active, committed text chunks are forwarded via a new helper that builds explicit Ghostty key events; the nil-text fallback is suppressed during marked text. A new XCTest verifies Control‑J forwards only the committed segment while leaving remaining marked text.

Changes

Committed IME Text Routing

Layer / File(s) Summary
Committed IME text helper and keyDown integration
Sources/GhosttyTerminalView.swift
Adds sendCommittedIMETextToSurface(_:action:sourceEvent:) which builds a ghostty_input_key_s for committed IME text (keycode = 0, consumed_mods = none, composing = false, text populated). keyDown iteration now routes committed chunks through this helper when markedTextBefore is true and only runs the nil-text fallback when markedTextBefore is false.
Test for Control-J committed text behavior
cmuxTests/CJKIMEMarkedSelectionTests.swift
Adds testControlJCommitWhileMarkedTextIsActiveSendsOnlyCommittedText() which simulates a CJK IME commit + remaining preedit, sends Control+J, and asserts Ghostty receives only the committed text ("日本") while the residual preedit ("語") remains marked.

Sequence Diagram(s)

sequenceDiagram
  participant KeyDown as keyDown Handler
  participant Accum as accumulatedText Iteration
  participant Helper as sendCommittedIMETextToSurface
  participant Ghostty as Ghostty Surface
  KeyDown->>Accum: iterate accumulated text chunks
  Accum->>Accum: check markedTextBefore
  Accum->>Helper: if chunk committed and marked, forward committed text
  Helper->>Ghostty: send ghostty_input_key_s (text, composing=false)
  Ghostty->>Ghostty: handle input
  Accum->>KeyDown: continue processing
Loading

Possibly related PRs

  • manaflow-ai/cmux#4382: Overlaps in modifications to GhosttyTerminalView's IME/text-forwarding logic and committed vs. marked handling.
  • manaflow-ai/cmux#3986: Also modifies GhosttyTerminalView.keyDown accumulated/committed text forwarding behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I nibble at the IME stream,
Commit some kanji, leave a dream—
Control‑J hops the finished part,
While the preedit keeps its quiet heart.


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
Cmux Swift Logging ❌ Error NSLog("[FOCUSDBG]...") at line 7360 of Sources/GhosttyTerminalView.swift violates swift-logging.md: NSLog in app code must be guarded by #if DEBUG, not runtime checks. Replace the NSLog with compile-time #if DEBUG guard, or use cmux's Logger with appropriate visibility controls.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The pull request description covers the main requirements but is missing the demo video URL and has incomplete checklist items that should have been addressed. Add a video URL/attachment for the demo or explicitly explain why video cannot be provided. Ensure all checklist items are reviewed; mark incomplete items or explain why they don't apply before merging.
✅ Passed checks (15 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed New private method sendCommittedIMETextToSurface added to GhosttyNSView (NSView UI type, implicitly @MainActor). All parameters are Sendable. No Swift 6 actor isolation violations introduced.
Cmux Swift Blocking Runtime ✅ Passed No blocking runtime primitives introduced. New sendCommittedIMETextToSurface() method has no sleep/sync/semaphore calls. Test RunLoop usage is allowed deterministic test scaffolding.
Cmux No Hacky Sleeps ✅ Passed PR modifies only Swift files; this check explicitly excludes Swift code and applies only to TypeScript, JavaScript, shell, and non-Swift build/runtime scripts.
Cmux Algorithmic Complexity ✅ Passed All changes use O(1) operations or iterate over bounded IME composition text; no nested scans or unbounded collection iterations violate the algorithmic complexity rules.
Cmux Swift Concurrency ✅ Passed New code is synchronous IME text helper and XCTest regression test; no legacy async patterns (DispatchQueue, Task, Combine, completion handlers) introduced.
Cmux Swift @Concurrent ✅ Passed The new sendCommittedIMETextToSurface method is synchronous UI-bound code on GhosttyNSView. No async work, no missing @concurrent, no violations of the concurrent annotation rules.
Cmux Swift File And Package Boundaries ✅ Passed Focused IME bug fix adding only 37 lines to oversized file, well below 250-line threshold. Matches allowed case for small focused fixes with clear extraction path via private helper.
Cmux User-Facing Error Privacy ✅ Passed Only internal IME routing logic and debug code (wrapped in #if DEBUG). No user-facing errors, vendor names, or sensitive data exposed. Test code is exempt.
Cmux Full Internationalization ✅ Passed PR adds only internal IME handling logic and test code; no user-facing strings, localization keys, or string catalog changes introduced.
Cmux Swiftui State Layout ✅ Passed PR modifies AppKit bridge code (IME handling in GhosttyNSView) with no new SwiftUI state patterns or violations detected.
Cmux Architecture Rethink ✅ Passed Adds platform bridge Set (imeConsumedKeyUps) matching established copy-mode pattern for coordinating OS keyDown/keyUp callbacks; no timing deps, observers, or new owners.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR adds hidden/internal headless startup window (alphaValue=0, ignoresMouseEvents=true) and test fixtures. Both are explicitly allowed per swift-auxiliary-window-close-shortcuts.md.
Title check ✅ Passed The title clearly and concisely describes the main change: fixing CJK IME marked text commit handling, which matches the primary objective of properly routing committed text through IME interpretation.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented May 21, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes two independent bugs: (1) CJK IME-committed text was being dropped and the trigger shortcut (e.g., Ctrl+J) was leaking to the terminal when marked text was active; (2) the legacy Ghostty config was not loaded when the new config file was entirely absent (only loaded when it was present but empty, which was inconsistent with shouldIncludeLegacyGhosttyConfigInScanPaths).

  • IME fix: When accumulatedText arrives from insertText while markedTextBefore is true, each text chunk is now routed through a new sendCommittedIMETextToSurface helper that synthesizes a keycode=0 / mods=NONE event, and the trigger key's keyUp is suppressed via imeConsumedKeyUps.insert. The original forwarding branch is also guarded with else if !markedTextBefore to prevent the Ctrl key from leaking when text delivery was handled via IME.
  • Config fix: shouldLoadLegacyGhosttyConfig now mirrors the existing shouldIncludeLegacyGhosttyConfigInScanPaths logic—returning true when newConfigFileSize is nil (file absent)—and all tests are updated to match.

Confidence Score: 5/5

Safe to merge — both the IME text routing and config legacy-loading fixes are well-scoped, paired with updated tests that cover the corrected behavior, and make no structural changes to the surrounding key-event pipeline.

The IME fix correctly threads committed text through a synthetic zero-keycode event, re-inserts the trigger key into the keyUp-suppression set before issuing continue, and guards the no-text fallback with !markedTextBefore so neither the text nor a phantom Ctrl key leaks to the terminal. The config fix closes a gap where shouldLoadLegacyGhosttyConfig returned false for a missing new-config file while the parallel shouldIncludeLegacyGhosttyConfigInScanPaths already returned true; both functions are now consistent. All changed tests are aligned with the new behavior.

No files require special attention.

Important Files Changed

Filename Overview
Sources/GhosttyTerminalView.swift Adds sendCommittedIMETextToSurface helper and routes IME-committed text through it when markedTextBefore is true; adds imeConsumedKeyUps.insert to suppress the trigger key's keyUp; guards the no-text fallback send with else if !markedTextBefore. Logic is correct.
cmuxTests/CJKIMEMarkedSelectionTests.swift Adds testControlJCommitWhileMarkedTextIsActiveSendsOnlyCommittedText covering the Ctrl+J Japanese IME commit path; asserts synthetic keycode=0/mods=NONE delivery, no leaked Ctrl press/release, and remaining preedit preserved.
Packages/macOS/CmuxTerminalCore/Sources/CmuxTerminalCore/ConfigDiscovery/GhosttyConfigDiscovery.swift Adds guard let newConfigFileSize else { return true } to shouldLoadLegacyGhosttyConfig, making it consistent with the already-correct shouldIncludeLegacyGhosttyConfigInScanPaths. Docstring updated to match.
Packages/macOS/CmuxTerminalCore/Tests/CmuxTerminalCoreTests/GhosttyConfigDiscoveryTests.swift Test renamed and updated: nil newConfigFileSize now asserts true (was asserting false), correctly reflecting the bug fix.
cmuxTests/GhosttyConfigTests.swift Mirrors the GhosttyConfigDiscoveryTests change at the GhosttyApp wrapper level: renamed and flipped to XCTAssertTrue.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[keyDown with Ctrl+J\nwhile IME preedit active] --> B{shouldSuppressGhosttyKeyForwardingAfterIMEHandling?}
    B -- yes --> C[imeConsumedKeyUps.insert\nreturn]
    B -- no --> D[imeConsumedKeyUps.remove keyCode\nbuild keyEvent]
    D --> E{accumulatedText non-empty?}
    E -- yes --> F[for each text in accumulatedText]
    F --> G{shouldSendText?}
    G -- yes + markedTextBefore --> H[imeConsumedKeyUps.insert keyCode\nsendCommittedIMETextToSurface\nkeycode=0 mods=NONE\ncontinue]
    G -- yes + NOT markedTextBefore --> I[send keyEvent with text\nnormal path]
    G -- no + NOT markedTextBefore --> J[send keyEvent text=nil\nno-text fallback]
    G -- no + markedTextBefore --> K[skip — do nothing]
    H --> L{more texts?}
    I --> L
    J --> L
    K --> L
    L -- yes --> F
    L -- no --> M{shouldSendCommittedIMEConfirmKey?\nKorean + Enter + empty preedit}
    M -- yes --> N[send Enter key to terminal]
    M -- no --> O[done]
    E -- no --> P[normal single-key send path]
    Q[keyUp with Ctrl+J] --> R{imeConsumedKeyUps contains keyCode?}
    R -- yes --> S[remove + suppress keyUp]
    R -- no --> T[forward keyUp to Ghostty]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[keyDown with Ctrl+J\nwhile IME preedit active] --> B{shouldSuppressGhosttyKeyForwardingAfterIMEHandling?}
    B -- yes --> C[imeConsumedKeyUps.insert\nreturn]
    B -- no --> D[imeConsumedKeyUps.remove keyCode\nbuild keyEvent]
    D --> E{accumulatedText non-empty?}
    E -- yes --> F[for each text in accumulatedText]
    F --> G{shouldSendText?}
    G -- yes + markedTextBefore --> H[imeConsumedKeyUps.insert keyCode\nsendCommittedIMETextToSurface\nkeycode=0 mods=NONE\ncontinue]
    G -- yes + NOT markedTextBefore --> I[send keyEvent with text\nnormal path]
    G -- no + NOT markedTextBefore --> J[send keyEvent text=nil\nno-text fallback]
    G -- no + markedTextBefore --> K[skip — do nothing]
    H --> L{more texts?}
    I --> L
    J --> L
    K --> L
    L -- yes --> F
    L -- no --> M{shouldSendCommittedIMEConfirmKey?\nKorean + Enter + empty preedit}
    M -- yes --> N[send Enter key to terminal]
    M -- no --> O[done]
    E -- no --> P[normal single-key send path]
    Q[keyUp with Ctrl+J] --> R{imeConsumedKeyUps contains keyCode?}
    R -- yes --> S[remove + suppress keyUp]
    R -- no --> T[forward keyUp to Ghostty]
Loading

Reviews (4): Last reviewed commit: "Load legacy Ghostty config when new file..." | Re-trigger Greptile

Comment thread Sources/GhosttyTerminalView.swift

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread Sources/GhosttyTerminalView.swift
@vercel

vercel Bot commented May 21, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment May 21, 2026 11:49am

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
Sources/GhosttyTerminalView.swift (2)

3093-3099: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Treat a missing config.ghostty as a legacy-config fallback case.

fileSize(_:) returns nil when config.ghostty is absent, but this helper only returns true for 0. That skips loading the legacy config file for legacy-only installations, which contradicts the contract documented in loadLegacyGhosttyConfigIfNeeded.

🐛 Proposed fix
 static func shouldLoadLegacyGhosttyConfig(
     newConfigFileSize: Int?,
     legacyConfigFileSize: Int?
 ) -> Bool {
         guard let legacyConfigFileSize, legacyConfigFileSize > 0 else { return false }
-        return newConfigFileSize == 0
+        guard let newConfigFileSize else { return true }
+        return newConfigFileSize == 0
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/GhosttyTerminalView.swift` around lines 3093 - 3099, The helper
shouldLoadLegacyGhosttyConfig(newConfigFileSize:legacyConfigFileSize:) currently
only returns true when newConfigFileSize == 0, but fileSize(_:) yields nil when
config.ghostty is missing; update the logic to treat a missing newConfigFileSize
(nil) as a fallback as well. Keep the existing guard that legacyConfigFileSize
must be non-nil and > 0, then return true if newConfigFileSize is nil or equals
0 so legacy config is loaded for legacy-only installations.

1725-3819: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Extract these additions out of GhosttyTerminalView.swift.

This file is already well past the repo’s size limit, and this change adds several hundred more lines across unrelated concerns: config loading, render/tick instrumentation, agent-hibernation tracking, terminal-surface helpers, and menu/clipboard actions. Please split the new helpers/types into dedicated files before merge.

As per coding guidelines, **/{Sources,CLI,Packages,cmuxTests,cmuxUITests}/**/*.swift: “Do not add more than 250 lines to an existing production Swift file that is already over 800 lines, unless an extraction exception is met...” and “Do not mix UI rendering, state ownership, persistence, networking, parsing, subprocess/socket protocol, and platform bridge code in one Swift file.”

Also applies to: 4912-7444, 8337-11017

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/GhosttyTerminalView.swift` around lines 1725 - 3819, The PR adds
several hundred lines of unrelated helpers and types into
GhosttyTerminalView.swift (config loading, CJK font logic, appearance sync,
tick/logging, clipboard/transfer helpers) which violates the file-size and
separation guidelines; extract these additions into focused new files. Move
related groups into separate files (e.g. CJK font helpers ->
GhosttyCJKFontFallback.swift containing cjkFontMappings,
autoInjectedCJKFontMappings, resolvedInjectedCJKFontName, configuredCTFont,
discoveredCTFont, fontContainsGlyphs, normalizedFontName,
cjkCoverageSampleCharactersByRange, sharedCJKRanges, japaneseRanges; config
parsing/scan helpers -> GhosttyConfigScan.swift with parsedConfigEntry,
applyConfigFileDirective, scanFontConfigFile, scanAppearanceConfigFile,
userFontConfigSummary, userAppearanceConfigSummary,
loadedGhosttyConfigScanPaths, loadedCJKScanPaths, configFileSize,
shouldIncludeLegacyGhosttyConfigInScanPaths, shouldLoadLegacyGhosttyConfig;
appearance/runtime sync -> GhosttyAppearanceSync.swift with
appearanceSynchronizationPlan, runtimeColorSchemeSynchronizationDecision,
runtimeColorSchemeSynchronizationDecision, ghosttyRuntimeColorScheme,
terminalRuntimeColorSchemePreference, runtimeColorSchemeForConfigLoad,
shouldReloadConfigurationForAppearanceChange,
shouldApplyDefaultBackgroundUpdate, synchronizeGhosttyRuntimeColorScheme
overloads; background/log and scroll lag utilities ->
GhosttyBackgroundAndLag.swift with DefaultBackgroundValues,
defaultBackgroundValues, resolvedAppearanceValue, shouldCaptureScrollLagEvent,
markScrollActivity/endScrollSession, and related properties moved to appropriate
classes), update GhosttyTerminalView to import/use these new symbols (e.g. call
UserFontConfigSummary via userFontConfigSummary(), call GhosttyConfig.load(...)
etc.), and ensure visibility (fileprivate/internal) and tests are updated; keep
all behavioral logic identical and run formatting/build to confirm no ABI or
symbol name changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@Sources/GhosttyTerminalView.swift`:
- Around line 3093-3099: The helper
shouldLoadLegacyGhosttyConfig(newConfigFileSize:legacyConfigFileSize:) currently
only returns true when newConfigFileSize == 0, but fileSize(_:) yields nil when
config.ghostty is missing; update the logic to treat a missing newConfigFileSize
(nil) as a fallback as well. Keep the existing guard that legacyConfigFileSize
must be non-nil and > 0, then return true if newConfigFileSize is nil or equals
0 so legacy config is loaded for legacy-only installations.
- Around line 1725-3819: The PR adds several hundred lines of unrelated helpers
and types into GhosttyTerminalView.swift (config loading, CJK font logic,
appearance sync, tick/logging, clipboard/transfer helpers) which violates the
file-size and separation guidelines; extract these additions into focused new
files. Move related groups into separate files (e.g. CJK font helpers ->
GhosttyCJKFontFallback.swift containing cjkFontMappings,
autoInjectedCJKFontMappings, resolvedInjectedCJKFontName, configuredCTFont,
discoveredCTFont, fontContainsGlyphs, normalizedFontName,
cjkCoverageSampleCharactersByRange, sharedCJKRanges, japaneseRanges; config
parsing/scan helpers -> GhosttyConfigScan.swift with parsedConfigEntry,
applyConfigFileDirective, scanFontConfigFile, scanAppearanceConfigFile,
userFontConfigSummary, userAppearanceConfigSummary,
loadedGhosttyConfigScanPaths, loadedCJKScanPaths, configFileSize,
shouldIncludeLegacyGhosttyConfigInScanPaths, shouldLoadLegacyGhosttyConfig;
appearance/runtime sync -> GhosttyAppearanceSync.swift with
appearanceSynchronizationPlan, runtimeColorSchemeSynchronizationDecision,
runtimeColorSchemeSynchronizationDecision, ghosttyRuntimeColorScheme,
terminalRuntimeColorSchemePreference, runtimeColorSchemeForConfigLoad,
shouldReloadConfigurationForAppearanceChange,
shouldApplyDefaultBackgroundUpdate, synchronizeGhosttyRuntimeColorScheme
overloads; background/log and scroll lag utilities ->
GhosttyBackgroundAndLag.swift with DefaultBackgroundValues,
defaultBackgroundValues, resolvedAppearanceValue, shouldCaptureScrollLagEvent,
markScrollActivity/endScrollSession, and related properties moved to appropriate
classes), update GhosttyTerminalView to import/use these new symbols (e.g. call
UserFontConfigSummary via userFontConfigSummary(), call GhosttyConfig.load(...)
etc.), and ensure visibility (fileprivate/internal) and tests are updated; keep
all behavioral logic identical and run formatting/build to confirm no ABI or
symbol name changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 05071dad-6962-4d40-8af0-c9962909f623

📥 Commits

Reviewing files that changed from the base of the PR and between aefbcae and 0a1ddc8.

📒 Files selected for processing (2)
  • Sources/GhosttyTerminalView.swift
  • cmuxTests/CJKIMEMarkedSelectionTests.swift
💤 Files with no reviewable changes (1)
  • cmuxTests/CJKIMEMarkedSelectionTests.swift

@knu

knu commented May 28, 2026

Copy link
Copy Markdown
Author

Rebased.

knu added 3 commits June 23, 2026 20:56
Send the text committed by IME interpretation when marked text is active, instead of dropping it and forwarding only the original key event to the terminal.

Covers Japanese IME commit paths triggered by control-key shortcuts, including both full and partial preedit commits.
Mark the original key event as IME-consumed when marked text commits through the synthetic text path, so the paired keyUp is not forwarded as an unmatched release.

Extend the CJK IME regression test to cover the keyUp after a control-key shortcut commit.
@knu
knu force-pushed the fix-cjk-ime-marked-commit branch from 0a1ddc8 to 1dc3a1f Compare June 23, 2026 12:07
@knu

knu commented Jun 23, 2026

Copy link
Copy Markdown
Author

Updated.

@teamleaderleo teamleaderleo added bug Something isn't working S3: minor Wrong behavior with a workaround area: input Keyboard, shortcuts, IME, mouse, clipboard and paste area: terminal Ghostty surface, rendering, scrollback, escape sequences, fonts labels Sep 30, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator

This is covered on current main: IME committed text and trigger-key suppression are in GhosttyNSView+IMEComposition, and the legacy Ghostty config fallback is in GhosttyConfigDiscovery. Thank you for the report :)

@teamleaderleo

Copy link
Copy Markdown
Collaborator

The shipped implementation is on current main at 5eda9315. Thank you for the report :)

@knu
knu deleted the fix-cjk-ime-marked-commit branch September 30, 2026 12:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: input Keyboard, shortcuts, IME, mouse, clipboard and paste area: terminal Ghostty surface, rendering, scrollback, escape sequences, fonts bug Something isn't working S3: minor Wrong behavior with a workaround

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants