Merge VS Code 1.31.1 (#4283)

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

View File

@@ -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);
}

View File

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

View File

@@ -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');
}
}

View File

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

View File

@@ -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": []
}

View File

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

View File

@@ -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;
}

View File

@@ -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]) || ''];

View File

@@ -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);
};
});

View File

@@ -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');

View File

@@ -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;
}

View File

@@ -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;
});
}

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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];

View File

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

View File

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

View File

@@ -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;
}

View File

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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -42,4 +42,6 @@ export namespace Schemas {
export const untitled: string = 'untitled';
export const data: string = 'data';
export const command: string = 'command';
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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]);
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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 '&lt;';
case '>': return '&gt;';
@@ -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

View File

@@ -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]);

View File

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

View File

@@ -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;
}

View File

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

View File

@@ -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);
}
}

View File

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