Skip to content

Fix TextBox IME and input-source handling#5340

Merged
lawrencecchen merged 6 commits into
mainfrom
fix-textbox-ime-input-sources
Jun 4, 2026
Merged

Fix TextBox IME and input-source handling#5340
lawrencecchen merged 6 commits into
mainfrom
fix-textbox-ime-input-sources

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Preserve AppKit-owned marked text during TextBox SwiftUI updates
  • Hide the TextBox placeholder while IME composition is active
  • Use layout-translated command characters for TextBox edit shortcuts

Verification

  • Built tagged app with ./scripts/reload.sh --tag tbime4
  • Local xcodebuild test not run because cmux tests are prohibited on the local Mac

Regression structure

  • First commit adds regression coverage
  • Second commit adds the implementation fix

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


Note

Medium Risk
Touches prompt input, submit gating, and SwiftUI–AppKit text sync—user-visible paths where IME or shortcut bugs could still slip through despite new tests.

Overview
Improves TextBox behavior during IME composition and on non-US keyboard layouts by tracking AppKit marked text in SwiftUI and routing edit shortcuts through layout-translated command characters.

While composition is active, the UI hides the placeholder, disables send/submit, and skips external text sync so SwiftUI updates do not wipe in-progress input; committed text is published when marked text clears, with a one-shot marked-text sync on representable creation that live updates can cancel. Command+C/X/V/Z (and related edit shortcuts) now key off textBoxCommandShortcutKey instead of fixed ANSI key codes.

Pure helpers (shouldSynchronizeExternalTextToTextBox, placeholder/submit gating, etc.) centralize the rules, and tests cover IME sync, submit gating, coordinator publish ordering, and translated shortcuts.

Reviewed by Cursor Bugbot for commit 7904df1. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Fixes TextBox IME composition and non‑US keyboard Command shortcuts to prevent text loss, accidental sends, and misrouted actions. Hides the placeholder during composition, blocks submit, syncs AppKit marked text into SwiftUI, and cancels stale initial marked‑state sync on first layout.

  • Bug Fixes
    • Track hasMarkedText across insert/set/unmark and selection; publish committed IME text before clearing; queue a one‑shot marked‑text sync on creation and cancel it if a live update arrives.
    • External text sync now skips during composition and when inline attachments exist; during composition we also hide the placeholder and block send/submit (including in submit()).
    • Resolve Command shortcuts via layout‑translated characters with textBoxCommandShortcutKey for copy/cut/paste and undo.

Written for commit 7904df1. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • End-to-end IME (marked-text) tracking in the text box, gating placeholder, send/submit availability, and external text synchronization.
  • Bug Fixes

    • External text sync now avoids overwriting during composition or when inline attachments exist.
    • Keyboard shortcut handling normalized to translated command keys for more consistent copy/paste/undo behavior.
  • Tests

    • Added IME composition, placeholder/send gating, external-sync suppression, and shortcut-routing tests.

@vercel

vercel Bot commented Jun 4, 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 Jun 4, 2026 6:33am
cmux-staging Building Building Preview, Comment Jun 4, 2026 6:33am

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Marked-text (IME composition) state is propagated from the AppKit text view through the representable coordinator into SwiftUI, gating placeholder rendering, external text synchronization, and submit/send enablement; keyboard shortcuts use a layout-aware command-character translator.

Changes

IME-aware text box and keyboard shortcuts

Layer / File(s) Summary
IME-aware decision and shortcut helpers
Sources/TextBoxInput.swift
Adds helpers for IME-aware gating and a keyboard-layout-aware textBoxCommandShortcutKey translator.
SwiftUI container state and gating
Sources/TextBoxInput.swift
TextBoxInputContainer tracks hasMarkedText, uses helpers for placeholder/send/submit gating, and updates marked-text state only on change.
TextBoxInputView representable API and conditional text sync
Sources/TextBoxInput.swift
TextBoxInputView adds onMarkedTextStateChanged, queues a one-shot marked-text sync, and conditionally writes external SwiftUI text into the AppKit text view using IME-aware rules.
Coordinator pending-sync and forwarding
Sources/TextBoxInput.swift
Coordinator stores a pending marked-text value, applies it after layout, and forwards textView.hasMarkedText() from textDidChange and selection changes into the SwiftUI parent.
AppKit text view overrides and callback
Sources/TextBoxInput.swift
TextBoxInputTextView exposes onMarkedTextStateChanged and overrides insertText, setMarkedText, and unmarkText to emit current marked-text state after superclass behavior.
Keyboard shortcut translation usage
Sources/TextBoxInput.swift
Undo (⌘Z) and standard edit shortcuts (⌘C/⌘X/⌘V) now use the translated command character from textBoxCommandShortcutKey(for:...) instead of raw keyCode matching.
Test coverage for IME behavior and keyboard shortcuts
cmuxTests/TextBoxMentionCompletionTests.swift
Adds tests for external-text sync blocking during IME composition, placeholder suppression while composing, submit disabling during composition, committed IME publication ordering, and translated Command-C/Command-Z resolution.

Sequence Diagram(s)

sequenceDiagram
  participant TextBoxInputTextView
  participant Coordinator
  participant TextBoxInputView
  TextBoxInputTextView->>Coordinator: onMarkedTextStateChanged(hasMarkedText)
  Coordinator->>TextBoxInputView: onMarkedTextStateChanged(Bool)
  TextBoxInputView->>Coordinator: queuePendingMarkedTextStateSync(from:)
  Coordinator->>TextBoxInputTextView: applyPendingMarkedTextStateSyncIfNeeded() / recalculateHeight()
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • manaflow-ai/cmux#5021: Related keyboard/IME routing changes; both PRs gate routing based on IME marked-text state.

Suggested reviewers

  • jesstelford

Poem

🐇 I nibble bytes where marked text grows,
I hop between the views and flows.
Keys learn the language of the layout,
Placeholders hush where IME winds blow.
A tiny rabbit claps — the textbox knows.


Caution

Pre-merge checks failed

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

  • Ignore

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
Cmux Swift Actor Isolation ❌ Error Five new file-level pure helper functions lack nonisolated annotation, violating actor isolation rules and existing codebase patterns established for similar pure utility functions. Add nonisolated keyword to: shouldSynchronizeExternalTextToTextBox, shouldShowTextBoxPlaceholder, shouldEnableTextBoxSubmit, shouldSubmitTextBox, and textBoxCommandShortcutKey.
Docstring Coverage ⚠️ Warning Docstring coverage is 7.50% 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 PR description covers the main changes (marked text tracking, placeholder hiding, command shortcut translation) and verification approach, but is missing key template sections. Add Testing section with details on how changes were tested, Demo Video section (if applicable), and complete the Checklist with all required items checked off.
✅ Passed checks (15 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change—fixing TextBox IME and input-source handling—which aligns with the primary objectives of preserving marked text, fixing placeholder visibility, and resolving command shortcuts.
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 Blocking Runtime ✅ Passed PR introduces no blocking primitives: new functions use simple logic, marked-text state uses non-blocking callbacks, text sync uses conditional checks. Pre-existing timers unchanged.
Cmux No Hacky Sleeps ✅ Passed PR modifies only Swift files. The rule applies exclusively to TypeScript, JavaScript, shell, and non-Swift build/runtime scripts; Swift code is out of scope per the rule documentation.
Cmux Algorithmic Complexity ✅ Passed New helpers are O(1) with Boolean checks; single-pass string trim is acceptable. inlineAttachments() call in updateNSView bounded by ~100 items, not user-record scalable.
Cmux Swift Concurrency ✅ Passed PR adds IME marked-text callbacks at AppKit/SwiftUI boundaries and pure helper functions without introducing legacy async patterns or Dispatch queues.
Cmux Swift @Concurrent ✅ Passed All PR changes are synchronous pure helpers with no async functions, no @concurrent annotations, and no heavy operations that would violate the concurrent annotation rules.
Cmux Swift File And Package Boundaries ✅ Passed 191 lines added (below 250 threshold) to existing 5888-line file; single coherent TextBox input responsibility; 5 testable helpers; comprehensive unit tests; qualifies as focused bug fix exemption.
Cmux Swift Logging ✅ Passed No logging violations found in PR changes. The 5 new functions and 2 properties contain no print, debugPrint, dump, or NSLog statements. Tests are properly separated.
Cmux User-Facing Error Privacy ✅ Passed PR adds only internal utility functions and unit tests with no new user-facing error messages, alerts, or sensitive information exposure.
Cmux Full Internationalization ✅ Passed PR adds only internal logic functions and test cases without new user-facing text. All existing strings already use String(localized:) with complete translations.
Cmux Swiftui State Layout ✅ Passed Simple @State for hasMarkedText with callbacks from AppKit lifecycle (insertText, setMarkedText, layout). No @Observable, ObservableObject, @Published, or render-time mutations.
Cmux Architecture Rethink ✅ Passed PR introduces required platform bridge code with clear ownership, testable pure functions, and layout-cycle deferred sync—no timing repairs, duplicate owners, or split lifecycle.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed No new auxiliary windows added. Existing TextBoxMentionCompletionPanel is unchanged and properly registered in IGNORED_IDENTIFIERS list as non-key popover.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-textbox-ime-input-sources

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 and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 57c762c8f9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +145 to +149
guard let event = makeKeyDownEvent(
key: "c",
modifiers: [.command],
keyCode: UInt16(kVK_ANSI_B),
windowNumber: 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Make shortcut regression tests layout-independent

In this test, key: "c" does not control what textBoxCommandShortcutKey(for:) returns: that helper first calls KeyboardLayout.character, which consults the machine's current TIS input source for event.keyCode. On a normal US/QWERTY CI host, kVK_ANSI_B translates to "b", so the expectation on line 155 fails regardless of the synthetic event's characters; the Y/Z test below has the same issue. Please mock/inject the layout translation or use a key code that matches the active layout.

Useful? React with 👍 / 👎.

Comment thread Sources/TextBoxInput.swift
@lawrencecchen lawrencecchen force-pushed the fix-textbox-ime-input-sources branch from e75f972 to 3297644 Compare June 4, 2026 05:46
coderabbitai[bot]
coderabbitai Bot previously requested changes Jun 4, 2026

@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.

Actionable comments posted: 2

🤖 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.

Inline comments:
In `@Sources/TextBoxInput.swift`:
- Line 3142: The binding `@Binding` var hasMarkedText is being written directly
during makeNSView/updateNSView which leaves a stale true value when
dismantleNSView preserves bindings; instead add a one-shot
"pendingMarkedTextSyncForNextLayout" flag (mirroring
pendingAttachmentUploadStateForNextLayout) and set that flag when rebuilding
representables in dismantleNSView or where appropriate, then on the next layout
pass (in the same place where pendingAttachmentUploadStateForNextLayout is
handled) read the new NSTextView.hasMarkedText() and update hasMarkedText once
and clear the pending flag; update references in makeNSView/updateNSView and the
layout sync handler to use pendingMarkedTextSyncForNextLayout rather than
directly assigning hasMarkedText so the fresh NSTextView publishes its real
initial state.
- Line 2657: The send button and submit path must be disabled/guarded while IME
composition is active: use the existing `@State` private var hasMarkedText to
prevent enabling or invoking submit() during marked text. Update the Send
button's binding/disabled logic to include hasMarkedText (e.g., disable when
hasMarkedText is true or when text.isEmpty) and add a guard at the start of
submit() to return early if hasMarkedText is true; ensure any UI paths that call
submit() (button action, shortcut handlers) check hasMarkedText before clearing
or sending text. Also audit related locations referencing text (e.g., where the
button enablement and submit invocation occur) and apply the same hasMarkedText
guard to avoid discarding IME composition.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8045b780-41a5-44e2-9c91-26abab416cac

📥 Commits

Reviewing files that changed from the base of the PR and between 9d926e2 and 57c762c.

📒 Files selected for processing (3)
  • Sources/TextBoxInput.swift
  • cmuxTests/AppDelegateShortcutRoutingTests.swift
  • cmuxTests/TextBoxMentionCompletionTests.swift

Comment thread Sources/TextBoxInput.swift
Comment thread Sources/TextBoxInput.swift Outdated
@greptile-apps

greptile-apps Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes two TextBox regressions: IME marked-text during composition is now preserved (external SwiftUI text sync, placeholder display, and send/submit are all gated on hasMarkedText), and Command keyboard shortcuts are now resolved via KeyboardLayout.character(forKeyCode:modifierFlags:) so they work correctly on non-US layouts.

  • Five new pure predicate helpers (shouldSynchronizeExternalTextToTextBox, shouldShowTextBoxPlaceholder, shouldEnableTextBoxSubmit, shouldSubmitTextBox, textBoxCommandShortcutKey) centralize the gating decisions and are exercised by the new unit tests.
  • TextBoxInputView.Coordinator gains deliveredMarkedTextState and pendingMarkedTextStateForNextLayout to flush committed text before clearing the marked-text flag, with a one-shot initial sync on representable creation that is cancelled if a live AppKit update arrives first.
  • TextBoxInputTextView overrides setMarkedText, unmarkText, and insertText to publish state changes synchronously via onMarkedTextStateChanged.

Confidence Score: 5/5

Safe to merge; all new production paths are tested and the AppKit override ordering is sound.

The IME gating logic is pure and fully unit-tested; the Coordinator's pending/delivered state machine handles the live-cancels-queued edge case correctly, and the publishTextViewContent idempotency check prevents double onContentChanged calls. The only concern is a style-level file-size issue that pre-dates this PR.

Sources/TextBoxInput.swift — already far over the package-boundary line threshold and grows further with this change.

Important Files Changed

Filename Overview
Sources/TextBoxInput.swift Adds IME marked-text tracking via helper predicates, Coordinator state, and AppKit overrides; file grows to ~5900 lines, exceeding the 800-line package-boundary threshold by a wide margin
cmuxTests/TextBoxMentionCompletionTests.swift Adds targeted unit tests for IME sync, placeholder/submit gating, commit-before-clear ordering, queued-sync cancellation, and shortcut translation; test-only, no production concerns

Reviews (3): Last reviewed commit: "fix: cancel stale textbox marked sync" | Re-trigger Greptile

Comment thread Sources/TextBoxInput.swift Outdated
let onInsertFileURLs: ([URL], TextBoxInputTextView) -> Bool
let onChooseFiles: () -> Void
let onContentChanged: () -> Void
var onMarkedTextStateChanged: (Bool) -> Void = { _ in }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 var breaks the let-closure convention for callback properties

Every other callback on TextBoxInputView (onContentChanged, onTextViewCreated, onTextViewMovedToWindow, onTextViewDismantled, etc.) is declared let, making the contract clear: these closures are fixed at construction time. Declaring onMarkedTextStateChanged as var just to supply a default no-op weakens that contract without a compelling reason — makeCoordinator can wire an always-present closure instead, or the default can be expressed with an Optional unwrapped at call sites. As written, any code that sees a TextBoxInputView value can silently reassign the handler.

Rule Used: Flag Swift fixes that patch symptoms while leaving... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@@ -2625,6 +2655,7 @@ struct TextBoxInputContainer: View {

@State private var textViewHeight: CGFloat = 0
@State private var hasPendingAttachmentUpload = false

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 New @State hasMarkedText introduces split SwiftUI/AppKit lifecycle ownership

@State private var hasMarkedText is a mirror of NSTextView.hasMarkedText() maintained through three separate AppKit entrypoints (setMarkedText, unmarkText, insertText) and two delegate callbacks (textViewDidChange, textViewDidChangeSelection). This is the flag/side-channel pattern flagged by the architectural rethink rule: AppKit owns the marked-text invariant, and SwiftUI now owns a shadow copy that must be kept in sync across five call sites.

The sync guard in updateNSView (shouldSynchronizeExternalTextToTextBox) already reads textView.hasMarkedText() directly — the real-time AppKit state — so the shadow @State flag is only needed for placeholder visibility. If any of the five notification paths is missed in a future refactor, the shadow can drift and the placeholder will flicker or show during active composition.

Rule Used: Flag Swift fixes that patch symptoms while leaving... (source)

@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.

♻️ Duplicate comments (2)
Sources/TextBoxInput.swift (2)

2695-2696: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Block button-driven submit while IME composition is active.

hasMarkedText is now tracked, but the Send button still enables from text/attachments alone and submit() clears the field without checking composition state. Clicking Send mid-IME can still discard the active marked text this PR is trying to preserve.

Suggested fix
-        let canSend = !hasPendingAttachmentUpload
+        let canSend = !hasPendingAttachmentUpload
+            && !hasMarkedText
             && (!text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || !attachments.isEmpty)
...
     private func submit() {
+        guard textViewReference.textView?.hasMarkedText() != true else {
+            NSSound.beep()
+            return
+        }
         guard textViewReference.textView?.hasPendingAttachmentUploadPlaceholder() != true else {
             NSSound.beep()
             return
         }

Also applies to: 2817-2835

🤖 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/TextBoxInput.swift` around lines 2695 - 2696, The Send button
enabling logic and submit flow must respect IME composition: update the canSend
computation (used when rendering the Send button) to also require hasMarkedText
== false in addition to the existing hasPendingAttachmentUpload/text/attachments
checks (modify the variable named canSend), and update the submit() method to
no-op or defer clearing `text` while hasMarkedText is true (check the
`hasMarkedText` flag at the start of submit() and return early or postpone
clearing any marked text until composition ends). Apply the same change to the
other submit-related block referenced around the 2817-2835 region so both button
state and submit clearing consistently honor `hasMarkedText`.

3210-3213: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Queue a one-shot marked-text sync after rebuilding the representable.

Only pending-upload state gets a post-construction sync. If the old view is torn down while TextBoxInputContainer.hasMarkedText == true, the replacement NSTextView never publishes its initial hasMarkedText() == false, so the placeholder can stay hidden until the user edits again.

Suggested fix
     final class Coordinator: NSObject, NSTextViewDelegate {
         var parent: TextBoxInputView
         private var pendingAttachmentUploadStateForNextLayout: Bool?
+        private var pendingMarkedTextStateForNextLayout: Bool?

         init(parent: TextBoxInputView) {
             self.parent = parent
         }

         /// Captures pending-upload state once after representable construction restores AppKit storage.
         func queuePendingAttachmentUploadStateSync(from textView: TextBoxInputTextView) {
             pendingAttachmentUploadStateForNextLayout = textView.hasPendingAttachmentUploadPlaceholder()
         }
+
+        func queuePendingMarkedTextStateSync(from textView: TextBoxInputTextView) {
+            pendingMarkedTextStateForNextLayout = textView.hasMarkedText()
+        }
...
         onTextViewCreated(textView)
         context.coordinator.queuePendingAttachmentUploadStateSync(from: textView)
+        context.coordinator.queuePendingMarkedTextStateSync(from: textView)
         return scrollView
...
             if let textBoxView = textView as? TextBoxInputTextView {
                 textBoxView.recenterSingleLineTextContainer()
                 applyPendingAttachmentUploadStateSyncIfNeeded()
+                applyPendingMarkedTextStateSyncIfNeeded()
             }
...
         private func applyPendingAttachmentUploadStateSyncIfNeeded() {
             guard let hasPendingUpload = pendingAttachmentUploadStateForNextLayout else { return }
             pendingAttachmentUploadStateForNextLayout = nil
             guard parent.hasPendingAttachmentUpload != hasPendingUpload else { return }
             parent.hasPendingAttachmentUpload = hasPendingUpload
         }
+
+        private func applyPendingMarkedTextStateSyncIfNeeded() {
+            guard let hasMarkedText = pendingMarkedTextStateForNextLayout else { return }
+            pendingMarkedTextStateForNextLayout = nil
+            parent.onMarkedTextStateChanged(hasMarkedText)
+        }

Also applies to: 3281-3379

🤖 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/TextBoxInput.swift` around lines 3210 - 3213, After rebuilding the
representable, also enqueue a one-shot marked-text sync so the new NSTextView
publishes its initial hasMarkedText() state; specifically, right after calling
updateTextView(...) and onTextViewCreated(...) (near where
context.coordinator.queuePendingAttachmentUploadStateSync(from: textView) is
called) add a coordinator method call that synchronizes
TextBoxInputContainer.hasMarkedText to the new textView’s hasMarkedText() once
(so the placeholder visibility is corrected when the old view was torn down with
hasMarkedText == true).
🤖 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.

Duplicate comments:
In `@Sources/TextBoxInput.swift`:
- Around line 2695-2696: The Send button enabling logic and submit flow must
respect IME composition: update the canSend computation (used when rendering the
Send button) to also require hasMarkedText == false in addition to the existing
hasPendingAttachmentUpload/text/attachments checks (modify the variable named
canSend), and update the submit() method to no-op or defer clearing `text` while
hasMarkedText is true (check the `hasMarkedText` flag at the start of submit()
and return early or postpone clearing any marked text until composition ends).
Apply the same change to the other submit-related block referenced around the
2817-2835 region so both button state and submit clearing consistently honor
`hasMarkedText`.
- Around line 3210-3213: After rebuilding the representable, also enqueue a
one-shot marked-text sync so the new NSTextView publishes its initial
hasMarkedText() state; specifically, right after calling updateTextView(...) and
onTextViewCreated(...) (near where
context.coordinator.queuePendingAttachmentUploadStateSync(from: textView) is
called) add a coordinator method call that synchronizes
TextBoxInputContainer.hasMarkedText to the new textView’s hasMarkedText() once
(so the placeholder visibility is corrected when the old view was torn down with
hasMarkedText == true).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: de1c6d55-814e-4d12-8400-8856db808e2b

📥 Commits

Reviewing files that changed from the base of the PR and between 57c762c and 3297644.

📒 Files selected for processing (2)
  • Sources/TextBoxInput.swift
  • cmuxTests/TextBoxMentionCompletionTests.swift

@cursor cursor 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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 95ec20f. Configure here.

Comment thread Sources/TextBoxInput.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 (changes from recent commits).

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

Re-trigger cubic

Comment thread Sources/TextBoxInput.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.

No issues found across 2 files

Re-trigger cubic

@lawrencecchen lawrencecchen dismissed coderabbitai[bot]’s stale review June 4, 2026 06:51

Dismissed stale CodeRabbit review: both actionable comments were addressed, later bot checks are green, and current Codex review is clean.

@lawrencecchen lawrencecchen merged commit ff172b0 into main Jun 4, 2026
22 checks passed
@lawrencecchen lawrencecchen deleted the fix-textbox-ime-input-sources branch June 4, 2026 06:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant