Change:
TLDR; Accepting Suggest Item (CompletionItem) fires partialAccept, but next line/next token acceptance fails to trigger the partialAccept. Repro steps: inline completion Suggest Dropdown accept next word (ctrl+right) PartialAccept notification sent Expected: PartialAccept message would be sent for the current shown completion Item This seems to occur as the edit application causes model update, which triggers disposal of inlineCompletions due to suggestItem being cleared. VS Code version: Code 1.83.0 OS version: ChromeOS Version 117.0.5938.144 (Official Build) (64-bit)
Can you reproduce in the ?
I wasn't able to reproduce in the playground. Might be already fixed at head? Closing as its already unrelevant, thanks!
We didn't touch that code for a while now. There might be an issue with the extension host or your extension though.
Might be, thanks for the pointers!
Hi . Sorry for reopening the issue, but I finally got to fixing it. It seems that the problem is in fact in the code, but its hard to reproduce in the playground, but here is the scenario: Note that this occurs mainly if the SuggestDropdown is second to arrive. E.g. if explicitly invoking suggest dropdown (ctrl+space) this doesn't seem to occur at all (Add breakpoints on the free & acceptPartial completion) in the already existing suggest dropdown appears, accept next token/next line (e.g. ctrl+right) the order of events. The free completion for the id of the suggestion is called before the partialAccept expected: The partialAccept is called before free, otherwise the extHost reference to the item will get disposed prematurely. This has the following effect. The Free calls dispose on and only afterwards the partial accept comes, which tries to fetch the completion by ID but it doesn't exist anymore. So the event is lost. The reason why its harder to reproduce in the playground environment is that the Extension host cleanup is not properly visible (we basically end at mainthread), as well as the suggest dropdown has to dissapear after the partial accept. Diving in to the reason why this fails: running the partialAccept triggers edit application, which runs the cursor move on SuggestController which runs and disposes the Suggest dropdown This in place reruns the in the inlineCompletions model which on non existent dropdown removes the SuggestWidget reference That causes the free up of the InlineCompletion reference, as its bound to the SuggestInfo The partial accept resumes and sends the event to mainthread which pushes it to extHost and tries to fetch the completion item, but its already been removed so no event is sent That raises 2 questions from my end. Shouldn't we add some telemetry in the ExtHost for these conditional retrievals to be able to preemtively catch issues with the non-connectivity (or possible regressions?) Should we increase the active reference to a completion in the partial Accept, to drop any possibility of race? proposed in

Discussion:
const partialText = line.substring(0, acceptUntilIndexExclusive); <del> this._isAcceptingPartially = true; </del> <ins> // Executing the edit might free the completion, so we have to hold a reference on it. completion.source.addRef(); </ins> try { <del> editor.pushUndoStop(); editor.executeEdits('inlineSuggestion.accept', [ EditOperation.replace(Range.fromPositions(position), partialText), ]); const length = lengthOfText(partialText); editor.setPosition(addPositions(position, length)); } finally { this._isAcceptingPartially = false; } </del> <ins> this._isAcceptingPartially = true; try { editor.pushUndoStop(); editor.executeEdits('inlineSuggestion.accept', [ EditOperation.replace(Range.fromPositions(position), partialText), ]); const length = lengthOfText(partialText); editor.setPosition(addPositions(position, length)); } finally { this._isAcceptingPartially = false; } </ins> <del> if (completion.source.provider.handlePartialAccept) { const acceptedRange = Range.fromPositions(completion.range.getStartPosition(), addPositions(position, lengthOfText(partialText))); // This assumes that the inline completion and the model use the same EOL style. const text = editor.getModel()!.getValueInRange(acceptedRange, EndOfLinePreference.LF); completion.source.provider.handlePartialAccept( completion.source.inlineCompletions, completion.sourceInlineCompletion, text.length, ); </del> <ins> if (completion.source.provider.handlePartialAccept) { const acceptedRange = Range.fromPositions(completion.range.getStartPosition(), addPositions(position, lengthOfText(partialText))); // This assumes that the inline completion and the model use the same EOL style. const text = editor.getModel()!.getValueInRange(acceptedRange, EndOfLinePreference.LF); completion.source.provider.handlePartialAccept( completion.source.inlineCompletions, completion.sourceInlineCompletion, text.length, ); } } finally { completion.source.removeRef(); </ins> } }