From b2cddf3e6464b6e68203eec009f52d7d3bc9d057 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 21 Apr 2023 11:27:20 +0200 Subject: [PATCH] Fixes #153754. (#180490) * Fixes #153754. * Fixes #159479 --- src/vs/editor/common/languages.ts | 3 +- .../browser/inlineCompletionsModel.ts | 42 ++++++++++++++----- src/vs/monaco.d.ts | 3 +- .../api/browser/mainThreadLanguageFeatures.ts | 4 +- .../workbench/api/common/extHost.protocol.ts | 2 +- .../api/common/extHostLanguageFeatures.ts | 10 ++--- ...e.proposed.inlineCompletionsAdditions.d.ts | 6 ++- 7 files changed, 49 insertions(+), 21 deletions(-) diff --git a/src/vs/editor/common/languages.ts b/src/vs/editor/common/languages.ts index ab948f583ed84..711a372d0d8de 100644 --- a/src/vs/editor/common/languages.ts +++ b/src/vs/editor/common/languages.ts @@ -705,8 +705,9 @@ export interface InlineCompletionsProvider { + const item = this.ghostTextAndCompletion.read(reader); + const completion = item?.completion; + if (completion?.semanticId !== lastItem?.semanticId) { + lastItem = completion; + if (completion) { + const i = completion.inlineCompletion; + const src = i.source; + src.provider.handleItemDidShow?.(src.inlineCompletions, i.sourceInlineCompletion, i.insertText); + } + } + })); } private async _update(reader: IReader | undefined, triggerKind: InlineCompletionTriggerKind, preserveCurrentCompletion: boolean = false): Promise { @@ -156,22 +170,22 @@ export class InlineCompletionsModel extends Disposable { } }); - public readonly ghostText = derived('ghostText', (reader) => { + public readonly ghostTextAndCompletion = derived('ghostText', (reader) => { const model = this.textModel; const suggestItem = this.selectedSuggestItem.read(reader); if (suggestItem) { const suggestWidgetInlineCompletions = this._source.suggestWidgetInlineCompletions.read(reader); - const candidateInlineCompletion = suggestWidgetInlineCompletions + const candidateInlineCompletions = suggestWidgetInlineCompletions ? suggestWidgetInlineCompletions.inlineCompletions : [this.selectedInlineCompletion.read(reader)].filter(isDefined); const suggestCompletion = suggestItem.toSingleTextEdit().removeCommonPrefix(model); - const augmentedCompletion = mapFind(candidateInlineCompletion, c => { - let r = c.toSingleTextEdit(reader); + const augmentedCompletion = mapFind(candidateInlineCompletions, completion => { + let r = completion.toSingleTextEdit(reader); r = r.removeCommonPrefix(model, Range.fromPositions(r.range.getStartPosition(), suggestItem.range.getEndPosition())); - return r.augments(suggestCompletion) ? r : undefined; + return r.augments(suggestCompletion) ? { edit: r, completion } : undefined; }); const isSuggestionPreviewEnabled = this._suggestPreviewEnabled.read(reader); @@ -179,15 +193,16 @@ export class InlineCompletionsModel extends Disposable { return undefined; } - const edit = augmentedCompletion ?? suggestCompletion; - const editPreviewLength = augmentedCompletion ? augmentedCompletion.text.length - suggestCompletion.text.length : 0; + const edit = augmentedCompletion?.edit ?? suggestCompletion; + const editPreviewLength = augmentedCompletion ? augmentedCompletion.edit.text.length - suggestCompletion.text.length : 0; const mode = this._suggestPreviewMode.read(reader); const cursor = this.cursorPosition.read(reader); const newGhostText = edit.computeGhostText(model, mode, cursor, editPreviewLength); // Show an invisible ghost text to reserve space - return newGhostText ?? new GhostText(edit.range.endLineNumber, []); + const ghostText = newGhostText ?? new GhostText(edit.range.endLineNumber, []); + return { ghostText, completion: augmentedCompletion?.completion }; } else { if (!this._isActive.read(reader)) { return undefined; } const item = this.selectedInlineCompletion.read(reader); @@ -196,10 +211,17 @@ export class InlineCompletionsModel extends Disposable { const replacement = item.toSingleTextEdit(reader); const mode = this._inlineSuggestMode.read(reader); const cursor = this.cursorPosition.read(reader); - return replacement.computeGhostText(model, mode, cursor); + const ghostText = replacement.computeGhostText(model, mode, cursor); + return ghostText ? { ghostText, completion: item } : undefined; } }); + public readonly ghostText = derived('ghostText', (reader) => { + const v = this.ghostTextAndCompletion.read(reader); + if (!v) { return undefined; } + return v.ghostText; + }); + public async triggerExplicitly(): Promise { await this._update(undefined, InlineCompletionTriggerKind.Explicit); } diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index fa0ca5ee7b4d9..ae937a7654c84 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -6895,8 +6895,9 @@ declare namespace monaco.languages { provideInlineCompletions(model: editor.ITextModel, position: Position, context: InlineCompletionContext, token: CancellationToken): ProviderResult; /** * Will be called when an item is shown. + * @param updatedInsertText Is useful to understand bracket completion. */ - handleItemDidShow?(completions: T, item: T['items'][number]): void; + handleItemDidShow?(completions: T, item: T['items'][number], updatedInsertText: string): void; /** * Will be called when an item is partially accepted. */ diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index 12badd0d5be78..cade9c37d39e6 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -561,9 +561,9 @@ export class MainThreadLanguageFeatures extends Disposable implements MainThread provideInlineCompletions: async (model: ITextModel, position: EditorPosition, context: languages.InlineCompletionContext, token: CancellationToken): Promise => { return this._proxy.$provideInlineCompletions(handle, model.uri, position, context, token); }, - handleItemDidShow: async (completions: IdentifiableInlineCompletions, item: IdentifiableInlineCompletion): Promise => { + handleItemDidShow: async (completions: IdentifiableInlineCompletions, item: IdentifiableInlineCompletion, updatedInsertText: string): Promise => { if (supportsHandleEvents) { - await this._proxy.$handleInlineCompletionDidShow(handle, completions.pid, item.idx); + await this._proxy.$handleInlineCompletionDidShow(handle, completions.pid, item.idx, updatedInsertText); } }, handlePartialAccept: async (completions, item, acceptedCharacters): Promise => { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index b36938696583f..f95e8c929b21f 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1863,7 +1863,7 @@ export interface ExtHostLanguageFeaturesShape { $resolveCompletionItem(handle: number, id: ChainedCacheId, token: CancellationToken): Promise; $releaseCompletionItems(handle: number, id: number): void; $provideInlineCompletions(handle: number, resource: UriComponents, position: IPosition, context: languages.InlineCompletionContext, token: CancellationToken): Promise; - $handleInlineCompletionDidShow(handle: number, pid: number, idx: number): void; + $handleInlineCompletionDidShow(handle: number, pid: number, idx: number, updatedInsertText: string): void; $handleInlineCompletionPartialAccept(handle: number, pid: number, idx: number, acceptedCharacters: number): void; $freeInlineCompletionsList(handle: number, pid: number): void; $provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: languages.SignatureHelpContext, token: CancellationToken): Promise; diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index ddb34ac6f3497..8e099740aad9d 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -1100,7 +1100,7 @@ class InlineCompletionAdapterBase { disposeCompletions(pid: number): void { } - handleDidShowCompletionItem(pid: number, idx: number): void { } + handleDidShowCompletionItem(pid: number, idx: number, updatedInsertText: string): void { } handlePartialAccept(pid: number, idx: number, acceptedCharacters: number): void { } } @@ -1209,11 +1209,11 @@ class InlineCompletionAdapter extends InlineCompletionAdapterBase { data?.dispose(); } - override handleDidShowCompletionItem(pid: number, idx: number): void { + override handleDidShowCompletionItem(pid: number, idx: number, updatedInsertText: string): void { const completionItem = this._references.get(pid)?.items[idx]; if (completionItem) { if (this._provider.handleDidShowCompletionItem && this._isAdditionsProposedApiEnabled) { - this._provider.handleDidShowCompletionItem(completionItem); + this._provider.handleDidShowCompletionItem(completionItem, updatedInsertText); } } } @@ -2207,9 +2207,9 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF return this._withAdapter(handle, InlineCompletionAdapterBase, adapter => adapter.provideInlineCompletions(URI.revive(resource), position, context, token), undefined, token); } - $handleInlineCompletionDidShow(handle: number, pid: number, idx: number): void { + $handleInlineCompletionDidShow(handle: number, pid: number, idx: number, updatedInsertText: string): void { this._withAdapter(handle, InlineCompletionAdapterBase, async adapter => { - adapter.handleDidShowCompletionItem(pid, idx); + adapter.handleDidShowCompletionItem(pid, idx, updatedInsertText); }, undefined, undefined); } diff --git a/src/vscode-dts/vscode.proposed.inlineCompletionsAdditions.d.ts b/src/vscode-dts/vscode.proposed.inlineCompletionsAdditions.d.ts index 241ccd1ffed1d..8412aca06edc4 100644 --- a/src/vscode-dts/vscode.proposed.inlineCompletionsAdditions.d.ts +++ b/src/vscode-dts/vscode.proposed.inlineCompletionsAdditions.d.ts @@ -16,8 +16,12 @@ declare module 'vscode' { } export interface InlineCompletionItemProvider { + /** + * @param completionItem The completion item that was shown. + * @param updatedInsertText The actual insert text (after brackets were fixed). + */ // eslint-disable-next-line local/vscode-dts-provider-naming - handleDidShowCompletionItem?(completionItem: InlineCompletionItem): void; + handleDidShowCompletionItem?(completionItem: InlineCompletionItem, updatedInsertText: string): void; /** * Is called when an inline completion item was accepted partially.