Merge from master

This commit is contained in:
Raj Musuku
2019-02-21 17:56:04 -08:00
parent 5a146e34fa
commit 666ae11639
11482 changed files with 119352 additions and 255574 deletions

View File

@@ -2,10 +2,9 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { TimeoutTimer, CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
import { isNonEmptyArray } from 'vs/base/common/arrays';
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';
@@ -15,10 +14,13 @@ import { CursorChangeReason, ICursorSelectionChangedEvent } from 'vs/editor/comm
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 { ISuggestSupport, StandardTokenType, SuggestContext, SuggestRegistry, SuggestTriggerKind } from 'vs/editor/common/modes';
import { CompletionItemProvider, StandardTokenType, CompletionContext, CompletionProviderRegistry, CompletionTriggerKind } from 'vs/editor/common/modes';
import { CompletionModel } from './completionModel';
import { ISuggestionItem, getSuggestionComparator, provideSuggestionItems, getSnippetSuggestSupport } 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';
import { WordDistance } from 'vs/editor/contrib/suggest/wordDistance';
export interface ICancelEvent {
readonly retrigger: boolean;
@@ -26,16 +28,19 @@ export interface ICancelEvent {
export interface ITriggerEvent {
readonly auto: boolean;
readonly shy: boolean;
}
export interface ISuggestEvent {
readonly completionModel: CompletionModel;
readonly isFrozen: boolean;
readonly auto: boolean;
readonly shy: boolean;
}
export interface SuggestTriggerContext {
readonly auto: boolean;
readonly shy?: boolean;
readonly triggerCharacter?: string;
}
@@ -67,13 +72,15 @@ export class LineContext {
readonly leadingLineContent: string;
readonly leadingWord: IWordAtPosition;
readonly auto: boolean;
readonly shy: boolean;
constructor(model: ITextModel, position: Position, auto: boolean) {
constructor(model: ITextModel, position: Position, auto: boolean, shy: boolean) {
this.leadingLineContent = model.getLineContent(position.lineNumber).substr(0, position.column - 1);
this.leadingWord = model.getWordUntilPosition(position);
this.lineNumber = position.lineNumber;
this.column = position.column;
this.auto = auto;
this.shy = shy;
}
}
@@ -85,15 +92,14 @@ export const enum State {
export class SuggestModel implements IDisposable {
private _editor: ICodeEditor;
private _toDispose: IDisposable[] = [];
private _quickSuggestDelay: number;
private _triggerCharacterListener: IDisposable;
private readonly _triggerQuickSuggest = new TimeoutTimer();
private readonly _triggerRefilter = new TimeoutTimer();
private _state: State;
private _state: State = State.Idle;
private _requestPromise: CancelablePromise<ISuggestionItem[]>;
private _requestToken: CancellationTokenSource;
private _context: LineContext;
private _currentSelection: Selection;
@@ -106,10 +112,10 @@ export class SuggestModel implements IDisposable {
readonly onDidTrigger: Event<ITriggerEvent> = this._onDidTrigger.event;
readonly onDidSuggest: Event<ISuggestEvent> = this._onDidSuggest.event;
constructor(editor: ICodeEditor) {
this._editor = editor;
this._state = State.Idle;
this._requestPromise = null;
constructor(
private readonly _editor: ICodeEditor,
private readonly _editorWorker: IEditorWorkerService
) {
this._completionModel = null;
this._context = null;
this._currentSelection = this._editor.getSelection() || new Selection(1, 1, 1, 1);
@@ -127,16 +133,31 @@ export class SuggestModel implements IDisposable {
this._updateTriggerCharacters();
this._updateQuickSuggest();
}));
this._toDispose.push(SuggestRegistry.onDidChange(() => {
this._toDispose.push(CompletionProviderRegistry.onDidChange(() => {
this._updateTriggerCharacters();
this._updateActiveSuggestSession();
}));
this._toDispose.push(this._editor.onDidChangeCursorSelection(e => {
this._onCursorChange(e);
}));
this._toDispose.push(this._editor.onDidChangeModelContent(e => {
let editorIsComposing = false;
this._toDispose.push(this._editor.onCompositionStart(() => {
editorIsComposing = true;
}));
this._toDispose.push(this._editor.onCompositionEnd(() => {
// refilter when composition ends
editorIsComposing = false;
this._refilterCompletionItems();
}));
this._toDispose.push(this._editor.onDidChangeModelContent(() => {
// only filter completions when the editor isn't
// composing a character, e.g. ¨ + u makes ü but just
// ¨ cannot be used for filtering
if (!editorIsComposing) {
this._refilterCompletionItems();
}
}));
this._updateTriggerCharacters();
this._updateQuickSuggest();
@@ -170,12 +191,9 @@ export class SuggestModel implements IDisposable {
return;
}
const supportsByTriggerCharacter: { [ch: string]: Set<ISuggestSupport> } = Object.create(null);
for (const support of SuggestRegistry.all(this._editor.getModel())) {
if (isFalsyOrEmpty(support.triggerCharacters)) {
continue;
}
for (const ch of support.triggerCharacters) {
const supportsByTriggerCharacter: { [ch: string]: Set<CompletionItemProvider> } = Object.create(null);
for (const support of CompletionProviderRegistry.all(this._editor.getModel())) {
for (const ch of support.triggerCharacters || []) {
let set = supportsByTriggerCharacter[ch];
if (!set) {
set = supportsByTriggerCharacter[ch] = new Set();
@@ -210,12 +228,10 @@ export class SuggestModel implements IDisposable {
if (this._triggerQuickSuggest) {
this._triggerQuickSuggest.cancel();
}
if (this._requestPromise) {
this._requestPromise.cancel();
this._requestPromise = null;
if (this._requestToken) {
this._requestToken.cancel();
}
this._state = State.Idle;
@@ -228,7 +244,7 @@ export class SuggestModel implements IDisposable {
private _updateActiveSuggestSession(): void {
if (this._state !== State.Idle) {
if (!SuggestRegistry.has(this._editor.getModel())) {
if (!CompletionProviderRegistry.has(this._editor.getModel())) {
this.cancel();
} else {
this.trigger({ auto: this._state === State.Auto }, true);
@@ -253,7 +269,7 @@ export class SuggestModel implements IDisposable {
return;
}
if (!SuggestRegistry.has(this._editor.getModel())) {
if (!CompletionProviderRegistry.has(this._editor.getModel())) {
return;
}
@@ -328,13 +344,13 @@ export class SuggestModel implements IDisposable {
// refine active suggestion
this._triggerRefilter.cancelAndSet(() => {
const position = this._editor.getPosition();
const ctx = new LineContext(model, position, this._state === State.Auto);
const ctx = new LineContext(model, position, this._state === State.Auto, false);
this._onNewContext(ctx);
}, 25);
}
}
trigger(context: SuggestTriggerContext, retrigger: boolean = false, onlyFrom?: ISuggestSupport[], existingItems?: ISuggestionItem[]): void {
trigger(context: SuggestTriggerContext, retrigger: boolean = false, onlyFrom?: CompletionItemProvider[], existingItems?: ISuggestionItem[]): void {
const model = this._editor.getModel();
@@ -342,41 +358,48 @@ export class SuggestModel implements IDisposable {
return;
}
const auto = context.auto;
const ctx = new LineContext(model, this._editor.getPosition(), auto);
const ctx = new LineContext(model, this._editor.getPosition(), auto, context.shy);
// Cancel previous requests, change state & update UI
this.cancel(retrigger);
this._state = auto ? State.Auto : State.Manual;
this._onDidTrigger.fire({ auto });
this._onDidTrigger.fire({ auto, shy: context.shy });
// Capture context when request was sent
this._context = ctx;
// Build context for request
let suggestCtx: SuggestContext;
let suggestCtx: CompletionContext;
if (context.triggerCharacter) {
suggestCtx = {
triggerKind: SuggestTriggerKind.TriggerCharacter,
triggerKind: CompletionTriggerKind.TriggerCharacter,
triggerCharacter: context.triggerCharacter
};
} else if (onlyFrom && onlyFrom.length) {
suggestCtx = { triggerKind: SuggestTriggerKind.TriggerForIncompleteCompletions };
suggestCtx = { triggerKind: CompletionTriggerKind.TriggerForIncompleteCompletions };
} else {
suggestCtx = { triggerKind: SuggestTriggerKind.Invoke };
suggestCtx = { triggerKind: CompletionTriggerKind.Invoke };
}
this._requestPromise = createCancelablePromise(token => provideSuggestionItems(
this._requestToken = new CancellationTokenSource();
// TODO: Remove this workaround - https://github.com/Microsoft/vscode/issues/61917
// let wordDistance = Promise.resolve().then(() => WordDistance.create(this._editorWorker, this._editor));
let wordDistance = WordDistance.create(this._editorWorker, this._editor);
let items = provideSuggestionItems(
model,
this._editor.getPosition(),
this._editor.getConfiguration().contribInfo.suggest.snippets,
onlyFrom,
suggestCtx,
token
));
this._requestToken.token
);
this._requestPromise.then(items => {
Promise.all([items, wordDistance]).then(([items, wordDistance]) => {
this._requestToken.dispose();
this._requestPromise = null;
if (this._state === State.Idle) {
return;
}
@@ -385,17 +408,18 @@ export class SuggestModel implements IDisposable {
return;
}
if (!isFalsyOrEmpty(existingItems)) {
if (isNonEmptyArray(existingItems)) {
const cmpFn = getSuggestionComparator(this._editor.getConfiguration().contribInfo.suggest.snippets);
items = items.concat(existingItems).sort(cmpFn);
}
const ctx = new LineContext(model, this._editor.getPosition(), auto);
const ctx = new LineContext(model, this._editor.getPosition(), auto, context.shy);
dispose(this._completionModel);
this._completionModel = new CompletionModel(items, this._context.column, {
leadingLineContent: ctx.leadingLineContent,
characterCountDelta: this._context ? ctx.column - this._context.column : 0
},
wordDistance,
this._editor.getConfiguration().contribInfo.suggest
);
this._onNewContext(ctx);
@@ -483,6 +507,7 @@ export class SuggestModel implements IDisposable {
this._onDidSuggest.fire({
completionModel: this._completionModel,
auto: this._context.auto,
shy: this._context.shy,
isFrozen,
});
}