Stop regenerating suggestion on Enter so post-Enter actions aren't masked#359
Merged
Conversation
…sked Return (keycode 36) and Keypad Enter (76) were grouped with Backspace and forward-delete as .textMutation, which both clears the visible suggestion AND immediately schedules a fresh prediction. The fresh suggestion's overlay then re-appears ~50-500ms later over whatever Enter actually did in the focused field (find-next in a Find Bar, form submit, send-message in a chat composer), making it feel like Enter was swallowed. Reclassify Return and Keypad Enter as .dismissal alongside Escape. They already clear the suggestion via .dismissal's shouldClearSuggestion path but no longer fire a fresh prediction. In multi-line fields the next typed character will schedule one anyway, so the only behavior change is that an immediate post-Enter overlay no longer races the user's intended action.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Return (keycode 36) and Keypad Enter (76) were classified as
.textMutationalongside Backspace and forward-delete inInputMonitor.classify(event:)..textMutationboth clears the visible suggestion and schedules a fresh prediction viaSuggestionCoordinator+Input.swift. The result: pressing Enter while a suggestion was on screen would clear it, then ~50-500ms later the regenerated suggestion's overlay popped back up over whatever Enter actually did in the field (find-next in a Find Bar, submit, send), so it felt like Cotabby had swallowed the key. The keystroke itself wasn't being consumed — the accept tap only swallows the configured accept binding — but the racing overlay obscured the post-Enter result.Reclassify Return and Keypad Enter as
.dismissal, the same bucket Escape already lives in. Suggestion still clears on Enter; no fresh prediction fires until the user types an actual character. In multi-line fields that means a one-keystroke delay before the next-line prediction shows, which is a much smaller cost than masking the user's intended action everywhere else.Validation
Manual repro before fix: open a browser, ⌘F to bring up the Find Bar, type a query, wait for Cotabby's suggestion overlay, press Enter. The overlay regenerates and obscures the find-next result. After fix: Enter dismisses the overlay cleanly and the find-next is unobscured.
Risk / rollout notes
InputMonitor.classify(...)isprivateand operates on aCGEvent, so unit-testing it cleanly would require a small refactor (extract a pure helper); deferred so this fix stays minimal.Greptile Summary
This PR reclassifies Return (keyCode 36) and Keypad Enter (76) from
.textMutationto.dismissalinInputMonitor.classify(event:). Previously, pressing Enter while a suggestion was visible would clear the overlay and immediately schedule a fresh prediction, causing the regenerated overlay to race with and obscure the app's native response to Enter (e.g., find-next in a Find Bar, form submit, chat send).textMutationbranch and into thedismissalbranch alongside Escape (53), soshouldSchedulePredictionreturnsfalsefor Enter and the coordinator sets state to.idleinstead of queuing another request.handleInputEvent(_:with:), which now routes Enter tocase .navigation, .dismissal:→ invalidate + idle) and the "no active session" path (clears suggestion, skips prediction scheduling).isDirectTextMutationcomment inSuggestionSessionReconciler.swiftreads "Control characters such as backspace or return require regeneration" — Return no longer triggers regeneration after this change, so that comment is slightly stale. Worth a follow-up update.Confidence Score: 5/5
Single-classification change with no state-machine or coordinator edits; both code paths that consume the event kind behave correctly for
.dismissal.The change touches exactly one conditional in one file. The
.dismissalkind is already handled by every downstream consumer:shouldClearSuggestionreturnstrue(overlay clears),shouldSchedulePredictionreturnsfalse(no racing prediction), and the active-session switch armcase .navigation, .dismissal:already existed and sets state to.idle. Return'scharacter was already excluded from optimistic session advancement byisDirectTextMutation, so there is no silent behaviour gap. The only loose end is a now-stale doc comment in an untouched file, which carries no runtime impact.No files require special attention. The stale
isDirectTextMutationcomment inSuggestionSessionReconciler.swiftis the only follow-up worth noting, but it does not affect runtime behaviour.Important Files Changed
.textMutationto.dismissal; the rest of the classify function is untouched. The change correctly threads through both the active-session and no-session coordinator paths — suggestion clears, no fresh prediction fires, state returns to idle.Reviews (1): Last reviewed commit: "Stop regenerating suggestion on Enter so..." | Re-trigger Greptile