mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-21 12:20:29 -04:00
Merge VS Code 1.31.1 (#4283)
This commit is contained in:
269
src/vs/editor/contrib/parameterHints/parameterHintsModel.ts
Normal file
269
src/vs/editor/contrib/parameterHints/parameterHintsModel.ts
Normal file
@@ -0,0 +1,269 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CancelablePromise, createCancelablePromise, Delayer } from 'vs/base/common/async';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { CharacterSet } from 'vs/editor/common/core/characterClassifier';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { provideSignatureHelp } from 'vs/editor/contrib/parameterHints/provideSignatureHelp';
|
||||
|
||||
export interface TriggerContext {
|
||||
readonly triggerKind: modes.SignatureHelpTriggerKind;
|
||||
readonly triggerCharacter?: string;
|
||||
}
|
||||
|
||||
namespace ParameterHintState {
|
||||
export const enum Type {
|
||||
Default,
|
||||
Active,
|
||||
Pending,
|
||||
}
|
||||
|
||||
export const Default = new class { readonly type = Type.Default; };
|
||||
export const Pending = new class { readonly type = Type.Pending; };
|
||||
|
||||
export class Active {
|
||||
readonly type = Type.Active;
|
||||
constructor(
|
||||
readonly hints: modes.SignatureHelp
|
||||
) { }
|
||||
}
|
||||
|
||||
export type State = typeof Default | typeof Pending | Active;
|
||||
}
|
||||
|
||||
export class ParameterHintsModel extends Disposable {
|
||||
|
||||
private static readonly DEFAULT_DELAY = 120; // ms
|
||||
|
||||
private readonly _onChangedHints = this._register(new Emitter<modes.SignatureHelp | undefined>());
|
||||
public readonly onChangedHints = this._onChangedHints.event;
|
||||
|
||||
private editor: ICodeEditor;
|
||||
private enabled: boolean;
|
||||
private state: ParameterHintState.State = ParameterHintState.Default;
|
||||
private triggerChars = new CharacterSet();
|
||||
private retriggerChars = new CharacterSet();
|
||||
|
||||
private throttledDelayer: Delayer<boolean>;
|
||||
private provideSignatureHelpRequest?: CancelablePromise<any>;
|
||||
private triggerId = 0;
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
delay: number = ParameterHintsModel.DEFAULT_DELAY
|
||||
) {
|
||||
super();
|
||||
|
||||
this.editor = editor;
|
||||
this.enabled = false;
|
||||
|
||||
this.throttledDelayer = new Delayer(delay);
|
||||
|
||||
this._register(this.editor.onDidChangeConfiguration(() => this.onEditorConfigurationChange()));
|
||||
this._register(this.editor.onDidChangeModel(e => this.onModelChanged()));
|
||||
this._register(this.editor.onDidChangeModelLanguage(_ => this.onModelChanged()));
|
||||
this._register(this.editor.onDidChangeCursorSelection(e => this.onCursorChange(e)));
|
||||
this._register(this.editor.onDidChangeModelContent(e => this.onModelContentChange()));
|
||||
this._register(modes.SignatureHelpProviderRegistry.onDidChange(this.onModelChanged, this));
|
||||
this._register(this.editor.onDidType(text => this.onDidType(text)));
|
||||
|
||||
this.onEditorConfigurationChange();
|
||||
this.onModelChanged();
|
||||
}
|
||||
|
||||
cancel(silent: boolean = false): void {
|
||||
this.state = ParameterHintState.Default;
|
||||
|
||||
this.throttledDelayer.cancel();
|
||||
|
||||
if (!silent) {
|
||||
this._onChangedHints.fire(undefined);
|
||||
}
|
||||
|
||||
if (this.provideSignatureHelpRequest) {
|
||||
this.provideSignatureHelpRequest.cancel();
|
||||
this.provideSignatureHelpRequest = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
trigger(context: TriggerContext, delay?: number): void {
|
||||
const model = this.editor.getModel();
|
||||
if (model === null || !modes.SignatureHelpProviderRegistry.has(model)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const triggerId = ++this.triggerId;
|
||||
this.throttledDelayer.trigger(
|
||||
() => this.doTrigger({
|
||||
triggerKind: context.triggerKind,
|
||||
triggerCharacter: context.triggerCharacter,
|
||||
isRetrigger: this.state.type === ParameterHintState.Type.Active || this.state.type === ParameterHintState.Type.Pending,
|
||||
activeSignatureHelp: this.state.type === ParameterHintState.Type.Active ? this.state.hints : undefined
|
||||
}, triggerId), delay).then(undefined, onUnexpectedError);
|
||||
}
|
||||
|
||||
public next(): void {
|
||||
if (this.state.type !== ParameterHintState.Type.Active) {
|
||||
return;
|
||||
}
|
||||
|
||||
const length = this.state.hints.signatures.length;
|
||||
const activeSignature = this.state.hints.activeSignature;
|
||||
const last = (activeSignature % length) === (length - 1);
|
||||
const cycle = this.editor.getConfiguration().contribInfo.parameterHints.cycle;
|
||||
|
||||
// If there is only one signature, or we're on last signature of list
|
||||
if ((length < 2 || last) && !cycle) {
|
||||
this.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateActiveSignature(last && cycle ? 0 : activeSignature + 1);
|
||||
}
|
||||
|
||||
public previous(): void {
|
||||
if (this.state.type !== ParameterHintState.Type.Active) {
|
||||
return;
|
||||
}
|
||||
|
||||
const length = this.state.hints.signatures.length;
|
||||
const activeSignature = this.state.hints.activeSignature;
|
||||
const first = activeSignature === 0;
|
||||
const cycle = this.editor.getConfiguration().contribInfo.parameterHints.cycle;
|
||||
|
||||
// If there is only one signature, or we're on first signature of list
|
||||
if ((length < 2 || first) && !cycle) {
|
||||
this.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateActiveSignature(first && cycle ? length - 1 : activeSignature - 1);
|
||||
}
|
||||
|
||||
private updateActiveSignature(activeSignature: number) {
|
||||
if (this.state.type !== ParameterHintState.Type.Active) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.state = new ParameterHintState.Active({ ...this.state.hints, activeSignature });
|
||||
this._onChangedHints.fire(this.state.hints);
|
||||
}
|
||||
|
||||
private doTrigger(triggerContext: modes.SignatureHelpContext, triggerId: number): Promise<boolean> {
|
||||
this.cancel(true);
|
||||
|
||||
if (!this.editor.hasModel()) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
const model = this.editor.getModel();
|
||||
const position = this.editor.getPosition();
|
||||
|
||||
this.state = ParameterHintState.Pending;
|
||||
|
||||
this.provideSignatureHelpRequest = createCancelablePromise(token =>
|
||||
provideSignatureHelp(model, position, triggerContext, token));
|
||||
|
||||
return this.provideSignatureHelpRequest.then(result => {
|
||||
// Check that we are still resolving the correct signature help
|
||||
if (triggerId !== this.triggerId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!result || !result.signatures || result.signatures.length === 0) {
|
||||
this.cancel();
|
||||
return false;
|
||||
} else {
|
||||
this.state = new ParameterHintState.Active(result);
|
||||
this._onChangedHints.fire(this.state.hints);
|
||||
return true;
|
||||
}
|
||||
}).catch(error => {
|
||||
this.state = ParameterHintState.Default;
|
||||
onUnexpectedError(error);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
private get isTriggered(): boolean {
|
||||
return this.state.type === ParameterHintState.Type.Active
|
||||
|| this.state.type === ParameterHintState.Type.Pending
|
||||
|| this.throttledDelayer.isTriggered();
|
||||
}
|
||||
|
||||
private onModelChanged(): void {
|
||||
this.cancel();
|
||||
|
||||
// Update trigger characters
|
||||
this.triggerChars = new CharacterSet();
|
||||
this.retriggerChars = new CharacterSet();
|
||||
|
||||
const model = this.editor.getModel();
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const support of modes.SignatureHelpProviderRegistry.ordered(model)) {
|
||||
for (const ch of support.signatureHelpTriggerCharacters || []) {
|
||||
this.triggerChars.add(ch.charCodeAt(0));
|
||||
|
||||
// All trigger characters are also considered retrigger characters
|
||||
this.retriggerChars.add(ch.charCodeAt(0));
|
||||
}
|
||||
|
||||
for (const ch of support.signatureHelpRetriggerCharacters || []) {
|
||||
this.retriggerChars.add(ch.charCodeAt(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private onDidType(text: string) {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lastCharIndex = text.length - 1;
|
||||
const triggerCharCode = text.charCodeAt(lastCharIndex);
|
||||
|
||||
if (this.triggerChars.has(triggerCharCode) || this.isTriggered && this.retriggerChars.has(triggerCharCode)) {
|
||||
this.trigger({
|
||||
triggerKind: modes.SignatureHelpTriggerKind.TriggerCharacter,
|
||||
triggerCharacter: text.charAt(lastCharIndex),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private onCursorChange(e: ICursorSelectionChangedEvent): void {
|
||||
if (e.source === 'mouse') {
|
||||
this.cancel();
|
||||
} else if (this.isTriggered) {
|
||||
this.trigger({ triggerKind: modes.SignatureHelpTriggerKind.ContentChange });
|
||||
}
|
||||
}
|
||||
|
||||
private onModelContentChange(): void {
|
||||
if (this.isTriggered) {
|
||||
this.trigger({ triggerKind: modes.SignatureHelpTriggerKind.ContentChange });
|
||||
}
|
||||
}
|
||||
|
||||
private onEditorConfigurationChange(): void {
|
||||
this.enabled = this.editor.getConfiguration().contribInfo.parameterHints.enabled;
|
||||
|
||||
if (!this.enabled) {
|
||||
this.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.cancel(true);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user