Merge VS Code 1.26.1 (#2394)

* Squash merge commits for 1.26 (#1) (#2323)

* Polish tag search as per feedback (#55269)

* Polish tag search as per feedback

* Updated regex

* Allow users to opt-out of features that send online requests in the background (#55097)

* settings sweep #54690

* Minor css tweaks to enable eoverflow elipsis in more places (#55277)

* fix an issue with titlebarheight when not scaling with zoom

* Settings descriptions update #54690

* fixes #55209

* Settings editor - many padding fixes

* More space above level 2 label

* Fixing Cannot debug npm script using Yarn #55103

* Settings editor - show ellipsis when description overflows

* Settings editor - ... fix measuring around links, relayout

* Setting descriptions

* Settings editor - fix ... for some short lines, fix select container width

* Settings editor - overlay trees so scrollable shadow is full width

* Fix #54133 - missing extension settings after reload

* Settings color token description tweak

* Settings editor - disable overflow indicator temporarily, needs to be faster

* Added command to Run the selected npm script

* fixes #54452

* fixes #54929

* fixes #55248

* prefix command with extension name

* Contribute run selected to the context menu

* node-debug@1.26.6

* Allow terminal rendererType to be swapped out at runtime

Part of #53274
Fixes #55344

* Settings editor - fix not focusing search when restoring editor
setInput must be actually async. Will be fixed naturally when we aren't using winJS promises...

* Settings editor - TOC should only expand the section with a selected item

* Bump node-debug2

* Settings editor - Tree focus outlines

* Settings editor - don't blink the scrollbar when toc selection changes
And hide TOC correctly when the editor is narrow

* Settings editor - header rows should not be selectable

* fixes #54877

* change debug assignee to isi

* Settings sweep (#54690)

* workaround for #55051

* Settings sweep (#54690)

* settings sweep

#54690

* Don't try closing tags when you type > after another >

* Describe what implementation code lens does

Fixes #55370

* fix javadoc formatter setting description

* fixes #55325

* update to officical TS version

* Settings editor - Even more padding, use semibold instead of bold

* Fix #55357 - fix TOC twistie

* fixes #55288

* explorer: refresh on di change file system provider registration

fixes #53256

* Disable push to Linux repo to test standalone publisher

* New env var to notify log level to extensions #54001

* Disable snippets in extension search (when not in suggest dropdown) (#55281)

* Disable snippits in extension search (when not in suggest dropdown)

* Add monaco input contributions

* Fix bug preventing snippetSuggestions from taking effect in sub-editors

* Latest emmet helper to fix #52366

* Fix comment updates for threads within same file

* Allow extensions to log telemetry to log files #54001

* Pull latest css grammar

* files.exclude control - use same style for "add" vs "edit"

* files.exclude control - focus/keyboard behavior

* don't show menubar too early

* files.exclude - better styling

* Place cursor at end of extensions search box on autofill (#55254)

* Place cursor at end of extensions search box on autofill

* Use position instead of selection

* fix linux build issue (empty if block)

* Settings editor - fix extension category prefixes

* Settings editor - add simple ellipsis for first line that overflows, doesn't cover case when first line does not overflow but there is more text, TODO

* File/Text search provider docs

* Fixes #52655

* Include epoch (#55008)

* Fixes #53385

* Fixes #49480

*  VS Code Insiders (Users) not opening Fixes #55353

* Better handling of the case when the extension host fails to start

* Fixes #53966

*  Remove confusing Start from wordPartLeft commands ID

* vscode-xterm@3.6.0-beta12

Fixes #55488

* Initial size is set to infinity!! Fixes #55461

* Polish embeddedEditorBackground

* configuration service misses event

* Fix #55224 - fix duplicate results in multiroot workspace from splitting the diskseach query

* Select all not working in issue reporter on mac, fixes #55424

* Disable fuzzy matching for extensions autosuggest (#55498)

* Fix clipping of extensions search border in some third party themes (#55504)

* fixes #55538

* Fix bug causing an aria alert to not be shown the third time
 (and odd numbers thereafter)

* Settings editor - work around rendering glitch with webkit-line-clamp

* Settings editor - revert earlier '...' changes

* Settings editor - move enumDescription to its own div, because it disturbs -webkit-line-clamp for some reason

* Settings editor - better overflow indicator

* Don't show existing filters in autocomplete (#55495)

* Dont show existing filters in autocomplete

* Simplify

* Settings Editor: Add aria labels for input elements Fixes: #54836 (#55543)

* fixes #55223

* Update vscode-css-languageservice to 3.0.10-next.1

* Fix #55509 - settings navigation

* Fix #55519

* Fix #55520

* FIx #55524

* Fix #55556 - include wordSeparators in all search queries, so findTextInFiles can respect isWordMatch correctly

* oss updates for endgame

* Fix unit tests

* fixes #55522

* Avoid missing manifest error from bubbling up #54757

* Settings format crawl

* Search provider - Fix FileSearchProvider to return array, not progress

* Fix #55598

* Settings editor - fix NPE rendering settings with no description

* dont render inden guides in search box (#55600)

* fixes #55454

* More settings crawl

* Another change for #55598 - maxResults applies to FileSearch and TextSearch but not FileIndex

* Fix FileSearchProvider unit tests for progress change

* fixes #55561

* Settings description update for #54690

* Update setting descriptions for online services

* Minor edits

* fixes #55513

* fixes #55451

* Fix #55612 - fix findTextInFiles cancellation

* fixes #55539

* More setting description tweaks

* Setting to disable online experiments #54354

* fixes #55507

* fixes #55515

* Show online services action only in Insiders for now

* Settings editor - change toc behavior default to 'filter'

* Settings editor - nicer filter count style during search

* Fix #55617 - search viewlet icons

* Settings editor - better styling for element count indicator

* SearchProvider - fix NPE when searching extraFileResources

* Allow extends to work without json suffix

Fixes #16905

* Remove accessability options logic entirely

Follow up on #55451

* use latest version of DAP

* fixes #55490

* fixes #55122

* fixes #52332

* Avoid assumptions about git: URIs (fixes #36236)

* relative path for descriptions

* resourece: get rid of isFile context key

fixes #48275

* Register previous ids for compatibility (#53497)

* more tuning for #48275

* no need to always re-read "files explorer"

fixes #52003

* read out active composites properly

fixes #51967

* Update link colors for hc theme to meet color contrast ratio, fixes #55651

Also updated link color for `textLinkActiveForeground` to be the same as `textLinkForeground` as it wasn't properly updated

* detect 'winpty-agent.exe'; fixes #55672

* node-debug@1.26.7

* reset counter on new label

* Settings editor - fix multiple setting links in one description

* Settings editor - color code blocks in setting descriptions, fix #55532

* Settings editor - hover color in TOC

* Settings editor - fix navigation NPE

* Settings editor - fix text control width

* Settings editor - maybe fix #55684

* Fix bug causing cursor to not move on paste

* fixes #53582

* Use ctrlCmd instead of ctrl for go down from search box

* fixes #55264

* fixes #55456

* filter for spcaes before triggering search (#55611)

* Fix #55698 - don't lose filtered TOC counts when refreshing TOC

* fixes #55421

* fixes #28979

* fixes #55576

* only add check for updates to windows/linux help

* readonly files: append decoration to label

fixes #53022

* debug: do not show toolbar while initialising

fixes #55026

* Opening launch.json should not activate debug extensions

fixes #55029

* fixes #55435

* fixes #55434

* fixes #55439

* trigger menu only on altkey up

* Fix #50555 - fix settings editor memory leak

* Fix #55712 - no need to focus 'a' anymore when restoring control focus after tree render

* fixes #55335

* proper fix for readonly model

fixes #53022

* improve FoldingRangeKind spec (for #55686)

* Use class with static fields (fixes #55494)

* Fixes #53671

* fixes #54630

* [html] should disable ionic suggestions by default. Currently forces deprecated Ionic v1 suggestions in .html files while typing. Fixes #53324

* cleanup deps

* debug issues back to andre

* update electron for smoketest

* Fix #55757 - prevent settings tabs from overflowing

* Fix #53897 - revert setting menu defaults to old editor

* Add enum descriptions to `typescript.preferences.importModuleSpecifier`

* Fix #55767 - leaking style elements from settings editor

* Fix #55521 - prevent flashing when clicking in exclude control

* Update Git modified color for contrast ratio, fixes #53140

* Revert "Merge branch 'master' of github.com:Microsoft/vscode"

This reverts commit bf46b6bfbae0cab99c2863e1244a916181fa9fbc, reversing
changes made to e275a424483dfb4ed33b428c97d5e2c441d6b917.

* Revert "Revert "Merge branch 'master' of github.com:Microsoft/vscode""

This reverts commit 53949d963f39e40757557c6526332354a31d9154.

* don't ask to install an incomplete menu

* Fix NPE in terminal AccessibilityManager

Fixes #55744

* don't display fallback menu unless we've closed the last window

* fixes #55547

* Fix smoke tests for extension search box

* Update OSSREADME.json for Electron 2.0.5

* Update distro

Includes Chromium license changes

* fix #55455

* fix #55865

* fixes #55893

* Fix bug causing workspace recommendations to go away upon ignoring a recommendation (#55805)

* Fix bug causing workspace recommendations to go away upon ignoring a recommendation

* ONly show on @recommended or @recommended:workspace

* Make more consistant

* Fix #55911

* Understand json activity (#55926)

* Understand json file activity

* Refactoring

* adding composer.json

* Distro update for experiments

* use terminal.processId for auto-attach; fixes #55918

* Reject invalid URI with vscode.openFolder (for #55891)

* improve win32 setup system vs user detection

fixes #55840

fixes #55840

delay winreg import

related to #55840

show notification earlier

related to #55840

fix #55840

update inno setup message

related to #55840

* Fix #55593 - this code only operates on local paths, so use fsPath and Uri.file instead

* Bring back the old menu due to electron 2.0 issues (#55913)

* add the old menu back for native menus

* make menu labels match

* `vscode.openFolder`: treat missing URI schema gracefully (for #55891)

* delay EH reattach; fixes #55955

* Mark all json files under appSettingsHome as settings

* Use localized strings for telemetry opt-out

* Exception when saving file editor opened from remote file provider (fixes #55051)

* Remove terminal menu from stable

Fixes 56003

* VSCode Insiders crashes on open with TypeError: Cannot read property 'lastIndexOf' of undefined. Fixes #54933

* improve fix for #55891

* fix #55916

* Improve #55891

* increase EH debugging restart delay; fixes #55955

* Revert "Don't include non-resource entries in history quick pick"

This reverts commit 37209a838e9f7e9abe6dc53ed73cdf1e03b72060.

* Diff editor: horizontal scrollbar height is smaller (fixes #56062)

* improve openFolder uri fix (correctly treat backslashes)

* fixes #56116
repair ipc for native menubar keybindings

* Fix #56240 - Open the JSON settings editor instead of the UI editor

* Fix #55536

* uriDisplay: if no formatter is registered fall back to getPathlabel

fixes #56104

* VSCode hangs when opening python file. Fixes #56377

* VS Code Hangs When Opening Specific PowerShell File. Fixes #56430

* Fix #56433 - search extraFileResources even when no folders open

* Workaround #55649

* Fix in master #56371

* Fix tests #56371

* Fix in master #56317

* increase version to 1.26.1

* Fixes #56387: Handle SIGPIPE in extension host

* fixes #56185

* Fix merge issues (part 1)

* Fix build breaks (part 1)

* Build breaks (part 2)

* Build breaks (part 3)

* More build breaks (part 4)

* Fix build breaks (part 5)

* WIP

* Fix menus

* Render query result and message panels (#2363)

* Put back query editor hot exit changes

* Fix grid changes that broke profiler (#2365)

* Update APIs for saving query editor state

* Fix restore view state for profiler and edit data

* Updating custom default themes to support 4.5:1 contrast ratio

* Test updates

* Fix Extension Manager and Windows Setup

* Update license headers

* Add appveyor and travis files back

* Fix hidden modal dropdown issue
This commit is contained in:
Karl Burtram
2018-09-04 14:55:00 -07:00
committed by GitHub
parent 3763278366
commit 81329fa7fa
2638 changed files with 118456 additions and 64012 deletions

View File

@@ -5,7 +5,7 @@
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
export interface ITelemetryData {
@@ -237,3 +237,26 @@ export class ActionRunner implements IActionRunner {
this._onDidRun.dispose();
}
}
export class RadioGroup {
private _disposable: IDisposable;
constructor(readonly actions: Action[]) {
this._disposable = combinedDisposable(actions.map(action => {
return action.onDidChange(e => {
if (e.checked && action.checked) {
for (const candidate of actions) {
if (candidate !== action) {
candidate.checked = false;
}
}
}
});
}));
}
dispose(): void {
this._disposable.dispose();
}
}

View File

@@ -12,11 +12,19 @@ import { ISplice } from 'vs/base/common/sequence';
* @param array The array.
* @param n Which element from the end (default is zero).
*/
export function tail<T>(array: T[], n: number = 0): T {
export function tail<T>(array: ArrayLike<T>, n: number = 0): T {
return array[array.length - (1 + n)];
}
export function equals<T>(one: T[], other: T[], itemEquals: (a: T, b: T) => boolean = (a, b) => a === b): boolean {
export function tail2<T>(arr: T[]): [T[], T] {
if (arr.length === 0) {
throw new Error('Invalid tail call');
}
return [arr.slice(0, arr.length - 1), arr[arr.length - 1]];
}
export function equals<T>(one: ReadonlyArray<T>, other: ReadonlyArray<T>, itemEquals: (a: T, b: T) => boolean = (a, b) => a === b): boolean {
if (one.length !== other.length) {
return false;
}
@@ -69,48 +77,56 @@ export function findFirstInSorted<T>(array: T[], p: (x: T) => boolean): number {
return low;
}
type Compare<T> = (a: T, b: T) => number;
/**
* Like `Array#sort` but always stable. Usually runs a little slower `than Array#sort`
* so only use this when actually needing stable sort.
*/
export function mergeSort<T>(data: T[], compare: (a: T, b: T) => number): T[] {
_divideAndMerge(data, compare);
export function mergeSort<T>(data: T[], compare: Compare<T>): T[] {
_sort(data, compare, 0, data.length - 1, []);
return data;
}
function _divideAndMerge<T>(data: T[], compare: (a: T, b: T) => number): void {
if (data.length <= 1) {
// sorted
return;
function _merge<T>(a: T[], compare: Compare<T>, lo: number, mid: number, hi: number, aux: T[]): void {
let leftIdx = lo, rightIdx = mid + 1;
for (let i = lo; i <= hi; i++) {
aux[i] = a[i];
}
const p = (data.length / 2) | 0;
const left = data.slice(0, p);
const right = data.slice(p);
_divideAndMerge(left, compare);
_divideAndMerge(right, compare);
let leftIdx = 0;
let rightIdx = 0;
let i = 0;
while (leftIdx < left.length && rightIdx < right.length) {
let ret = compare(left[leftIdx], right[rightIdx]);
if (ret <= 0) {
// smaller_equal -> take left to preserve order
data[i++] = left[leftIdx++];
for (let i = lo; i <= hi; i++) {
if (leftIdx > mid) {
// left side consumed
a[i] = aux[rightIdx++];
} else if (rightIdx > hi) {
// right side consumed
a[i] = aux[leftIdx++];
} else if (compare(aux[rightIdx], aux[leftIdx]) < 0) {
// right element is less -> comes first
a[i] = aux[rightIdx++];
} else {
// greater -> take right
data[i++] = right[rightIdx++];
// left element comes first (less or equal)
a[i] = aux[leftIdx++];
}
}
while (leftIdx < left.length) {
data[i++] = left[leftIdx++];
}
while (rightIdx < right.length) {
data[i++] = right[rightIdx++];
}
}
function _sort<T>(a: T[], compare: Compare<T>, lo: number, hi: number, aux: T[]) {
if (hi <= lo) {
return;
}
let mid = lo + ((hi - lo) / 2) | 0;
_sort(a, compare, lo, mid, aux);
_sort(a, compare, mid + 1, hi, aux);
if (compare(a[mid], a[mid + 1]) <= 0) {
// left and right are sorted and if the last-left element is less
// or equals than the first-right element there is nothing else
// to do
return;
}
_merge(a, compare, lo, mid, hi, aux);
}
export function groupBy<T>(data: T[], compare: (a: T, b: T) => number): T[][] {
const result: T[][] = [];
let currentGroup: T[];
@@ -276,12 +292,27 @@ function topStep<T>(array: T[], compare: (a: T, b: T) => number, result: T[], i:
/**
* @returns a new array with all undefined or null values removed. The original array is not modified at all.
*/
export function coalesce<T>(array: T[]): T[] {
export function coalesce<T>(array: T[]): T[];
export function coalesce<T>(array: T[], inplace: true): void;
export function coalesce<T>(array: T[], inplace?: true): void | T[] {
if (!array) {
return array;
if (!inplace) {
return array;
}
}
if (!inplace) {
return array.filter(e => !!e);
return array.filter(e => !!e);
} else {
let to = 0;
for (let i = 0; i < array.length; i++) {
if (!!array[i]) {
array[to] = array[i];
to += 1;
}
}
array.length = to;
}
}
/**
@@ -338,7 +369,7 @@ export function uniqueFilter<T>(keyFn: (t: T) => string): (t: T) => boolean {
};
}
export function firstIndex<T>(array: T[], fn: (item: T) => boolean): number {
export function firstIndex<T>(array: T[] | ReadonlyArray<T>, fn: (item: T) => boolean): number {
for (let i = 0; i < array.length; i++) {
const element = array[i];
@@ -350,7 +381,7 @@ export function firstIndex<T>(array: T[], fn: (item: T) => boolean): number {
return -1;
}
export function first<T>(array: T[], fn: (item: T) => boolean, notFoundValue: T = null): T {
export function first<T>(array: T[] | ReadonlyArray<T>, fn: (item: T) => boolean, notFoundValue: T = null): T {
const index = firstIndex(array, fn);
return index < 0 ? notFoundValue : array[index];
}
@@ -443,15 +474,44 @@ export function arrayInsert<T>(target: T[], insertIndex: number, insertArr: T[])
* Uses Fisher-Yates shuffle to shuffle the given array
* @param array
*/
export function shuffle<T>(array: T[]): void {
var i = 0
, j = 0
, temp = null;
export function shuffle<T>(array: T[], seed?: number): void {
// Seeded random number generator in JS. Modified from:
// https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript
const random = () => {
var x = Math.sin(seed++) * 179426549; // throw away most significant digits and reduce any potential bias
return x - Math.floor(x);
};
for (i = array.length - 1; i > 0; i -= 1) {
j = Math.floor(Math.random() * (i + 1));
temp = array[i];
const rand = typeof seed === 'number' ? random : Math.random;
for (let i = array.length - 1; i > 0; i -= 1) {
let j = Math.floor(rand() * (i + 1));
let temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
/**
* Pushes an element to the start of the array, if found.
*/
export function pushToStart<T>(arr: T[], value: T): void {
const index = arr.indexOf(value);
if (index > -1) {
arr.splice(index, 1);
arr.unshift(value);
}
}
/**
* Pushes an element to the end of the array, if found.
*/
export function pushToEnd<T>(arr: T[], value: T): void {
const index = arr.indexOf(value);
if (index > -1) {
arr.splice(index, 1);
arr.push(value);
}
}

View File

@@ -6,7 +6,7 @@
'use strict';
import * as errors from 'vs/base/common/errors';
import { Promise, TPromise, ValueCallback, ErrorCallback, ProgressCallback } from 'vs/base/common/winjs.base';
import { TPromise, ValueCallback, ErrorCallback, ProgressCallback } from 'vs/base/common/winjs.base';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
@@ -24,6 +24,48 @@ export function toThenable<T>(arg: T | Thenable<T>): Thenable<T> {
}
}
export function toWinJsPromise<T>(arg: Thenable<T> | TPromise<T>): TPromise<T> {
if (arg instanceof TPromise) {
return arg;
}
return new TPromise((resolve, reject) => arg.then(resolve, reject));
}
export interface CancelablePromise<T> extends Promise<T> {
cancel(): void;
}
export function createCancelablePromise<T>(callback: (token: CancellationToken) => Thenable<T>): CancelablePromise<T> {
const source = new CancellationTokenSource();
const thenable = callback(source.token);
const promise = new Promise<T>((resolve, reject) => {
source.token.onCancellationRequested(() => {
reject(errors.canceled());
});
Promise.resolve(thenable).then(value => {
source.dispose();
resolve(value);
}, err => {
source.dispose();
reject(err);
});
});
return new class implements CancelablePromise<T> {
cancel() {
source.cancel();
}
then<TResult1 = T, TResult2 = never>(resolve?: ((value: T) => TResult1 | Thenable<TResult1>) | undefined | null, reject?: ((reason: any) => TResult2 | Thenable<TResult2>) | undefined | null): Promise<TResult1 | TResult2> {
return promise.then(resolve, reject);
}
catch<TResult = never>(reject?: ((reason: any) => TResult | Thenable<TResult>) | undefined | null): Promise<T | TResult> {
return this.then(undefined, reject);
}
};
}
export function asWinJsPromise<T>(callback: (token: CancellationToken) => T | TPromise<T> | Thenable<T>): TPromise<T> {
let source = new CancellationTokenSource();
return new TPromise<T>((resolve, reject, progress) => {
@@ -69,6 +111,33 @@ export function wireCancellationToken<T>(token: CancellationToken, promise: TPro
return always(promise, () => subscription.dispose());
}
export function asDisposablePromise<T>(input: Thenable<T>, cancelValue?: T, bucket?: IDisposable[]): { promise: Thenable<T> } & IDisposable {
let dispose: () => void;
let promise = new TPromise((resolve, reject) => {
dispose = function () {
resolve(cancelValue);
if (isWinJSPromise(input)) {
input.cancel();
}
};
input.then(resolve, err => {
if (errors.isPromiseCanceledError(err)) {
resolve(cancelValue);
} else {
reject(err);
}
});
});
let res = {
promise,
dispose
};
if (Array.isArray(bucket)) {
bucket.push(res);
}
return res;
}
export interface ITask<T> {
(): T;
}
@@ -101,9 +170,9 @@ export interface ITask<T> {
*/
export class Throttler {
private activePromise: Promise;
private queuedPromise: Promise;
private queuedPromiseFactory: ITask<Promise>;
private activePromise: TPromise;
private queuedPromise: TPromise;
private queuedPromiseFactory: ITask<TPromise>;
constructor() {
this.activePromise = null;
@@ -169,7 +238,7 @@ export class SimpleThrottler {
* A helper to delay execution of a task that is being requested often.
*
* Following the throttler, now imagine the mail man wants to optimize the number of
* trips proactively. The trip itself can be long, so the he decides not to make the trip
* trips proactively. The trip itself can be long, so he decides not to make the trip
* as soon as a letter is submitted. Instead he waits a while, in case more
* letters are submitted. After said waiting period, if no letters were submitted, he
* decides to make the trip. Imagine that N more letters were submitted after the first
@@ -191,7 +260,7 @@ export class SimpleThrottler {
export class Delayer<T> {
private timeout: number;
private completionPromise: Promise;
private completionPromise: TPromise;
private onSuccess: ValueCallback;
private task: ITask<T | TPromise<T>>;
@@ -254,7 +323,7 @@ export class Delayer<T> {
* A helper to delay execution of a task that is being requested often, while
* preventing accumulation of consecutive executions, while the task runs.
*
* Simply combine the two mail man strategies from the Throttler and Delayer
* Simply combine the two mail men's strategies from the Throttler and Delayer
* helpers, for an analogy.
*/
export class ThrottledDelayer<T> extends Delayer<TPromise<T>> {
@@ -283,7 +352,7 @@ export class Barrier {
constructor() {
this._isOpen = false;
this._promise = new TPromise<boolean>((c, e, p) => {
this._promise = new TPromise<boolean>((c, e) => {
this._completePromise = c;
}, () => {
console.warn('You should really not try to cancel this ready promise!');
@@ -327,10 +396,18 @@ export class ShallowCancelThenPromise<T> extends TPromise<T> {
}
/**
* Replacement for `WinJS.Promise.timeout`.
* Replacement for `WinJS.TPromise.timeout`.
*/
export function timeout(n: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, n));
export function timeout(n: number): CancelablePromise<void> {
return createCancelablePromise(token => {
return new Promise((resolve, reject) => {
const handle = setTimeout(resolve, n);
token.onCancellationRequested(_ => {
clearTimeout(handle);
reject(errors.canceled());
});
});
});
}
function isWinJSPromise(candidate: any): candidate is TPromise {
@@ -384,16 +461,11 @@ export function always<T>(winjsPromiseOrThenable: Thenable<T> | TPromise<T>, f:
export function sequence<T>(promiseFactories: ITask<Thenable<T>>[]): TPromise<T[]> {
const results: T[] = [];
let index = 0;
const len = promiseFactories.length;
// reverse since we start with last element using pop()
promiseFactories = promiseFactories.reverse();
function next(): Thenable<any> {
if (promiseFactories.length) {
return promiseFactories.pop()();
}
return null;
function next(): Thenable<T> | null {
return index < len ? promiseFactories[index++]() : null;
}
function thenHandler(result: any): Thenable<any> {
@@ -412,15 +484,38 @@ export function sequence<T>(promiseFactories: ITask<Thenable<T>>[]): TPromise<T[
return TPromise.as(null).then(thenHandler);
}
export function first<T>(promiseFactories: ITask<TPromise<T>>[], shouldStop: (t: T) => boolean = t => !!t): TPromise<T> {
promiseFactories = [...promiseFactories.reverse()];
export function first2<T>(promiseFactories: ITask<Promise<T>>[], shouldStop: (t: T) => boolean = t => !!t, defaultValue: T = null): Promise<T> {
let index = 0;
const len = promiseFactories.length;
const loop = () => {
if (index >= len) {
return Promise.resolve(defaultValue);
}
const factory = promiseFactories[index++];
const promise = factory();
return promise.then(result => {
if (shouldStop(result)) {
return Promise.resolve(result);
}
return loop();
});
};
return loop();
}
export function first<T>(promiseFactories: ITask<TPromise<T>>[], shouldStop: (t: T) => boolean = t => !!t, defaultValue: T = null): TPromise<T> {
let index = 0;
const len = promiseFactories.length;
const loop: () => TPromise<T> = () => {
if (promiseFactories.length === 0) {
return TPromise.as(null);
if (index >= len) {
return TPromise.as(defaultValue);
}
const factory = promiseFactories.pop();
const factory = promiseFactories[index++];
const promise = factory();
return promise.then(result => {
@@ -436,7 +531,7 @@ export function first<T>(promiseFactories: ITask<TPromise<T>>[], shouldStop: (t:
}
interface ILimitedTaskFactory {
factory: ITask<Promise>;
factory: ITask<TPromise>;
c: ValueCallback;
e: ErrorCallback;
p: ProgressCallback;
@@ -467,7 +562,7 @@ export class Limiter<T> {
return this.runningPromises + this.outstandingPromises.length;
}
queue(promiseFactory: ITask<Promise>): Promise;
queue(promiseFactory: ITask<TPromise>): TPromise;
queue(promiseFactory: ITask<TPromise<T>>): TPromise<T> {
return new TPromise<T>((c, e, p) => {
this.outstandingPromises.push({
@@ -620,12 +715,13 @@ export class IntervalTimer extends Disposable {
export class RunOnceScheduler {
protected runner: (...args: any[]) => void;
private timeoutToken: number;
private runner: () => void;
private timeout: number;
private timeoutHandler: () => void;
constructor(runner: () => void, timeout: number) {
constructor(runner: (...args: any[]) => void, timeout: number) {
this.timeoutToken = -1;
this.runner = runner;
this.timeout = timeout;
@@ -668,61 +764,52 @@ export class RunOnceScheduler {
private onTimeout() {
this.timeoutToken = -1;
if (this.runner) {
this.runner();
this.doRun();
}
}
protected doRun(): void {
this.runner();
}
}
export function nfcall(fn: Function, ...args: any[]): Promise;
export class RunOnceWorker<T> extends RunOnceScheduler {
private units: T[] = [];
constructor(runner: (units: T[]) => void, timeout: number) {
super(runner, timeout);
}
work(unit: T): void {
this.units.push(unit);
if (!this.isScheduled()) {
this.schedule();
}
}
protected doRun(): void {
const units = this.units;
this.units = [];
this.runner(units);
}
dispose(): void {
this.units = [];
super.dispose();
}
}
export function nfcall(fn: Function, ...args: any[]): TPromise;
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: any, result: any) => err ? e(err) : c(result)), () => null);
}
export function ninvoke(thisArg: any, fn: Function, ...args: any[]): Promise;
export function ninvoke(thisArg: any, fn: Function, ...args: any[]): TPromise;
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: 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

@@ -47,6 +47,15 @@ export function size<T>(from: IStringDictionary<T> | INumberDictionary<T>): numb
return count;
}
export function first<T>(from: IStringDictionary<T> | INumberDictionary<T>): T {
for (let key in from) {
if (hasOwnProperty.call(from, key)) {
return from[key];
}
}
return undefined;
}
/**
* Iterates over each entry in the provided set. The iterator allows
* to remove elements and will stop when the callback returns {{false}}.

View File

@@ -114,7 +114,7 @@ export class HSLA {
return new HSLA(h, s, l, a);
}
private static _hue2rgb(p: number, q: number, t: number) {
private static _hue2rgb(p: number, q: number, t: number): number {
if (t < 0) {
t += 1;
}

View File

@@ -5,21 +5,15 @@
'use strict';
function pad(number: number): string {
if (number < 10) {
return '0' + number;
}
return String(number);
}
import { pad } from './strings';
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()) +
'-' + pad(date.getMonth() + 1, 2) +
'-' + pad(date.getDate(), 2) +
'T' + pad(date.getHours(), 2) +
':' + pad(date.getMinutes(), 2) +
':' + pad(date.getSeconds(), 2) +
'.' + (date.getMilliseconds() / 1000).toFixed(3).slice(2, 5) +
'Z';
}
}

View File

@@ -69,19 +69,23 @@ export interface IDebouceReducer<T> {
export function debounce<T>(delay: number, reducer?: IDebouceReducer<T>, initialValueProvider?: () => T): Function {
return createDecorator((fn, key) => {
const timerKey = `$debounce$${key}`;
let result = initialValueProvider ? initialValueProvider() : void 0;
const resultKey = `$debounce$result$${key}`;
return function (this: any, ...args: any[]) {
if (!this[resultKey]) {
this[resultKey] = initialValueProvider ? initialValueProvider() : void 0;
}
clearTimeout(this[timerKey]);
if (reducer) {
result = reducer(result, ...args);
args = [result];
this[resultKey] = reducer(this[resultKey], ...args);
args = [this[resultKey]];
}
this[timerKey] = setTimeout(() => {
fn.apply(this, args);
result = initialValueProvider ? initialValueProvider() : void 0;
this[resultKey] = initialValueProvider ? initialValueProvider() : void 0;
}, delay);
};
});

View File

@@ -1,88 +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 * as Platform from 'vs/base/common/platform';
/**
* To enable diagnostics, open a browser console and type: window.Monaco.Diagnostics.<diagnostics name> = true.
* Then trigger an action that will write to diagnostics to see all cached output from the past.
*/
const globals = Platform.globals;
if (!globals.Monaco) {
globals.Monaco = {};
}
globals.Monaco.Diagnostics = {};
const switches = globals.Monaco.Diagnostics;
const map = new Map<string, Function[]>();
const data: any[] = [];
function fifo(array: any[], size: number) {
while (array.length > size) {
array.shift();
}
}
export function register(what: string, fn: Function): (...args: any[]) => void {
let disable = true; // Otherwise we have unreachable code.
if (disable) {
return () => {
// Intentional empty, disable for now because it is leaking memory
};
}
// register switch
const flag = switches[what] || false;
switches[what] = flag;
// register function
const tracers = map.get(what) || [];
tracers.push(fn);
map.set(what, tracers);
const result = function (...args: any[]) {
let idx: number;
if (switches[what] === true) {
// replay back-in-time functions
const allArgs = [arguments];
idx = data.indexOf(fn);
if (idx !== -1) {
allArgs.unshift.apply(allArgs, data[idx + 1] || []);
data[idx + 1] = [];
}
const doIt: () => void = function () {
const thisArguments = allArgs.shift();
fn.apply(fn, thisArguments);
if (allArgs.length > 0) {
setTimeout(doIt, 500);
}
};
doIt();
} else {
// know where to store
idx = data.indexOf(fn);
idx = idx !== -1 ? idx : data.length;
const dataIdx = idx + 1;
// store arguments
const allargs = data[dataIdx] || [];
allargs.push(arguments);
fifo(allargs, 50);
// store data
data[idx] = fn;
data[dataIdx] = allargs;
}
};
return result;
}

View File

@@ -6,12 +6,10 @@
import { DiffChange } from 'vs/base/common/diff/diffChange';
function createStringSequence(a: string): ISequence {
return {
getLength() { return a.length; },
getElementHash(pos: number) { return a[pos]; }
getElementAtIndex(pos: number) { return a.charCodeAt(pos); }
};
}
@@ -22,7 +20,7 @@ export function stringDiff(original: string, modified: string, pretty: boolean):
export interface ISequence {
getLength(): number;
getElementHash(index: number): string;
getElementAtIndex(index: number): number | string;
}
export interface IDiffChange {
@@ -211,8 +209,6 @@ class DiffChangeHelper {
}
const hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* An implementation of the difference algorithm described in
* "An O(ND) Difference Algorithm and its variations" by Eugene W. Myers
@@ -223,8 +219,6 @@ export class LcsDiff {
private ModifiedSequence: ISequence;
private ContinueProcessingPredicate: IContinueProcessingPredicate;
private m_originalIds: number[];
private m_modifiedIds: number[];
private m_forwardHistory: number[][];
private m_reverseHistory: number[][];
@@ -235,63 +229,21 @@ export class LcsDiff {
this.OriginalSequence = originalSequence;
this.ModifiedSequence = newSequence;
this.ContinueProcessingPredicate = continueProcessingPredicate;
this.m_originalIds = [];
this.m_modifiedIds = [];
this.m_forwardHistory = [];
this.m_reverseHistory = [];
this.ComputeUniqueIdentifiers();
}
private ComputeUniqueIdentifiers(): void {
let originalSequenceLength = this.OriginalSequence.getLength();
let modifiedSequenceLength = this.ModifiedSequence.getLength();
this.m_originalIds = new Array<number>(originalSequenceLength);
this.m_modifiedIds = new Array<number>(modifiedSequenceLength);
// Create a new hash table for unique elements from the original
// sequence.
let hashTable: { [key: string]: number; } = {};
let currentUniqueId = 1;
let i: number;
// Fill up the hash table for unique elements
for (i = 0; i < originalSequenceLength; i++) {
let originalElementHash = this.OriginalSequence.getElementHash(i);
if (!hasOwnProperty.call(hashTable, originalElementHash)) {
// No entry in the hashtable so this is a new unique element.
// Assign the element a new unique identifier and add it to the
// hash table
this.m_originalIds[i] = currentUniqueId++;
hashTable[originalElementHash] = this.m_originalIds[i];
} else {
this.m_originalIds[i] = hashTable[originalElementHash];
}
}
// Now match up modified elements
for (i = 0; i < modifiedSequenceLength; i++) {
let modifiedElementHash = this.ModifiedSequence.getElementHash(i);
if (!hasOwnProperty.call(hashTable, modifiedElementHash)) {
this.m_modifiedIds[i] = currentUniqueId++;
hashTable[modifiedElementHash] = this.m_modifiedIds[i];
} else {
this.m_modifiedIds[i] = hashTable[modifiedElementHash];
}
}
}
private ElementsAreEqual(originalIndex: number, newIndex: number): boolean {
return this.m_originalIds[originalIndex] === this.m_modifiedIds[newIndex];
return (this.OriginalSequence.getElementAtIndex(originalIndex) === this.ModifiedSequence.getElementAtIndex(newIndex));
}
private OriginalElementsAreEqual(index1: number, index2: number): boolean {
return this.m_originalIds[index1] === this.m_originalIds[index2];
return (this.OriginalSequence.getElementAtIndex(index1) === this.OriginalSequence.getElementAtIndex(index2));
}
private ModifiedElementsAreEqual(index1: number, index2: number): boolean {
return this.m_modifiedIds[index1] === this.m_modifiedIds[index2];
return (this.ModifiedSequence.getElementAtIndex(index1) === this.ModifiedSequence.getElementAtIndex(index2));
}
public ComputeDiff(pretty: boolean): IDiffChange[] {
@@ -891,7 +843,8 @@ export class LcsDiff {
if (index <= 0 || index >= this.OriginalSequence.getLength() - 1) {
return true;
}
return /^\s*$/.test(this.OriginalSequence.getElementHash(index));
const element = this.OriginalSequence.getElementAtIndex(index);
return (typeof element === 'string' && /^\s*$/.test(element));
}
private _OriginalRegionIsBoundary(originalStart: number, originalLength: number): boolean {
@@ -911,7 +864,8 @@ export class LcsDiff {
if (index <= 0 || index >= this.ModifiedSequence.getLength() - 1) {
return true;
}
return /^\s*$/.test(this.ModifiedSequence.getElementHash(index));
const element = this.ModifiedSequence.getElementAtIndex(index);
return (typeof element === 'string' && /^\s*$/.test(element));
}
private _ModifiedRegionIsBoundary(modifiedStart: number, modifiedLength: number): boolean {

View File

@@ -4,11 +4,11 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IDisposable, toDisposable, combinedDisposable, empty as EmptyDisposable } from 'vs/base/common/lifecycle';
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 { once as onceFn } from 'vs/base/common/functional';
import { combinedDisposable, Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { LinkedList } from 'vs/base/common/linkedList';
import { TPromise } from 'vs/base/common/winjs.base';
/**
* To an event a function with one or zero parameters
@@ -58,9 +58,9 @@ export class Emitter<T> {
private static readonly _noop = function () { };
private _event: Event<T>;
private _listeners: LinkedList<Listener>;
private _deliveryQueue: [Listener, T][];
private _disposed: boolean;
private _deliveryQueue: [Listener, T][];
protected _listeners: LinkedList<Listener>;
constructor(private _options?: EmitterOptions) {
@@ -159,6 +159,52 @@ export class Emitter<T> {
}
}
export interface IWaitUntil {
waitUntil(thenable: Thenable<any>): void;
}
export class AsyncEmitter<T extends IWaitUntil> extends Emitter<T> {
private _asyncDeliveryQueue: [Listener, T, Thenable<any>[]][];
async fireAsync(eventFn: (thenables: Thenable<any>[], listener: Function) => T): Promise<void> {
if (!this._listeners) {
return;
}
// put all [listener,event]-pairs into delivery queue
// then emit all event. an inner/nested event might be
// the driver of this
if (!this._asyncDeliveryQueue) {
this._asyncDeliveryQueue = [];
}
for (let iter = this._listeners.iterator(), e = iter.next(); !e.done; e = iter.next()) {
let thenables: Thenable<void>[] = [];
this._asyncDeliveryQueue.push([e.value, eventFn(thenables, typeof e.value === 'function' ? e.value : e.value[0]), thenables]);
}
while (this._asyncDeliveryQueue.length > 0) {
const [listener, event, thenables] = this._asyncDeliveryQueue.shift();
try {
if (typeof listener === 'function') {
listener.call(undefined, event);
} else {
listener[0].call(listener[1], event);
}
} catch (e) {
onUnexpectedError(e);
continue;
}
// freeze thenables-collection to enforce sync-calls to
// wait until and then wait for all thenables to resolve
Object.freeze(thenables);
await Promise.all(thenables);
}
}
}
export class EventMultiplexer<T> implements IDisposable {
private readonly emitter: Emitter<T>;
@@ -367,6 +413,7 @@ export interface IChainableEvent<T> {
filter(fn: (e: T) => boolean): IChainableEvent<T>;
latch(): IChainableEvent<T>;
on(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable;
once(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable;
}
export function mapEvent<I, O>(event: Event<I>, map: (i: I) => O): Event<O> {
@@ -377,6 +424,8 @@ export function forEach<I>(event: Event<I>, each: (i: I) => void): Event<I> {
return (listener, thisArgs = null, disposables?) => event(i => { each(i); listener.call(thisArgs, i); }, null, disposables);
}
export function filterEvent<T>(event: Event<T>, filter: (e: T) => boolean): Event<T>;
export function filterEvent<T, R>(event: Event<T | R>, filter: (e: T | R) => e is R): Event<R>;
export function filterEvent<T>(event: Event<T>, filter: (e: T) => boolean): Event<T> {
return (listener, thisArgs = null, disposables?) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables);
}
@@ -406,6 +455,10 @@ class ChainableEvent<T> implements IChainableEvent<T> {
on(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[]) {
return this._event(listener, thisArgs, disposables);
}
once(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[]) {
return once(this._event)(listener, thisArgs, disposables);
}
}
export function chain<T>(event: Event<T>): IChainableEvent<T> {
@@ -513,7 +566,7 @@ export class Relay<T> implements IDisposable {
private emitter = new Emitter<T>();
readonly event: Event<T> = this.emitter.event;
private disposable: IDisposable = EmptyDisposable;
private disposable: IDisposable = Disposable.None;
set input(event: Event<T>) {
this.disposable.dispose();
@@ -550,4 +603,4 @@ export function latch<T>(event: Event<T>): Event<T> {
cache = value;
return shouldEmit;
});
}
}

View File

@@ -255,7 +255,8 @@ export function matchesCamelCase(word: string, camelCaseWord: string): IMatch[]
let result: IMatch[] = null;
let i = 0;
while (i < camelCaseWord.length && (result = _matchesCamelCase(word.toLowerCase(), camelCaseWord, 0, i)) === null) {
word = word.toLowerCase();
while (i < camelCaseWord.length && (result = _matchesCamelCase(word, camelCaseWord, 0, i)) === null) {
i = nextAnchor(camelCaseWord, i + 1);
}
@@ -275,7 +276,9 @@ export function matchesWords(word: string, target: string, contiguous: boolean =
let result: IMatch[] = null;
let i = 0;
while (i < target.length && (result = _matchesWords(word.toLowerCase(), target, 0, i, contiguous)) === null) {
word = word.toLowerCase();
target = target.toLowerCase();
while (i < target.length && (result = _matchesWords(word, target, 0, i, contiguous)) === null) {
i = nextWord(target, i + 1);
}
@@ -287,7 +290,7 @@ function _matchesWords(word: string, target: string, i: number, j: number, conti
return [];
} else if (j === target.length) {
return null;
} else if (word[i] !== target[j].toLowerCase()) {
} else if (word[i] !== target[j]) {
return null;
} else {
let result: IMatch[] = null;
@@ -341,7 +344,7 @@ export function matchesFuzzy(word: string, wordToMatchAgainst: string, enableSep
return enableSeparateSubstringMatching ? fuzzySeparateFilter(word, wordToMatchAgainst) : fuzzyContiguousFilter(word, wordToMatchAgainst);
}
export function skipScore(pattern: string, word: string, patternMaxWhitespaceIgnore?: number): [number, number[]] {
export function anyScore(pattern: string, word: string, patternMaxWhitespaceIgnore?: number): FuzzyScore {
pattern = pattern.toLowerCase();
word = word.toLowerCase();
@@ -452,7 +455,9 @@ function isWhitespaceAtPos(value: string, index: number): boolean {
const enum Arrow { Top = 0b1, Diag = 0b10, Left = 0b100 }
export function fuzzyScore(pattern: string, word: string, patternMaxWhitespaceIgnore?: number): [number, number[]] {
export type FuzzyScore = [number, number[]];
export function fuzzyScore(pattern: string, word: string, patternMaxWhitespaceIgnore?: number, firstMatchCanBeWeak?: boolean): FuzzyScore {
const patternLen = pattern.length > 100 ? 100 : pattern.length;
const wordLen = word.length > 100 ? 100 : word.length;
@@ -514,7 +519,7 @@ export function fuzzyScore(pattern: string, word: string, patternMaxWhitespaceIg
} else {
score = 5;
}
} else if (lowWordChar !== word[wordPos - 1]) {
} else if (lowWordChar !== word[wordPos - 1] && (wordPos === 1 || lowWord[wordPos - 2] === word[wordPos - 2])) {
// hitting upper-case: `foo <-> forOthers`
if (pattern[patternPos - 1] === word[wordPos - 1]) {
score = 7;
@@ -576,6 +581,7 @@ export function fuzzyScore(pattern: string, word: string, patternMaxWhitespaceIg
_matchesCount = 0;
_topScore = -100;
_patternStartPos = patternStartPos;
_firstMatchCanBeWeak = firstMatchCanBeWeak;
_findAllMatches(patternLen, wordLen, patternLen === wordLen ? 1 : 0, new LazyArray(), false);
if (_matchesCount === 0) {
@@ -589,6 +595,7 @@ let _matchesCount: number = 0;
let _topMatch: LazyArray;
let _topScore: number = 0;
let _patternStartPos: number = 0;
let _firstMatchCanBeWeak: boolean = false;
function _findAllMatches(patternPos: number, wordPos: number, total: number, matches: LazyArray, lastMatched: boolean): void {
@@ -642,7 +649,7 @@ function _findAllMatches(patternPos: number, wordPos: number, total: number, mat
if (score === 1) {
simpleMatchCount += 1;
if (patternPos === _patternStartPos) {
if (patternPos === _patternStartPos && !_firstMatchCanBeWeak) {
// when the first match is a weak
// match we discard it
return undefined;
@@ -715,15 +722,15 @@ class LazyArray {
//#region --- graceful ---
export function fuzzyScoreGracefulAggressive(pattern: string, word: string, patternMaxWhitespaceIgnore?: number): [number, number[]] {
export function fuzzyScoreGracefulAggressive(pattern: string, word: string, patternMaxWhitespaceIgnore?: number): FuzzyScore {
return fuzzyScoreWithPermutations(pattern, word, true, patternMaxWhitespaceIgnore);
}
export function fuzzyScoreGraceful(pattern: string, word: string, patternMaxWhitespaceIgnore?: number): [number, number[]] {
export function fuzzyScoreGraceful(pattern: string, word: string, patternMaxWhitespaceIgnore?: number): FuzzyScore {
return fuzzyScoreWithPermutations(pattern, word, false, patternMaxWhitespaceIgnore);
}
function fuzzyScoreWithPermutations(pattern: string, word: string, aggressive?: boolean, patternMaxWhitespaceIgnore?: number): [number, number[]] {
function fuzzyScoreWithPermutations(pattern: string, word: string, aggressive?: boolean, patternMaxWhitespaceIgnore?: number): FuzzyScore {
let top: [number, number[]] = fuzzyScore(pattern, word, patternMaxWhitespaceIgnore);
if (top && !aggressive) {

View File

@@ -247,8 +247,8 @@ const T5 = /^([\w\.-]+(\/[\w\.-]+)*)\/?$/; // something/else
export type ParsedPattern = (path: string, basename?: string) => boolean;
// The ParsedExpression returns a Promise iff siblingsFn returns a Promise.
export type ParsedExpression = (path: string, basename?: string, siblingsFn?: () => string[] | TPromise<string[]>) => string | TPromise<string> /* the matching pattern */;
// The ParsedExpression returns a Promise iff hasSibling returns a Promise.
export type ParsedExpression = (path: string, basename?: string, hasSibling?: (name: string) => boolean | TPromise<boolean>) => string | TPromise<string> /* the matching pattern */;
export interface IGlobOptions {
/**
@@ -264,9 +264,8 @@ interface ParsedStringPattern {
allBasenames?: string[];
allPaths?: string[];
}
type SiblingsPattern = { siblings: string[], name: string };
interface ParsedExpressionPattern {
(path: string, basename: string, siblingsPatternFn: () => SiblingsPattern | TPromise<SiblingsPattern>): string | TPromise<string> /* the matching pattern */;
(path: string, basename: string, name: string, hasSibling: (name: string) => boolean | TPromise<boolean>): string | TPromise<string> /* the matching pattern */;
requiresSiblings?: boolean;
allBasenames?: string[];
allPaths?: string[];
@@ -436,13 +435,13 @@ function toRegExp(pattern: string): ParsedStringPattern {
* - character ranges (using [...])
*/
export function match(pattern: string | IRelativePattern, path: string): boolean;
export function match(expression: IExpression, path: string, siblingsFn?: () => string[]): string /* the matching pattern */;
export function match(arg1: string | IExpression | IRelativePattern, path: string, siblingsFn?: () => string[]): any {
export function match(expression: IExpression, path: string, hasSibling?: (name: string) => boolean): string /* the matching pattern */;
export function match(arg1: string | IExpression | IRelativePattern, path: string, hasSibling?: (name: string) => boolean): any {
if (!arg1 || !path) {
return false;
}
return parse(<IExpression>arg1)(path, undefined, siblingsFn);
return parse(<IExpression>arg1)(path, undefined, hasSibling);
}
/**
@@ -482,6 +481,44 @@ export function parse(arg1: string | IExpression | IRelativePattern, options: IG
return parsedExpression(<IExpression>arg1, options);
}
export function hasSiblingPromiseFn(siblingsFn?: () => TPromise<string[]>) {
if (!siblingsFn) {
return undefined;
}
let siblings: TPromise<Record<string, true>>;
return (name: string) => {
if (!siblings) {
siblings = (siblingsFn() || TPromise.as([]))
.then(list => list ? listToMap(list) : {});
}
return siblings.then(map => !!map[name]);
};
}
export function hasSiblingFn(siblingsFn?: () => string[]) {
if (!siblingsFn) {
return undefined;
}
let siblings: Record<string, true>;
return (name: string) => {
if (!siblings) {
const list = siblingsFn();
siblings = list ? listToMap(list) : {};
}
return !!siblings[name];
};
}
function listToMap(list: string[]) {
const map: Record<string, true> = {};
for (const key of list) {
map[key] = true;
}
return map;
}
export function isRelativePattern(obj: any): obj is IRelativePattern {
const rp = obj as IRelativePattern;
@@ -493,8 +530,8 @@ export 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?: () => string[] | TPromise<string[]>): string | TPromise<string> => {
const result = parsedExpression(path, basename, siblingsFn);
return (path: string, basename?: string, hasSibling?: (name: string) => boolean | TPromise<boolean>): string | TPromise<string> => {
const result = parsedExpression(path, basename, hasSibling);
return result instanceof TPromise ? result : TPromise.as(result);
};
}
@@ -522,7 +559,7 @@ function parsedExpression(expression: IExpression, options: IGlobOptions): Parse
return <ParsedStringPattern>parsedPatterns[0];
}
const resultExpression: ParsedStringPattern = function (path: string, basename: string, siblingsFn?: () => string[]) {
const resultExpression: ParsedStringPattern = function (path: string, basename: string) {
for (let i = 0, n = parsedPatterns.length; i < n; i++) {
// Pattern matches path
const result = (<ParsedStringPattern>parsedPatterns[i])(path, basename);
@@ -547,38 +584,21 @@ function parsedExpression(expression: IExpression, options: IGlobOptions): Parse
return resultExpression;
}
const resultExpression: ParsedStringPattern = function (path: string, basename: string, siblingsFn?: () => string[] | TPromise<string[]>) {
let siblingsPattern: SiblingsPattern | TPromise<SiblingsPattern>;
let siblingsResolved = !siblingsFn;
function siblingsToSiblingsPattern(siblings: string[]) {
if (siblings && siblings.length) {
if (!basename) {
basename = paths.basename(path);
}
const name = basename.substr(0, basename.length - paths.extname(path).length);
return { siblings, name };
}
return undefined;
}
function siblingsPatternFn() {
// Resolve siblings only once
if (!siblingsResolved) {
siblingsResolved = true;
const siblings = siblingsFn();
siblingsPattern = TPromise.is(siblings) ?
siblings.then(siblingsToSiblingsPattern) :
siblingsToSiblingsPattern(siblings);
}
return siblingsPattern;
}
const resultExpression: ParsedStringPattern = function (path: string, basename: string, hasSibling?: (name: string) => boolean | TPromise<boolean>) {
let name: string;
for (let i = 0, n = parsedPatterns.length; i < n; i++) {
// Pattern matches path
const result = (<ParsedExpressionPattern>parsedPatterns[i])(path, basename, siblingsPatternFn);
const parsedPattern = (<ParsedExpressionPattern>parsedPatterns[i]);
if (parsedPattern.requiresSiblings && hasSibling) {
if (!basename) {
basename = paths.basename(path);
}
if (!name) {
name = basename.substr(0, basename.length - paths.extname(path).length);
}
}
const result = parsedPattern(path, basename, name, hasSibling);
if (result) {
return result;
}
@@ -619,28 +639,16 @@ function parseExpressionPattern(pattern: string, value: any, options: IGlobOptio
if (value) {
const when = (<SiblingClause>value).when;
if (typeof when === 'string') {
const siblingsPatternToMatchingPattern = (siblingsPattern: SiblingsPattern): string => {
let clausePattern = when.replace('$(basename)', siblingsPattern.name);
if (siblingsPattern.siblings.indexOf(clausePattern) !== -1) {
return pattern;
} else {
return null; // pattern does not match in the end because the when clause is not satisfied
}
};
const result: ParsedExpressionPattern = (path: string, basename: string, siblingsPatternFn: () => SiblingsPattern | TPromise<SiblingsPattern>) => {
if (!parsedPattern(path, basename)) {
const result: ParsedExpressionPattern = (path: string, basename: string, name: string, hasSibling: (name: string) => boolean | TPromise<boolean>) => {
if (!hasSibling || !parsedPattern(path, basename)) {
return null;
}
const siblingsPattern = siblingsPatternFn();
if (!siblingsPattern) {
return null; // pattern is malformed or we don't have siblings
}
return TPromise.is(siblingsPattern) ?
siblingsPattern.then(siblingsPatternToMatchingPattern) :
siblingsPatternToMatchingPattern(siblingsPattern);
const clausePattern = when.replace('$(basename)', name);
const matched = hasSibling(clausePattern);
return TPromise.is(matched) ?
matched.then(m => m ? pattern : null) :
matched ? pattern : null;
};
result.requiresSiblings = true;
return result;

View File

@@ -27,26 +27,12 @@ export class HistoryNavigator<T> implements INavigator<T> {
this._onChange();
}
public addIfNotPresent(t: T) {
if (!this._history.has(t)) {
this.add(t);
}
}
public next(): T {
if (this._navigator.next()) {
return this._navigator.current();
}
this.last();
return null;
return this._navigator.next();
}
public previous(): T {
if (this._navigator.previous()) {
return this._navigator.current();
}
this.first();
return null;
return this._navigator.previous();
}
public current(): T {
@@ -65,6 +51,10 @@ export class HistoryNavigator<T> implements INavigator<T> {
return this._navigator.last();
}
public has(t: T): boolean {
return this._history.has(t);
}
public clear(): void {
this._initialize([]);
this._onChange();
@@ -72,8 +62,7 @@ export class HistoryNavigator<T> implements INavigator<T> {
private _onChange() {
this._reduceToLimit();
this._navigator = new ArrayNavigator(this._elements);
this._navigator.last();
this._navigator = new ArrayNavigator(this._elements, 0, this._elements.length, this._elements.length);
}
private _reduceToLimit() {
@@ -95,4 +84,4 @@ export class HistoryNavigator<T> implements INavigator<T> {
this._history.forEach(e => elements.push(e));
return elements;
}
}
}

View File

@@ -5,8 +5,86 @@
'use strict';
export interface IIterator<E> {
next(): { readonly done: boolean, readonly value: E };
export interface IteratorResult<T> {
readonly done: boolean;
readonly value: T | undefined;
}
export interface Iterator<T> {
next(): IteratorResult<T>;
}
export module Iterator {
const _empty: Iterator<any> = {
next() {
return { done: true, value: undefined };
}
};
export function empty<T>(): Iterator<T> {
return _empty;
}
export function iterate<T>(array: T[], index = 0, length = array.length): Iterator<T> {
return {
next(): IteratorResult<T> {
if (index >= length) {
return { done: true, value: undefined };
}
return { done: false, value: array[index++] };
}
};
}
export function map<T, R>(iterator: Iterator<T>, fn: (t: T) => R): Iterator<R> {
return {
next() {
const { done, value } = iterator.next();
return { done, value: done ? undefined : fn(value) };
}
};
}
export function filter<T>(iterator: Iterator<T>, fn: (t: T) => boolean): Iterator<T> {
return {
next() {
while (true) {
const { done, value } = iterator.next();
if (done) {
return { done, value: undefined };
}
if (fn(value)) {
return { done, value };
}
}
}
};
}
export function forEach<T>(iterator: Iterator<T>, fn: (t: T) => void): void {
for (let next = iterator.next(); !next.done; next = iterator.next()) {
fn(next.value);
}
}
export function collect<T>(iterator: Iterator<T>): T[] {
const result: T[] = [];
forEach(iterator, value => result.push(value));
return result;
}
}
export type ISequence<T> = Iterator<T> | T[];
export function getSequenceIterator<T>(arg: Iterator<T> | T[]): Iterator<T> {
if (Array.isArray(arg)) {
return Iterator.iterate(arg);
} else {
return arg;
}
}
export interface INextIterator<T> {
@@ -20,11 +98,11 @@ export class ArrayIterator<T> implements INextIterator<T> {
protected end: number;
protected index: number;
constructor(items: T[], start: number = 0, end: number = items.length) {
constructor(items: T[], start: number = 0, end: number = items.length, index = start - 1) {
this.items = items;
this.start = start;
this.end = end;
this.index = start - 1;
this.index = index;
}
public first(): T {
@@ -48,8 +126,8 @@ export class ArrayIterator<T> implements INextIterator<T> {
export class ArrayNavigator<T> extends ArrayIterator<T> implements INavigator<T> {
constructor(items: T[], start: number = 0, end: number = items.length) {
super(items, start, end);
constructor(items: T[], start: number = 0, end: number = items.length, index = start - 1) {
super(items, start, end, index);
}
public current(): T {

View File

@@ -407,6 +407,7 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON
case CharacterCodes.doubleQuote:
case CharacterCodes.colon:
case CharacterCodes.comma:
case CharacterCodes.slash:
return false;
}
return true;
@@ -628,7 +629,7 @@ export type JSONPath = Segment[];
export interface ParseOptions {
disallowComments?: boolean;
allowTrailingComma?: boolean;
disallowTrailingComma?: boolean;
}
/**
@@ -817,7 +818,7 @@ export function visit(text: string, visitor: JSONVisitor, options?: ParseOptions
onError = toOneArgVisit(visitor.onError);
let disallowComments = options && options.disallowComments;
let allowTrailingComma = options && options.allowTrailingComma;
let disallowTrailingComma = options && options.disallowTrailingComma;
function scanNext(): SyntaxKind {
while (true) {
let token = _scanner.scan();
@@ -929,7 +930,7 @@ export function visit(text: string, visitor: JSONVisitor, options?: ParseOptions
}
onSeparator(',');
scanNext(); // consume comma
if (_scanner.getToken() === SyntaxKind.CloseBraceToken && allowTrailingComma) {
if (_scanner.getToken() === SyntaxKind.CloseBraceToken && !disallowTrailingComma) {
break;
}
} else if (needsComma) {
@@ -961,7 +962,7 @@ export function visit(text: string, visitor: JSONVisitor, options?: ParseOptions
}
onSeparator(',');
scanNext(); // consume comma
if (_scanner.getToken() === SyntaxKind.CloseBracketToken && allowTrailingComma) {
if (_scanner.getToken() === SyntaxKind.CloseBracketToken && !disallowTrailingComma) {
break;
}
} else if (needsComma) {

View File

@@ -59,6 +59,13 @@ export const UILabelProvider = new ModifierLabelProvider(
altKey: nls.localize({ key: 'altKey', comment: ['This is the short form for the Alt key on the keyboard'] }, "Alt"),
metaKey: nls.localize({ key: 'windowsKey', comment: ['This is the short form for the Windows key on the keyboard'] }, "Windows"),
separator: '+',
},
{
ctrlKey: nls.localize({ key: 'ctrlKey', comment: ['This is the short form for the Control key on the keyboard'] }, "Ctrl"),
shiftKey: nls.localize({ key: 'shiftKey', comment: ['This is the short form for the Shift key on the keyboard'] }, "Shift"),
altKey: nls.localize({ key: 'altKey', comment: ['This is the short form for the Alt key on the keyboard'] }, "Alt"),
metaKey: nls.localize({ key: 'superKey', comment: ['This is the short form for the Super key on the keyboard'] }, "Super"),
separator: '+',
}
);
@@ -79,6 +86,13 @@ export const AriaLabelProvider = new ModifierLabelProvider(
altKey: nls.localize({ key: 'altKey.long', comment: ['This is the long form for the Alt key on the keyboard'] }, "Alt"),
metaKey: nls.localize({ key: 'windowsKey.long', comment: ['This is the long form for the Windows key on the keyboard'] }, "Windows"),
separator: '+',
},
{
ctrlKey: nls.localize({ key: 'ctrlKey.long', comment: ['This is the long form for the Control key on the keyboard'] }, "Control"),
shiftKey: nls.localize({ key: 'shiftKey.long', comment: ['This is the long form for the Shift key on the keyboard'] }, "Shift"),
altKey: nls.localize({ key: 'altKey.long', comment: ['This is the long form for the Alt key on the keyboard'] }, "Alt"),
metaKey: nls.localize({ key: 'superKey.long', comment: ['This is the long form for the Super key on the keyboard'] }, "Super"),
separator: '+',
}
);

View File

@@ -5,15 +5,16 @@
'use strict';
import URI from 'vs/base/common/uri';
import { nativeSep, normalize, basename as pathsBasename, join, sep } from 'vs/base/common/paths';
import { endsWith, ltrim, equalsIgnoreCase, startsWithIgnoreCase, rtrim, startsWith } from 'vs/base/common/strings';
import { nativeSep, normalize, basename as pathsBasename, sep } from 'vs/base/common/paths';
import { endsWith, ltrim, startsWithIgnoreCase, rtrim, startsWith } from 'vs/base/common/strings';
import { Schemas } from 'vs/base/common/network';
import { isLinux, isWindows, isMacintosh } from 'vs/base/common/platform';
import { isEqual } from 'vs/base/common/resources';
export interface IWorkspaceFolderProvider {
getWorkspaceFolder(resource: URI): { uri: URI };
getWorkspaceFolder(resource: URI): { uri: URI, name?: string };
getWorkspace(): {
folders: { uri: URI }[];
folders: { uri: URI, name?: string }[];
};
}
@@ -21,7 +22,10 @@ export interface IUserHomeProvider {
userHome: string;
}
export function getPathLabel(resource: URI | string, rootProvider?: IWorkspaceFolderProvider, userHomeProvider?: IUserHomeProvider): string {
/**
* @deprecated use UriLabelService instead
*/
export function getPathLabel(resource: URI | string, userHomeProvider: IUserHomeProvider, rootProvider?: IWorkspaceFolderProvider): string {
if (!resource) {
return null;
}
@@ -30,31 +34,31 @@ export function getPathLabel(resource: URI | string, rootProvider?: IWorkspaceFo
resource = URI.file(resource);
}
// return early if the resource is neither file:// nor untitled://
if (resource.scheme !== Schemas.file && resource.scheme !== Schemas.untitled) {
return resource.with({ query: null, fragment: null }).toString(true);
}
// return early if we can resolve a relative path label from the root
const baseResource = rootProvider ? rootProvider.getWorkspaceFolder(resource) : null;
if (baseResource) {
const hasMultipleRoots = rootProvider.getWorkspace().folders.length > 1;
let pathLabel: string;
if (isLinux ? baseResource.uri.fsPath === resource.fsPath : equalsIgnoreCase(baseResource.uri.fsPath, resource.fsPath)) {
pathLabel = ''; // no label if pathes are identical
if (isEqual(baseResource.uri, resource, !isLinux)) {
pathLabel = ''; // no label if paths are identical
} else {
pathLabel = normalize(ltrim(resource.fsPath.substr(baseResource.uri.fsPath.length), nativeSep), true);
pathLabel = normalize(ltrim(resource.path.substr(baseResource.uri.path.length), sep), true);
}
if (hasMultipleRoots) {
const rootName = pathsBasename(baseResource.uri.fsPath);
pathLabel = pathLabel ? join(rootName, pathLabel) : rootName; // always show root basename if there are multiple
const rootName = (baseResource && baseResource.name) ? baseResource.name : pathsBasename(baseResource.uri.fsPath);
pathLabel = pathLabel ? (rootName + ' • ' + pathLabel) : rootName; // always show root basename if there are multiple
}
return pathLabel;
}
// return if the resource is neither file:// nor untitled:// and no baseResource was provided
if (resource.scheme !== Schemas.file && resource.scheme !== Schemas.untitled) {
return resource.with({ query: null, fragment: null }).toString(true);
}
// convert c:\something => C:\something
if (hasDriveLetter(resource.fsPath)) {
return normalize(normalizeDriveLetter(resource.fsPath), true);
@@ -78,7 +82,7 @@ export function getBaseLabel(resource: URI | string): string {
resource = URI.file(resource);
}
const base = pathsBasename(resource.fsPath) || resource.fsPath /* can be empty string if '/' is passed in */;
const base = pathsBasename(resource.path) || (resource.scheme === Schemas.file ? resource.fsPath : resource.path) /* can be empty string if '/' is passed in */;
// convert c: => C:
if (hasDriveLetter(base)) {

View File

@@ -7,10 +7,6 @@
import { once } from 'vs/base/common/functional';
export const empty: IDisposable = Object.freeze<IDisposable>({
dispose() { }
});
export interface IDisposable {
dispose(): void;
}
@@ -24,7 +20,6 @@ export function dispose<T extends IDisposable>(disposable: T): T;
export function dispose<T extends IDisposable>(...disposables: T[]): T[];
export function dispose<T extends IDisposable>(disposables: T[]): T[];
export function dispose<T extends IDisposable>(first: T | T[], ...rest: T[]): T | T[] {
if (Array.isArray(first)) {
first.forEach(d => d && d.dispose());
return [];
@@ -45,23 +40,16 @@ export function combinedDisposable(disposables: IDisposable[]): IDisposable {
return { dispose: () => dispose(disposables) };
}
export function toDisposable(...fns: (() => void)[]): IDisposable {
return {
dispose() {
for (const fn of fns) {
fn();
}
}
};
export function toDisposable(fn: () => void): IDisposable {
return { dispose() { fn(); } };
}
export abstract class Disposable implements IDisposable {
private _toDispose: IDisposable[];
static None = Object.freeze<IDisposable>({ dispose() { } });
constructor() {
this._toDispose = [];
}
protected _toDispose: IDisposable[] = [];
protected get toDispose(): IDisposable[] { return this._toDispose; }
public dispose(): void {
this._toDispose = dispose(this._toDispose);
@@ -69,6 +57,7 @@ export abstract class Disposable implements IDisposable {
protected _register<T extends IDisposable>(t: T): T {
this._toDispose.push(t);
return t;
}
}

View File

@@ -5,7 +5,7 @@
'use strict';
import { IIterator } from 'vs/base/common/iterator';
import { Iterator } from 'vs/base/common/iterator';
class Node<E> {
element: E;
@@ -94,7 +94,7 @@ export class LinkedList<E> {
};
}
iterator(): IIterator<E> {
iterator(): Iterator<E> {
let element = {
done: undefined,
value: undefined,

View File

@@ -6,6 +6,8 @@
'use strict';
import URI from 'vs/base/common/uri';
import { CharCode } from 'vs/base/common/charCode';
import { Iterator } from './iterator';
export function values<V = any>(set: Set<V>): V[];
export function values<K = any, V = any>(map: Map<K, V>): V[];
@@ -35,7 +37,6 @@ export function getOrSet<K, V>(map: Map<K, V>, key: K, value: V): V {
export interface IKeyIterator {
reset(key: string): this;
next(): this;
join(parts: string[]): string;
hasNext(): boolean;
cmp(a: string): number;
@@ -58,10 +59,6 @@ export class StringIterator implements IKeyIterator {
return this;
}
join(parts: string[]): string {
return parts.join('');
}
hasNext(): boolean {
return this._pos < this._value.length - 1;
}
@@ -79,9 +76,6 @@ export class StringIterator implements IKeyIterator {
export class PathIterator implements IKeyIterator {
private static readonly _fwd = '/'.charCodeAt(0);
private static readonly _bwd = '\\'.charCodeAt(0);
private _value: string;
private _from: number;
private _to: number;
@@ -97,17 +91,13 @@ export class PathIterator implements IKeyIterator {
return this._to < this._value.length;
}
join(parts: string[]): string {
return parts.join('/');
}
next(): this {
// this._data = key.split(/[\\/]/).filter(s => !!s);
this._from = this._to;
let justSeps = true;
for (; this._to < this._value.length; this._to++) {
const ch = this._value.charCodeAt(this._to);
if (ch === PathIterator._fwd || ch === PathIterator._bwd) {
if (ch === CharCode.Slash || ch === CharCode.Backslash) {
if (justSeps) {
this._from++;
} else {
@@ -150,14 +140,15 @@ export class PathIterator implements IKeyIterator {
}
class TernarySearchTreeNode<E> {
str: string;
element: E;
segment: string;
value: E;
key: string;
left: TernarySearchTreeNode<E>;
mid: TernarySearchTreeNode<E>;
right: TernarySearchTreeNode<E>;
isEmpty(): boolean {
return !this.left && !this.mid && !this.right && !this.element;
return !this.left && !this.mid && !this.right && !this.value;
}
}
@@ -188,17 +179,17 @@ export class TernarySearchTree<E> {
if (!this._root) {
this._root = new TernarySearchTreeNode<E>();
this._root.str = iter.value();
this._root.segment = iter.value();
}
node = this._root;
while (true) {
let val = iter.cmp(node.str);
let val = iter.cmp(node.segment);
if (val > 0) {
// left
if (!node.left) {
node.left = new TernarySearchTreeNode<E>();
node.left.str = iter.value();
node.left.segment = iter.value();
}
node = node.left;
@@ -206,7 +197,7 @@ export class TernarySearchTree<E> {
// right
if (!node.right) {
node.right = new TernarySearchTreeNode<E>();
node.right.str = iter.value();
node.right.segment = iter.value();
}
node = node.right;
@@ -215,15 +206,16 @@ export class TernarySearchTree<E> {
iter.next();
if (!node.mid) {
node.mid = new TernarySearchTreeNode<E>();
node.mid.str = iter.value();
node.mid.segment = iter.value();
}
node = node.mid;
} else {
break;
}
}
const oldElement = node.element;
node.element = element;
const oldElement = node.value;
node.value = element;
node.key = key;
return oldElement;
}
@@ -231,7 +223,7 @@ export class TernarySearchTree<E> {
let iter = this._iter.reset(key);
let node = this._root;
while (node) {
let val = iter.cmp(node.str);
let val = iter.cmp(node.segment);
if (val > 0) {
// left
node = node.left;
@@ -246,7 +238,7 @@ export class TernarySearchTree<E> {
break;
}
}
return node ? node.element : undefined;
return node ? node.value : undefined;
}
delete(key: string): void {
@@ -257,7 +249,7 @@ export class TernarySearchTree<E> {
// find and unset node
while (node) {
let val = iter.cmp(node.str);
let val = iter.cmp(node.segment);
if (val > 0) {
// left
stack.push([1, node]);
@@ -273,7 +265,7 @@ export class TernarySearchTree<E> {
node = node.mid;
} else {
// remove element
node.element = undefined;
node.value = undefined;
// clean up empty nodes
while (stack.length > 0 && node.isEmpty()) {
@@ -295,7 +287,7 @@ export class TernarySearchTree<E> {
let node = this._root;
let candidate: E;
while (node) {
let val = iter.cmp(node.str);
let val = iter.cmp(node.segment);
if (val > 0) {
// left
node = node.left;
@@ -305,20 +297,20 @@ export class TernarySearchTree<E> {
} else if (iter.hasNext()) {
// mid
iter.next();
candidate = node.element || candidate;
candidate = node.value || candidate;
node = node.mid;
} else {
break;
}
}
return node && node.element || candidate;
return node && node.value || candidate;
}
findSuperstr(key: string): TernarySearchTree<E> {
findSuperstr(key: string): Iterator<E> {
let iter = this._iter.reset(key);
let node = this._root;
while (node) {
let val = iter.cmp(node.str);
let val = iter.cmp(node.segment);
if (val > 0) {
// left
node = node.left;
@@ -333,35 +325,59 @@ export class TernarySearchTree<E> {
// collect
if (!node.mid) {
return undefined;
} else {
return this._nodeIterator(node.mid);
}
let ret = new TernarySearchTree<E>(this._iter);
ret._root = node.mid;
return ret;
}
}
return undefined;
}
forEach(callback: (value: E, index: string) => any) {
this._forEach(this._root, [], callback);
private _nodeIterator(node: TernarySearchTreeNode<E>): Iterator<E> {
let res = {
done: false,
value: undefined
};
let idx: number;
let data: E[];
let next = () => {
if (!data) {
// lazy till first invocation
data = [];
idx = 0;
this._forEach(node, value => data.push(value));
}
if (idx >= data.length) {
res.done = true;
res.value = undefined;
} else {
res.done = false;
res.value = data[idx++];
}
return res;
};
return { next };
}
private _forEach(node: TernarySearchTreeNode<E>, parts: string[], callback: (value: E, index: string) => any) {
forEach(callback: (value: E, index: string) => any) {
this._forEach(this._root, callback);
}
private _forEach(node: TernarySearchTreeNode<E>, callback: (value: E, index: string) => any) {
if (node) {
// left
this._forEach(node.left, parts, callback);
this._forEach(node.left, callback);
// node
parts.push(node.str);
if (node.element) {
callback(node.element, this._iter.join(parts));
if (node.value) {
// callback(node.value, this._iter.join(parts));
callback(node.value, node.key);
}
// mid
this._forEach(node.mid, parts, callback);
parts.pop();
this._forEach(node.mid, callback);
// right
this._forEach(node.right, parts, callback);
this._forEach(node.right, callback);
}
}
}
@@ -420,6 +436,14 @@ export class ResourceMap<T> {
public keys(): URI[] {
return keys(this.map).map(URI.parse);
}
public clone(): ResourceMap<T> {
const resourceMap = new ResourceMap<T>();
this.map.forEach((value, key) => resourceMap.map.set(key, value));
return resourceMap;
}
}
// We should fold BoundedMap and LinkedMap. See https://github.com/Microsoft/vscode/issues/28496

View File

@@ -1,12 +1,12 @@
/**
* marked - a markdown parser
* Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
* Copyright (c) 2011-2014, Christopher Jeffrey. (Source EULAd)
* https://github.com/markedjs/marked
*/
var __marked_exports;
;(function(root) {
; (function (root) {
'use strict';
/**
@@ -18,20 +18,29 @@ var block = {
code: /^( {4}[^\n]+\n*)+/,
fences: noop,
hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,
nptable: noop,
blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
html: '^ {0,3}(?:' // optional indentation
+ '<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
+ '|comment[^\\n]*(\\n+|$)' // (2)
+ '|<\\?[\\s\\S]*?\\?>\\n*' // (3)
+ '|<![A-Z][\\s\\S]*?>\\n*' // (4)
+ '|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>\\n*' // (5)
+ '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)' // (6)
+ '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag
+ '|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag
+ ')',
def: /^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,
table: noop,
lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
paragraph: /^([^\n]+(?:\n?(?!hr|heading|lheading| {0,3}>|tag)[^\n]+)+)/,
paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading| {0,3}>|<\/?(?:tag)(?: +|\n|\/?>)|<(?:script|pre|style|!--))[^\n]+)*)/,
text: /^[^\n]+/
};
block._label = /(?:\\[\[\]]|[^\[\]])+/;
block._title = /(?:"(?:\\"|[^"]|"[^"\n]*")*"|'\n?(?:[^'\n]+\n?)*'|\([^()]*\))/;
block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/;
block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
block.def = edit(block.def)
.replace('label', block._label)
.replace('title', block._title)
@@ -49,23 +58,24 @@ block.list = edit(block.list)
.replace('def', '\\n+(?=' + block.def.source + ')')
.getRegex();
block._tag = '(?!(?:'
+ 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
+ '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
+ '|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b';
block.html = edit(block.html)
.replace('comment', /<!--[\s\S]*?-->/)
.replace('closed', /<(tag)[\s\S]+?<\/\1>/)
.replace('closing', /<tag(?:"[^"]*"|'[^']*'|\s[^'"\/>\s]*)*?\/?>/)
.replace(/tag/g, block._tag)
block._tag = 'address|article|aside|base|basefont|blockquote|body|caption'
+ '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption'
+ '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe'
+ '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'
+ '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr'
+ '|track|ul';
block._comment = /<!--(?!-?>)[\s\S]*?-->/;
block.html = edit(block.html, 'i')
.replace('comment', block._comment)
.replace('tag', block._tag)
.replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/)
.getRegex();
block.paragraph = edit(block.paragraph)
.replace('hr', block.hr)
.replace('heading', block.heading)
.replace('lheading', block.lheading)
.replace('tag', '<' + block._tag)
.replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
.getRegex();
block.blockquote = edit(block.blockquote)
@@ -99,8 +109,26 @@ block.gfm.paragraph = edit(block.paragraph)
*/
block.tables = merge({}, block.gfm, {
nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
nptable: /^ *([^|\n ].*\|.*)\n *([-:]+ *\|[-| :]*)(?:\n((?:.*[^>\n ].*(?:\n|$))*)\n*|$)/,
table: /^ *\|(.+)\n *\|?( *[-:]+[-| :]*)(?:\n((?: *[^>\n ].*(?:\n|$))*)\n*|$)/
});
/**
* Pedantic grammar
*/
block.pedantic = merge({}, block.normal, {
html: edit(
'^ *(?:comment *(?:\\n|\\s*$)'
+ '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
+ '|<tag(?:"[^"]*"|\'[^\']*\'|\\s[^\'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))')
.replace('comment', block._comment)
.replace(/tag/g, '(?!(?:'
+ 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub'
+ '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)'
+ '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b')
.getRegex(),
def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/
});
/**
@@ -113,7 +141,9 @@ function Lexer(options) {
this.options = options || marked.defaults;
this.rules = block.normal;
if (this.options.gfm) {
if (this.options.pedantic) {
this.rules = block.pedantic;
} else if (this.options.gfm) {
if (this.options.tables) {
this.rules = block.tables;
} else {
@@ -167,7 +197,9 @@ Lexer.prototype.token = function(src, top) {
i,
tag,
l,
isordered;
isordered,
istask,
ischecked;
while (src) {
// newline
@@ -187,7 +219,7 @@ Lexer.prototype.token = function(src, top) {
this.tokens.push({
type: 'code',
text: !this.options.pedantic
? cap.replace(/\n+$/, '')
? rtrim(cap, '\n')
: cap
});
continue;
@@ -217,34 +249,36 @@ Lexer.prototype.token = function(src, top) {
// table no leading pipe (gfm)
if (top && (cap = this.rules.nptable.exec(src))) {
src = src.substring(cap[0].length);
item = {
type: 'table',
header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
cells: cap[3].replace(/\n$/, '').split('\n')
cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
};
for (i = 0; i < item.align.length; i++) {
if (/^ *-+: *$/.test(item.align[i])) {
item.align[i] = 'right';
} else if (/^ *:-+: *$/.test(item.align[i])) {
item.align[i] = 'center';
} else if (/^ *:-+ *$/.test(item.align[i])) {
item.align[i] = 'left';
} else {
item.align[i] = null;
if (item.header.length === item.align.length) {
src = src.substring(cap[0].length);
for (i = 0; i < item.align.length; i++) {
if (/^ *-+: *$/.test(item.align[i])) {
item.align[i] = 'right';
} else if (/^ *:-+: *$/.test(item.align[i])) {
item.align[i] = 'center';
} else if (/^ *:-+ *$/.test(item.align[i])) {
item.align[i] = 'left';
} else {
item.align[i] = null;
}
}
for (i = 0; i < item.cells.length; i++) {
item.cells[i] = splitCells(item.cells[i], item.header.length);
}
this.tokens.push(item);
continue;
}
for (i = 0; i < item.cells.length; i++) {
item.cells[i] = item.cells[i].split(/ *\| */);
}
this.tokens.push(item);
continue;
}
// hr
@@ -333,10 +367,20 @@ Lexer.prototype.token = function(src, top) {
if (!loose) loose = next;
}
// Check for task list items
istask = /^\[[ xX]\] /.test(item);
ischecked = undefined;
if (istask) {
ischecked = item[1] !== ' ';
item = item.replace(/^\[[ xX]\] +/, '');
}
this.tokens.push({
type: loose
? 'loose_item_start'
: 'list_item_start'
: 'list_item_start',
task: istask,
checked: ischecked
});
// Recurse.
@@ -372,7 +416,7 @@ Lexer.prototype.token = function(src, top) {
if (top && (cap = this.rules.def.exec(src))) {
src = src.substring(cap[0].length);
if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1);
tag = cap[1].toLowerCase();
tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
if (!this.tokens.links[tag]) {
this.tokens.links[tag] = {
href: cap[2],
@@ -384,36 +428,38 @@ Lexer.prototype.token = function(src, top) {
// table (gfm)
if (top && (cap = this.rules.table.exec(src))) {
src = src.substring(cap[0].length);
item = {
type: 'table',
header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
cells: cap[3] ? cap[3].replace(/(?: *\| *)?\n$/, '').split('\n') : []
};
for (i = 0; i < item.align.length; i++) {
if (/^ *-+: *$/.test(item.align[i])) {
item.align[i] = 'right';
} else if (/^ *:-+: *$/.test(item.align[i])) {
item.align[i] = 'center';
} else if (/^ *:-+ *$/.test(item.align[i])) {
item.align[i] = 'left';
} else {
item.align[i] = null;
if (item.header.length === item.align.length) {
src = src.substring(cap[0].length);
for (i = 0; i < item.align.length; i++) {
if (/^ *-+: *$/.test(item.align[i])) {
item.align[i] = 'right';
} else if (/^ *:-+: *$/.test(item.align[i])) {
item.align[i] = 'center';
} else if (/^ *:-+ *$/.test(item.align[i])) {
item.align[i] = 'left';
} else {
item.align[i] = null;
}
}
for (i = 0; i < item.cells.length; i++) {
item.cells[i] = splitCells(
item.cells[i].replace(/^ *\| *| *\| *$/g, ''),
item.header.length);
}
this.tokens.push(item);
continue;
}
for (i = 0; i < item.cells.length; i++) {
item.cells[i] = item.cells[i]
.replace(/^ *\| *| *\| *$/g, '')
.split(/ *\| */);
}
this.tokens.push(item);
continue;
}
// lheading
@@ -463,39 +509,54 @@ Lexer.prototype.token = function(src, top) {
*/
var inline = {
escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
url: noop,
tag: /^<!--[\s\S]*?-->|^<\/?[a-zA-Z0-9\-]+(?:"[^"]*"|'[^']*'|\s[^<'">\/\s]*)*?\/?>/,
link: /^!?\[(inside)\]\(href\)/,
reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
nolink: /^!?\[((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\]/,
strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
em: /^_([^\s_](?:[^_]|__)+?[^\s_])_\b|^\*((?:\*\*|[^*])+?)\*(?!\*)/,
tag: '^comment'
+ '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
+ '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
+ '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
+ '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
+ '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>', // CDATA section
link: /^!?\[(label)\]\(href(?:\s+(title))?\s*\)/,
reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
strong: /^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)|^__([^\s])__(?!_)|^\*\*([^\s])\*\*(?!\*)/,
em: /^_([^\s][\s\S]*?[^\s_])_(?!_)|^_([^\s_][\s\S]*?[^\s])_(?!_)|^\*([^\s][\s\S]*?[^\s*])\*(?!\*)|^\*([^\s*][\s\S]*?[^\s])\*(?!\*)|^_([^\s_])_(?!_)|^\*([^\s*])\*(?!\*)/,
code: /^(`+)\s*([\s\S]*?[^`]?)\s*\1(?!`)/,
br: /^ {2,}\n(?!\s*$)/,
del: noop,
text: /^[\s\S]+?(?=[\\<!\[`*]|\b_| {2,}\n|$)/
};
inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
inline._email = /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/;
inline.autolink = edit(inline.autolink)
.replace('scheme', inline._scheme)
.replace('email', inline._email)
.getRegex()
.getRegex();
inline._inside = /(?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]]|\](?=[^\[]*\]))*/;
inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
inline.tag = edit(inline.tag)
.replace('comment', block._comment)
.replace('attribute', inline._attribute)
.getRegex();
inline._label = /(?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?/;
inline._href = /\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f()\\]*\)|[^\s\x00-\x1f()\\])*?)/;
inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
inline.link = edit(inline.link)
.replace('inside', inline._inside)
.replace('label', inline._label)
.replace('href', inline._href)
.replace('title', inline._title)
.getRegex();
inline.reflink = edit(inline.reflink)
.replace('inside', inline._inside)
.replace('label', inline._label)
.getRegex();
/**
@@ -510,7 +571,13 @@ inline.normal = merge({}, inline);
inline.pedantic = merge({}, inline.normal, {
strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,
link: edit(/^!?\[(label)\]\((.*?)\)/)
.replace('label', inline._label)
.getRegex(),
reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/)
.replace('label', inline._label)
.getRegex()
});
/**
@@ -554,14 +621,14 @@ function InlineLexer(links, options) {
throw new Error('Tokens array requires a `links` property.');
}
if (this.options.gfm) {
if (this.options.pedantic) {
this.rules = inline.pedantic;
} else if (this.options.gfm) {
if (this.options.breaks) {
this.rules = inline.breaks;
} else {
this.rules = inline.gfm;
}
} else if (this.options.pedantic) {
this.rules = inline.pedantic;
}
}
@@ -589,6 +656,7 @@ InlineLexer.prototype.output = function(src) {
link,
text,
href,
title,
cap;
while (src) {
@@ -652,9 +720,23 @@ InlineLexer.prototype.output = function(src) {
if (cap = this.rules.link.exec(src)) {
src = src.substring(cap[0].length);
this.inLink = true;
href = cap[2];
if (this.options.pedantic) {
link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
if (link) {
href = link[1];
title = link[3];
} else {
title = '';
}
} else {
title = cap[3] ? cap[3].slice(1, -1) : '';
}
href = href.trim().replace(/^<([\s\S]*)>$/, '$1');
out += this.outputLink(cap, {
href: cap[2],
title: cap[3]
href: InlineLexer.escapes(href),
title: InlineLexer.escapes(title)
});
this.inLink = false;
continue;
@@ -680,14 +762,14 @@ InlineLexer.prototype.output = function(src) {
// strong
if (cap = this.rules.strong.exec(src)) {
src = src.substring(cap[0].length);
out += this.renderer.strong(this.output(cap[2] || cap[1]));
out += this.renderer.strong(this.output(cap[4] || cap[3] || cap[2] || cap[1]));
continue;
}
// em
if (cap = this.rules.em.exec(src)) {
src = src.substring(cap[0].length);
out += this.renderer.em(this.output(cap[2] || cap[1]));
out += this.renderer.em(this.output(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1]));
continue;
}
@@ -727,12 +809,16 @@ InlineLexer.prototype.output = function(src) {
return out;
};
InlineLexer.escapes = function(text) {
return text ? text.replace(InlineLexer.rules._escapes, '$1') : text;
}
/**
* Compile Link
*/
InlineLexer.prototype.outputLink = function(cap, link) {
var href = escape(link.href),
var href = link.href,
title = link.title ? escape(link.title) : null;
return cap[0].charAt(0) !== '!'
@@ -790,7 +876,7 @@ InlineLexer.prototype.mangle = function(text) {
*/
function Renderer(options) {
this.options = options || {};
this.options = options || marked.defaults;
}
Renderer.prototype.code = function(code, lang, escaped) {
@@ -805,7 +891,7 @@ Renderer.prototype.code = function(code, lang, escaped) {
if (!lang) {
return '<pre><code>'
+ (escaped ? code : escape(code, true))
+ '\n</code></pre>';
+ '</code></pre>';
}
return '<pre><code class="'
@@ -813,7 +899,7 @@ Renderer.prototype.code = function(code, lang, escaped) {
+ escape(lang, true)
+ '">'
+ (escaped ? code : escape(code, true))
+ '\n</code></pre>\n';
+ '</code></pre>\n';
};
Renderer.prototype.blockquote = function(quote) {
@@ -825,16 +911,20 @@ Renderer.prototype.html = function(html) {
};
Renderer.prototype.heading = function(text, level, raw) {
return '<h'
+ level
+ ' id="'
+ this.options.headerPrefix
+ raw.toLowerCase().replace(/[^\w]+/g, '-')
+ '">'
+ text
+ '</h'
+ level
+ '>\n';
if (this.options.headerIds) {
return '<h'
+ level
+ ' id="'
+ this.options.headerPrefix
+ raw.toLowerCase().replace(/[^\w]+/g, '-')
+ '">'
+ text
+ '</h'
+ level
+ '>\n';
}
// ignore IDs
return '<h' + level + '>' + text + '</h' + level + '>\n';
};
Renderer.prototype.hr = function() {
@@ -851,18 +941,26 @@ Renderer.prototype.listitem = function(text) {
return '<li>' + text + '</li>\n';
};
Renderer.prototype.checkbox = function(checked) {
return '<input '
+ (checked ? 'checked="" ' : '')
+ 'disabled="" type="checkbox"'
+ (this.options.xhtml ? ' /' : '')
+ '> ';
}
Renderer.prototype.paragraph = function(text) {
return '<p>' + text + '</p>\n';
};
Renderer.prototype.table = function(header, body) {
if (body) body = '<tbody>' + body + '</tbody>';
return '<table>\n'
+ '<thead>\n'
+ header
+ '</thead>\n'
+ '<tbody>\n'
+ body
+ '</tbody>\n'
+ '</table>\n';
};
@@ -873,7 +971,7 @@ Renderer.prototype.tablerow = function(content) {
Renderer.prototype.tablecell = function(content, flags) {
var type = flags.header ? 'th' : 'td';
var tag = flags.align
? '<' + type + ' style="text-align:' + flags.align + '">'
? '<' + type + ' align="' + flags.align + '">'
: '<' + type + '>';
return tag + content + '</' + type + '>\n';
};
@@ -915,7 +1013,12 @@ Renderer.prototype.link = function(href, title, text) {
if (this.options.baseUrl && !originIndependentUrl.test(href)) {
href = resolveUrl(this.options.baseUrl, href);
}
var out = '<a href="' + href + '"';
try {
href = encodeURI(href).replace(/%25/g, '%');
} catch (e) {
return text;
}
var out = '<a href="' + escape(href) + '"';
if (title) {
out += ' title="' + title + '"';
}
@@ -1117,6 +1220,10 @@ Parser.prototype.tok = function() {
case 'list_item_start': {
body = '';
if (this.token.task) {
body += this.renderer.checkbox(this.token.checked);
}
while (this.next().type !== 'list_item_end') {
body += this.token.type === 'text'
? this.parseText()
@@ -1135,10 +1242,8 @@ Parser.prototype.tok = function() {
return this.renderer.listitem(body);
}
case 'html': {
var html = !this.token.pre && !this.options.pedantic
? this.inline.output(this.token.text)
: this.token.text;
return this.renderer.html(html);
// TODO parse inline content if parameter markdown=1
return this.renderer.html(this.token.text);
}
case 'paragraph': {
return this.renderer.paragraph(this.inline.output(this.token.text));
@@ -1177,7 +1282,7 @@ function unescape(html) {
}
function edit(regex, opt) {
regex = regex.source;
regex = regex.source || regex;
opt = opt || '';
return {
replace: function(name, val) {
@@ -1200,7 +1305,7 @@ function resolveUrl(base, href) {
if (/^[^:]+:\/*[^/]*$/.test(base)) {
baseUrls[' ' + base] = base + '/';
} else {
baseUrls[' ' + base] = base.replace(/[^/]*$/, '');
baseUrls[' ' + base] = rtrim(base, '/', true);
}
}
base = baseUrls[' ' + base];
@@ -1236,6 +1341,64 @@ function merge(obj) {
return obj;
}
function splitCells(tableRow, count) {
// ensure that every cell-delimiting pipe has a space
// before it to distinguish it from an escaped pipe
var row = tableRow.replace(/\|/g, function (match, offset, str) {
var escaped = false,
curr = offset;
while (--curr >= 0 && str[curr] === '\\') escaped = !escaped;
if (escaped) {
// odd number of slashes means | is escaped
// so we leave it alone
return '|';
} else {
// add space before unescaped |
return ' |';
}
}),
cells = row.split(/ \|/),
i = 0;
if (cells.length > count) {
cells.splice(count);
} else {
while (cells.length < count) cells.push('');
}
for (; i < cells.length; i++) {
// leading or trailing whitespace is ignored per the gfm spec
cells[i] = cells[i].trim().replace(/\\\|/g, '|');
}
return cells;
}
// Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
// /c*$/ is vulnerable to REDOS.
// invert: Remove suffix of non-c chars instead. Default falsey.
function rtrim(str, c, invert) {
if (str.length === 0) {
return '';
}
// Length of suffix matching the invert condition.
var suffLen = 0;
// Step left until we fail to match the invert condition.
while (suffLen < str.length) {
var currChar = str.charAt(str.length - suffLen - 1);
if (currChar === c && !invert) {
suffLen++;
} else if (currChar !== c && invert) {
suffLen++;
} else {
break;
}
}
return str.substr(0, str.length - suffLen);
}
/**
* Marked
*/
@@ -1343,24 +1506,29 @@ marked.setOptions = function(opt) {
return marked;
};
marked.defaults = {
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: false,
sanitizer: null,
mangle: true,
smartLists: false,
silent: false,
highlight: null,
langPrefix: 'lang-',
smartypants: false,
headerPrefix: '',
renderer: new Renderer(),
xhtml: false,
baseUrl: null
};
marked.getDefaults = function () {
return {
baseUrl: null,
breaks: false,
gfm: true,
headerIds: true,
headerPrefix: '',
highlight: null,
langPrefix: 'language-',
mangle: true,
pedantic: false,
renderer: new Renderer(),
sanitize: false,
sanitizer: null,
silent: false,
smartLists: false,
smartypants: false,
tables: true,
xhtml: false
};
}
marked.defaults = marked.getDefaults();
/**
* Expose
@@ -1379,16 +1547,15 @@ marked.InlineLexer = InlineLexer;
marked.inlineLexer = InlineLexer.output;
marked.parse = marked;
__marked_exports = marked;
}).call(this);
// ESM-comment-begin
define([], function() {
return {
marked: __marked_exports
};
return {
marked: __marked_exports
};
});
// ESM-comment-end

View File

@@ -238,4 +238,63 @@ export function suggestFilename(langId: string, prefix: string): string {
}
return prefix; // without any known extension, just return the prefix
}
interface MapExtToMediaMimes {
[index: string]: string;
}
// Known media mimes that we can handle
const mapExtToMediaMimes: MapExtToMediaMimes = {
'.bmp': 'image/bmp',
'.gif': 'image/gif',
'.jpg': 'image/jpg',
'.jpeg': 'image/jpg',
'.jpe': 'image/jpg',
'.png': 'image/png',
'.tiff': 'image/tiff',
'.tif': 'image/tiff',
'.ico': 'image/x-icon',
'.tga': 'image/x-tga',
'.psd': 'image/vnd.adobe.photoshop',
'.webp': 'image/webp',
'.mid': 'audio/midi',
'.midi': 'audio/midi',
'.mp4a': 'audio/mp4',
'.mpga': 'audio/mpeg',
'.mp2': 'audio/mpeg',
'.mp2a': 'audio/mpeg',
'.mp3': 'audio/mpeg',
'.m2a': 'audio/mpeg',
'.m3a': 'audio/mpeg',
'.oga': 'audio/ogg',
'.ogg': 'audio/ogg',
'.spx': 'audio/ogg',
'.aac': 'audio/x-aac',
'.wav': 'audio/x-wav',
'.wma': 'audio/x-ms-wma',
'.mp4': 'video/mp4',
'.mp4v': 'video/mp4',
'.mpg4': 'video/mp4',
'.mpeg': 'video/mpeg',
'.mpg': 'video/mpeg',
'.mpe': 'video/mpeg',
'.m1v': 'video/mpeg',
'.m2v': 'video/mpeg',
'.ogv': 'video/ogg',
'.qt': 'video/quicktime',
'.mov': 'video/quicktime',
'.webm': 'video/webm',
'.mkv': 'video/x-matroska',
'.mk3d': 'video/x-matroska',
'.mks': 'video/x-matroska',
'.wmv': 'video/x-ms-wmv',
'.flv': 'video/x-flv',
'.avi': 'video/x-msvideo',
'.movie': 'video/x-sgi-movie'
};
export function getMediaMime(path: string): string | undefined {
const ext = paths.extname(path);
return mapExtToMediaMimes[ext.toLowerCase()];
}

View File

@@ -0,0 +1,49 @@
/*---------------------------------------------------------------------------------------------
* 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 { LRUCache } from 'vs/base/common/map';
/**
* The normalize() method returns the Unicode Normalization Form of a given string. The form will be
* the Normalization Form Canonical Composition.
*
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize}
*/
export const canNormalize = typeof ((<any>'').normalize) === 'function';
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 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: LRUCache<string, string>): string {
if (!canNormalize || !str) {
return str;
}
const cached = normalizedCache.get(str);
if (cached) {
return cached;
}
let res: string;
if (nonAsciiCharactersPattern.test(str)) {
res = (<any>str).normalize(form);
} else {
res = str;
}
// Use the cache for fast lookup
normalizedCache.set(str, res);
return res;
}

View File

@@ -16,7 +16,7 @@ export function deepClone<T>(obj: T): T {
return obj as any;
}
const result: any = Array.isArray(obj) ? [] : {};
Object.keys(obj).forEach((key: keyof T) => {
Object.keys(obj).forEach((key: string) => {
if (obj[key] && typeof obj[key] === 'object') {
result[key] = deepClone(obj[key]);
} else {
@@ -225,6 +225,7 @@ export function getOrDefault<T, R>(obj: T, fn: (obj: T) => R, defaultValue: R =
return typeof result === 'undefined' ? defaultValue : result;
}
type obj = { [key: string]: any; };
/**
* Returns an object that has keys for each value that is different in the base object. Keys
* that do not exist in the target but in the base object are not considered.
@@ -235,7 +236,6 @@ export function getOrDefault<T, R>(obj: T, fn: (obj: T) => R, defaultValue: R =
* @param base the object to diff against
* @param obj the object to use for diffing
*/
export type obj = { [key: string]: any; };
export function distinct(base: obj, target: obj): obj {
const result = Object.create(null);

View File

@@ -81,7 +81,7 @@ export abstract class Parser {
}
protected static merge<T>(destination: T, source: T, overwrite: boolean): void {
Object.keys(source).forEach((key: keyof T) => {
Object.keys(source).forEach((key: string) => {
let destValue = destination[key];
let sourceValue = source[key];
if (Types.isUndefined(sourceValue)) {

View File

@@ -53,7 +53,7 @@ export function basename(path: string): string {
}
/**
* @returns {{.far}} from boo.far or the empty string.
* @returns `.far` from `boo.far` or the empty string.
*/
export function extname(path: string): string {
path = basename(path);
@@ -328,7 +328,7 @@ export function isEqual(pathA: string, pathB: string, ignoreCase?: boolean): boo
return equalsIgnoreCase(pathA, pathB);
}
export function isEqualOrParent(path: string, candidate: string, ignoreCase?: boolean): boolean {
export function isEqualOrParent(path: string, candidate: string, ignoreCase?: boolean, separator = nativeSep): boolean {
if (path === candidate) {
return true;
}
@@ -352,15 +352,15 @@ export function isEqualOrParent(path: string, candidate: string, ignoreCase?: bo
}
let sepOffset = candidate.length;
if (candidate.charAt(candidate.length - 1) === nativeSep) {
if (candidate.charAt(candidate.length - 1) === separator) {
sepOffset--; // adjust the expected sep offset in case our candidate already ends in separator character
}
return path.charAt(sepOffset) === nativeSep;
return path.charAt(sepOffset) === separator;
}
if (candidate.charAt(candidate.length - 1) !== nativeSep) {
candidate += nativeSep;
if (candidate.charAt(candidate.length - 1) !== separator) {
candidate += separator;
}
return path.indexOf(candidate) === 0;

View File

@@ -14,11 +14,6 @@ export function mark(name: string): void;
export function measure(name: string, from?: string, to?: string): PerformanceEntry;
/**
* Time something, shorthant for `mark` and `measure`
*/
export function time(name: string): { stop(): void };
/**
* All entries filtered by type and sorted by `startTime`.
*/

View File

@@ -42,31 +42,33 @@ define([], function () {
function getEntries(type, name) {
const result = [];
const entries = global._performanceEntries;
for (let i = 0; i < entries.length; i += 4) {
for (let i = 0; i < entries.length; i += 5) {
if (entries[i] === type && (name === void 0 || entries[i + 1] === name)) {
result.push({
type: entries[i],
name: entries[i + 1],
startTime: entries[i + 2],
duration: entries[i + 3],
seq: entries[i + 4],
});
}
}
return result.sort((a, b) => {
return a.startTime - b.startTime;
return a.startTime - b.startTime || a.seq - b.seq;
});
}
function getEntry(type, name) {
const entries = global._performanceEntries;
for (let i = 0; i < entries.length; i += 4) {
for (let i = 0; i < entries.length; i += 5) {
if (entries[i] === type && entries[i + 1] === name) {
return {
type: entries[i],
name: entries[i + 1],
startTime: entries[i + 2],
duration: entries[i + 3],
seq: entries[i + 4],
};
}
}
@@ -76,7 +78,7 @@ define([], function () {
const entries = global._performanceEntries;
let name = from;
let startTime = 0;
for (let i = 0; i < entries.length; i += 4) {
for (let i = 0; i < entries.length; i += 5) {
if (entries[i + 1] === name) {
if (name === from) {
// found `from` (start of interval)
@@ -91,19 +93,15 @@ define([], function () {
return 0;
}
let seq = 0;
function mark(name) {
global._performanceEntries.push('mark', name, _now(), 0);
global._performanceEntries.push('mark', name, _now(), 0, seq++);
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;
@@ -127,9 +125,9 @@ define([], function () {
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];
for (let i = entries.length - 1; i >= 0; i -= 5) {
if (entries[i - 3] === name) {
return entries[i - 2];
}
}
@@ -139,7 +137,6 @@ define([], function () {
var exports = {
mark: mark,
measure: measure,
time: time,
getEntries: getEntries,
getEntry: getEntry,
getDuration: getDuration,

View File

@@ -46,6 +46,8 @@ if (typeof process === 'object' && typeof process.nextTick === 'function' && typ
_isWindows = (process.platform === 'win32');
_isMacintosh = (process.platform === 'darwin');
_isLinux = (process.platform === 'linux');
_locale = LANGUAGE_DEFAULT;
_language = LANGUAGE_DEFAULT;
const rawNlsConfig = process.env['VSCODE_NLS_CONFIG'];
if (rawNlsConfig) {
try {

View File

@@ -7,6 +7,18 @@
import * as paths from 'vs/base/common/paths';
import uri from 'vs/base/common/uri';
import { equalsIgnoreCase } from 'vs/base/common/strings';
import { Schemas } from 'vs/base/common/network';
import { isLinux } from 'vs/base/common/platform';
export function getComparisonKey(resource: uri): string {
return hasToIgnoreCase(resource) ? resource.toString().toLowerCase() : resource.toString();
}
export function hasToIgnoreCase(resource: uri): boolean {
// A file scheme resource is in the same platform as code, so ignore case for non linux platforms
// Resource can be from another platform. Lowering the case as an hack. Should come from File system provider
return resource && resource.scheme === Schemas.file ? !isLinux : true;
}
export function basenameOrAuthority(resource: uri): string {
return paths.basename(resource.path) || resource.authority;
@@ -18,7 +30,7 @@ export function isEqualOrParent(resource: uri, candidate: uri, ignoreCase?: bool
return paths.isEqualOrParent(resource.fsPath, candidate.fsPath, ignoreCase);
}
return paths.isEqualOrParent(resource.path, candidate.path, ignoreCase);
return paths.isEqualOrParent(resource.path, candidate.path, ignoreCase, '/');
}
return false;
@@ -52,6 +64,13 @@ export function dirname(resource: uri): uri {
});
}
export function joinPath(resource: uri, pathFragment: string): uri {
const joinedPath = paths.join(resource.path || '/', pathFragment);
return resource.with({
path: joinedPath
});
}
export function distinctParents<T>(items: T[], resourceAccessor: (item: T) => uri): T[] {
const distinctParents: T[] = [];
for (let i = 0; i < items.length; i++) {

View File

@@ -229,7 +229,7 @@ export class Scrollable extends Disposable {
/**
* Returns the final scroll position that the instance will have once the smooth scroll animation concludes.
* If no scroll animation is occuring, it will return the current scroll position instead.
* If no scroll animation is occurring, it will return the current scroll position instead.
*/
public getFutureScrollPosition(): IScrollPosition {
if (this._smoothScrolling) {

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { LRUCache } from 'vs/base/common/map';
import { CharCode } from 'vs/base/common/charCode';
/**
@@ -239,48 +238,6 @@ export function regExpContainsBackreference(regexpValue: string): boolean {
return !!regexpValue.match(/([^\\]|^)(\\\\)*\\\d+/);
}
/**
* The normalize() method returns the Unicode Normalization Form of a given string. The form will be
* the Normalization Form Canonical Composition.
*
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize}
*/
export const canNormalize = typeof ((<any>'').normalize) === 'function';
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 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: LRUCache<string, string>): string {
if (!canNormalize || !str) {
return str;
}
const cached = normalizedCache.get(str);
if (cached) {
return cached;
}
let res: string;
if (nonAsciiCharactersPattern.test(str)) {
res = (<any>str).normalize(form);
} else {
res = str;
}
// Use the cache for fast lookup
normalizedCache.set(str, res);
return res;
}
/**
* Returns first index of the string that is not whitespace.
* If string is empty or contains only whitespaces, returns -1
@@ -376,11 +333,11 @@ export function compareIgnoreCase(a: string, b: string): number {
}
}
function isLowerAsciiLetter(code: number): boolean {
export function isLowerAsciiLetter(code: number): boolean {
return code >= CharCode.a && code <= CharCode.z;
}
function isUpperAsciiLetter(code: number): boolean {
export function isUpperAsciiLetter(code: number): boolean {
return code >= CharCode.A && code <= CharCode.Z;
}

View File

@@ -4,22 +4,8 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as platform from 'vs/base/common/platform';
function _encode(ch: string): string {
return '%' + ch.charCodeAt(0).toString(16).toUpperCase();
}
// see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
function encodeURIComponent2(str: string): string {
return encodeURIComponent(str).replace(/[!'()*]/g, _encode);
}
function encodeNoop(str: string): string {
return str.replace(/[#?]/, _encode);
}
import { isWindows } from 'vs/base/common/platform';
import { CharCode } from 'vs/base/common/charCode';
const _schemePattern = /^\w[\w\d+.-]*$/;
const _singleSlashStart = /^\//;
@@ -50,12 +36,30 @@ function _validateUri(ret: URI): void {
}
}
// implements a bit of https://tools.ietf.org/html/rfc3986#section-5
function _referenceResolution(scheme: string, path: string): string {
// the slash-character is our 'default base' as we don't
// support constructing URIs relative to other URIs. This
// also means that we alter and potentially break paths.
// see https://tools.ietf.org/html/rfc3986#section-5.1.4
switch (scheme) {
case 'https':
case 'http':
case 'file':
if (!path) {
path = _slash;
} else if (path[0] !== _slash) {
path = _slash + path;
}
break;
}
return path;
}
const _empty = '';
const _slash = '/';
const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
const _driveLetterPath = /^\/[a-zA-Z]:/;
const _upperCaseDrive = /^(\/)?([A-Z]:)/;
const _driveLetter = /^[a-zA-Z]:/;
/**
* Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986.
@@ -143,9 +147,10 @@ export default class URI implements UriComponents {
} else {
this.scheme = schemeOrData || _empty;
this.authority = authority || _empty;
this.path = path || _empty;
this.path = _referenceResolution(this.scheme, path || _empty);
this.query = query || _empty;
this.fragment = fragment || _empty;
_validateUri(this);
}
}
@@ -232,7 +237,7 @@ export default class URI implements UriComponents {
// normalize to fwd-slashes on windows,
// on other systems bwd-slashes are valid
// filename character, eg /f\oo/ba\r.txt
if (platform.isWindows) {
if (isWindows) {
path = path.replace(/\\/g, _slash);
}
@@ -249,18 +254,6 @@ export default class URI implements UriComponents {
}
}
// Ensure that path starts with a slash
// or that it is at least a slash
if (_driveLetter.test(path)) {
path = _slash + path;
} else if (path[0] !== _slash) {
// tricky -> makes invalid paths
// but otherwise we have to stop
// allowing relative paths...
path = _slash + path;
}
return new _URI('file', authority, path, _empty, _empty);
}
@@ -285,33 +278,7 @@ export default class URI implements UriComponents {
}
public toJSON(): object {
const res = <UriState>{
$mid: 1,
fsPath: this.fsPath,
external: this.toString(),
};
if (this.path) {
res.path = this.path;
}
if (this.scheme) {
res.scheme = this.scheme;
}
if (this.authority) {
res.authority = this.authority;
}
if (this.query) {
res.query = this.query;
}
if (this.fragment) {
res.fragment = this.fragment;
}
return res;
return this;
}
static revive(data: UriComponents | any): URI {
@@ -367,8 +334,141 @@ class _URI extends URI {
return _asFormatted(this, true);
}
}
toJSON(): object {
const res = <UriState>{
$mid: 1
};
// cached state
if (this._fsPath) {
res.fsPath = this._fsPath;
}
if (this._formatted) {
res.external = this._formatted;
}
// uri components
if (this.path) {
res.path = this.path;
}
if (this.scheme) {
res.scheme = this.scheme;
}
if (this.authority) {
res.authority = this.authority;
}
if (this.query) {
res.query = this.query;
}
if (this.fragment) {
res.fragment = this.fragment;
}
return res;
}
}
// reserved characters: https://tools.ietf.org/html/rfc3986#section-2.2
const encodeTable: { [ch: number]: string } = {
[CharCode.Colon]: '%3A', // gen-delims
[CharCode.Slash]: '%2F',
[CharCode.QuestionMark]: '%3F',
[CharCode.Hash]: '%23',
[CharCode.OpenSquareBracket]: '%5B',
[CharCode.CloseSquareBracket]: '%5D',
[CharCode.AtSign]: '%40',
[CharCode.ExclamationMark]: '%21', // sub-delims
[CharCode.DollarSign]: '%24',
[CharCode.Ampersand]: '%26',
[CharCode.SingleQuote]: '%27',
[CharCode.OpenParen]: '%28',
[CharCode.CloseParen]: '%29',
[CharCode.Asterisk]: '%2A',
[CharCode.Plus]: '%2B',
[CharCode.Comma]: '%2C',
[CharCode.Semicolon]: '%3B',
[CharCode.Equals]: '%3D',
[CharCode.Space]: '%20',
};
function encodeURIComponentFast(uriComponent: string, allowSlash: boolean): string {
let res: string = undefined;
let nativeEncodePos = -1;
for (let pos = 0; pos < uriComponent.length; pos++) {
let code = uriComponent.charCodeAt(pos);
// unreserved characters: https://tools.ietf.org/html/rfc3986#section-2.3
if (
(code >= CharCode.a && code <= CharCode.z)
|| (code >= CharCode.A && code <= CharCode.Z)
|| (code >= CharCode.Digit0 && code <= CharCode.Digit9)
|| code === CharCode.Dash
|| code === CharCode.Period
|| code === CharCode.Underline
|| code === CharCode.Tilde
|| (allowSlash && code === CharCode.Slash)
) {
// check if we are delaying native encode
if (nativeEncodePos !== -1) {
res += encodeURIComponent(uriComponent.substring(nativeEncodePos, pos));
nativeEncodePos = -1;
}
// check if we write into a new string (by default we try to return the param)
if (res !== undefined) {
res += uriComponent.charAt(pos);
}
} else {
// encoding needed, we need to allocate a new string
if (res === undefined) {
res = uriComponent.substr(0, pos);
}
// check with default table first
let escaped = encodeTable[code];
if (escaped !== undefined) {
// check if we are delaying native encode
if (nativeEncodePos !== -1) {
res += encodeURIComponent(uriComponent.substring(nativeEncodePos, pos));
nativeEncodePos = -1;
}
// append escaped variant to result
res += escaped;
} else if (nativeEncodePos === -1) {
// use native encode only when needed
nativeEncodePos = pos;
}
}
}
if (nativeEncodePos !== -1) {
res += encodeURIComponent(uriComponent.substring(nativeEncodePos));
}
return res !== undefined ? res : uriComponent;
}
function encodeURIComponentMinimal(path: string): string {
let res: string = undefined;
for (let pos = 0; pos < path.length; pos++) {
let code = path.charCodeAt(pos);
if (code === CharCode.Hash || code === CharCode.QuestionMark) {
if (res === undefined) {
res = path.substr(0, pos);
}
res += encodeTable[code];
} else {
if (res !== undefined) {
res += path[pos];
}
}
}
return res !== undefined ? res : path;
}
/**
* Compute `fsPath` for the given uri
@@ -377,17 +477,21 @@ class _URI extends URI {
function _makeFsPath(uri: URI): string {
let value: string;
if (uri.authority && uri.path && uri.scheme === 'file') {
if (uri.authority && uri.path.length > 1 && uri.scheme === 'file') {
// unc path: file://shares/c$/far/boo
value = `//${uri.authority}${uri.path}`;
} else if (_driveLetterPath.test(uri.path)) {
} else if (
uri.path.charCodeAt(0) === CharCode.Slash
&& (uri.path.charCodeAt(1) >= CharCode.A && uri.path.charCodeAt(1) <= CharCode.Z || uri.path.charCodeAt(1) >= CharCode.a && uri.path.charCodeAt(1) <= CharCode.z)
&& uri.path.charCodeAt(2) === CharCode.Colon
) {
// windows drive letter: file:///c:/far/boo
value = uri.path[1].toLowerCase() + uri.path.substr(2);
} else {
// other path
value = uri.path;
}
if (platform.isWindows) {
if (isWindows) {
value = value.replace(/\//g, '\\');
}
return value;
@@ -399,71 +503,69 @@ function _makeFsPath(uri: URI): string {
function _asFormatted(uri: URI, skipEncoding: boolean): string {
const encoder = !skipEncoding
? encodeURIComponent2
: encodeNoop;
const parts: string[] = [];
? encodeURIComponentFast
: encodeURIComponentMinimal;
let res = '';
let { scheme, authority, path, query, fragment } = uri;
if (scheme) {
parts.push(scheme, ':');
res += scheme;
res += ':';
}
if (authority || scheme === 'file') {
parts.push('//');
res += _slash;
res += _slash;
}
if (authority) {
let idx = authority.indexOf('@');
if (idx !== -1) {
// <user>@<auth>
const userinfo = authority.substr(0, idx);
authority = authority.substr(idx + 1);
idx = userinfo.indexOf(':');
if (idx === -1) {
parts.push(encoder(userinfo));
res += encoder(userinfo, false);
} else {
parts.push(encoder(userinfo.substr(0, idx)), ':', encoder(userinfo.substr(idx + 1)));
// <user>:<pass>@<auth>
res += encoder(userinfo.substr(0, idx), false);
res += ':';
res += encoder(userinfo.substr(idx + 1), false);
}
parts.push('@');
res += '@';
}
authority = authority.toLowerCase();
idx = authority.indexOf(':');
if (idx === -1) {
parts.push(encoder(authority));
res += encoder(authority, false);
} else {
parts.push(encoder(authority.substr(0, idx)), authority.substr(idx));
// <auth>:<port>
res += encoder(authority.substr(0, idx), false);
res += authority.substr(idx);
}
}
if (path) {
// lower-case windows drive letters in /C:/fff or C:/fff
const m = _upperCaseDrive.exec(path);
if (m) {
if (m[1]) {
path = '/' + m[2].toLowerCase() + path.substr(3); // "/c:".length === 3
} else {
path = m[2].toLowerCase() + path.substr(2); // // "c:".length === 2
if (path.length >= 3 && path.charCodeAt(0) === CharCode.Slash && path.charCodeAt(2) === CharCode.Colon) {
let code = path.charCodeAt(1);
if (code >= CharCode.A && code <= CharCode.Z) {
path = `/${String.fromCharCode(code + 32)}:${path.substr(3)}`; // "/c:".length === 3
}
} else if (path.length >= 2 && path.charCodeAt(1) === CharCode.Colon) {
let code = path.charCodeAt(0);
if (code >= CharCode.A && code <= CharCode.Z) {
path = `${String.fromCharCode(code + 32)}:${path.substr(2)}`; // "/c:".length === 3
}
}
// encode every segement but not slashes
// make sure that # and ? are always encoded
// when occurring in paths - otherwise the result
// cannot be parsed back again
let lastIdx = 0;
while (true) {
let idx = path.indexOf(_slash, lastIdx);
if (idx === -1) {
parts.push(encoder(path.substring(lastIdx)));
break;
}
parts.push(encoder(path.substring(lastIdx, idx)), _slash);
lastIdx = idx + 1;
}
// encode the rest of the path
res += encoder(path, true);
}
if (query) {
parts.push('?', encoder(query));
res += '?';
res += encoder(query, false);
}
if (fragment) {
parts.push('#', encoder(fragment));
res += '#';
res += !skipEncoding ? encodeURIComponentFast(fragment, false) : fragment;
}
return parts.join(_empty);
return res;
}

View File

@@ -0,0 +1,18 @@
/*---------------------------------------------------------------------------------------------
* 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 URI, { UriComponents } from 'vs/base/common/uri';
export interface IURITransformer {
transformIncoming(uri: UriComponents): UriComponents;
transformOutgoing(uri: URI): URI;
}
export const DefaultURITransformer: IURITransformer = {
transformIncoming: (uri: UriComponents) => uri,
transformOutgoing: (uri: URI) => uri,
};

View File

@@ -28,7 +28,7 @@ class ValueUUID implements UUID {
class V4UUID extends ValueUUID {
private static readonly _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', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
private static readonly _timeHighBits = ['8', '9', 'a', 'b'];

View File

@@ -39,7 +39,6 @@ export declare class Promise<T = any, TProgress = any> {
public static join<T1, T2>(promises: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<[T1, T2]>;
public static join<T>(promises: (T | PromiseLike<T>)[]): Promise<T[]>;
public static join<T>(promises: { [n: string]: T | PromiseLike<T> }): Promise<{ [n: string]: T }>;
public static any<T>(promises: (T | PromiseLike<T>)[]): Promise<{ key: string; value: Promise<T>; }>;

View File

@@ -1038,6 +1038,12 @@ _winjs("WinJS/Promise/_StateMachine", ["WinJS/Core/_Global","WinJS/Core/_BaseCor
/// error function.
/// </returns>
/// </signature>
// BEGIN monaco change
if (this.then !== Promise_then) {
this.then(onComplete, onError, onProgress);
return;
}
// END monaco change
return this._state.then(this, onComplete, onError, onProgress);
},

View File

@@ -91,7 +91,7 @@ class SimpleWorkerProtocol {
c: null,
e: null
};
let result = new TPromise<any>((c, e, p) => {
let result = new TPromise<any>((c, e) => {
reply.c = c;
reply.e = e;
}, () => {
@@ -232,7 +232,7 @@ export class SimpleWorkerClient<T> extends Disposable {
loaderConfiguration = (<any>self).requirejs.s.contexts._.config;
}
this._lazyProxy = new TPromise<T>((c, e, p) => {
this._lazyProxy = new TPromise<T>((c, e) => {
lazyProxyFulfill = c;
lazyProxyReject = e;
}, () => { /* no cancel */ });
@@ -273,7 +273,7 @@ export class SimpleWorkerClient<T> extends Disposable {
}
private _request(method: string, args: any[]): TPromise<any> {
return new TPromise<any>((c, e, p) => {
return new TPromise<any>((c, e) => {
this._onModuleLoaded.then(() => {
this._protocol.sendMessage(method, args).then(c, e);
}, e);
@@ -290,6 +290,7 @@ export class SimpleWorkerClient<T> extends Disposable {
export interface IRequestHandler {
_requestHandlerBrand: any;
[prop: string]: any;
}
/**
@@ -362,7 +363,7 @@ export class SimpleWorkerServer {
let cc: ValueCallback;
let ee: ErrorCallback;
let r = new TPromise<any>((c, e, p) => {
let r = new TPromise<any>((c, e) => {
cc = c;
ee = e;
});