Initial VS Code 1.19 source merge (#571)

* Initial 1.19 xcopy

* Fix yarn build

* Fix numerous build breaks

* Next batch of build break fixes

* More build break fixes

* Runtime breaks

* Additional post merge fixes

* Fix windows setup file

* Fix test failures.

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

View File

@@ -5,9 +5,7 @@
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { IEventEmitter, EventEmitter } from 'vs/base/common/eventEmitter';
import { IDisposable } from 'vs/base/common/lifecycle';
import * as Events from 'vs/base/common/events';
import Event, { Emitter } from 'vs/base/common/event';
export interface ITelemetryData {
@@ -27,11 +25,13 @@ export interface IAction extends IDisposable {
run(event?: any): TPromise<any>;
}
export interface IActionRunner extends IEventEmitter {
export interface IActionRunner extends IDisposable {
run(action: IAction, context?: any): TPromise<any>;
onDidRun: Event<IRunEvent>;
onDidBeforeRun: Event<IRunEvent>;
}
export interface IActionItem extends IEventEmitter {
export interface IActionItem {
actionRunner: IActionRunner;
setActionContext(context: any): void;
render(element: any /* HTMLElement */): void;
@@ -41,33 +41,6 @@ export interface IActionItem extends IEventEmitter {
dispose(): void;
}
/**
* Checks if the provided object is compatible
* with the IAction interface.
* @param thing an object
*/
export function isAction(thing: any): thing is IAction {
if (!thing) {
return false;
} else if (thing instanceof Action) {
return true;
} else if (typeof thing.id !== 'string') {
return false;
} else if (typeof thing.label !== 'string') {
return false;
} else if (typeof thing.class !== 'string') {
return false;
} else if (typeof thing.enabled !== 'boolean') {
return false;
} else if (typeof thing.checked !== 'boolean') {
return false;
} else if (typeof thing.run !== 'function') {
return false;
} else {
return true;
}
}
export interface IActionChangeEvent {
label?: string;
tooltip?: string;
@@ -222,23 +195,44 @@ export interface IRunEvent {
error?: any;
}
export class ActionRunner extends EventEmitter implements IActionRunner {
export class ActionRunner implements IActionRunner {
private _onDidBeforeRun = new Emitter<IRunEvent>();
private _onDidRun = new Emitter<IRunEvent>();
public get onDidRun(): Event<IRunEvent> {
return this._onDidRun.event;
}
public get onDidBeforeRun(): Event<IRunEvent> {
return this._onDidBeforeRun.event;
}
public run(action: IAction, context?: any): TPromise<any> {
if (!action.enabled) {
return TPromise.as(null);
}
this.emit(Events.EventType.BEFORE_RUN, { action: action });
this._onDidBeforeRun.fire({ action: action });
return this.runAction(action, context).then((result: any) => {
this.emit(Events.EventType.RUN, <IRunEvent>{ action: action, result: result });
this._onDidRun.fire({ action: action, result: result });
}, (error: any) => {
this.emit(Events.EventType.RUN, <IRunEvent>{ action: action, error: error });
this._onDidRun.fire({ action: action, error: error });
});
}
protected runAction(action: IAction, context?: any): TPromise<any> {
return TPromise.as(context ? action.run(context) : action.run());
const res = context ? action.run(context) : action.run();
if (TPromise.is(res)) {
return res;
}
return TPromise.wrap(res);
}
public dispose(): void {
// noop
}
}

View File

@@ -5,6 +5,7 @@
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { ISplice } from 'vs/base/common/sequence';
/**
* Returns the last element of an array.
@@ -124,20 +125,18 @@ export function groupBy<T>(data: T[], compare: (a: T, b: T) => number): T[][] {
return result;
}
export interface Splice<T> {
start: number;
interface IMutableSplice<T> extends ISplice<T> {
deleteCount: number;
inserted: 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): Splice<T>[] {
const result: Splice<T>[] = [];
export function sortedDiff<T>(before: T[], after: T[], compare: (a: T, b: T) => number): ISplice<T>[] {
const result: IMutableSplice<T>[] = [];
function pushSplice(start: number, deleteCount: number, inserted: T[]): void {
if (deleteCount === 0 && inserted.length === 0) {
function pushSplice(start: number, deleteCount: number, toInsert: T[]): void {
if (deleteCount === 0 && toInsert.length === 0) {
return;
}
@@ -145,9 +144,9 @@ export function sortedDiff<T>(before: T[], after: T[], compare: (a: T, b: T) =>
if (latest && latest.start + latest.deleteCount === start) {
latest.deleteCount += deleteCount;
latest.inserted.push(...inserted);
latest.toInsert.push(...toInsert);
} else {
result.push({ start, deleteCount, inserted });
result.push({ start, deleteCount, toInsert });
}
}
@@ -199,7 +198,7 @@ export function delta<T>(before: T[], after: T[], compare: (a: T, b: T) => numbe
for (const splice of splices) {
removed.push(...before.slice(splice.start, splice.start + splice.deleteCount));
added.push(...splice.inserted);
added.push(...splice.toInsert);
}
return { removed, added };
@@ -397,21 +396,6 @@ export function range(arg: number, to?: number): number[] {
return result;
}
export function weave<T>(a: T[], b: T[]): T[] {
const result: T[] = [];
let ai = 0, bi = 0;
for (let i = 0, length = a.length + b.length; i < length; i++) {
if ((i % 2 === 0 && ai < a.length) || bi >= b.length) {
result.push(a[ai++]);
} else {
result.push(b[bi++]);
}
}
return result;
}
export function fill<T>(num: number, valueFn: () => T, arr: T[] = []): T[] {
for (let i = 0; i < num; i++) {
arr[i] = valueFn();

View File

@@ -146,7 +146,7 @@ export class Throttler {
// TODO@Joao: can the previous throttler be replaced with this?
export class SimpleThrottler {
private current = TPromise.as<any>(null);
private current = TPromise.wrap<any>(null);
queue<T>(promiseTask: ITask<TPromise<T>>): TPromise<T> {
return this.current = this.current.then(() => promiseTask());
@@ -261,56 +261,34 @@ export class ThrottledDelayer<T> extends Delayer<TPromise<T>> {
}
/**
* Similar to the ThrottledDelayer, except it also guarantees that the promise
* factory doesn't get called more often than every `minimumPeriod` milliseconds.
* A barrier that is initially closed and then becomes opened permanently.
*/
export class PeriodThrottledDelayer<T> extends ThrottledDelayer<T> {
export class Barrier {
private minimumPeriod: number;
private periodThrottler: Throttler;
constructor(defaultDelay: number, minimumPeriod: number = 0) {
super(defaultDelay);
this.minimumPeriod = minimumPeriod;
this.periodThrottler = new Throttler();
}
trigger(promiseFactory: ITask<TPromise<T>>, delay?: number): Promise {
return super.trigger(() => {
return this.periodThrottler.queue(() => {
return Promise.join([
TPromise.timeout(this.minimumPeriod),
promiseFactory()
]).then(r => r[1]);
});
}, delay);
}
}
export class PromiseSource<T> {
private _value: TPromise<T>;
private _completeCallback: Function;
private _errorCallback: Function;
private _isOpen: boolean;
private _promise: TPromise<boolean>;
private _completePromise: (v: boolean) => void;
constructor() {
this._value = new TPromise<T>((c, e) => {
this._completeCallback = c;
this._errorCallback = e;
this._isOpen = false;
this._promise = new TPromise<boolean>((c, e, p) => {
this._completePromise = c;
}, () => {
console.warn('You should really not try to cancel this ready promise!');
});
}
get value(): TPromise<T> {
return this._value;
isOpen(): boolean {
return this._isOpen;
}
complete(value?: T): void {
this._completeCallback(value);
open(): void {
this._isOpen = true;
this._completePromise(true);
}
error(err?: any): void {
this._errorCallback(err);
wait(): TPromise<boolean> {
return this._promise;
}
}
@@ -510,7 +488,7 @@ export class Queue<T> extends Limiter<T> {
* A helper to organize queues per resource. The ResourceQueue makes sure to manage queues per resource
* by disposing them once the queue is empty.
*/
export class ResourceQueue<T> {
export class ResourceQueue {
private queues: { [path: string]: Queue<void> };
constructor() {
@@ -639,13 +617,6 @@ export class RunOnceScheduler {
}
}
/**
* Replace runner. If there is a runner already scheduled, the new runner will be called.
*/
setRunner(runner: () => void): void {
this.runner = runner;
}
/**
* Cancel previous runner (if any) & schedule a new runner.
*/
@@ -672,11 +643,53 @@ export class RunOnceScheduler {
export function nfcall(fn: Function, ...args: any[]): Promise;
export function nfcall<T>(fn: Function, ...args: any[]): TPromise<T>;
export function nfcall(fn: Function, ...args: any[]): any {
return new TPromise((c, e) => fn(...args, (err, result) => err ? e(err) : c(result)), () => null);
return new TPromise((c, e) => fn(...args, (err: any, result: any) => err ? e(err) : c(result)), () => null);
}
export function ninvoke(thisArg: any, fn: Function, ...args: any[]): Promise;
export function ninvoke<T>(thisArg: any, fn: Function, ...args: any[]): TPromise<T>;
export function ninvoke(thisArg: any, fn: Function, ...args: any[]): any {
return new TPromise((c, e) => fn.call(thisArg, ...args, (err, result) => err ? e(err) : c(result)), () => null);
return new TPromise((c, e) => fn.call(thisArg, ...args, (err: any, result: any) => err ? e(err) : c(result)), () => null);
}
/**
* An emitter that will ignore any events that occur during a specific code
* execution triggered via throttle() until the promise has finished (either
* successfully or with an error). Only after the promise has finished, the
* last event that was fired during the operation will get emitted.
*
*/
export class ThrottledEmitter<T> extends Emitter<T> {
private suspended: boolean;
private lastEvent: T;
private hasLastEvent: boolean;
public throttle<C>(promise: TPromise<C>): TPromise<C> {
this.suspended = true;
return always(promise, () => this.resume());
}
public fire(event?: T): any {
if (this.suspended) {
this.lastEvent = event;
this.hasLastEvent = true;
return;
}
return super.fire(event);
}
private resume(): void {
this.suspended = false;
if (this.hasLastEvent) {
this.fire(this.lastEvent);
}
this.hasLastEvent = false;
this.lastEvent = void 0;
}
}

View File

@@ -1,60 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IDisposable } from 'vs/base/common/lifecycle';
import { onUnexpectedError } from 'vs/base/common/errors';
import { LinkedList } from 'vs/base/common/linkedList';
export default class CallbackList {
private _callbacks: LinkedList<[Function, any]>;
public add(callback: Function, context: any = null, bucket?: IDisposable[]): () => void {
if (!this._callbacks) {
this._callbacks = new LinkedList<[Function, any]>();
}
const remove = this._callbacks.push([callback, context]);
if (Array.isArray(bucket)) {
bucket.push({ dispose: remove });
}
return remove;
}
public invoke(...args: any[]): any[] {
if (!this._callbacks) {
return undefined;
}
const ret: any[] = [];
const elements = this._callbacks.toArray();
for (const [callback, context] of elements) {
try {
ret.push(callback.apply(context, args));
} catch (e) {
onUnexpectedError(e);
}
}
return ret;
}
public entries(): [Function, any][] {
if (!this._callbacks) {
return [];
}
return this._callbacks
? this._callbacks.toArray()
: [];
}
public isEmpty(): boolean {
return !this._callbacks || this._callbacks.isEmpty();
}
public dispose(): void {
this._callbacks = undefined;
}
}

View File

@@ -31,7 +31,7 @@ export function values<T>(from: IStringDictionary<T> | INumberDictionary<T>): T[
const result: T[] = [];
for (let key in from) {
if (hasOwnProperty.call(from, key)) {
result.push(from[key]);
result.push((from as any)[key]);
}
}
return result;
@@ -54,8 +54,8 @@ export function size<T>(from: IStringDictionary<T> | INumberDictionary<T>): numb
export function forEach<T>(from: IStringDictionary<T> | INumberDictionary<T>, callback: (entry: { key: any; value: T; }, remove: Function) => any): void {
for (let key in from) {
if (hasOwnProperty.call(from, key)) {
const result = callback({ key: key, value: from[key] }, function () {
delete from[key];
const result = callback({ key: key, value: (from as any)[key] }, function () {
delete (from as any)[key];
});
if (result === false) {
return;
@@ -72,7 +72,7 @@ export function remove<T>(from: IStringDictionary<T> | INumberDictionary<T>, key
if (!hasOwnProperty.call(from, key)) {
return false;
}
delete from[key];
delete (from as any)[key];
return true;
}

View File

@@ -214,7 +214,7 @@ export class HSVA {
m = ((r - g) / delta) + 4;
}
return new HSVA(m * 60, s, cmax, rgba.a);
return new HSVA(Math.round(m * 60), s, cmax, rgba.a);
}
// from http://www.rapidtables.com/convert/color/hsv-to-rgb.htm

View File

@@ -0,0 +1,25 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
function pad(number: number): string {
if (number < 10) {
return '0' + number;
}
return String(number);
}
export function toLocalISOString(date: Date): string {
return date.getFullYear() +
'-' + pad(date.getMonth() + 1) +
'-' + pad(date.getDate()) +
'T' + pad(date.getHours()) +
':' + pad(date.getMinutes()) +
':' + pad(date.getSeconds()) +
'.' + (date.getMilliseconds() / 1000).toFixed(3).slice(2, 5) +
'Z';
}

View File

@@ -62,7 +62,7 @@ export function debounce(delay: number): Function {
return createDecorator((fn, key) => {
const timerKey = `$debounce$${key}`;
return function (...args: any[]) {
return function (this: any, ...args: any[]) {
clearTimeout(this[timerKey]);
this[timerKey] = setTimeout(() => fn.apply(this, args), delay);
};

View File

@@ -95,7 +95,7 @@ export class MyArray {
// LcsDiff.cs
//
// An implementation of the difference algorithm described in
// "An O(ND) Difference Algorithm and its letiations" by Eugene W. Myers
// "An O(ND) Difference Algorithm and its variations" by Eugene W. Myers
//
// Copyright (C) 2008 Microsoft Corporation @minifier_do_not_preserve
//*****************************************************************************
@@ -215,7 +215,7 @@ const hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* An implementation of the difference algorithm described in
* "An O(ND) Difference Algorithm and its letiations" by Eugene W. Myers
* "An O(ND) Difference Algorithm and its variations" by Eugene W. Myers
*/
export class LcsDiff {

View File

@@ -57,8 +57,6 @@ export class LcsDiff2 {
private ids_for_x: number[];
private ids_for_y: number[];
private hashFunc: IHashFunction;
private resultX: boolean[];
private resultY: boolean[];
private forwardPrev: number[];
@@ -72,14 +70,6 @@ export class LcsDiff2 {
this.ids_for_x = [];
this.ids_for_y = [];
if (hashFunc) {
this.hashFunc = hashFunc;
} else {
this.hashFunc = function (sequence, index) {
return sequence[index];
};
}
this.resultX = [];
this.resultY = [];
this.forwardPrev = [];

View File

@@ -4,12 +4,6 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
export const DifferenceType = {
Add: 0,
Remove: 1,
Change: 2
};
/**
* Represents information about a specific difference between two sequences.
*/
@@ -51,19 +45,6 @@ export class DiffChange {
this.modifiedLength = modifiedLength;
}
/**
* The type of difference.
*/
public getChangeType() {
if (this.originalLength === 0) {
return DifferenceType.Add;
} else if (this.modifiedLength === 0) {
return DifferenceType.Remove;
} else {
return DifferenceType.Change;
}
}
/**
* The end point (exclusive) of the change in the original sequence.
*/

View File

@@ -5,156 +5,8 @@
'use strict';
import nls = require('vs/nls');
import objects = require('vs/base/common/objects');
import types = require('vs/base/common/types');
import arrays = require('vs/base/common/arrays');
import strings = require('vs/base/common/strings');
export interface IXHRResponse {
responseText: string;
status: number;
readyState: number;
getResponseHeader: (header: string) => string;
}
export interface IConnectionErrorData {
status: number;
statusText?: string;
responseText?: string;
}
/**
* The base class for all connection errors originating from XHR requests.
*/
export class ConnectionError implements Error {
public status: number;
public statusText: string;
public responseText: string;
public errorMessage: string;
public errorCode: string;
public errorObject: any;
public name: string;
constructor(mixin: IConnectionErrorData);
constructor(request: IXHRResponse);
constructor(arg: any) {
this.status = arg.status;
this.statusText = arg.statusText;
this.name = 'ConnectionError';
try {
this.responseText = arg.responseText;
} catch (e) {
this.responseText = '';
}
this.errorMessage = null;
this.errorCode = null;
this.errorObject = null;
if (this.responseText) {
try {
let errorObj = JSON.parse(this.responseText);
this.errorMessage = errorObj.message;
this.errorCode = errorObj.code;
this.errorObject = errorObj;
} catch (error) {
// Ignore
}
}
}
public get message(): string {
return this.connectionErrorToMessage(this, false);
}
public get verboseMessage(): string {
return this.connectionErrorToMessage(this, true);
}
private connectionErrorDetailsToMessage(error: ConnectionError, verbose: boolean): string {
let errorCode = error.errorCode;
let errorMessage = error.errorMessage;
if (errorCode !== null && errorMessage !== null) {
return nls.localize(
{
key: 'message',
comment: [
'{0} represents the error message',
'{1} represents the error code'
]
},
"{0}. Error code: {1}",
strings.rtrim(errorMessage, '.'), errorCode);
}
if (errorMessage !== null) {
return errorMessage;
}
if (verbose && error.responseText !== null) {
return error.responseText;
}
return null;
}
private connectionErrorToMessage(error: ConnectionError, verbose: boolean): string {
let details = this.connectionErrorDetailsToMessage(error, verbose);
// Status Code based Error
if (error.status === 401) {
if (details !== null) {
return nls.localize(
{
key: 'error.permission.verbose',
comment: [
'{0} represents detailed information why the permission got denied'
]
},
"Permission Denied (HTTP {0})",
details);
}
return nls.localize('error.permission', "Permission Denied");
}
// Return error details if present
if (details) {
return details;
}
// Fallback to HTTP Status and Code
if (error.status > 0 && error.statusText !== null) {
if (verbose && error.responseText !== null && error.responseText.length > 0) {
return nls.localize('error.http.verbose', "{0} (HTTP {1}: {2})", error.statusText, error.status, error.responseText);
}
return nls.localize('error.http', "{0} (HTTP {1})", error.statusText, error.status);
}
// Finally its an Unknown Connection Error
if (verbose && error.responseText !== null && error.responseText.length > 0) {
return nls.localize('error.connection.unknown.verbose', "Unknown Connection Error ({0})", error.responseText);
}
return nls.localize('error.connection.unknown', "An unknown connection error occurred. Either you are no longer connected to the internet or the server you are connected to is offline.");
}
}
// Bug: Can not subclass a JS Type. Do it manually (as done in WinJS.Class.derive)
objects.derive(Error, ConnectionError);
function xhrToErrorMessage(xhr: IConnectionErrorData, verbose: boolean): string {
let ce = new ConnectionError(xhr);
if (verbose) {
return ce.verboseMessage;
} else {
return ce.message;
}
}
function exceptionToErrorMessage(exception: any, verbose: boolean): string {
if (exception.message) {
@@ -181,6 +33,7 @@ function detectSystemErrorMessage(exception: any): string {
/**
* Tries to generate a human readable error message out of the error. If the verbose parameter
* is set to true, the error message will include stacktrace details if provided.
*
* @returns A string containing the error message.
*/
export function toErrorMessage(error: any = null, verbose: boolean = false): string {
@@ -189,8 +42,8 @@ export function toErrorMessage(error: any = null, verbose: boolean = false): str
}
if (Array.isArray(error)) {
let errors: any[] = arrays.coalesce(error);
let msg = toErrorMessage(errors[0], verbose);
const errors: any[] = arrays.coalesce(error);
const msg = toErrorMessage(errors[0], verbose);
if (errors.length > 1) {
return nls.localize('error.moreErrors', "{0} ({1} errors in total)", msg, errors.length);
@@ -203,36 +56,14 @@ export function toErrorMessage(error: any = null, verbose: boolean = false): str
return error;
}
if (!types.isUndefinedOrNull(error.status)) {
return xhrToErrorMessage(error, verbose);
}
if (error.detail) {
let detail = error.detail;
const detail = error.detail;
if (detail.error) {
if (detail.error && !types.isUndefinedOrNull(detail.error.status)) {
return xhrToErrorMessage(detail.error, verbose);
}
if (types.isArray(detail.error)) {
for (let i = 0; i < detail.error.length; i++) {
if (detail.error[i] && !types.isUndefinedOrNull(detail.error[i].status)) {
return xhrToErrorMessage(detail.error[i], verbose);
}
}
}
else {
return exceptionToErrorMessage(detail.error, verbose);
}
return exceptionToErrorMessage(detail.error, verbose);
}
if (detail.exception) {
if (!types.isUndefinedOrNull(detail.exception.status)) {
return xhrToErrorMessage(detail.exception, verbose);
}
return exceptionToErrorMessage(detail.exception, verbose);
}
}

View File

@@ -148,10 +148,6 @@ export function onUnexpectedExternalError(e: any): undefined {
return undefined;
}
export function onUnexpectedPromiseError<T>(promise: TPromise<T>): TPromise<T | void> {
return promise.then(null, onUnexpectedError);
}
export interface SerializedError {
readonly $isError: true;
readonly name: string;
@@ -213,13 +209,6 @@ export function canceled(): Error {
return error;
}
/**
* Returns an error that signals something is not implemented.
*/
export function notImplemented(): Error {
return new Error('Not Implemented');
}
export function illegalArgument(name?: string): Error {
if (name) {
return new Error(`Illegal argument: ${name}`);

View File

@@ -5,10 +5,10 @@
'use strict';
import { IDisposable, toDisposable, combinedDisposable, empty as EmptyDisposable } from 'vs/base/common/lifecycle';
import CallbackList from 'vs/base/common/callbackList';
import { EventEmitter } from 'vs/base/common/eventEmitter';
import { TPromise } from 'vs/base/common/winjs.base';
import { once as onceFn } from 'vs/base/common/functional';
import { onUnexpectedError } from 'vs/base/common/errors';
import { LinkedList } from 'vs/base/common/linkedList';
/**
* To an event a function with one or zero parameters
@@ -25,6 +25,8 @@ namespace Event {
export default Event;
type Listener = [Function, any] | Function;
export interface EmitterOptions {
onFirstListenerAdd?: Function;
onFirstListenerDidAdd?: Function;
@@ -55,10 +57,11 @@ export interface EmitterOptions {
*/
export class Emitter<T> {
private static _noop = function () { };
private static readonly _noop = function () { };
private _event: Event<T>;
private _callbacks: CallbackList;
private _listeners: LinkedList<Listener>;
private _deliveryQueue: [Listener, T][];
private _disposed: boolean;
constructor(private _options?: EmitterOptions) {
@@ -72,17 +75,17 @@ export class Emitter<T> {
get event(): Event<T> {
if (!this._event) {
this._event = (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]) => {
if (!this._callbacks) {
this._callbacks = new CallbackList();
if (!this._listeners) {
this._listeners = new LinkedList();
}
const firstListener = this._callbacks.isEmpty();
const firstListener = this._listeners.isEmpty();
if (firstListener && this._options && this._options.onFirstListenerAdd) {
this._options.onFirstListenerAdd(this);
}
const remove = this._callbacks.add(listener, thisArgs);
const remove = this._listeners.push(!thisArgs ? listener : [listener, thisArgs]);
if (firstListener && this._options && this._options.onFirstListenerDidAdd) {
this._options.onFirstListenerDidAdd(this);
@@ -98,7 +101,7 @@ export class Emitter<T> {
result.dispose = Emitter._noop;
if (!this._disposed) {
remove();
if (this._options && this._options.onLastListenerRemove && this._callbacks.isEmpty()) {
if (this._options && this._options.onLastListenerRemove && this._listeners.isEmpty()) {
this._options.onLastListenerRemove(this);
}
}
@@ -119,17 +122,42 @@ export class Emitter<T> {
* subscribers
*/
fire(event?: T): any {
if (this._callbacks) {
this._callbacks.invoke.call(this._callbacks, event);
if (this._listeners) {
// put all [listener,event]-pairs into delivery queue
// then emit all event. an inner/nested event might be
// the driver of this
if (!this._deliveryQueue) {
this._deliveryQueue = [];
}
for (let iter = this._listeners.iterator(), e = iter.next(); !e.done; e = iter.next()) {
this._deliveryQueue.push([e.value, event]);
}
while (this._deliveryQueue.length > 0) {
const [listener, event] = this._deliveryQueue.shift();
try {
if (typeof listener === 'function') {
listener.call(undefined, event);
} else {
listener[0].call(listener[1], event);
}
} catch (e) {
onUnexpectedError(e);
}
}
}
}
dispose() {
if (this._callbacks) {
this._callbacks.dispose();
this._callbacks = undefined;
this._disposed = true;
if (this._listeners) {
this._listeners = undefined;
}
if (this._deliveryQueue) {
this._deliveryQueue.length = 0;
}
this._disposed = true;
}
}
@@ -194,40 +222,6 @@ export class EventMultiplexer<T> implements IDisposable {
}
}
/**
* Creates an Event which is backed-up by the event emitter. This allows
* to use the existing eventing pattern and is likely using less memory.
* Sample:
*
* class Document {
*
* private _eventbus = new EventEmitter();
*
* public onDidChange = fromEventEmitter(this._eventbus, 'changed');
*
* // getter-style
* // get onDidChange(): Event<(value:string)=>any> {
* // cache fromEventEmitter result and return
* // }
*
* private _doIt() {
* // ...
* this._eventbus.emit('changed', value)
* }
* }
*/
export function fromEventEmitter<T>(emitter: EventEmitter, eventType: string): Event<T> {
return function (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable {
const result = emitter.addListener(eventType, function () {
listener.apply(thisArgs, arguments);
});
if (Array.isArray(disposables)) {
disposables.push(result);
}
return result;
};
}
export function fromCallback<T>(fn: (handler: (e: T) => void) => IDisposable): Event<T> {
let listener: IDisposable;
@@ -239,8 +233,8 @@ export function fromCallback<T>(fn: (handler: (e: T) => void) => IDisposable): E
return emitter.event;
}
export function fromPromise(promise: TPromise<any>): Event<void> {
const emitter = new Emitter<void>();
export function fromPromise<T =any>(promise: TPromise<T>): Event<T> {
const emitter = new Emitter<T>();
let shouldEmit = false;
promise
@@ -266,33 +260,6 @@ export function toPromise<T>(event: Event<T>): TPromise<T> {
});
}
export function delayed<T>(promise: TPromise<Event<T>>): Event<T> {
let toCancel: TPromise<any> = null;
let listener: IDisposable = null;
const emitter = new Emitter<T>({
onFirstListenerAdd() {
toCancel = promise.then(
event => listener = event(e => emitter.fire(e)),
() => null
);
},
onLastListenerRemove() {
if (toCancel) {
toCancel.cancel();
toCancel = null;
}
if (listener) {
listener.dispose();
listener = null;
}
}
});
return emitter.event;
}
export function once<T>(event: Event<T>): Event<T> {
return (listener, thisArgs = null, disposables?) => {
const result = event(e => {
@@ -398,6 +365,7 @@ 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>;
on(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable;
}
@@ -406,6 +374,10 @@ 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> {
return (listener, thisArgs = null, disposables?) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables);
}
@@ -420,6 +392,10 @@ class ChainableEvent<T> implements IChainableEvent<T> {
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));
}
@@ -532,7 +508,7 @@ export function echo<T>(event: Event<T>, nextTick = false, buffer: T[] = []): Ev
export class Relay<T> implements IDisposable {
private emitter = new Emitter<T>();
readonly output: Event<T> = this.emitter.event;
readonly event: Event<T> = this.emitter.event;
private disposable: IDisposable = EmptyDisposable;
@@ -546,3 +522,17 @@ 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;
}

View File

@@ -1,299 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import Errors = require('vs/base/common/errors');
import { IDisposable } from 'vs/base/common/lifecycle';
export class EmitterEvent {
public readonly type: string;
public readonly data: any;
constructor(eventType: string = null, data: any = null) {
this.type = eventType;
this.data = data;
}
}
export interface ListenerCallback {
(value: any): void;
}
export interface BulkListenerCallback {
(value: EmitterEvent[]): void;
}
export interface IBaseEventEmitter {
addBulkListener(listener: BulkListenerCallback): IDisposable;
}
export interface IEventEmitter extends IBaseEventEmitter, IDisposable {
addListener(eventType: string, listener: ListenerCallback): IDisposable;
addOneTimeListener(eventType: string, listener: ListenerCallback): IDisposable;
addEmitter(eventEmitter: IEventEmitter): IDisposable;
}
export interface IListenersMap {
[key: string]: ListenerCallback[];
}
export class EventEmitter implements IEventEmitter {
protected _listeners: IListenersMap;
protected _bulkListeners: ListenerCallback[];
private _collectedEvents: EmitterEvent[];
private _deferredCnt: number;
private _allowedEventTypes: { [eventType: string]: boolean; };
constructor(allowedEventTypes: string[] = null) {
this._listeners = {};
this._bulkListeners = [];
this._collectedEvents = [];
this._deferredCnt = 0;
if (allowedEventTypes) {
this._allowedEventTypes = {};
for (let i = 0; i < allowedEventTypes.length; i++) {
this._allowedEventTypes[allowedEventTypes[i]] = true;
}
} else {
this._allowedEventTypes = null;
}
}
public dispose(): void {
this._listeners = {};
this._bulkListeners = [];
this._collectedEvents = [];
this._deferredCnt = 0;
this._allowedEventTypes = null;
}
public addListener(eventType: string, listener: ListenerCallback): IDisposable {
if (eventType === '*') {
throw new Error('Use addBulkListener(listener) to register your listener!');
}
if (this._allowedEventTypes && !this._allowedEventTypes.hasOwnProperty(eventType)) {
throw new Error('This object will never emit this event type!');
}
if (this._listeners.hasOwnProperty(eventType)) {
this._listeners[eventType].push(listener);
} else {
this._listeners[eventType] = [listener];
}
let bound = this;
return {
dispose: () => {
if (!bound) {
// Already called
return;
}
bound._removeListener(eventType, listener);
// Prevent leakers from holding on to the event emitter
bound = null;
listener = null;
}
};
}
public addOneTimeListener(eventType: string, listener: ListenerCallback): IDisposable {
const disposable = this.addListener(eventType, value => {
disposable.dispose();
listener(value);
});
return disposable;
}
public addBulkListener(listener: BulkListenerCallback): IDisposable {
this._bulkListeners.push(listener);
return {
dispose: () => {
this._removeBulkListener(listener);
}
};
}
public addEmitter(eventEmitter: IBaseEventEmitter): IDisposable {
return eventEmitter.addBulkListener((events: EmitterEvent[]): void => {
if (this._deferredCnt === 0) {
this._emitEvents(events);
} else {
// Collect for later
this._collectedEvents.push.apply(this._collectedEvents, events);
}
});
}
private _removeListener(eventType: string, listener: ListenerCallback): void {
if (this._listeners.hasOwnProperty(eventType)) {
let listeners = this._listeners[eventType];
for (let i = 0, len = listeners.length; i < len; i++) {
if (listeners[i] === listener) {
listeners.splice(i, 1);
break;
}
}
}
}
private _removeBulkListener(listener: BulkListenerCallback): void {
for (let i = 0, len = this._bulkListeners.length; i < len; i++) {
if (this._bulkListeners[i] === listener) {
this._bulkListeners.splice(i, 1);
break;
}
}
}
protected _emitToSpecificTypeListeners(eventType: string, data: any): void {
if (this._listeners.hasOwnProperty(eventType)) {
const listeners = this._listeners[eventType].slice(0);
for (let i = 0, len = listeners.length; i < len; i++) {
safeInvoke1Arg(listeners[i], data);
}
}
}
protected _emitToBulkListeners(events: EmitterEvent[]): void {
const bulkListeners = this._bulkListeners.slice(0);
for (let i = 0, len = bulkListeners.length; i < len; i++) {
safeInvoke1Arg(bulkListeners[i], events);
}
}
protected _emitEvents(events: EmitterEvent[]): void {
if (this._bulkListeners.length > 0) {
this._emitToBulkListeners(events);
}
for (let i = 0, len = events.length; i < len; i++) {
const e = events[i];
this._emitToSpecificTypeListeners(e.type, e.data);
}
}
public emit(eventType: string, data: any = {}): void {
if (this._allowedEventTypes && !this._allowedEventTypes.hasOwnProperty(eventType)) {
throw new Error('Cannot emit this event type because it wasn\'t listed!');
}
// Early return if no listeners would get this
if (!this._listeners.hasOwnProperty(eventType) && this._bulkListeners.length === 0) {
return;
}
const emitterEvent = new EmitterEvent(eventType, data);
if (this._deferredCnt === 0) {
this._emitEvents([emitterEvent]);
} else {
// Collect for later
this._collectedEvents.push(emitterEvent);
}
}
public beginDeferredEmit(): void {
this._deferredCnt = this._deferredCnt + 1;
}
public endDeferredEmit(): void {
this._deferredCnt = this._deferredCnt - 1;
if (this._deferredCnt === 0) {
this._emitCollected();
}
}
public deferredEmit<T>(callback: () => T): T {
this.beginDeferredEmit();
let result: T = safeInvokeNoArg<T>(callback);
this.endDeferredEmit();
return result;
}
private _emitCollected(): void {
if (this._collectedEvents.length === 0) {
return;
}
// Flush collected events
const events = this._collectedEvents;
this._collectedEvents = [];
this._emitEvents(events);
}
}
class EmitQueueElement {
public target: Function;
public arg: any;
constructor(target: Function, arg: any) {
this.target = target;
this.arg = arg;
}
}
/**
* Same as EventEmitter, but guarantees events are delivered in order to each listener
*/
export class OrderGuaranteeEventEmitter extends EventEmitter {
private _emitQueue: EmitQueueElement[];
constructor() {
super(null);
this._emitQueue = [];
}
protected _emitToSpecificTypeListeners(eventType: string, data: any): void {
if (this._listeners.hasOwnProperty(eventType)) {
let listeners = this._listeners[eventType];
for (let i = 0, len = listeners.length; i < len; i++) {
this._emitQueue.push(new EmitQueueElement(listeners[i], data));
}
}
}
protected _emitToBulkListeners(events: EmitterEvent[]): void {
let bulkListeners = this._bulkListeners;
for (let i = 0, len = bulkListeners.length; i < len; i++) {
this._emitQueue.push(new EmitQueueElement(bulkListeners[i], events));
}
}
protected _emitEvents(events: EmitterEvent[]): void {
super._emitEvents(events);
while (this._emitQueue.length > 0) {
let queueElement = this._emitQueue.shift();
safeInvoke1Arg(queueElement.target, queueElement.arg);
}
}
}
function safeInvokeNoArg<T>(func: Function): T {
try {
return func();
} catch (e) {
Errors.onUnexpectedError(e);
}
return undefined;
}
function safeInvoke1Arg(func: Function, arg1: any): any {
try {
return func(arg1);
} catch (e) {
Errors.onUnexpectedError(e);
}
}

View File

@@ -1,78 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
export class Event {
public time: number;
public originalEvent: Event;
public source: any;
constructor(originalEvent?: Event) {
this.time = (new Date()).getTime();
this.originalEvent = originalEvent;
this.source = null;
}
}
export class PropertyChangeEvent extends Event {
public key: string;
public oldValue: any;
public newValue: any;
constructor(key?: string, oldValue?: any, newValue?: any, originalEvent?: Event) {
super(originalEvent);
this.key = key;
this.oldValue = oldValue;
this.newValue = newValue;
}
}
export class ViewerEvent extends Event {
public element: any;
constructor(element: any, originalEvent?: Event) {
super(originalEvent);
this.element = element;
}
}
export interface ISelectionEvent {
selection: any[];
payload?: any;
source: any;
}
export interface IFocusEvent {
focus: any;
payload?: any;
source: any;
}
export interface IHighlightEvent {
highlight: any;
payload?: any;
source: any;
}
export const EventType = {
PROPERTY_CHANGED: 'propertyChanged',
SELECTION: 'selection',
FOCUS: 'focus',
BLUR: 'blur',
HIGHLIGHT: 'highlight',
EXPAND: 'expand',
COLLAPSE: 'collapse',
TOGGLE: 'toggle',
BEFORE_RUN: 'beforeRun',
RUN: 'run',
EDIT: 'edit',
SAVE: 'save',
CANCEL: 'cancel',
CHANGE: 'change',
DISPOSE: 'dispose',
};

View File

@@ -5,7 +5,7 @@
'use strict';
import strings = require('vs/base/common/strings');
import { BoundedMap } from 'vs/base/common/map';
import { LRUCache } from 'vs/base/common/map';
import { CharCode } from 'vs/base/common/charCode';
export interface IFilter {
@@ -38,25 +38,6 @@ export function or(...filter: IFilter[]): IFilter {
};
}
/**
* @returns A filter which combines the provided set
* of filters with an and. The combines matches are
* returned if *all* filters match.
*/
export function and(...filter: IFilter[]): IFilter {
return function (word: string, wordToMatchAgainst: string): IMatch[] {
let result: IMatch[] = [];
for (let i = 0, len = filter.length; i < len; i++) {
let match = filter[i](word, wordToMatchAgainst);
if (!match) {
return null;
}
result = result.concat(match);
}
return result;
};
}
// Prefix
export const matchesStrictPrefix: IFilter = _matchesPrefix.bind(undefined, false);
@@ -334,14 +315,9 @@ function nextWord(word: string, start: number): number {
// Fuzzy
export enum SubstringMatching {
Contiguous,
Separate
}
export const fuzzyContiguousFilter = or(matchesPrefix, matchesCamelCase, matchesContiguousSubString);
const fuzzySeparateFilter = or(matchesPrefix, matchesCamelCase, matchesSubString);
const fuzzyRegExpCache = new BoundedMap<RegExp>(10000); // bounded to 10000 elements
const fuzzyRegExpCache = new LRUCache<string, RegExp>(10000); // bounded to 10000 elements
export function matchesFuzzy(word: string, wordToMatchAgainst: string, enableSeparateSubstringMatching = false): IMatch[] {
if (typeof word !== 'string' || typeof wordToMatchAgainst !== 'string') {
@@ -365,6 +341,8 @@ export function matchesFuzzy(word: string, wordToMatchAgainst: string, enableSep
return enableSeparateSubstringMatching ? fuzzySeparateFilter(word, wordToMatchAgainst) : fuzzyContiguousFilter(word, wordToMatchAgainst);
}
//#region --- fuzzyScore ---
export function createMatches(position: number[]): IMatch[] {
let ret: IMatch[] = [];
if (!position) {
@@ -527,7 +505,7 @@ export function fuzzyScore(pattern: string, word: string, patternMaxWhitespaceIg
} else {
score = 5;
}
} else if (isSeparatorAtPos(lowWord, wordPos - 2)) {
} else if (isSeparatorAtPos(lowWord, wordPos - 2) || isWhitespaceAtPos(lowWord, wordPos - 2)) {
// post separator: `foo <-> bar_foo`
score = 5;
@@ -697,8 +675,7 @@ class LazyArray {
slice(): LazyArray {
const ret = new LazyArray();
ret._parent = this;
ret._parentLen = this._data ? this._data.length : 0;
return ret;
ret._parentLen = this._data ? this._data.length : 0; return ret;
}
toArray(): number[] {
@@ -717,23 +694,69 @@ class LazyArray {
}
}
export function nextTypoPermutation(pattern: string, patternPos: number) {
//#endregion
//#region --- graceful ---
export function fuzzyScoreGracefulAggressive(pattern: string, word: string, patternMaxWhitespaceIgnore?: number): [number, number[]] {
return fuzzyScoreWithPermutations(pattern, word, true, patternMaxWhitespaceIgnore);
}
export function fuzzyScoreGraceful(pattern: string, word: string, patternMaxWhitespaceIgnore?: number): [number, number[]] {
return fuzzyScoreWithPermutations(pattern, word, false, patternMaxWhitespaceIgnore);
}
function fuzzyScoreWithPermutations(pattern: string, word: string, aggressive?: boolean, patternMaxWhitespaceIgnore?: number): [number, number[]] {
let top: [number, number[]] = fuzzyScore(pattern, word, patternMaxWhitespaceIgnore);
if (top && !aggressive) {
// when using the original pattern yield a result we`
// return it unless we are aggressive and try to find
// a better alignment, e.g. `cno` -> `^co^ns^ole` or `^c^o^nsole`.
return top;
}
if (pattern.length >= 3) {
// When the pattern is long enough then try a few (max 7)
// permutations of the pattern to find a better match. The
// permutations only swap neighbouring characters, e.g
// `cnoso` becomes `conso`, `cnsoo`, `cnoos`.
let tries = Math.min(7, pattern.length - 1);
for (let patternPos = 1; patternPos < tries; patternPos++) {
let newPattern = nextTypoPermutation(pattern, patternPos);
if (newPattern) {
let candidate = fuzzyScore(newPattern, word, patternMaxWhitespaceIgnore);
if (candidate) {
candidate[0] -= 3; // permutation penalty
if (!top || candidate[0] > top[0]) {
top = candidate;
}
}
}
}
}
return top;
}
function nextTypoPermutation(pattern: string, patternPos: number): string {
if (patternPos + 1 >= pattern.length) {
return undefined;
}
let swap1 = pattern[patternPos];
let swap2 = pattern[patternPos + 1];
if (swap1 === swap2) {
return undefined;
}
return pattern.slice(0, patternPos)
+ pattern[patternPos + 1]
+ pattern[patternPos]
+ swap2
+ swap1
+ pattern.slice(patternPos + 2);
}
export function fuzzyScoreGraceful(pattern: string, word: string): [number, number[]] {
let ret = fuzzyScore(pattern, word);
for (let patternPos = 1; patternPos < pattern.length - 1 && !ret; patternPos++) {
let pattern2 = nextTypoPermutation(pattern, patternPos);
ret = fuzzyScore(pattern2, word);
}
return ret;
}
//#endregion

View File

@@ -5,12 +5,7 @@
'use strict';
export function not<A>(fn: (a: A) => boolean): (a: A) => boolean;
export function not(fn: Function): Function {
return (...args) => !fn(...args);
}
export function once<T extends Function>(fn: T): T {
export function once<T extends Function>(this: any, fn: T): T {
const _this = this;
let didCall = false;
let result: any;

View File

@@ -5,10 +5,9 @@
'use strict';
import arrays = require('vs/base/common/arrays');
import objects = require('vs/base/common/objects');
import strings = require('vs/base/common/strings');
import paths = require('vs/base/common/paths');
import { BoundedMap } from 'vs/base/common/map';
import { LRUCache } from 'vs/base/common/map';
import { CharCode } from 'vs/base/common/charCode';
import { TPromise } from 'vs/base/common/winjs.base';
@@ -19,16 +18,13 @@ export interface IExpression {
export interface IRelativePattern {
base: string;
pattern: string;
pathToRelative(from: string, to: string): string;
}
export function getEmptyExpression(): IExpression {
return Object.create(null);
}
export function mergeExpressions(...expressions: IExpression[]): IExpression {
return objects.assign(getEmptyExpression(), ...expressions.filter(expr => !!expr));
}
export interface SiblingClause {
when: string;
}
@@ -152,17 +148,28 @@ function parseRegExp(pattern: string): string {
}
// Support brackets
if (char !== ']' && inBrackets) {
if (inBrackets && (char !== ']' || !bracketVal) /* ] is literally only allowed as first character in brackets to match it */) {
let res: string;
switch (char) {
case '-': // allow the range operator
res = char;
break;
case '^': // allow the negate operator
res = char;
break;
default:
res = strings.escapeRegExpCharacters(char);
// range operator
if (char === '-') {
res = char;
}
// negation operator (only valid on first index in bracket)
else if ((char === '^' || char === '!') && !bracketVal) {
res = '^';
}
// glob split matching is not allowed within character ranges
// see http://man7.org/linux/man-pages/man7/glob.7.html
else if (char === GLOB_SPLIT) {
res = '';
}
// anything else gets escaped
else {
res = strings.escapeRegExpCharacters(char);
}
bracketVal += res;
@@ -261,7 +268,7 @@ interface ParsedExpressionPattern {
allPaths?: string[];
}
const CACHE = new BoundedMap<ParsedStringPattern>(10000); // bounded to 10000 elements
const CACHE = new LRUCache<string, ParsedStringPattern>(10000); // bounded to 10000 elements
const FALSE = function () {
return false;
@@ -332,7 +339,7 @@ function wrapRelativePattern(parsedPattern: ParsedStringPattern, arg2: string |
return null;
}
return parsedPattern(paths.relative(arg2.base, path), basename);
return parsedPattern(paths.normalize(arg2.pathToRelative(arg2.base, path)), basename);
};
}
@@ -471,10 +478,10 @@ export function parse(arg1: string | IExpression | IRelativePattern, options: IG
return parsedExpression(<IExpression>arg1, options);
}
function isRelativePattern(obj: any): obj is IRelativePattern {
export function isRelativePattern(obj: any): obj is IRelativePattern {
const rp = obj as IRelativePattern;
return typeof rp.base === 'string' && typeof rp.pattern === 'string';
return rp && typeof rp.base === 'string' && typeof rp.pattern === 'string' && typeof rp.pathToRelative === 'function';
}
/**
@@ -482,7 +489,7 @@ function isRelativePattern(obj: any): obj is IRelativePattern {
*/
export function parseToAsync(expression: IExpression, options?: IGlobOptions): ParsedExpression {
const parsedExpression = parse(expression, options);
return (path: string, basename?: string, siblingsFn?: () => TPromise<string[]>): TPromise<string> => {
return (path: string, basename?: string, siblingsFn?: () => string[] | TPromise<string[]>): string | TPromise<string> => {
const result = parsedExpression(path, basename, siblingsFn);
return result instanceof TPromise ? result : TPromise.as(result);
};

View File

@@ -6,7 +6,7 @@
'use strict';
export interface IIterator<E> {
next(): { done: boolean, value: E };
next(): { readonly done: boolean, readonly value: E };
}
export interface INextIterator<T> {

View File

@@ -585,39 +585,6 @@ const enum CharacterCodes {
}
/**
* Takes JSON with JavaScript-style comments and remove
* them. Optionally replaces every none-newline character
* of comments with a replaceCharacter
*/
export function stripComments(text: string, replaceCh?: string): string {
let _scanner = createScanner(text),
parts: string[] = [],
kind: SyntaxKind,
offset = 0,
pos: number;
do {
pos = _scanner.getPosition();
kind = _scanner.scan();
switch (kind) {
case SyntaxKind.LineCommentTrivia:
case SyntaxKind.BlockCommentTrivia:
case SyntaxKind.EOF:
if (offset !== pos) {
parts.push(text.substring(offset, pos));
}
if (replaceCh !== void 0) {
parts.push(_scanner.getTokenValue().replace(/[^\r\n]/g, replaceCh));
}
offset = _scanner.getPosition();
break;
}
} while (kind !== SyntaxKind.EOF);
return parts.join('');
}
export interface ParseError {
error: ParseErrorCode;
@@ -659,147 +626,6 @@ export interface Node {
export type Segment = string | number;
export type JSONPath = Segment[];
export interface Location {
/**
* The previous property key or literal value (string, number, boolean or null) or undefined.
*/
previousNode?: Node;
/**
* The path describing the location in the JSON document. The path consists of a sequence strings
* representing an object property or numbers for array indices.
*/
path: JSONPath;
/**
* Matches the locations path against a pattern consisting of strings (for properties) and numbers (for array indices).
* '*' will match a single segment, of any property name or index.
* '**' will match a sequece of segments or no segment, of any property name or index.
*/
matches: (patterns: JSONPath) => boolean;
/**
* If set, the location's offset is at a property key.
*/
isAtPropertyKey: boolean;
}
/**
* For a given offset, evaluate the location in the JSON document. Each segment in the location path is either a property name or an array index.
*/
export function getLocation(text: string, position: number): Location {
let segments: any[] = []; // strings or numbers
let earlyReturnException = new Object();
let previousNode: Node = void 0;
const previousNodeInst: Node = {
value: void 0,
offset: void 0,
length: void 0,
type: void 0
};
let isAtPropertyKey = false;
function setPreviousNode(value: string, offset: number, length: number, type: NodeType) {
previousNodeInst.value = value;
previousNodeInst.offset = offset;
previousNodeInst.length = length;
previousNodeInst.type = type;
previousNodeInst.columnOffset = void 0;
previousNode = previousNodeInst;
}
try {
visit(text, {
onObjectBegin: (offset: number, length: number) => {
if (position <= offset) {
throw earlyReturnException;
}
previousNode = void 0;
isAtPropertyKey = position > offset;
segments.push(''); // push a placeholder (will be replaced)
},
onObjectProperty: (name: string, offset: number, length: number) => {
if (position < offset) {
throw earlyReturnException;
}
setPreviousNode(name, offset, length, 'property');
segments[segments.length - 1] = name;
if (position <= offset + length) {
throw earlyReturnException;
}
},
onObjectEnd: (offset: number, length: number) => {
if (position <= offset) {
throw earlyReturnException;
}
previousNode = void 0;
segments.pop();
},
onArrayBegin: (offset: number, length: number) => {
if (position <= offset) {
throw earlyReturnException;
}
previousNode = void 0;
segments.push(0);
},
onArrayEnd: (offset: number, length: number) => {
if (position <= offset) {
throw earlyReturnException;
}
previousNode = void 0;
segments.pop();
},
onLiteralValue: (value: any, offset: number, length: number) => {
if (position < offset) {
throw earlyReturnException;
}
setPreviousNode(value, offset, length, getLiteralNodeType(value));
if (position <= offset + length) {
throw earlyReturnException;
}
},
onSeparator: (sep: string, offset: number, length: number) => {
if (position <= offset) {
throw earlyReturnException;
}
if (sep === ':' && previousNode.type === 'property') {
previousNode.columnOffset = offset;
isAtPropertyKey = false;
previousNode = void 0;
} else if (sep === ',') {
let last = segments[segments.length - 1];
if (typeof last === 'number') {
segments[segments.length - 1] = last + 1;
} else {
isAtPropertyKey = true;
segments[segments.length - 1] = '';
}
previousNode = void 0;
}
}
});
} catch (e) {
if (e !== earlyReturnException) {
throw e;
}
}
return {
path: segments,
previousNode,
isAtPropertyKey,
matches: (pattern: string[]) => {
let k = 0;
for (let i = 0; k < pattern.length && i < segments.length; i++) {
if (pattern[k] === segments[i] || pattern[k] === '*') {
k++;
} else if (pattern[k] !== '**') {
return false;
}
}
return k === pattern.length;
}
};
}
export interface ParseOptions {
disallowComments?: boolean;
allowTrailingComma?: boolean;
@@ -1135,6 +961,9 @@ export function visit(text: string, visitor: JSONVisitor, options?: ParseOptions
}
onSeparator(',');
scanNext(); // consume comma
if (_scanner.getToken() === SyntaxKind.CloseBracketToken && allowTrailingComma) {
break;
}
} else if (needsComma) {
handleError(ParseErrorCode.CommaExpected, [], []);
}

View File

@@ -55,6 +55,7 @@ export interface IJSONSchema {
markdownEnumDescriptions?: string[]; // VSCode extension
markdownDescription?: string; // VSCode extension
doNotSuggest?: boolean; // VSCode extension
allowComments?: boolean; // VSCode extension
}
export interface IJSONSchemaMap {

View File

@@ -476,6 +476,14 @@ export class SimpleKeybinding {
);
}
public getHashCode(): string {
let ctrl = this.ctrlKey ? '1' : '0';
let shift = this.shiftKey ? '1' : '0';
let alt = this.altKey ? '1' : '0';
let meta = this.metaKey ? '1' : '0';
return `${ctrl}${shift}${alt}${meta}${this.keyCode}`;
}
public isModifierKey(): boolean {
return (
this.keyCode === KeyCode.Unknown
@@ -509,6 +517,10 @@ export class ChordKeybinding {
this.firstPart = firstPart;
this.chordPart = chordPart;
}
public getHashCode(): string {
return `${this.firstPart.getHashCode()};${this.chordPart.getHashCode()}`;
}
}
export type Keybinding = SimpleKeybinding | ChordKeybinding;

View File

@@ -6,17 +6,9 @@
import URI from 'vs/base/common/uri';
import platform = require('vs/base/common/platform');
import { nativeSep, normalize, isEqualOrParent, isEqual, basename, join } from 'vs/base/common/paths';
import { nativeSep, normalize, isEqualOrParent, isEqual, basename as pathsBasename, join } from 'vs/base/common/paths';
import { endsWith, ltrim } from 'vs/base/common/strings';
export interface ILabelProvider {
/**
* Given an element returns a label for it to display in the UI.
*/
getLabel(element: any): string;
}
export interface IWorkspaceFolderProvider {
getWorkspaceFolder(resource: URI): { uri: URI };
getWorkspace(): {
@@ -54,7 +46,7 @@ export function getPathLabel(resource: URI | string, rootProvider?: IWorkspaceFo
}
if (hasMultipleRoots) {
const rootName = basename(baseResource.uri.fsPath);
const rootName = pathsBasename(baseResource.uri.fsPath);
pathLabel = pathLabel ? join(rootName, pathLabel) : rootName; // always show root basename if there are multiple
}
@@ -75,6 +67,25 @@ export function getPathLabel(resource: URI | string, rootProvider?: IWorkspaceFo
return res;
}
export function getBaseLabel(resource: URI | string): string {
if (!resource) {
return null;
}
if (typeof resource === 'string') {
resource = URI.file(resource);
}
const base = pathsBasename(resource.fsPath) || resource.fsPath /* can be empty string if '/' is passed in */;
// convert c: => C:
if (hasDriveLetter(base)) {
return normalizeDriveLetter(base);
}
return base;
}
function hasDriveLetter(path: string): boolean {
return platform.isWindows && path && path[1] === ':';
}
@@ -95,6 +106,10 @@ export function tildify(path: string, userHome: string): string {
return path;
}
export function untildify(path: string, userHome: string): string {
return path.replace(/^~($|\/|\\)/, `${userHome}$1`);
}
/**
* Shortens the paths but keeps them easy to distinguish.
* Replaces not important parts with ellipsis.

View File

@@ -7,7 +7,7 @@
import { once } from 'vs/base/common/functional';
export const empty: IDisposable = Object.freeze({
export const empty: IDisposable = Object.freeze<IDisposable>({
dispose() { }
});

View File

@@ -26,6 +26,11 @@ export class LinkedList<E> {
return !this._first;
}
clear(): void {
this._first = undefined;
this._last = undefined;
}
unshift(element: E) {
return this.insert(element, false);
}
@@ -90,21 +95,19 @@ export class LinkedList<E> {
}
iterator(): IIterator<E> {
let _done: boolean;
let _value: E;
let element = {
get done() { return _done; },
get value() { return _value; }
done: undefined,
value: undefined,
};
let node = this._first;
return {
next(): { done: boolean; value: E } {
if (!node) {
_done = true;
_value = undefined;
element.done = true;
element.value = undefined;
} else {
_done = false;
_value = node.element;
element.done = false;
element.value = node.element;
node = node.next;
}
return element;

View File

@@ -7,15 +7,6 @@
import URI from 'vs/base/common/uri';
export interface Key {
toString(): string;
}
export interface Entry<K, T> {
key: K;
value: T;
}
export function values<K, V>(map: Map<K, V>): V[] {
const result: V[] = [];
map.forEach(value => result.push(value));
@@ -40,186 +31,6 @@ export function getOrSet<K, V>(map: Map<K, V>, key: K, value: V): V {
return result;
}
export interface ISerializedBoundedLinkedMap<T> {
entries: { key: string; value: T }[];
}
interface LinkedEntry<K, T> extends Entry<K, T> {
next?: LinkedEntry<K, T>;
prev?: LinkedEntry<K, T>;
}
/**
* A simple Map<T> that optionally allows to set a limit of entries to store. Once the limit is hit,
* the cache will remove the entry that was last recently added. Or, if a ratio is provided below 1,
* all elements will be removed until the ratio is full filled (e.g. 0.75 to remove 25% of old elements).
*/
export class BoundedMap<T> {
private map: Map<string, LinkedEntry<string, T>>;
private head: LinkedEntry<string, T>;
private tail: LinkedEntry<string, T>;
private ratio: number;
constructor(private limit = Number.MAX_VALUE, ratio = 1, value?: ISerializedBoundedLinkedMap<T>) {
this.map = new Map<string, LinkedEntry<string, T>>();
this.ratio = limit * ratio;
if (value) {
value.entries.forEach(entry => {
this.set(entry.key, entry.value);
});
}
}
public setLimit(limit: number): void {
if (limit < 0) {
return; // invalid limit
}
this.limit = limit;
while (this.map.size > this.limit) {
this.trim();
}
}
public serialize(): ISerializedBoundedLinkedMap<T> {
const serialized: ISerializedBoundedLinkedMap<T> = { entries: [] };
this.map.forEach(entry => {
serialized.entries.push({ key: entry.key, value: entry.value });
});
return serialized;
}
public get size(): number {
return this.map.size;
}
public set(key: string, value: T): boolean {
if (this.map.has(key)) {
return false; // already present!
}
const entry: LinkedEntry<string, T> = { key, value };
this.push(entry);
if (this.size > this.limit) {
this.trim();
}
return true;
}
public get(key: string): T {
const entry = this.map.get(key);
return entry ? entry.value : null;
}
public getOrSet(k: string, t: T): T {
const res = this.get(k);
if (res) {
return res;
}
this.set(k, t);
return t;
}
public delete(key: string): T {
const entry = this.map.get(key);
if (entry) {
this.map.delete(key);
if (entry.next) {
entry.next.prev = entry.prev; // [A]<-[x]<-[C] = [A]<-[C]
} else {
this.head = entry.prev; // [A]-[x] = [A]
}
if (entry.prev) {
entry.prev.next = entry.next; // [A]->[x]->[C] = [A]->[C]
} else {
this.tail = entry.next; // [x]-[A] = [A]
}
return entry.value;
}
return null;
}
public has(key: string): boolean {
return this.map.has(key);
}
public clear(): void {
this.map.clear();
this.head = null;
this.tail = null;
}
private push(entry: LinkedEntry<string, T>): void {
if (this.head) {
// [A]-[B] = [A]-[B]->[X]
entry.prev = this.head;
this.head.next = entry;
}
if (!this.tail) {
this.tail = entry;
}
this.head = entry;
this.map.set(entry.key, entry);
}
private trim(): void {
if (this.tail) {
// Remove all elements until ratio is reached
if (this.ratio < this.limit) {
let index = 0;
let current = this.tail;
while (current.next) {
// Remove the entry
this.map.delete(current.key);
// if we reached the element that overflows our ratio condition
// make its next element the new tail of the Map and adjust the size
if (index === this.ratio) {
this.tail = current.next;
this.tail.prev = null;
break;
}
// Move on
current = current.next;
index++;
}
}
// Just remove the tail element
else {
this.map.delete(this.tail.key);
// [x]-[B] = [B]
this.tail = this.tail.next;
if (this.tail) {
this.tail.prev = null;
}
}
}
}
}
export interface IKeyIterator {
reset(key: string): this;
next(): this;
@@ -267,8 +78,8 @@ export class StringIterator implements IKeyIterator {
export class PathIterator implements IKeyIterator {
private static _fwd = '/'.charCodeAt(0);
private static _bwd = '\\'.charCodeAt(0);
private static readonly _fwd = '/'.charCodeAt(0);
private static readonly _bwd = '\\'.charCodeAt(0);
private _value: string;
private _from: number;
@@ -370,7 +181,7 @@ export class TernarySearchTree<E> {
this._root = undefined;
}
set(key: string, element: E): void {
set(key: string, element: E): E {
let iter = this._iter.reset(key);
let node: TernarySearchTreeNode<E>;
@@ -410,7 +221,9 @@ export class TernarySearchTree<E> {
break;
}
}
const oldElement = node.element;
node.element = element;
return oldElement;
}
get(key: string): E {
@@ -436,29 +249,44 @@ export class TernarySearchTree<E> {
}
delete(key: string): void {
this._delete(this._root, this._iter.reset(key));
}
private _delete(node: TernarySearchTreeNode<E>, iter: IKeyIterator): TernarySearchTreeNode<E> {
if (!node) {
return undefined;
}
const cmp = iter.cmp(node.str);
if (cmp > 0) {
// left
node.left = this._delete(node.left, iter);
} else if (cmp < 0) {
// right
node.right = this._delete(node.right, iter);
} else if (iter.hasNext()) {
// mid
node.mid = this._delete(node.mid, iter.next());
} else {
// remove element
node.element = undefined;
}
let iter = this._iter.reset(key);
let stack: [-1 | 0 | 1, TernarySearchTreeNode<E>][] = [];
let node = this._root;
return node.isEmpty() ? undefined : node;
// find and unset node
while (node) {
let val = iter.cmp(node.str);
if (val > 0) {
// left
stack.push([1, node]);
node = node.left;
} else if (val < 0) {
// right
stack.push([-1, node]);
node = node.right;
} else if (iter.hasNext()) {
// mid
iter.next();
stack.push([0, node]);
node = node.mid;
} else {
// remove element
node.element = undefined;
// clean up empty nodes
while (stack.length > 0 && node.isEmpty()) {
let [dir, parent] = stack.pop();
switch (dir) {
case 1: parent.left = undefined; break;
case 0: parent.mid = undefined; break;
case -1: parent.right = undefined; break;
}
node = parent;
}
break;
}
}
}
findSubstr(key: string): E {
@@ -518,17 +346,22 @@ export class TernarySearchTree<E> {
}
private _forEach(node: TernarySearchTreeNode<E>, parts: string[], callback: (value: E, index: string) => any) {
if (!node) {
return;
if (node) {
// left
this._forEach(node.left, parts, callback);
// node
parts.push(node.str);
if (node.element) {
callback(node.element, this._iter.join(parts));
}
// mid
this._forEach(node.mid, parts, callback);
parts.pop();
// right
this._forEach(node.right, parts, callback);
}
this._forEach(node.left, parts, callback);
this._forEach(node.right, parts, callback);
let newParts = parts.slice();
newParts.push(node.str);
if (node.element) {
callback(node.element, this._iter.join(newParts));
}
this._forEach(node.mid, newParts, callback);
}
}
@@ -603,14 +436,12 @@ interface Item<K, V> {
value: V;
}
export namespace Touch {
export const None: 0 = 0;
export const First: 1 = 1;
export const Last: 2 = 2;
export enum Touch {
None = 0,
AsOld = 1,
AsNew = 2
}
export type Touch = 0 | 1 | 2;
export class LinkedMap<K, V> {
private _map: Map<K, Item<K, V>>;
@@ -644,11 +475,14 @@ export class LinkedMap<K, V> {
return this._map.has(key);
}
public get(key: K): V | undefined {
public get(key: K, touch: Touch = Touch.None): V | undefined {
const item = this._map.get(key);
if (!item) {
return undefined;
}
if (touch !== Touch.None) {
this.touch(item, touch);
}
return item.value;
}
@@ -665,10 +499,10 @@ export class LinkedMap<K, V> {
case Touch.None:
this.addItemLast(item);
break;
case Touch.First:
case Touch.AsOld:
this.addItemFirst(item);
break;
case Touch.Last:
case Touch.AsNew:
this.addItemLast(item);
break;
default:
@@ -721,18 +555,6 @@ export class LinkedMap<K, V> {
}
}
public forEachReverse(callbackfn: (value: V, key: K, map: LinkedMap<K, V>) => void, thisArg?: any): void {
let current = this._tail;
while (current) {
if (thisArg) {
callbackfn.bind(thisArg)(current.value, current.key, this);
} else {
callbackfn(current.value, current.key, this);
}
current = current.previous;
}
}
public values(): V[] {
let result: V[] = [];
let current = this._head;
@@ -793,6 +615,26 @@ export class LinkedMap<K, V> {
}
*/
protected trimOld(newSize: number) {
if (newSize >= this.size) {
return;
}
if (newSize === 0) {
this.clear();
return;
}
let current = this._head;
let currentSize = this.size;
while (current && currentSize > newSize) {
this._map.delete(current.key);
current = current.next;
currentSize--;
}
this._head = current;
this._size = currentSize;
current.previous = void 0;
}
private addItemFirst(item: Item<K, V>): void {
// First time Insert
if (!this._head && !this._tail) {
@@ -821,8 +663,8 @@ export class LinkedMap<K, V> {
private removeItem(item: Item<K, V>): void {
if (item === this._head && item === this._tail) {
this._head = undefined;
this._tail = undefined;
this._head = void 0;
this._tail = void 0;
}
else if (item === this._head) {
this._head = item.next;
@@ -845,11 +687,11 @@ export class LinkedMap<K, V> {
if (!this._head || !this._tail) {
throw new Error('Invalid list');
}
if ((touch !== Touch.First && touch !== Touch.Last)) {
if ((touch !== Touch.AsOld && touch !== Touch.AsNew)) {
return;
}
if (touch === Touch.First) {
if (touch === Touch.AsOld) {
if (item === this._head) {
return;
}
@@ -861,7 +703,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 = undefined;
previous!.next = void 0;
this._tail = previous;
}
else {
@@ -871,11 +713,11 @@ export class LinkedMap<K, V> {
}
// Insert the node at head
item.previous = undefined;
item.previous = void 0;
item.next = this._head;
this._head.previous = item;
this._head = item;
} else if (touch === Touch.Last) {
} else if (touch === Touch.AsNew) {
if (item === this._tail) {
return;
}
@@ -887,17 +729,66 @@ 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 = undefined;
next!.previous = void 0;
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 = undefined;
item.next = void 0;
item.previous = this._tail;
this._tail.next = item;
this._tail = item;
}
}
}
export class LRUCache<K, V> extends LinkedMap<K, V> {
private _limit: number;
private _ratio: number;
constructor(limit: number, ratio: number = 1) {
super();
this._limit = limit;
this._ratio = Math.min(Math.max(0, ratio), 1);
}
public get limit(): number {
return this._limit;
}
public set limit(limit: number) {
this._limit = limit;
this.checkTrim();
}
public get ratio(): number {
return this._ratio;
}
public set ratio(ratio: number) {
this._ratio = Math.min(Math.max(0, ratio), 1);
this.checkTrim();
}
public get(key: K): V | undefined {
return super.get(key, Touch.AsNew);
}
public peek(key: K): V | undefined {
return super.get(key, Touch.None);
}
public set(key: K, value: V): void {
super.set(key, value, Touch.AsNew);
this.checkTrim();
}
private checkTrim() {
if (this.size > this._limit) {
this.trimOld(Math.round(this._limit * this._ratio));
}
}
}

View File

@@ -11,7 +11,9 @@ export function stringify(obj: any): string {
}
export function parse(text: string): any {
return JSON.parse(text, reviver);
let data = JSON.parse(text);
data = revive(data, 0);
return data;
}
interface MarshalledObject {
@@ -30,15 +32,27 @@ function replacer(key: string, value: any): any {
return value;
}
function reviver(key: string, value: any): any {
let marshallingConst: number;
if (value !== void 0 && value !== null) {
marshallingConst = (<MarshalledObject>value).$mid;
function revive(obj: any, depth: number): any {
if (!obj || depth > 200) {
return obj;
}
switch (marshallingConst) {
case 1: return URI.revive(value);
case 2: return new RegExp(value.source, value.flags);
default: return value;
if (typeof obj === 'object') {
switch ((<MarshalledObject>obj).$mid) {
case 1: return URI.revive(obj);
case 2: return new RegExp(obj.source, obj.flags);
}
// walk object (or array)
for (let key in obj) {
if (Object.hasOwnProperty.call(obj, key)) {
obj[key] = revive(obj[key], depth + 1);
}
}
}
return obj;
}

View File

@@ -5,7 +5,6 @@
'use strict';
import paths = require('vs/base/common/paths');
import types = require('vs/base/common/types');
import strings = require('vs/base/common/strings');
import { match } from 'vs/base/common/glob';
@@ -37,7 +36,7 @@ let userRegisteredAssociations: ITextMimeAssociationItem[] = [];
/**
* Associate a text mime to the registry.
*/
export function registerTextMime(association: ITextMimeAssociation): void {
export function registerTextMime(association: ITextMimeAssociation, warnOnOverwrite = false): void {
// Register
const associationItem = toTextMimeAssociationItem(association);
@@ -49,7 +48,7 @@ export function registerTextMime(association: ITextMimeAssociation): void {
}
// Check for conflicts unless this is a user configured association
if (!associationItem.userConfigured) {
if (warnOnOverwrite && !associationItem.userConfigured) {
registeredAssociations.forEach(a => {
if (a.mime === associationItem.mime || a.userConfigured) {
return; // same mime or userConfigured is ok
@@ -113,23 +112,23 @@ export function guessMimeTypes(path: string, firstLine?: string): string[] {
}
path = path.toLowerCase();
let filename = paths.basename(path);
const filename = paths.basename(path);
// 1.) User configured mappings have highest priority
let configuredMime = guessMimeTypeByPath(path, filename, userRegisteredAssociations);
const configuredMime = guessMimeTypeByPath(path, filename, userRegisteredAssociations);
if (configuredMime) {
return [configuredMime, MIME_TEXT];
}
// 2.) Registered mappings have middle priority
let registeredMime = guessMimeTypeByPath(path, filename, nonUserRegisteredAssociations);
const registeredMime = guessMimeTypeByPath(path, filename, nonUserRegisteredAssociations);
if (registeredMime) {
return [registeredMime, MIME_TEXT];
}
// 3.) Firstline has lowest priority
if (firstLine) {
let firstlineMime = guessMimeTypeByFirstline(firstLine);
const firstlineMime = guessMimeTypeByFirstline(firstLine);
if (firstlineMime) {
return [firstlineMime, MIME_TEXT];
}
@@ -146,7 +145,7 @@ function guessMimeTypeByPath(path: string, filename: string, associations: IText
// We want to prioritize associations based on the order they are registered so that the last registered
// association wins over all other. This is for https://github.com/Microsoft/vscode/issues/20074
for (let i = associations.length - 1; i >= 0; i--) {
let association = associations[i];
const association = associations[i];
// First exact name match
if (filename === association.filenameLowercase) {
@@ -157,7 +156,7 @@ function guessMimeTypeByPath(path: string, filename: string, associations: IText
// Longest pattern match
if (association.filepattern) {
if (!patternMatch || association.filepattern.length > patternMatch.filepattern.length) {
let target = association.filepatternOnPath ? path : filename; // match on full path if pattern contains path separator
const target = association.filepatternOnPath ? path : filename; // match on full path if pattern contains path separator
if (match(association.filepatternLowercase, target)) {
patternMatch = association;
}
@@ -199,12 +198,12 @@ function guessMimeTypeByFirstline(firstLine: string): string {
if (firstLine.length > 0) {
for (let i = 0; i < registeredAssociations.length; ++i) {
let association = registeredAssociations[i];
const association = registeredAssociations[i];
if (!association.firstline) {
continue;
}
let matches = firstLine.match(association.firstline);
const matches = firstLine.match(association.firstline);
if (matches && matches.length > 0) {
return association.mime;
}
@@ -214,23 +213,6 @@ function guessMimeTypeByFirstline(firstLine: string): string {
return null;
}
export function isBinaryMime(mimes: string): boolean;
export function isBinaryMime(mimes: string[]): boolean;
export function isBinaryMime(mimes: any): boolean {
if (!mimes) {
return false;
}
let mimeVals: string[];
if (types.isArray(mimes)) {
mimeVals = (<string[]>mimes);
} else {
mimeVals = (<string>mimes).split(',').map((mime) => mime.trim());
}
return mimeVals.indexOf(MIME_BINARY) >= 0;
}
export function isUnspecific(mime: string[] | string): boolean {
if (!mime) {
return true;
@@ -245,7 +227,7 @@ export function isUnspecific(mime: string[] | string): boolean {
export function suggestFilename(langId: string, prefix: string): string {
for (let i = 0; i < registeredAssociations.length; i++) {
let association = registeredAssociations[i];
const association = registeredAssociations[i];
if (association.userConfigured) {
continue; // only support registered ones
}

View File

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

View File

@@ -7,6 +7,15 @@
import types = require('vs/base/common/types');
export function clamp(value: number, min: number, max: number): number {
return Math.min(Math.max(value, min), max);
}
export function rot(index: number, modulo: number): number {
return (modulo + (index % modulo)) % modulo;
}
// {{SQL CARBON EDIT}}
export type NumberCallback = (index: number) => void;
export function count(to: number, callback: NumberCallback): void;
@@ -46,12 +55,3 @@ export function countToArray(fromOrTo: number, to?: number): number[] {
return result;
}
export function clamp(value: number, min: number, max: number): number {
return Math.min(Math.max(value, min), max);
}
export function rot(index: number, modulo: number): number {
return (modulo + (index % modulo)) % modulo;
}

View File

@@ -7,7 +7,7 @@
import { isObject, isUndefinedOrNull, isArray } from 'vs/base/common/types';
export function clone<T>(obj: T): T {
export function deepClone<T>(obj: T): T {
if (!obj || typeof obj !== 'object') {
return obj;
}
@@ -15,23 +15,8 @@ export function clone<T>(obj: T): T {
// See https://github.com/Microsoft/TypeScript/issues/10990
return obj as any;
}
const result = (Array.isArray(obj)) ? <any>[] : <any>{};
Object.keys(obj).forEach(key => {
if (obj[key] && typeof obj[key] === 'object') {
result[key] = clone(obj[key]);
} else {
result[key] = obj[key];
}
});
return result;
}
export function deepClone<T>(obj: T): T {
if (!obj || typeof obj !== 'object') {
return obj;
}
const result = (Array.isArray(obj)) ? <any>[] : <any>{};
Object.getOwnPropertyNames(obj).forEach(key => {
const result: any = Array.isArray(obj) ? [] : {};
Object.keys(obj).forEach((key: keyof T) => {
if (obj[key] && typeof obj[key] === 'object') {
result[key] = deepClone(obj[key]);
} else {
@@ -41,7 +26,27 @@ export function deepClone<T>(obj: T): T {
return result;
}
const hasOwnProperty = Object.prototype.hasOwnProperty;
export function deepFreeze<T>(obj: T): T {
if (!obj || typeof obj !== 'object') {
return obj;
}
const stack: any[] = [obj];
while (stack.length > 0) {
let obj = stack.shift();
Object.freeze(obj);
for (const key in obj) {
if (_hasOwnProperty.call(obj, key)) {
let prop = obj[key];
if (typeof prop === 'object' && !Object.isFrozen(prop)) {
stack.push(prop);
}
}
}
}
return obj;
}
const _hasOwnProperty = Object.prototype.hasOwnProperty;
export function cloneAndChange(obj: any, changer: (orig: any) => any): any {
return _cloneAndChange(obj, changer, []);
@@ -72,8 +77,8 @@ function _cloneAndChange(obj: any, changer: (orig: any) => any, encounteredObjec
encounteredObjects.push(obj);
const r2 = {};
for (let i2 in obj) {
if (hasOwnProperty.call(obj, i2)) {
r2[i2] = _cloneAndChange(obj[i2], changer, encounteredObjects);
if (_hasOwnProperty.call(obj, i2)) {
(r2 as any)[i2] = _cloneAndChange(obj[i2], changer, encounteredObjects);
}
}
encounteredObjects.pop();
@@ -115,10 +120,6 @@ export function assign(destination: any, ...sources: any[]): any {
return destination;
}
export function toObject<T>(arr: T[], keyMap: (t: T) => string): { [key: string]: T } {
return arr.reduce((o, d) => assign(o, { [keyMap(d)]: d }), Object.create(null));
}
export function equals(one: any, other: any): boolean {
if (one === other) {
return true;
@@ -172,12 +173,6 @@ export function equals(one: any, other: any): boolean {
return true;
}
export function ensureProperty(obj: any, property: string, defaultValue: any) {
if (typeof obj[property] === 'undefined') {
obj[property] = defaultValue;
}
}
export function arrayToHash(array: any[]) {
const result: any = {};
for (let i = 0; i < array.length; ++i) {
@@ -206,34 +201,6 @@ export function createKeywordMatcher(arr: string[], caseInsensitive: boolean = f
}
}
/**
* Started from TypeScript's __extends function to make a type a subclass of a specific class.
* Modified to work with properties already defined on the derivedClass, since we can't get TS
* to call this method before the constructor definition.
*/
export function derive(baseClass: any, derivedClass: any): void {
for (let prop in baseClass) {
if (baseClass.hasOwnProperty(prop)) {
derivedClass[prop] = baseClass[prop];
}
}
derivedClass = derivedClass || function () { };
const basePrototype = baseClass.prototype;
const derivedPrototype = derivedClass.prototype;
derivedClass.prototype = Object.create(basePrototype);
for (let prop in derivedPrototype) {
if (derivedPrototype.hasOwnProperty(prop)) {
// handle getters and setters properly
Object.defineProperty(derivedClass.prototype, prop, Object.getOwnPropertyDescriptor(derivedPrototype, prop));
}
}
// Cast to any due to Bug 16188:PropertyDescriptor set and get function should be optional.
Object.defineProperty(derivedClass.prototype, 'constructor', <any>{ value: derivedClass, writable: true, configurable: true, enumerable: true });
}
/**
* Calls JSON.Stringify with a replacer to break apart any circular references.
* This prevents JSON.stringify from throwing the exception
@@ -287,4 +254,4 @@ export function distinct(base: obj, target: obj): obj {
});
return result;
}
}

View File

@@ -51,7 +51,7 @@ export class PagedModel<T> implements IPagedModel<T> {
get length(): number { return this.pager.total; }
constructor(private arg: IPager<T> | T[], private pageTimeout: number = 500) {
constructor(arg: IPager<T> | T[], private pageTimeout: number = 500) {
this.pager = isArray(arg) ? singlePagePager<T>(arg) : arg;
this.pages = [{ isResolved: true, promise: null, promiseIndexes: new Set<number>(), elements: this.pager.firstPage.slice() }];

View File

@@ -5,7 +5,6 @@
'use strict';
import * as Types from 'vs/base/common/types';
import { IStringDictionary } from 'vs/base/common/collections';
export enum ValidationState {
OK = 0,
@@ -49,14 +48,6 @@ export interface IProblemReporter {
status: ValidationStatus;
}
export class NullProblemReporter implements IProblemReporter {
info(message: string): void { };
warn(message: string): void { };
error(message: string): void { };
fatal(message: string): void { };
status: ValidationStatus = new ValidationStatus();
}
export abstract class Parser {
private _problemReporter: IProblemReporter;
@@ -89,30 +80,8 @@ export abstract class Parser {
this._problemReporter.fatal(message);
}
protected is(value: any, func: (value: any) => boolean, wrongTypeState?: ValidationState, wrongTypeMessage?: string, undefinedState?: ValidationState, undefinedMessage?: string): boolean {
if (Types.isUndefined(value)) {
if (undefinedState) {
this._problemReporter.status.state = undefinedState;
}
if (undefinedMessage) {
this._problemReporter.info(undefinedMessage);
}
return false;
}
if (!func(value)) {
if (wrongTypeState) {
this._problemReporter.status.state = wrongTypeState;
}
if (wrongTypeMessage) {
this.info(wrongTypeMessage);
}
return false;
}
return true;
}
protected static merge<T>(destination: T, source: T, overwrite: boolean): void {
Object.keys(source).forEach((key) => {
Object.keys(source).forEach((key: keyof T) => {
let destValue = destination[key];
let sourceValue = source[key];
if (Types.isUndefined(sourceValue)) {
@@ -131,87 +100,4 @@ export abstract class Parser {
}
});
}
}
export interface ISystemVariables {
resolve(value: string): string;
resolve(value: string[]): string[];
resolve(value: IStringDictionary<string>): IStringDictionary<string>;
resolve(value: IStringDictionary<string[]>): IStringDictionary<string[]>;
resolve(value: IStringDictionary<IStringDictionary<string>>): IStringDictionary<IStringDictionary<string>>;
resolveAny<T>(value: T): T;
[key: string]: any;
}
export abstract class AbstractSystemVariables implements ISystemVariables {
public resolve(value: string): string;
public resolve(value: string[]): string[];
public resolve(value: IStringDictionary<string>): IStringDictionary<string>;
public resolve(value: IStringDictionary<string[]>): IStringDictionary<string[]>;
public resolve(value: IStringDictionary<IStringDictionary<string>>): IStringDictionary<IStringDictionary<string>>;
public resolve(value: any): any {
if (Types.isString(value)) {
return this.resolveString(value);
} else if (Types.isArray(value)) {
return this.__resolveArray(value);
} else if (Types.isObject(value)) {
return this.__resolveLiteral(value);
}
return value;
}
resolveAny<T>(value: T): T;
resolveAny<T>(value: any): any {
if (Types.isString(value)) {
return this.resolveString(value);
} else if (Types.isArray(value)) {
return this.__resolveAnyArray(value);
} else if (Types.isObject(value)) {
return this.__resolveAnyLiteral(value);
}
return value;
}
protected resolveString(value: string): string {
let regexp = /\$\{(.*?)\}/g;
return value.replace(regexp, (match: string, name: string) => {
let newValue = (<any>this)[name];
if (Types.isString(newValue)) {
return newValue;
} else {
return match && match.indexOf('env.') > 0 ? '' : match;
}
});
}
private __resolveLiteral(values: IStringDictionary<string | IStringDictionary<string> | string[]>): IStringDictionary<string | IStringDictionary<string> | string[]> {
let result: IStringDictionary<string | IStringDictionary<string> | string[]> = Object.create(null);
Object.keys(values).forEach(key => {
let value = values[key];
result[key] = <any>this.resolve(<any>value);
});
return result;
}
private __resolveAnyLiteral<T>(values: T): T;
private __resolveAnyLiteral<T>(values: any): any {
let result: IStringDictionary<string | IStringDictionary<string> | string[]> = Object.create(null);
Object.keys(values).forEach(key => {
let value = values[key];
result[key] = <any>this.resolveAny(<any>value);
});
return result;
}
private __resolveArray(value: string[]): string[] {
return value.map(s => this.resolveString(s));
}
private __resolveAnyArray<T>(value: T[]): T[];
private __resolveAnyArray(value: any[]): any[] {
return value.map(s => this.resolveAny(s));
}
}

View File

@@ -4,9 +4,8 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { isLinux, isWindows } from 'vs/base/common/platform';
import { fill } from 'vs/base/common/arrays';
import { rtrim, beginsWithIgnoreCase, equalsIgnoreCase } from 'vs/base/common/strings';
import { isWindows } from 'vs/base/common/platform';
import { beginsWithIgnoreCase, equalsIgnoreCase } from 'vs/base/common/strings';
import { CharCode } from 'vs/base/common/charCode';
/**
@@ -19,35 +18,6 @@ export const sep = '/';
*/
export const nativeSep = isWindows ? '\\' : '/';
export function relative(from: string, to: string): string {
// ignore trailing slashes
const originalNormalizedFrom = rtrim(normalize(from), sep);
const originalNormalizedTo = rtrim(normalize(to), sep);
// we're assuming here that any non=linux OS is case insensitive
// so we must compare each part in its lowercase form
const normalizedFrom = isLinux ? originalNormalizedFrom : originalNormalizedFrom.toLowerCase();
const normalizedTo = isLinux ? originalNormalizedTo : originalNormalizedTo.toLowerCase();
const fromParts = normalizedFrom.split(sep);
const toParts = normalizedTo.split(sep);
let i = 0, max = Math.min(fromParts.length, toParts.length);
for (; i < max; i++) {
if (fromParts[i] !== toParts[i]) {
break;
}
}
const result = [
...fill(fromParts.length - i, () => '..'),
...originalNormalizedTo.split(sep).slice(i)
];
return result.join(sep);
}
/**
* @returns the directory name of a path.
*/

29
src/vs/base/common/performance.d.ts vendored Normal file
View File

@@ -0,0 +1,29 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export interface PerformanceEntry {
readonly type: 'mark' | 'measure';
readonly name: string;
readonly startTime: number;
readonly duration: number;
}
export function mark(name: string): void;
export function measure(name: string, from?: string, to?: string): void;
/**
* Time something, shorthant for `mark` and `measure`
*/
export function time(name: string): { stop(): void };
/**
* All entries filtered by type and sorted by `startTime`.
*/
export function getEntries(type: 'mark' | 'measure'): PerformanceEntry[];
type ExportData = any[];
export function importEntries(data: ExportData): void;
export function exportEntries(): ExportData;

View File

@@ -0,0 +1,111 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
/*global define*/
// 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'
global._performanceEntries = global._performanceEntries || [];
if (typeof define !== "function" && typeof module === "object" && typeof module.exports === "object") {
// this is commonjs, fake amd
global.define = function (dep, callback) {
module.exports = callback();
global.define = undefined;
};
}
define([], function () {
// const _now = global.performance && performance.now ? performance.now : Date.now
const _now = Date.now;
function importEntries(entries) {
global._performanceEntries.splice(0, 0, ...entries);
}
function exportEntries() {
return global._performanceEntries.splice(0);
}
function getEntries(type) {
const result = [];
const entries = global._performanceEntries;
for (let i = 0; i < entries.length; i += 4) {
if (entries[i] === type) {
result.push({
type: entries[i],
name: entries[i + 1],
startTime: entries[i + 2],
duration: entries[i + 3],
});
}
}
return result.sort((a, b) => {
return a.startTime - b.startTime;
});
}
function mark(name) {
global._performanceEntries.push('mark', name, _now(), 0);
if (typeof console.timeStamp === 'function') {
console.timeStamp(name);
}
}
function time(name) {
let from = `${name}/start`;
mark(from);
return { stop() { measure(name, from); } };
}
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 -= 4) {
if (entries[i - 2] === name) {
return entries[i - 1];
}
}
throw new Error(name + ' not found');
}
var exports = {
mark: mark,
measure: measure,
time: time,
getEntries: getEntries,
importEntries: importEntries,
exportEntries: exportEntries
};
return exports;
});

View File

@@ -127,9 +127,6 @@ interface IGlobals {
const _globals = <IGlobals>(typeof self === 'object' ? self : global);
export const globals: any = _globals;
export function hasWebWorkerSupport(): boolean {
return typeof _globals.Worker !== 'undefined';
}
export const setTimeout = _globals.setTimeout.bind(_globals);
export const clearTimeout = _globals.clearTimeout.bind(_globals);

View File

@@ -4,15 +4,6 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import NLS = require('vs/nls');
import * as Objects from 'vs/base/common/objects';
import * as Platform from 'vs/base/common/platform';
import { IStringDictionary } from 'vs/base/common/collections';
import * as Types from 'vs/base/common/types';
import { ValidationState, IProblemReporter, Parser } from 'vs/base/common/parsers';
/**
* Options to be passed to the external program or shell.
*/
@@ -94,159 +85,3 @@ export enum TerminateResponseCode {
AccessDenied = 2,
ProcessNotFound = 3,
}
export namespace Config {
/**
* Options to be passed to the external program or shell
*/
export interface CommandOptions {
/**
* The current working directory of the executed program or shell.
* If omitted VSCode's current workspace root is used.
*/
cwd?: string;
/**
* The additional environment of the executed program or shell. If omitted
* the parent process' environment is used.
*/
env?: IStringDictionary<string>;
/**
* Index signature
*/
[key: string]: string | string[] | IStringDictionary<string>;
}
export interface BaseExecutable {
/**
* The command to be executed. Can be an external program or a shell
* command.
*/
command?: string;
/**
* Specifies whether the command is a shell command and therefore must
* be executed in a shell interpreter (e.g. cmd.exe, bash, ...).
*
* Defaults to false if omitted.
*/
isShellCommand?: boolean;
/**
* The arguments passed to the command. Can be omitted.
*/
args?: string[];
/**
* The command options used when the command is executed. Can be omitted.
*/
options?: CommandOptions;
}
export interface Executable extends BaseExecutable {
/**
* Windows specific executable configuration
*/
windows?: BaseExecutable;
/**
* Mac specific executable configuration
*/
osx?: BaseExecutable;
/**
* Linux specific executable configuration
*/
linux?: BaseExecutable;
}
}
export interface ParserOptions {
globals?: Executable;
emptyCommand?: boolean;
noDefaults?: boolean;
}
export class ExecutableParser extends Parser {
constructor(logger: IProblemReporter) {
super(logger);
}
public parse(json: Config.Executable, parserOptions: ParserOptions = { globals: null, emptyCommand: false, noDefaults: false }): Executable {
let result = this.parseExecutable(json, parserOptions.globals);
if (this.problemReporter.status.isFatal()) {
return result;
}
let osExecutable: Executable;
if (json.windows && Platform.platform === Platform.Platform.Windows) {
osExecutable = this.parseExecutable(json.windows);
} else if (json.osx && Platform.platform === Platform.Platform.Mac) {
osExecutable = this.parseExecutable(json.osx);
} else if (json.linux && Platform.platform === Platform.Platform.Linux) {
osExecutable = this.parseExecutable(json.linux);
}
if (osExecutable) {
result = ExecutableParser.mergeExecutable(result, osExecutable);
}
if ((!result || !result.command) && !parserOptions.emptyCommand) {
this.fatal(NLS.localize('ExecutableParser.commandMissing', 'Error: executable info must define a command of type string.'));
return null;
}
if (!parserOptions.noDefaults) {
Parser.merge(result, {
command: undefined,
isShellCommand: false,
args: [],
options: {}
}, false);
}
return result;
}
public parseExecutable(json: Config.BaseExecutable, globals?: Executable): Executable {
let command: string = undefined;
let isShellCommand: boolean = undefined;
let args: string[] = undefined;
let options: CommandOptions = undefined;
if (this.is(json.command, Types.isString)) {
command = json.command;
}
if (this.is(json.isShellCommand, Types.isBoolean, ValidationState.Warning, NLS.localize('ExecutableParser.isShellCommand', 'Warning: isShellCommand must be of type boolean. Ignoring value {0}.', json.isShellCommand))) {
isShellCommand = json.isShellCommand;
}
if (this.is(json.args, Types.isStringArray, ValidationState.Warning, NLS.localize('ExecutableParser.args', 'Warning: args must be of type string[]. Ignoring value {0}.', json.isShellCommand))) {
args = json.args.slice(0);
}
if (this.is(json.options, Types.isObject)) {
options = this.parseCommandOptions(json.options);
}
return { command, isShellCommand, args, options };
}
private parseCommandOptions(json: Config.CommandOptions): CommandOptions {
let result: CommandOptions = {};
if (!json) {
return result;
}
if (this.is(json.cwd, Types.isString, ValidationState.Warning, NLS.localize('ExecutableParser.invalidCWD', 'Warning: options.cwd must be of type string. Ignoring value {0}.', json.cwd))) {
result.cwd = json.cwd;
}
if (!Types.isUndefined(json.env)) {
result.env = Objects.clone(json.env);
}
return result;
}
public static mergeExecutable(executable: Executable, other: Executable): Executable {
if (!executable) {
return other;
}
Parser.merge(executable, other, true);
return executable;
}
}

View File

@@ -0,0 +1,36 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import Event, { Emitter } from 'vs/base/common/event';
export interface ISplice<T> {
readonly start: number;
readonly deleteCount: number;
readonly toInsert: T[];
}
export interface ISpliceable<T> {
splice(start: number, deleteCount: number, toInsert: T[]): void;
}
export interface ISequence<T> {
readonly elements: T[];
readonly onDidSplice: Event<ISplice<T>>;
}
export class Sequence<T> implements ISequence<T>, ISpliceable<T> {
readonly elements: T[] = [];
private _onDidSplice = new Emitter<ISplice<T>>();
readonly onDidSplice: Event<ISplice<T>> = this._onDidSplice.event;
splice(start: number, deleteCount: number, toInsert: T[] = []): void {
this.elements.splice(start, deleteCount, ...toInsert);
this._onDidSplice.fire({ start, deleteCount, toInsert });
}
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { BoundedMap } from 'vs/base/common/map';
import { LRUCache } from 'vs/base/common/map';
import { CharCode } from 'vs/base/common/charCode';
/**
@@ -243,18 +243,18 @@ export function regExpContainsBackreference(regexpValue: string): boolean {
*/
export const canNormalize = typeof ((<any>'').normalize) === 'function';
const nfcCache = new BoundedMap<string>(10000); // bounded to 10000 elements
const nfcCache = new LRUCache<string, string>(10000); // bounded to 10000 elements
export function normalizeNFC(str: string): string {
return normalize(str, 'NFC', nfcCache);
}
const nfdCache = new BoundedMap<string>(10000); // bounded to 10000 elements
const nfdCache = new LRUCache<string, string>(10000); // bounded to 10000 elements
export function normalizeNFD(str: string): string {
return normalize(str, 'NFD', nfdCache);
}
const nonAsciiCharactersPattern = /[^\u0000-\u0080]/;
function normalize(str: string, form: string, normalizedCache: BoundedMap<string>): string {
function normalize(str: string, form: string, normalizedCache: LRUCache<string, string>): string {
if (!canNormalize || !str) {
return str;
}
@@ -618,81 +618,27 @@ export function isFullWidthCharacter(charCode: number): boolean {
);
}
/**
* Computes the difference score for two strings. More similar strings have a higher score.
* We use largest common subsequence dynamic programming approach but penalize in the end for length differences.
* Strings that have a large length difference will get a bad default score 0.
* Complexity - both time and space O(first.length * second.length)
* Dynamic programming LCS computation http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
*
* @param first a string
* @param second a string
*/
export function difference(first: string, second: string, maxLenDelta: number = 4): number {
let lengthDifference = Math.abs(first.length - second.length);
// We only compute score if length of the currentWord and length of entry.name are similar.
if (lengthDifference > maxLenDelta) {
return 0;
}
// Initialize LCS (largest common subsequence) matrix.
let LCS: number[][] = [];
let zeroArray: number[] = [];
let i: number, j: number;
for (i = 0; i < second.length + 1; ++i) {
zeroArray.push(0);
}
for (i = 0; i < first.length + 1; ++i) {
LCS.push(zeroArray);
}
for (i = 1; i < first.length + 1; ++i) {
for (j = 1; j < second.length + 1; ++j) {
if (first[i - 1] === second[j - 1]) {
LCS[i][j] = LCS[i - 1][j - 1] + 1;
} else {
LCS[i][j] = Math.max(LCS[i - 1][j], LCS[i][j - 1]);
}
}
}
return LCS[first.length][second.length] - Math.sqrt(lengthDifference);
}
/**
* Returns an array in which every entry is the offset of a
* line. There is always one entry which is zero.
*/
export function computeLineStarts(text: string): number[] {
let regexp = /\r\n|\r|\n/g,
ret: number[] = [0],
match: RegExpExecArray;
while ((match = regexp.exec(text))) {
ret.push(regexp.lastIndex);
}
return ret;
}
/**
* Given a string and a max length returns a shorted version. Shorting
* happens at favorable positions - such as whitespace or punctuation characters.
*/
export function lcut(text: string, n: number): string {
export function lcut(text: string, n: number) {
if (text.length < n) {
return text;
}
let segments = text.split(/\b/),
count = 0;
for (let i = segments.length - 1; i >= 0; i--) {
count += segments[i].length;
if (count > n) {
segments.splice(0, i);
const re = /\b/g;
let i = 0;
while (re.test(text)) {
if (text.length - re.lastIndex < n) {
break;
}
i = re.lastIndex;
re.lastIndex += 1;
}
return segments.join(empty).replace(/^\s/, empty);
return text.substring(i).replace(/^\s/, empty);
}
// Escape codes
@@ -723,25 +669,6 @@ export function stripUTF8BOM(str: string): string {
return startsWithUTF8BOM(str) ? str.substr(1) : str;
}
/**
* Appends two strings. If the appended result is longer than maxLength,
* trims the start of the result and replaces it with '...'.
*/
export function appendWithLimit(first: string, second: string, maxLength: number): string {
const newLength = first.length + second.length;
if (newLength > maxLength) {
first = '...' + first.substr(newLength - maxLength);
}
if (second.length > maxLength) {
first += second.substr(second.length - maxLength);
} else {
first += second;
}
return first;
}
export function safeBtoa(str: string): string {
return btoa(encodeURIComponent(str)); // we use encodeURIComponent because btoa fails for non Latin 1 values
}
@@ -784,4 +711,4 @@ export function fuzzyContains(target: string, query: string): boolean {
}
return true;
}
}

View File

@@ -4,8 +4,6 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
const _typeof = {
number: 'number',
string: 'string',
@@ -149,7 +147,7 @@ export function validateConstraint(arg: any, constraint: TypeConstraint): void {
if (arg instanceof constraint) {
return;
}
if (arg && arg.constructor === constraint) {
if (!isUndefinedOrNull(arg) && arg.constructor === constraint) {
return;
}
if (constraint.length === 1 && constraint.call(undefined, arg) === true) {
@@ -169,52 +167,3 @@ export function create(ctor: Function, ...args: any[]): any {
return obj;
}
export interface IFunction0<T> {
(): T;
}
export interface IFunction1<A1, T> {
(a1: A1): T;
}
export interface IFunction2<A1, A2, T> {
(a1: A1, a2: A2): T;
}
export interface IFunction3<A1, A2, A3, T> {
(a1: A1, a2: A2, a3: A3): T;
}
export interface IFunction4<A1, A2, A3, A4, T> {
(a1: A1, a2: A2, a3: A3, a4: A4): T;
}
export interface IFunction5<A1, A2, A3, A4, A5, T> {
(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5): T;
}
export interface IFunction6<A1, A2, A3, A4, A5, A6, T> {
(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6): T;
}
export interface IFunction7<A1, A2, A3, A4, A5, A6, A7, T> {
(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7): T;
}
export interface IFunction8<A1, A2, A3, A4, A5, A6, A7, A8, T> {
(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8): T;
}
export interface IAction0 extends IFunction0<void> { }
export interface IAction1<A1> extends IFunction1<A1, void> { }
export interface IAction2<A1, A2> extends IFunction2<A1, A2, void> { }
export interface IAction3<A1, A2, A3> extends IFunction3<A1, A2, A3, void> { }
export interface IAction4<A1, A2, A3, A4> extends IFunction4<A1, A2, A3, A4, void> { }
export interface IAction5<A1, A2, A3, A4, A5> extends IFunction5<A1, A2, A3, A4, A5, void> { }
export interface IAction6<A1, A2, A3, A4, A5, A6> extends IFunction6<A1, A2, A3, A4, A5, A6, void> { }
export interface IAction7<A1, A2, A3, A4, A5, A6, A7> extends IFunction7<A1, A2, A3, A4, A5, A6, A7, void> { }
export interface IAction8<A1, A2, A3, A4, A5, A6, A7, A8> extends IFunction8<A1, A2, A3, A4, A5, A6, A7, A8, void> { }
export interface IAsyncFunction0<T> extends IFunction0<TPromise<T>> { }
export interface IAsyncFunction1<A1, T> extends IFunction1<A1, TPromise<T>> { }
export interface IAsyncFunction2<A1, A2, T> extends IFunction2<A1, A2, TPromise<T>> { }
export interface IAsyncFunction3<A1, A2, A3, T> extends IFunction3<A1, A2, A3, TPromise<T>> { }
export interface IAsyncFunction4<A1, A2, A3, A4, T> extends IFunction4<A1, A2, A3, A4, TPromise<T>> { }
export interface IAsyncFunction5<A1, A2, A3, A4, A5, T> extends IFunction5<A1, A2, A3, A4, A5, TPromise<T>> { }
export interface IAsyncFunction6<A1, A2, A3, A4, A5, A6, T> extends IFunction6<A1, A2, A3, A4, A5, A6, TPromise<T>> { }
export interface IAsyncFunction7<A1, A2, A3, A4, A5, A6, A7, T> extends IFunction7<A1, A2, A3, A4, A5, A6, A7, TPromise<T>> { }
export interface IAsyncFunction8<A1, A2, A3, A4, A5, A6, A7, A8, T> extends IFunction8<A1, A2, A3, A4, A5, A6, A7, A8, TPromise<T>> { }

View File

@@ -450,7 +450,7 @@ function _asFormatted(uri: URI, skipEncoding: boolean): string {
}
parts.push(encoder(path.substring(lastIdx, idx)), _slash);
lastIdx = idx + 1;
};
}
}
if (query) {
parts.push('?', encoder(query));

View File

@@ -13,8 +13,6 @@ export interface UUID {
* @returns the canonical representation in sets of hexadecimal numbers separated by dashes.
*/
asHex(): string;
equals(other: UUID): boolean;
}
class ValueUUID implements UUID {
@@ -26,17 +24,13 @@ class ValueUUID implements UUID {
public asHex(): string {
return this._value;
}
public equals(other: UUID): boolean {
return this.asHex() === other.asHex();
}
}
class V4UUID extends ValueUUID {
private static _chars = ['0', '1', '2', '3', '4', '5', '6', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
private static readonly _chars = ['0', '1', '2', '3', '4', '5', '6', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
private static _timeHighBits = ['8', '9', 'a', 'b'];
private static readonly _timeHighBits = ['8', '9', 'a', 'b'];
private static _oneOf(array: string[]): string {
return array[Math.floor(array.length * Math.random())];

View File

@@ -29,6 +29,7 @@ export declare class Promise<T = any, TProgress = any> {
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>;

View File

@@ -42,14 +42,14 @@ export class PolyfillPromise<T = any> implements Promise<T> {
constructor(winjsPromise: WinJSPromise);
constructor(callback: (resolve: (value?: T) => void, reject: (err?: any) => void) => any);
constructor(callback: WinJSPromise | ((resolve: (value?: T) => void, reject: (err?: any) => void) => any)) {
constructor(initOrPromise: WinJSPromise | ((resolve: (value?: T) => void, reject: (err?: any) => void) => any)) {
if (WinJSPromise.is(callback)) {
this._winjsPromise = callback;
if (WinJSPromise.is(initOrPromise)) {
this._winjsPromise = initOrPromise;
} else {
this._winjsPromise = new WinJSPromise((resolve, reject) => {
let initializing = true;
callback(function (value) {
initOrPromise(function (value) {
if (!initializing) {
resolve(value);
} else {
@@ -68,10 +68,28 @@ export class PolyfillPromise<T = any> implements Promise<T> {
}
then(onFulfilled?: any, onRejected?: any): PolyfillPromise {
return new PolyfillPromise(this._winjsPromise.then(onFulfilled, onRejected));
let sync = true;
let promise = new PolyfillPromise(this._winjsPromise.then(
onFulfilled && function (value) {
if (!sync) {
onFulfilled(value);
} else {
setImmediate(onFulfilled, value);
}
},
onRejected && function (err) {
if (!sync) {
onFulfilled(err);
} else {
setImmediate(onFulfilled, err);
}
}
));
sync = false;
return promise;
}
catch(onRejected?: any): PolyfillPromise {
return new PolyfillPromise(this._winjsPromise.then(null, onRejected));
return this.then(null, onRejected);
}
}

View File

@@ -188,7 +188,6 @@ export class SimpleWorkerClient<T> extends Disposable {
private _onModuleLoaded: TPromise<string[]>;
private _protocol: SimpleWorkerProtocol;
private _lazyProxy: TPromise<T>;
private _lastRequestTimestamp = -1;
constructor(workerFactory: IWorkerFactory, moduleId: string) {
super();
@@ -244,7 +243,7 @@ export class SimpleWorkerClient<T> extends Disposable {
this._onModuleLoaded.then((availableMethods: string[]) => {
let proxy = <T>{};
for (let i = 0; i < availableMethods.length; i++) {
proxy[availableMethods[i]] = createProxyMethod(availableMethods[i], proxyMethodRequest);
(proxy as any)[availableMethods[i]] = createProxyMethod(availableMethods[i], proxyMethodRequest);
}
lazyProxyFulfill(proxy);
}, (e) => {
@@ -270,14 +269,9 @@ export class SimpleWorkerClient<T> extends Disposable {
return new ShallowCancelThenPromise(this._lazyProxy);
}
public getLastRequestTimestamp(): number {
return this._lastRequestTimestamp;
}
private _request(method: string, args: any[]): TPromise<any> {
return new TPromise<any>((c, e, p) => {
this._onModuleLoaded.then(() => {
this._lastRequestTimestamp = Date.now();
this._protocol.sendMessage(method, args).then(c, e);
}, e);
}, () => {
@@ -292,7 +286,7 @@ export class SimpleWorkerClient<T> extends Disposable {
}
export interface IRequestHandler {
_requestHandlerTrait: any;
_requestHandlerBrand: any;
}
/**