Change:
<!-- Do Not Delete This! bugreporttemplate --<!-- Please read our Rules of Conduct: --<!-- Read our guide about submitting issues: --<!-- Search existing issues to avoid creating duplicates. --<!-- Test using the latest Insiders build to see if your issue has already been fixed: --<!-- Instead of creating your report here, use 'Report Issue' from the 'Help' menu in VS Code to pre-fill useful information. --<!-- Launch with to check. --<!-- If you answered No above, use 'Help: Start Extension Bisect' from Command Palette to try to identify the cause. --<!-- Issues caused by an extension need to be reported directly to the extension publisher. The 'Help Report Issue' dialog can assist with this. --- VS Code Version: 1.71.2 OS Version: Windows 10 x64 Steps to Reproduce: I'm experiencing this when using TypeScript. I'm not 100% sure why this happens but many times when typing a partial text, say like: I receive a list of completions, say the first one is: However, when pressing enter, instead of applying the completion, it applies a different completion that is not listed in the dropdown menu! For example, in this case, it found a module that contained a function called and decided to import the function from it. However, a suggestion for did not appear on the dropdown! After experimenting a bit with this I realized that the suggestion did later appear in the dropdown (?), but not initially. This is so strange. Is this an issue specific to the built-in TypeScript extension? (not sure?) or maybe has to do with the dropdown menu showing partial results (incremental loading?). This kind of subtle unexpected behavior is actually kind of tricky to notice. I usually type so fast that I tend to ignore / overlook it and simply undo it immediately (it happens a lot!). It took a while until I came to realize there might be an issue here (I verified several times that a suggestion for "filter" did not appear initially, yet it still used it as a completion).
There is no incremental loading, all results from all sources are awaited and shown at once. Am I understanding you correctly that you get suggestions (or that a request has been made) and that you continue typing to "narrow down" the (future) results and that a wrong suggestion is then selected? Do you have by any chance a recording so that I can look at this frame by frame. Or better have a small sample that shows reproduces this?
I'm not 100% sure what's happening. It seems like I selected a suggestion (e.g. ), but then since a better one exists () which is not listed, it is selected instead. This is very hard to reproduce (I haven't succeeded yet intentionally), since it seems like only happens for a short duration (maybe when some of the code syntactically broken?), and eventually the missing completion seems to appear later. I don't know. There's also the possibility that I've somehow become "selectively blind" to seeing only the option that I'm looking for, maybe I got mentally confused/overwhelmed due to how VSCode partially obscures the name with the identifier's declaration string (which is another issue): ! Maybe I thought I selected the right option, which I believed was partially obscured (e.g. ), but it wasn't? Anyway I'll try to reproduce this again, and if I don't succeed in while, I'll close the issue. When I opened it I was very sure what was happening was real. This is pretty mysterious..
For better reference, I've made some screenshots of the particular situation I originally encountered. While trying to reproduce this I noticed that when I type , my top suggestion is ! But if I add the letter , then the top suggestion changes to : ! It could be that the particular issue I had was that I typed the word but the suggestion menu, due to some reason, was too slow to update to the additional letter , so based on what I believed that the selection I made was , but since internally the extra letter was caught, it applied a different completion than I expected. This seems to happen a lot. Maybe there's something that can be done to improve it?
I trust your observation. Looking at the code there might be a small chance of inserting an outdated item, when typing we resort/refilter all suggestions. Tho, we do that at end of the current (macro-)task and if you accept a suggestion we will pick the "old" one - accepting doesn't wait for scheduled resort/refilter. All of this happens in the same task, so should occur rarely and only when typing really fast. It would be really great and helpful if you can capture a recording of this. Then I can look at this frame by frame and understand what's happening
Track this as a bug - despite the lack of repro steps This is likely happening because the refiltering happens in a at the time of the model change the editor selection isn't updated yet. Inserting a suggestion doesn't wait for this to happen and will insert the suggestion from the N-1 state
Wow. Thanks for attempting to provide help! I'll try my best to get a better understanding of this while it happens. It seems to be very difficult to analyze and reproduce. What I gave so far are mostly hypotheses (several different ones), not definite evidence. This is the type of thing that users might experience (perhaps a lot) but will find it elusive to characterize or even comprehend and may just attribute to their own human error. I simply had things like this happing too often that at some point I felt I had to do something about it, though I haven't succeeded at characterizing it exactly (maybe it also have to do with the fact I'm using a slow, 9 year old PC.. so these subtle "blink-of-an-eye" kind of behaviors are more visible to me).
<!-- AUTHORVERIFICATIONREQUEST --This bug has been fixed in the latest release of ! you can help us out by commenting if things are now working as expected. If things still don't seem right, please ensure you're on version of Insiders (today's or later - you can use in the command palette to check), and leave a comment letting us know what isn't working as expected. Happy Coding!
Couldn't reproduce this myself so did a review of the code change and the tests.

Discussion:
import { IWordAtPosition } from 'vs/editor/common/core/wordHelper'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; import { FuzzyScoreOptions } from 'vs/base/common/filters'; <ins> import { assertType } from 'vs/base/common/types'; </ins> export interface ICancelEvent { readonly retrigger: boolean;

} private _refilterCompletionItems(): void { <del> // Re-filter suggestions. This MUST run async because filtering/scoring // uses the model content AND the cursor position. The latter is NOT // updated when the document has changed (the event which drives this method) // and therefore a little pause (next mirco task) is needed. See: // https://stackoverflow.com/questions/25915634/difference-between-microtask-and-macrotask-within-an-event-loop-context#25933985 Promise.resolve().then(() => { if (this._state === State.Idle) { return; } if (!this._editor.hasModel()) { return; } const model = this._editor.getModel(); const position = this._editor.getPosition(); const ctx = new LineContext(model, position, this._state === State.Auto, false, false); this._onNewContext(ctx); }); </del> <ins> assertType(this._editor.hasModel()); const model = this._editor.getModel(); const position = this._editor.getPosition(); const ctx = new LineContext(model, position, this._state === State.Auto, false, false); this._onNewContext(ctx); </ins> } trigger(context: SuggestTriggerContext, retrigger: boolean = false, onlyFrom?: Set<CompletionItemProvider>, existing?: { items: CompletionItem[]; clipboardText: string | undefined }, noFilter?: boolean): void {

assert.strictEqual(editor.getValue(), 'import "my_class.txt";nMyClassName'); }); <ins> test('Pressing enter on autocomplete should always apply the selected dropdown completion, not a different, hidden one #161883', async function () { disposables.add(languageFeaturesService.completionProvider.register({ scheme: 'test-ctrl' }, { provideCompletionItems(doc, pos) { const word = doc.getWordUntilPosition(pos); const range = new Range(pos.lineNumber, word.startColumn, pos.lineNumber, word.endColumn); return { suggestions: [{ kind: CompletionItemKind.Text, label: 'filterBankSize', insertText: 'filterBankSize', sortText: 'a', range }, { kind: CompletionItemKind.Text, label: 'filter', insertText: 'filter', sortText: 'b', range }] }; } })); editor.setValue('filte'); editor.setSelection(new Selection(1, 6, 1, 6)); const p1 = Event.toPromise(controller.model.onDidSuggest); controller.triggerSuggest(); const { completionModel } = await p1; assert.strictEqual(completionModel.items.length, 2); const [first, second] = completionModel.items; assert.strictEqual(first.textLabel, 'filterBankSize'); assert.strictEqual(second.textLabel, 'filter'); assert.deepStrictEqual(editor.getSelection(), new Selection(1, 6, 1, 6)); editor.trigger('keyboard', 'type', { text: 'r' }); // now filter "overtakes" filterBankSize because it is fully matched assert.deepStrictEqual(editor.getSelection(), new Selection(1, 7, 1, 7)); controller.acceptSelectedSuggestion(false, false); assert.strictEqual(editor.getValue(), 'filter'); }); test('Fast autocomple typing selects the previous autocomplete suggestion, #71795', async function () { disposables.add(languageFeaturesService.completionProvider.register({ scheme: 'test-ctrl' }, { provideCompletionItems(doc, pos) { const word = doc.getWordUntilPosition(pos); const range = new Range(pos.lineNumber, word.startColumn, pos.lineNumber, word.endColumn); return { suggestions: [{ kind: CompletionItemKind.Text, label: 'false', insertText: 'false', range }, { kind: CompletionItemKind.Text, label: 'float', insertText: 'float', range }, { kind: CompletionItemKind.Text, label: 'for', insertText: 'for', range }, { kind: CompletionItemKind.Text, label: 'foreach', insertText: 'foreach', range }] }; } })); editor.setValue('f'); editor.setSelection(new Selection(1, 2, 1, 2)); const p1 = Event.toPromise(controller.model.onDidSuggest); controller.triggerSuggest(); const { completionModel } = await p1; assert.strictEqual(completionModel.items.length, 4); const [first, second, third, fourth] = completionModel.items; assert.strictEqual(first.textLabel, 'false'); assert.strictEqual(second.textLabel, 'float'); assert.strictEqual(third.textLabel, 'for'); assert.strictEqual(fourth.textLabel, 'foreach'); assert.deepStrictEqual(editor.getSelection(), new Selection(1, 2, 1, 2)); editor.trigger('keyboard', 'type', { text: 'o' }); // filters`false` and `float` assert.deepStrictEqual(editor.getSelection(), new Selection(1, 3, 1, 3)); controller.acceptSelectedSuggestion(false, false); assert.strictEqual(editor.getValue(), 'for'); }); </ins> });

model.setValue(''); <del> return withOracle((model, editor) => { </del> <ins> return withOracle(async (model, editor) => { </ins> <del> return assertEvent(model.onDidSuggest, () => { </del> <ins> await assertEvent(model.onDidSuggest, () => { </ins> editor.setPosition({ lineNumber: 1, column: 1 }); editor.trigger('keyboard', Handler.Type, { text: 'foo' });

const [first] = event.completionModel.items; assert.strictEqual(first.completion.label, 'foo.bar'); <del> return assertEvent(model.onDidSuggest, () => { editor.trigger('keyboard', Handler.Type, { text: '.' }); </del> <ins> }); </ins> <del> }, event => { assert.strictEqual(event.auto, true); assert.strictEqual(event.completionModel.items.length, 2); const [first, second] = event.completionModel.items; assert.strictEqual(first.completion.label, 'foo.bar'); assert.strictEqual(second.completion.label, 'boom'); }); </del> <ins> await assertEvent(model.onDidSuggest, () => { editor.trigger('keyboard', Handler.Type, { text: '.' }); }, event => { // SYNC assert.strictEqual(event.auto, true); assert.strictEqual(event.completionModel.items.length, 1); const [first] = event.completionModel.items; assert.strictEqual(first.completion.label, 'foo.bar'); }); await assertEvent(model.onDidSuggest, () => { // nothing -> triggered by the trigger character typing (see above) }, event => { // ASYNC assert.strictEqual(event.auto, true); assert.strictEqual(event.completionModel.items.length, 2); const [first, second] = event.completionModel.items; assert.strictEqual(first.completion.label, 'foo.bar'); assert.strictEqual(second.completion.label, 'boom'); </ins> }); }); });