Initial VS Code 1.19 source merge (#571)

* Initial 1.19 xcopy

* Fix yarn build

* Fix numerous build breaks

* Next batch of build break fixes

* More build break fixes

* Runtime breaks

* Additional post merge fixes

* Fix windows setup file

* Fix test failures.

* Update license header blocks to refer to source eula
This commit is contained in:
Karl Burtram
2018-01-28 23:37:17 -08:00
committed by GitHub
parent 9a1ac20710
commit 251ae01c3e
8009 changed files with 93378 additions and 35634 deletions

View File

@@ -0,0 +1,528 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'vs/css!./parameterHints';
import nls = require('vs/nls');
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, SignatureHelpProviderRegistry } from 'vs/editor/common/modes';
import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';
import { RunOnceScheduler } 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 { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { CharacterSet } from 'vs/editor/common/core/characterClassifier';
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 { IModeService } from 'vs/editor/common/services/modeService';
import { MarkdownRenderer } from 'vs/editor/contrib/markdown/markdownRenderer';
const $ = dom.$;
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: ICodeEditor;
private enabled: boolean;
private triggerCharactersListeners: IDisposable[];
private active: boolean;
private throttledDelayer: RunOnceScheduler;
constructor(editor: ICodeEditor) {
super();
this.editor = editor;
this.enabled = false;
this.triggerCharactersListeners = [];
this.throttledDelayer = new RunOnceScheduler(() => this.doTrigger(), ParameterHintsModel.DELAY);
this.active = false;
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(SignatureHelpProviderRegistry.onDidChange(this.onModelChanged, this));
this.onEditorConfigurationChange();
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(null, onUnexpectedError)
.then(result => {
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;
});
}
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 triggerChars = new CharacterSet();
for (const support of SignatureHelpProviderRegistry.ordered(model)) {
if (Array.isArray(support.signatureHelpTriggerCharacters)) {
for (const ch of support.signatureHelpTriggerCharacters) {
triggerChars.add(ch.charCodeAt(0));
}
}
}
this.triggerCharactersListeners.push(this.editor.onDidType((text: string) => {
if (!this.enabled) {
return;
}
if (triggerChars.has(text.charCodeAt(text.length - 1))) {
this.trigger();
}
}));
}
private onCursorChange(e: ICursorSelectionChangedEvent): void {
if (e.source === 'mouse') {
this.cancel();
} else if (this.isTriggered()) {
this.trigger();
}
}
private onEditorConfigurationChange(): void {
this.enabled = this.editor.getConfiguration().contribInfo.parameterHints;
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';
private markdownRenderer: MarkdownRenderer;
private model: ParameterHintsModel;
private keyVisible: IContextKey<boolean>;
private keyMultipleSignatures: IContextKey<boolean>;
private element: HTMLElement;
private signature: HTMLElement;
private docs: HTMLElement;
private overloads: HTMLElement;
private currentSignature: number;
private visible: boolean;
private hints: SignatureHelp;
private announcedLabel: string;
private scrollbar: DomScrollableElement;
private disposables: IDisposable[];
// Editor.IContentWidget.allowEditorOverflow
allowEditorOverflow = true;
constructor(
private editor: ICodeEditor,
@IContextKeyService contextKeyService: IContextKeyService,
@IOpenerService openerService: IOpenerService,
@IModeService modeService: IModeService,
) {
this.markdownRenderer = new MarkdownRenderer(editor, modeService, openerService);
this.model = new ParameterHintsModel(editor);
this.keyVisible = Context.Visible.bindTo(contextKeyService);
this.keyMultipleSignatures = Context.MultipleSignatures.bindTo(contextKeyService);
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();
}));
}
private createParamaterHintDOMNodes() {
this.element = $('.editor-widget.parameter-hints-widget');
const wrapper = dom.append(this.element, $('.wrapper'));
const buttons = dom.append(wrapper, $('.buttons'));
const previous = dom.append(buttons, $('.button.previous'));
const next = dom.append(buttons, $('.button.next'));
const onPreviousClick = stop(domEvent(previous, 'click'));
onPreviousClick(this.previous, this, this.disposables);
const onNextClick = stop(domEvent(next, 'click'));
onNextClick(this.next, this, this.disposables);
this.overloads = dom.append(wrapper, $('.overloads'));
const body = $('.body');
this.scrollbar = new DomScrollableElement(body, {});
this.disposables.push(this.scrollbar);
wrapper.appendChild(this.scrollbar.getDomNode());
this.signature = dom.append(body, $('.signature'));
this.docs = dom.append(body, $('.docs'));
this.currentSignature = 0;
this.editor.addContentWidget(this);
this.hide();
this.disposables.push(this.editor.onDidChangeCursorSelection(e => {
if (this.visible) {
this.editor.layoutContentWidget(this);
}
}));
const updateFont = () => {
const fontInfo = this.editor.getConfiguration().fontInfo;
this.element.style.fontSize = `${fontInfo.fontSize}px`;
};
updateFont();
chain<IConfigurationChangedEvent>(this.editor.onDidChangeConfiguration.bind(this.editor))
.filter(e => e.fontInfo)
.on(updateFont, null, this.disposables);
this.disposables.push(this.editor.onDidLayoutChange(e => this.updateMaxHeight()));
this.updateMaxHeight();
}
private show(): void {
if (!this.model || this.visible) {
return;
}
if (!this.element) {
this.createParamaterHintDOMNodes();
}
this.keyVisible.set(true);
this.visible = true;
TPromise.timeout(100).done(() => dom.addClass(this.element, 'visible'));
this.editor.layoutContentWidget(this);
}
private hide(): void {
if (!this.model || !this.visible) {
return;
}
if (!this.element) {
this.createParamaterHintDOMNodes();
}
this.keyVisible.reset();
this.visible = false;
this.hints = null;
this.announcedLabel = null;
dom.removeClass(this.element, 'visible');
this.editor.layoutContentWidget(this);
}
getPosition(): IContentWidgetPosition {
if (this.visible) {
return {
position: this.editor.getPosition(),
preference: [ContentWidgetPositionPreference.ABOVE, ContentWidgetPositionPreference.BELOW]
};
}
return null;
}
private render(): void {
const multiple = this.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];
if (!signature) {
return;
}
const code = dom.append(this.signature, $('.code'));
const hasParameters = signature.parameters.length > 0;
const fontInfo = this.editor.getConfiguration().fontInfo;
code.style.fontSize = `${fontInfo.fontSize}px`;
code.style.fontFamily = fontInfo.fontFamily;
if (!hasParameters) {
const label = dom.append(code, $('span'));
label.textContent = signature.label;
} else {
this.renderParameters(code, signature, this.hints.activeParameter);
}
const activeParameter = signature.parameters[this.hints.activeParameter];
if (activeParameter && activeParameter.documentation) {
const documentation = $('span.documentation');
if (typeof activeParameter.documentation === 'string') {
dom.removeClass(this.docs, 'markdown-docs');
documentation.textContent = activeParameter.documentation;
} else {
dom.addClass(this.docs, 'markdown-docs');
documentation.appendChild(this.markdownRenderer.render(activeParameter.documentation));
}
dom.append(this.docs, $('p', null, documentation));
}
dom.toggleClass(this.signature, 'has-docs', !!signature.documentation);
if (typeof signature.documentation === 'string') {
dom.append(this.docs, $('p', null, signature.documentation));
} else {
dom.append(this.docs, this.markdownRenderer.render(signature.documentation));
}
let currentOverload = String(this.currentSignature + 1);
if (this.hints.signatures.length < 10) {
currentOverload += `/${this.hints.signatures.length}`;
}
this.overloads.textContent = currentOverload;
if (activeParameter) {
const labelToAnnounce = 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);
this.scrollbar.scanDomNode();
}
private renderParameters(parent: HTMLElement, signature: SignatureInformation, currentParameter: number): void {
let end = signature.label.length;
let idx = 0;
let element: HTMLSpanElement;
for (let i = signature.parameters.length - 1; i >= 0; i--) {
const parameter = signature.parameters[i];
idx = signature.label.lastIndexOf(parameter.label, end - 1);
let signatureLabelOffset = 0;
let signatureLabelEnd = 0;
if (idx >= 0) {
signatureLabelOffset = idx;
signatureLabelEnd = idx + parameter.label.length;
}
// non parameter part
element = document.createElement('span');
element.textContent = signature.label.substring(signatureLabelEnd, end);
dom.prepend(parent, element);
// parameter part
element = document.createElement('span');
element.className = `parameter ${i === currentParameter ? 'active' : ''}`;
element.textContent = signature.label.substring(signatureLabelOffset, signatureLabelEnd);
dom.prepend(parent, element);
end = signatureLabelOffset;
}
// non parameter part
element = document.createElement('span');
element.textContent = signature.label.substring(0, end);
dom.prepend(parent, element);
}
// 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 {
const length = this.hints.signatures.length;
if (length < 2) {
this.cancel();
return false;
}
this.currentSignature = (this.currentSignature + 1) % length;
this.render();
return true;
}
previous(): boolean {
const length = this.hints.signatures.length;
if (length < 2) {
this.cancel();
return false;
}
this.currentSignature = (this.currentSignature - 1 + length) % length;
this.render();
return true;
}
cancel(): void {
this.model.cancel();
}
getDomNode(): HTMLElement {
return this.element;
}
getId(): string {
return ParameterHintsWidget.ID;
}
trigger(): void {
this.model.trigger(0);
}
private updateMaxHeight(): void {
const height = Math.max(this.editor.getLayoutInfo().height / 4, 250);
this.element.style.maxHeight = `${height}px`;
}
dispose(): void {
this.disposables = dispose(this.disposables);
this.model = null;
}
}
registerThemingParticipant((theme, collector) => {
let border = theme.getColor(editorHoverBorder);
if (border) {
let 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)}; }`);
}
let background = theme.getColor(editorHoverBackground);
if (background) {
collector.addRule(`.monaco-editor .parameter-hints-widget { background-color: ${background}; }`);
}
const link = theme.getColor(textLinkForeground);
if (link) {
collector.addRule(`.monaco-editor .parameter-hints-widget a { color: ${link}; }`);
}
let codeBackground = theme.getColor(textCodeBlockBackground);
if (codeBackground) {
collector.addRule(`.monaco-editor .parameter-hints-widget code { background-color: ${codeBackground}; }`);
}
});