Skip to content

Support InsertReplaceEdit and keep existing arguments when completing function calls#2676

Open
Steffeeen wants to merge 2 commits into
swiftlang:mainfrom
Steffeeen:completion-improvements
Open

Support InsertReplaceEdit and keep existing arguments when completing function calls#2676
Steffeeen wants to merge 2 commits into
swiftlang:mainfrom
Steffeeen:completion-improvements

Conversation

@Steffeeen
Copy link
Copy Markdown
Member

This PR implements two closely related features for code completion.

InsertReplaceEdit Support

First, it adds support for InsertReplaceEdit allowing the user to choose between inserting (Enter in VSCode) the function name or replacing (Tab in VSCode) the existing rest of the identifier if the completion was invoked in the middle of an identifier. This often happens when changing which function is called. Example showing the difference:

Screen.Recording.2026-05-29.at.15.43.22.mov

Reusing Existing Parentheses

The second feature this PR implements is not inserting parentheses or braces if they are already present in the document. This is useful in general, but was especially needed for the use case of changing which function is called. This example shows what happens with just the InsertReplaceEdit changes:

Screen.Recording.2026-05-29.at.15.47.46.mov

Compare this to the behavior when using the changes from both commits:

Screen.Recording.2026-05-29.at.15.49.37.mov

Below is an example of the general case of completing a function call with already present parentheses. Previously, the parentheses and argument labels would always be inserted and the user would end up with testabc(x: , y: )(x: 3, y: 5).

Screen.Recording.2026-05-29.at.15.56.48.mov

If the parentheses already contain arguments, they are kept, even if the labels don't match the function call. I also thought about using an InsertReplaceEdit to let the user decide whether to replace the arguments or keep the existing ones. This however leads to a problem in situations like this: foo|bar(x: 1, y: 2). Here, the replace operation could be for replacing just bar or replacing bar(x: 1, y: 2). I also could not find another language server that does it that way, so I opted for not implementing this for now. But then again, no other language (that I know of) has mandatory argument labels where autocomplete is a real benefit. In Rust for example, the only benefit of autocomplete in this case would be inserting the commas between the arguments.

If the parentheses are empty, they are overwritten with the argument labels:

Screen.Recording.2026-05-29.at.15.51.23.mov

While this feature was primarily intended for the use case of completing function calls, I also ensured that it works for other similar cases, like enum case completion and macros.

Steffeeen added 2 commits May 29, 2026 11:24
If the user invokes code completion in the middle of an identifier and
the client supports `InsertReplaceEdit`s the client can now let the user
choose between inserting the completion or replacing the existing rest
of the identifier.
With this commit, we no longer insert the parentheses or trailing
closure when completing a function call (or something that looks similar
to a function call) if they are already present.
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