提交 8a9b191f 编写于 作者: J Joao Moreno

suggest: cleanup

上级 7c548667
......@@ -25,15 +25,11 @@ export var ContiguousSubString: ISuggestionFilter = wrapBaseFilter(Filters.match
// Combined Filters
export function or(first: ISuggestionFilter, second: ISuggestionFilter): ISuggestionFilter {
return (word: string, suggestion: ISuggestion): Filters.IMatch[] => {
return first(word, suggestion) || second(word, suggestion);
};
return (word, suggestion) => first(word, suggestion) || second(word, suggestion);
}
export function and(first: ISuggestionFilter, second: ISuggestionFilter): ISuggestionFilter {
return (word: string, suggestion: ISuggestion): Filters.IMatch[] => {
return first(word, suggestion) && second(word, suggestion);
};
return (word, suggestion) => first(word, suggestion) && second(word, suggestion);
}
export var DefaultFilter = or(or(Prefix, CamelCase), ContiguousSubString);
\ No newline at end of file
......@@ -7,22 +7,22 @@
import nls = require('vs/nls');
import Lifecycle = require('vs/base/common/lifecycle');
import Snippet = require('vs/editor/contrib/snippet/common/snippet');
import SuggestWidget = require('./suggestWidget');
import SuggestModel = require('./suggestModel');
import { SuggestWidget } from './suggestWidget';
import { SuggestModel } from './suggestModel';
import Errors = require('vs/base/common/errors');
import {TPromise} from 'vs/base/common/winjs.base';
import {EditorBrowserRegistry} from 'vs/editor/browser/editorBrowserExtensions';
import {CommonEditorRegistry, ContextKey, EditorActionDescriptor} from 'vs/editor/common/editorCommonExtensions';
import {EditorAction, Behaviour} from 'vs/editor/common/editorAction';
import { TPromise } from 'vs/base/common/winjs.base';
import { EditorBrowserRegistry } from 'vs/editor/browser/editorBrowserExtensions';
import { CommonEditorRegistry, ContextKey, EditorActionDescriptor } from 'vs/editor/common/editorCommonExtensions';
import { EditorAction, Behaviour } from 'vs/editor/common/editorAction';
import EditorBrowser = require('vs/editor/browser/editorBrowser');
import EditorCommon = require('vs/editor/common/editorCommon');
import Modes = require('vs/editor/common/modes');
import EventEmitter = require('vs/base/common/eventEmitter');
import {IKeybindingService, IKeybindingContextKey} from 'vs/platform/keybinding/common/keybindingService';
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
import {SuggestRegistry, ACCEPT_SELECTED_SUGGESTION_CMD, CONTEXT_SUGGEST_WIDGET_VISIBLE} from 'vs/editor/contrib/suggest/common/suggest';
import {INullService} from 'vs/platform/instantiation/common/instantiation';
import {KeyMod, KeyCode} from 'vs/base/common/keyCodes';
import { IKeybindingService, IKeybindingContextKey } from 'vs/platform/keybinding/common/keybindingService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { SuggestRegistry, ACCEPT_SELECTED_SUGGESTION_CMD, CONTEXT_SUGGEST_WIDGET_VISIBLE } from 'vs/editor/contrib/suggest/common/suggest';
import { IInstantiationService, INullService } from 'vs/platform/instantiation/common/instantiation';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
export class SuggestController implements EditorCommon.IEditorContribution {
static ID = 'editor.contrib.suggestController';
......@@ -31,39 +31,25 @@ export class SuggestController implements EditorCommon.IEditorContribution {
return <SuggestController>editor.getContribution(SuggestController.ID);
}
private editor:EditorBrowser.ICodeEditor;
private model:SuggestModel.SuggestModel;
private suggestWidget: SuggestWidget.SuggestWidget;
private toDispose: Lifecycle.IDisposable[];
private model: SuggestModel;
private widget: SuggestWidget;
private triggerCharacterListeners: Function[];
private suggestWidgetVisible: IKeybindingContextKey<boolean>;
private toDispose: Lifecycle.IDisposable[];
constructor(
editor:EditorBrowser.ICodeEditor,
private editor:EditorBrowser.ICodeEditor,
@IKeybindingService keybindingService: IKeybindingService,
@ITelemetryService telemetryService: ITelemetryService
@IInstantiationService instantiationService: IInstantiationService
) {
this.editor = editor;
this.suggestWidgetVisible = keybindingService.createKey(CONTEXT_SUGGEST_WIDGET_VISIBLE, false);
this.model = new SuggestModel.SuggestModel(
this.editor,
(snippet:Snippet.CodeSnippet, overwriteBefore:number, overwriteAfter:number) => Snippet.get(this.editor).run(snippet, overwriteBefore, overwriteAfter)
);
this.suggestWidget = new SuggestWidget.SuggestWidget(
this.editor,
this.model,
telemetryService,
keybindingService,
() => this.suggestWidgetVisible.set(true),
() => this.suggestWidgetVisible.reset()
);
this.model = new SuggestModel(this.editor);
this.widget = instantiationService.createInstance(SuggestWidget, this.editor, this.model);
this.triggerCharacterListeners = [];
this.toDispose = [];
this.toDispose.push(this.widget.onDidVisibilityChange(visible => visible ? this.suggestWidgetVisible.set(true) : this.suggestWidgetVisible.reset()));
this.toDispose.push(editor.addListener2(EditorCommon.EventType.ConfigurationChanged, () => this.update()));
this.toDispose.push(editor.addListener2(EditorCommon.EventType.ModelChanged, () => this.update()));
this.toDispose.push(editor.addListener2(EditorCommon.EventType.ModelModeChanged, () => this.update()));
......@@ -74,6 +60,9 @@ export class SuggestController implements EditorCommon.IEditorContribution {
}));
this.toDispose.push(SuggestRegistry.onDidChange(this.update, this));
// TODO@Joao: what is this?
this.toDispose.push(this.model.onDidAccept(e => Snippet.get(this.editor).run(e.snippet, e.overwriteBefore, e.overwriteAfter)));
this.update();
}
......@@ -85,12 +74,12 @@ export class SuggestController implements EditorCommon.IEditorContribution {
this.toDispose = Lifecycle.disposeAll(this.toDispose);
this.triggerCharacterListeners = Lifecycle.cAll(this.triggerCharacterListeners);
if (this.suggestWidget) {
this.suggestWidget.destroy();
this.suggestWidget = null;
if (this.widget) {
this.widget.dispose();
this.widget = null;
}
if (this.model) {
this.model.destroy();
this.model.dispose();
this.model = null;
}
}
......@@ -167,38 +156,38 @@ export class SuggestController implements EditorCommon.IEditorContribution {
}
public acceptSelectedSuggestion(): void {
if (this.suggestWidget) {
this.suggestWidget.acceptSelectedSuggestion();
if (this.widget) {
this.widget.acceptSelectedSuggestion();
}
}
public hideSuggestWidget(): void {
if (this.suggestWidget) {
this.suggestWidget.cancel();
if (this.widget) {
this.widget.cancel();
}
}
public selectNextSuggestion(): void {
if (this.suggestWidget) {
this.suggestWidget.selectNext();
if (this.widget) {
this.widget.selectNext();
}
}
public selectNextPageSuggestion(): void {
if (this.suggestWidget) {
this.suggestWidget.selectNextPage();
if (this.widget) {
this.widget.selectNextPage();
}
}
public selectPrevSuggestion(): void {
if (this.suggestWidget) {
this.suggestWidget.selectPrevious();
if (this.widget) {
this.widget.selectPrevious();
}
}
public selectPrevPageSuggestion(): void {
if (this.suggestWidget) {
this.suggestWidget.selectPreviousPage();
if (this.widget) {
this.widget.selectPreviousPage();
}
}
}
......
......@@ -21,10 +21,10 @@ import { CodeSnippet } from 'vs/editor/contrib/snippet/common/snippet';
import { IDisposable, disposeAll } from 'vs/base/common/lifecycle';
import { SuggestRegistry, ISuggestResult2, suggest } from '../common/suggest';
enum SuggestState {
NOT_ACTIVE = 0,
MANUAL_TRIGGER = 1,
AUTO_TRIGGER = 2
enum State {
Idle = 0,
Manual = 1,
Auto = 2
}
export interface SuggestDataEvent {
......@@ -261,17 +261,21 @@ export interface ISuggestEvent {
auto: boolean;
}
export class SuggestModel {
export interface IAcceptEvent {
snippet: CodeSnippet;
overwriteBefore: number;
overwriteAfter: number;
}
export class SuggestModel implements IDisposable {
private editor: EditorCommon.ICommonCodeEditor;
private onAccept:(snippet: CodeSnippet, overwriteBefore:number, overwriteAfter:number)=>void;
private toDispose: IDisposable[];
private autoSuggestDelay:number;
private triggerAutoSuggestPromise:TPromise<void>;
private state:SuggestState;
private state:State;
// Members which make sense when state is active
private requestPromise:TPromise<void>;
private requestContext:SuggestionContext;
private raw:RawModel;
......@@ -285,41 +289,26 @@ export class SuggestModel {
private _onDidSuggest: Emitter<ISuggestEvent> = new Emitter();
public get onDidSuggest(): Event<ISuggestEvent> { return this._onDidSuggest.event; }
constructor(editor:EditorCommon.ICommonCodeEditor, onAccept:(snippet: CodeSnippet, overwriteBefore:number, overwriteAfter:number)=>void) {
this.editor = editor;
this.onAccept = onAccept;
this.toDispose = [];
this.toDispose.push(this.editor.addListener2(EditorCommon.EventType.ConfigurationChanged, () => this.onEditorConfigurationChange()));
this.onEditorConfigurationChange();
// TODO@joao: remove
private _onDidAccept: Emitter<IAcceptEvent> = new Emitter();
public get onDidAccept(): Event<IAcceptEvent> { return this._onDidAccept.event; }
constructor(private editor: EditorCommon.ICommonCodeEditor) {
this.state = State.Idle;
this.triggerAutoSuggestPromise = null;
this.state = SuggestState.NOT_ACTIVE;
this.requestPromise = null;
this.raw = null;
this.requestContext = null;
this.toDispose.push(this.editor.addListener2(EditorCommon.EventType.CursorSelectionChanged, (e: EditorCommon.ICursorSelectionChangedEvent) => {
if (!e.selection.isEmpty()) {
this.cancel();
return;
}
if (e.source !== 'keyboard' || e.reason !== '') {
this.cancel();
return;
}
this.onCursorChange();
}));
this.toDispose.push(this.editor.addListener2(EditorCommon.EventType.ModelChanged, (e) => {
this.cancel();
}));
this.toDispose = [];
this.toDispose.push(this.editor.addListener2(EditorCommon.EventType.ConfigurationChanged, () => this.onEditorConfigurationChange()));
this.toDispose.push(this.editor.addListener2(EditorCommon.EventType.CursorSelectionChanged, e => this.onCursorChange(e)));
this.toDispose.push(this.editor.addListener2(EditorCommon.EventType.ModelChanged, () => this.cancel()));
this.onEditorConfigurationChange();
}
public cancel(silent:boolean = false, retrigger:boolean = false):boolean {
var actuallyCanceled = (this.state !== SuggestState.NOT_ACTIVE);
var actuallyCanceled = this.state !== State.Idle;
if (this.triggerAutoSuggestPromise) {
this.triggerAutoSuggestPromise.cancel();
......@@ -331,7 +320,7 @@ export class SuggestModel {
this.requestPromise = null;
}
this.state = SuggestState.NOT_ACTIVE;
this.state = State.Idle;
this.raw = null;
this.requestContext = null;
......@@ -346,6 +335,7 @@ export class SuggestModel {
if(!this.requestContext) {
return null;
}
return {
lineNumber: this.requestContext.lineNumber,
column: this.requestContext.column
......@@ -353,15 +343,25 @@ export class SuggestModel {
}
private isAutoSuggest():boolean {
return this.state === SuggestState.AUTO_TRIGGER;
return this.state === State.Auto;
}
private onCursorChange():void {
private onCursorChange(e: EditorCommon.ICursorSelectionChangedEvent):void {
if (!e.selection.isEmpty()) {
this.cancel();
return;
}
if (e.source !== 'keyboard' || e.reason !== '') {
this.cancel();
return;
}
if (!SuggestRegistry.has(this.editor.getModel())) {
return;
}
var isInactive = this.state === SuggestState.NOT_ACTIVE;
var isInactive = this.state === State.Idle;
if (isInactive && !this.editor.getConfiguration().quickSuggestions) {
return;
......@@ -382,7 +382,7 @@ export class SuggestModel {
}
} else if (this.raw && this.raw.incomplete) {
this.trigger(this.state === SuggestState.AUTO_TRIGGER, undefined, true);
this.trigger(this.state === State.Auto, undefined, true);
} else {
this.onNewContext(ctx);
}
......@@ -402,35 +402,27 @@ export class SuggestModel {
return;
}
var $tTrigger = timer.start(timer.Topic.EDITOR, 'suggest/TRIGGER');
// Cancel previous requests, change state & update UI
this.cancel(false, retrigger);
this.state = (auto || characterTriggered) ? SuggestState.AUTO_TRIGGER : SuggestState.MANUAL_TRIGGER;
this.state = (auto || characterTriggered) ? State.Auto : State.Manual;
this._onDidTrigger.fire({ auto: this.isAutoSuggest(), characterTriggered, retrigger });
// Capture context when request was sent
this.requestContext = ctx;
// Send mode request
var $tRequest = timer.start(timer.Topic.EDITOR, 'suggest/REQUEST');
var position = this.editor.getPosition();
let raw = new RawModel();
let rank = 0;
this.requestPromise = suggest(model, position, triggerCharacter, groups).then(all => {
for (let suggestions of all) {
if (raw.insertSuggestions(rank, suggestions)) {
rank++;
}
}
});
this.requestPromise.then(() => {
$tRequest.stop();
this.requestPromise = null;
if (this.state === SuggestState.NOT_ACTIVE) {
if (this.state === State.Idle) {
return;
}
......@@ -447,15 +439,13 @@ export class SuggestModel {
} else {
this._onDidSuggest.fire({ suggestions: null, auto: this.isAutoSuggest() });
}
}, () => {
$tRequest.stop();
}).done(() => $tTrigger.stop());
}).then(null, onUnexpectedError);
}
private onNewContext(ctx:SuggestionContext):void {
if (this.requestContext && !this.requestContext.isValidForNewContext(ctx)) {
if (this.requestContext.isValidForRetrigger(ctx)) {
this.trigger(this.state === SuggestState.AUTO_TRIGGER, undefined, true);
this.trigger(this.state === State.Auto, undefined, true);
} else {
this.cancel();
}
......@@ -491,7 +481,10 @@ export class SuggestModel {
: Math.max(0, parentSuggestions.overwriteAfter);
this.cancel();
this.onAccept(new CodeSnippet(item.suggestion.codeSnippet), overwriteBefore, overwriteAfter);
this._onDidAccept.fire({
snippet: new CodeSnippet(item.suggestion.codeSnippet),
overwriteBefore, overwriteAfter
});
return true;
}
......@@ -504,7 +497,7 @@ export class SuggestModel {
}
}
public destroy():void {
public dispose():void {
this.cancel(true);
this.toDispose = disposeAll(this.toDispose);
}
......
......@@ -10,6 +10,7 @@ import nls = require('vs/nls');
import { TPromise } from 'vs/base/common/winjs.base';
import { IDisposable, disposeAll } from 'vs/base/common/lifecycle';
import Errors = require('vs/base/common/errors');
import Event, { Emitter } from 'vs/base/common/event';
import dom = require('vs/base/browser/dom');
import Tree = require('vs/base/parts/tree/common/tree');
import TreeImpl = require('vs/base/parts/tree/browser/treeImpl');
......@@ -138,12 +139,6 @@ interface ISuggestionTemplateData {
class Renderer implements Tree.IRenderer {
private editor: EditorBrowser.ICodeEditor;
constructor(editor: EditorBrowser.ICodeEditor) {
this.editor = editor;
}
public getHeight(tree:Tree.ITree, element:any):number {
// var suggestion = <Modes.ISuggestion>element;
......@@ -245,14 +240,13 @@ interface ITelemetryData {
wasAutomaticallyTriggered?: boolean;
}
export class SuggestWidget implements EditorBrowser.IContentWidget {
export class SuggestWidget implements EditorBrowser.IContentWidget, IDisposable {
static ID = 'editor.widget.suggestWidget';
static WIDTH = 438;
static LOADING_MESSAGE = new MessageRoot(nls.localize('suggestWidget.loading', "Loading..."));
static NO_SUGGESTIONS_MESSAGE = new MessageRoot(nls.localize('suggestWidget.noSuggestions', "No suggestions."));
private editor: EditorBrowser.ICodeEditor;
private shouldShowEmptySuggestionList: boolean;
private isActive: boolean;
private isLoading: boolean;
......@@ -273,21 +267,15 @@ export class SuggestWidget implements EditorBrowser.IContentWidget {
// Editor.IContentWidget.allowEditorOverflow
public allowEditorOverflow = true;
private _onShown: () => void;
private _onHidden: () => void;
private _onDidVisibilityChange: Emitter<boolean> = new Emitter();
public get onDidVisibilityChange(): Event<boolean> { return this._onDidVisibilityChange.event; }
constructor(
editor: EditorBrowser.ICodeEditor,
private editor: EditorBrowser.ICodeEditor,
private model: SuggestModel,
telemetryService:ITelemetryService,
keybindingService:IKeybindingService,
onShown: () => void,
onHidden: () => void
@IKeybindingService keybindingService: IKeybindingService,
@ITelemetryService telemetryService: ITelemetryService
) {
this.editor = editor;
this._onShown = onShown;
this._onHidden = onHidden;
this.isActive = false;
this.isLoading = false;
this.isAuto = false;
......@@ -324,14 +312,12 @@ export class SuggestWidget implements EditorBrowser.IContentWidget {
dom.addClass(this.element, 'no-icons');
}
var dataSource = new DataSource();
this.renderer = new Renderer(this.editor);
this.renderer = new Renderer();
const dataSource = new DataSource();
const controller = new Controller();
const configuration = { renderer: this.renderer, dataSource, controller };
this.tree = new TreeImpl.Tree(this.element, {
dataSource: dataSource,
renderer: this.renderer,
controller: new Controller()
}, {
this.tree = new TreeImpl.Tree(this.element, configuration, {
twistiePixels: 0,
alwaysFocused: true,
verticalScrollMode: 'visible',
......@@ -612,7 +598,7 @@ export class SuggestWidget implements EditorBrowser.IContentWidget {
}
public show(): void {
this._onShown();
this._onDidVisibilityChange.fire(true);
this.isActive = true;
this.tree.layout();
this.editor.layoutContentWidget(this);
......@@ -626,8 +612,7 @@ export class SuggestWidget implements EditorBrowser.IContentWidget {
}
public hide(): void {
this._onHidden();
this._onDidVisibilityChange.fire(false);
this.isActive = false;
dom.removeClass(this.element, 'visible');
this.editor.layoutContentWidget(this);
......@@ -679,7 +664,7 @@ export class SuggestWidget implements EditorBrowser.IContentWidget {
this.editor.layoutContentWidget(this);
}
public destroy() : void {
public dispose() : void {
this.modelListenersToRemove = disposeAll(this.modelListenersToRemove);
this.model = null;
this.tree.dispose();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册