Merge VS Code 1.31.1 (#4283)

This commit is contained in:
Matt Irvine
2019-03-15 13:09:45 -07:00
committed by GitHub
parent 7d31575149
commit 86bac90001
1716 changed files with 53308 additions and 48375 deletions

View File

@@ -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) {