Fixes #137000. SelectedCompletionInfo now has the members completionKind and isSnippetText.

This commit is contained in:
Henning Dieterichs 2021-11-23 15:30:55 +01:00
parent 0231d1aa45
commit 075ba020e8
No known key found for this signature in database
GPG key ID: 771381EFFDB9EC06
6 changed files with 63 additions and 24 deletions

View file

@ -677,6 +677,8 @@ export interface InlineCompletionContext {
export interface SelectedSuggestionInfo {
range: IRange;
text: string;
isSnippetText: boolean;
completionKind: CompletionItemKind;
}
export interface InlineCompletion {

View file

@ -9,7 +9,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { CompletionItemInsertTextRule } from 'vs/editor/common/modes';
import { CompletionItemInsertTextRule, CompletionItemKind } from 'vs/editor/common/modes';
import { SnippetParser } from 'vs/editor/contrib/snippet/snippetParser';
import { SnippetSession } from 'vs/editor/contrib/snippet/snippetSession';
import { CompletionItem } from 'vs/editor/contrib/suggest/suggest';
@ -22,14 +22,20 @@ export interface SuggestWidgetState {
/**
* Represents the currently selected item in the suggest widget as inline completion, if possible.
*/
selectedItemAsInlineCompletion: NormalizedInlineCompletion | undefined;
selectedItem: SuggestItemInfo | undefined;
}
export interface SuggestItemInfo {
normalizedInlineCompletion: NormalizedInlineCompletion;
isSnippetText: boolean;
completionItemKind: CompletionItemKind;
}
export class SuggestWidgetInlineCompletionProvider extends Disposable {
private isSuggestWidgetVisible: boolean = false;
private isShiftKeyPressed = false;
private _isActive = false;
private _currentInlineCompletion: NormalizedInlineCompletion | undefined = undefined;
private _currentSuggestItemInfo: SuggestItemInfo | undefined = undefined;
private readonly onDidChangeEmitter = new Emitter<void>();
public readonly onDidChange = this.onDidChangeEmitter.event;
@ -51,7 +57,7 @@ export class SuggestWidgetInlineCompletionProvider extends Disposable {
if (!this._isActive) {
return undefined;
}
return { selectedItemAsInlineCompletion: this._currentInlineCompletion };
return { selectedItem: this._currentSuggestItemInfo };
}
constructor(
@ -88,8 +94,8 @@ export class SuggestWidgetInlineCompletionProvider extends Disposable {
const candidates = suggestItems
.map((suggestItem, index) => {
const inlineSuggestItem = suggestionToInlineCompletion(suggestController, position, suggestItem, this.isShiftKeyPressed);
const normalizedSuggestItem = minimizeInlineCompletion(textModel, inlineSuggestItem);
const inlineSuggestItem = suggestionToSuggestItemInfo(suggestController, position, suggestItem, this.isShiftKeyPressed);
const normalizedSuggestItem = minimizeInlineCompletion(textModel, inlineSuggestItem?.normalizedInlineCompletion);
if (!normalizedSuggestItem) {
return undefined;
}
@ -138,10 +144,10 @@ export class SuggestWidgetInlineCompletionProvider extends Disposable {
}
private update(newActive: boolean): void {
const newInlineCompletion = this.getInlineCompletion();
const newInlineCompletion = this.getSuggestItemInfo();
let shouldFire = false;
if (!normalizedInlineCompletionsEquals(this._currentInlineCompletion, newInlineCompletion)) {
this._currentInlineCompletion = newInlineCompletion;
if (!suggestItemInfoEquals(this._currentSuggestItemInfo, newInlineCompletion)) {
this._currentSuggestItemInfo = newInlineCompletion;
shouldFire = true;
}
if (this._isActive !== newActive) {
@ -153,7 +159,7 @@ export class SuggestWidgetInlineCompletionProvider extends Disposable {
}
}
private getInlineCompletion(): NormalizedInlineCompletion | undefined {
private getSuggestItemInfo(): SuggestItemInfo | undefined {
const suggestController = SuggestController.get(this.editor);
if (!suggestController) {
return undefined;
@ -167,7 +173,7 @@ export class SuggestWidgetInlineCompletionProvider extends Disposable {
}
// TODO: item.isResolved
return suggestionToInlineCompletion(
return suggestionToSuggestItemInfo(
suggestController,
this.editor.getPosition(),
focusedItem.item,
@ -200,17 +206,35 @@ export function rangeStartsWith(rangeToTest: Range, prefix: Range): boolean {
);
}
function suggestionToInlineCompletion(suggestController: SuggestController, position: Position, item: CompletionItem, toggleMode: boolean): NormalizedInlineCompletion | undefined {
function suggestItemInfoEquals(a: SuggestItemInfo | undefined, b: SuggestItemInfo | undefined): boolean {
if (a === b) {
return true;
}
if (!a || !b) {
return false;
}
return a.completionItemKind === b.completionItemKind &&
a.isSnippetText === b.isSnippetText &&
normalizedInlineCompletionsEquals(a.normalizedInlineCompletion, b.normalizedInlineCompletion);
}
function suggestionToSuggestItemInfo(suggestController: SuggestController, position: Position, item: CompletionItem, toggleMode: boolean): SuggestItemInfo | undefined {
// additionalTextEdits might not be resolved here, this could be problematic.
if (Array.isArray(item.completion.additionalTextEdits) && item.completion.additionalTextEdits.length > 0) {
// cannot represent additional text edits
return {
text: '',
range: Range.fromPositions(position, position),
completionItemKind: item.completion.kind,
isSnippetText: false,
normalizedInlineCompletion: {
// Dummy element, so that space is reserved, but no text is shown
range: Range.fromPositions(position, position),
text: ''
},
};
}
let { insertText } = item.completion;
let isSnippetText = false;
if (item.completion.insertTextRules! & CompletionItemInsertTextRule.InsertAsSnippet) {
const snippet = new SnippetParser().parse(insertText);
const model = suggestController.editor.getModel()!;
@ -223,14 +247,19 @@ function suggestionToInlineCompletion(suggestController: SuggestController, posi
SnippetSession.adjustWhitespace(model, position, snippet, true, true);
insertText = snippet.toString();
isSnippetText = true;
}
const info = suggestController.getOverwriteInfo(item, toggleMode);
return {
text: insertText,
range: Range.fromPositions(
position.delta(0, -info.overwriteBefore),
position.delta(0, Math.max(info.overwriteAfter, 0))
),
isSnippetText,
completionItemKind: item.completion.kind,
normalizedInlineCompletion: {
text: insertText,
range: Range.fromPositions(
position.delta(0, -info.overwriteBefore),
position.delta(0, Math.max(info.overwriteAfter, 0))
),
}
};
}

View file

@ -79,13 +79,15 @@ export class SuggestWidgetPreviewModel extends BaseGhostTextWidgetModel {
private async updateCache() {
const state = this.suggestionInlineCompletionSource.state;
if (!state || !state.selectedItemAsInlineCompletion) {
if (!state || !state.selectedItem) {
return;
}
const info: SelectedSuggestionInfo = {
text: state.selectedItemAsInlineCompletion.text,
range: state.selectedItemAsInlineCompletion.range,
text: state.selectedItem.normalizedInlineCompletion.text,
range: state.selectedItem.normalizedInlineCompletion.range,
isSnippetText: state.selectedItem.isSnippetText,
completionKind: state.selectedItem.completionItemKind,
};
const position = this.editor.getPosition();
@ -125,7 +127,7 @@ export class SuggestWidgetPreviewModel extends BaseGhostTextWidgetModel {
const augmentedCompletion = minimizeInlineCompletion(this.editor.getModel()!, this.cache.value?.completions[0]?.toLiveInlineCompletion());
const suggestWidgetState = this.suggestionInlineCompletionSource.state;
const suggestInlineCompletion = minimizeInlineCompletion(this.editor.getModel()!, suggestWidgetState?.selectedItemAsInlineCompletion);
const suggestInlineCompletion = minimizeInlineCompletion(this.editor.getModel()!, suggestWidgetState?.selectedItem?.normalizedInlineCompletion);
const isAugmentedCompletionValid = augmentedCompletion
&& suggestInlineCompletion

2
src/vs/monaco.d.ts vendored
View file

@ -6019,6 +6019,8 @@ declare namespace monaco.languages {
export interface SelectedSuggestionInfo {
range: IRange;
text: string;
isSnippetText: boolean;
completionKind: CompletionItemKind;
}
export interface InlineCompletion {

View file

@ -1042,7 +1042,9 @@ class InlineCompletionAdapter {
context.selectedSuggestionInfo
? {
range: typeConvert.Range.to(context.selectedSuggestionInfo.range),
text: context.selectedSuggestionInfo.text
text: context.selectedSuggestionInfo.text,
isSnippetText: context.selectedSuggestionInfo.isSnippetText,
completionKind: typeConvert.CompletionItemKind.to(context.selectedSuggestionInfo.completionKind),
}
: undefined,
triggerKind: context.triggerKind

View file

@ -48,6 +48,8 @@ declare module 'vscode' {
export interface SelectedCompletionInfo {
range: Range;
text: string;
completionKind: CompletionItemKind;
isSnippetText: boolean;
}
/**