mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-24 05:40:29 -04:00
Merge VS Code 1.31.1 (#4283)
This commit is contained in:
@@ -3,232 +3,28 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./parameterHints';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import * as aria from 'vs/base/browser/ui/aria/aria';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';
|
||||
import { createCancelablePromise, CancelablePromise, Delayer } from 'vs/base/common/async';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Event, Emitter, chain } from 'vs/base/common/event';
|
||||
import { domEvent, stop } from 'vs/base/browser/event';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { Context, provideSignatureHelp } from 'vs/editor/contrib/parameterHints/provideSignatureHelp';
|
||||
import * as aria from 'vs/base/browser/ui/aria/aria';
|
||||
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import { CharacterSet } from 'vs/editor/common/core/characterClassifier';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import 'vs/css!./parameterHints';
|
||||
import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';
|
||||
import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions';
|
||||
import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { registerThemingParticipant, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService';
|
||||
import { editorHoverBackground, editorHoverBorder, textLinkForeground, textCodeBlockBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { MarkdownRenderer } from 'vs/editor/contrib/markdown/markdownRenderer';
|
||||
import { Context } from 'vs/editor/contrib/parameterHints/provideSignatureHelp';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { editorHoverBackground, editorHoverBorder, textCodeBlockBackground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { HIGH_CONTRAST, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { ParameterHintsModel, TriggerContext } from 'vs/editor/contrib/parameterHints/parameterHintsModel';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
export interface TriggerContext {
|
||||
readonly triggerKind: modes.SignatureHelpTriggerKind;
|
||||
readonly triggerCharacter?: string;
|
||||
}
|
||||
|
||||
export interface IHintEvent {
|
||||
hints: modes.SignatureHelp;
|
||||
}
|
||||
|
||||
export class ParameterHintsModel extends Disposable {
|
||||
|
||||
private static readonly DEFAULT_DELAY = 120; // ms
|
||||
|
||||
private readonly _onHint = this._register(new Emitter<IHintEvent>());
|
||||
public readonly onHint: Event<IHintEvent> = this._onHint.event;
|
||||
|
||||
private readonly _onCancel = this._register(new Emitter<void>());
|
||||
public readonly onCancel: Event<void> = this._onCancel.event;
|
||||
|
||||
private editor: ICodeEditor;
|
||||
private enabled: boolean;
|
||||
private triggerCharactersListeners: IDisposable[];
|
||||
private active: boolean = false;
|
||||
private pending: boolean = false;
|
||||
private triggerChars = new CharacterSet();
|
||||
private retriggerChars = new CharacterSet();
|
||||
|
||||
private throttledDelayer: Delayer<boolean>;
|
||||
private provideSignatureHelpRequest?: CancelablePromise<modes.SignatureHelp | null | undefined>;
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
delay: number = ParameterHintsModel.DEFAULT_DELAY
|
||||
) {
|
||||
super();
|
||||
|
||||
this.editor = editor;
|
||||
this.enabled = false;
|
||||
this.triggerCharactersListeners = [];
|
||||
|
||||
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.active = false;
|
||||
this.pending = false;
|
||||
|
||||
this.throttledDelayer.cancel();
|
||||
|
||||
if (!silent) {
|
||||
this._onCancel.fire(void 0);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
this.throttledDelayer.trigger(
|
||||
() => this.doTrigger({
|
||||
triggerKind: context.triggerKind,
|
||||
triggerCharacter: context.triggerCharacter,
|
||||
isRetrigger: this.isTriggered,
|
||||
}), delay).then(undefined, onUnexpectedError);
|
||||
}
|
||||
|
||||
private doTrigger(triggerContext: modes.SignatureHelpContext): Promise<boolean> {
|
||||
this.cancel(true);
|
||||
|
||||
if (!this.editor.hasModel()) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
const model = this.editor.getModel();
|
||||
const position = this.editor.getPosition();
|
||||
|
||||
this.pending = true;
|
||||
|
||||
this.provideSignatureHelpRequest = createCancelablePromise(token =>
|
||||
provideSignatureHelp(model!, position!, triggerContext, token));
|
||||
|
||||
return this.provideSignatureHelpRequest.then(result => {
|
||||
this.pending = false;
|
||||
|
||||
if (!result || !result.signatures || 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;
|
||||
|
||||
}).catch(error => {
|
||||
this.pending = false;
|
||||
onUnexpectedError(error);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
private get isTriggered(): boolean {
|
||||
return this.active || this.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)) {
|
||||
if (Array.isArray(support.signatureHelpTriggerCharacters)) {
|
||||
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));
|
||||
|
||||
}
|
||||
}
|
||||
if (Array.isArray(support.signatureHelpRetriggerCharacters)) {
|
||||
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);
|
||||
this.triggerCharactersListeners = dispose(this.triggerCharactersListeners);
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class ParameterHintsWidget implements IContentWidget, IDisposable {
|
||||
|
||||
private static readonly ID = 'editor.widget.parameterHintsWidget';
|
||||
@@ -242,9 +38,7 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable {
|
||||
private signature: HTMLElement;
|
||||
private docs: HTMLElement;
|
||||
private overloads: HTMLElement;
|
||||
private currentSignature: number;
|
||||
private visible: boolean;
|
||||
private hints: modes.SignatureHelp | null;
|
||||
private announcedLabel: string | null;
|
||||
private scrollbar: DomScrollableElement;
|
||||
private disposables: IDisposable[];
|
||||
@@ -265,15 +59,13 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable {
|
||||
this.visible = false;
|
||||
this.disposables = [];
|
||||
|
||||
this.disposables.push(this.model.onHint(e => {
|
||||
this.show();
|
||||
this.hints = e.hints;
|
||||
this.currentSignature = e.hints.activeSignature;
|
||||
this.render();
|
||||
}));
|
||||
|
||||
this.disposables.push(this.model.onCancel(() => {
|
||||
this.hide();
|
||||
this.disposables.push(this.model.onChangedHints(newParameterHints => {
|
||||
if (newParameterHints) {
|
||||
this.show();
|
||||
this.render(newParameterHints);
|
||||
} else {
|
||||
this.hide();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -302,8 +94,6 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable {
|
||||
|
||||
this.docs = dom.append(body, $('.docs'));
|
||||
|
||||
this.currentSignature = 0;
|
||||
|
||||
this.editor.addContentWidget(this);
|
||||
this.hide();
|
||||
|
||||
@@ -321,7 +111,7 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable {
|
||||
|
||||
updateFont();
|
||||
|
||||
chain<IConfigurationChangedEvent>(this.editor.onDidChangeConfiguration.bind(this.editor))
|
||||
Event.chain<IConfigurationChangedEvent>(this.editor.onDidChangeConfiguration.bind(this.editor))
|
||||
.filter(e => e.fontInfo)
|
||||
.on(updateFont, null, this.disposables);
|
||||
|
||||
@@ -355,7 +145,6 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable {
|
||||
|
||||
this.keyVisible.reset();
|
||||
this.visible = false;
|
||||
this.hints = null;
|
||||
this.announcedLabel = null;
|
||||
dom.removeClass(this.element, 'visible');
|
||||
this.editor.layoutContentWidget(this);
|
||||
@@ -371,19 +160,15 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable {
|
||||
return null;
|
||||
}
|
||||
|
||||
private render(): void {
|
||||
if (!this.hints) {
|
||||
return;
|
||||
}
|
||||
|
||||
const multiple = this.hints.signatures.length > 1;
|
||||
private render(hints: modes.SignatureHelp): void {
|
||||
const multiple = hints.signatures.length > 1;
|
||||
dom.toggleClass(this.element, 'multiple', multiple);
|
||||
this.keyMultipleSignatures.set(multiple);
|
||||
|
||||
this.signature.innerHTML = '';
|
||||
this.docs.innerHTML = '';
|
||||
|
||||
const signature = this.hints.signatures[this.currentSignature];
|
||||
const signature = hints.signatures[hints.activeSignature];
|
||||
|
||||
if (!signature) {
|
||||
return;
|
||||
@@ -401,13 +186,13 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable {
|
||||
label.textContent = signature.label;
|
||||
|
||||
} else {
|
||||
this.renderParameters(code, signature, this.hints.activeParameter);
|
||||
this.renderParameters(code, signature, hints.activeParameter);
|
||||
}
|
||||
|
||||
dispose(this.renderDisposeables);
|
||||
this.renderDisposeables = [];
|
||||
|
||||
const activeParameter = signature.parameters[this.hints.activeParameter];
|
||||
const activeParameter = signature.parameters[hints.activeParameter];
|
||||
|
||||
if (activeParameter && activeParameter.documentation) {
|
||||
const documentation = $('span.documentation');
|
||||
@@ -434,16 +219,16 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable {
|
||||
dom.append(this.docs, renderedContents.element);
|
||||
}
|
||||
|
||||
let currentOverload = String(this.currentSignature + 1);
|
||||
let currentOverload = String(hints.activeSignature + 1);
|
||||
|
||||
if (this.hints.signatures.length < 10) {
|
||||
currentOverload += `/${this.hints.signatures.length}`;
|
||||
if (hints.signatures.length < 10) {
|
||||
currentOverload += `/${hints.signatures.length}`;
|
||||
}
|
||||
|
||||
this.overloads.textContent = currentOverload;
|
||||
|
||||
if (activeParameter) {
|
||||
const labelToAnnounce = this.getParameterLabel(signature, this.hints.activeParameter);
|
||||
const labelToAnnounce = this.getParameterLabel(signature, hints.activeParameter);
|
||||
// Select method gets called on every user type while parameter hints are visible.
|
||||
// We do not want to spam the user with same announcements, so we only announce if the current parameter changed.
|
||||
|
||||
@@ -459,16 +244,16 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable {
|
||||
|
||||
private renderParameters(parent: HTMLElement, signature: modes.SignatureInformation, currentParameter: number): void {
|
||||
|
||||
let [start, end] = this.getParameterLabelOffsets(signature, currentParameter);
|
||||
const [start, end] = this.getParameterLabelOffsets(signature, currentParameter);
|
||||
|
||||
let beforeSpan = document.createElement('span');
|
||||
const beforeSpan = document.createElement('span');
|
||||
beforeSpan.textContent = signature.label.substring(0, start);
|
||||
|
||||
let paramSpan = document.createElement('span');
|
||||
const paramSpan = document.createElement('span');
|
||||
paramSpan.textContent = signature.label.substring(start, end);
|
||||
paramSpan.className = 'parameter active';
|
||||
|
||||
let afterSpan = document.createElement('span');
|
||||
const afterSpan = document.createElement('span');
|
||||
afterSpan.textContent = signature.label.substring(end);
|
||||
|
||||
dom.append(parent, beforeSpan, paramSpan, afterSpan);
|
||||
@@ -497,85 +282,18 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
// private select(position: number): void {
|
||||
// const signature = this.signatureViews[position];
|
||||
|
||||
// if (!signature) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// this.signatures.style.height = `${ signature.height }px`;
|
||||
// this.signatures.scrollTop = signature.top;
|
||||
|
||||
// let overloads = '' + (position + 1);
|
||||
|
||||
// if (this.signatureViews.length < 10) {
|
||||
// overloads += '/' + this.signatureViews.length;
|
||||
// }
|
||||
|
||||
// this.overloads.textContent = overloads;
|
||||
|
||||
// if (this.hints && this.hints.signatures[position].parameters[this.hints.activeParameter]) {
|
||||
// const labelToAnnounce = this.hints.signatures[position].parameters[this.hints.activeParameter].label;
|
||||
// // Select method gets called on every user type while parameter hints are visible.
|
||||
// // We do not want to spam the user with same announcements, so we only announce if the current parameter changed.
|
||||
// if (this.announcedLabel !== labelToAnnounce) {
|
||||
// aria.alert(nls.localize('hint', "{0}, hint", labelToAnnounce));
|
||||
// this.announcedLabel = labelToAnnounce;
|
||||
// }
|
||||
// }
|
||||
|
||||
// this.editor.layoutContentWidget(this);
|
||||
// }
|
||||
|
||||
next(): boolean {
|
||||
if (!this.hints) {
|
||||
return false;
|
||||
next(): void {
|
||||
if (this.model) {
|
||||
this.editor.focus();
|
||||
this.model.next();
|
||||
}
|
||||
|
||||
const length = this.hints.signatures.length;
|
||||
const last = (this.currentSignature % 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 false;
|
||||
}
|
||||
|
||||
if (last && cycle) {
|
||||
this.currentSignature = 0;
|
||||
} else {
|
||||
this.currentSignature++;
|
||||
}
|
||||
|
||||
this.render();
|
||||
return true;
|
||||
}
|
||||
|
||||
previous(): boolean {
|
||||
if (!this.hints) {
|
||||
return false;
|
||||
previous(): void {
|
||||
if (this.model) {
|
||||
this.editor.focus();
|
||||
this.model.previous();
|
||||
}
|
||||
|
||||
const length = this.hints.signatures.length;
|
||||
const first = this.currentSignature === 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 false;
|
||||
}
|
||||
|
||||
if (first && cycle) {
|
||||
this.currentSignature = length - 1;
|
||||
} else {
|
||||
this.currentSignature--;
|
||||
}
|
||||
|
||||
this.render();
|
||||
return true;
|
||||
}
|
||||
|
||||
cancel(): void {
|
||||
@@ -617,11 +335,10 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable {
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
const border = theme.getColor(editorHoverBorder);
|
||||
if (border) {
|
||||
let borderWidth = theme.type === HIGH_CONTRAST ? 2 : 1;
|
||||
const borderWidth = theme.type === HIGH_CONTRAST ? 2 : 1;
|
||||
collector.addRule(`.monaco-editor .parameter-hints-widget { border: ${borderWidth}px solid ${border}; }`);
|
||||
collector.addRule(`.monaco-editor .parameter-hints-widget.multiple .body { border-left: 1px solid ${border.transparent(0.5)}; }`);
|
||||
collector.addRule(`.monaco-editor .parameter-hints-widget .signature.has-docs { border-bottom: 1px solid ${border.transparent(0.5)}; }`);
|
||||
|
||||
}
|
||||
const background = theme.getColor(editorHoverBackground);
|
||||
if (background) {
|
||||
|
||||
Reference in New Issue
Block a user