mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-07 01:25:38 -05:00
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:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}}.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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: '+',
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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()];
|
||||
}
|
||||
49
src/vs/base/common/normalization.ts
Normal file
49
src/vs/base/common/normalization.ts
Normal 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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
5
src/vs/base/common/performance.d.ts
vendored
5
src/vs/base/common/performance.d.ts
vendored
@@ -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`.
|
||||
*/
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
18
src/vs/base/common/uriIpc.ts
Normal file
18
src/vs/base/common/uriIpc.ts
Normal 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,
|
||||
};
|
||||
@@ -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'];
|
||||
|
||||
|
||||
1
src/vs/base/common/winjs.base.d.ts
vendored
1
src/vs/base/common/winjs.base.d.ts
vendored
@@ -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>; }>;
|
||||
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user