fix(editor): replace the whole typed word when accepting a completion#1601
Merged
Conversation
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.
Problem
User report: with a column named
message, typingmessand pressing Tab insertsmemessageinstead ofmessage. The completion left the first typed characters in place and replaced only a tail subrange.Root cause
SQLCompletionAdapter.completionWindowApplyCompletionbuilt the replace range from a stored token start paired with the live cursor:completionOnCursorMovekept the window open across keystrokes but never updated the stored rangessfuzzy-matchesmessage), so nothing self-corrected before TabAny drift in that pipeline became a wrong
location, and Tab replaced the wrong subrange. The happy path was correct, which is why the bug appeared only intermittently (fast typing during a schema fetch, multi-statement or multibyte documents).Fix
Compute the replacement range from the live text at accept time, the way AppKit's own completion (
rangeForUserCompletion) behaves:SQLTokenBoundaryholds the single identifier-boundary rule (UTF-16 scanning, stops at.so qualified-name segment completion keeps its semantics) andreplacementRange(in:cursor:fallback:)completionWindowApplyCompletionandcompletionOnCursorMoveboth use it, so the visible filtering and the applied range always agree; the stored range remains only as a fallback when no cursor is suppliedSQLContextAnalyzerdelegates its boundary checks to the shared rule so analyzer and adapter cannot diverge againTests
11 unit tests in
SQLTokenBoundaryTests: plain word, dot segments, quoted identifiers, multibyte text before the token, cursor clamping, empty prefix, and the regression case (stale stored range + live cursor must produceSELECT message, neverSELECT memessage). All pass locally;swiftlint lint --strictclean on changed files.