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

parameter hints 💄

上级 ea75c05c
......@@ -7,17 +7,16 @@
import * as nls from 'vs/nls';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
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 { ICommonCodeEditor, IEditorActionDescriptorData, IEditorContribution } from 'vs/editor/common/editorCommon';
import { CommonEditorRegistry, ContextKey, EditorActionDescriptor } from 'vs/editor/common/editorCommonExtensions';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorBrowserRegistry } from 'vs/editor/browser/editorBrowserExtensions';
import { SignatureHelpProviderRegistry } from 'vs/editor/common/modes';
import { ParameterHintsModel } from './parameterHintsModel';
import { ParameterHintsWidget } from './parameterHintsWidget';
const CONTEXT_PARAMETER_HINTS_VISIBLE = 'parameterHintsVisible';
import { Context } from '../common/parameterHints';
class ParameterHintsController implements IEditorContribution {
......@@ -28,27 +27,11 @@ class ParameterHintsController implements IEditorContribution {
}
private editor:ICodeEditor;
private model: ParameterHintsModel;
private widget: ParameterHintsWidget;
private parameterHintsVisible: IKeybindingContextKey<boolean>;
constructor(editor:ICodeEditor, @IKeybindingService keybindingService: IKeybindingService) {
constructor(editor:ICodeEditor, @IInstantiationService instantiationService: IInstantiationService) {
this.editor = editor;
this.model = new ParameterHintsModel(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;
this.widget = instantiationService.createInstance(ParameterHintsWidget, this.editor);
}
getId(): string {
......@@ -68,7 +51,11 @@ class ParameterHintsController implements IEditorContribution {
}
trigger(): void {
this.model.trigger(0);
this.widget.trigger();
}
dispose(): void {
this.widget = dispose(this.widget);
}
}
......@@ -111,7 +98,7 @@ CommonEditorRegistry.registerEditorCommand(
weight,
{ primary: KeyCode.Escape, secondary: [KeyMod.Shift | KeyCode.Escape] },
true,
CONTEXT_PARAMETER_HINTS_VISIBLE,
Context.Visible,
handler(c => c.closeWidget())
);
......@@ -120,7 +107,7 @@ CommonEditorRegistry.registerEditorCommand(
weight,
{ primary: KeyCode.UpArrow, secondary: [KeyMod.Alt | KeyCode.UpArrow] },
true,
CONTEXT_PARAMETER_HINTS_VISIBLE,
Context.Visible,
handler(c =>c.showPrevHint())
);
......@@ -129,6 +116,6 @@ CommonEditorRegistry.registerEditorCommand(
weight,
{ primary: KeyCode.DownArrow, secondary: [KeyMod.Alt | KeyCode.DownArrow] },
true,
CONTEXT_PARAMETER_HINTS_VISIBLE,
Context.Visible,
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 @@
import 'vs/css!./parameterHints';
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 * as dom from 'vs/base/browser/dom';
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 { 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;
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 {
top: number;
height: number;
}
export class ParameterHintsWidget implements IContentWidget {
export class ParameterHintsWidget implements IContentWidget, IDisposable {
static ID = 'editor.widget.parameterHintsWidget';
private editor: ICodeEditor;
private model: ParameterHintsModel;
private parameterHintsVisible: IKeybindingContextKey<boolean>;
private element: HTMLElement;
private signatures: HTMLElement;
private overloads: HTMLElement;
......@@ -38,20 +159,13 @@ export class ParameterHintsWidget implements IContentWidget {
private announcedLabel: string;
private disposables: IDisposable[];
private _onShown: () => void;
private _onHidden: () => void;
// Editor.IContentWidget.allowEditorOverflow
allowEditorOverflow = true;
constructor(model: ParameterHintsModel, editor: ICodeEditor, onShown: () => void, onHidden: () => void) {
this._onShown = onShown;
this._onHidden = onHidden;
this.editor = editor;
this.model = null;
constructor(private editor: ICodeEditor, @IKeybindingService keybindingService: IKeybindingService) {
this.model = new ParameterHintsModel(editor);
this.parameterHintsVisible = keybindingService.createKey(Context.Visible, false);
this.visible = false;
this.model = model;
this.disposables = [];
this.disposables.push(this.model.onHint((e:IHintEvent) => {
......@@ -62,7 +176,9 @@ export class ParameterHintsWidget implements IContentWidget {
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');
......@@ -109,7 +225,7 @@ export class ParameterHintsWidget implements IContentWidget {
return;
}
this._onShown();
this.parameterHintsVisible.set(true);
this.visible = true;
TPromise.timeout(100).done(() => dom.addClass(this.element, 'visible'));
this.editor.layoutContentWidget(this);
......@@ -120,7 +236,7 @@ export class ParameterHintsWidget implements IContentWidget {
return;
}
this._onHidden();
this.parameterHintsVisible.reset();
this.visible = false;
this.parameterHints = null;
this.announcedLabel = null;
......@@ -318,7 +434,11 @@ export class ParameterHintsWidget implements IContentWidget {
return ParameterHintsWidget.ID;
}
destroy(): void {
trigger(): void {
this.model.trigger(0);
}
dispose(): void {
this.disposables = dispose(this.disposables);
this.model = null;
}
......
......@@ -12,6 +12,10 @@ import { SignatureHelp, SignatureHelpProviderRegistry } from 'vs/editor/common/m
import { asWinJsPromise } from 'vs/base/common/async';
import { Position } from 'vs/editor/common/core/position';
export const Context = {
Visible: 'parameterHintsVisible'
};
export function provideSignatureHelp(model:IReadOnlyModel, position:Position): TPromise<SignatureHelp> {
const support = SignatureHelpProviderRegistry.ordered(model)[0];
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册