mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-21 12:20:29 -04:00
Vscode merge (#4582)
* Merge from vscode 37cb23d3dd4f9433d56d4ba5ea3203580719a0bd * fix issues with merges * bump node version in azpipe * replace license headers * remove duplicate launch task * fix build errors * fix build errors * fix tslint issues * working through package and linux build issues * more work * wip * fix packaged builds * working through linux build errors * wip * wip * wip * fix mac and linux file limits * iterate linux pipeline * disable editor typing * revert series to parallel * remove optimize vscode from linux * fix linting issues * revert testing change * add work round for new node * readd packaging for extensions * fix issue with angular not resolving decorator dependencies
This commit is contained in:
@@ -4,7 +4,6 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { first } from 'vs/base/common/async';
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
import { onUnexpectedExternalError, canceled, isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
@@ -87,7 +86,20 @@ export class CompletionItem {
|
||||
}
|
||||
}
|
||||
|
||||
export type SnippetConfig = 'top' | 'bottom' | 'inline' | 'none';
|
||||
export const enum SnippetSortOrder {
|
||||
Top, Inline, Bottom
|
||||
}
|
||||
|
||||
export class CompletionOptions {
|
||||
|
||||
static readonly default = new CompletionOptions();
|
||||
|
||||
constructor(
|
||||
readonly snippetSortOrder = SnippetSortOrder.Bottom,
|
||||
readonly kindFilter = new Set<modes.CompletionItemKind>(),
|
||||
readonly providerFilter = new Set<modes.CompletionItemProvider>(),
|
||||
) { }
|
||||
}
|
||||
|
||||
let _snippetSuggestSupport: modes.CompletionItemProvider;
|
||||
|
||||
@@ -104,15 +116,12 @@ export function setSnippetSuggestSupport(support: modes.CompletionItemProvider):
|
||||
export function provideSuggestionItems(
|
||||
model: ITextModel,
|
||||
position: Position,
|
||||
snippetConfig: SnippetConfig = 'bottom',
|
||||
onlyFrom?: modes.CompletionItemProvider[],
|
||||
context?: modes.CompletionContext,
|
||||
options: CompletionOptions = CompletionOptions.default,
|
||||
context: modes.CompletionContext = { triggerKind: modes.CompletionTriggerKind.Invoke },
|
||||
token: CancellationToken = CancellationToken.None
|
||||
): Promise<CompletionItem[]> {
|
||||
|
||||
const allSuggestions: CompletionItem[] = [];
|
||||
const acceptSuggestion = createSuggesionFilter(snippetConfig);
|
||||
|
||||
const wordUntil = model.getWordUntilPosition(position);
|
||||
const defaultRange = new Range(position.lineNumber, wordUntil.startColumn, position.lineNumber, wordUntil.endColumn);
|
||||
|
||||
@@ -122,12 +131,10 @@ export function provideSuggestionItems(
|
||||
const supports = modes.CompletionProviderRegistry.orderedGroups(model);
|
||||
|
||||
// add snippets provider unless turned off
|
||||
if (snippetConfig !== 'none' && _snippetSuggestSupport) {
|
||||
if (!options.kindFilter.has(modes.CompletionItemKind.Snippet) && _snippetSuggestSupport) {
|
||||
supports.unshift([_snippetSuggestSupport]);
|
||||
}
|
||||
|
||||
const suggestConext = context || { triggerKind: modes.CompletionTriggerKind.Invoke };
|
||||
|
||||
// add suggestions from contributed providers - providers are ordered in groups of
|
||||
// equal score and once a group produces a result the process stops
|
||||
let hasResult = false;
|
||||
@@ -135,17 +142,17 @@ export function provideSuggestionItems(
|
||||
// for each support in the group ask for suggestions
|
||||
return Promise.all(supports.map(provider => {
|
||||
|
||||
if (isNonEmptyArray(onlyFrom) && onlyFrom.indexOf(provider) < 0) {
|
||||
if (options.providerFilter.size > 0 && !options.providerFilter.has(provider)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return Promise.resolve(provider.provideCompletionItems(model, position, suggestConext, token)).then(container => {
|
||||
return Promise.resolve(provider.provideCompletionItems(model, position, context, token)).then(container => {
|
||||
|
||||
const len = allSuggestions.length;
|
||||
|
||||
if (container) {
|
||||
for (let suggestion of container.suggestions || []) {
|
||||
if (acceptSuggestion(suggestion)) {
|
||||
if (!options.kindFilter.has(suggestion.kind)) {
|
||||
|
||||
// fill in default range when missing
|
||||
if (!suggestion.range) {
|
||||
@@ -170,9 +177,9 @@ export function provideSuggestionItems(
|
||||
return hasResult || token.isCancellationRequested;
|
||||
}).then(() => {
|
||||
if (token.isCancellationRequested) {
|
||||
return Promise.reject(canceled());
|
||||
return Promise.reject<any>(canceled());
|
||||
}
|
||||
return allSuggestions.sort(getSuggestionComparator(snippetConfig));
|
||||
return allSuggestions.sort(getSuggestionComparator(options.snippetSortOrder));
|
||||
});
|
||||
|
||||
// result.then(items => {
|
||||
@@ -185,13 +192,7 @@ export function provideSuggestionItems(
|
||||
return result;
|
||||
}
|
||||
|
||||
function createSuggesionFilter(snippetConfig: SnippetConfig): (candidate: modes.CompletionItem) => boolean {
|
||||
if (snippetConfig === 'none') {
|
||||
return suggestion => suggestion.kind !== modes.CompletionItemKind.Snippet;
|
||||
} else {
|
||||
return () => true;
|
||||
}
|
||||
}
|
||||
|
||||
function defaultComparator(a: CompletionItem, b: CompletionItem): number {
|
||||
// check with 'sortText'
|
||||
if (a.sortTextLow && b.sortTextLow) {
|
||||
@@ -233,14 +234,14 @@ function snippetDownComparator(a: CompletionItem, b: CompletionItem): number {
|
||||
return defaultComparator(a, b);
|
||||
}
|
||||
|
||||
export function getSuggestionComparator(snippetConfig: SnippetConfig): (a: CompletionItem, b: CompletionItem) => number {
|
||||
if (snippetConfig === 'top') {
|
||||
return snippetUpComparator;
|
||||
} else if (snippetConfig === 'bottom') {
|
||||
return snippetDownComparator;
|
||||
} else {
|
||||
return defaultComparator;
|
||||
}
|
||||
interface Comparator<T> { (a: T, b: T): number; }
|
||||
const _snippetComparators = new Map<SnippetSortOrder, Comparator<CompletionItem>>();
|
||||
_snippetComparators.set(SnippetSortOrder.Top, snippetUpComparator);
|
||||
_snippetComparators.set(SnippetSortOrder.Bottom, snippetDownComparator);
|
||||
_snippetComparators.set(SnippetSortOrder.Inline, defaultComparator);
|
||||
|
||||
export function getSuggestionComparator(snippetConfig: SnippetSortOrder): (a: CompletionItem, b: CompletionItem) => number {
|
||||
return _snippetComparators.get(snippetConfig)!;
|
||||
}
|
||||
|
||||
registerDefaultLanguageCommand('_executeCompletionItemProvider', (model, position, args) => {
|
||||
@@ -269,11 +270,10 @@ registerDefaultLanguageCommand('_executeCompletionItemProvider', (model, positio
|
||||
});
|
||||
|
||||
interface SuggestController extends IEditorContribution {
|
||||
triggerSuggest(onlyFrom?: modes.CompletionItemProvider[]): void;
|
||||
triggerSuggest(onlyFrom?: Set<modes.CompletionItemProvider>): void;
|
||||
}
|
||||
|
||||
|
||||
let _provider = new class implements modes.CompletionItemProvider {
|
||||
const _provider = new class implements modes.CompletionItemProvider {
|
||||
|
||||
onlyOnceSuggestions: modes.CompletionItem[] = [];
|
||||
|
||||
@@ -290,6 +290,6 @@ modes.CompletionProviderRegistry.register('*', _provider);
|
||||
export function showSimpleSuggestions(editor: ICodeEditor, suggestions: modes.CompletionItem[]) {
|
||||
setTimeout(() => {
|
||||
_provider.onlyOnceSuggestions.push(...suggestions);
|
||||
editor.getContribution<SuggestController>('editor.contrib.suggestController').triggerSuggest([_provider]);
|
||||
editor.getContribution<SuggestController>('editor.contrib.suggestController').triggerSuggest(new Set<modes.CompletionItemProvider>().add(_provider));
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ export class SuggestController implements IEditorContribution {
|
||||
this._widget.getValue().hideWidget();
|
||||
}
|
||||
}));
|
||||
this._toDispose.push(this._editor.onDidBlurEditorText(() => {
|
||||
this._toDispose.push(this._editor.onDidBlurEditorWidget(() => {
|
||||
if (!this._sticky) {
|
||||
this._model.cancel();
|
||||
}
|
||||
@@ -292,11 +292,13 @@ export class SuggestController implements IEditorContribution {
|
||||
}
|
||||
|
||||
private _alertCompletionItem({ completion: suggestion }: CompletionItem): void {
|
||||
let msg = nls.localize('arai.alert.snippet', "Accepting '{0}' did insert the following text: {1}", suggestion.label, suggestion.insertText);
|
||||
alert(msg);
|
||||
if (isNonEmptyArray(suggestion.additionalTextEdits)) {
|
||||
let msg = nls.localize('arai.alert.snippet', "Accepting '{0}' made {1} additional edits", suggestion.label, suggestion.additionalTextEdits.length);
|
||||
alert(msg);
|
||||
}
|
||||
}
|
||||
|
||||
triggerSuggest(onlyFrom?: CompletionItemProvider[]): void {
|
||||
triggerSuggest(onlyFrom?: Set<CompletionItemProvider>): void {
|
||||
if (this._editor.hasModel()) {
|
||||
this._model.trigger({ auto: false, shy: false }, false, onlyFrom);
|
||||
this._editor.revealLine(this._editor.getPosition().lineNumber, ScrollType.Smooth);
|
||||
|
||||
@@ -8,7 +8,7 @@ import { LRUCache, TernarySearchTree } from 'vs/base/common/map';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { CompletionItemKind, completionKindFromLegacyString } from 'vs/editor/common/modes';
|
||||
import { CompletionItemKind, completionKindFromString } from 'vs/editor/common/modes';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -124,7 +124,7 @@ export class LRUMemory extends Memory {
|
||||
let seq = 0;
|
||||
for (const [key, value] of data) {
|
||||
value.touch = seq;
|
||||
value.type = typeof value.type === 'number' ? value.type : completionKindFromLegacyString(value.type);
|
||||
value.type = typeof value.type === 'number' ? value.type : completionKindFromString(value.type);
|
||||
this._cache.set(key, value);
|
||||
}
|
||||
this._seq = this._cache.size;
|
||||
@@ -188,7 +188,7 @@ export class PrefixMemory extends Memory {
|
||||
if (data.length > 0) {
|
||||
this._seq = data[0][1].touch + 1;
|
||||
for (const [key, value] of data) {
|
||||
value.type = typeof value.type === 'number' ? value.type : completionKindFromLegacyString(value.type);
|
||||
value.type = typeof value.type === 'number' ? value.type : completionKindFromString(value.type);
|
||||
this._trie.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,15 +8,14 @@ import { TimeoutTimer } from 'vs/base/common/async';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { CursorChangeReason, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { ITextModel, IWordAtPosition } from 'vs/editor/common/model';
|
||||
import { CompletionItemProvider, StandardTokenType, CompletionContext, CompletionProviderRegistry, CompletionTriggerKind } from 'vs/editor/common/modes';
|
||||
import { CompletionItemProvider, StandardTokenType, CompletionContext, CompletionProviderRegistry, CompletionTriggerKind, CompletionItemKind, completionKindFromString } from 'vs/editor/common/modes';
|
||||
import { CompletionModel } from './completionModel';
|
||||
import { CompletionItem, getSuggestionComparator, provideSuggestionItems, getSnippetSuggestSupport } from './suggest';
|
||||
import { CompletionItem, getSuggestionComparator, provideSuggestionItems, getSnippetSuggestSupport, SnippetSortOrder, CompletionOptions } from './suggest';
|
||||
import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
|
||||
@@ -209,7 +208,7 @@ export class SuggestModel implements IDisposable {
|
||||
// keep existing items that where not computed by the
|
||||
// supports/providers that want to trigger now
|
||||
const items: CompletionItem[] | undefined = this._completionModel ? this._completionModel.adopt(supports) : undefined;
|
||||
this.trigger({ auto: true, shy: false, triggerCharacter: lastChar }, Boolean(this._completionModel), values(supports), items);
|
||||
this.trigger({ auto: true, shy: false, triggerCharacter: lastChar }, Boolean(this._completionModel), supports, items);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -347,7 +346,7 @@ export class SuggestModel implements IDisposable {
|
||||
}, 25);
|
||||
}
|
||||
|
||||
trigger(context: SuggestTriggerContext, retrigger: boolean = false, onlyFrom?: CompletionItemProvider[], existingItems?: CompletionItem[]): void {
|
||||
trigger(context: SuggestTriggerContext, retrigger: boolean = false, onlyFrom?: Set<CompletionItemProvider>, existingItems?: CompletionItem[]): void {
|
||||
if (!this._editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
@@ -371,7 +370,7 @@ export class SuggestModel implements IDisposable {
|
||||
triggerKind: CompletionTriggerKind.TriggerCharacter,
|
||||
triggerCharacter: context.triggerCharacter
|
||||
};
|
||||
} else if (onlyFrom && onlyFrom.length) {
|
||||
} else if (onlyFrom && onlyFrom.size > 0) {
|
||||
suggestCtx = { triggerKind: CompletionTriggerKind.TriggerForIncompleteCompletions };
|
||||
} else {
|
||||
suggestCtx = { triggerKind: CompletionTriggerKind.Invoke };
|
||||
@@ -379,13 +378,40 @@ export class SuggestModel implements IDisposable {
|
||||
|
||||
this._requestToken = new CancellationTokenSource();
|
||||
|
||||
// kind filter and snippet sort rules
|
||||
const { contribInfo } = this._editor.getConfiguration();
|
||||
let itemKindFilter = new Set<CompletionItemKind>();
|
||||
let snippetSortOrder = SnippetSortOrder.Inline;
|
||||
switch (contribInfo.suggest.snippets) {
|
||||
case 'top':
|
||||
snippetSortOrder = SnippetSortOrder.Top;
|
||||
break;
|
||||
// ↓ that's the default anyways...
|
||||
// case 'inline':
|
||||
// snippetSortOrder = SnippetSortOrder.Inline;
|
||||
// break;
|
||||
case 'bottom':
|
||||
snippetSortOrder = SnippetSortOrder.Bottom;
|
||||
break;
|
||||
case 'none':
|
||||
itemKindFilter.add(CompletionItemKind.Snippet);
|
||||
break;
|
||||
}
|
||||
|
||||
// kind filter
|
||||
for (const key in contribInfo.suggest.filteredTypes) {
|
||||
const kind = completionKindFromString(key, true);
|
||||
if (typeof kind !== 'undefined' && contribInfo.suggest.filteredTypes[key] === false) {
|
||||
itemKindFilter.add(kind);
|
||||
}
|
||||
}
|
||||
|
||||
let wordDistance = WordDistance.create(this._editorWorker, this._editor);
|
||||
|
||||
let items = provideSuggestionItems(
|
||||
model,
|
||||
this._editor.getPosition(),
|
||||
this._editor.getConfiguration().contribInfo.suggest.snippets,
|
||||
onlyFrom,
|
||||
new CompletionOptions(snippetSortOrder, itemKindFilter, onlyFrom),
|
||||
suggestCtx,
|
||||
this._requestToken.token
|
||||
);
|
||||
@@ -405,7 +431,7 @@ export class SuggestModel implements IDisposable {
|
||||
const model = this._editor.getModel();
|
||||
|
||||
if (isNonEmptyArray(existingItems)) {
|
||||
const cmpFn = getSuggestionComparator(this._editor.getConfiguration().contribInfo.suggest.snippets);
|
||||
const cmpFn = getSuggestionComparator(snippetSortOrder);
|
||||
items = items.concat(existingItems).sort(cmpFn);
|
||||
}
|
||||
|
||||
@@ -461,7 +487,7 @@ export class SuggestModel implements IDisposable {
|
||||
// typed -> moved cursor RIGHT & incomple model & still on a word -> retrigger
|
||||
const { incomplete } = this._completionModel;
|
||||
const adopted = this._completionModel.adopt(incomplete);
|
||||
this.trigger({ auto: this._state === State.Auto, shy: false }, true, values(incomplete), adopted);
|
||||
this.trigger({ auto: this._state === State.Auto, shy: false }, true, incomplete, adopted);
|
||||
|
||||
} else {
|
||||
// typed -> moved cursor RIGHT -> update UI
|
||||
|
||||
@@ -40,7 +40,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { FileKind } from 'vs/platform/files/common/files';
|
||||
|
||||
const expandSuggestionDocsByDefault = false;
|
||||
const maxSuggestionsToShow = 12;
|
||||
|
||||
interface ISuggestionTemplateData {
|
||||
root: HTMLElement;
|
||||
@@ -63,8 +62,16 @@ export const editorSuggestWidgetHighlightForeground = registerColor('editorSugge
|
||||
|
||||
|
||||
const colorRegExp = /^(#([\da-f]{3}){1,2}|(rgb|hsl)a\(\s*(\d{1,3}%?\s*,\s*){3}(1|0?\.\d+)\)|(rgb|hsl)\(\s*\d{1,3}%?(\s*,\s*\d{1,3}%?){2}\s*\))$/i;
|
||||
function matchesColor(text: string): string | null {
|
||||
return text && text.match(colorRegExp) ? text : null;
|
||||
function extractColor(item: CompletionItem, out: string[]): boolean {
|
||||
if (item.completion.label.match(colorRegExp)) {
|
||||
out[0] = item.completion.label;
|
||||
return true;
|
||||
}
|
||||
if (typeof item.completion.documentation === 'string' && item.completion.documentation.match(colorRegExp)) {
|
||||
out[0] = item.completion.documentation;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function canExpandCompletionItem(item: CompletionItem | null) {
|
||||
@@ -156,11 +163,11 @@ class Renderer implements IListRenderer<CompletionItem, ISuggestionTemplateData>
|
||||
matches: createMatches(element.score)
|
||||
};
|
||||
|
||||
let color: string | null = null;
|
||||
if (suggestion.kind === CompletionItemKind.Color && ((color = matchesColor(suggestion.label) || typeof suggestion.documentation === 'string' ? matchesColor(suggestion.documentation as any) : null))) {
|
||||
let color: string[] = [];
|
||||
if (suggestion.kind === CompletionItemKind.Color && extractColor(element, color)) {
|
||||
// special logic for 'color' completion items
|
||||
data.icon.className = 'icon customcolor';
|
||||
data.colorspan.style.backgroundColor = color;
|
||||
data.colorspan.style.backgroundColor = color[0];
|
||||
|
||||
} else if (suggestion.kind === CompletionItemKind.File && this._themeService.getIconTheme().hasFileIcons) {
|
||||
// special logic for 'file' completion items
|
||||
@@ -243,10 +250,10 @@ class SuggestionDetails {
|
||||
|
||||
constructor(
|
||||
container: HTMLElement,
|
||||
private widget: SuggestWidget,
|
||||
private editor: ICodeEditor,
|
||||
private markdownRenderer: MarkdownRenderer,
|
||||
private triggerKeybindingLabel: string
|
||||
private readonly widget: SuggestWidget,
|
||||
private readonly editor: ICodeEditor,
|
||||
private readonly markdownRenderer: MarkdownRenderer,
|
||||
private readonly triggerKeybindingLabel: string
|
||||
) {
|
||||
this.disposables = [];
|
||||
|
||||
@@ -416,8 +423,8 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
private list: List<CompletionItem>;
|
||||
private listHeight: number;
|
||||
|
||||
private suggestWidgetVisible: IContextKey<boolean>;
|
||||
private suggestWidgetMultipleSuggestions: IContextKey<boolean>;
|
||||
private readonly suggestWidgetVisible: IContextKey<boolean>;
|
||||
private readonly suggestWidgetMultipleSuggestions: IContextKey<boolean>;
|
||||
|
||||
private readonly editorBlurTimeout = new TimeoutTimer();
|
||||
private readonly showTimeout = new TimeoutTimer();
|
||||
@@ -436,7 +443,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
|
||||
private readonly maxWidgetWidth = 660;
|
||||
private readonly listWidth = 330;
|
||||
private storageService: IStorageService;
|
||||
private readonly storageService: IStorageService;
|
||||
private detailsFocusBorderColor: string;
|
||||
private detailsBorderColor: string;
|
||||
|
||||
@@ -446,7 +453,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
private docsPositionPreviousWidgetY: number | null;
|
||||
|
||||
constructor(
|
||||
private editor: ICodeEditor,
|
||||
private readonly editor: ICodeEditor,
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@@ -465,14 +472,14 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
this.storageService = storageService;
|
||||
|
||||
this.element = $('.editor-widget.suggest-widget');
|
||||
if (!this.editor.getConfiguration().contribInfo.iconsInSuggestions) {
|
||||
addClass(this.element, 'no-icons');
|
||||
}
|
||||
|
||||
this.messageElement = append(this.element, $('.message'));
|
||||
this.listElement = append(this.element, $('.tree'));
|
||||
this.details = new SuggestionDetails(this.element, this, this.editor, markdownRenderer, triggerKeybindingLabel);
|
||||
|
||||
const applyIconStyle = () => toggleClass(this.element, 'no-icons', !this.editor.getConfiguration().contribInfo.suggest.showIcons);
|
||||
applyIconStyle();
|
||||
|
||||
let renderer = instantiationService.createInstance(Renderer, this, this.editor, triggerKeybindingLabel);
|
||||
|
||||
this.list = new List(this.listElement, this, [renderer], {
|
||||
@@ -491,7 +498,8 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
this.list.onMouseDown(e => this.onListMouseDown(e)),
|
||||
this.list.onSelectionChange(e => this.onListSelection(e)),
|
||||
this.list.onFocusChange(e => this.onListFocus(e)),
|
||||
this.editor.onDidChangeCursorSelection(() => this.onCursorSelectionChanged())
|
||||
this.editor.onDidChangeCursorSelection(() => this.onCursorSelectionChanged()),
|
||||
this.editor.onDidChangeConfiguration(e => e.contribInfo && applyIconStyle())
|
||||
];
|
||||
|
||||
this.suggestWidgetVisible = SuggestContext.Visible.bindTo(contextKeyService);
|
||||
@@ -522,6 +530,10 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
return;
|
||||
}
|
||||
|
||||
// prevent stealing browser focus from the editor
|
||||
e.browserEvent.preventDefault();
|
||||
e.browserEvent.stopPropagation();
|
||||
|
||||
this.select(e.element, e.index);
|
||||
}
|
||||
|
||||
@@ -542,23 +554,15 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
|
||||
item.resolve(CancellationToken.None).then(() => {
|
||||
this.onDidSelectEmitter.fire({ item, index, model: completionModel });
|
||||
alert(nls.localize('suggestionAriaAccepted', "{0}, accepted", item.completion.label));
|
||||
this.editor.focus();
|
||||
});
|
||||
}
|
||||
|
||||
private _getSuggestionAriaAlertLabel(item: CompletionItem): string {
|
||||
const isSnippet = item.completion.kind === CompletionItemKind.Snippet;
|
||||
|
||||
if (!canExpandCompletionItem(item)) {
|
||||
return isSnippet ? nls.localize('ariaCurrentSnippetSuggestion', "{0}, snippet suggestion", item.completion.label)
|
||||
: nls.localize('ariaCurrentSuggestion', "{0}, suggestion", item.completion.label);
|
||||
} else if (this.expandDocsSettingFromStorage()) {
|
||||
return isSnippet ? nls.localize('ariaCurrentSnippeSuggestionReadDetails', "{0}, snippet suggestion. Reading details. {1}", item.completion.label, this.details.getAriaLabel())
|
||||
: nls.localize('ariaCurrenttSuggestionReadDetails', "{0}, suggestion. Reading details. {1}", item.completion.label, this.details.getAriaLabel());
|
||||
if (this.expandDocsSettingFromStorage()) {
|
||||
return nls.localize('ariaCurrenttSuggestionReadDetails', "Item {0}, docs: {1}", item.completion.label, this.details.getAriaLabel());
|
||||
} else {
|
||||
return isSnippet ? nls.localize('ariaCurrentSnippetSuggestionWithDetails', "{0}, snippet suggestion, has details", item.completion.label)
|
||||
: nls.localize('ariaCurrentSuggestionWithDetails', "{0}, suggestion, has details", item.completion.label);
|
||||
return item.completion.label;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -569,7 +573,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
}
|
||||
this._lastAriaAlertLabel = newAriaAlertLabel;
|
||||
if (this._lastAriaAlertLabel) {
|
||||
alert(this._lastAriaAlertLabel);
|
||||
alert(this._lastAriaAlertLabel, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1040,7 +1044,8 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
height = this.unfocusedHeight;
|
||||
} else {
|
||||
const suggestionCount = this.list.contentHeight / this.unfocusedHeight;
|
||||
height = Math.min(suggestionCount, maxSuggestionsToShow) * this.unfocusedHeight;
|
||||
const { maxVisibleSuggestions } = this.editor.getConfiguration().contribInfo.suggest;
|
||||
height = Math.min(suggestionCount, maxVisibleSuggestions) * this.unfocusedHeight;
|
||||
}
|
||||
|
||||
this.element.style.lineHeight = `${this.unfocusedHeight}px`;
|
||||
@@ -1120,7 +1125,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
// Heights
|
||||
|
||||
private get maxWidgetHeight(): number {
|
||||
return this.unfocusedHeight * maxSuggestionsToShow;
|
||||
return this.unfocusedHeight * this.editor.getConfiguration().contribInfo.suggest.maxVisibleSuggestions;
|
||||
}
|
||||
|
||||
private get unfocusedHeight(): number {
|
||||
|
||||
@@ -6,7 +6,7 @@ import * as assert from 'assert';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { CompletionModel } from 'vs/editor/contrib/suggest/completionModel';
|
||||
import { CompletionItem, getSuggestionComparator } from 'vs/editor/contrib/suggest/suggest';
|
||||
import { CompletionItem, getSuggestionComparator, SnippetSortOrder } from 'vs/editor/contrib/suggest/suggest';
|
||||
import { WordDistance } from 'vs/editor/contrib/suggest/wordDistance';
|
||||
|
||||
export function createSuggestItem(label: string, overwriteBefore: number, kind = modes.CompletionItemKind.Property, incomplete: boolean = false, position: IPosition = { lineNumber: 1, column: 1 }, sortText?: string, filterText?: string): CompletionItem {
|
||||
@@ -157,7 +157,16 @@ suite('CompletionModel', function () {
|
||||
], 1, {
|
||||
leadingLineContent: 's',
|
||||
characterCountDelta: 0
|
||||
}, WordDistance.None, { snippets: 'top', snippetsPreventQuickSuggestions: true, filterGraceful: true, localityBonus: false, shareSuggestSelections: false });
|
||||
}, WordDistance.None, {
|
||||
snippets: 'top',
|
||||
snippetsPreventQuickSuggestions: true,
|
||||
filterGraceful: true,
|
||||
localityBonus: false,
|
||||
shareSuggestSelections: false,
|
||||
showIcons: true,
|
||||
maxVisibleSuggestions: 12,
|
||||
filteredTypes: Object.create(null)
|
||||
});
|
||||
|
||||
assert.equal(model.items.length, 2);
|
||||
const [a, b] = model.items;
|
||||
@@ -176,7 +185,16 @@ suite('CompletionModel', function () {
|
||||
], 1, {
|
||||
leadingLineContent: 's',
|
||||
characterCountDelta: 0
|
||||
}, WordDistance.None, { snippets: 'bottom', snippetsPreventQuickSuggestions: true, filterGraceful: true, localityBonus: false, shareSuggestSelections: false });
|
||||
}, WordDistance.None, {
|
||||
snippets: 'bottom',
|
||||
snippetsPreventQuickSuggestions: true,
|
||||
filterGraceful: true,
|
||||
localityBonus: false,
|
||||
shareSuggestSelections: false,
|
||||
showIcons: true,
|
||||
maxVisibleSuggestions: 12,
|
||||
filteredTypes: Object.create(null)
|
||||
});
|
||||
|
||||
assert.equal(model.items.length, 2);
|
||||
const [a, b] = model.items;
|
||||
@@ -194,7 +212,16 @@ suite('CompletionModel', function () {
|
||||
], 1, {
|
||||
leadingLineContent: 's',
|
||||
characterCountDelta: 0
|
||||
}, WordDistance.None, { snippets: 'inline', snippetsPreventQuickSuggestions: true, filterGraceful: true, localityBonus: false, shareSuggestSelections: false });
|
||||
}, WordDistance.None, {
|
||||
snippets: 'inline',
|
||||
snippetsPreventQuickSuggestions: true,
|
||||
filterGraceful: true,
|
||||
localityBonus: false,
|
||||
shareSuggestSelections: false,
|
||||
showIcons: true,
|
||||
maxVisibleSuggestions: 12,
|
||||
filteredTypes: Object.create(null)
|
||||
});
|
||||
|
||||
assert.equal(model.items.length, 2);
|
||||
const [a, b] = model.items;
|
||||
@@ -226,7 +253,7 @@ suite('CompletionModel', function () {
|
||||
|
||||
const item1 = createSuggestItem('<- groups', 2, modes.CompletionItemKind.Property, false, { lineNumber: 1, column: 3 }, '00002', ' groups');
|
||||
const item2 = createSuggestItem('source', 0, modes.CompletionItemKind.Property, false, { lineNumber: 1, column: 3 }, '00001', 'source');
|
||||
const items = [item1, item2].sort(getSuggestionComparator('inline'));
|
||||
const items = [item1, item2].sort(getSuggestionComparator(SnippetSortOrder.Inline));
|
||||
|
||||
model = new CompletionModel(items, 3, {
|
||||
leadingLineContent: ' ',
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
import * as assert from 'assert';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { CompletionProviderRegistry, CompletionItemKind } from 'vs/editor/common/modes';
|
||||
import { provideSuggestionItems } from 'vs/editor/contrib/suggest/suggest';
|
||||
import { CompletionProviderRegistry, CompletionItemKind, CompletionItemProvider } from 'vs/editor/common/modes';
|
||||
import { provideSuggestionItems, SnippetSortOrder, CompletionOptions } from 'vs/editor/contrib/suggest/suggest';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
@@ -51,7 +51,7 @@ suite('Suggest', function () {
|
||||
});
|
||||
|
||||
test('sort - snippet inline', async function () {
|
||||
const items = await provideSuggestionItems(model, new Position(1, 1), 'inline');
|
||||
const items = await provideSuggestionItems(model, new Position(1, 1), new CompletionOptions(SnippetSortOrder.Inline));
|
||||
assert.equal(items.length, 3);
|
||||
assert.equal(items[0].completion.label, 'aaa');
|
||||
assert.equal(items[1].completion.label, 'fff');
|
||||
@@ -59,7 +59,7 @@ suite('Suggest', function () {
|
||||
});
|
||||
|
||||
test('sort - snippet top', async function () {
|
||||
const items = await provideSuggestionItems(model, new Position(1, 1), 'top');
|
||||
const items = await provideSuggestionItems(model, new Position(1, 1), new CompletionOptions(SnippetSortOrder.Top));
|
||||
assert.equal(items.length, 3);
|
||||
assert.equal(items[0].completion.label, 'aaa');
|
||||
assert.equal(items[1].completion.label, 'zzz');
|
||||
@@ -67,7 +67,7 @@ suite('Suggest', function () {
|
||||
});
|
||||
|
||||
test('sort - snippet bottom', async function () {
|
||||
const items = await provideSuggestionItems(model, new Position(1, 1), 'bottom');
|
||||
const items = await provideSuggestionItems(model, new Position(1, 1), new CompletionOptions(SnippetSortOrder.Bottom));
|
||||
assert.equal(items.length, 3);
|
||||
assert.equal(items[0].completion.label, 'fff');
|
||||
assert.equal(items[1].completion.label, 'aaa');
|
||||
@@ -75,7 +75,7 @@ suite('Suggest', function () {
|
||||
});
|
||||
|
||||
test('sort - snippet none', async function () {
|
||||
const items = await provideSuggestionItems(model, new Position(1, 1), 'none');
|
||||
const items = await provideSuggestionItems(model, new Position(1, 1), new CompletionOptions(undefined, new Set<CompletionItemKind>().add(CompletionItemKind.Snippet)));
|
||||
assert.equal(items.length, 1);
|
||||
assert.equal(items[0].completion.label, 'fff');
|
||||
});
|
||||
@@ -98,7 +98,7 @@ suite('Suggest', function () {
|
||||
};
|
||||
const registration = CompletionProviderRegistry.register({ pattern: 'bar/path', scheme: 'foo' }, foo);
|
||||
|
||||
provideSuggestionItems(model, new Position(1, 1), undefined, [foo]).then(items => {
|
||||
provideSuggestionItems(model, new Position(1, 1), new CompletionOptions(undefined, undefined, new Set<CompletionItemProvider>().add(foo))).then(items => {
|
||||
registration.dispose();
|
||||
|
||||
assert.equal(items.length, 1);
|
||||
|
||||
@@ -34,11 +34,11 @@ export abstract class WordDistance {
|
||||
return Promise.resolve(WordDistance.None);
|
||||
}
|
||||
|
||||
return new BracketSelectionRangeProvider().provideSelectionRanges(model, position).then(ranges => {
|
||||
if (!ranges || ranges.length === 0) {
|
||||
return new BracketSelectionRangeProvider().provideSelectionRanges(model, [position]).then(ranges => {
|
||||
if (!ranges || ranges.length === 0 || ranges[0].length === 0) {
|
||||
return WordDistance.None;
|
||||
}
|
||||
return service.computeWordRanges(model.uri, ranges[0].range).then(wordRanges => {
|
||||
return service.computeWordRanges(model.uri, ranges[0][0].range).then(wordRanges => {
|
||||
return new class extends WordDistance {
|
||||
distance(anchor: IPosition, suggestion: CompletionItem) {
|
||||
if (!wordRanges || !position.equals(editor.getPosition())) {
|
||||
@@ -55,7 +55,7 @@ export abstract class WordDistance {
|
||||
let idx = binarySearch(wordLines, Range.fromPositions(anchor), Range.compareRangesUsingStarts);
|
||||
let bestWordRange = idx >= 0 ? wordLines[idx] : wordLines[Math.max(0, ~idx - 1)];
|
||||
let blockDistance = ranges.length;
|
||||
for (const range of ranges) {
|
||||
for (const range of ranges[0]) {
|
||||
if (!Range.containsRange(range.range, bestWordRange)) {
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user