mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-10 05:28:19 -05:00
first cut of CompletionItem#commitCharacters, #7326
This commit is contained in:
@@ -214,6 +214,7 @@ export interface ISuggestion {
|
||||
filterText?: string;
|
||||
sortText?: string;
|
||||
noAutoAccept?: boolean;
|
||||
commitCharacters?: string[];
|
||||
overwriteBefore?: number;
|
||||
overwriteAfter?: number;
|
||||
additionalTextEdits?: editorCommon.ISingleEditOperation[];
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import * as nls from 'vs/nls';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
@@ -25,6 +26,47 @@ import { SuggestModel } from '../common/suggestModel';
|
||||
import { ICompletionItem } from '../common/completionModel';
|
||||
import { SuggestWidget } from './suggestWidget';
|
||||
|
||||
class AcceptOnCharacterOracle {
|
||||
|
||||
private _disposables: IDisposable[] = [];
|
||||
|
||||
private _activeAcceptCharacters = new Set<string>();
|
||||
private _activeItem: ICompletionItem;
|
||||
|
||||
constructor(editor: ICodeEditor, widget: SuggestWidget, accept: (item: ICompletionItem) => any) {
|
||||
|
||||
this._disposables.push(widget.onDidFocus(item => {
|
||||
if (!item || isFalsyOrEmpty(item.suggestion.commitCharacters)) {
|
||||
this._activeItem = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
this._activeItem = item;
|
||||
this._activeAcceptCharacters.clear();
|
||||
for (const ch of item.suggestion.commitCharacters) {
|
||||
this._activeAcceptCharacters.add(ch[0]);
|
||||
}
|
||||
}));
|
||||
|
||||
this._disposables.push(editor.onWillType(text => {
|
||||
if (this._activeItem) {
|
||||
const ch = text[text.length - 1];
|
||||
if (this._activeAcceptCharacters.has(ch)) {
|
||||
accept(this._activeItem);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this._activeItem = undefined;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
dispose(this._disposables);
|
||||
}
|
||||
}
|
||||
|
||||
@editorContribution
|
||||
export class SuggestController implements IEditorContribution {
|
||||
private static ID: string = 'editor.contrib.suggestController';
|
||||
@@ -59,6 +101,14 @@ export class SuggestController implements IEditorContribution {
|
||||
|
||||
this.widget = instantiationService.createInstance(SuggestWidget, this.editor);
|
||||
this.toDispose.push(this.widget.onDidSelect(this.onDidSelectItem, this));
|
||||
|
||||
// Wire up logic to accept a suggestion on certain characters
|
||||
const autoAcceptOracle = new AcceptOnCharacterOracle(editor, this.widget, item => this.onDidSelectItem(item));
|
||||
this.toDispose.push(
|
||||
this.model.onDidCancel(autoAcceptOracle.reset, autoAcceptOracle),
|
||||
this.model.onDidTrigger(autoAcceptOracle.reset, autoAcceptOracle),
|
||||
autoAcceptOracle
|
||||
);
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
|
||||
@@ -293,7 +293,7 @@ export class SuggestWidget implements IContentWidget, IDelegate<ICompletionItem>
|
||||
static NO_SUGGESTIONS_MESSAGE: string = nls.localize('suggestWidget.noSuggestions', "No suggestions.");
|
||||
|
||||
// Editor.IContentWidget.allowEditorOverflow
|
||||
allowEditorOverflow = true;
|
||||
readonly allowEditorOverflow = true;
|
||||
|
||||
private state: State;
|
||||
private isAuto: boolean;
|
||||
@@ -312,12 +312,16 @@ export class SuggestWidget implements IContentWidget, IDelegate<ICompletionItem>
|
||||
private suggestWidgetMultipleSuggestions: IContextKey<boolean>;
|
||||
private suggestionSupportsAutoAccept: IContextKey<boolean>;
|
||||
|
||||
private onDidSelectEmitter = new Emitter<ICompletionItem>();
|
||||
|
||||
private editorBlurTimeout: TPromise<void>;
|
||||
private showTimeout: TPromise<void>;
|
||||
private toDispose: IDisposable[];
|
||||
|
||||
private onDidSelectEmitter = new Emitter<ICompletionItem>();
|
||||
private onDidFocusEmitter = new Emitter<ICompletionItem>();
|
||||
|
||||
readonly onDidSelect: Event<ICompletionItem> = this.onDidSelectEmitter.event;
|
||||
readonly onDidFocus: Event<ICompletionItem> = this.onDidFocusEmitter.event;
|
||||
|
||||
constructor(
|
||||
private editor: ICodeEditor,
|
||||
@ITelemetryService private telemetryService: ITelemetryService,
|
||||
@@ -472,6 +476,9 @@ export class SuggestWidget implements IContentWidget, IDelegate<ICompletionItem>
|
||||
})
|
||||
.then(null, err => !isPromiseCanceledError(err) && onUnexpectedError(err))
|
||||
.then(() => this.currentSuggestionDetails = null);
|
||||
|
||||
// emit an event
|
||||
this.onDidFocusEmitter.fire(item);
|
||||
}
|
||||
|
||||
private setState(state: State): void {
|
||||
@@ -528,10 +535,6 @@ export class SuggestWidget implements IContentWidget, IDelegate<ICompletionItem>
|
||||
}
|
||||
}
|
||||
|
||||
get onDidSelect(): Event<ICompletionItem> {
|
||||
return this.onDidSelectEmitter.event;
|
||||
}
|
||||
|
||||
showTriggered(auto: boolean) {
|
||||
if (this.state !== State.Hidden) {
|
||||
return;
|
||||
|
||||
9
src/vs/vscode.d.ts
vendored
9
src/vs/vscode.d.ts
vendored
@@ -2396,6 +2396,13 @@ declare module 'vscode' {
|
||||
*/
|
||||
range?: Range;
|
||||
|
||||
/**
|
||||
* An optional set of characters that when pressed while this completion is active will accept it first and
|
||||
* then insert type that character. *Note* that all commit characters should have `length=1` and that superfluous
|
||||
* characters will be ignored.
|
||||
*/
|
||||
commitCharacters?: string[];
|
||||
|
||||
/**
|
||||
* @deprecated **Deprecated** in favor of `CompletionItem.insertText` and `CompletionItem.range`.
|
||||
*
|
||||
@@ -2814,7 +2821,7 @@ declare module 'vscode' {
|
||||
/**
|
||||
* Readable dictionary that backs this configuration.
|
||||
*/
|
||||
readonly [key: string]: any;
|
||||
readonly[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -514,7 +514,8 @@ class SuggestAdapter {
|
||||
//
|
||||
insertText: undefined,
|
||||
additionalTextEdits: item.additionalTextEdits && item.additionalTextEdits.map(TypeConverters.TextEdit.from),
|
||||
command: this._commands.toInternal(item.command)
|
||||
command: this._commands.toInternal(item.command),
|
||||
commitCharacters: item.commitCharacters
|
||||
};
|
||||
|
||||
// 'insertText'-logic
|
||||
|
||||
Reference in New Issue
Block a user