Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Prevent autocompletion from triggering incorrectly within words #15030

Merged
merged 2 commits into from
Mar 3, 2025

Conversation

eneufeld
Copy link
Contributor

What it does

This commit fixes an issue where autocompletion would incorrectly trigger when typing a variable character '#' in the middle of words (e.g., "Hello#").

Changes:

  • Removed '#' from trigger characters in the variable argument completion provider
  • Improved boundary detection in the variable argument picker to prevent triggering when '#' appears within words
  • Added better context validation to ensure completion only happens in appropriate cases
  • Fixed the implementation to maintain correct functionality for legitimate variable references like "#file:"
  • Refactored code to remove code duplication

The fix ensures that autocompletion is only triggered in intended contexts while preserving all existing functionality. Fixed #15028

How to test

In the chat Input view test different cases:

  • starting with ~, @ or # should trigger the autocompletion
  • continuing after a variable selection via #file with a : should trigger the argument selection
  • typing Foo~, Foo@ or Foo# should not trigger the autocompletion
  • typing Foo ~, Foo @ or Foo # should trigger the autocompletion

Follow-ups

Breaking changes

  • This PR introduces breaking changes and requires careful review. If yes, the breaking changes section in the changelog has been updated.

Attribution

Review checklist

Reminder for reviewers

@JonasHelming JonasHelming requested a review from planger February 26, 2025 09:49
Copy link
Contributor

@planger planger left a comment

Choose a reason for hiding this comment

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

Thanks for this improvement! It indeed is a good idea to avoid triggering a code completion if the trigger character is not the beginning of the word.

However, there are a few cases that are not covered / broken now as far as I tested:

  1. We should also skip requesting completions for provideVariableWithArgCompletions. Currently the file suggestions still show up if the user enters abc#re and then types Ctr+Space.
  2. It looks like there are no direct argument suggestions anymore from the file provider via provideVariableWithArgCompletions after typing #. On master it worked to trigger the completion with # and then directly start typing a file name (at least after character 3-4). Note that it still works when canceling the suggestions and retrigger them manually with Ctrl+space.
  3. The argument picker isn't triggered anymore after completing a variable with arguments, e.g. #file. On master this would insert #file: and trigger the argument picker via the quick input.

As a side note: The implementation of the completion providers in this class was always a bit brittle a. I had to fix a few bugs here lately. This was mainly because the implementation of the completion providers relied a lot on the trigger characters instead of focusing on the current text at the position. The user can trigger an autocompletion at any time manually and it should always be complete, not just if the autocompletion is triggered by the trigger character. I aimed at improving the situation a bit with #15018, but I feel that it still is somewhat brittle and inconsistent (triggered suggestions vs manual Ctrl+space). Probably because the computed range doesn't always fit with the suggestions.

@@ -31,6 +31,17 @@ const VARIABLE_RESOLUTION_CONTEXT = { context: 'chat-input-autocomplete' };
const VARIABLE_ARGUMENT_PICKER_COMMAND = 'trigger-variable-argument-picker';
const VARIABLE_ADD_CONTEXT_COMMAND = 'add-context-variable';

// Define a consistent interface for completion sources
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// Define a consistent interface for completion sources

Imho this comment doesn't add a lot of information

monaco.languages.registerCompletionItemProvider(CHAT_VIEW_LANGUAGE_ID, {
triggerCharacters: [PromptText.AGENT_CHAR],
provideCompletionItems: (model, position, _context, _token): ProviderResult<monaco.languages.CompletionList> => this.provideAgentCompletions(model, position),
// Register all completion providers
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// Register all completion providers

Imho this comment doesn't add a lot of information

}

protected registerCompletionProviders(): void {
// Register standard completion providers
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// Register standard completion providers

Imho this comment doesn't add a lot of information

// Register standard completion providers
this.registerStandardCompletionProvider({
triggerCharacter: PromptText.AGENT_CHAR,
getItems: () => this.agentService.getAgents(), // Use function to fetch the latest items
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
getItems: () => this.agentService.getAgents(), // Use function to fetch the latest items
getItems: () => this.agentService.getAgents(),

Imho this comment doesn't add a lot of information


this.registerStandardCompletionProvider({
triggerCharacter: PromptText.VARIABLE_CHAR,
getItems: () => this.variableService.getVariables(), // Use function to fetch the latest items
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
getItems: () => this.variableService.getVariables(), // Use function to fetch the latest items
getItems: () => this.variableService.getVariables(),


this.registerStandardCompletionProvider({
triggerCharacter: PromptText.FUNCTION_CHAR,
getItems: () => this.toolInvocationRegistry.getAllFunctions(), // Use function to fetch the latest items
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
getItems: () => this.toolInvocationRegistry.getAllFunctions(), // Use function to fetch the latest items
getItems: () => this.toolInvocationRegistry.getAllFunctions(),

});

// Register the variable argument completion provider (special case)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// Register the variable argument completion provider (special case)

Imho this comment is rather confusing out of context

@eneufeld
Copy link
Contributor Author

@planger thank you for the review and the improvement suggestions. I updated the code and the provideVariableWithArgCompletions should now also work as expected

@planger planger self-requested a review February 27, 2025 09:03
Copy link
Contributor

@planger planger left a comment

Choose a reason for hiding this comment

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

Thanks for the revision! Looks much better. The regression no 3 I mentioned in my previous comment still persists. I quickly debugged the code and marked the causing line. We need to account for the : that we add to variables with mandatory arguments.

Thank you!

const wordInfo = model.getWordUntilPosition(position);

// Only trigger if current word starts with #, followed by actual text
if (!wordInfo.word.startsWith(PromptText.VARIABLE_CHAR) || wordInfo.word.length <= 1) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This prevents the regression no 3 I mentioned before. The word is actually empty, because we end with a : if the variable has mandatory arguments. So we would actually need to check if the character at the position is PromptText.VARIABLE_SEPARATOR_CHAR (see code below on line 246 etc.).

Copy link
Contributor

@planger planger left a comment

Choose a reason for hiding this comment

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

Thank you, now case 3 works again. However, I'm afraid the manual auto-completion after the : is know broken. Try typing #file: and then type Ctrl-space.

This commit fixes an issue where autocompletion would incorrectly trigger when typing a variable character '#' in the middle of words (e.g., "Hello#").

Changes:
- Removed '#' from trigger characters in the variable argument completion provider
- Improved boundary detection in the variable argument picker to prevent triggering when '#' appears within words
- Added better context validation to ensure completion only happens in appropriate cases
- Fixed the implementation to maintain correct functionality for legitimate variable references like "#file:"

The fix ensures that autocompletion is only triggered in intended contexts while preserving all existing functionality.
Fixed eclipse-theia#15028
@eneufeld
Copy link
Contributor Author

eneufeld commented Mar 1, 2025

Thank you, now case 3 works again. However, I'm afraid the manual auto-completion after the : is know broken. Try typing #file: and then type Ctrl-space.

I can't reproduce your error, or I don't understand it:
AutoComplete

So when I type #fil I can select the #file entry which completes it to #file: and then triggers the selection at the top. I can abort it using escape key and then trigger the autocompletion using ctrl+space and get the autocompletion in place again.

@planger
Copy link
Contributor

planger commented Mar 1, 2025

Thank you, now case 3 works again. However, I'm afraid the manual auto-completion after the : is know broken. Try typing #file: and then type Ctrl-space.

I can't reproduce your error, or I don't understand it:
AutoComplete

So when I type #fil I can select the #file entry which completes it to #file: and then triggers the selection at the top. I can abort it using escape key and then trigger the autocompletion using ctrl+space and get the autocompletion in place again.

Right, the behavior I'm referring to happens if you just type (no auto-completion) #file:. This should trigger a suggestion on the : which shows the possible arguments of the file variable.

On master this works but seemed to stop working in this PR. Let me know if you're having troubles to reproduce this.

@eneufeld
Copy link
Contributor Author

eneufeld commented Mar 3, 2025

I still can't reproduce it:
AutoComplete_2

Copy link
Contributor

@planger planger left a comment

Choose a reason for hiding this comment

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

I think your latest force-push actually fixed it. I tested it and now it looks like all use cases work fine.

@eneufeld eneufeld merged commit 14908a2 into eclipse-theia:master Mar 3, 2025
10 of 11 checks passed
@eneufeld eneufeld deleted the fix/GH-15028 branch March 3, 2025 16:38
@github-actions github-actions bot added this to the 1.60.0 milestone Mar 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

[Theia AI] Hashtags always autocomplete in the chat
2 participants