mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-11 18:48:33 -05:00
Merge VS Code 1.31.1 (#4283)
This commit is contained in:
@@ -20,11 +20,11 @@ export interface IAction extends IDisposable {
|
||||
enabled: boolean;
|
||||
checked: boolean;
|
||||
radio: boolean;
|
||||
run(event?: any): Thenable<any>;
|
||||
run(event?: any): Promise<any>;
|
||||
}
|
||||
|
||||
export interface IActionRunner extends IDisposable {
|
||||
run(action: IAction, context?: any): Thenable<any>;
|
||||
run(action: IAction, context?: any): Promise<any>;
|
||||
onDidRun: Event<IRunEvent>;
|
||||
onDidBeforeRun: Event<IRunEvent>;
|
||||
}
|
||||
@@ -60,9 +60,9 @@ export class Action implements IAction {
|
||||
protected _enabled: boolean;
|
||||
protected _checked: boolean;
|
||||
protected _radio: boolean;
|
||||
protected _actionCallback?: (event?: any) => Thenable<any>;
|
||||
protected _actionCallback?: (event?: any) => Promise<any>;
|
||||
|
||||
constructor(id: string, label: string = '', cssClass: string = '', enabled: boolean = true, actionCallback?: (event?: any) => Thenable<any>) {
|
||||
constructor(id: string, label: string = '', cssClass: string = '', enabled: boolean = true, actionCallback?: (event?: any) => Promise<any>) {
|
||||
this._id = id;
|
||||
this._label = label;
|
||||
this._cssClass = cssClass;
|
||||
@@ -164,7 +164,7 @@ export class Action implements IAction {
|
||||
}
|
||||
}
|
||||
|
||||
run(event?: any, _data?: ITelemetryData): Thenable<any> {
|
||||
run(event?: any, _data?: ITelemetryData): Promise<any> {
|
||||
if (this._actionCallback) {
|
||||
return this._actionCallback(event);
|
||||
}
|
||||
@@ -191,7 +191,7 @@ export class ActionRunner extends Disposable implements IActionRunner {
|
||||
private _onDidRun = this._register(new Emitter<IRunEvent>());
|
||||
readonly onDidRun: Event<IRunEvent> = this._onDidRun.event;
|
||||
|
||||
run(action: IAction, context?: any): Thenable<any> {
|
||||
run(action: IAction, context?: any): Promise<any> {
|
||||
if (!action.enabled) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
@@ -205,7 +205,7 @@ export class ActionRunner extends Disposable implements IActionRunner {
|
||||
});
|
||||
}
|
||||
|
||||
protected runAction(action: IAction, context?: any): Thenable<any> {
|
||||
protected runAction(action: IAction, context?: any): Promise<any> {
|
||||
const res = context ? action.run(context) : action.run();
|
||||
return Promise.resolve(res);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export function equals<T>(one: ReadonlyArray<T> | undefined, other: ReadonlyArra
|
||||
return true;
|
||||
}
|
||||
|
||||
export function binarySearch<T>(array: T[], key: T, comparator: (op1: T, op2: T) => number): number {
|
||||
export function binarySearch<T>(array: ReadonlyArray<T>, key: T, comparator: (op1: T, op2: T) => number): number {
|
||||
let low = 0,
|
||||
high = array.length - 1;
|
||||
|
||||
@@ -69,7 +69,7 @@ export function binarySearch<T>(array: T[], key: T, comparator: (op1: T, op2: T)
|
||||
* are located before all elements where p(x) is true.
|
||||
* @returns the least x for which p(x) is true or array.length if no element fullfills the given function.
|
||||
*/
|
||||
export function findFirstInSorted<T>(array: T[], p: (x: T) => boolean): number {
|
||||
export function findFirstInSorted<T>(array: ReadonlyArray<T>, p: (x: T) => boolean): number {
|
||||
let low = 0, high = array.length;
|
||||
if (high === 0) {
|
||||
return 0; // no children
|
||||
@@ -135,7 +135,7 @@ function _sort<T>(a: T[], compare: Compare<T>, lo: number, hi: number, aux: T[])
|
||||
}
|
||||
|
||||
|
||||
export function groupBy<T>(data: T[], compare: (a: T, b: T) => number): T[][] {
|
||||
export function groupBy<T>(data: ReadonlyArray<T>, compare: (a: T, b: T) => number): T[][] {
|
||||
const result: T[][] = [];
|
||||
let currentGroup: T[] | undefined = undefined;
|
||||
for (const element of mergeSort(data.slice(0), compare)) {
|
||||
@@ -156,7 +156,7 @@ interface IMutableSplice<T> extends ISplice<T> {
|
||||
/**
|
||||
* Diffs two *sorted* arrays and computes the splices which apply the diff.
|
||||
*/
|
||||
export function sortedDiff<T>(before: T[], after: T[], compare: (a: T, b: T) => number): ISplice<T>[] {
|
||||
export function sortedDiff<T>(before: ReadonlyArray<T>, after: ReadonlyArray<T>, compare: (a: T, b: T) => number): ISplice<T>[] {
|
||||
const result: IMutableSplice<T>[] = [];
|
||||
|
||||
function pushSplice(start: number, deleteCount: number, toInsert: T[]): void {
|
||||
@@ -211,11 +211,8 @@ export function sortedDiff<T>(before: T[], after: T[], compare: (a: T, b: T) =>
|
||||
/**
|
||||
* Takes two *sorted* arrays and computes their delta (removed, added elements).
|
||||
* Finishes in `Math.min(before.length, after.length)` steps.
|
||||
* @param before
|
||||
* @param after
|
||||
* @param compare
|
||||
*/
|
||||
export function delta<T>(before: T[], after: T[], compare: (a: T, b: T) => number): { removed: T[], added: T[] } {
|
||||
export function delta<T>(before: ReadonlyArray<T>, after: ReadonlyArray<T>, compare: (a: T, b: T) => number): { removed: T[], added: T[] } {
|
||||
const splices = sortedDiff(before, after, compare);
|
||||
const removed: T[] = [];
|
||||
const added: T[] = [];
|
||||
@@ -238,7 +235,7 @@ export function delta<T>(before: T[], after: T[], compare: (a: T, b: T) => numbe
|
||||
* @param n The number of elements to return.
|
||||
* @return The first n elemnts from array when sorted with compare.
|
||||
*/
|
||||
export function top<T>(array: T[], compare: (a: T, b: T) => number, n: number): T[] {
|
||||
export function top<T>(array: ReadonlyArray<T>, compare: (a: T, b: T) => number, n: number): T[] {
|
||||
if (n === 0) {
|
||||
return [];
|
||||
}
|
||||
@@ -284,7 +281,7 @@ export function topAsync<T>(array: T[], compare: (a: T, b: T) => number, n: numb
|
||||
});
|
||||
}
|
||||
|
||||
function topStep<T>(array: T[], compare: (a: T, b: T) => number, result: T[], i: number, m: number): void {
|
||||
function topStep<T>(array: ReadonlyArray<T>, compare: (a: T, b: T) => number, result: T[], i: number, m: number): void {
|
||||
for (const n = result.length; i < m; i++) {
|
||||
const element = array[i];
|
||||
if (compare(element, result[n - 1]) < 0) {
|
||||
@@ -298,7 +295,7 @@ function topStep<T>(array: T[], compare: (a: T, b: T) => number, result: T[], i:
|
||||
/**
|
||||
* @returns a new array with all falsy values removed. The original array IS NOT modified.
|
||||
*/
|
||||
export function coalesce<T>(array: (T | undefined | null)[]): T[] {
|
||||
export function coalesce<T>(array: Array<T | undefined | null>): T[] {
|
||||
if (!array) {
|
||||
return array;
|
||||
}
|
||||
@@ -308,7 +305,7 @@ export function coalesce<T>(array: (T | undefined | null)[]): T[] {
|
||||
/**
|
||||
* Remove all falsey values from `array`. The original array IS modified.
|
||||
*/
|
||||
export function coalesceInPlace<T>(array: (T | undefined | null)[]): void {
|
||||
export function coalesceInPlace<T>(array: Array<T | undefined | null>): void {
|
||||
if (!array) {
|
||||
return;
|
||||
}
|
||||
@@ -330,15 +327,14 @@ export function move(array: any[], from: number, to: number): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {{false}} if the provided object is an array
|
||||
* and not empty.
|
||||
* @returns false if the provided object is an array and not empty.
|
||||
*/
|
||||
export function isFalsyOrEmpty(obj: any): boolean {
|
||||
return !Array.isArray(obj) || obj.length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {{true}} if the provided object is an array and has at least one element.
|
||||
* @returns True if the provided object is an array and has at least one element.
|
||||
*/
|
||||
export function isNonEmptyArray<T>(obj: ReadonlyArray<T> | undefined | null): obj is Array<T> {
|
||||
return Array.isArray(obj) && obj.length > 0;
|
||||
@@ -348,7 +344,7 @@ export function isNonEmptyArray<T>(obj: ReadonlyArray<T> | undefined | null): ob
|
||||
* Removes duplicates from the given array. The optional keyFn allows to specify
|
||||
* how elements are checked for equalness by returning a unique string for each.
|
||||
*/
|
||||
export function distinct<T>(array: T[], keyFn?: (t: T) => string): T[] {
|
||||
export function distinct<T>(array: ReadonlyArray<T>, keyFn?: (t: T) => string): T[] {
|
||||
if (!keyFn) {
|
||||
return array.filter((element, position) => {
|
||||
return array.indexOf(element) === position;
|
||||
@@ -383,7 +379,7 @@ export function uniqueFilter<T>(keyFn: (t: T) => string): (t: T) => boolean {
|
||||
};
|
||||
}
|
||||
|
||||
export function firstIndex<T>(array: T[] | ReadonlyArray<T>, fn: (item: T) => boolean): number {
|
||||
export function firstIndex<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean): number {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const element = array[i];
|
||||
|
||||
@@ -395,14 +391,14 @@ export function firstIndex<T>(array: T[] | ReadonlyArray<T>, fn: (item: T) => bo
|
||||
return -1;
|
||||
}
|
||||
|
||||
export function first<T>(array: T[] | ReadonlyArray<T>, fn: (item: T) => boolean, notFoundValue: T): T;
|
||||
export function first<T>(array: T[] | ReadonlyArray<T>, fn: (item: T) => boolean): T | null;
|
||||
export function first<T>(array: T[] | ReadonlyArray<T>, fn: (item: T) => boolean, notFoundValue: T | null = null): T | null {
|
||||
export function first<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean, notFoundValue: T): T;
|
||||
export function first<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean): T | null;
|
||||
export function first<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean, notFoundValue: T | null = null): T | null {
|
||||
const index = firstIndex(array, fn);
|
||||
return index < 0 ? notFoundValue : array[index];
|
||||
}
|
||||
|
||||
export function commonPrefixLength<T>(one: T[], other: T[], equals: (a: T, b: T) => boolean = (a, b) => a === b): number {
|
||||
export function commonPrefixLength<T>(one: ReadonlyArray<T>, other: ReadonlyArray<T>, equals: (a: T, b: T) => boolean = (a, b) => a === b): number {
|
||||
let result = 0;
|
||||
|
||||
for (let i = 0, len = Math.min(one.length, other.length); i < len && equals(one[i], other[i]); i++) {
|
||||
@@ -443,17 +439,17 @@ export function range(arg: number, to?: number): number[] {
|
||||
return result;
|
||||
}
|
||||
|
||||
export function fill<T>(num: number, valueFn: () => T, arr: T[] = []): T[] {
|
||||
export function fill<T>(num: number, value: T, arr: T[] = []): T[] {
|
||||
for (let i = 0; i < num; i++) {
|
||||
arr[i] = valueFn();
|
||||
arr[i] = value;
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
export function index<T>(array: T[], indexer: (t: T) => string): { [key: string]: T; };
|
||||
export function index<T, R>(array: T[], indexer: (t: T) => string, merger?: (t: T, r: R) => R): { [key: string]: R; };
|
||||
export function index<T, R>(array: T[], indexer: (t: T) => string, merger: (t: T, r: R) => R = t => t as any): { [key: string]: R; } {
|
||||
export function index<T>(array: ReadonlyArray<T>, indexer: (t: T) => string): { [key: string]: T; };
|
||||
export function index<T, R>(array: ReadonlyArray<T>, indexer: (t: T) => string, merger?: (t: T, r: R) => R): { [key: string]: R; };
|
||||
export function index<T, R>(array: ReadonlyArray<T>, indexer: (t: T) => string, merger: (t: T, r: R) => R = t => t as any): { [key: string]: R; } {
|
||||
return array.reduce((r, t) => {
|
||||
const key = indexer(t);
|
||||
r[key] = merger(t, r[key]);
|
||||
@@ -488,7 +484,6 @@ export function arrayInsert<T>(target: T[], insertIndex: number, insertArr: T[])
|
||||
|
||||
/**
|
||||
* Uses Fisher-Yates shuffle to shuffle the given array
|
||||
* @param array
|
||||
*/
|
||||
export function shuffle<T>(array: T[], _seed?: number): void {
|
||||
let rand: () => number;
|
||||
@@ -498,7 +493,7 @@ export function shuffle<T>(array: T[], _seed?: number): void {
|
||||
// Seeded random number generator in JS. Modified from:
|
||||
// https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript
|
||||
rand = () => {
|
||||
var x = Math.sin(seed++) * 179426549; // throw away most significant digits and reduce any potential bias
|
||||
const x = Math.sin(seed++) * 179426549; // throw away most significant digits and reduce any potential bias
|
||||
return x - Math.floor(x);
|
||||
};
|
||||
} else {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Throws an error with the provided message if the provided value does not evaluate to a true Javascript value.
|
||||
*/
|
||||
export function ok(value?: any, message?: string) {
|
||||
if (!value || value === null) {
|
||||
if (!value) {
|
||||
throw new Error(message ? 'Assertion failed (' + message + ')' : 'Assertion Failed');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,18 +6,18 @@
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
export function isThenable<T>(obj: any): obj is Thenable<T> {
|
||||
return obj && typeof (<Thenable<any>>obj).then === 'function';
|
||||
export function isThenable<T>(obj: any): obj is Promise<T> {
|
||||
return obj && typeof (<Promise<any>>obj).then === 'function';
|
||||
}
|
||||
|
||||
export interface CancelablePromise<T> extends Promise<T> {
|
||||
cancel(): void;
|
||||
}
|
||||
|
||||
export function createCancelablePromise<T>(callback: (token: CancellationToken) => Thenable<T>): CancelablePromise<T> {
|
||||
export function createCancelablePromise<T>(callback: (token: CancellationToken) => Promise<T>): CancelablePromise<T> {
|
||||
const source = new CancellationTokenSource();
|
||||
|
||||
const thenable = callback(source.token);
|
||||
@@ -38,16 +38,19 @@ export function createCancelablePromise<T>(callback: (token: CancellationToken)
|
||||
cancel() {
|
||||
source.cancel();
|
||||
}
|
||||
then<TResult1 = T, TResult2 = never>(resolve?: ((value: T) => TResult1 | Thenable<TResult1>) | undefined | null, reject?: ((reason: any) => TResult2 | Thenable<TResult2>) | undefined | null): Promise<TResult1 | TResult2> {
|
||||
then<TResult1 = T, TResult2 = never>(resolve?: ((value: T) => TResult1 | Promise<TResult1>) | undefined | null, reject?: ((reason: any) => TResult2 | Promise<TResult2>) | undefined | null): Promise<TResult1 | TResult2> {
|
||||
return promise.then(resolve, reject);
|
||||
}
|
||||
catch<TResult = never>(reject?: ((reason: any) => TResult | Thenable<TResult>) | undefined | null): Promise<T | TResult> {
|
||||
catch<TResult = never>(reject?: ((reason: any) => TResult | Promise<TResult>) | undefined | null): Promise<T | TResult> {
|
||||
return this.then(undefined, reject);
|
||||
}
|
||||
finally(onfinally?: (() => void) | undefined | null): Promise<T> {
|
||||
return always(promise, onfinally || (() => { }));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function asThenable<T>(callback: () => T | Thenable<T>): Promise<T> {
|
||||
export function asPromise<T>(callback: () => T | Thenable<T>): Promise<T> {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
let item = callback();
|
||||
if (isThenable<T>(item)) {
|
||||
@@ -90,9 +93,9 @@ export interface ITask<T> {
|
||||
*/
|
||||
export class Throttler {
|
||||
|
||||
private activePromise: Thenable<any> | null;
|
||||
private queuedPromise: Thenable<any> | null;
|
||||
private queuedPromiseFactory: ITask<Thenable<any>> | null;
|
||||
private activePromise: Promise<any> | null;
|
||||
private queuedPromise: Promise<any> | null;
|
||||
private queuedPromiseFactory: ITask<Promise<any>> | null;
|
||||
|
||||
constructor() {
|
||||
this.activePromise = null;
|
||||
@@ -100,7 +103,7 @@ export class Throttler {
|
||||
this.queuedPromiseFactory = null;
|
||||
}
|
||||
|
||||
queue<T>(promiseFactory: ITask<Thenable<T>>): Thenable<T> {
|
||||
queue<T>(promiseFactory: ITask<Promise<T>>): Promise<T> {
|
||||
if (this.activePromise) {
|
||||
this.queuedPromiseFactory = promiseFactory;
|
||||
|
||||
@@ -142,7 +145,7 @@ export class Sequencer {
|
||||
|
||||
private current: Promise<any> = Promise.resolve(null);
|
||||
|
||||
queue<T>(promiseTask: ITask<Thenable<T>>): Thenable<T> {
|
||||
queue<T>(promiseTask: ITask<Promise<T>>): Promise<T> {
|
||||
return this.current = this.current.then(() => promiseTask());
|
||||
}
|
||||
}
|
||||
@@ -173,10 +176,10 @@ export class Sequencer {
|
||||
export class Delayer<T> implements IDisposable {
|
||||
|
||||
private timeout: any;
|
||||
private completionPromise: Thenable<any> | null;
|
||||
private doResolve: ((value?: any | Thenable<any>) => void) | null;
|
||||
private completionPromise: Promise<any> | null;
|
||||
private doResolve: ((value?: any | Promise<any>) => void) | null;
|
||||
private doReject: (err: any) => void;
|
||||
private task: ITask<T | Thenable<T>> | null;
|
||||
private task: ITask<T | Promise<T>> | null;
|
||||
|
||||
constructor(public defaultDelay: number) {
|
||||
this.timeout = null;
|
||||
@@ -185,7 +188,7 @@ export class Delayer<T> implements IDisposable {
|
||||
this.task = null;
|
||||
}
|
||||
|
||||
trigger(task: ITask<T | Thenable<T>>, delay: number = this.defaultDelay): Thenable<T> {
|
||||
trigger(task: ITask<T | Promise<T>>, delay: number = this.defaultDelay): Promise<T> {
|
||||
this.task = task;
|
||||
this.cancelTimeout();
|
||||
|
||||
@@ -247,7 +250,7 @@ export class Delayer<T> implements IDisposable {
|
||||
*/
|
||||
export class ThrottledDelayer<T> {
|
||||
|
||||
private delayer: Delayer<Thenable<T>>;
|
||||
private delayer: Delayer<Promise<T>>;
|
||||
private throttler: Throttler;
|
||||
|
||||
constructor(defaultDelay: number) {
|
||||
@@ -255,8 +258,8 @@ export class ThrottledDelayer<T> {
|
||||
this.throttler = new Throttler();
|
||||
}
|
||||
|
||||
trigger(promiseFactory: ITask<Thenable<T>>, delay?: number): Thenable<T> {
|
||||
return this.delayer.trigger(() => this.throttler.queue(promiseFactory), delay) as any as Thenable<T>;
|
||||
trigger(promiseFactory: ITask<Promise<T>>, delay?: number): Promise<T> {
|
||||
return this.delayer.trigger(() => this.throttler.queue(promiseFactory), delay) as any as Promise<T>;
|
||||
}
|
||||
|
||||
isTriggered(): boolean {
|
||||
@@ -303,8 +306,8 @@ export class Barrier {
|
||||
}
|
||||
|
||||
export function timeout(millis: number): CancelablePromise<void>;
|
||||
export function timeout(millis: number, token: CancellationToken): Thenable<void>;
|
||||
export function timeout(millis: number, token?: CancellationToken): CancelablePromise<void> | Thenable<void> {
|
||||
export function timeout(millis: number, token: CancellationToken): Promise<void>;
|
||||
export function timeout(millis: number, token?: CancellationToken): CancelablePromise<void> | Promise<void> {
|
||||
if (!token) {
|
||||
return createCancelablePromise(token => timeout(millis, token));
|
||||
}
|
||||
@@ -318,13 +321,9 @@ export function timeout(millis: number, token?: CancellationToken): CancelablePr
|
||||
});
|
||||
}
|
||||
|
||||
export function disposableTimeout(handler: Function, timeout = 0): IDisposable {
|
||||
export function disposableTimeout(handler: () => void, timeout = 0): IDisposable {
|
||||
const timer = setTimeout(handler, timeout);
|
||||
return {
|
||||
dispose() {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
};
|
||||
return toDisposable(() => clearTimeout(timer));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -334,7 +333,7 @@ export function disposableTimeout(handler: Function, timeout = 0): IDisposable {
|
||||
* @param promise a promise
|
||||
* @param callback a function that will be call in the success and error case.
|
||||
*/
|
||||
export function always<T>(promise: Thenable<T>, callback: () => void): Promise<T> {
|
||||
export function always<T>(promise: Promise<T>, callback: () => void): Promise<T> {
|
||||
function safeCallback() {
|
||||
try {
|
||||
callback();
|
||||
@@ -346,7 +345,7 @@ export function always<T>(promise: Thenable<T>, callback: () => void): Promise<T
|
||||
return Promise.resolve(promise);
|
||||
}
|
||||
|
||||
export function ignoreErrors<T>(promise: Thenable<T>): Thenable<T | undefined> {
|
||||
export function ignoreErrors<T>(promise: Promise<T>): Promise<T | undefined> {
|
||||
return promise.then(undefined, _ => undefined);
|
||||
}
|
||||
|
||||
@@ -355,16 +354,16 @@ export function ignoreErrors<T>(promise: Thenable<T>): Thenable<T | undefined> {
|
||||
* promise will complete to an array of results from each promise.
|
||||
*/
|
||||
|
||||
export function sequence<T>(promiseFactories: ITask<Thenable<T>>[]): Promise<T[]> {
|
||||
export function sequence<T>(promiseFactories: ITask<Promise<T>>[]): Promise<T[]> {
|
||||
const results: T[] = [];
|
||||
let index = 0;
|
||||
const len = promiseFactories.length;
|
||||
|
||||
function next(): Thenable<T> | null {
|
||||
function next(): Promise<T> | null {
|
||||
return index < len ? promiseFactories[index++]() : null;
|
||||
}
|
||||
|
||||
function thenHandler(result: any): Thenable<any> {
|
||||
function thenHandler(result: any): Promise<any> {
|
||||
if (result !== undefined && result !== null) {
|
||||
results.push(result);
|
||||
}
|
||||
@@ -380,7 +379,7 @@ export function sequence<T>(promiseFactories: ITask<Thenable<T>>[]): Promise<T[]
|
||||
return Promise.resolve(null).then(thenHandler);
|
||||
}
|
||||
|
||||
export function first<T>(promiseFactories: ITask<Thenable<T>>[], shouldStop: (t: T) => boolean = t => !!t, defaultValue: T | null = null): Promise<T | null> {
|
||||
export function first<T>(promiseFactories: ITask<Promise<T>>[], shouldStop: (t: T) => boolean = t => !!t, defaultValue: T | null = null): Promise<T | null> {
|
||||
let index = 0;
|
||||
const len = promiseFactories.length;
|
||||
|
||||
@@ -405,8 +404,8 @@ export function first<T>(promiseFactories: ITask<Thenable<T>>[], shouldStop: (t:
|
||||
}
|
||||
|
||||
interface ILimitedTaskFactory<T> {
|
||||
factory: ITask<Thenable<T>>;
|
||||
c: (value?: T | Thenable<T>) => void;
|
||||
factory: ITask<Promise<T>>;
|
||||
c: (value?: T | Promise<T>) => void;
|
||||
e: (error?: any) => void;
|
||||
}
|
||||
|
||||
@@ -438,7 +437,7 @@ export class Limiter<T> {
|
||||
// return this.runningPromises + this.outstandingPromises.length;
|
||||
}
|
||||
|
||||
queue(factory: ITask<Thenable<T>>): Thenable<T> {
|
||||
queue(factory: ITask<Promise<T>>): Promise<T> {
|
||||
this._size++;
|
||||
|
||||
return new Promise<T>((c, e) => {
|
||||
@@ -685,8 +684,8 @@ export function nfcall(fn: Function, ...args: any[]): any {
|
||||
return new Promise((c, e) => fn(...args, (err: any, result: any) => err ? e(err) : c(result)));
|
||||
}
|
||||
|
||||
export function ninvoke(thisArg: any, fn: Function, ...args: any[]): Thenable<any>;
|
||||
export function ninvoke<T>(thisArg: any, fn: Function, ...args: any[]): Thenable<T>;
|
||||
export function ninvoke(thisArg: any, fn: Function, ...args: any[]): Promise<any>;
|
||||
export function ninvoke<T>(thisArg: any, fn: Function, ...args: any[]): Promise<T>;
|
||||
export function ninvoke(thisArg: any, fn: Function, ...args: any[]): any {
|
||||
return new Promise((resolve, reject) => fn.call(thisArg, ...args, (err: any, result: any) => err ? reject(err) : resolve(result)));
|
||||
}
|
||||
@@ -712,8 +711,8 @@ declare function cancelIdleCallback(handle: number): void;
|
||||
didTimeout: true,
|
||||
timeRemaining() { return 15; }
|
||||
});
|
||||
runWhenIdle = (runner, timeout = 0) => {
|
||||
let handle = setTimeout(() => runner(dummyIdle), timeout);
|
||||
runWhenIdle = (runner) => {
|
||||
let handle = setTimeout(() => runner(dummyIdle));
|
||||
let disposed = false;
|
||||
return {
|
||||
dispose() {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
{
|
||||
"name": "vs/base",
|
||||
"dependencies": [
|
||||
{ "name": "vs", "internal": false }
|
||||
{
|
||||
"name": "vs",
|
||||
"internal": false
|
||||
}
|
||||
],
|
||||
"libs": [
|
||||
"lib.core.d.ts"
|
||||
@@ -9,7 +12,5 @@
|
||||
"sources": [
|
||||
"**/*.ts"
|
||||
],
|
||||
"declares": [
|
||||
"vs/base/winjs.base.d.ts"
|
||||
]
|
||||
}
|
||||
"declares": []
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ export function first<T>(from: IStringDictionary<T> | INumberDictionary<T>): T |
|
||||
* Iterates over each entry in the provided set. The iterator allows
|
||||
* to remove elements and will stop when the callback returns {{false}}.
|
||||
*/
|
||||
export function forEach<T>(from: IStringDictionary<T> | INumberDictionary<T>, callback: (entry: { key: any; value: T; }, remove: Function) => any): void {
|
||||
export function forEach<T>(from: IStringDictionary<T> | INumberDictionary<T>, callback: (entry: { key: any; value: T; }, remove: () => void) => any): void {
|
||||
for (let key in from) {
|
||||
if (hasOwnProperty.call(from, key)) {
|
||||
const result = callback({ key: key, value: (from as any)[key] }, function () {
|
||||
|
||||
@@ -388,7 +388,7 @@ export class Color {
|
||||
const colorA = rgba.a;
|
||||
|
||||
let a = thisA + colorA * (1 - thisA);
|
||||
if (a < 1.0e-6) {
|
||||
if (a < 1e-6) {
|
||||
return Color.transparent;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ export function setFileNameComparer(collator: IdleValue<{ collator: Intl.Collato
|
||||
intlFileNameCollator = collator;
|
||||
}
|
||||
|
||||
export function compareFileNames(one: string, other: string, caseSensitive = false): number {
|
||||
export function compareFileNames(one: string | null, other: string | null, caseSensitive = false): number {
|
||||
if (intlFileNameCollator) {
|
||||
const a = one || '';
|
||||
const b = other || '';
|
||||
@@ -33,7 +33,7 @@ export function compareFileNames(one: string, other: string, caseSensitive = fal
|
||||
|
||||
const FileNameMatch = /^(.*?)(\.([^.]*))?$/;
|
||||
|
||||
export function noIntlCompareFileNames(one: string, other: string, caseSensitive = false): number {
|
||||
export function noIntlCompareFileNames(one: string | null, other: string | null, caseSensitive = false): number {
|
||||
if (!caseSensitive) {
|
||||
one = one && one.toLowerCase();
|
||||
other = other && other.toLowerCase();
|
||||
@@ -53,7 +53,7 @@ export function noIntlCompareFileNames(one: string, other: string, caseSensitive
|
||||
return oneExtension < otherExtension ? -1 : 1;
|
||||
}
|
||||
|
||||
export function compareFileExtensions(one: string, other: string): number {
|
||||
export function compareFileExtensions(one: string | null, other: string | null): number {
|
||||
if (intlFileNameCollator) {
|
||||
const [oneName, oneExtension] = extractNameAndExtension(one);
|
||||
const [otherName, otherExtension] = extractNameAndExtension(other);
|
||||
@@ -81,7 +81,7 @@ export function compareFileExtensions(one: string, other: string): number {
|
||||
return noIntlCompareFileExtensions(one, other);
|
||||
}
|
||||
|
||||
function noIntlCompareFileExtensions(one: string, other: string): number {
|
||||
function noIntlCompareFileExtensions(one: string | null, other: string | null): number {
|
||||
const [oneName, oneExtension] = extractNameAndExtension(one && one.toLowerCase());
|
||||
const [otherName, otherExtension] = extractNameAndExtension(other && other.toLowerCase());
|
||||
|
||||
@@ -96,7 +96,7 @@ function noIntlCompareFileExtensions(one: string, other: string): number {
|
||||
return oneName < otherName ? -1 : 1;
|
||||
}
|
||||
|
||||
function extractNameAndExtension(str?: string): [string, string] {
|
||||
function extractNameAndExtension(str?: string | null): [string, string] {
|
||||
const match = str ? FileNameMatch.exec(str) as Array<string> : ([] as Array<string>);
|
||||
|
||||
return [(match && match[1]) || '', (match && match[3]) || ''];
|
||||
|
||||
@@ -71,7 +71,7 @@ export function debounce<T>(delay: number, reducer?: IDebouceReducer<T>, initial
|
||||
|
||||
return function (this: any, ...args: any[]) {
|
||||
if (!this[resultKey]) {
|
||||
this[resultKey] = initialValueProvider ? initialValueProvider() : void 0;
|
||||
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
|
||||
}
|
||||
|
||||
clearTimeout(this[timerKey]);
|
||||
@@ -83,7 +83,7 @@ export function debounce<T>(delay: number, reducer?: IDebouceReducer<T>, initial
|
||||
|
||||
this[timerKey] = setTimeout(() => {
|
||||
fn.apply(this, args);
|
||||
this[resultKey] = initialValueProvider ? initialValueProvider() : void 0;
|
||||
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
|
||||
}, delay);
|
||||
};
|
||||
});
|
||||
|
||||
@@ -763,7 +763,7 @@ export class LcsDiff {
|
||||
change.modifiedStart++;
|
||||
}
|
||||
|
||||
let mergedChangeArr: (DiffChange | null)[] = [null];
|
||||
let mergedChangeArr: Array<DiffChange | null> = [null];
|
||||
if (i < changes.length - 1 && this.ChangesOverlap(changes[i], changes[i + 1], mergedChangeArr)) {
|
||||
changes[i] = mergedChangeArr[0]!;
|
||||
changes.splice(i + 1, 1);
|
||||
@@ -913,7 +913,7 @@ export class LcsDiff {
|
||||
* @param mergedChange The merged change if the two overlap, null otherwise
|
||||
* @returns True if the two changes overlap
|
||||
*/
|
||||
private ChangesOverlap(left: DiffChange, right: DiffChange, mergedChangeArr: (DiffChange | null)[]): boolean {
|
||||
private ChangesOverlap(left: DiffChange, right: DiffChange, mergedChangeArr: Array<DiffChange | null>): boolean {
|
||||
Debug.Assert(left.originalStart <= right.originalStart, 'Left change is not less than or equal to right change');
|
||||
Debug.Assert(left.modifiedStart <= right.modifiedStart, 'Left change is not less than or equal to right change');
|
||||
|
||||
|
||||
@@ -3,59 +3,6 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { TPromise, IPromiseError, IPromiseErrorDetail } from 'vs/base/common/winjs.base';
|
||||
|
||||
// ------ BEGIN Hook up error listeners to winjs promises
|
||||
|
||||
let outstandingPromiseErrors: { [id: string]: IPromiseErrorDetail; } = {};
|
||||
function promiseErrorHandler(e: IPromiseError): void {
|
||||
|
||||
//
|
||||
// e.detail looks like: { exception, error, promise, handler, id, parent }
|
||||
//
|
||||
const details = e.detail;
|
||||
const id = details.id;
|
||||
|
||||
// If the error has a parent promise then this is not the origination of the
|
||||
// error so we check if it has a handler, and if so we mark that the error
|
||||
// was handled by removing it from outstandingPromiseErrors
|
||||
//
|
||||
if (details.parent) {
|
||||
if (details.handler && outstandingPromiseErrors) {
|
||||
delete outstandingPromiseErrors[id];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Indicate that this error was originated and needs to be handled
|
||||
outstandingPromiseErrors[id] = details;
|
||||
|
||||
// The first time the queue fills up this iteration, schedule a timeout to
|
||||
// check if any errors are still unhandled.
|
||||
if (Object.keys(outstandingPromiseErrors).length === 1) {
|
||||
setTimeout(function () {
|
||||
const errors = outstandingPromiseErrors;
|
||||
outstandingPromiseErrors = {};
|
||||
Object.keys(errors).forEach(function (errorId) {
|
||||
const error = errors[errorId];
|
||||
if (error.exception) {
|
||||
onUnexpectedError(error.exception);
|
||||
} else if (error.error) {
|
||||
onUnexpectedError(error.error);
|
||||
}
|
||||
console.log('WARNING: Promise with no error callback:' + error.id);
|
||||
console.log(error);
|
||||
if (error.exception) {
|
||||
console.log(error.exception.stack);
|
||||
}
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
TPromise.addEventListener('error', promiseErrorHandler);
|
||||
|
||||
// ------ END Hook up error listeners to winjs promises
|
||||
|
||||
export interface ErrorListenerCallback {
|
||||
(error: any): void;
|
||||
}
|
||||
|
||||
@@ -19,9 +19,348 @@ export interface Event<T> {
|
||||
export namespace Event {
|
||||
const _disposable = { dispose() { } };
|
||||
export const None: Event<any> = function () { return _disposable; };
|
||||
|
||||
/**
|
||||
* Given an event, returns another event which only fires once.
|
||||
*/
|
||||
export function once<T>(event: Event<T>): Event<T> {
|
||||
return (listener, thisArgs = null, disposables?) => {
|
||||
// we need this, in case the event fires during the listener call
|
||||
let didFire = false;
|
||||
|
||||
const result = event(e => {
|
||||
if (didFire) {
|
||||
return;
|
||||
} else if (result) {
|
||||
result.dispose();
|
||||
} else {
|
||||
didFire = true;
|
||||
}
|
||||
|
||||
return listener.call(thisArgs, e);
|
||||
}, null, disposables);
|
||||
|
||||
if (didFire) {
|
||||
result.dispose();
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an event and a `map` function, returns another event which maps each element
|
||||
* throught the mapping function.
|
||||
*/
|
||||
export function map<I, O>(event: Event<I>, map: (i: I) => O): Event<O> {
|
||||
return (listener, thisArgs = null, disposables?) => event(i => listener.call(thisArgs, map(i)), null, disposables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an event and an `each` function, returns another identical event and calls
|
||||
* the `each` function per each element.
|
||||
*/
|
||||
export function forEach<I>(event: Event<I>, each: (i: I) => void): Event<I> {
|
||||
return (listener, thisArgs = null, disposables?) => event(i => { each(i); listener.call(thisArgs, i); }, null, disposables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an event and a `filter` function, returns another event which emits those
|
||||
* elements for which the `filter` function returns `true`.
|
||||
*/
|
||||
export function filter<T>(event: Event<T>, filter: (e: T) => boolean): Event<T>;
|
||||
export function filter<T, R>(event: Event<T | R>, filter: (e: T | R) => e is R): Event<R>;
|
||||
export function filter<T>(event: Event<T>, filter: (e: T) => boolean): Event<T> {
|
||||
return (listener, thisArgs = null, disposables?) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an event, returns the same event but typed as `Event<void>`.
|
||||
*/
|
||||
export function signal<T>(event: Event<T>): Event<void> {
|
||||
return event as Event<any> as Event<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a collection of events, returns a single event which emits
|
||||
* whenever any of the provided events emit.
|
||||
*/
|
||||
export function any<T>(...events: Event<T>[]): Event<T> {
|
||||
return (listener, thisArgs = null, disposables?) => combinedDisposable(events.map(event => event(e => listener.call(thisArgs, e), null, disposables)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an event and a `merge` function, returns another event which maps each element
|
||||
* and the cummulative result throught the `merge` function. Similar to `map`, but with memory.
|
||||
*/
|
||||
export function reduce<I, O>(event: Event<I>, merge: (last: O | undefined, event: I) => O, initial?: O): Event<O> {
|
||||
let output: O | undefined = initial;
|
||||
|
||||
return map<I, O>(event, e => {
|
||||
output = merge(output, e);
|
||||
return output;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Debounces the provided event, given a `merge` function.
|
||||
*
|
||||
* @param event The input event.
|
||||
* @param merge The reducing function.
|
||||
* @param delay The debouncing delay in millis.
|
||||
* @param leading Whether the event should fire in the leading phase of the timeout.
|
||||
* @param leakWarningThreshold The leak warning threshold override.
|
||||
*/
|
||||
export function debounce<T>(event: Event<T>, merge: (last: T, event: T) => T, delay?: number, leading?: boolean, leakWarningThreshold?: number): Event<T>;
|
||||
export function debounce<I, O>(event: Event<I>, merge: (last: O | undefined, event: I) => O, delay?: number, leading?: boolean, leakWarningThreshold?: number): Event<O>;
|
||||
export function debounce<I, O>(event: Event<I>, merge: (last: O | undefined, event: I) => O, delay: number = 100, leading = false, leakWarningThreshold?: number): Event<O> {
|
||||
|
||||
let subscription: IDisposable;
|
||||
let output: O | undefined = undefined;
|
||||
let handle: any = undefined;
|
||||
let numDebouncedCalls = 0;
|
||||
|
||||
const emitter = new Emitter<O>({
|
||||
leakWarningThreshold,
|
||||
onFirstListenerAdd() {
|
||||
subscription = event(cur => {
|
||||
numDebouncedCalls++;
|
||||
output = merge(output, cur);
|
||||
|
||||
if (leading && !handle) {
|
||||
emitter.fire(output);
|
||||
}
|
||||
|
||||
clearTimeout(handle);
|
||||
handle = setTimeout(() => {
|
||||
let _output = output;
|
||||
output = undefined;
|
||||
handle = undefined;
|
||||
if (!leading || numDebouncedCalls > 1) {
|
||||
emitter.fire(_output!);
|
||||
}
|
||||
|
||||
numDebouncedCalls = 0;
|
||||
}, delay);
|
||||
});
|
||||
},
|
||||
onLastListenerRemove() {
|
||||
subscription.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
return emitter.event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an event, it returns another event which fires only once and as soon as
|
||||
* the input event emits. The event data is the number of millis it took for the
|
||||
* event to fire.
|
||||
*/
|
||||
export function stopwatch<T>(event: Event<T>): Event<number> {
|
||||
const start = new Date().getTime();
|
||||
return map(once(event), _ => new Date().getTime() - start);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an event, it returns another event which fires only when the event
|
||||
* element changes.
|
||||
*/
|
||||
export function latch<T>(event: Event<T>): Event<T> {
|
||||
let firstCall = true;
|
||||
let cache: T;
|
||||
|
||||
return filter(event, value => {
|
||||
let shouldEmit = firstCall || value !== cache;
|
||||
firstCall = false;
|
||||
cache = value;
|
||||
return shouldEmit;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Buffers the provided event until a first listener comes
|
||||
* along, at which point fire all the events at once and
|
||||
* pipe the event from then on.
|
||||
*
|
||||
* ```typescript
|
||||
* const emitter = new Emitter<number>();
|
||||
* const event = emitter.event;
|
||||
* const bufferedEvent = buffer(event);
|
||||
*
|
||||
* emitter.fire(1);
|
||||
* emitter.fire(2);
|
||||
* emitter.fire(3);
|
||||
* // nothing...
|
||||
*
|
||||
* const listener = bufferedEvent(num => console.log(num));
|
||||
* // 1, 2, 3
|
||||
*
|
||||
* emitter.fire(4);
|
||||
* // 4
|
||||
* ```
|
||||
*/
|
||||
export function buffer<T>(event: Event<T>, nextTick = false, _buffer: T[] = []): Event<T> {
|
||||
let buffer: T[] | null = _buffer.slice();
|
||||
|
||||
let listener: IDisposable | null = event(e => {
|
||||
if (buffer) {
|
||||
buffer.push(e);
|
||||
} else {
|
||||
emitter.fire(e);
|
||||
}
|
||||
});
|
||||
|
||||
const flush = () => {
|
||||
if (buffer) {
|
||||
buffer.forEach(e => emitter.fire(e));
|
||||
}
|
||||
buffer = null;
|
||||
};
|
||||
|
||||
const emitter = new Emitter<T>({
|
||||
onFirstListenerAdd() {
|
||||
if (!listener) {
|
||||
listener = event(e => emitter.fire(e));
|
||||
}
|
||||
},
|
||||
|
||||
onFirstListenerDidAdd() {
|
||||
if (buffer) {
|
||||
if (nextTick) {
|
||||
setTimeout(flush);
|
||||
} else {
|
||||
flush();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onLastListenerRemove() {
|
||||
if (listener) {
|
||||
listener.dispose();
|
||||
}
|
||||
listener = null;
|
||||
}
|
||||
});
|
||||
|
||||
return emitter.event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to `buffer` but it buffers indefinitely and repeats
|
||||
* the buffered events to every new listener.
|
||||
*/
|
||||
export function echo<T>(event: Event<T>, nextTick = false, buffer: T[] = []): Event<T> {
|
||||
buffer = buffer.slice();
|
||||
|
||||
event(e => {
|
||||
buffer.push(e);
|
||||
emitter.fire(e);
|
||||
});
|
||||
|
||||
const flush = (listener: (e: T) => any, thisArgs?: any) => buffer.forEach(e => listener.call(thisArgs, e));
|
||||
|
||||
const emitter = new Emitter<T>({
|
||||
onListenerDidAdd(emitter, listener: (e: T) => any, thisArgs?: any) {
|
||||
if (nextTick) {
|
||||
setTimeout(() => flush(listener, thisArgs));
|
||||
} else {
|
||||
flush(listener, thisArgs);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return emitter.event;
|
||||
}
|
||||
|
||||
export interface IChainableEvent<T> {
|
||||
event: Event<T>;
|
||||
map<O>(fn: (i: T) => O): IChainableEvent<O>;
|
||||
forEach(fn: (i: T) => void): IChainableEvent<T>;
|
||||
filter(fn: (e: T) => boolean): IChainableEvent<T>;
|
||||
reduce<R>(merge: (last: R | undefined, event: T) => R, initial?: R): IChainableEvent<R>;
|
||||
latch(): IChainableEvent<T>;
|
||||
on(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable;
|
||||
once(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable;
|
||||
}
|
||||
|
||||
class ChainableEvent<T> implements IChainableEvent<T> {
|
||||
|
||||
get event(): Event<T> { return this._event; }
|
||||
|
||||
constructor(private _event: Event<T>) { }
|
||||
|
||||
map<O>(fn: (i: T) => O): IChainableEvent<O> {
|
||||
return new ChainableEvent(map(this._event, fn));
|
||||
}
|
||||
|
||||
forEach(fn: (i: T) => void): IChainableEvent<T> {
|
||||
return new ChainableEvent(forEach(this._event, fn));
|
||||
}
|
||||
|
||||
filter(fn: (e: T) => boolean): IChainableEvent<T> {
|
||||
return new ChainableEvent(filter(this._event, fn));
|
||||
}
|
||||
|
||||
reduce<R>(merge: (last: R | undefined, event: T) => R, initial?: R): IChainableEvent<R> {
|
||||
return new ChainableEvent(reduce(this._event, merge, initial));
|
||||
}
|
||||
|
||||
latch(): IChainableEvent<T> {
|
||||
return new ChainableEvent(latch(this._event));
|
||||
}
|
||||
|
||||
on(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[]) {
|
||||
return this._event(listener, thisArgs, disposables);
|
||||
}
|
||||
|
||||
once(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[]) {
|
||||
return once(this._event)(listener, thisArgs, disposables);
|
||||
}
|
||||
}
|
||||
|
||||
export function chain<T>(event: Event<T>): IChainableEvent<T> {
|
||||
return new ChainableEvent(event);
|
||||
}
|
||||
|
||||
export interface NodeEventEmitter {
|
||||
on(event: string | symbol, listener: Function): this;
|
||||
removeListener(event: string | symbol, listener: Function): this;
|
||||
}
|
||||
|
||||
export function fromNodeEventEmitter<T>(emitter: NodeEventEmitter, eventName: string, map: (...args: any[]) => T = id => id): Event<T> {
|
||||
const fn = (...args: any[]) => result.fire(map(...args));
|
||||
const onFirstListenerAdd = () => emitter.on(eventName, fn);
|
||||
const onLastListenerRemove = () => emitter.removeListener(eventName, fn);
|
||||
const result = new Emitter<T>({ onFirstListenerAdd, onLastListenerRemove });
|
||||
|
||||
return result.event;
|
||||
}
|
||||
|
||||
export function fromPromise<T = any>(promise: Promise<T>): Event<undefined> {
|
||||
const emitter = new Emitter<undefined>();
|
||||
let shouldEmit = false;
|
||||
|
||||
promise
|
||||
.then(undefined, () => null)
|
||||
.then(() => {
|
||||
if (!shouldEmit) {
|
||||
setTimeout(() => emitter.fire(undefined), 0);
|
||||
} else {
|
||||
emitter.fire(undefined);
|
||||
}
|
||||
});
|
||||
|
||||
shouldEmit = true;
|
||||
return emitter.event;
|
||||
}
|
||||
|
||||
export function toPromise<T>(event: Event<T>): Promise<T> {
|
||||
return new Promise(c => once(event)(c));
|
||||
}
|
||||
}
|
||||
|
||||
type Listener = [Function, any] | Function;
|
||||
type Listener<T> = [(e: T) => void, any] | ((e: T) => void);
|
||||
|
||||
export interface EmitterOptions {
|
||||
onFirstListenerAdd?: Function;
|
||||
@@ -80,7 +419,7 @@ class LeakageMonitor {
|
||||
if (this._warnCountdown <= 0) {
|
||||
// only warn on first exceed and then every time the limit
|
||||
// is exceeded by 50% again
|
||||
this._warnCountdown = threshold * .5;
|
||||
this._warnCountdown = threshold * 0.5;
|
||||
|
||||
// find most frequent listener and print warning
|
||||
let topStack: string;
|
||||
@@ -128,12 +467,12 @@ export class Emitter<T> {
|
||||
|
||||
private static readonly _noop = function () { };
|
||||
|
||||
private readonly _options: EmitterOptions | undefined;
|
||||
private readonly _leakageMon: LeakageMonitor | undefined;
|
||||
private readonly _options?: EmitterOptions;
|
||||
private readonly _leakageMon?: LeakageMonitor;
|
||||
private _disposed: boolean = false;
|
||||
private _event: Event<T> | undefined;
|
||||
private _deliveryQueue: [Listener, (T | undefined)][] | undefined;
|
||||
protected _listeners: LinkedList<Listener> | undefined;
|
||||
private _event?: Event<T>;
|
||||
private _deliveryQueue: [Listener<T>, T][];
|
||||
protected _listeners?: LinkedList<Listener<T>>;
|
||||
|
||||
constructor(options?: EmitterOptions) {
|
||||
this._options = options;
|
||||
@@ -207,7 +546,7 @@ export class Emitter<T> {
|
||||
* To be kept private to fire an event to
|
||||
* subscribers
|
||||
*/
|
||||
fire(event?: T): any {
|
||||
fire(event: T): void {
|
||||
if (this._listeners) {
|
||||
// put all [listener,event]-pairs into delivery queue
|
||||
// then emit all event. an inner/nested event might be
|
||||
@@ -251,14 +590,14 @@ export class Emitter<T> {
|
||||
}
|
||||
|
||||
export interface IWaitUntil {
|
||||
waitUntil(thenable: Thenable<any>): void;
|
||||
waitUntil(thenable: Promise<any>): void;
|
||||
}
|
||||
|
||||
export class AsyncEmitter<T extends IWaitUntil> extends Emitter<T> {
|
||||
|
||||
private _asyncDeliveryQueue: [Listener, T, Thenable<any>[]][];
|
||||
private _asyncDeliveryQueue: [Listener<T>, T, Promise<any>[]][];
|
||||
|
||||
async fireAsync(eventFn: (thenables: Thenable<any>[], listener: Function) => T): Promise<void> {
|
||||
async fireAsync(eventFn: (thenables: Promise<any>[], listener: Function) => T): Promise<void> {
|
||||
if (!this._listeners) {
|
||||
return;
|
||||
}
|
||||
@@ -271,7 +610,7 @@ export class AsyncEmitter<T extends IWaitUntil> extends Emitter<T> {
|
||||
}
|
||||
|
||||
for (let iter = this._listeners.iterator(), e = iter.next(); !e.done; e = iter.next()) {
|
||||
let thenables: Thenable<void>[] = [];
|
||||
let thenables: Promise<void>[] = [];
|
||||
this._asyncDeliveryQueue.push([e.value, eventFn(thenables, typeof e.value === 'function' ? e.value : e.value[0]), thenables]);
|
||||
}
|
||||
|
||||
@@ -359,98 +698,6 @@ export class EventMultiplexer<T> implements IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
export function fromPromise<T =any>(promise: Thenable<T>): Event<T> {
|
||||
const emitter = new Emitter<T>();
|
||||
let shouldEmit = false;
|
||||
|
||||
promise
|
||||
.then(undefined, () => null)
|
||||
.then(() => {
|
||||
if (!shouldEmit) {
|
||||
setTimeout(() => emitter.fire(), 0);
|
||||
} else {
|
||||
emitter.fire();
|
||||
}
|
||||
});
|
||||
|
||||
shouldEmit = true;
|
||||
return emitter.event;
|
||||
}
|
||||
|
||||
export function toPromise<T>(event: Event<T>): Thenable<T> {
|
||||
return new Promise(c => once(event)(c));
|
||||
}
|
||||
|
||||
export function once<T>(event: Event<T>): Event<T> {
|
||||
return (listener, thisArgs = null, disposables?) => {
|
||||
// we need this, in case the event fires during the listener call
|
||||
let didFire = false;
|
||||
|
||||
const result = event(e => {
|
||||
if (didFire) {
|
||||
return;
|
||||
} else if (result) {
|
||||
result.dispose();
|
||||
} else {
|
||||
didFire = true;
|
||||
}
|
||||
|
||||
return listener.call(thisArgs, e);
|
||||
}, null, disposables);
|
||||
|
||||
if (didFire) {
|
||||
result.dispose();
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export function anyEvent<T>(...events: Event<T>[]): Event<T> {
|
||||
return (listener, thisArgs = null, disposables?) => combinedDisposable(events.map(event => event(e => listener.call(thisArgs, e), null, disposables)));
|
||||
}
|
||||
|
||||
export function debounceEvent<T>(event: Event<T>, merger: (last: T, event: T) => T, delay?: number, leading?: boolean, leakWarningThreshold?: number): Event<T>;
|
||||
export function debounceEvent<I, O>(event: Event<I>, merger: (last: O | undefined, event: I) => O, delay?: number, leading?: boolean, leakWarningThreshold?: number): Event<O>;
|
||||
export function debounceEvent<I, O>(event: Event<I>, merger: (last: O | undefined, event: I) => O, delay: number = 100, leading = false, leakWarningThreshold?: number): Event<O> {
|
||||
|
||||
let subscription: IDisposable;
|
||||
let output: O | undefined = undefined;
|
||||
let handle: any = undefined;
|
||||
let numDebouncedCalls = 0;
|
||||
|
||||
const emitter = new Emitter<O>({
|
||||
leakWarningThreshold,
|
||||
onFirstListenerAdd() {
|
||||
subscription = event(cur => {
|
||||
numDebouncedCalls++;
|
||||
output = merger(output, cur);
|
||||
|
||||
if (leading && !handle) {
|
||||
emitter.fire(output);
|
||||
}
|
||||
|
||||
clearTimeout(handle);
|
||||
handle = setTimeout(() => {
|
||||
let _output = output;
|
||||
output = undefined;
|
||||
handle = undefined;
|
||||
if (!leading || numDebouncedCalls > 1) {
|
||||
emitter.fire(_output);
|
||||
}
|
||||
|
||||
numDebouncedCalls = 0;
|
||||
}, delay);
|
||||
});
|
||||
},
|
||||
onLastListenerRemove() {
|
||||
subscription.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
return emitter.event;
|
||||
}
|
||||
|
||||
/**
|
||||
* The EventBufferer is useful in situations in which you want
|
||||
* to delay firing your events during some code.
|
||||
@@ -485,12 +732,12 @@ export class EventBufferer {
|
||||
} else {
|
||||
listener.call(thisArgs, i);
|
||||
}
|
||||
}, void 0, disposables);
|
||||
}, undefined, disposables);
|
||||
};
|
||||
}
|
||||
|
||||
bufferEvents<R = void>(fn: () => R): R {
|
||||
const buffer: Function[] = [];
|
||||
const buffer: Array<() => R> = [];
|
||||
this.buffers.push(buffer);
|
||||
const r = fn();
|
||||
this.buffers.pop();
|
||||
@@ -499,169 +746,12 @@ export class EventBufferer {
|
||||
}
|
||||
}
|
||||
|
||||
export interface IChainableEvent<T> {
|
||||
event: Event<T>;
|
||||
map<O>(fn: (i: T) => O): IChainableEvent<O>;
|
||||
forEach(fn: (i: T) => void): IChainableEvent<T>;
|
||||
filter(fn: (e: T) => boolean): IChainableEvent<T>;
|
||||
latch(): IChainableEvent<T>;
|
||||
on(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable;
|
||||
once(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable;
|
||||
}
|
||||
|
||||
export function mapEvent<I, O>(event: Event<I>, map: (i: I) => O): Event<O> {
|
||||
return (listener, thisArgs = null, disposables?) => event(i => listener.call(thisArgs, map(i)), null, disposables);
|
||||
}
|
||||
|
||||
export function forEach<I>(event: Event<I>, each: (i: I) => void): Event<I> {
|
||||
return (listener, thisArgs = null, disposables?) => event(i => { each(i); listener.call(thisArgs, i); }, null, disposables);
|
||||
}
|
||||
|
||||
export function filterEvent<T>(event: Event<T>, filter: (e: T) => boolean): Event<T>;
|
||||
export function filterEvent<T, R>(event: Event<T | R>, filter: (e: T | R) => e is R): Event<R>;
|
||||
export function filterEvent<T>(event: Event<T>, filter: (e: T) => boolean): Event<T> {
|
||||
return (listener, thisArgs = null, disposables?) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables);
|
||||
}
|
||||
|
||||
export function signalEvent<T>(event: Event<T>): Event<void> {
|
||||
return event as Event<any> as Event<void>;
|
||||
}
|
||||
|
||||
class ChainableEvent<T> implements IChainableEvent<T> {
|
||||
|
||||
get event(): Event<T> { return this._event; }
|
||||
|
||||
constructor(private _event: Event<T>) { }
|
||||
|
||||
map<O>(fn: (i: T) => O): IChainableEvent<O> {
|
||||
return new ChainableEvent(mapEvent(this._event, fn));
|
||||
}
|
||||
|
||||
forEach(fn: (i: T) => void): IChainableEvent<T> {
|
||||
return new ChainableEvent(forEach(this._event, fn));
|
||||
}
|
||||
|
||||
filter(fn: (e: T) => boolean): IChainableEvent<T> {
|
||||
return new ChainableEvent(filterEvent(this._event, fn));
|
||||
}
|
||||
|
||||
latch(): IChainableEvent<T> {
|
||||
return new ChainableEvent(latch(this._event));
|
||||
}
|
||||
|
||||
on(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[]) {
|
||||
return this._event(listener, thisArgs, disposables);
|
||||
}
|
||||
|
||||
once(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[]) {
|
||||
return once(this._event)(listener, thisArgs, disposables);
|
||||
}
|
||||
}
|
||||
|
||||
export function chain<T>(event: Event<T>): IChainableEvent<T> {
|
||||
return new ChainableEvent(event);
|
||||
}
|
||||
|
||||
export function stopwatch<T>(event: Event<T>): Event<number> {
|
||||
const start = new Date().getTime();
|
||||
return mapEvent(once(event), _ => new Date().getTime() - start);
|
||||
}
|
||||
|
||||
/**
|
||||
* Buffers the provided event until a first listener comes
|
||||
* along, at which point fire all the events at once and
|
||||
* pipe the event from then on.
|
||||
*
|
||||
* ```typescript
|
||||
* const emitter = new Emitter<number>();
|
||||
* const event = emitter.event;
|
||||
* const bufferedEvent = buffer(event);
|
||||
*
|
||||
* emitter.fire(1);
|
||||
* emitter.fire(2);
|
||||
* emitter.fire(3);
|
||||
* // nothing...
|
||||
*
|
||||
* const listener = bufferedEvent(num => console.log(num));
|
||||
* // 1, 2, 3
|
||||
*
|
||||
* emitter.fire(4);
|
||||
* // 4
|
||||
* ```
|
||||
* A Relay is an event forwarder which functions as a replugabble event pipe.
|
||||
* Once created, you can connect an input event to it and it will simply forward
|
||||
* events from that input event through its own `event` property. The `input`
|
||||
* can be changed at any point in time.
|
||||
*/
|
||||
export function buffer<T>(event: Event<T>, nextTick = false, _buffer: T[] = []): Event<T> {
|
||||
let buffer: T[] | null = _buffer.slice();
|
||||
|
||||
let listener: IDisposable | null = event(e => {
|
||||
if (buffer) {
|
||||
buffer.push(e);
|
||||
} else {
|
||||
emitter.fire(e);
|
||||
}
|
||||
});
|
||||
|
||||
const flush = () => {
|
||||
if (buffer) {
|
||||
buffer.forEach(e => emitter.fire(e));
|
||||
}
|
||||
buffer = null;
|
||||
};
|
||||
|
||||
const emitter = new Emitter<T>({
|
||||
onFirstListenerAdd() {
|
||||
if (!listener) {
|
||||
listener = event(e => emitter.fire(e));
|
||||
}
|
||||
},
|
||||
|
||||
onFirstListenerDidAdd() {
|
||||
if (buffer) {
|
||||
if (nextTick) {
|
||||
setTimeout(flush);
|
||||
} else {
|
||||
flush();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onLastListenerRemove() {
|
||||
if (listener) {
|
||||
listener.dispose();
|
||||
}
|
||||
listener = null;
|
||||
}
|
||||
});
|
||||
|
||||
return emitter.event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to `buffer` but it buffers indefinitely and repeats
|
||||
* the buffered events to every new listener.
|
||||
*/
|
||||
export function echo<T>(event: Event<T>, nextTick = false, buffer: T[] = []): Event<T> {
|
||||
buffer = buffer.slice();
|
||||
|
||||
event(e => {
|
||||
buffer.push(e);
|
||||
emitter.fire(e);
|
||||
});
|
||||
|
||||
const flush = (listener: (e: T) => any, thisArgs?: any) => buffer.forEach(e => listener.call(thisArgs, e));
|
||||
|
||||
const emitter = new Emitter<T>({
|
||||
onListenerDidAdd(emitter, listener: (e: T) => any, thisArgs?: any) {
|
||||
if (nextTick) {
|
||||
setTimeout(() => flush(listener, thisArgs));
|
||||
} else {
|
||||
flush(listener, thisArgs);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return emitter.event;
|
||||
}
|
||||
|
||||
export class Relay<T> implements IDisposable {
|
||||
|
||||
private listening = false;
|
||||
@@ -695,29 +785,3 @@ export class Relay<T> implements IDisposable {
|
||||
this.emitter.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export interface NodeEventEmitter {
|
||||
on(event: string | symbol, listener: Function): this;
|
||||
removeListener(event: string | symbol, listener: Function): this;
|
||||
}
|
||||
|
||||
export function fromNodeEventEmitter<T>(emitter: NodeEventEmitter, eventName: string, map: (...args: any[]) => T = id => id): Event<T> {
|
||||
const fn = (...args: any[]) => result.fire(map(...args));
|
||||
const onFirstListenerAdd = () => emitter.on(eventName, fn);
|
||||
const onLastListenerRemove = () => emitter.removeListener(eventName, fn);
|
||||
const result = new Emitter<T>({ onFirstListenerAdd, onLastListenerRemove });
|
||||
|
||||
return result.event;
|
||||
}
|
||||
|
||||
export function latch<T>(event: Event<T>): Event<T> {
|
||||
let firstCall = true;
|
||||
let cache: T;
|
||||
|
||||
return filterEvent(event, value => {
|
||||
let shouldEmit = firstCall || value !== cache;
|
||||
firstCall = false;
|
||||
cache = value;
|
||||
return shouldEmit;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ function nextWord(word: string, start: number): number {
|
||||
|
||||
// Fuzzy
|
||||
|
||||
export const fuzzyContiguousFilter = or(matchesPrefix, matchesCamelCase, matchesContiguousSubString);
|
||||
const fuzzyContiguousFilter = or(matchesPrefix, matchesCamelCase, matchesContiguousSubString);
|
||||
const fuzzySeparateFilter = or(matchesPrefix, matchesCamelCase, matchesSubString);
|
||||
const fuzzyRegExpCache = new LRUCache<string, RegExp>(10000); // bounded to 10000 elements
|
||||
|
||||
@@ -343,54 +343,67 @@ export function matchesFuzzy(word: string, wordToMatchAgainst: string, enableSep
|
||||
return enableSeparateSubstringMatching ? fuzzySeparateFilter(word, wordToMatchAgainst) : fuzzyContiguousFilter(word, wordToMatchAgainst);
|
||||
}
|
||||
|
||||
export function anyScore(pattern: string, word: string, patternMaxWhitespaceIgnore?: number): FuzzyScore {
|
||||
pattern = pattern.toLowerCase();
|
||||
word = word.toLowerCase();
|
||||
/**
|
||||
* Match pattern againt word in a fuzzy way. As in IntelliSense and faster and more
|
||||
* powerfull than `matchesFuzzy`
|
||||
*/
|
||||
export function matchesFuzzy2(pattern: string, word: string): IMatch[] | null {
|
||||
let score = fuzzyScore(pattern, pattern.toLowerCase(), 0, word, word.toLowerCase(), 0, true);
|
||||
return score ? createMatches(score) : null;
|
||||
}
|
||||
|
||||
const matches: number[] = [];
|
||||
let idx = 0;
|
||||
for (let pos = 0; pos < pattern.length; ++pos) {
|
||||
const thisIdx = word.indexOf(pattern.charAt(pos), idx);
|
||||
if (thisIdx >= 0) {
|
||||
matches.push(thisIdx);
|
||||
idx = thisIdx + 1;
|
||||
export function anyScore(pattern: string, lowPattern: string, _patternPos: number, word: string, lowWord: string, _wordPos: number): FuzzyScore {
|
||||
const result = fuzzyScore(pattern, lowPattern, 0, word, lowWord, 0, true);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
let matches = 0;
|
||||
let score = 0;
|
||||
let idx = _wordPos;
|
||||
for (let patternPos = 0; patternPos < lowPattern.length && patternPos < _maxLen; ++patternPos) {
|
||||
const wordPos = lowWord.indexOf(lowPattern.charAt(patternPos), idx);
|
||||
if (wordPos >= 0) {
|
||||
score += 1;
|
||||
matches += 2 ** wordPos;
|
||||
idx = wordPos + 1;
|
||||
}
|
||||
}
|
||||
return [matches.length, matches];
|
||||
return [score, matches, _wordPos];
|
||||
}
|
||||
|
||||
//#region --- fuzzyScore ---
|
||||
|
||||
export function createMatches(offsetOrScore: number[] | FuzzyScore): IMatch[] {
|
||||
let ret: IMatch[] = [];
|
||||
if (!offsetOrScore) {
|
||||
return ret;
|
||||
export function createMatches(score: undefined | FuzzyScore): IMatch[] {
|
||||
if (typeof score === 'undefined') {
|
||||
return [];
|
||||
}
|
||||
let offsets: number[];
|
||||
if (Array.isArray(offsetOrScore[1])) {
|
||||
offsets = (offsetOrScore as FuzzyScore)[1];
|
||||
} else {
|
||||
offsets = offsetOrScore as number[];
|
||||
}
|
||||
let last: IMatch | undefined;
|
||||
for (const pos of offsets) {
|
||||
if (last && last.end === pos) {
|
||||
last.end += 1;
|
||||
} else {
|
||||
last = { start: pos, end: pos + 1 };
|
||||
ret.push(last);
|
||||
|
||||
const matches = score[1].toString(2);
|
||||
const wordStart = score[2];
|
||||
const res: IMatch[] = [];
|
||||
|
||||
for (let pos = wordStart; pos < _maxLen; pos++) {
|
||||
if (matches[matches.length - (pos + 1)] === '1') {
|
||||
const last = res[res.length - 1];
|
||||
if (last && last.end === pos) {
|
||||
last.end = pos + 1;
|
||||
} else {
|
||||
res.push({ start: pos, end: pos + 1 });
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
return res;
|
||||
}
|
||||
|
||||
const _maxLen = 53;
|
||||
|
||||
function initTable() {
|
||||
const table: number[][] = [];
|
||||
const row: number[] = [0];
|
||||
for (let i = 1; i <= 100; i++) {
|
||||
for (let i = 1; i <= _maxLen; i++) {
|
||||
row.push(-i);
|
||||
}
|
||||
for (let i = 0; i <= 100; i++) {
|
||||
for (let i = 0; i <= _maxLen; i++) {
|
||||
let thisRow = row.slice(0);
|
||||
thisRow[0] = -i;
|
||||
table.push(thisRow);
|
||||
@@ -438,6 +451,7 @@ function isSeparatorAtPos(value: string, index: number): boolean {
|
||||
case CharCode.SingleQuote:
|
||||
case CharCode.DoubleQuote:
|
||||
case CharCode.Colon:
|
||||
case CharCode.DollarSign:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -458,18 +472,49 @@ function isWhitespaceAtPos(value: string, index: number): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
function isUpperCaseAtPos(pos: number, word: string, wordLow: string): boolean {
|
||||
return word[pos] !== wordLow[pos];
|
||||
}
|
||||
|
||||
function isPatternInWord(patternLow: string, patternPos: number, patternLen: number, wordLow: string, wordPos: number, wordLen: number): boolean {
|
||||
while (patternPos < patternLen && wordPos < wordLen) {
|
||||
if (patternLow[patternPos] === wordLow[wordPos]) {
|
||||
patternPos += 1;
|
||||
}
|
||||
wordPos += 1;
|
||||
}
|
||||
return patternPos === patternLen; // pattern must be exhausted
|
||||
}
|
||||
|
||||
const enum Arrow { Top = 0b1, Diag = 0b10, Left = 0b100 }
|
||||
|
||||
export type FuzzyScore = [number, number[]];
|
||||
/**
|
||||
* A tuple of three values.
|
||||
* 0. the score
|
||||
* 1. the matches encoded as bitmask (2^53)
|
||||
* 2. the offset at which matching started
|
||||
*/
|
||||
export type FuzzyScore = [number, number, number];
|
||||
|
||||
export namespace FuzzyScore {
|
||||
/**
|
||||
* No matches and value `-100`
|
||||
*/
|
||||
export const Default: [-100, 0, 0] = [-100, 0, 0];
|
||||
|
||||
export function isDefault(score?: FuzzyScore): score is [-100, 0, 0] {
|
||||
return !score || (score[0] === -100 && score[1] === 0 && score[2] === 0);
|
||||
}
|
||||
}
|
||||
|
||||
export interface FuzzyScorer {
|
||||
(pattern: string, lowPattern: string, patternPos: number, word: string, lowWord: string, wordPos: number, firstMatchCanBeWeak: boolean): FuzzyScore | undefined;
|
||||
}
|
||||
|
||||
export function fuzzyScore(pattern: string, lowPattern: string, patternPos: number, word: string, lowWord: string, wordPos: number, firstMatchCanBeWeak: boolean): FuzzyScore | undefined {
|
||||
export function fuzzyScore(pattern: string, patternLow: string, patternPos: number, word: string, wordLow: string, wordPos: number, firstMatchCanBeWeak: boolean): FuzzyScore | undefined {
|
||||
|
||||
const patternLen = pattern.length > 100 ? 100 : pattern.length;
|
||||
const wordLen = word.length > 100 ? 100 : word.length;
|
||||
const patternLen = pattern.length > _maxLen ? _maxLen : pattern.length;
|
||||
const wordLen = word.length > _maxLen ? _maxLen : word.length;
|
||||
|
||||
if (patternPos >= patternLen || wordPos >= wordLen || patternLen > wordLen) {
|
||||
return undefined;
|
||||
@@ -478,20 +523,12 @@ export function fuzzyScore(pattern: string, lowPattern: string, patternPos: numb
|
||||
// Run a simple check if the characters of pattern occur
|
||||
// (in order) at all in word. If that isn't the case we
|
||||
// stop because no match will be possible
|
||||
const patternStartPos = patternPos;
|
||||
const wordStartPos = wordPos;
|
||||
while (patternPos < patternLen && wordPos < wordLen) {
|
||||
if (lowPattern[patternPos] === lowWord[wordPos]) {
|
||||
patternPos += 1;
|
||||
}
|
||||
wordPos += 1;
|
||||
}
|
||||
if (patternPos !== patternLen) {
|
||||
if (!isPatternInWord(patternLow, patternPos, patternLen, wordLow, wordPos, wordLen)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
patternPos = patternStartPos;
|
||||
wordPos = wordStartPos;
|
||||
const patternStartPos = patternPos;
|
||||
const wordStartPos = wordPos;
|
||||
|
||||
// There will be a mach, fill in tables
|
||||
for (patternPos = patternStartPos + 1; patternPos <= patternLen; patternPos++) {
|
||||
@@ -499,24 +536,27 @@ export function fuzzyScore(pattern: string, lowPattern: string, patternPos: numb
|
||||
for (wordPos = 1; wordPos <= wordLen; wordPos++) {
|
||||
|
||||
let score = -1;
|
||||
let lowWordChar = lowWord[wordPos - 1];
|
||||
if (lowPattern[patternPos - 1] === lowWordChar) {
|
||||
if (patternLow[patternPos - 1] === wordLow[wordPos - 1]) {
|
||||
|
||||
if (wordPos === (patternPos - patternStartPos)) {
|
||||
// common prefix: `foobar <-> foobaz`
|
||||
// ^^^^^
|
||||
if (pattern[patternPos - 1] === word[wordPos - 1]) {
|
||||
score = 7;
|
||||
} else {
|
||||
score = 5;
|
||||
}
|
||||
} else if (lowWordChar !== word[wordPos - 1] && (wordPos === 1 || lowWord[wordPos - 2] === word[wordPos - 2])) {
|
||||
} else if (isUpperCaseAtPos(wordPos - 1, word, wordLow) && (wordPos === 1 || !isUpperCaseAtPos(wordPos - 2, word, wordLow))) {
|
||||
// hitting upper-case: `foo <-> forOthers`
|
||||
// ^^ ^
|
||||
if (pattern[patternPos - 1] === word[wordPos - 1]) {
|
||||
score = 7;
|
||||
} else {
|
||||
score = 5;
|
||||
}
|
||||
} else if (isSeparatorAtPos(lowWord, wordPos - 2) || isWhitespaceAtPos(lowWord, wordPos - 2)) {
|
||||
} else if (isSeparatorAtPos(wordLow, wordPos - 2) || isWhitespaceAtPos(wordLow, wordPos - 2)) {
|
||||
// post separator: `foo <-> bar_foo`
|
||||
// ^^^
|
||||
score = 5;
|
||||
|
||||
} else {
|
||||
@@ -564,29 +604,26 @@ export function fuzzyScore(pattern: string, lowPattern: string, patternPos: numb
|
||||
console.log(printTable(_scores, pattern, patternLen, word, wordLen));
|
||||
}
|
||||
|
||||
// _bucket is an array of [PrefixArray] we use to keep
|
||||
// track of scores and matches. After calling `_findAllMatches`
|
||||
// the best match (if available) is the first item in the array
|
||||
_matchesCount = 0;
|
||||
_topScore = -100;
|
||||
_patternStartPos = patternStartPos;
|
||||
_firstMatchCanBeWeak = firstMatchCanBeWeak;
|
||||
_findAllMatches(patternLen, wordLen, patternLen === wordLen ? 1 : 0, new LazyArray(), false);
|
||||
|
||||
_findAllMatches2(patternLen, wordLen, patternLen === wordLen ? 1 : 0, 0, false);
|
||||
if (_matchesCount === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return [_topScore, _topMatch.toArray()];
|
||||
return [_topScore, _topMatch2, wordStartPos];
|
||||
}
|
||||
|
||||
|
||||
let _matchesCount: number = 0;
|
||||
let _topMatch: LazyArray;
|
||||
let _topMatch2: number = 0;
|
||||
let _topScore: number = 0;
|
||||
let _patternStartPos: number = 0;
|
||||
let _firstMatchCanBeWeak: boolean = false;
|
||||
|
||||
function _findAllMatches(patternPos: number, wordPos: number, total: number, matches: LazyArray, lastMatched: boolean): void {
|
||||
function _findAllMatches2(patternPos: number, wordPos: number, total: number, matches: number, lastMatched: boolean): void {
|
||||
|
||||
if (_matchesCount >= 10 || total < -25) {
|
||||
// stop when having already 10 results, or
|
||||
@@ -602,11 +639,11 @@ function _findAllMatches(patternPos: number, wordPos: number, total: number, mat
|
||||
let arrow = _arrows[patternPos][wordPos];
|
||||
|
||||
if (arrow === Arrow.Left) {
|
||||
// left
|
||||
// left -> no match, skip a word character
|
||||
wordPos -= 1;
|
||||
if (lastMatched) {
|
||||
total -= 5; // new gap penalty
|
||||
} else if (!matches.isEmpty()) {
|
||||
} else if (matches !== 0) {
|
||||
total -= 1; // gap penalty after first match
|
||||
}
|
||||
lastMatched = false;
|
||||
@@ -616,11 +653,11 @@ function _findAllMatches(patternPos: number, wordPos: number, total: number, mat
|
||||
|
||||
if (arrow & Arrow.Left) {
|
||||
// left
|
||||
_findAllMatches(
|
||||
_findAllMatches2(
|
||||
patternPos,
|
||||
wordPos - 1,
|
||||
!matches.isEmpty() ? total - 1 : total, // gap penalty after first match
|
||||
matches.slice(),
|
||||
matches !== 0 ? total - 1 : total, // gap penalty after first match
|
||||
matches,
|
||||
lastMatched
|
||||
);
|
||||
}
|
||||
@@ -629,9 +666,11 @@ function _findAllMatches(patternPos: number, wordPos: number, total: number, mat
|
||||
total += score;
|
||||
patternPos -= 1;
|
||||
wordPos -= 1;
|
||||
matches.unshift(wordPos);
|
||||
lastMatched = true;
|
||||
|
||||
// match -> set a 1 at the word pos
|
||||
matches += 2 ** wordPos;
|
||||
|
||||
// count simple matches and boost a row of
|
||||
// simple matches when they yield in a
|
||||
// strong match.
|
||||
@@ -662,47 +701,7 @@ function _findAllMatches(patternPos: number, wordPos: number, total: number, mat
|
||||
_matchesCount += 1;
|
||||
if (total > _topScore) {
|
||||
_topScore = total;
|
||||
_topMatch = matches;
|
||||
}
|
||||
}
|
||||
|
||||
class LazyArray {
|
||||
|
||||
private _parent: LazyArray;
|
||||
private _parentLen: number;
|
||||
private _data: number[];
|
||||
|
||||
isEmpty(): boolean {
|
||||
return !this._data && (!this._parent || this._parent.isEmpty());
|
||||
}
|
||||
|
||||
unshift(n: number) {
|
||||
if (!this._data) {
|
||||
this._data = [n];
|
||||
} else {
|
||||
this._data.unshift(n);
|
||||
}
|
||||
}
|
||||
|
||||
slice(): LazyArray {
|
||||
const ret = new LazyArray();
|
||||
ret._parent = this;
|
||||
ret._parentLen = this._data ? this._data.length : 0; return ret;
|
||||
}
|
||||
|
||||
toArray(): number[] {
|
||||
if (!this._data) {
|
||||
return this._parent.toArray();
|
||||
}
|
||||
const bucket: number[][] = [];
|
||||
let element = <LazyArray>this;
|
||||
while (element) {
|
||||
if (element._parent && element._parent._data) {
|
||||
bucket.push(element._parent._data.slice(element._parent._data.length - element._parentLen));
|
||||
}
|
||||
element = element._parent;
|
||||
}
|
||||
return Array.prototype.concat.apply(this._data, bucket);
|
||||
_topMatch2 = matches;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,11 +58,8 @@ export function splitGlobAware(pattern: string, splitChar: string): string[] {
|
||||
let inBraces = false;
|
||||
let inBrackets = false;
|
||||
|
||||
let char: string;
|
||||
let curVal = '';
|
||||
for (let i = 0; i < pattern.length; i++) {
|
||||
char = pattern[i];
|
||||
|
||||
for (const char of pattern) {
|
||||
switch (char) {
|
||||
case splitChar:
|
||||
if (!inBraces && !inBrackets) {
|
||||
@@ -136,10 +133,7 @@ function parseRegExp(pattern: string): string {
|
||||
let inBrackets = false;
|
||||
let bracketVal = '';
|
||||
|
||||
let char: string;
|
||||
for (let i = 0; i < segment.length; i++) {
|
||||
char = segment[i];
|
||||
|
||||
for (const char of segment) {
|
||||
// Support brace expansion
|
||||
if (char !== '}' && inBraces) {
|
||||
braceVal += char;
|
||||
@@ -658,7 +652,7 @@ function parseExpressionPattern(pattern: string, value: any, options: IGlobOptio
|
||||
return parsedPattern;
|
||||
}
|
||||
|
||||
function aggregateBasenameMatches(parsedPatterns: (ParsedStringPattern | ParsedExpressionPattern)[], result?: string): (ParsedStringPattern | ParsedExpressionPattern)[] {
|
||||
function aggregateBasenameMatches(parsedPatterns: Array<ParsedStringPattern | ParsedExpressionPattern>, result?: string): Array<ParsedStringPattern | ParsedExpressionPattern> {
|
||||
const basenamePatterns = parsedPatterns.filter(parsedPattern => !!(<ParsedStringPattern>parsedPattern).basenames);
|
||||
if (basenamePatterns.length < 2) {
|
||||
return parsedPatterns;
|
||||
|
||||
@@ -16,7 +16,6 @@ export class MarkdownString implements IMarkdownString {
|
||||
|
||||
value: string;
|
||||
isTrusted?: boolean;
|
||||
sanitize: boolean = true;
|
||||
|
||||
constructor(value: string = '') {
|
||||
this.value = value;
|
||||
@@ -58,7 +57,7 @@ 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 === void 0);
|
||||
&& (typeof (<IMarkdownString>thing).isTrusted === 'boolean' || (<IMarkdownString>thing).isTrusted === undefined);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -205,10 +205,10 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON
|
||||
token: SyntaxKind = SyntaxKind.Unknown,
|
||||
scanError: ScanError = ScanError.None;
|
||||
|
||||
function scanHexDigits(count: number, exact?: boolean): number {
|
||||
function scanHexDigits(count: number): number {
|
||||
let digits = 0;
|
||||
let value = 0;
|
||||
while (digits < count || !exact) {
|
||||
while (digits < count) {
|
||||
let ch = text.charCodeAt(pos);
|
||||
if (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) {
|
||||
value = value * 16 + ch - CharacterCodes._0;
|
||||
@@ -331,7 +331,7 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON
|
||||
result += '\t';
|
||||
break;
|
||||
case CharacterCodes.u:
|
||||
let ch = scanHexDigits(4, true);
|
||||
let ch = scanHexDigits(4);
|
||||
if (ch >= 0) {
|
||||
result += String.fromCharCode(ch);
|
||||
} else {
|
||||
@@ -344,7 +344,7 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON
|
||||
start = pos;
|
||||
continue;
|
||||
}
|
||||
if (ch >= 0 && ch <= 0x1f) {
|
||||
if (ch >= 0 && ch <= 0x1F) {
|
||||
if (isLineBreak(ch)) {
|
||||
result += text.substring(start, pos);
|
||||
scanError = ScanError.UnexpectedEndOfString;
|
||||
@@ -668,7 +668,7 @@ const enum CharacterCodes {
|
||||
W = 0x57,
|
||||
X = 0x58,
|
||||
Y = 0x59,
|
||||
Z = 0x5a,
|
||||
Z = 0x5A,
|
||||
|
||||
ampersand = 0x26, // &
|
||||
asterisk = 0x2A, // *
|
||||
@@ -722,13 +722,13 @@ interface NodeImpl extends Node {
|
||||
export function getLocation(text: string, position: number): Location {
|
||||
let segments: Segment[] = []; // strings or numbers
|
||||
let earlyReturnException = new Object();
|
||||
let previousNode: NodeImpl | undefined = void 0;
|
||||
let previousNode: NodeImpl | undefined = undefined;
|
||||
const previousNodeInst: NodeImpl = {
|
||||
value: {},
|
||||
offset: 0,
|
||||
length: 0,
|
||||
type: 'object',
|
||||
parent: void 0
|
||||
parent: undefined
|
||||
};
|
||||
let isAtPropertyKey = false;
|
||||
function setPreviousNode(value: string, offset: number, length: number, type: NodeType) {
|
||||
@@ -736,7 +736,7 @@ export function getLocation(text: string, position: number): Location {
|
||||
previousNodeInst.offset = offset;
|
||||
previousNodeInst.length = length;
|
||||
previousNodeInst.type = type;
|
||||
previousNodeInst.colonOffset = void 0;
|
||||
previousNodeInst.colonOffset = undefined;
|
||||
previousNode = previousNodeInst;
|
||||
}
|
||||
try {
|
||||
@@ -746,7 +746,7 @@ export function getLocation(text: string, position: number): Location {
|
||||
if (position <= offset) {
|
||||
throw earlyReturnException;
|
||||
}
|
||||
previousNode = void 0;
|
||||
previousNode = undefined;
|
||||
isAtPropertyKey = position > offset;
|
||||
segments.push(''); // push a placeholder (will be replaced)
|
||||
},
|
||||
@@ -764,21 +764,21 @@ export function getLocation(text: string, position: number): Location {
|
||||
if (position <= offset) {
|
||||
throw earlyReturnException;
|
||||
}
|
||||
previousNode = void 0;
|
||||
previousNode = undefined;
|
||||
segments.pop();
|
||||
},
|
||||
onArrayBegin: (offset: number, length: number) => {
|
||||
if (position <= offset) {
|
||||
throw earlyReturnException;
|
||||
}
|
||||
previousNode = void 0;
|
||||
previousNode = undefined;
|
||||
segments.push(0);
|
||||
},
|
||||
onArrayEnd: (offset: number, length: number) => {
|
||||
if (position <= offset) {
|
||||
throw earlyReturnException;
|
||||
}
|
||||
previousNode = void 0;
|
||||
previousNode = undefined;
|
||||
segments.pop();
|
||||
},
|
||||
onLiteralValue: (value: any, offset: number, length: number) => {
|
||||
@@ -798,7 +798,7 @@ export function getLocation(text: string, position: number): Location {
|
||||
if (sep === ':' && previousNode && previousNode.type === 'property') {
|
||||
previousNode.colonOffset = offset;
|
||||
isAtPropertyKey = false;
|
||||
previousNode = void 0;
|
||||
previousNode = undefined;
|
||||
} else if (sep === ',') {
|
||||
let last = segments[segments.length - 1];
|
||||
if (typeof last === 'number') {
|
||||
@@ -807,7 +807,7 @@ export function getLocation(text: string, position: number): Location {
|
||||
isAtPropertyKey = true;
|
||||
segments[segments.length - 1] = '';
|
||||
}
|
||||
previousNode = void 0;
|
||||
previousNode = undefined;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -891,7 +891,7 @@ export function parse(text: string, errors: ParseError[] = [], options: ParseOpt
|
||||
* Parses the given text and returns a tree representation the JSON content. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.
|
||||
*/
|
||||
export function parseTree(text: string, errors: ParseError[] = [], options: ParseOptions = ParseOptions.DEFAULT): Node {
|
||||
let currentParent: NodeImpl = { type: 'array', offset: -1, length: -1, children: [], parent: void 0 }; // artificial root
|
||||
let currentParent: NodeImpl = { type: 'array', offset: -1, length: -1, children: [], parent: undefined }; // artificial root
|
||||
|
||||
function ensurePropertyComplete(endOffset: number) {
|
||||
if (currentParent.type === 'property') {
|
||||
@@ -957,13 +957,13 @@ export function parseTree(text: string, errors: ParseError[] = [], options: Pars
|
||||
*/
|
||||
export function findNodeAtLocation(root: Node, path: JSONPath): Node | undefined {
|
||||
if (!root) {
|
||||
return void 0;
|
||||
return undefined;
|
||||
}
|
||||
let node = root;
|
||||
for (let segment of path) {
|
||||
if (typeof segment === 'string') {
|
||||
if (node.type !== 'object' || !Array.isArray(node.children)) {
|
||||
return void 0;
|
||||
return undefined;
|
||||
}
|
||||
let found = false;
|
||||
for (const propertyNode of node.children) {
|
||||
@@ -974,12 +974,12 @@ export function findNodeAtLocation(root: Node, path: JSONPath): Node | undefined
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return void 0;
|
||||
return undefined;
|
||||
}
|
||||
} else {
|
||||
let index = <number>segment;
|
||||
if (node.type !== 'array' || index < 0 || !Array.isArray(node.children) || index >= node.children.length) {
|
||||
return void 0;
|
||||
return undefined;
|
||||
}
|
||||
node = node.children[index];
|
||||
}
|
||||
@@ -1029,7 +1029,7 @@ export function getNodeValue(node: Node): any {
|
||||
case 'boolean':
|
||||
return node.value;
|
||||
default:
|
||||
return void 0;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1055,7 +1055,7 @@ export function findNodeAtOffset(node: Node, offset: number, includeRightBound =
|
||||
}
|
||||
return node;
|
||||
}
|
||||
return void 0;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -1322,7 +1322,7 @@ export function stripComments(text: string, replaceCh?: string): string {
|
||||
if (offset !== pos) {
|
||||
parts.push(text.substring(offset, pos));
|
||||
}
|
||||
if (replaceCh !== void 0) {
|
||||
if (replaceCh !== undefined) {
|
||||
parts.push(_scanner.getTokenValue().replace(/[^\r\n]/g, replaceCh));
|
||||
}
|
||||
offset = _scanner.getPosition();
|
||||
|
||||
@@ -8,20 +8,20 @@ import { Edit, format, isEOL, FormattingOptions } from './jsonFormatter';
|
||||
|
||||
|
||||
export function removeProperty(text: string, path: JSONPath, formattingOptions: FormattingOptions): Edit[] {
|
||||
return setProperty(text, path, void 0, formattingOptions);
|
||||
return setProperty(text, path, undefined, formattingOptions);
|
||||
}
|
||||
|
||||
export function setProperty(text: string, originalPath: JSONPath, value: any, formattingOptions: FormattingOptions, getInsertionIndex?: (properties: string[]) => number): Edit[] {
|
||||
let path = originalPath.slice();
|
||||
let errors: ParseError[] = [];
|
||||
let root = parseTree(text, errors);
|
||||
let parent: Node | undefined = void 0;
|
||||
let parent: Node | undefined = undefined;
|
||||
|
||||
let lastSegment: Segment | undefined = void 0;
|
||||
let lastSegment: Segment | undefined = undefined;
|
||||
while (path.length > 0) {
|
||||
lastSegment = path.pop();
|
||||
parent = findNodeAtLocation(root, path);
|
||||
if (parent === void 0 && value !== void 0) {
|
||||
if (parent === undefined && value !== undefined) {
|
||||
if (typeof lastSegment === 'string') {
|
||||
value = { [lastSegment]: value };
|
||||
} else {
|
||||
@@ -34,14 +34,14 @@ export function setProperty(text: string, originalPath: JSONPath, value: any, fo
|
||||
|
||||
if (!parent) {
|
||||
// empty document
|
||||
if (value === void 0) { // delete
|
||||
if (value === undefined) { // delete
|
||||
throw new Error('Can not delete in empty document');
|
||||
}
|
||||
return withFormatting(text, { offset: root ? root.offset : 0, length: root ? root.length : 0, content: JSON.stringify(value) }, formattingOptions);
|
||||
} else if (parent.type === 'object' && typeof lastSegment === 'string' && Array.isArray(parent.children)) {
|
||||
let existing = findNodeAtLocation(parent, [lastSegment]);
|
||||
if (existing !== void 0) {
|
||||
if (value === void 0) { // delete
|
||||
if (existing !== undefined) {
|
||||
if (value === undefined) { // delete
|
||||
if (!existing.parent) {
|
||||
throw new Error('Malformed AST');
|
||||
}
|
||||
@@ -66,7 +66,7 @@ export function setProperty(text: string, originalPath: JSONPath, value: any, fo
|
||||
return withFormatting(text, { offset: existing.offset, length: existing.length, content: JSON.stringify(value) }, formattingOptions);
|
||||
}
|
||||
} else {
|
||||
if (value === void 0) { // delete
|
||||
if (value === undefined) { // delete
|
||||
return []; // property does not exist, nothing to do
|
||||
}
|
||||
let newProperty = `${JSON.stringify(lastSegment)}: ${JSON.stringify(value)}`;
|
||||
@@ -96,7 +96,7 @@ export function setProperty(text: string, originalPath: JSONPath, value: any, fo
|
||||
}
|
||||
return withFormatting(text, edit, formattingOptions);
|
||||
} else {
|
||||
if (value === void 0 && parent.children.length >= 0) {
|
||||
if (value === undefined && parent.children.length >= 0) {
|
||||
//Removal
|
||||
let removalIndex = lastSegment;
|
||||
let toRemove = parent.children[removalIndex];
|
||||
|
||||
@@ -395,7 +395,7 @@ const enum BinaryKeybindingsMask {
|
||||
Shift = (1 << 10) >>> 0,
|
||||
Alt = (1 << 9) >>> 0,
|
||||
WinCtrl = (1 << 8) >>> 0,
|
||||
KeyCode = 0x000000ff
|
||||
KeyCode = 0x000000FF
|
||||
}
|
||||
|
||||
export const enum KeyMod {
|
||||
@@ -406,7 +406,7 @@ export const enum KeyMod {
|
||||
}
|
||||
|
||||
export function KeyChord(firstPart: number, secondPart: number): number {
|
||||
let chordPart = ((secondPart & 0x0000ffff) << 16) >>> 0;
|
||||
let chordPart = ((secondPart & 0x0000FFFF) << 16) >>> 0;
|
||||
return (firstPart | chordPart) >>> 0;
|
||||
}
|
||||
|
||||
@@ -414,8 +414,8 @@ export function createKeybinding(keybinding: number, OS: OperatingSystem): Keybi
|
||||
if (keybinding === 0) {
|
||||
return null;
|
||||
}
|
||||
const firstPart = (keybinding & 0x0000ffff) >>> 0;
|
||||
const chordPart = (keybinding & 0xffff0000) >>> 16;
|
||||
const firstPart = (keybinding & 0x0000FFFF) >>> 0;
|
||||
const chordPart = (keybinding & 0xFFFF0000) >>> 16;
|
||||
if (chordPart !== 0) {
|
||||
return new ChordKeybinding(
|
||||
createSimpleKeybinding(firstPart, OS),
|
||||
|
||||
@@ -70,7 +70,9 @@ export function getPathLabel(resource: URI | string, userHomeProvider?: IUserHom
|
||||
return res;
|
||||
}
|
||||
|
||||
export function getBaseLabel(resource: URI | string): string | undefined {
|
||||
export function getBaseLabel(resource: URI | string): string;
|
||||
export function getBaseLabel(resource: URI | string | undefined): string | undefined;
|
||||
export function getBaseLabel(resource: URI | string | undefined): string | undefined {
|
||||
if (!resource) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -108,7 +110,7 @@ export function tildify(path: string, userHome: string): string {
|
||||
}
|
||||
|
||||
// Keep a normalized user home path as cache to prevent accumulated string creation
|
||||
let normalizedUserHome = normalizedUserHomeCached.original === userHome ? normalizedUserHomeCached.normalized : void 0;
|
||||
let normalizedUserHome = normalizedUserHomeCached.original === userHome ? normalizedUserHomeCached.normalized : undefined;
|
||||
if (!normalizedUserHome) {
|
||||
normalizedUserHome = `${rtrim(userHome, sep)}${sep}`;
|
||||
normalizedUserHomeCached = { original: userHome, normalized: normalizedUserHome };
|
||||
@@ -284,11 +286,8 @@ export function template(template: string, values: { [key: string]: string | ISe
|
||||
const segments: ISegment[] = [];
|
||||
|
||||
let inVariable = false;
|
||||
let char: string;
|
||||
let curVal = '';
|
||||
for (let i = 0; i < template.length; i++) {
|
||||
char = template[i];
|
||||
|
||||
for (const char of template) {
|
||||
// Beginning of variable
|
||||
if (char === '$' || (inVariable && char === '{')) {
|
||||
if (curVal) {
|
||||
@@ -364,7 +363,7 @@ export function mnemonicMenuLabel(label: string, forceDisableMnemonics?: boolean
|
||||
|
||||
/**
|
||||
* Handles mnemonics for buttons. Depending on OS:
|
||||
* - Windows: Supported via & character (replace && with &)
|
||||
* - Windows: Supported via & character (replace && with & and & with && for escaping)
|
||||
* - Linux: Supported via _ character (replace && with _)
|
||||
* - macOS: Unsupported (replace && with empty string)
|
||||
*/
|
||||
@@ -373,7 +372,11 @@ export function mnemonicButtonLabel(label: string): string {
|
||||
return label.replace(/\(&&\w\)|&&/g, '');
|
||||
}
|
||||
|
||||
return label.replace(/&&/g, isWindows ? '&' : '_');
|
||||
if (isWindows) {
|
||||
return label.replace(/&&|&/g, m => m === '&' ? '&&' : '&');
|
||||
}
|
||||
|
||||
return label.replace(/&&/g, '_');
|
||||
}
|
||||
|
||||
export function unmnemonicLabel(label: string): string {
|
||||
|
||||
@@ -15,7 +15,7 @@ export function isDisposable<E extends object>(thing: E): thing is E & IDisposab
|
||||
}
|
||||
|
||||
export function dispose<T extends IDisposable>(disposable: T): T;
|
||||
export function dispose<T extends IDisposable>(...disposables: (T | undefined)[]): T[];
|
||||
export function dispose<T extends IDisposable>(...disposables: Array<T | undefined>): T[];
|
||||
export function dispose<T extends IDisposable>(disposables: T[]): T[];
|
||||
export function dispose<T extends IDisposable>(first: T | T[], ...rest: T[]): T | T[] | undefined {
|
||||
if (Array.isArray(first)) {
|
||||
@@ -49,12 +49,20 @@ export abstract class Disposable implements IDisposable {
|
||||
protected _toDispose: IDisposable[] = [];
|
||||
protected get toDispose(): IDisposable[] { return this._toDispose; }
|
||||
|
||||
private _lifecycle_disposable_isDisposed = false;
|
||||
|
||||
public dispose(): void {
|
||||
this._lifecycle_disposable_isDisposed = true;
|
||||
this._toDispose = dispose(this._toDispose);
|
||||
}
|
||||
|
||||
protected _register<T extends IDisposable>(t: T): T {
|
||||
this._toDispose.push(t);
|
||||
if (this._lifecycle_disposable_isDisposed) {
|
||||
console.warn('Registering disposable on object that has already been disposed.');
|
||||
t.dispose();
|
||||
} else {
|
||||
this._toDispose.push(t);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -32,17 +32,18 @@ export class LinkedList<E> {
|
||||
clear(): void {
|
||||
this._first = undefined;
|
||||
this._last = undefined;
|
||||
this._size = 0;
|
||||
}
|
||||
|
||||
unshift(element: E) {
|
||||
return this.insert(element, false);
|
||||
unshift(element: E): () => void {
|
||||
return this._insert(element, false);
|
||||
}
|
||||
|
||||
push(element: E) {
|
||||
return this.insert(element, true);
|
||||
push(element: E): () => void {
|
||||
return this._insert(element, true);
|
||||
}
|
||||
|
||||
private insert(element: E, atTheEnd: boolean) {
|
||||
private _insert(element: E, atTheEnd: boolean): () => void {
|
||||
const newNode = new Node(element);
|
||||
if (!this._first) {
|
||||
this._first = newNode;
|
||||
@@ -63,41 +64,63 @@ export class LinkedList<E> {
|
||||
oldFirst.prev = newNode;
|
||||
}
|
||||
this._size += 1;
|
||||
return this._remove.bind(this, newNode);
|
||||
}
|
||||
|
||||
return () => {
|
||||
let candidate: Node<E> | undefined = this._first;
|
||||
while (candidate instanceof Node) {
|
||||
if (candidate !== newNode) {
|
||||
candidate = candidate.next;
|
||||
continue;
|
||||
}
|
||||
if (candidate.prev && candidate.next) {
|
||||
// middle
|
||||
let anchor = candidate.prev;
|
||||
anchor.next = candidate.next;
|
||||
candidate.next.prev = anchor;
|
||||
|
||||
} else if (!candidate.prev && !candidate.next) {
|
||||
// only node
|
||||
this._first = undefined;
|
||||
this._last = undefined;
|
||||
shift(): E | undefined {
|
||||
if (!this._first) {
|
||||
return undefined;
|
||||
} else {
|
||||
const res = this._first.element;
|
||||
this._remove(this._first);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (!candidate.next) {
|
||||
// last
|
||||
this._last = this._last!.prev!;
|
||||
this._last.next = undefined;
|
||||
pop(): E | undefined {
|
||||
if (!this._last) {
|
||||
return undefined;
|
||||
} else {
|
||||
const res = this._last.element;
|
||||
this._remove(this._last);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (!candidate.prev) {
|
||||
// first
|
||||
this._first = this._first!.next!;
|
||||
this._first.prev = undefined;
|
||||
}
|
||||
|
||||
// done
|
||||
this._size -= 1;
|
||||
break;
|
||||
private _remove(node: Node<E>): void {
|
||||
let candidate: Node<E> | undefined = this._first;
|
||||
while (candidate instanceof Node) {
|
||||
if (candidate !== node) {
|
||||
candidate = candidate.next;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
if (candidate.prev && candidate.next) {
|
||||
// middle
|
||||
let anchor = candidate.prev;
|
||||
anchor.next = candidate.next;
|
||||
candidate.next.prev = anchor;
|
||||
|
||||
} else if (!candidate.prev && !candidate.next) {
|
||||
// only node
|
||||
this._first = undefined;
|
||||
this._last = undefined;
|
||||
|
||||
} else if (!candidate.next) {
|
||||
// last
|
||||
this._last = this._last!.prev!;
|
||||
this._last.next = undefined;
|
||||
|
||||
} else if (!candidate.prev) {
|
||||
// first
|
||||
this._first = this._first!.next!;
|
||||
this._first.prev = undefined;
|
||||
}
|
||||
|
||||
// done
|
||||
this._size -= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iterator(): Iterator<E> {
|
||||
|
||||
@@ -24,7 +24,7 @@ export function keys<K, V>(map: Map<K, V>): K[] {
|
||||
|
||||
export function getOrSet<K, V>(map: Map<K, V>, key: K, value: V): V {
|
||||
let result = map.get(key);
|
||||
if (result === void 0) {
|
||||
if (result === undefined) {
|
||||
result = value;
|
||||
map.set(key, result);
|
||||
}
|
||||
@@ -431,7 +431,7 @@ export class ResourceMap<T> {
|
||||
this.map.set(this.toKey(resource), value);
|
||||
}
|
||||
|
||||
get(resource: URI): T {
|
||||
get(resource: URI): T | undefined {
|
||||
return this.map.get(this.toKey(resource));
|
||||
}
|
||||
|
||||
@@ -687,7 +687,7 @@ export class LinkedMap<K, V> {
|
||||
this._head = current;
|
||||
this._size = currentSize;
|
||||
if (current) {
|
||||
current.previous = void 0;
|
||||
current.previous = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -719,8 +719,8 @@ export class LinkedMap<K, V> {
|
||||
|
||||
private removeItem(item: Item<K, V>): void {
|
||||
if (item === this._head && item === this._tail) {
|
||||
this._head = void 0;
|
||||
this._tail = void 0;
|
||||
this._head = undefined;
|
||||
this._tail = undefined;
|
||||
}
|
||||
else if (item === this._head) {
|
||||
this._head = item.next;
|
||||
@@ -759,7 +759,7 @@ export class LinkedMap<K, V> {
|
||||
if (item === this._tail) {
|
||||
// previous must be defined since item was not head but is tail
|
||||
// So there are more than on item in the map
|
||||
previous!.next = void 0;
|
||||
previous!.next = undefined;
|
||||
this._tail = previous;
|
||||
}
|
||||
else {
|
||||
@@ -769,7 +769,7 @@ export class LinkedMap<K, V> {
|
||||
}
|
||||
|
||||
// Insert the node at head
|
||||
item.previous = void 0;
|
||||
item.previous = undefined;
|
||||
item.next = this._head;
|
||||
this._head.previous = item;
|
||||
this._head = item;
|
||||
@@ -785,14 +785,14 @@ export class LinkedMap<K, V> {
|
||||
if (item === this._head) {
|
||||
// next must be defined since item was not tail but is head
|
||||
// So there are more than on item in the map
|
||||
next!.previous = void 0;
|
||||
next!.previous = undefined;
|
||||
this._head = next;
|
||||
} else {
|
||||
// Both next and previous are not undefined since item was neither head nor tail.
|
||||
next!.previous = previous;
|
||||
previous!.next = next;
|
||||
}
|
||||
item.next = void 0;
|
||||
item.next = undefined;
|
||||
item.previous = this._tail;
|
||||
this._tail.next = item;
|
||||
this._tail = item;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { regExpFlags } from 'vs/base/common/strings';
|
||||
|
||||
export function stringify(obj: any): string {
|
||||
return JSON.stringify(obj, replacer);
|
||||
@@ -24,8 +25,8 @@ function replacer(key: string, value: any): any {
|
||||
if (value instanceof RegExp) {
|
||||
return {
|
||||
$mid: 2,
|
||||
source: (<RegExp>value).source,
|
||||
flags: ((<RegExp>value).global ? 'g' : '') + ((<RegExp>value).ignoreCase ? 'i' : '') + ((<RegExp>value).multiline ? 'm' : ''),
|
||||
source: value.source,
|
||||
flags: regExpFlags(value),
|
||||
};
|
||||
}
|
||||
return value;
|
||||
|
||||
@@ -13,20 +13,20 @@ export const MIME_BINARY = 'application/octet-stream';
|
||||
export const MIME_UNKNOWN = 'application/unknown';
|
||||
|
||||
export interface ITextMimeAssociation {
|
||||
id: string;
|
||||
mime: string;
|
||||
filename?: string;
|
||||
extension?: string;
|
||||
filepattern?: string;
|
||||
firstline?: RegExp;
|
||||
userConfigured?: boolean;
|
||||
readonly id: string;
|
||||
readonly mime: string;
|
||||
readonly filename?: string;
|
||||
readonly extension?: string;
|
||||
readonly filepattern?: string;
|
||||
readonly firstline?: RegExp;
|
||||
readonly userConfigured?: boolean;
|
||||
}
|
||||
|
||||
interface ITextMimeAssociationItem extends ITextMimeAssociation {
|
||||
filenameLowercase?: string;
|
||||
extensionLowercase?: string;
|
||||
filepatternLowercase?: string;
|
||||
filepatternOnPath?: boolean;
|
||||
readonly filenameLowercase?: string;
|
||||
readonly extensionLowercase?: string;
|
||||
readonly filepatternLowercase?: string;
|
||||
readonly filepatternOnPath?: boolean;
|
||||
}
|
||||
|
||||
let registeredAssociations: ITextMimeAssociationItem[] = [];
|
||||
@@ -82,9 +82,9 @@ function toTextMimeAssociationItem(association: ITextMimeAssociation): ITextMime
|
||||
filepattern: association.filepattern,
|
||||
firstline: association.firstline,
|
||||
userConfigured: association.userConfigured,
|
||||
filenameLowercase: association.filename ? association.filename.toLowerCase() : void 0,
|
||||
extensionLowercase: association.extension ? association.extension.toLowerCase() : void 0,
|
||||
filepatternLowercase: association.filepattern ? association.filepattern.toLowerCase() : void 0,
|
||||
filenameLowercase: association.filename ? association.filename.toLowerCase() : undefined,
|
||||
extensionLowercase: association.extension ? association.extension.toLowerCase() : undefined,
|
||||
filepatternLowercase: association.filepattern ? association.filepattern.toLowerCase() : undefined,
|
||||
filepatternOnPath: association.filepattern ? association.filepattern.indexOf(paths.sep) >= 0 : false
|
||||
};
|
||||
}
|
||||
@@ -106,7 +106,7 @@ export function clearTextMimes(onlyUserConfigured?: boolean): void {
|
||||
/**
|
||||
* Given a file, return the best matching mime type for it
|
||||
*/
|
||||
export function guessMimeTypes(path: string, firstLine?: string, skipUserAssociations: boolean = false): string[] {
|
||||
export function guessMimeTypes(path: string | null, firstLine?: string): string[] {
|
||||
if (!path) {
|
||||
return [MIME_UNKNOWN];
|
||||
}
|
||||
@@ -114,12 +114,10 @@ export function guessMimeTypes(path: string, firstLine?: string, skipUserAssocia
|
||||
path = path.toLowerCase();
|
||||
const filename = paths.basename(path);
|
||||
|
||||
if (!skipUserAssociations) {
|
||||
// 1.) User configured mappings have highest priority
|
||||
const configuredMime = guessMimeTypeByPath(path, filename, userRegisteredAssociations);
|
||||
if (configuredMime) {
|
||||
return [configuredMime, MIME_TEXT];
|
||||
}
|
||||
// 1.) User configured mappings have highest priority
|
||||
const configuredMime = guessMimeTypeByPath(path, filename, userRegisteredAssociations);
|
||||
if (configuredMime) {
|
||||
return [configuredMime, MIME_TEXT];
|
||||
}
|
||||
|
||||
// 2.) Registered mappings have middle priority
|
||||
@@ -199,8 +197,7 @@ function guessMimeTypeByFirstline(firstLine: string): string | null {
|
||||
}
|
||||
|
||||
if (firstLine.length > 0) {
|
||||
for (let i = 0; i < registeredAssociations.length; ++i) {
|
||||
const association = registeredAssociations[i];
|
||||
for (const association of registeredAssociations) {
|
||||
if (!association.firstline) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -42,4 +42,6 @@ export namespace Schemas {
|
||||
export const untitled: string = 'untitled';
|
||||
|
||||
export const data: string = 'data';
|
||||
|
||||
export const command: string = 'command';
|
||||
}
|
||||
|
||||
@@ -62,8 +62,8 @@ function _cloneAndChange(obj: any, changer: (orig: any) => any, seen: Set<any>):
|
||||
|
||||
if (isArray(obj)) {
|
||||
const r1: any[] = [];
|
||||
for (let i1 = 0; i1 < obj.length; i1++) {
|
||||
r1.push(_cloneAndChange(obj[i1], changer, seen));
|
||||
for (const e of obj) {
|
||||
r1.push(_cloneAndChange(e, changer, seen));
|
||||
}
|
||||
return r1;
|
||||
}
|
||||
@@ -177,8 +177,8 @@ export function equals(one: any, other: any): boolean {
|
||||
|
||||
function arrayToHash(array: string[]): { [name: string]: true } {
|
||||
const result: any = {};
|
||||
for (let i = 0; i < array.length; ++i) {
|
||||
result[array[i]] = true;
|
||||
for (const e of array) {
|
||||
result[e] = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ function doParseOcticons(text: string, firstOcticonIndex: number): IParsedOctico
|
||||
if (chars) {
|
||||
textWithoutOcticons += chars;
|
||||
|
||||
for (let i = 0; i < chars.length; i++) {
|
||||
for (const _ of chars) {
|
||||
octiconOffsets.push(octiconsOffset); // make sure to fill in octicon offsets
|
||||
}
|
||||
}
|
||||
@@ -115,10 +115,10 @@ export function matchesFuzzyOcticonAware(query: string, target: IParsedOcticons,
|
||||
|
||||
// Map matches back to offsets with octicons and trimming
|
||||
if (matches) {
|
||||
for (let i = 0; i < matches.length; i++) {
|
||||
const octiconOffset = octiconOffsets[matches[i].start + leadingWhitespaceOffset] /* octicon offsets at index */ + leadingWhitespaceOffset /* overall leading whitespace offset */;
|
||||
matches[i].start += octiconOffset;
|
||||
matches[i].end += octiconOffset;
|
||||
for (const match of matches) {
|
||||
const octiconOffset = octiconOffsets[match.start + leadingWhitespaceOffset] /* octicon offsets at index */ + leadingWhitespaceOffset /* overall leading whitespace offset */;
|
||||
match.start += octiconOffset;
|
||||
match.end += octiconOffset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,12 +15,12 @@ export interface IPager<T> {
|
||||
firstPage: T[];
|
||||
total: number;
|
||||
pageSize: number;
|
||||
getPage(pageIndex: number, cancellationToken: CancellationToken): Thenable<T[]>;
|
||||
getPage(pageIndex: number, cancellationToken: CancellationToken): Promise<T[]>;
|
||||
}
|
||||
|
||||
interface IPage<T> {
|
||||
isResolved: boolean;
|
||||
promise: Thenable<void> | null;
|
||||
promise: Promise<void> | null;
|
||||
cts: CancellationTokenSource | null;
|
||||
promiseIndexes: Set<number>;
|
||||
elements: T[];
|
||||
@@ -43,7 +43,7 @@ export interface IPagedModel<T> {
|
||||
length: number;
|
||||
isResolved(index: number): boolean;
|
||||
get(index: number): T;
|
||||
resolve(index: number, cancellationToken: CancellationToken): Thenable<T>;
|
||||
resolve(index: number, cancellationToken: CancellationToken): Promise<T>;
|
||||
}
|
||||
|
||||
export function singlePagePager<T>(elements: T[]): IPager<T> {
|
||||
@@ -51,7 +51,7 @@ export function singlePagePager<T>(elements: T[]): IPager<T> {
|
||||
firstPage: elements,
|
||||
total: elements.length,
|
||||
pageSize: elements.length,
|
||||
getPage: (pageIndex: number, cancellationToken: CancellationToken): Thenable<T[]> => {
|
||||
getPage: (pageIndex: number, cancellationToken: CancellationToken): Promise<T[]> => {
|
||||
return Promise.resolve(elements);
|
||||
}
|
||||
};
|
||||
@@ -90,7 +90,7 @@ export class PagedModel<T> implements IPagedModel<T> {
|
||||
return page.elements[indexInPage];
|
||||
}
|
||||
|
||||
resolve(index: number, cancellationToken: CancellationToken): Thenable<T> {
|
||||
resolve(index: number, cancellationToken: CancellationToken): Promise<T> {
|
||||
if (cancellationToken.isCancellationRequested) {
|
||||
return Promise.reject(canceled());
|
||||
}
|
||||
@@ -151,7 +151,7 @@ export class DelayedPagedModel<T> implements IPagedModel<T> {
|
||||
return this.model.get(index);
|
||||
}
|
||||
|
||||
resolve(index: number, cancellationToken: CancellationToken): Thenable<T> {
|
||||
resolve(index: number, cancellationToken: CancellationToken): Promise<T> {
|
||||
return new Promise((c, e) => {
|
||||
if (cancellationToken.isCancellationRequested) {
|
||||
return e(canceled());
|
||||
@@ -196,7 +196,7 @@ export function mergePagers<T>(one: IPager<T>, other: IPager<T>): IPager<T> {
|
||||
firstPage: [...one.firstPage, ...other.firstPage],
|
||||
total: one.total + other.total,
|
||||
pageSize: one.pageSize + other.pageSize,
|
||||
getPage(pageIndex: number, token): Thenable<T[]> {
|
||||
getPage(pageIndex: number, token): Promise<T[]> {
|
||||
return Promise.all([one.getPage(pageIndex, token), other.getPage(pageIndex, token)])
|
||||
.then(([onePage, otherPage]) => [...onePage, ...otherPage]);
|
||||
}
|
||||
|
||||
@@ -17,27 +17,45 @@ export const sep = '/';
|
||||
*/
|
||||
export const nativeSep = isWindows ? '\\' : '/';
|
||||
|
||||
|
||||
function isPathSeparator(code: number) {
|
||||
return code === CharCode.Slash || code === CharCode.Backslash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param path the path to get the dirname from
|
||||
* @param separator the separator to use
|
||||
* @returns the directory name of a path.
|
||||
*
|
||||
* '.' is returned for empty paths or single segment relative paths (as done by NodeJS)
|
||||
* For paths consisting only of a root, the input path is returned
|
||||
*/
|
||||
export function dirname(path: string, separator = nativeSep): string {
|
||||
const idx = ~path.lastIndexOf('/') || ~path.lastIndexOf('\\');
|
||||
if (idx === 0) {
|
||||
const len = path.length;
|
||||
if (len === 0) {
|
||||
return '.';
|
||||
} else if (~idx === 0) {
|
||||
return path[0];
|
||||
} else if (~idx === path.length - 1) {
|
||||
return dirname(path.substring(0, path.length - 1));
|
||||
} else {
|
||||
let res = path.substring(0, ~idx);
|
||||
if (isWindows && res[res.length - 1] === ':') {
|
||||
res += separator; // make sure drive letters end with backslash
|
||||
}
|
||||
return res;
|
||||
} else if (len === 1) {
|
||||
return isPathSeparator(path.charCodeAt(0)) ? path : '.';
|
||||
}
|
||||
const root = getRoot(path, separator);
|
||||
let rootLength = root.length;
|
||||
if (rootLength >= len) {
|
||||
return path; // matched the root
|
||||
}
|
||||
if (rootLength === 0 && isPathSeparator(path.charCodeAt(0))) {
|
||||
rootLength = 1; // absolute paths stay absolute paths.
|
||||
}
|
||||
|
||||
let i = len - 1;
|
||||
if (i > rootLength) {
|
||||
i--; // no need to look at the last character. If it's a trailing slash, we ignore it.
|
||||
while (i > rootLength && !isPathSeparator(path.charCodeAt(i))) {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
if (i === 0) {
|
||||
return '.'; // it was a relative path with a single segment, no root. Nodejs returns '.' here.
|
||||
}
|
||||
return path.substr(0, i);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,7 +95,7 @@ export function normalize(path: null, toOSPath?: boolean): null;
|
||||
export function normalize(path: string, toOSPath?: boolean): string;
|
||||
export function normalize(path: string | null | undefined, toOSPath?: boolean): string | null | undefined {
|
||||
|
||||
if (path === null || path === void 0) {
|
||||
if (path === null || path === undefined) {
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -102,7 +120,7 @@ export function normalize(path: string | null | undefined, toOSPath?: boolean):
|
||||
for (let end = root.length; end <= len; end++) {
|
||||
|
||||
// either at the end or at a path-separator character
|
||||
if (end === len || path.charCodeAt(end) === CharCode.Slash || path.charCodeAt(end) === CharCode.Backslash) {
|
||||
if (end === len || isPathSeparator(path.charCodeAt(end))) {
|
||||
|
||||
if (streql(path, start, end, '..')) {
|
||||
// skip current and remove parent (if there is already something)
|
||||
@@ -148,29 +166,23 @@ export function getRoot(path: string, sep: string = '/'): string {
|
||||
}
|
||||
|
||||
let len = path.length;
|
||||
let code = path.charCodeAt(0);
|
||||
if (code === CharCode.Slash || code === CharCode.Backslash) {
|
||||
|
||||
code = path.charCodeAt(1);
|
||||
if (code === CharCode.Slash || code === CharCode.Backslash) {
|
||||
const firstLetter = path.charCodeAt(0);
|
||||
if (isPathSeparator(firstLetter)) {
|
||||
if (isPathSeparator(path.charCodeAt(1))) {
|
||||
// UNC candidate \\localhost\shares\ddd
|
||||
// ^^^^^^^^^^^^^^^^^^^
|
||||
code = path.charCodeAt(2);
|
||||
if (code !== CharCode.Slash && code !== CharCode.Backslash) {
|
||||
if (!isPathSeparator(path.charCodeAt(2))) {
|
||||
let pos = 3;
|
||||
let start = pos;
|
||||
for (; pos < len; pos++) {
|
||||
code = path.charCodeAt(pos);
|
||||
if (code === CharCode.Slash || code === CharCode.Backslash) {
|
||||
if (isPathSeparator(path.charCodeAt(pos))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
code = path.charCodeAt(pos + 1);
|
||||
if (start !== pos && code !== CharCode.Slash && code !== CharCode.Backslash) {
|
||||
if (start !== pos && !isPathSeparator(path.charCodeAt(pos + 1))) {
|
||||
pos += 1;
|
||||
for (; pos < len; pos++) {
|
||||
code = path.charCodeAt(pos);
|
||||
if (code === CharCode.Slash || code === CharCode.Backslash) {
|
||||
if (isPathSeparator(path.charCodeAt(pos))) {
|
||||
return path.slice(0, pos + 1) // consume this separator
|
||||
.replace(/[\\/]/g, sep);
|
||||
}
|
||||
@@ -183,12 +195,11 @@ export function getRoot(path: string, sep: string = '/'): string {
|
||||
// ^
|
||||
return sep;
|
||||
|
||||
} else if ((code >= CharCode.A && code <= CharCode.Z) || (code >= CharCode.a && code <= CharCode.z)) {
|
||||
} else if (isWindowsDriveLetter(firstLetter)) {
|
||||
// check for windows drive letter c:\ or c:
|
||||
|
||||
if (path.charCodeAt(1) === CharCode.Colon) {
|
||||
code = path.charCodeAt(2);
|
||||
if (code === CharCode.Slash || code === CharCode.Backslash) {
|
||||
if (isPathSeparator(path.charCodeAt(2))) {
|
||||
// C:\fff
|
||||
// ^^^
|
||||
return path.slice(0, 2) + sep;
|
||||
@@ -207,8 +218,7 @@ export function getRoot(path: string, sep: string = '/'): string {
|
||||
if (pos !== -1) {
|
||||
pos += 3; // 3 -> "://".length
|
||||
for (; pos < len; pos++) {
|
||||
code = path.charCodeAt(pos);
|
||||
if (code === CharCode.Slash || code === CharCode.Backslash) {
|
||||
if (isPathSeparator(path.charCodeAt(pos))) {
|
||||
return path.slice(0, pos + 1); // consume this separator
|
||||
}
|
||||
}
|
||||
@@ -229,9 +239,9 @@ export const join: (...parts: string[]) => string = function () {
|
||||
// add the separater between two parts unless
|
||||
// there already is one
|
||||
let last = value.charCodeAt(value.length - 1);
|
||||
if (last !== CharCode.Slash && last !== CharCode.Backslash) {
|
||||
if (!isPathSeparator(last)) {
|
||||
let next = part.charCodeAt(0);
|
||||
if (next !== CharCode.Slash && next !== CharCode.Backslash) {
|
||||
if (!isPathSeparator(next)) {
|
||||
|
||||
value += sep;
|
||||
}
|
||||
@@ -386,12 +396,12 @@ export function isAbsolute_win32(path: string): boolean {
|
||||
}
|
||||
|
||||
const char0 = path.charCodeAt(0);
|
||||
if (char0 === CharCode.Slash || char0 === CharCode.Backslash) {
|
||||
if (isPathSeparator(char0)) {
|
||||
return true;
|
||||
} else if ((char0 >= CharCode.A && char0 <= CharCode.Z) || (char0 >= CharCode.a && char0 <= CharCode.z)) {
|
||||
} else if (isWindowsDriveLetter(char0)) {
|
||||
if (path.length > 2 && path.charCodeAt(1) === CharCode.Colon) {
|
||||
const char2 = path.charCodeAt(2);
|
||||
if (char2 === CharCode.Slash || char2 === CharCode.Backslash) {
|
||||
if (isPathSeparator(char2)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -403,3 +413,7 @@ export function isAbsolute_win32(path: string): boolean {
|
||||
export function isAbsolute_posix(path: string): boolean {
|
||||
return !!(path && path.charCodeAt(0) === CharCode.Slash);
|
||||
}
|
||||
|
||||
export function isWindowsDriveLetter(char0: number): boolean {
|
||||
return char0 >= CharCode.A && char0 <= CharCode.Z || char0 >= CharCode.a && char0 <= CharCode.z;
|
||||
}
|
||||
|
||||
10
src/vs/base/common/performance.d.ts
vendored
10
src/vs/base/common/performance.d.ts
vendored
@@ -4,22 +4,18 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export interface PerformanceEntry {
|
||||
readonly type: 'mark' | 'measure';
|
||||
readonly name: string;
|
||||
readonly startTime: number;
|
||||
readonly duration: number;
|
||||
readonly timestamp: number;
|
||||
}
|
||||
|
||||
export function mark(name: string): void;
|
||||
|
||||
export function measure(name: string, from?: string, to?: string): PerformanceEntry;
|
||||
|
||||
/**
|
||||
* All entries filtered by type and sorted by `startTime`.
|
||||
*/
|
||||
export function getEntries(type: 'mark' | 'measure'): PerformanceEntry[];
|
||||
export function getEntries(): PerformanceEntry[];
|
||||
|
||||
export function getEntry(type: 'mark' | 'measure', name: string): PerformanceEntry;
|
||||
export function getEntry(name: string): PerformanceEntry;
|
||||
|
||||
export function getDuration(from: string, to: string): number;
|
||||
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
// This module can be loaded in an amd and commonjs-context.
|
||||
// Because we want both instances to use the same perf-data
|
||||
// we store them globally
|
||||
// stores data as 'type','name','startTime','duration'
|
||||
// stores data as: 'name','timestamp'
|
||||
|
||||
if (typeof define !== "function" && typeof module === "object" && typeof module.exports === "object") {
|
||||
// this is commonjs, fake amd
|
||||
global.define = function (dep, callback) {
|
||||
global.define = function (_dep, callback) {
|
||||
module.exports = callback();
|
||||
global.define = undefined;
|
||||
};
|
||||
@@ -22,14 +22,10 @@ if (typeof define !== "function" && typeof module === "object" && typeof module.
|
||||
|
||||
define([], function () {
|
||||
|
||||
var _global = this;
|
||||
if (typeof global !== 'undefined') {
|
||||
_global = global;
|
||||
}
|
||||
_global._performanceEntries = _global._performanceEntries || [];
|
||||
global._performanceEntries = global._performanceEntries || [];
|
||||
|
||||
// const _now = global.performance && performance.now ? performance.now : Date.now
|
||||
const _now = Date.now;
|
||||
const _dataLen = 2;
|
||||
const _timeStamp = typeof console.timeStamp === 'function' ? console.timeStamp.bind(console) : () => { };
|
||||
|
||||
function importEntries(entries) {
|
||||
global._performanceEntries.splice(0, 0, ...entries);
|
||||
@@ -39,36 +35,25 @@ define([], function () {
|
||||
return global._performanceEntries.slice(0);
|
||||
}
|
||||
|
||||
function getEntries(type, name) {
|
||||
function getEntries() {
|
||||
const result = [];
|
||||
const entries = global._performanceEntries;
|
||||
for (let i = 0; i < entries.length; i += 5) {
|
||||
if (entries[i] === type && (name === void 0 || entries[i + 1] === name)) {
|
||||
result.push({
|
||||
type: entries[i],
|
||||
name: entries[i + 1],
|
||||
startTime: entries[i + 2],
|
||||
duration: entries[i + 3],
|
||||
seq: entries[i + 4],
|
||||
});
|
||||
}
|
||||
for (let i = 0; i < entries.length; i += _dataLen) {
|
||||
result.push({
|
||||
name: entries[i],
|
||||
timestamp: entries[i + 1],
|
||||
});
|
||||
}
|
||||
|
||||
return result.sort((a, b) => {
|
||||
return a.startTime - b.startTime || a.seq - b.seq;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function getEntry(type, name) {
|
||||
function getEntry(name) {
|
||||
const entries = global._performanceEntries;
|
||||
for (let i = 0; i < entries.length; i += 5) {
|
||||
if (entries[i] === type && entries[i + 1] === name) {
|
||||
for (let i = 0; i < entries.length; i += _dataLen) {
|
||||
if (entries[i] === name) {
|
||||
return {
|
||||
type: entries[i],
|
||||
name: entries[i + 1],
|
||||
startTime: entries[i + 2],
|
||||
duration: entries[i + 3],
|
||||
seq: entries[i + 4],
|
||||
name: entries[i],
|
||||
timestamp: entries[i + 1],
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -77,65 +62,29 @@ define([], function () {
|
||||
function getDuration(from, to) {
|
||||
const entries = global._performanceEntries;
|
||||
let target = to;
|
||||
let endTime = 0;
|
||||
for (let i = entries.length - 1; i >= 0; i -= 5) {
|
||||
if (entries[i - 3] === target) {
|
||||
let endIndex = 0;
|
||||
for (let i = entries.length - _dataLen; i >= 0; i -= _dataLen) {
|
||||
if (entries[i] === target) {
|
||||
if (target === to) {
|
||||
// found `to` (end of interval)
|
||||
endTime = entries[i - 2];
|
||||
endIndex = i;
|
||||
target = from;
|
||||
} else {
|
||||
return endTime - entries[i - 2];
|
||||
// found `from` (start of interval)
|
||||
return entries[endIndex + 1] - entries[i + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
let seq = 0;
|
||||
|
||||
function mark(name) {
|
||||
global._performanceEntries.push('mark', name, _now(), 0, seq++);
|
||||
if (typeof console.timeStamp === 'function') {
|
||||
console.timeStamp(name);
|
||||
}
|
||||
}
|
||||
|
||||
function measure(name, from, to) {
|
||||
|
||||
let startTime;
|
||||
let duration;
|
||||
let now = _now();
|
||||
|
||||
if (!from) {
|
||||
startTime = now;
|
||||
} else {
|
||||
startTime = _getLastStartTime(from);
|
||||
}
|
||||
|
||||
if (!to) {
|
||||
duration = now - startTime;
|
||||
} else {
|
||||
duration = _getLastStartTime(to) - startTime;
|
||||
}
|
||||
|
||||
global._performanceEntries.push('measure', name, startTime, duration);
|
||||
}
|
||||
|
||||
function _getLastStartTime(name) {
|
||||
const entries = global._performanceEntries;
|
||||
for (let i = entries.length - 1; i >= 0; i -= 5) {
|
||||
if (entries[i - 3] === name) {
|
||||
return entries[i - 2];
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(name + ' not found');
|
||||
global._performanceEntries.push(name, Date.now());
|
||||
_timeStamp(name);
|
||||
}
|
||||
|
||||
var exports = {
|
||||
mark: mark,
|
||||
measure: measure,
|
||||
getEntries: getEntries,
|
||||
getEntry: getEntry,
|
||||
getDuration: getDuration,
|
||||
|
||||
@@ -73,6 +73,9 @@ export function basename(resource: URI): string {
|
||||
* @returns The URI representing the directory of the input URI.
|
||||
*/
|
||||
export function dirname(resource: URI): URI | null {
|
||||
if (resource.path.length === 0) {
|
||||
return resource;
|
||||
}
|
||||
if (resource.scheme === Schemas.file) {
|
||||
return URI.file(paths.dirname(fsPath(resource)));
|
||||
}
|
||||
@@ -111,6 +114,9 @@ export function joinPath(resource: URI, pathFragment: string): URI {
|
||||
* @returns The URI with the normalized path.
|
||||
*/
|
||||
export function normalizePath(resource: URI): URI {
|
||||
if (!resource.path.length) {
|
||||
return resource;
|
||||
}
|
||||
let normalizedPath: string;
|
||||
if (resource.scheme === Schemas.file) {
|
||||
normalizedPath = URI.file(paths.normalize(fsPath(resource))).path;
|
||||
@@ -128,19 +134,20 @@ export function normalizePath(resource: URI): URI {
|
||||
*/
|
||||
export function fsPath(uri: URI): string {
|
||||
let value: string;
|
||||
if (uri.authority && uri.path.length > 1 && uri.scheme === 'file') {
|
||||
const uriPath = uri.path;
|
||||
if (uri.authority && uriPath.length > 1 && uri.scheme === 'file') {
|
||||
// unc path: file://shares/c$/far/boo
|
||||
value = `//${uri.authority}${uri.path}`;
|
||||
value = `//${uri.authority}${uriPath}`;
|
||||
} else if (
|
||||
isWindows
|
||||
&& uri.path.charCodeAt(0) === CharCode.Slash
|
||||
&& (uri.path.charCodeAt(1) >= CharCode.A && uri.path.charCodeAt(1) <= CharCode.Z || uri.path.charCodeAt(1) >= CharCode.a && uri.path.charCodeAt(1) <= CharCode.z)
|
||||
&& uri.path.charCodeAt(2) === CharCode.Colon
|
||||
&& uriPath.charCodeAt(0) === CharCode.Slash
|
||||
&& paths.isWindowsDriveLetter(uriPath.charCodeAt(1))
|
||||
&& uriPath.charCodeAt(2) === CharCode.Colon
|
||||
) {
|
||||
value = uri.path.substr(1);
|
||||
value = uriPath.substr(1);
|
||||
} else {
|
||||
// other path
|
||||
value = uri.path;
|
||||
value = uriPath;
|
||||
}
|
||||
if (isWindows) {
|
||||
value = value.replace(/\//g, '\\');
|
||||
@@ -186,7 +193,7 @@ export function isMalformedFileUri(candidate: URI): URI | undefined {
|
||||
if (!candidate.scheme || isWindows && candidate.scheme.match(/^[a-zA-Z]$/)) {
|
||||
return URI.file((candidate.scheme ? candidate.scheme + ':' : '') + candidate.path);
|
||||
}
|
||||
return void 0;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ export function format(value: string, ...args: any[]): string {
|
||||
* being used e.g. in HTMLElement.innerHTML.
|
||||
*/
|
||||
export function escape(html: string): string {
|
||||
return html.replace(/[<|>|&]/g, function (match) {
|
||||
return html.replace(/[<>&]/g, function (match) {
|
||||
switch (match) {
|
||||
case '<': return '<';
|
||||
case '>': return '>';
|
||||
@@ -188,6 +188,7 @@ export interface RegExpOptions {
|
||||
wholeWord?: boolean;
|
||||
multiline?: boolean;
|
||||
global?: boolean;
|
||||
unicode?: boolean;
|
||||
}
|
||||
|
||||
export function createRegExp(searchString: string, isRegex: boolean, options: RegExpOptions = {}): RegExp {
|
||||
@@ -215,6 +216,9 @@ export function createRegExp(searchString: string, isRegex: boolean, options: Re
|
||||
if (options.multiline) {
|
||||
modifiers += 'm';
|
||||
}
|
||||
if (options.unicode) {
|
||||
modifiers += 'u';
|
||||
}
|
||||
|
||||
return new RegExp(searchString, modifiers);
|
||||
}
|
||||
@@ -236,6 +240,13 @@ export function regExpContainsBackreference(regexpValue: string): boolean {
|
||||
return !!regexpValue.match(/([^\\]|^)(\\\\)*\\\d+/);
|
||||
}
|
||||
|
||||
export function regExpFlags(regexp: RegExp): string {
|
||||
return (regexp.global ? 'g' : '')
|
||||
+ (regexp.ignoreCase ? 'i' : '')
|
||||
+ (regexp.multiline ? 'm' : '')
|
||||
+ ((regexp as any).unicode ? 'u' : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns first index of the string that is not whitespace.
|
||||
* If string is empty or contains only whitespaces, returns -1
|
||||
|
||||
@@ -124,12 +124,12 @@ export function isFunction(obj: any): obj is Function {
|
||||
* @returns whether the provided parameters is are JavaScript Function or not.
|
||||
*/
|
||||
export function areFunctions(...objects: any[]): boolean {
|
||||
return objects && objects.length > 0 && objects.every(isFunction);
|
||||
return objects.length > 0 && objects.every(isFunction);
|
||||
}
|
||||
|
||||
export type TypeConstraint = string | Function;
|
||||
|
||||
export function validateConstraints(args: any[], constraints: (TypeConstraint | undefined)[]): void {
|
||||
export function validateConstraints(args: any[], constraints: Array<TypeConstraint | undefined>): void {
|
||||
const len = Math.min(args.length, constraints.length);
|
||||
for (let i = 0; i < len; i++) {
|
||||
validateConstraint(args[i], constraints[i]);
|
||||
|
||||
@@ -108,7 +108,10 @@ export class URI implements UriComponents {
|
||||
&& typeof (<URI>thing).fragment === 'string'
|
||||
&& typeof (<URI>thing).path === 'string'
|
||||
&& typeof (<URI>thing).query === 'string'
|
||||
&& typeof (<URI>thing).scheme === 'string';
|
||||
&& typeof (<URI>thing).scheme === 'string'
|
||||
&& typeof (<URI>thing).fsPath === 'function'
|
||||
&& typeof (<URI>thing).with === 'function'
|
||||
&& typeof (<URI>thing).toString === 'function';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,27 +218,27 @@ export class URI implements UriComponents {
|
||||
}
|
||||
|
||||
let { scheme, authority, path, query, fragment } = change;
|
||||
if (scheme === void 0) {
|
||||
if (scheme === undefined) {
|
||||
scheme = this.scheme;
|
||||
} else if (scheme === null) {
|
||||
scheme = _empty;
|
||||
}
|
||||
if (authority === void 0) {
|
||||
if (authority === undefined) {
|
||||
authority = this.authority;
|
||||
} else if (authority === null) {
|
||||
authority = _empty;
|
||||
}
|
||||
if (path === void 0) {
|
||||
if (path === undefined) {
|
||||
path = this.path;
|
||||
} else if (path === null) {
|
||||
path = _empty;
|
||||
}
|
||||
if (query === void 0) {
|
||||
if (query === undefined) {
|
||||
query = this.query;
|
||||
} else if (query === null) {
|
||||
query = _empty;
|
||||
}
|
||||
if (fragment === void 0) {
|
||||
if (fragment === undefined) {
|
||||
fragment = this.fragment;
|
||||
} else if (fragment === null) {
|
||||
fragment = _empty;
|
||||
@@ -546,7 +549,6 @@ function encodeURIComponentMinimal(path: string): string {
|
||||
|
||||
/**
|
||||
* Compute `fsPath` for the given uri
|
||||
* @param uri
|
||||
*/
|
||||
function _makeFsPath(uri: URI): string {
|
||||
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { MarshalledObject } from 'vs/base/common/marshalling';
|
||||
|
||||
export interface IURITransformer {
|
||||
transformIncoming(uri: UriComponents): UriComponents;
|
||||
transformOutgoing(uri: URI): URI;
|
||||
transformOutgoing(uri: UriComponents): UriComponents;
|
||||
transformOutgoingURI(uri: URI): URI;
|
||||
}
|
||||
|
||||
export const DefaultURITransformer: IURITransformer = new class {
|
||||
@@ -16,9 +17,90 @@ export const DefaultURITransformer: IURITransformer = new class {
|
||||
return uri;
|
||||
}
|
||||
|
||||
transformOutgoing(uri: URI): URI;
|
||||
transformOutgoing(uri: UriComponents): UriComponents;
|
||||
transformOutgoing(uri: URI | UriComponents): URI | UriComponents {
|
||||
transformOutgoing(uri: UriComponents): UriComponents {
|
||||
return uri;
|
||||
}
|
||||
};
|
||||
|
||||
transformOutgoingURI(uri: URI): URI {
|
||||
return uri;
|
||||
}
|
||||
};
|
||||
|
||||
function _transformOutgoingURIs(obj: any, transformer: IURITransformer, depth: number): any {
|
||||
|
||||
if (!obj || depth > 200) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof obj === 'object') {
|
||||
if (obj instanceof URI) {
|
||||
return transformer.transformOutgoing(obj);
|
||||
}
|
||||
|
||||
// walk object (or array)
|
||||
for (let key in obj) {
|
||||
if (Object.hasOwnProperty.call(obj, key)) {
|
||||
const r = _transformOutgoingURIs(obj[key], transformer, depth + 1);
|
||||
if (r !== null) {
|
||||
obj[key] = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function transformOutgoingURIs<T>(obj: T, transformer: IURITransformer): T {
|
||||
const result = _transformOutgoingURIs(obj, transformer, 0);
|
||||
if (result === null) {
|
||||
// no change
|
||||
return obj;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
function _transformIncomingURIs(obj: any, transformer: IURITransformer, revive: boolean, depth: number): any {
|
||||
|
||||
if (!obj || depth > 200) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof obj === 'object') {
|
||||
|
||||
if ((<MarshalledObject>obj).$mid === 1) {
|
||||
return revive ? URI.revive(transformer.transformIncoming(obj)) : transformer.transformIncoming(obj);
|
||||
}
|
||||
|
||||
// walk object (or array)
|
||||
for (let key in obj) {
|
||||
if (Object.hasOwnProperty.call(obj, key)) {
|
||||
const r = _transformIncomingURIs(obj[key], transformer, revive, depth + 1);
|
||||
if (r !== null) {
|
||||
obj[key] = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function transformIncomingURIs<T>(obj: T, transformer: IURITransformer): T {
|
||||
const result = _transformIncomingURIs(obj, transformer, false, 0);
|
||||
if (result === null) {
|
||||
// no change
|
||||
return obj;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function transformAndReviveIncomingURIs<T>(obj: T, transformer: IURITransformer): T {
|
||||
const result = _transformIncomingURIs(obj, transformer, true, 0);
|
||||
if (result === null) {
|
||||
// no change
|
||||
return obj;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
53
src/vs/base/common/winjs.base.d.ts
vendored
53
src/vs/base/common/winjs.base.d.ts
vendored
@@ -1,53 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
/// Interfaces for WinJS
|
||||
|
||||
export type ErrorCallback = (error: any) => void;
|
||||
|
||||
export class Promise<T = any> {
|
||||
constructor(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason: any) => void) => void);
|
||||
|
||||
public then<TResult1 = T, TResult2 = never>(
|
||||
onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
|
||||
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
|
||||
|
||||
|
||||
public static as(value: null): Promise<null>;
|
||||
public static as(value: undefined): Promise<undefined>;
|
||||
public static as<T>(value: PromiseLike<T>): PromiseLike<T>;
|
||||
public static as<T, SomePromise extends PromiseLike<T>>(value: SomePromise): SomePromise;
|
||||
public static as<T>(value: T): Promise<T>;
|
||||
|
||||
public static join<T1, T2>(promises: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<[T1, T2]>;
|
||||
public static join<T>(promises: (T | PromiseLike<T>)[]): Promise<T[]>;
|
||||
|
||||
public static wrap<T>(value: T | PromiseLike<T>): Promise<T>;
|
||||
|
||||
public static wrapError<T = never>(error: Error): Promise<T>;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static addEventListener(event: 'error', promiseErrorHandler: (e: IPromiseError) => void): void;
|
||||
}
|
||||
|
||||
export type TValueCallback<T = any> = (value: T | PromiseLike<T>) => void;
|
||||
|
||||
export {
|
||||
Promise as TPromise,
|
||||
TValueCallback as ValueCallback
|
||||
};
|
||||
|
||||
export interface IPromiseErrorDetail {
|
||||
parent: Promise;
|
||||
error: any;
|
||||
id: number;
|
||||
handler: Function;
|
||||
exception: Error;
|
||||
}
|
||||
|
||||
export interface IPromiseError {
|
||||
detail: IPromiseErrorDetail;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,133 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Promise as WinJSPromise } from './winjs.base';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { isThenable } from 'vs/base/common/async';
|
||||
|
||||
function isWinJSPromise(candidate: any): candidate is WinJSPromise {
|
||||
return isThenable(candidate) && typeof (candidate as any).done === 'function';
|
||||
}
|
||||
|
||||
declare class WinJSPromiseRemovals {
|
||||
any<T=any>(promises: (T | PromiseLike<T>)[]): WinJSPromise<{ key: string; value: WinJSPromise<T>; }>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A polyfill for the native promises. The implementation is based on
|
||||
* WinJS promises but tries to gap differences between winjs promises
|
||||
* and native promises.
|
||||
*/
|
||||
export class PolyfillPromise<T = any> implements Promise<T> {
|
||||
|
||||
static all(thenables: Thenable<any>[]): PolyfillPromise {
|
||||
return new PolyfillPromise(WinJSPromise.join(thenables).then(null, values => {
|
||||
// WinJSPromise returns a sparse array whereas
|
||||
// native promises return the *first* error
|
||||
for (var key in values) {
|
||||
if (values.hasOwnProperty(key)) {
|
||||
return values[key];
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
static race(thenables: Thenable<any>[]): PolyfillPromise {
|
||||
// WinJSPromise returns `{ key: <index/key>, value: <promise> }`
|
||||
// from the `any` call and Promise.race just wants the value
|
||||
return new PolyfillPromise((WinJSPromise as any as WinJSPromiseRemovals).any(thenables).then(entry => entry.value, err => err.value));
|
||||
}
|
||||
|
||||
static resolve(value): PolyfillPromise {
|
||||
return new PolyfillPromise(WinJSPromise.wrap(value));
|
||||
}
|
||||
|
||||
static reject(value): PolyfillPromise {
|
||||
return new PolyfillPromise(WinJSPromise.wrapError(value));
|
||||
}
|
||||
|
||||
private _winjsPromise: WinJSPromise;
|
||||
|
||||
constructor(winjsPromise: WinJSPromise);
|
||||
constructor(callback: (resolve: (value?: T) => void, reject: (err?: any) => void) => any);
|
||||
constructor(initOrPromise: WinJSPromise | ((resolve: (value?: T) => void, reject: (err?: any) => void) => any)) {
|
||||
|
||||
if (isWinJSPromise(initOrPromise)) {
|
||||
this._winjsPromise = initOrPromise;
|
||||
} else {
|
||||
this._winjsPromise = new WinJSPromise((resolve, reject) => {
|
||||
let initializing = true;
|
||||
initOrPromise(function (value) {
|
||||
if (!initializing) {
|
||||
resolve(value);
|
||||
} else {
|
||||
platform.setImmediate(() => resolve(value));
|
||||
}
|
||||
}, function (err) {
|
||||
if (!initializing) {
|
||||
reject(err);
|
||||
} else {
|
||||
platform.setImmediate(() => reject(err));
|
||||
}
|
||||
});
|
||||
initializing = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
then(onFulfilled?: any, onRejected?: any): PolyfillPromise {
|
||||
let sync = true;
|
||||
// To support chaining, we need to return the value of the
|
||||
// onFulfilled and onRejected callback.
|
||||
// WinJSPromise supports a flat-map style #then, ie. the callbacks
|
||||
// passed to WinJSPromise#then can return a Promise.
|
||||
let promise = new PolyfillPromise(this._winjsPromise.then(
|
||||
onFulfilled && function (value) {
|
||||
if (!sync) {
|
||||
return onFulfilled(value);
|
||||
} else {
|
||||
return new WinJSPromise((resolve, reject) => {
|
||||
platform.setImmediate(() => {
|
||||
let result;
|
||||
try {
|
||||
result = onFulfilled(value);
|
||||
}
|
||||
catch (err2) {
|
||||
reject(err2);
|
||||
return;
|
||||
}
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
onRejected && function (err) {
|
||||
if (!sync) {
|
||||
return onRejected(err);
|
||||
} else {
|
||||
return new WinJSPromise((resolve, reject) => {
|
||||
platform.setImmediate(() => {
|
||||
let result;
|
||||
try {
|
||||
result = onRejected(err);
|
||||
}
|
||||
catch (err2) {
|
||||
reject(err2);
|
||||
return;
|
||||
}
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
));
|
||||
sync = false;
|
||||
return promise;
|
||||
}
|
||||
|
||||
catch(onRejected?: any): PolyfillPromise {
|
||||
return this.then(null, onRejected);
|
||||
}
|
||||
}
|
||||
@@ -6,15 +6,6 @@
|
||||
import { transformErrorForSerialization } from 'vs/base/common/errors';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { isWeb } from 'vs/base/common/platform';
|
||||
import { PolyfillPromise } from 'vs/base/common/winjs.polyfill.promise';
|
||||
|
||||
var global: any = self;
|
||||
|
||||
// When missing, polyfill the native promise
|
||||
// with our winjs-based polyfill
|
||||
if (typeof global.Promise === 'undefined') {
|
||||
global.Promise = PolyfillPromise;
|
||||
}
|
||||
|
||||
const INITIALIZE = '$initialize';
|
||||
|
||||
@@ -243,8 +234,8 @@ export class SimpleWorkerClient<T> extends Disposable {
|
||||
lazyProxyReject = reject;
|
||||
this._onModuleLoaded.then((availableMethods: string[]) => {
|
||||
let proxy = <T>{};
|
||||
for (let i = 0; i < availableMethods.length; i++) {
|
||||
(proxy as any)[availableMethods[i]] = createProxyMethod(availableMethods[i], proxyMethodRequest);
|
||||
for (const methodName of availableMethods) {
|
||||
(proxy as any)[methodName] = createProxyMethod(methodName, proxyMethodRequest);
|
||||
}
|
||||
resolve(proxy);
|
||||
}, (e) => {
|
||||
@@ -254,11 +245,11 @@ export class SimpleWorkerClient<T> extends Disposable {
|
||||
});
|
||||
|
||||
// Create proxy to loaded code
|
||||
let proxyMethodRequest = (method: string, args: any[]): Promise<any> => {
|
||||
const proxyMethodRequest = (method: string, args: any[]): Promise<any> => {
|
||||
return this._request(method, args);
|
||||
};
|
||||
|
||||
let createProxyMethod = (method: string, proxyMethodRequest: (method: string, args: any[]) => Promise<any>): Function => {
|
||||
const createProxyMethod = (method: string, proxyMethodRequest: (method: string, args: any[]) => Promise<any>): () => Promise<any> => {
|
||||
return function () {
|
||||
let args = Array.prototype.slice.call(arguments, 0);
|
||||
return proxyMethodRequest(method, args);
|
||||
|
||||
Reference in New Issue
Block a user