From d7771265a839f183d2f085def32de81d2dd714b2 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 17 Aug 2016 12:36:31 +0200 Subject: [PATCH] move more logic into suggest model --- .../suggest/browser/suggestController.ts | 52 +------ .../contrib/suggest/common/suggestModel.ts | 131 +++++++++++++----- 2 files changed, 95 insertions(+), 88 deletions(-) diff --git a/src/vs/editor/contrib/suggest/browser/suggestController.ts b/src/vs/editor/contrib/suggest/browser/suggestController.ts index e18ee8cb0dd..684c8a3ccb6 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestController.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestController.ts @@ -7,13 +7,10 @@ import * as nls from 'vs/nls'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { isFalsyOrEmpty } from 'vs/base/common/arrays'; -import { forEach } from 'vs/base/common/collections'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ICommonCodeEditor, IEditorContribution, EditorContextKeys, ModeContextKeys } from 'vs/editor/common/editorCommon'; import { editorAction, ServicesAccessor, EditorAction, EditorCommand, CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; -import { ISuggestSupport, SuggestRegistry } from 'vs/editor/common/modes'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorBrowserRegistry } from 'vs/editor/browser/editorBrowserExtensions'; import { getSnippetController, CodeSnippet } from 'vs/editor/contrib/snippet/common/snippet'; @@ -31,7 +28,7 @@ export class SuggestController implements IEditorContribution { private model: SuggestModel; private widget: SuggestWidget; - private triggerCharacterListeners: IDisposable[]; + private toDispose: IDisposable[] = []; constructor( @@ -39,22 +36,12 @@ export class SuggestController implements IEditorContribution { @IInstantiationService instantiationService: IInstantiationService ) { this.model = new SuggestModel(this.editor); - this.widget = instantiationService.createInstance(SuggestWidget, this.editor); - this.toDispose.push(this.model.onDidTrigger(e => this.widget.showTriggered(e))); this.toDispose.push(this.model.onDidSuggest(e => this.widget.showSuggestions(e))); this.toDispose.push(this.model.onDidCancel(e => this.widget.showDidCancel(e))); + this.widget = instantiationService.createInstance(SuggestWidget, this.editor); this.toDispose.push(this.widget.onDidSelect(this.onDidSelectItem, this)); - - this.triggerCharacterListeners = []; - - this.toDispose.push(editor.onDidChangeConfiguration(() => this.update())); - this.toDispose.push(editor.onDidChangeModel(() => this.update())); - this.toDispose.push(editor.onDidChangeModelMode(() => this.update())); - this.toDispose.push(SuggestRegistry.onDidChange(this.update, this)); - - this.update(); } getId(): string { @@ -63,8 +50,6 @@ export class SuggestController implements IEditorContribution { dispose(): void { this.toDispose = dispose(this.toDispose); - this.triggerCharacterListeners = dispose(this.triggerCharacterListeners); - if (this.widget) { this.widget.dispose(); this.widget = null; @@ -88,39 +73,6 @@ export class SuggestController implements IEditorContribution { this.model.cancel(); } - private update(): void { - - this.triggerCharacterListeners = dispose(this.triggerCharacterListeners); - - if (this.editor.getConfiguration().readOnly - || !this.editor.getModel() - || !this.editor.getConfiguration().contribInfo.suggestOnTriggerCharacters) { - - return; - } - - const supportsByTriggerCharacter: { [ch: string]: 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 array = supportsByTriggerCharacter[ch]; - if (!array) { - supportsByTriggerCharacter[ch] = [support]; - } else { - array.push(support); - } - } - } - - forEach(supportsByTriggerCharacter, entry => { - this.triggerCharacterListeners.push(this.editor.addTypingListener(entry.key, () => { - this.model.trigger(true, false, entry.value); - })); - }); - } - triggerSuggest(): void { this.model.trigger(false, false); this.editor.focus(); diff --git a/src/vs/editor/contrib/suggest/common/suggestModel.ts b/src/vs/editor/contrib/suggest/common/suggestModel.ts index df77506ad29..6cc81ede226 100644 --- a/src/vs/editor/contrib/suggest/common/suggestModel.ts +++ b/src/vs/editor/contrib/suggest/common/suggestModel.ts @@ -5,6 +5,8 @@ 'use strict'; import {onUnexpectedError} from 'vs/base/common/errors'; +import { isFalsyOrEmpty } from 'vs/base/common/arrays'; +import { forEach } from 'vs/base/common/collections'; import Event, { Emitter } from 'vs/base/common/event'; import {IDisposable, dispose} from 'vs/base/common/lifecycle'; import {startsWith} from 'vs/base/common/strings'; @@ -140,8 +142,9 @@ enum State { export class SuggestModel implements IDisposable { - private toDispose: IDisposable[]; - private autoSuggestDelay: number; + private toDispose: IDisposable[] = []; + private quickSuggestDelay: number; + private triggerCharacterListeners: IDisposable[] = []; private triggerAutoSuggestPromise: TPromise; private state: State; @@ -171,15 +174,83 @@ export class SuggestModel implements IDisposable { this.incomplete = false; this.context = null; - this.toDispose = []; - this.toDispose.push(this._onDidCancel, this._onDidSuggest, this._onDidTrigger); - this.toDispose.push(this.editor.onDidChangeConfiguration(() => this.onEditorConfigurationChange())); - this.toDispose.push(this.editor.onDidChangeCursorSelection(e => this.onCursorChange(e))); - this.toDispose.push(this.editor.onDidChangeModel(() => this.cancel())); - this.toDispose.push(SuggestRegistry.onDidChange(this.onSuggestRegistryChange, this)); - this.onEditorConfigurationChange(); + // wire up various listeners + this.toDispose.push(this.editor.onDidChangeModel(() => { + this.updateTriggerCharacters(); + this.cancel(); + })); + this.toDispose.push(editor.onDidChangeModelMode(() => { + this.updateTriggerCharacters(); + this.cancel(); + })); + this.toDispose.push(this.editor.onDidChangeConfiguration(() => { + this.updateTriggerCharacters(); + this.updateQuickSuggest(); + })); + this.toDispose.push(SuggestRegistry.onDidChange(() => { + this.updateTriggerCharacters(); + this.updateActiveSuggestSession(); + })); + this.toDispose.push(this.editor.onDidChangeCursorSelection(e => { + this.onCursorChange(e); + })); + + this.updateTriggerCharacters(); + this.updateQuickSuggest(); } + dispose(): void { + dispose([this._onDidCancel, this._onDidSuggest, this._onDidTrigger]); + this.toDispose = dispose(this.toDispose); + this.triggerCharacterListeners = dispose(this.triggerCharacterListeners); + this.cancel(); + } + + // --- handle configuration & precondition changes + + private updateQuickSuggest(): void { + this.quickSuggestDelay = this.editor.getConfiguration().contribInfo.quickSuggestionsDelay; + + if (isNaN(this.quickSuggestDelay) || (!this.quickSuggestDelay && this.quickSuggestDelay !== 0) || this.quickSuggestDelay < 0) { + this.quickSuggestDelay = 10; + } + } + + private updateTriggerCharacters(): void { + + this.triggerCharacterListeners = dispose(this.triggerCharacterListeners); + + if (this.editor.getConfiguration().readOnly + || !this.editor.getModel() + || !this.editor.getConfiguration().contribInfo.suggestOnTriggerCharacters) { + + return; + } + + const supportsByTriggerCharacter: { [ch: string]: 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 array = supportsByTriggerCharacter[ch]; + if (!array) { + supportsByTriggerCharacter[ch] = [support]; + } else { + array.push(support); + } + } + } + + forEach(supportsByTriggerCharacter, entry => { + this.triggerCharacterListeners.push(this.editor.addTypingListener(entry.key, () => { + this.trigger(true, false, entry.value); + })); + }); + } + + // --- trigger/retrigger/cancel suggest + cancel(retrigger: boolean = false): boolean { const actuallyCanceled = this.state !== State.Idle; @@ -203,8 +274,14 @@ export class SuggestModel implements IDisposable { return actuallyCanceled; } - private isAutoSuggest(): boolean { - return this.state === State.Auto; + private updateActiveSuggestSession(): void { + if (this.state !== State.Idle) { + if (!SuggestRegistry.has(this.editor.getModel())) { + this.cancel(); + } else { + this.trigger(this.state === State.Auto, true); + } + } } private onCursorChange(e: ICursorSelectionChangedEvent): void { @@ -241,7 +318,7 @@ export class SuggestModel implements IDisposable { this.cancel(); if (ctx.shouldAutoTrigger()) { - this.triggerAutoSuggestPromise = TPromise.timeout(this.autoSuggestDelay); + this.triggerAutoSuggestPromise = TPromise.timeout(this.quickSuggestDelay); this.triggerAutoSuggestPromise.then(() => { this.triggerAutoSuggestPromise = null; this.trigger(true); @@ -255,19 +332,6 @@ export class SuggestModel implements IDisposable { } } - private onSuggestRegistryChange(): void { - if (this.state === State.Idle) { - return; - } - - if (!SuggestRegistry.has(this.editor.getModel())) { - this.cancel(); - return; - } - - this.trigger(this.state === State.Auto, true); - } - public trigger(auto: boolean, retrigger: boolean = false, onlyFrom?: ISuggestSupport[]): void { const model = this.editor.getModel(); @@ -311,6 +375,10 @@ export class SuggestModel implements IDisposable { }).then(null, onUnexpectedError); } + private isAutoSuggest(): boolean { + return this.state === State.Auto; + } + public getTriggerPosition(): IPosition { const {lineNumber, column} = this.context; return { lineNumber, column }; @@ -355,17 +423,4 @@ export class SuggestModel implements IDisposable { }); } } - - private onEditorConfigurationChange(): void { - this.autoSuggestDelay = this.editor.getConfiguration().contribInfo.quickSuggestionsDelay; - - if (isNaN(this.autoSuggestDelay) || (!this.autoSuggestDelay && this.autoSuggestDelay !== 0) || this.autoSuggestDelay < 0) { - this.autoSuggestDelay = 10; - } - } - - dispose(): void { - this.toDispose = dispose(this.toDispose); - this.cancel(); - } }