mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-20 19:14:10 +01:00
show IntelliSense window when having multiple tab completions, #22216
This commit is contained in:
@@ -21,6 +21,7 @@ import { alert } from 'vs/base/browser/ui/aria/aria';
|
||||
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ISuggestSupport } from 'vs/editor/common/modes';
|
||||
import { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser';
|
||||
import { SnippetController2 } from 'vs/editor/contrib/snippet/browser/snippetController2';
|
||||
import { Context as SuggestContext } from './suggest';
|
||||
@@ -210,8 +211,8 @@ export class SuggestController implements IEditorContribution {
|
||||
alert(msg);
|
||||
}
|
||||
|
||||
triggerSuggest(): void {
|
||||
this._model.trigger(false, false);
|
||||
triggerSuggest(onlyFrom?: ISuggestSupport[]): void {
|
||||
this._model.trigger(false, false, onlyFrom);
|
||||
this._editor.revealLine(this._editor.getPosition().lineNumber);
|
||||
this._editor.focus();
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ export interface ISimpleModel {
|
||||
getLineContent(lineNumber: number): string;
|
||||
}
|
||||
|
||||
class SnippetSuggestion implements ISuggestion {
|
||||
export class SnippetSuggestion implements ISuggestion {
|
||||
|
||||
private static _userSnippet = localize('source.snippet', "User Snippet");
|
||||
|
||||
|
||||
@@ -9,16 +9,50 @@ import { localize } from 'vs/nls';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { RawContextKey, IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { ISnippetsService, getNonWhitespacePrefix, ISnippet } from 'vs/workbench/parts/snippets/electron-browser/snippetsService';
|
||||
import { ISnippetsService, getNonWhitespacePrefix, ISnippet, SnippetSuggestion } from 'vs/workbench/parts/snippets/electron-browser/snippetsService';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { endsWith } from 'vs/base/common/strings';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { CommonEditorRegistry, commonEditorContribution, EditorCommand } from 'vs/editor/common/editorCommonExtensions';
|
||||
import { SnippetController2 } from 'vs/editor/contrib/snippet/browser/snippetController2';
|
||||
import { SuggestController } from 'vs/editor/contrib/suggest/browser/suggestController';
|
||||
import { ISuggestSupport, ISuggestResult, SuggestRegistry } from 'vs/editor/common/modes';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { IConfigurationRegistry, Extensions as ConfigExt } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
|
||||
class TabCompletionProvider implements ISuggestSupport {
|
||||
|
||||
position: Position;
|
||||
snippets: ISnippet[];
|
||||
|
||||
reset(): this {
|
||||
return this.set(undefined, undefined);
|
||||
}
|
||||
|
||||
set(position: Position, snippets: ISnippet[]): this {
|
||||
this.position = position;
|
||||
this.snippets = snippets;
|
||||
return this;
|
||||
}
|
||||
|
||||
provideCompletionItems(model: editorCommon.IModel, position: Position): ISuggestResult {
|
||||
if (!this.snippets
|
||||
|| this.position.lineNumber !== position.lineNumber
|
||||
|| this.position.column > position.column
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
const delta = position.column - this.position.column;
|
||||
const suggestions: SnippetSuggestion[] = [];
|
||||
for (const snippet of this.snippets) {
|
||||
suggestions.push(new SnippetSuggestion(snippet, delta + snippet.prefix.length));
|
||||
}
|
||||
return { suggestions };
|
||||
}
|
||||
}
|
||||
|
||||
@commonEditorContribution
|
||||
export class TabCompletionController implements editorCommon.IEditorContribution {
|
||||
|
||||
@@ -29,20 +63,27 @@ export class TabCompletionController implements editorCommon.IEditorContribution
|
||||
return editor.getContribution<TabCompletionController>(TabCompletionController.ID);
|
||||
}
|
||||
|
||||
private _snippetController: SnippetController2;
|
||||
private _cursorChangeSubscription: IDisposable;
|
||||
private _currentSnippets: ISnippet[] = [];
|
||||
private readonly _editor: editorCommon.ICommonCodeEditor;
|
||||
private readonly _snippetController: SnippetController2;
|
||||
private readonly _suggestController: SuggestController;
|
||||
private readonly _tabCompletionProvider: TabCompletionProvider;
|
||||
private readonly _dispoables: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
editor: editorCommon.ICommonCodeEditor,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@ISnippetsService snippetService: ISnippetsService
|
||||
) {
|
||||
this._editor = editor;
|
||||
this._snippetController = SnippetController2.get(editor);
|
||||
const hasSnippets = TabCompletionController.ContextKey.bindTo(contextKeyService);
|
||||
this._cursorChangeSubscription = editor.onDidChangeCursorSelection(e => {
|
||||
this._suggestController = SuggestController.get(editor);
|
||||
this._tabCompletionProvider = new TabCompletionProvider();
|
||||
this._dispoables.push(SuggestRegistry.register('*', this._tabCompletionProvider));
|
||||
|
||||
this._currentSnippets.length = 0;
|
||||
const hasSnippets = TabCompletionController.ContextKey.bindTo(contextKeyService);
|
||||
this._dispoables.push(editor.onDidChangeCursorSelection(e => {
|
||||
|
||||
let snippets: ISnippet[] = [];
|
||||
let selectFn: (snippet: ISnippet) => boolean;
|
||||
|
||||
if (e.selection.isEmpty()) {
|
||||
@@ -59,32 +100,36 @@ export class TabCompletionController implements editorCommon.IEditorContribution
|
||||
if (selectFn) {
|
||||
snippetService.visitSnippets(editor.getModel().getLanguageIdentifier().id, s => {
|
||||
if (selectFn(s)) {
|
||||
this._currentSnippets.push(s);
|
||||
snippets.push(s);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
hasSnippets.set(this._currentSnippets.length === 1); //todo@joh make it work with N
|
||||
});
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._cursorChangeSubscription.dispose();
|
||||
}
|
||||
|
||||
performSnippetCompletions(): void {
|
||||
if (this._currentSnippets.length === 1) {
|
||||
const snippet = this._currentSnippets[0];
|
||||
this._snippetController.insert(snippet.codeSnippet, snippet.prefix.length, 0);
|
||||
// } else {
|
||||
// todo@joh - show suggest widget with proposals
|
||||
}
|
||||
this._tabCompletionProvider.set(editor.getPosition(), snippets);
|
||||
hasSnippets.set(this._tabCompletionProvider.snippets.length > 0);
|
||||
}));
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
return TabCompletionController.ID;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
dispose(this._dispoables);
|
||||
}
|
||||
|
||||
performSnippetCompletions(): void {
|
||||
const { snippets } = this._tabCompletionProvider;
|
||||
if (snippets.length === 1) {
|
||||
// one -> just insert
|
||||
const [snippet] = snippets;
|
||||
this._snippetController.insert(snippet.codeSnippet, snippet.prefix.length, 0);
|
||||
|
||||
} else if (snippets.length > 1) {
|
||||
// two or more -> show IntelliSense box
|
||||
this._suggestController.triggerSuggest([this._tabCompletionProvider]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const TabCompletionCommand = EditorCommand.bindToContribution<TabCompletionController>(TabCompletionController.get);
|
||||
|
||||
Reference in New Issue
Block a user