mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Merge from vscode a4177f50c475fc0fa278a78235e3bee9ffdec781 (#8649)
* Merge from vscode a4177f50c475fc0fa278a78235e3bee9ffdec781 * distro * fix tests
This commit is contained in:
@@ -15,6 +15,7 @@ import { cloneAndChange } from 'vs/base/common/objects';
|
||||
import { escape } from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { renderCodicons, markdownEscapeEscapedCodicons } from 'vs/base/common/codicons';
|
||||
|
||||
export interface MarkdownRenderOptions extends FormattedTextRenderOptions {
|
||||
codeBlockRenderer?: (modeId: string, value: string) => Promise<string>;
|
||||
@@ -118,7 +119,7 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
|
||||
}
|
||||
};
|
||||
renderer.paragraph = (text): string => {
|
||||
return `<p>${text}</p>`;
|
||||
return `<p>${markdown.supportThemeIcons ? renderCodicons(text) : text}</p>`;
|
||||
};
|
||||
|
||||
if (options.codeBlockRenderer) {
|
||||
@@ -192,7 +193,13 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
|
||||
allowedSchemes.push(Schemas.command);
|
||||
}
|
||||
|
||||
const renderedMarkdown = marked.parse(markdown.value, markedOptions);
|
||||
const renderedMarkdown = marked.parse(
|
||||
markdown.supportThemeIcons
|
||||
? markdownEscapeEscapedCodicons(markdown.value)
|
||||
: markdown.value,
|
||||
markedOptions
|
||||
);
|
||||
|
||||
element.innerHTML = insane(renderedMarkdown, {
|
||||
allowedSchemes,
|
||||
allowedAttributes: {
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 3.76345L5.80687 11.9351L5.08584 11.8927L1 7.29614L1.76345 6.61752L5.50997 10.8324L14.3214 3L15 3.76345Z" fill="#C5C5C5"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 278 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 3.76345L5.80687 11.9351L5.08584 11.8927L1 7.29614L1.76345 6.61752L5.50997 10.8324L14.3214 3L15 3.76345Z" fill="#424242"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 278 B |
@@ -44,10 +44,7 @@
|
||||
background-size: 16px !important;
|
||||
}
|
||||
|
||||
.monaco-custom-checkbox.monaco-simple-checkbox.checked {
|
||||
background: url('check-light.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-custom-checkbox.monaco-simple-checkbox.checked {
|
||||
background: url('check-dark.svg') center center no-repeat;
|
||||
/* hide check when unchecked */
|
||||
.monaco-custom-checkbox.monaco-simple-checkbox.unchecked:not(.checked)::before {
|
||||
visibility: hidden;;
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ export class SimpleCheckbox extends Widget {
|
||||
constructor(private title: string, private isChecked: boolean) {
|
||||
super();
|
||||
|
||||
this.checkbox = new Checkbox({ title: this.title, isChecked: this.isChecked, actionClassName: 'monaco-simple-checkbox' });
|
||||
this.checkbox = new Checkbox({ title: this.title, isChecked: this.isChecked, actionClassName: 'monaco-simple-checkbox codicon-check' });
|
||||
|
||||
this.domNode = this.checkbox.domNode;
|
||||
|
||||
|
||||
@@ -395,9 +395,9 @@
|
||||
.codicon-debug-breakpoint-function-unverified:before { content: "\eb87" }
|
||||
.codicon-debug-breakpoint-function:before { content: "\eb88" }
|
||||
.codicon-debug-breakpoint-function-disabled:before { content: "\eb88" }
|
||||
.codicon-debug-breakpoint-stackframe-active:before { content: "\eb89" }
|
||||
.codicon-debug-breakpoint-stackframe:before { content: "\eb8b" }
|
||||
.codicon-debug-breakpoint-stackframe-focused:before { content: "\eb8b" }
|
||||
.codicon-debug-stackframe-active:before { content: "\eb89" }
|
||||
.codicon-debug-stackframe:before { content: "\eb8b" }
|
||||
.codicon-debug-stackframe-focused:before { content: "\eb8b" }
|
||||
.codicon-debug-breakpoint-unsupported:before { content: "\eb8c" }
|
||||
.codicon-symbol-string:before { content: "\eb8d" }
|
||||
.codicon-debug-reverse-continue:before { content: "\eb8e" }
|
||||
|
||||
@@ -6,16 +6,7 @@
|
||||
import 'vs/css!./codicon/codicon';
|
||||
import 'vs/css!./codicon/codicon-animations';
|
||||
import { escape } from 'vs/base/common/strings';
|
||||
|
||||
function expand(text: string): string {
|
||||
return text.replace(/\$\((([a-z0-9\-]+?)(~([a-z0-9\-]*?))?)\)/gi, (_match, _g1, name, _g3, animation) => {
|
||||
return `<span class="codicon codicon-${name} ${animation ? `codicon-animation-${animation}` : ''}"></span>`;
|
||||
});
|
||||
}
|
||||
|
||||
export function renderCodicons(label: string): string {
|
||||
return expand(escape(label));
|
||||
}
|
||||
import { renderCodicons } from 'vs/base/common/codicons';
|
||||
|
||||
export class CodiconLabel {
|
||||
|
||||
@@ -24,7 +15,7 @@ export class CodiconLabel {
|
||||
) { }
|
||||
|
||||
set text(text: string) {
|
||||
this._container.innerHTML = renderCodicons(text || '');
|
||||
this._container.innerHTML = renderCodicons(escape(text ?? ''));
|
||||
}
|
||||
|
||||
set title(title: string) {
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
|
||||
.context-view {
|
||||
position: absolute;
|
||||
z-index: 2000;
|
||||
}
|
||||
z-index: 2500;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
max-width: 90%;
|
||||
min-height: 75px;
|
||||
padding: 10px;
|
||||
transform: translate3d(0px, 0px, 0px);
|
||||
}
|
||||
|
||||
/** Dialog: Title Actions Row */
|
||||
|
||||
@@ -46,6 +46,7 @@ interface ButtonMapEntry {
|
||||
|
||||
export class Dialog extends Disposable {
|
||||
private element: HTMLElement | undefined;
|
||||
private shadowElement: HTMLElement | undefined;
|
||||
private modal: HTMLElement | undefined;
|
||||
private buttonsContainer: HTMLElement | undefined;
|
||||
private messageDetailElement: HTMLElement | undefined;
|
||||
@@ -61,7 +62,8 @@ export class Dialog extends Disposable {
|
||||
constructor(private container: HTMLElement, private message: string, buttons: string[], private options: IDialogOptions) {
|
||||
super();
|
||||
this.modal = this.container.appendChild($(`.dialog-modal-block${options.type === 'pending' ? '.dimmed' : ''}`));
|
||||
this.element = this.modal.appendChild($('.dialog-box'));
|
||||
this.shadowElement = this.modal.appendChild($('.dialog-shadow'));
|
||||
this.element = this.shadowElement.appendChild($('.dialog-box'));
|
||||
hide(this.element);
|
||||
|
||||
// If no button is provided, default to OK
|
||||
@@ -249,10 +251,13 @@ export class Dialog extends Disposable {
|
||||
const shadowColor = style.dialogShadow ? `0 0px 8px ${style.dialogShadow}` : '';
|
||||
const border = style.dialogBorder ? `1px solid ${style.dialogBorder}` : '';
|
||||
|
||||
if (this.shadowElement) {
|
||||
this.shadowElement.style.boxShadow = shadowColor;
|
||||
}
|
||||
|
||||
if (this.element) {
|
||||
this.element.style.color = fgColor;
|
||||
this.element.style.backgroundColor = bgColor;
|
||||
this.element.style.boxShadow = shadowColor;
|
||||
this.element.style.border = border;
|
||||
|
||||
if (this.buttonGroup) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import { renderCodicons } from 'vs/base/browser/ui/codiconLabel/codiconLabel';
|
||||
import { renderCodicons } from 'vs/base/common/codicons';
|
||||
import { escape } from 'vs/base/common/strings';
|
||||
|
||||
export interface IHighlight {
|
||||
@@ -65,13 +65,13 @@ export class HighlightedLabel {
|
||||
if (pos < highlight.start) {
|
||||
htmlContent += '<span>';
|
||||
const substring = this.text.substring(pos, highlight.start);
|
||||
htmlContent += this.supportCodicons ? renderCodicons(substring) : escape(substring);
|
||||
htmlContent += this.supportCodicons ? renderCodicons(escape(substring)) : escape(substring);
|
||||
htmlContent += '</span>';
|
||||
pos = highlight.end;
|
||||
}
|
||||
htmlContent += '<span class="highlight">';
|
||||
const substring = this.text.substring(highlight.start, highlight.end);
|
||||
htmlContent += this.supportCodicons ? renderCodicons(substring) : escape(substring);
|
||||
htmlContent += this.supportCodicons ? renderCodicons(escape(substring)) : escape(substring);
|
||||
htmlContent += '</span>';
|
||||
pos = highlight.end;
|
||||
}
|
||||
@@ -79,7 +79,7 @@ export class HighlightedLabel {
|
||||
if (pos < this.text.length) {
|
||||
htmlContent += '<span>';
|
||||
const substring = this.text.substring(pos);
|
||||
htmlContent += this.supportCodicons ? renderCodicons(substring) : escape(substring);
|
||||
htmlContent += this.supportCodicons ? renderCodicons(escape(substring)) : escape(substring);
|
||||
htmlContent += '</span>';
|
||||
}
|
||||
|
||||
|
||||
@@ -593,7 +593,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
|
||||
const isSelected = this.element && hasClass(this.element, 'focused');
|
||||
const fgColor = isSelected && this.menuStyle.selectionForegroundColor ? this.menuStyle.selectionForegroundColor : this.menuStyle.foregroundColor;
|
||||
const bgColor = isSelected && this.menuStyle.selectionBackgroundColor ? this.menuStyle.selectionBackgroundColor : this.menuStyle.backgroundColor;
|
||||
const bgColor = isSelected && this.menuStyle.selectionBackgroundColor ? this.menuStyle.selectionBackgroundColor : undefined;
|
||||
const border = isSelected && this.menuStyle.selectionBorderColor ? `thin solid ${this.menuStyle.selectionBorderColor}` : '';
|
||||
|
||||
if (this.item) {
|
||||
|
||||
@@ -1298,7 +1298,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
|
||||
onDidModelSplice(() => null, null, this.disposables);
|
||||
|
||||
// Active nodes can change when the model changes or when focus or selection change.
|
||||
// We debouce it with 0 delay since these events may fire in the same stack and we only
|
||||
// We debounce it with 0 delay since these events may fire in the same stack and we only
|
||||
// want to run this once. It also doesn't matter if it runs on the next tick since it's only
|
||||
// a nice to have UI feature.
|
||||
onDidChangeActiveNodes.input = Event.chain(Event.any<any>(onDidModelSplice, this.focus.onDidChange, this.selection.onDidChange))
|
||||
|
||||
29
src/vs/base/common/codicons.ts
Normal file
29
src/vs/base/common/codicons.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
const escapeCodiconsRegex = /(?<!\\)\$\([a-z0-9\-]+?(?:~[a-z0-9\-]*?)?\)/gi;
|
||||
export function escapeCodicons(text: string): string {
|
||||
return text.replace(escapeCodiconsRegex, match => `\\${match}`);
|
||||
}
|
||||
|
||||
const markdownEscapedCodiconsRegex = /\\\$\([a-z0-9\-]+?(?:~[a-z0-9\-]*?)?\)/gi;
|
||||
export function markdownEscapeEscapedCodicons(text: string): string {
|
||||
// Need to add an extra \ for escaping in markdown
|
||||
return text.replace(markdownEscapedCodiconsRegex, match => `\\${match}`);
|
||||
}
|
||||
|
||||
const markdownUnescapeCodiconsRegex = /(?<!\\)\$\\\(([a-z0-9\-]+?(?:~[a-z0-9\-]*?)?)\\\)/gi;
|
||||
export function markdownUnescapeCodicons(text: string): string {
|
||||
return text.replace(markdownUnescapeCodiconsRegex, (_, codicon) => `$(${codicon})`);
|
||||
}
|
||||
|
||||
const renderCodiconsRegex = /(\\)?\$\((([a-z0-9\-]+?)(?:~([a-z0-9\-]*?))?)\)/gi;
|
||||
export function renderCodicons(text: string): string {
|
||||
return text.replace(renderCodiconsRegex, (_, escape, codicon, name, animation) => {
|
||||
return escape
|
||||
? `$(${codicon})`
|
||||
: `<span class="codicon codicon-${name}${animation ? ` codicon-animation-${animation}` : ''}"></span>`;
|
||||
});
|
||||
}
|
||||
@@ -84,11 +84,11 @@ export function memoize(target: any, key: string, descriptor: any) {
|
||||
return createMemoizer()(target, key, descriptor);
|
||||
}
|
||||
|
||||
export interface IDebouceReducer<T> {
|
||||
export interface IDebounceReducer<T> {
|
||||
(previousValue: T, ...args: any[]): T;
|
||||
}
|
||||
|
||||
export function debounce<T>(delay: number, reducer?: IDebouceReducer<T>, initialValueProvider?: () => T): Function {
|
||||
export function debounce<T>(delay: number, reducer?: IDebounceReducer<T>, initialValueProvider?: () => T): Function {
|
||||
return createDecorator((fn, key) => {
|
||||
const timerKey = `$debounce$${key}`;
|
||||
const resultKey = `$debounce$result$${key}`;
|
||||
@@ -112,3 +112,44 @@ export function debounce<T>(delay: number, reducer?: IDebouceReducer<T>, initial
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function throttle<T>(delay: number, reducer?: IDebounceReducer<T>, initialValueProvider?: () => T): Function {
|
||||
return createDecorator((fn, key) => {
|
||||
const timerKey = `$throttle$timer$${key}`;
|
||||
const resultKey = `$throttle$result$${key}`;
|
||||
const lastRunKey = `$throttle$lastRun$${key}`;
|
||||
const pendingKey = `$throttle$pending$${key}`;
|
||||
|
||||
return function (this: any, ...args: any[]) {
|
||||
if (!this[resultKey]) {
|
||||
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
|
||||
}
|
||||
if (this[lastRunKey] === null || this[lastRunKey] === undefined) {
|
||||
this[lastRunKey] = -Number.MAX_VALUE;
|
||||
}
|
||||
|
||||
if (reducer) {
|
||||
this[resultKey] = reducer(this[resultKey], ...args);
|
||||
}
|
||||
|
||||
if (this[pendingKey]) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nextTime = this[lastRunKey] + delay;
|
||||
if (nextTime <= Date.now()) {
|
||||
this[lastRunKey] = Date.now();
|
||||
fn.apply(this, [this[resultKey]]);
|
||||
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
|
||||
} else {
|
||||
this[pendingKey] = true;
|
||||
this[timerKey] = setTimeout(() => {
|
||||
this[pendingKey] = false;
|
||||
this[lastRunKey] = Date.now();
|
||||
fn.apply(this, [this[resultKey]]);
|
||||
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
|
||||
}, nextTime - Date.now());
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,15 +8,11 @@ import * as types from 'vs/base/common/types';
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
|
||||
function exceptionToErrorMessage(exception: any, verbose: boolean): string {
|
||||
if (exception.message) {
|
||||
if (verbose && (exception.stack || exception.stacktrace)) {
|
||||
return nls.localize('stackTrace.format', "{0}: {1}", detectSystemErrorMessage(exception), stackToString(exception.stack) || stackToString(exception.stacktrace));
|
||||
}
|
||||
|
||||
return detectSystemErrorMessage(exception);
|
||||
if (verbose && (exception.stack || exception.stacktrace)) {
|
||||
return nls.localize('stackTrace.format', "{0}: {1}", detectSystemErrorMessage(exception), stackToString(exception.stack) || stackToString(exception.stacktrace));
|
||||
}
|
||||
|
||||
return nls.localize('error.defaultMessage', "An unknown error occurred. Please consult the log for more details.");
|
||||
return detectSystemErrorMessage(exception);
|
||||
}
|
||||
|
||||
function stackToString(stack: string[] | string | undefined): string | undefined {
|
||||
@@ -34,7 +30,7 @@ function detectSystemErrorMessage(exception: any): string {
|
||||
return nls.localize('nodeExceptionMessage', "A system error occurred ({0})", exception.message);
|
||||
}
|
||||
|
||||
return exception.message;
|
||||
return exception.message || nls.localize('error.defaultMessage', "An unknown error occurred. Please consult the log for more details.");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,7 +31,7 @@ export class ErrorHandler {
|
||||
};
|
||||
}
|
||||
|
||||
public addListener(listener: ErrorListenerCallback): ErrorListenerUnbind {
|
||||
addListener(listener: ErrorListenerCallback): ErrorListenerUnbind {
|
||||
this.listeners.push(listener);
|
||||
|
||||
return () => {
|
||||
@@ -49,21 +49,21 @@ export class ErrorHandler {
|
||||
this.listeners.splice(this.listeners.indexOf(listener), 1);
|
||||
}
|
||||
|
||||
public setUnexpectedErrorHandler(newUnexpectedErrorHandler: (e: any) => void): void {
|
||||
setUnexpectedErrorHandler(newUnexpectedErrorHandler: (e: any) => void): void {
|
||||
this.unexpectedErrorHandler = newUnexpectedErrorHandler;
|
||||
}
|
||||
|
||||
public getUnexpectedErrorHandler(): (e: any) => void {
|
||||
getUnexpectedErrorHandler(): (e: any) => void {
|
||||
return this.unexpectedErrorHandler;
|
||||
}
|
||||
|
||||
public onUnexpectedError(e: any): void {
|
||||
onUnexpectedError(e: any): void {
|
||||
this.unexpectedErrorHandler(e);
|
||||
this.emit(e);
|
||||
}
|
||||
|
||||
// For external errors, we don't want the listeners to be called
|
||||
public onUnexpectedExternalError(e: any): void {
|
||||
onUnexpectedExternalError(e: any): void {
|
||||
this.unexpectedErrorHandler(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,37 +5,51 @@
|
||||
|
||||
import { equals } from 'vs/base/common/arrays';
|
||||
import { UriComponents } from 'vs/base/common/uri';
|
||||
import { escapeCodicons, markdownUnescapeCodicons } from 'vs/base/common/codicons';
|
||||
|
||||
export interface IMarkdownString {
|
||||
readonly value: string;
|
||||
readonly isTrusted?: boolean;
|
||||
readonly supportThemeIcons?: boolean;
|
||||
uris?: { [href: string]: UriComponents };
|
||||
}
|
||||
|
||||
export class MarkdownString implements IMarkdownString {
|
||||
private readonly _isTrusted: boolean;
|
||||
private readonly _supportThemeIcons: boolean;
|
||||
|
||||
private _value: string;
|
||||
private _isTrusted: boolean;
|
||||
constructor(
|
||||
private _value: string = '',
|
||||
isTrustedOrOptions: boolean | { isTrusted?: boolean, supportThemeIcons?: boolean } = false,
|
||||
) {
|
||||
if (typeof isTrustedOrOptions === 'boolean') {
|
||||
this._isTrusted = isTrustedOrOptions;
|
||||
this._supportThemeIcons = false;
|
||||
}
|
||||
else {
|
||||
this._isTrusted = isTrustedOrOptions.isTrusted ?? false;
|
||||
this._supportThemeIcons = isTrustedOrOptions.supportThemeIcons ?? false;
|
||||
}
|
||||
|
||||
constructor(value: string = '', isTrusted = false) {
|
||||
this._value = value;
|
||||
this._isTrusted = isTrusted;
|
||||
}
|
||||
|
||||
get value() { return this._value; }
|
||||
get isTrusted() { return this._isTrusted; }
|
||||
get supportThemeIcons() { return this._supportThemeIcons; }
|
||||
|
||||
appendText(value: string): MarkdownString {
|
||||
// escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
|
||||
this._value += value
|
||||
value = value
|
||||
.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&')
|
||||
.replace('\n', '\n\n');
|
||||
this._value += this.supportThemeIcons ? markdownUnescapeCodicons(value) : value;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
appendMarkdown(value: string): MarkdownString {
|
||||
this._value += value;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -47,6 +61,10 @@ export class MarkdownString implements IMarkdownString {
|
||||
this._value += '\n```\n';
|
||||
return this;
|
||||
}
|
||||
|
||||
static escapeThemeIcons(value: string): string {
|
||||
return escapeCodicons(value);
|
||||
}
|
||||
}
|
||||
|
||||
export function isEmptyMarkdownString(oneOrMany: IMarkdownString | IMarkdownString[] | null | undefined): boolean {
|
||||
@@ -64,7 +82,8 @@ export function isMarkdownString(thing: any): thing is IMarkdownString {
|
||||
return true;
|
||||
} else if (thing && typeof thing === 'object') {
|
||||
return typeof (<IMarkdownString>thing).value === 'string'
|
||||
&& (typeof (<IMarkdownString>thing).isTrusted === 'boolean' || (<IMarkdownString>thing).isTrusted === undefined);
|
||||
&& (typeof (<IMarkdownString>thing).isTrusted === 'boolean' || (<IMarkdownString>thing).isTrusted === undefined)
|
||||
&& (typeof (<IMarkdownString>thing).supportThemeIcons === 'boolean' || (<IMarkdownString>thing).supportThemeIcons === undefined);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -89,7 +108,7 @@ function markdownStringEqual(a: IMarkdownString, b: IMarkdownString): boolean {
|
||||
} else if (!a || !b) {
|
||||
return false;
|
||||
} else {
|
||||
return a.value === b.value && a.isTrusted === b.isTrusted;
|
||||
return a.value === b.value && a.isTrusted === b.isTrusted && a.supportThemeIcons === b.supportThemeIcons;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ export class Client implements IChannelClient, IDisposable {
|
||||
this.child.on('error', err => console.warn('IPC "' + this.options.serverName + '" errored with ' + err));
|
||||
|
||||
this.child.on('exit', (code: any, signal: any) => {
|
||||
process.removeListener('exit', onExit);
|
||||
process.removeListener('exit' as 'loaded', onExit); // https://github.com/electron/electron/issues/21475
|
||||
|
||||
this.activeRequests.forEach(r => dispose(r));
|
||||
this.activeRequests.clear();
|
||||
|
||||
@@ -6,42 +6,104 @@
|
||||
import * as assert from 'assert';
|
||||
import * as marked from 'vs/base/common/marked/marked';
|
||||
import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
suite('MarkdownRenderer', () => {
|
||||
test('image rendering conforms to default', () => {
|
||||
const markdown = { value: `` };
|
||||
const result: HTMLElement = renderMarkdown(markdown);
|
||||
const renderer = new marked.Renderer();
|
||||
const imageFromMarked = marked(markdown.value, {
|
||||
sanitize: true,
|
||||
renderer
|
||||
}).trim();
|
||||
assert.strictEqual(result.innerHTML, imageFromMarked);
|
||||
suite('Images', () => {
|
||||
|
||||
test('image rendering conforms to default', () => {
|
||||
const markdown = { value: `` };
|
||||
const result: HTMLElement = renderMarkdown(markdown);
|
||||
const renderer = new marked.Renderer();
|
||||
const imageFromMarked = marked(markdown.value, {
|
||||
sanitize: true,
|
||||
renderer
|
||||
}).trim();
|
||||
assert.strictEqual(result.innerHTML, imageFromMarked);
|
||||
});
|
||||
|
||||
test('image rendering conforms to default without title', () => {
|
||||
const markdown = { value: `` };
|
||||
const result: HTMLElement = renderMarkdown(markdown);
|
||||
const renderer = new marked.Renderer();
|
||||
const imageFromMarked = marked(markdown.value, {
|
||||
sanitize: true,
|
||||
renderer
|
||||
}).trim();
|
||||
assert.strictEqual(result.innerHTML, imageFromMarked);
|
||||
});
|
||||
|
||||
test('image width from title params', () => {
|
||||
let result: HTMLElement = renderMarkdown({ value: `` });
|
||||
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" width="100"></p>`);
|
||||
});
|
||||
|
||||
test('image height from title params', () => {
|
||||
let result: HTMLElement = renderMarkdown({ value: `` });
|
||||
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" height="100"></p>`);
|
||||
});
|
||||
|
||||
test('image width and height from title params', () => {
|
||||
let result: HTMLElement = renderMarkdown({ value: `` });
|
||||
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" width="100" height="200"></p>`);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
test('image rendering conforms to default without title', () => {
|
||||
const markdown = { value: `` };
|
||||
const result: HTMLElement = renderMarkdown(markdown);
|
||||
const renderer = new marked.Renderer();
|
||||
const imageFromMarked = marked(markdown.value, {
|
||||
sanitize: true,
|
||||
renderer
|
||||
}).trim();
|
||||
assert.strictEqual(result.innerHTML, imageFromMarked);
|
||||
suite('ThemeIcons Support On', () => {
|
||||
|
||||
test('render appendText', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: true });
|
||||
mds.appendText('$(zap) $(dont match me)');
|
||||
|
||||
let result: HTMLElement = renderMarkdown(mds);
|
||||
assert.strictEqual(result.innerHTML, `<p><span class="codicon codicon-zap"></span> $(dont match me)</p>`);
|
||||
});
|
||||
|
||||
test('render appendText escaped', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: true });
|
||||
mds.appendText(MarkdownString.escapeThemeIcons('$(zap) $(dont match me)'));
|
||||
|
||||
let result: HTMLElement = renderMarkdown(mds);
|
||||
assert.strictEqual(result.innerHTML, `<p>$(zap) $(dont match me)</p>`);
|
||||
});
|
||||
|
||||
test('render appendMarkdown', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: true });
|
||||
mds.appendMarkdown('$(zap) $(dont match me)');
|
||||
|
||||
let result: HTMLElement = renderMarkdown(mds);
|
||||
assert.strictEqual(result.innerHTML, `<p><span class="codicon codicon-zap"></span> $(dont match me)</p>`);
|
||||
});
|
||||
|
||||
test('render appendMarkdown escaped', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: true });
|
||||
mds.appendMarkdown(MarkdownString.escapeThemeIcons('$(zap) $(dont match me)'));
|
||||
|
||||
let result: HTMLElement = renderMarkdown(mds);
|
||||
assert.strictEqual(result.innerHTML, `<p>$(zap) $(dont match me)</p>`);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
test('image width from title params', () => {
|
||||
let result: HTMLElement = renderMarkdown({ value: `` });
|
||||
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" width="100"></p>`);
|
||||
suite('ThemeIcons Support Off', () => {
|
||||
|
||||
test('render appendText', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: false });
|
||||
mds.appendText('$(zap) $(dont match me)');
|
||||
|
||||
let result: HTMLElement = renderMarkdown(mds);
|
||||
assert.strictEqual(result.innerHTML, `<p>$(zap) $(dont match me)</p>`);
|
||||
});
|
||||
|
||||
test('render appendMarkdown', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: false });
|
||||
mds.appendMarkdown('$(zap) $(dont match me)');
|
||||
|
||||
let result: HTMLElement = renderMarkdown(mds);
|
||||
assert.strictEqual(result.innerHTML, `<p>$(zap) $(dont match me)</p>`);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
test('image height from title params', () => {
|
||||
let result: HTMLElement = renderMarkdown({ value: `` });
|
||||
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" height="100"></p>`);
|
||||
});
|
||||
|
||||
test('image width and height from title params', () => {
|
||||
let result: HTMLElement = renderMarkdown({ value: `` });
|
||||
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" width="100" height="200"></p>`);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as sinon from 'sinon';
|
||||
import * as assert from 'assert';
|
||||
import { memoize, createMemoizer } from 'vs/base/common/decorators';
|
||||
import { memoize, createMemoizer, throttle } from 'vs/base/common/decorators';
|
||||
|
||||
suite('Decorators', () => {
|
||||
test('memoize should memoize methods', () => {
|
||||
@@ -100,7 +101,9 @@ suite('Decorators', () => {
|
||||
test('memoized property should not be enumerable', () => {
|
||||
class Foo {
|
||||
@memoize
|
||||
get answer() { return 42; }
|
||||
get answer() {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
|
||||
const foo = new Foo();
|
||||
@@ -112,7 +115,9 @@ suite('Decorators', () => {
|
||||
test('memoized property should not be writable', () => {
|
||||
class Foo {
|
||||
@memoize
|
||||
get answer() { return 42; }
|
||||
get answer() {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
|
||||
const foo = new Foo();
|
||||
@@ -131,7 +136,9 @@ suite('Decorators', () => {
|
||||
let counter = 0;
|
||||
class Foo {
|
||||
@memoizer
|
||||
get answer() { return ++counter; }
|
||||
get answer() {
|
||||
return ++counter;
|
||||
}
|
||||
}
|
||||
|
||||
const foo = new Foo();
|
||||
@@ -145,4 +152,49 @@ suite('Decorators', () => {
|
||||
assert.equal(foo.answer, 3);
|
||||
assert.equal(foo.answer, 3);
|
||||
});
|
||||
|
||||
test('throttle', () => {
|
||||
const spy = sinon.spy();
|
||||
const clock = sinon.useFakeTimers();
|
||||
try {
|
||||
class ThrottleTest {
|
||||
private _handle: Function;
|
||||
|
||||
constructor(fn: Function) {
|
||||
this._handle = fn;
|
||||
}
|
||||
|
||||
@throttle(
|
||||
100,
|
||||
(a: number, b: number) => a + b,
|
||||
() => 0
|
||||
)
|
||||
report(p: number): void {
|
||||
this._handle(p);
|
||||
}
|
||||
}
|
||||
|
||||
const t = new ThrottleTest(spy);
|
||||
|
||||
t.report(1);
|
||||
t.report(2);
|
||||
t.report(3);
|
||||
assert.deepEqual(spy.args, [[1]]);
|
||||
|
||||
clock.tick(200);
|
||||
assert.deepEqual(spy.args, [[1], [5]]);
|
||||
spy.reset();
|
||||
|
||||
t.report(4);
|
||||
t.report(5);
|
||||
clock.tick(50);
|
||||
t.report(6);
|
||||
|
||||
assert.deepEqual(spy.args, [[4]]);
|
||||
clock.tick(60);
|
||||
assert.deepEqual(spy.args, [[4], [11]]);
|
||||
} finally {
|
||||
clock.restore();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
|
||||
@@ -16,9 +17,17 @@ suite('Errors', () => {
|
||||
error.detail.exception = {};
|
||||
error.detail.exception.message = 'Foo Bar';
|
||||
assert.strictEqual(toErrorMessage(error), 'Foo Bar');
|
||||
assert.strictEqual(toErrorMessage(error, true), 'Foo Bar');
|
||||
|
||||
assert(toErrorMessage());
|
||||
assert(toErrorMessage(null));
|
||||
assert(toErrorMessage({}));
|
||||
|
||||
try {
|
||||
throw new Error();
|
||||
} catch (error) {
|
||||
assert.strictEqual(toErrorMessage(error), 'An unknown error occurred. Please consult the log for more details.');
|
||||
assert.ok(toErrorMessage(error, true).length > 'An unknown error occurred. Please consult the log for more details.'.length);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -43,4 +43,14 @@ suite('Hash', () => {
|
||||
assert.notEqual(hash({ 'foo': 'bar' }), hash({ 'foo': 'bar2' }));
|
||||
assert.notEqual(hash({}), hash([]));
|
||||
});
|
||||
});
|
||||
|
||||
test('array - unexpected collision', function () {
|
||||
this.skip();
|
||||
const a = hash([undefined, undefined, undefined, undefined, undefined]);
|
||||
const b = hash([undefined, undefined, 'HHHHHH', [{ line: 0, character: 0 }, { line: 0, character: 0 }], undefined]);
|
||||
// console.log(a);
|
||||
// console.log(b);
|
||||
assert.notEqual(a, b);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as assert from 'assert';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
suite('markdownString', () => {
|
||||
suite('MarkdownString', () => {
|
||||
|
||||
test('escape', () => {
|
||||
|
||||
@@ -16,4 +16,63 @@ suite('markdownString', () => {
|
||||
|
||||
assert.equal(mds.value, '\\# foo\n\n\\*bar\\*');
|
||||
});
|
||||
|
||||
suite('ThemeIcons', () => {
|
||||
|
||||
test('escapeThemeIcons', () => {
|
||||
assert.equal(
|
||||
MarkdownString.escapeThemeIcons('$(zap) $(not an icon) foo$(bar)'),
|
||||
'\\$(zap) $(not an icon) foo\\$(bar)'
|
||||
);
|
||||
});
|
||||
|
||||
suite('Support On', () => {
|
||||
|
||||
test('appendText', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: true });
|
||||
mds.appendText('$(zap)');
|
||||
|
||||
assert.equal(mds.value, '$(zap)');
|
||||
});
|
||||
|
||||
test('appendText escaped', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: true });
|
||||
mds.appendText(MarkdownString.escapeThemeIcons('$(zap)'));
|
||||
|
||||
assert.equal(mds.value, '\\\\$\\(zap\\)');
|
||||
});
|
||||
|
||||
test('appendMarkdown', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: true });
|
||||
mds.appendMarkdown('$(zap)');
|
||||
|
||||
assert.equal(mds.value, '$(zap)');
|
||||
});
|
||||
|
||||
test('appendMarkdown escaped', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: true });
|
||||
mds.appendMarkdown(MarkdownString.escapeThemeIcons('$(zap)'));
|
||||
|
||||
assert.equal(mds.value, '\\$(zap)');
|
||||
});
|
||||
});
|
||||
|
||||
suite('Support Off', () => {
|
||||
|
||||
test('appendText', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: false });
|
||||
mds.appendText('$(zap)');
|
||||
|
||||
assert.equal(mds.value, '$\\(zap\\)');
|
||||
});
|
||||
|
||||
test('appendMarkdown', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: false });
|
||||
mds.appendMarkdown('$(zap)');
|
||||
|
||||
assert.equal(mds.value, '$(zap)');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user