提交 f3993616 编写于 作者: J Joao Moreno

parameter hints 💄

上级 ea75c05c
...@@ -7,17 +7,16 @@ ...@@ -7,17 +7,16 @@
import * as nls from 'vs/nls'; import * as nls from 'vs/nls';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { TPromise } from 'vs/base/common/winjs.base'; import { TPromise } from 'vs/base/common/winjs.base';
import { IKeybindingContextKey, IKeybindingService } from 'vs/platform/keybinding/common/keybindingService'; import { dispose } from 'vs/base/common/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { EditorAction } from 'vs/editor/common/editorAction'; import { EditorAction } from 'vs/editor/common/editorAction';
import { ICommonCodeEditor, IEditorActionDescriptorData, IEditorContribution } from 'vs/editor/common/editorCommon'; import { ICommonCodeEditor, IEditorActionDescriptorData, IEditorContribution } from 'vs/editor/common/editorCommon';
import { CommonEditorRegistry, ContextKey, EditorActionDescriptor } from 'vs/editor/common/editorCommonExtensions'; import { CommonEditorRegistry, ContextKey, EditorActionDescriptor } from 'vs/editor/common/editorCommonExtensions';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorBrowserRegistry } from 'vs/editor/browser/editorBrowserExtensions'; import { EditorBrowserRegistry } from 'vs/editor/browser/editorBrowserExtensions';
import { SignatureHelpProviderRegistry } from 'vs/editor/common/modes'; import { SignatureHelpProviderRegistry } from 'vs/editor/common/modes';
import { ParameterHintsModel } from './parameterHintsModel';
import { ParameterHintsWidget } from './parameterHintsWidget'; import { ParameterHintsWidget } from './parameterHintsWidget';
import { Context } from '../common/parameterHints';
const CONTEXT_PARAMETER_HINTS_VISIBLE = 'parameterHintsVisible';
class ParameterHintsController implements IEditorContribution { class ParameterHintsController implements IEditorContribution {
...@@ -28,27 +27,11 @@ class ParameterHintsController implements IEditorContribution { ...@@ -28,27 +27,11 @@ class ParameterHintsController implements IEditorContribution {
} }
private editor:ICodeEditor; private editor:ICodeEditor;
private model: ParameterHintsModel;
private widget: ParameterHintsWidget; private widget: ParameterHintsWidget;
private parameterHintsVisible: IKeybindingContextKey<boolean>;
constructor(editor:ICodeEditor, @IKeybindingService keybindingService: IKeybindingService) { constructor(editor:ICodeEditor, @IInstantiationService instantiationService: IInstantiationService) {
this.editor = editor; this.editor = editor;
this.model = new ParameterHintsModel(this.editor); this.widget = instantiationService.createInstance(ParameterHintsWidget, this.editor);
this.parameterHintsVisible = keybindingService.createKey(CONTEXT_PARAMETER_HINTS_VISIBLE, false);
this.widget = new ParameterHintsWidget(this.model, this.editor, () => {
this.parameterHintsVisible.set(true);
}, () => {
this.parameterHintsVisible.reset();
});
}
dispose(): void {
this.model.dispose();
this.model = null;
this.widget.destroy();
this.widget = null;
} }
getId(): string { getId(): string {
...@@ -68,7 +51,11 @@ class ParameterHintsController implements IEditorContribution { ...@@ -68,7 +51,11 @@ class ParameterHintsController implements IEditorContribution {
} }
trigger(): void { trigger(): void {
this.model.trigger(0); this.widget.trigger();
}
dispose(): void {
this.widget = dispose(this.widget);
} }
} }
...@@ -111,7 +98,7 @@ CommonEditorRegistry.registerEditorCommand( ...@@ -111,7 +98,7 @@ CommonEditorRegistry.registerEditorCommand(
weight, weight,
{ primary: KeyCode.Escape, secondary: [KeyMod.Shift | KeyCode.Escape] }, { primary: KeyCode.Escape, secondary: [KeyMod.Shift | KeyCode.Escape] },
true, true,
CONTEXT_PARAMETER_HINTS_VISIBLE, Context.Visible,
handler(c => c.closeWidget()) handler(c => c.closeWidget())
); );
...@@ -120,7 +107,7 @@ CommonEditorRegistry.registerEditorCommand( ...@@ -120,7 +107,7 @@ CommonEditorRegistry.registerEditorCommand(
weight, weight,
{ primary: KeyCode.UpArrow, secondary: [KeyMod.Alt | KeyCode.UpArrow] }, { primary: KeyCode.UpArrow, secondary: [KeyMod.Alt | KeyCode.UpArrow] },
true, true,
CONTEXT_PARAMETER_HINTS_VISIBLE, Context.Visible,
handler(c =>c.showPrevHint()) handler(c =>c.showPrevHint())
); );
...@@ -129,6 +116,6 @@ CommonEditorRegistry.registerEditorCommand( ...@@ -129,6 +116,6 @@ CommonEditorRegistry.registerEditorCommand(
weight, weight,
{ primary: KeyCode.DownArrow, secondary: [KeyMod.Alt | KeyCode.DownArrow] }, { primary: KeyCode.DownArrow, secondary: [KeyMod.Alt | KeyCode.DownArrow] },
true, true,
CONTEXT_PARAMETER_HINTS_VISIBLE, Context.Visible,
handler(c => c.showNextHint()) handler(c => c.showNextHint())
); );
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { RunOnceScheduler } from 'vs/base/common/async';
import { onUnexpectedError } from 'vs/base/common/errors';
import Event, {Emitter} from 'vs/base/common/event';
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
import { ICommonCodeEditor, ICursorSelectionChangedEvent } from 'vs/editor/common/editorCommon';
import { SignatureHelpProviderRegistry, SignatureHelp } from 'vs/editor/common/modes';
import { provideSignatureHelp } from '../common/parameterHints';
export interface IHintEvent {
hints: SignatureHelp;
}
export class ParameterHintsModel extends Disposable {
static DELAY = 120; // ms
private _onHint = this._register(new Emitter<IHintEvent>());
onHint: Event<IHintEvent> = this._onHint.event;
private _onCancel = this._register(new Emitter<void>());
onCancel: Event<void> = this._onCancel.event;
private editor: ICommonCodeEditor;
private triggerCharactersListeners: IDisposable[];
private active: boolean;
private throttledDelayer: RunOnceScheduler;
constructor(editor:ICommonCodeEditor) {
super();
this.editor = editor;
this.triggerCharactersListeners = [];
this.throttledDelayer = new RunOnceScheduler(() => this.doTrigger(), ParameterHintsModel.DELAY);
this.active = false;
this._register(this.editor.onDidChangeModel(e => this.onModelChanged()));
this._register(this.editor.onDidChangeModelMode(_ => this.onModelChanged()));
this._register(this.editor.onDidChangeCursorSelection(e => this.onCursorChange(e)));
this._register(SignatureHelpProviderRegistry.onDidChange(this.onModelChanged, this));
this.onModelChanged();
}
cancel(silent: boolean = false): void {
this.active = false;
this.throttledDelayer.cancel();
if (!silent) {
this._onCancel.fire(void 0);
}
}
trigger(delay = ParameterHintsModel.DELAY): void {
if (!SignatureHelpProviderRegistry.has(this.editor.getModel())) {
return;
}
this.cancel(true);
return this.throttledDelayer.schedule(delay);
}
private doTrigger(): void {
provideSignatureHelp(this.editor.getModel(), this.editor.getPosition())
.then<SignatureHelp>(null, onUnexpectedError)
.then(result => {
if (!result || result.signatures.length === 0) {
this.cancel();
this._onCancel.fire(void 0);
return false;
}
this.active = true;
const event:IHintEvent = { hints: result };
this._onHint.fire(event);
return true;
});
}
isTriggered():boolean {
return this.active || this.throttledDelayer.isScheduled();
}
private onModelChanged(): void {
if (this.active) {
this.cancel();
}
this.triggerCharactersListeners = dispose(this.triggerCharactersListeners);
const model = this.editor.getModel();
if (!model) {
return;
}
const support = SignatureHelpProviderRegistry.ordered(model)[0];
if (!support) {
return;
}
this.triggerCharactersListeners = support.signatureHelpTriggerCharacters.map((ch) => {
return this.editor.addTypingListener(ch, () => {
this.trigger();
});
});
}
private onCursorChange(e: ICursorSelectionChangedEvent): void {
if (e.source === 'mouse') {
this.cancel();
} else if (this.isTriggered()) {
this.trigger();
}
}
dispose(): void {
this.cancel(true);
this.triggerCharactersListeners = dispose(this.triggerCharactersListeners);
super.dispose();
}
}
...@@ -7,27 +7,148 @@ ...@@ -7,27 +7,148 @@
import 'vs/css!./parameterHints'; import 'vs/css!./parameterHints';
import nls = require('vs/nls'); import nls = require('vs/nls');
import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
import { TPromise } from 'vs/base/common/winjs.base'; import { TPromise } from 'vs/base/common/winjs.base';
import * as dom from 'vs/base/browser/dom'; import * as dom from 'vs/base/browser/dom';
import aria = require('vs/base/browser/ui/aria/aria'); import aria = require('vs/base/browser/ui/aria/aria');
import { SignatureHelp, SignatureInformation } from 'vs/editor/common/modes'; import { SignatureHelp, SignatureInformation, SignatureHelpProviderRegistry } from 'vs/editor/common/modes';
import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';
import { IHintEvent, ParameterHintsModel } from './parameterHintsModel'; import { RunOnceScheduler } from 'vs/base/common/async';
import { onUnexpectedError } from 'vs/base/common/errors';
import Event, {Emitter} from 'vs/base/common/event';
import { ICommonCodeEditor, ICursorSelectionChangedEvent } from 'vs/editor/common/editorCommon';
import { IKeybindingContextKey, IKeybindingService } from 'vs/platform/keybinding/common/keybindingService';
import { Context, provideSignatureHelp } from '../common/parameterHints';
const $ = dom.emmet; const $ = dom.emmet;
export interface IHintEvent {
hints: SignatureHelp;
}
export class ParameterHintsModel extends Disposable {
static DELAY = 120; // ms
private _onHint = this._register(new Emitter<IHintEvent>());
onHint: Event<IHintEvent> = this._onHint.event;
private _onCancel = this._register(new Emitter<void>());
onCancel: Event<void> = this._onCancel.event;
private editor: ICommonCodeEditor;
private triggerCharactersListeners: IDisposable[];
private active: boolean;
private throttledDelayer: RunOnceScheduler;
constructor(editor:ICommonCodeEditor) {
super();
this.editor = editor;
this.triggerCharactersListeners = [];
this.throttledDelayer = new RunOnceScheduler(() => this.doTrigger(), ParameterHintsModel.DELAY);
this.active = false;
this._register(this.editor.onDidChangeModel(e => this.onModelChanged()));
this._register(this.editor.onDidChangeModelMode(_ => this.onModelChanged()));
this._register(this.editor.onDidChangeCursorSelection(e => this.onCursorChange(e)));
this._register(SignatureHelpProviderRegistry.onDidChange(this.onModelChanged, this));
this.onModelChanged();
}
cancel(silent: boolean = false): void {
this.active = false;
this.throttledDelayer.cancel();
if (!silent) {
this._onCancel.fire(void 0);
}
}
trigger(delay = ParameterHintsModel.DELAY): void {
if (!SignatureHelpProviderRegistry.has(this.editor.getModel())) {
return;
}
this.cancel(true);
return this.throttledDelayer.schedule(delay);
}
private doTrigger(): void {
provideSignatureHelp(this.editor.getModel(), this.editor.getPosition())
.then<SignatureHelp>(null, onUnexpectedError)
.then(result => {
if (!result || result.signatures.length === 0) {
this.cancel();
this._onCancel.fire(void 0);
return false;
}
this.active = true;
const event:IHintEvent = { hints: result };
this._onHint.fire(event);
return true;
});
}
isTriggered():boolean {
return this.active || this.throttledDelayer.isScheduled();
}
private onModelChanged(): void {
if (this.active) {
this.cancel();
}
this.triggerCharactersListeners = dispose(this.triggerCharactersListeners);
const model = this.editor.getModel();
if (!model) {
return;
}
const support = SignatureHelpProviderRegistry.ordered(model)[0];
if (!support) {
return;
}
this.triggerCharactersListeners = support.signatureHelpTriggerCharacters.map((ch) => {
return this.editor.addTypingListener(ch, () => {
this.trigger();
});
});
}
private onCursorChange(e: ICursorSelectionChangedEvent): void {
if (e.source === 'mouse') {
this.cancel();
} else if (this.isTriggered()) {
this.trigger();
}
}
dispose(): void {
this.cancel(true);
this.triggerCharactersListeners = dispose(this.triggerCharactersListeners);
super.dispose();
}
}
interface ISignatureView { interface ISignatureView {
top: number; top: number;
height: number; height: number;
} }
export class ParameterHintsWidget implements IContentWidget { export class ParameterHintsWidget implements IContentWidget, IDisposable {
static ID = 'editor.widget.parameterHintsWidget'; static ID = 'editor.widget.parameterHintsWidget';
private editor: ICodeEditor;
private model: ParameterHintsModel; private model: ParameterHintsModel;
private parameterHintsVisible: IKeybindingContextKey<boolean>;
private element: HTMLElement; private element: HTMLElement;
private signatures: HTMLElement; private signatures: HTMLElement;
private overloads: HTMLElement; private overloads: HTMLElement;
...@@ -38,20 +159,13 @@ export class ParameterHintsWidget implements IContentWidget { ...@@ -38,20 +159,13 @@ export class ParameterHintsWidget implements IContentWidget {
private announcedLabel: string; private announcedLabel: string;
private disposables: IDisposable[]; private disposables: IDisposable[];
private _onShown: () => void;
private _onHidden: () => void;
// Editor.IContentWidget.allowEditorOverflow // Editor.IContentWidget.allowEditorOverflow
allowEditorOverflow = true; allowEditorOverflow = true;
constructor(model: ParameterHintsModel, editor: ICodeEditor, onShown: () => void, onHidden: () => void) { constructor(private editor: ICodeEditor, @IKeybindingService keybindingService: IKeybindingService) {
this._onShown = onShown; this.model = new ParameterHintsModel(editor);
this._onHidden = onHidden; this.parameterHintsVisible = keybindingService.createKey(Context.Visible, false);
this.editor = editor;
this.model = null;
this.visible = false; this.visible = false;
this.model = model;
this.disposables = []; this.disposables = [];
this.disposables.push(this.model.onHint((e:IHintEvent) => { this.disposables.push(this.model.onHint((e:IHintEvent) => {
...@@ -62,7 +176,9 @@ export class ParameterHintsWidget implements IContentWidget { ...@@ -62,7 +176,9 @@ export class ParameterHintsWidget implements IContentWidget {
this.select(this.currentSignature); this.select(this.currentSignature);
})); }));
this.disposables.push(this.model.onCancel(() => this.hide())); this.disposables.push(this.model.onCancel(() => {
this.hide();
}));
this.element = $('.editor-widget.parameter-hints-widget'); this.element = $('.editor-widget.parameter-hints-widget');
...@@ -109,7 +225,7 @@ export class ParameterHintsWidget implements IContentWidget { ...@@ -109,7 +225,7 @@ export class ParameterHintsWidget implements IContentWidget {
return; return;
} }
this._onShown(); this.parameterHintsVisible.set(true);
this.visible = true; this.visible = true;
TPromise.timeout(100).done(() => dom.addClass(this.element, 'visible')); TPromise.timeout(100).done(() => dom.addClass(this.element, 'visible'));
this.editor.layoutContentWidget(this); this.editor.layoutContentWidget(this);
...@@ -120,7 +236,7 @@ export class ParameterHintsWidget implements IContentWidget { ...@@ -120,7 +236,7 @@ export class ParameterHintsWidget implements IContentWidget {
return; return;
} }
this._onHidden(); this.parameterHintsVisible.reset();
this.visible = false; this.visible = false;
this.parameterHints = null; this.parameterHints = null;
this.announcedLabel = null; this.announcedLabel = null;
...@@ -318,7 +434,11 @@ export class ParameterHintsWidget implements IContentWidget { ...@@ -318,7 +434,11 @@ export class ParameterHintsWidget implements IContentWidget {
return ParameterHintsWidget.ID; return ParameterHintsWidget.ID;
} }
destroy(): void { trigger(): void {
this.model.trigger(0);
}
dispose(): void {
this.disposables = dispose(this.disposables); this.disposables = dispose(this.disposables);
this.model = null; this.model = null;
} }
......
...@@ -12,6 +12,10 @@ import { SignatureHelp, SignatureHelpProviderRegistry } from 'vs/editor/common/m ...@@ -12,6 +12,10 @@ import { SignatureHelp, SignatureHelpProviderRegistry } from 'vs/editor/common/m
import { asWinJsPromise } from 'vs/base/common/async'; import { asWinJsPromise } from 'vs/base/common/async';
import { Position } from 'vs/editor/common/core/position'; import { Position } from 'vs/editor/common/core/position';
export const Context = {
Visible: 'parameterHintsVisible'
};
export function provideSignatureHelp(model:IReadOnlyModel, position:Position): TPromise<SignatureHelp> { export function provideSignatureHelp(model:IReadOnlyModel, position:Position): TPromise<SignatureHelp> {
const support = SignatureHelpProviderRegistry.ordered(model)[0]; const support = SignatureHelpProviderRegistry.ordered(model)[0];
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册