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

Fixes #153754. #180490

Merged
merged 2 commits into from
Apr 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/vs/editor/common/languages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -705,8 +705,9 @@ export interface InlineCompletionsProvider<T extends InlineCompletions = InlineC

/**
* 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { mapFind } from 'vs/base/common/arrays';
import { BugIndicatingError, onUnexpectedExternalError } from 'vs/base/common/errors';
import { Disposable } from 'vs/base/common/lifecycle';
import { IObservable, IReader, ITransaction, autorunHandleChanges, derived, observableSignal, observableValue, transaction } from 'vs/base/common/observable';
import { IObservable, IReader, ITransaction, autorun, autorunHandleChanges, derived, observableSignal, observableValue, transaction } from 'vs/base/common/observable';
import { isDefined } from 'vs/base/common/types';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditOperation } from 'vs/editor/common/core/editOperation';
Expand Down Expand Up @@ -76,6 +76,20 @@ export class InlineCompletionsModel extends Disposable {
}
preserveCurrentCompletion = false;
}));

let lastItem: InlineCompletionWithUpdatedRange | undefined = undefined;
this._register(autorun('call handleItemDidShow', reader => {
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<void> {
Expand Down Expand Up @@ -156,38 +170,39 @@ 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);
if (!isSuggestionPreviewEnabled && !augmentedCompletion) {
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);
Expand All @@ -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<void> {
await this._update(undefined, InlineCompletionTriggerKind.Explicit);
}
Expand Down
3 changes: 2 additions & 1 deletion src/vs/monaco.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6895,8 +6895,9 @@ declare namespace monaco.languages {
provideInlineCompletions(model: editor.ITextModel, position: Position, context: InlineCompletionContext, token: CancellationToken): ProviderResult<T>;
/**
* 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.
*/
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -561,9 +561,9 @@ export class MainThreadLanguageFeatures extends Disposable implements MainThread
provideInlineCompletions: async (model: ITextModel, position: EditorPosition, context: languages.InlineCompletionContext, token: CancellationToken): Promise<IdentifiableInlineCompletions | undefined> => {
return this._proxy.$provideInlineCompletions(handle, model.uri, position, context, token);
},
handleItemDidShow: async (completions: IdentifiableInlineCompletions, item: IdentifiableInlineCompletion): Promise<void> => {
handleItemDidShow: async (completions: IdentifiableInlineCompletions, item: IdentifiableInlineCompletion, updatedInsertText: string): Promise<void> => {
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<void> => {
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/api/common/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1863,7 +1863,7 @@ export interface ExtHostLanguageFeaturesShape {
$resolveCompletionItem(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<ISuggestDataDto | undefined>;
$releaseCompletionItems(handle: number, id: number): void;
$provideInlineCompletions(handle: number, resource: UriComponents, position: IPosition, context: languages.InlineCompletionContext, token: CancellationToken): Promise<IdentifiableInlineCompletions | undefined>;
$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<ISignatureHelpDto | undefined>;
Expand Down
10 changes: 5 additions & 5 deletions src/vs/workbench/api/common/extHostLanguageFeatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 { }
}
Expand Down Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down