Merge from vscode c58aaab8a1cc22a7139b761166a0d4f37d41e998 (#7880)

* Merge from vscode c58aaab8a1cc22a7139b761166a0d4f37d41e998

* fix pipelines

* fix strict-null-checks

* add missing files
This commit is contained in:
Anthony Dresser
2019-10-21 22:12:22 -07:00
committed by GitHub
parent 7c9be74970
commit 1e22f47304
913 changed files with 18898 additions and 16536 deletions

View File

@@ -29,7 +29,6 @@ export interface IAction extends IDisposable {
class: string | undefined;
enabled: boolean;
checked: boolean;
radio: boolean;
run(event?: any): Promise<any>;
}
@@ -54,7 +53,6 @@ export interface IActionChangeEvent {
readonly class?: string;
readonly enabled?: boolean;
readonly checked?: boolean;
readonly radio?: boolean;
}
export class Action extends Disposable implements IAction {
@@ -68,7 +66,6 @@ export class Action extends Disposable implements IAction {
protected _cssClass: string | undefined;
protected _enabled: boolean = true;
protected _checked: boolean = false;
protected _radio: boolean = false;
protected readonly _actionCallback?: (event?: any) => Promise<any>;
constructor(id: string, label: string = '', cssClass: string = '', enabled: boolean = true, actionCallback?: (event?: any) => Promise<any>) {
@@ -152,14 +149,6 @@ export class Action extends Disposable implements IAction {
this._setChecked(value);
}
get radio(): boolean {
return this._radio;
}
set radio(value: boolean) {
this._setRadio(value);
}
protected _setChecked(value: boolean): void {
if (this._checked !== value) {
this._checked = value;
@@ -167,13 +156,6 @@ export class Action extends Disposable implements IAction {
}
}
protected _setRadio(value: boolean): void {
if (this._radio !== value) {
this._radio = value;
this._onDidChange.fire({ radio: value });
}
}
run(event?: any, _data?: ITelemetryData): Promise<any> {
if (this._actionCallback) {
return this._actionCallback(event);

View File

@@ -116,7 +116,10 @@ export class CancellationTokenSource {
}
}
dispose(): void {
dispose(cancel: boolean = false): void {
if (cancel) {
this.cancel();
}
if (this._parentListener) {
this._parentListener.dispose();
}

View File

@@ -0,0 +1,135 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { matchesFuzzy, IMatch } from 'vs/base/common/filters';
import { ltrim } from 'vs/base/common/strings';
const codiconStartMarker = '$(';
export interface IParsedCodicons {
readonly text: string;
readonly codiconOffsets?: readonly number[];
}
export function parseCodicons(text: string): IParsedCodicons {
const firstCodiconIndex = text.indexOf(codiconStartMarker);
if (firstCodiconIndex === -1) {
return { text }; // return early if the word does not include an codicon
}
return doParseCodicons(text, firstCodiconIndex);
}
function doParseCodicons(text: string, firstCodiconIndex: number): IParsedCodicons {
const codiconOffsets: number[] = [];
let textWithoutCodicons: string = '';
function appendChars(chars: string) {
if (chars) {
textWithoutCodicons += chars;
for (const _ of chars) {
codiconOffsets.push(codiconsOffset); // make sure to fill in codicon offsets
}
}
}
let currentCodiconStart = -1;
let currentCodiconValue: string = '';
let codiconsOffset = 0;
let char: string;
let nextChar: string;
let offset = firstCodiconIndex;
const length = text.length;
// Append all characters until the first codicon
appendChars(text.substr(0, firstCodiconIndex));
// example: $(file-symlink-file) my cool $(other-codicon) entry
while (offset < length) {
char = text[offset];
nextChar = text[offset + 1];
// beginning of codicon: some value $( <--
if (char === codiconStartMarker[0] && nextChar === codiconStartMarker[1]) {
currentCodiconStart = offset;
// if we had a previous potential codicon value without
// the closing ')', it was actually not an codicon and
// so we have to add it to the actual value
appendChars(currentCodiconValue);
currentCodiconValue = codiconStartMarker;
offset++; // jump over '('
}
// end of codicon: some value $(some-codicon) <--
else if (char === ')' && currentCodiconStart !== -1) {
const currentCodiconLength = offset - currentCodiconStart + 1; // +1 to include the closing ')'
codiconsOffset += currentCodiconLength;
currentCodiconStart = -1;
currentCodiconValue = '';
}
// within codicon
else if (currentCodiconStart !== -1) {
// Make sure this is a real codicon name
if (/^[a-z0-9\-]$/i.test(char)) {
currentCodiconValue += char;
} else {
// This is not a real codicon, treat it as text
appendChars(currentCodiconValue);
currentCodiconStart = -1;
currentCodiconValue = '';
}
}
// any value outside of codicons
else {
appendChars(char);
}
offset++;
}
// if we had a previous potential codicon value without
// the closing ')', it was actually not an codicon and
// so we have to add it to the actual value
appendChars(currentCodiconValue);
return { text: textWithoutCodicons, codiconOffsets };
}
export function matchesFuzzyCodiconAware(query: string, target: IParsedCodicons, enableSeparateSubstringMatching = false): IMatch[] | null {
const { text, codiconOffsets } = target;
// Return early if there are no codicon markers in the word to match against
if (!codiconOffsets || codiconOffsets.length === 0) {
return matchesFuzzy(query, text, enableSeparateSubstringMatching);
}
// Trim the word to match against because it could have leading
// whitespace now if the word started with an codicon
const wordToMatchAgainstWithoutCodiconsTrimmed = ltrim(text, ' ');
const leadingWhitespaceOffset = text.length - wordToMatchAgainstWithoutCodiconsTrimmed.length;
// match on value without codicons
const matches = matchesFuzzy(query, wordToMatchAgainstWithoutCodiconsTrimmed, enableSeparateSubstringMatching);
// Map matches back to offsets with codicons and trimming
if (matches) {
for (const match of matches) {
const codiconOffset = codiconOffsets[match.start + leadingWhitespaceOffset] /* codicon offsets at index */ + leadingWhitespaceOffset /* overall leading whitespace offset */;
match.start += codiconOffset;
match.end += codiconOffset;
}
}
return matches;
}

View File

@@ -507,10 +507,6 @@ export namespace Color {
* The default format will use HEX if opaque and RGBA otherwise.
*/
export function format(color: Color): string | null {
if (!color) {
return null;
}
if (color.isOpaque()) {
return Color.Format.CSS.formatHex(color);
}
@@ -524,11 +520,6 @@ export namespace Color {
* @param hex string (#RGB, #RGBA, #RRGGBB or #RRGGBBAA).
*/
export function parseHex(hex: string): Color | null {
if (!hex) {
// Invalid color
return null;
}
const length = hex.length;
if (length === 0) {

View File

@@ -4,22 +4,29 @@
*--------------------------------------------------------------------------------------------*/
import { DiffChange } from 'vs/base/common/diff/diffChange';
import { stringHash } from 'vs/base/common/hash';
import { Constants } from 'vs/base/common/uint';
function createStringSequence(a: string): ISequence {
return {
getLength() { return a.length; },
getElementAtIndex(pos: number) { return a.charCodeAt(pos); }
};
export class StringDiffSequence implements ISequence {
constructor(private source: string) { }
getElements(): Int32Array | number[] | string[] {
const source = this.source;
const characters = new Int32Array(source.length);
for (let i = 0, len = source.length; i < len; i++) {
characters[i] = source.charCodeAt(i);
}
return characters;
}
}
export function stringDiff(original: string, modified: string, pretty: boolean): IDiffChange[] {
return new LcsDiff(createStringSequence(original), createStringSequence(modified)).ComputeDiff(pretty);
return new LcsDiff(new StringDiffSequence(original), new StringDiffSequence(modified)).ComputeDiff(pretty).changes;
}
export interface ISequence {
getLength(): number;
getElementAtIndex(index: number): number | string;
getElements(): Int32Array | number[] | string[];
}
export interface IDiffChange {
@@ -49,7 +56,12 @@ export interface IDiffChange {
}
export interface IContinueProcessingPredicate {
(furthestOriginalIndex: number, originalSequence: ISequence, matchLengthOfLongest: number): boolean;
(furthestOriginalIndex: number, matchLengthOfLongest: number): boolean;
}
export interface IDiffResult {
quitEarly: boolean;
changes: IDiffChange[];
}
//
@@ -86,6 +98,11 @@ export class MyArray {
destinationArray[destinationIndex + i] = sourceArray[sourceIndex + i];
}
}
public static Copy2(sourceArray: Int32Array, sourceIndex: number, destinationArray: Int32Array, destinationIndex: number, length: number) {
for (let i = 0; i < length; i++) {
destinationArray[destinationIndex + i] = sourceArray[sourceIndex + i];
}
}
}
//*****************************************************************************
@@ -100,11 +117,9 @@ export class MyArray {
// Our total memory usage for storing history is (worst-case):
// 2 * [(MaxDifferencesHistory + 1) * (MaxDifferencesHistory + 1) - 1] * sizeof(int)
// 2 * [1448*1448 - 1] * 4 = 16773624 = 16MB
let MaxDifferencesHistory = 1447;
//let MaxDifferencesHistory = 100;
const enum LocalConstants {
MaxDifferencesHistory = 1447
}
/**
* A utility class which helps to create the set of DiffChanges from
@@ -127,8 +142,8 @@ class DiffChangeHelper {
*/
constructor() {
this.m_changes = [];
this.m_originalStart = Number.MAX_VALUE;
this.m_modifiedStart = Number.MAX_VALUE;
this.m_originalStart = Constants.MAX_SAFE_SMALL_INTEGER;
this.m_modifiedStart = Constants.MAX_SAFE_SMALL_INTEGER;
this.m_originalCount = 0;
this.m_modifiedCount = 0;
}
@@ -147,8 +162,8 @@ class DiffChangeHelper {
// Reset for the next change
this.m_originalCount = 0;
this.m_modifiedCount = 0;
this.m_originalStart = Number.MAX_VALUE;
this.m_modifiedStart = Number.MAX_VALUE;
this.m_originalStart = Constants.MAX_SAFE_SMALL_INTEGER;
this.m_modifiedStart = Constants.MAX_SAFE_SMALL_INTEGER;
}
/**
@@ -214,39 +229,81 @@ class DiffChangeHelper {
*/
export class LcsDiff {
private OriginalSequence: ISequence;
private ModifiedSequence: ISequence;
private ContinueProcessingPredicate: IContinueProcessingPredicate | null;
private readonly ContinueProcessingPredicate: IContinueProcessingPredicate | null;
private m_forwardHistory: number[][];
private m_reverseHistory: number[][];
private readonly _hasStrings: boolean;
private readonly _originalStringElements: string[];
private readonly _originalElementsOrHash: Int32Array;
private readonly _modifiedStringElements: string[];
private readonly _modifiedElementsOrHash: Int32Array;
private m_forwardHistory: Int32Array[];
private m_reverseHistory: Int32Array[];
/**
* Constructs the DiffFinder
*/
constructor(originalSequence: ISequence, newSequence: ISequence, continueProcessingPredicate: IContinueProcessingPredicate | null = null) {
this.OriginalSequence = originalSequence;
this.ModifiedSequence = newSequence;
constructor(originalSequence: ISequence, modifiedSequence: ISequence, continueProcessingPredicate: IContinueProcessingPredicate | null = null) {
this.ContinueProcessingPredicate = continueProcessingPredicate;
const [originalStringElements, originalElementsOrHash, originalHasStrings] = LcsDiff._getElements(originalSequence);
const [modifiedStringElements, modifiedElementsOrHash, modifiedHasStrings] = LcsDiff._getElements(modifiedSequence);
this._hasStrings = (originalHasStrings && modifiedHasStrings);
this._originalStringElements = originalStringElements;
this._originalElementsOrHash = originalElementsOrHash;
this._modifiedStringElements = modifiedStringElements;
this._modifiedElementsOrHash = modifiedElementsOrHash;
this.m_forwardHistory = [];
this.m_reverseHistory = [];
}
private static _isStringArray(arr: Int32Array | number[] | string[]): arr is string[] {
return (arr.length > 0 && typeof arr[0] === 'string');
}
private static _getElements(sequence: ISequence): [string[], Int32Array, boolean] {
const elements = sequence.getElements();
if (LcsDiff._isStringArray(elements)) {
const hashes = new Int32Array(elements.length);
for (let i = 0, len = elements.length; i < len; i++) {
hashes[i] = stringHash(elements[i], 0);
}
return [elements, hashes, true];
}
if (elements instanceof Int32Array) {
return [[], elements, false];
}
return [[], new Int32Array(elements), false];
}
private ElementsAreEqual(originalIndex: number, newIndex: number): boolean {
return (this.OriginalSequence.getElementAtIndex(originalIndex) === this.ModifiedSequence.getElementAtIndex(newIndex));
if (this._originalElementsOrHash[originalIndex] !== this._modifiedElementsOrHash[newIndex]) {
return false;
}
return (this._hasStrings ? this._originalStringElements[originalIndex] === this._modifiedStringElements[newIndex] : true);
}
private OriginalElementsAreEqual(index1: number, index2: number): boolean {
return (this.OriginalSequence.getElementAtIndex(index1) === this.OriginalSequence.getElementAtIndex(index2));
if (this._originalElementsOrHash[index1] !== this._originalElementsOrHash[index2]) {
return false;
}
return (this._hasStrings ? this._originalStringElements[index1] === this._originalStringElements[index2] : true);
}
private ModifiedElementsAreEqual(index1: number, index2: number): boolean {
return (this.ModifiedSequence.getElementAtIndex(index1) === this.ModifiedSequence.getElementAtIndex(index2));
if (this._modifiedElementsOrHash[index1] !== this._modifiedElementsOrHash[index2]) {
return false;
}
return (this._hasStrings ? this._modifiedStringElements[index1] === this._modifiedStringElements[index2] : true);
}
public ComputeDiff(pretty: boolean): IDiffChange[] {
return this._ComputeDiff(0, this.OriginalSequence.getLength() - 1, 0, this.ModifiedSequence.getLength() - 1, pretty);
public ComputeDiff(pretty: boolean): IDiffResult {
return this._ComputeDiff(0, this._originalElementsOrHash.length - 1, 0, this._modifiedElementsOrHash.length - 1, pretty);
}
/**
@@ -254,18 +311,21 @@ export class LcsDiff {
* sequences on the bounded range.
* @returns An array of the differences between the two input sequences.
*/
private _ComputeDiff(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, pretty: boolean): DiffChange[] {
let quitEarlyArr = [false];
private _ComputeDiff(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, pretty: boolean): IDiffResult {
const quitEarlyArr = [false];
let changes = this.ComputeDiffRecursive(originalStart, originalEnd, modifiedStart, modifiedEnd, quitEarlyArr);
if (pretty) {
// We have to clean up the computed diff to be more intuitive
// but it turns out this cannot be done correctly until the entire set
// of diffs have been computed
return this.PrettifyChanges(changes);
changes = this.PrettifyChanges(changes);
}
return changes;
return {
quitEarly: quitEarlyArr[0],
changes: changes
};
}
/**
@@ -318,11 +378,12 @@ export class LcsDiff {
}
// This problem can be solved using the Divide-And-Conquer technique.
let midOriginalArr = [0], midModifiedArr = [0];
let result = this.ComputeRecursionPoint(originalStart, originalEnd, modifiedStart, modifiedEnd, midOriginalArr, midModifiedArr, quitEarlyArr);
const midOriginalArr = [0];
const midModifiedArr = [0];
const result = this.ComputeRecursionPoint(originalStart, originalEnd, modifiedStart, modifiedEnd, midOriginalArr, midModifiedArr, quitEarlyArr);
let midOriginal = midOriginalArr[0];
let midModified = midModifiedArr[0];
const midOriginal = midOriginalArr[0];
const midModified = midModifiedArr[0];
if (result !== null) {
// Result is not-null when there was enough memory to compute the changes while
@@ -334,7 +395,7 @@ export class LcsDiff {
// Second Half: (midOriginal + 1, minModified + 1) to (originalEnd, modifiedEnd)
// NOTE: ComputeDiff() is inclusive, therefore the second range starts on the next point
let leftChanges = this.ComputeDiffRecursive(originalStart, midOriginal, modifiedStart, midModified, quitEarlyArr);
const leftChanges = this.ComputeDiffRecursive(originalStart, midOriginal, modifiedStart, midModified, quitEarlyArr);
let rightChanges: DiffChange[] = [];
if (!quitEarlyArr[0]) {
@@ -358,24 +419,25 @@ export class LcsDiff {
private WALKTRACE(diagonalForwardBase: number, diagonalForwardStart: number, diagonalForwardEnd: number, diagonalForwardOffset: number,
diagonalReverseBase: number, diagonalReverseStart: number, diagonalReverseEnd: number, diagonalReverseOffset: number,
forwardPoints: number[], reversePoints: number[],
forwardPoints: Int32Array, reversePoints: Int32Array,
originalIndex: number, originalEnd: number, midOriginalArr: number[],
modifiedIndex: number, modifiedEnd: number, midModifiedArr: number[],
deltaIsEven: boolean, quitEarlyArr: boolean[]): DiffChange[] {
let forwardChanges: DiffChange[] | null = null, reverseChanges: DiffChange[] | null = null;
deltaIsEven: boolean, quitEarlyArr: boolean[]
): DiffChange[] {
let forwardChanges: DiffChange[] | null = null;
let reverseChanges: DiffChange[] | null = null;
// First, walk backward through the forward diagonals history
let changeHelper = new DiffChangeHelper();
let diagonalMin = diagonalForwardStart;
let diagonalMax = diagonalForwardEnd;
let diagonalRelative = (midOriginalArr[0] - midModifiedArr[0]) - diagonalForwardOffset;
let lastOriginalIndex = Number.MIN_VALUE;
let lastOriginalIndex = Constants.MIN_SAFE_SMALL_INTEGER;
let historyIndex = this.m_forwardHistory.length - 1;
let diagonal: number;
do {
// Get the diagonal index from the relative diagonal number
diagonal = diagonalRelative + diagonalForwardBase;
const diagonal = diagonalRelative + diagonalForwardBase;
// Figure out where we came from
if (diagonal === diagonalMin || (diagonal < diagonalMax && forwardPoints[diagonal - 1] < forwardPoints[diagonal + 1])) {
@@ -420,7 +482,7 @@ export class LcsDiff {
let modifiedStartPoint = midModifiedArr[0] + 1;
if (forwardChanges !== null && forwardChanges.length > 0) {
let lastForwardChange = forwardChanges[forwardChanges.length - 1];
const lastForwardChange = forwardChanges[forwardChanges.length - 1];
originalStartPoint = Math.max(originalStartPoint, lastForwardChange.getOriginalEnd());
modifiedStartPoint = Math.max(modifiedStartPoint, lastForwardChange.getModifiedEnd());
}
@@ -435,12 +497,12 @@ export class LcsDiff {
diagonalMin = diagonalReverseStart;
diagonalMax = diagonalReverseEnd;
diagonalRelative = (midOriginalArr[0] - midModifiedArr[0]) - diagonalReverseOffset;
lastOriginalIndex = Number.MAX_VALUE;
lastOriginalIndex = Constants.MAX_SAFE_SMALL_INTEGER;
historyIndex = (deltaIsEven) ? this.m_reverseHistory.length - 1 : this.m_reverseHistory.length - 2;
do {
// Get the diagonal index from the relative diagonal number
diagonal = diagonalRelative + diagonalReverseBase;
const diagonal = diagonalRelative + diagonalReverseBase;
// Figure out where we came from
if (diagonal === diagonalMin || (diagonal < diagonalMax && reversePoints[diagonal - 1] >= reversePoints[diagonal + 1])) {
@@ -501,7 +563,6 @@ export class LcsDiff {
let originalIndex = 0, modifiedIndex = 0;
let diagonalForwardStart = 0, diagonalForwardEnd = 0;
let diagonalReverseStart = 0, diagonalReverseEnd = 0;
let numDifferences: number;
// To traverse the edit graph and produce the proper LCS, our actual
// start position is just outside the given boundary
@@ -521,26 +582,26 @@ export class LcsDiff {
// The integer value in the cell represents the originalIndex of the furthest
// reaching point found so far that ends in that diagonal.
// The modifiedIndex can be computed mathematically from the originalIndex and the diagonal number.
let maxDifferences = (originalEnd - originalStart) + (modifiedEnd - modifiedStart);
let numDiagonals = maxDifferences + 1;
let forwardPoints: number[] = new Array<number>(numDiagonals);
let reversePoints: number[] = new Array<number>(numDiagonals);
const maxDifferences = (originalEnd - originalStart) + (modifiedEnd - modifiedStart);
const numDiagonals = maxDifferences + 1;
const forwardPoints = new Int32Array(numDiagonals);
const reversePoints = new Int32Array(numDiagonals);
// diagonalForwardBase: Index into forwardPoints of the diagonal which passes through (originalStart, modifiedStart)
// diagonalReverseBase: Index into reversePoints of the diagonal which passes through (originalEnd, modifiedEnd)
let diagonalForwardBase = (modifiedEnd - modifiedStart);
let diagonalReverseBase = (originalEnd - originalStart);
const diagonalForwardBase = (modifiedEnd - modifiedStart);
const diagonalReverseBase = (originalEnd - originalStart);
// diagonalForwardOffset: Geometric offset which allows modifiedIndex to be computed from originalIndex and the
// diagonal number (relative to diagonalForwardBase)
// diagonalReverseOffset: Geometric offset which allows modifiedIndex to be computed from originalIndex and the
// diagonal number (relative to diagonalReverseBase)
let diagonalForwardOffset = (originalStart - modifiedStart);
let diagonalReverseOffset = (originalEnd - modifiedEnd);
const diagonalForwardOffset = (originalStart - modifiedStart);
const diagonalReverseOffset = (originalEnd - modifiedEnd);
// delta: The difference between the end diagonal and the start diagonal. This is used to relate diagonal numbers
// relative to the start diagonal with diagonal numbers relative to the end diagonal.
// The Even/Oddn-ness of this delta is important for determining when we should check for overlap
let delta = diagonalReverseBase - diagonalForwardBase;
let deltaIsEven = (delta % 2 === 0);
const delta = diagonalReverseBase - diagonalForwardBase;
const deltaIsEven = (delta % 2 === 0);
// Here we set up the start and end points as the furthest points found so far
// in both the forward and reverse directions, respectively
@@ -559,15 +620,14 @@ export class LcsDiff {
// away from the reference diagonal (which is diagonalForwardBase for forward, diagonalReverseBase for reverse).
// --We extend on even diagonals (relative to the reference diagonal) only when numDifferences
// is even and odd diagonals only when numDifferences is odd.
let diagonal: number, tempOriginalIndex: number;
for (numDifferences = 1; numDifferences <= (maxDifferences / 2) + 1; numDifferences++) {
for (let numDifferences = 1; numDifferences <= (maxDifferences / 2) + 1; numDifferences++) {
let furthestOriginalIndex = 0;
let furthestModifiedIndex = 0;
// Run the algorithm in the forward direction
diagonalForwardStart = this.ClipDiagonalBound(diagonalForwardBase - numDifferences, numDifferences, diagonalForwardBase, numDiagonals);
diagonalForwardEnd = this.ClipDiagonalBound(diagonalForwardBase + numDifferences, numDifferences, diagonalForwardBase, numDiagonals);
for (diagonal = diagonalForwardStart; diagonal <= diagonalForwardEnd; diagonal += 2) {
for (let diagonal = diagonalForwardStart; diagonal <= diagonalForwardEnd; diagonal += 2) {
// STEP 1: We extend the furthest reaching point in the present diagonal
// by looking at the diagonals above and below and picking the one whose point
// is further away from the start point (originalStart, modifiedStart)
@@ -579,7 +639,7 @@ export class LcsDiff {
modifiedIndex = originalIndex - (diagonal - diagonalForwardBase) - diagonalForwardOffset;
// Save the current originalIndex so we can test for false overlap in step 3
tempOriginalIndex = originalIndex;
const tempOriginalIndex = originalIndex;
// STEP 2: We can continue to extend the furthest reaching point in the present diagonal
// so long as the elements are equal.
@@ -603,7 +663,7 @@ export class LcsDiff {
midOriginalArr[0] = originalIndex;
midModifiedArr[0] = modifiedIndex;
if (tempOriginalIndex <= reversePoints[diagonal] && MaxDifferencesHistory > 0 && numDifferences <= (MaxDifferencesHistory + 1)) {
if (tempOriginalIndex <= reversePoints[diagonal] && LocalConstants.MaxDifferencesHistory > 0 && numDifferences <= (LocalConstants.MaxDifferencesHistory + 1)) {
// BINGO! We overlapped, and we have the full trace in memory!
return this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset,
diagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset,
@@ -622,9 +682,9 @@ export class LcsDiff {
}
// Check to see if we should be quitting early, before moving on to the next iteration.
let matchLengthOfLongest = ((furthestOriginalIndex - originalStart) + (furthestModifiedIndex - modifiedStart) - numDifferences) / 2;
const matchLengthOfLongest = ((furthestOriginalIndex - originalStart) + (furthestModifiedIndex - modifiedStart) - numDifferences) / 2;
if (this.ContinueProcessingPredicate !== null && !this.ContinueProcessingPredicate(furthestOriginalIndex, this.OriginalSequence, matchLengthOfLongest)) {
if (this.ContinueProcessingPredicate !== null && !this.ContinueProcessingPredicate(furthestOriginalIndex, matchLengthOfLongest)) {
// We can't finish, so skip ahead to generating a result from what we have.
quitEarlyArr[0] = true;
@@ -632,7 +692,7 @@ export class LcsDiff {
midOriginalArr[0] = furthestOriginalIndex;
midModifiedArr[0] = furthestModifiedIndex;
if (matchLengthOfLongest > 0 && MaxDifferencesHistory > 0 && numDifferences <= (MaxDifferencesHistory + 1)) {
if (matchLengthOfLongest > 0 && LocalConstants.MaxDifferencesHistory > 0 && numDifferences <= (LocalConstants.MaxDifferencesHistory + 1)) {
// Enough of the history is in memory to walk it backwards
return this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset,
diagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset,
@@ -659,7 +719,7 @@ export class LcsDiff {
// Run the algorithm in the reverse direction
diagonalReverseStart = this.ClipDiagonalBound(diagonalReverseBase - numDifferences, numDifferences, diagonalReverseBase, numDiagonals);
diagonalReverseEnd = this.ClipDiagonalBound(diagonalReverseBase + numDifferences, numDifferences, diagonalReverseBase, numDiagonals);
for (diagonal = diagonalReverseStart; diagonal <= diagonalReverseEnd; diagonal += 2) {
for (let diagonal = diagonalReverseStart; diagonal <= diagonalReverseEnd; diagonal += 2) {
// STEP 1: We extend the furthest reaching point in the present diagonal
// by looking at the diagonals above and below and picking the one whose point
// is further away from the start point (originalEnd, modifiedEnd)
@@ -671,7 +731,7 @@ export class LcsDiff {
modifiedIndex = originalIndex - (diagonal - diagonalReverseBase) - diagonalReverseOffset;
// Save the current originalIndex so we can test for false overlap
tempOriginalIndex = originalIndex;
const tempOriginalIndex = originalIndex;
// STEP 2: We can continue to extend the furthest reaching point in the present diagonal
// as long as the elements are equal.
@@ -689,7 +749,7 @@ export class LcsDiff {
midOriginalArr[0] = originalIndex;
midModifiedArr[0] = modifiedIndex;
if (tempOriginalIndex >= forwardPoints[diagonal] && MaxDifferencesHistory > 0 && numDifferences <= (MaxDifferencesHistory + 1)) {
if (tempOriginalIndex >= forwardPoints[diagonal] && LocalConstants.MaxDifferencesHistory > 0 && numDifferences <= (LocalConstants.MaxDifferencesHistory + 1)) {
// BINGO! We overlapped, and we have the full trace in memory!
return this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset,
diagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset,
@@ -708,24 +768,22 @@ export class LcsDiff {
}
// Save current vectors to history before the next iteration
if (numDifferences <= MaxDifferencesHistory) {
if (numDifferences <= LocalConstants.MaxDifferencesHistory) {
// We are allocating space for one extra int, which we fill with
// the index of the diagonal base index
let temp: number[] = new Array<number>(diagonalForwardEnd - diagonalForwardStart + 2);
let temp = new Int32Array(diagonalForwardEnd - diagonalForwardStart + 2);
temp[0] = diagonalForwardBase - diagonalForwardStart + 1;
MyArray.Copy(forwardPoints, diagonalForwardStart, temp, 1, diagonalForwardEnd - diagonalForwardStart + 1);
MyArray.Copy2(forwardPoints, diagonalForwardStart, temp, 1, diagonalForwardEnd - diagonalForwardStart + 1);
this.m_forwardHistory.push(temp);
temp = new Array<number>(diagonalReverseEnd - diagonalReverseStart + 2);
temp = new Int32Array(diagonalReverseEnd - diagonalReverseStart + 2);
temp[0] = diagonalReverseBase - diagonalReverseStart + 1;
MyArray.Copy(reversePoints, diagonalReverseStart, temp, 1, diagonalReverseEnd - diagonalReverseStart + 1);
MyArray.Copy2(reversePoints, diagonalReverseStart, temp, 1, diagonalReverseEnd - diagonalReverseStart + 1);
this.m_reverseHistory.push(temp);
}
}
// If we got here, then we have the full trace in history. We just have to convert it to a change list
// NOTE: This part is a bit messy
return this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset,
@@ -750,8 +808,8 @@ export class LcsDiff {
// Shift all the changes down first
for (let i = 0; i < changes.length; i++) {
const change = changes[i];
const originalStop = (i < changes.length - 1) ? changes[i + 1].originalStart : this.OriginalSequence.getLength();
const modifiedStop = (i < changes.length - 1) ? changes[i + 1].modifiedStart : this.ModifiedSequence.getLength();
const originalStop = (i < changes.length - 1) ? changes[i + 1].originalStart : this._originalElementsOrHash.length;
const modifiedStop = (i < changes.length - 1) ? changes[i + 1].modifiedStart : this._modifiedElementsOrHash.length;
const checkOriginal = change.originalLength > 0;
const checkModified = change.modifiedLength > 0;
@@ -795,8 +853,8 @@ export class LcsDiff {
let bestScore = this._boundaryScore(change.originalStart, change.originalLength, change.modifiedStart, change.modifiedLength);
for (let delta = 1; ; delta++) {
let originalStart = change.originalStart - delta;
let modifiedStart = change.modifiedStart - delta;
const originalStart = change.originalStart - delta;
const modifiedStart = change.modifiedStart - delta;
if (originalStart < originalStop || modifiedStart < modifiedStop) {
break;
@@ -810,7 +868,7 @@ export class LcsDiff {
break;
}
let score = this._boundaryScore(originalStart, change.originalLength, modifiedStart, change.modifiedLength);
const score = this._boundaryScore(originalStart, change.originalLength, modifiedStart, change.modifiedLength);
if (score > bestScore) {
bestScore = score;
@@ -826,11 +884,10 @@ export class LcsDiff {
}
private _OriginalIsBoundary(index: number): boolean {
if (index <= 0 || index >= this.OriginalSequence.getLength() - 1) {
if (index <= 0 || index >= this._originalElementsOrHash.length - 1) {
return true;
}
const element = this.OriginalSequence.getElementAtIndex(index);
return (typeof element === 'string' && /^\s*$/.test(element));
return (this._hasStrings && /^\s*$/.test(this._originalStringElements[index]));
}
private _OriginalRegionIsBoundary(originalStart: number, originalLength: number): boolean {
@@ -838,7 +895,7 @@ export class LcsDiff {
return true;
}
if (originalLength > 0) {
let originalEnd = originalStart + originalLength;
const originalEnd = originalStart + originalLength;
if (this._OriginalIsBoundary(originalEnd - 1) || this._OriginalIsBoundary(originalEnd)) {
return true;
}
@@ -847,11 +904,10 @@ export class LcsDiff {
}
private _ModifiedIsBoundary(index: number): boolean {
if (index <= 0 || index >= this.ModifiedSequence.getLength() - 1) {
if (index <= 0 || index >= this._modifiedElementsOrHash.length - 1) {
return true;
}
const element = this.ModifiedSequence.getElementAtIndex(index);
return (typeof element === 'string' && /^\s*$/.test(element));
return (this._hasStrings && /^\s*$/.test(this._modifiedStringElements[index]));
}
private _ModifiedRegionIsBoundary(modifiedStart: number, modifiedLength: number): boolean {
@@ -859,7 +915,7 @@ export class LcsDiff {
return true;
}
if (modifiedLength > 0) {
let modifiedEnd = modifiedStart + modifiedLength;
const modifiedEnd = modifiedStart + modifiedLength;
if (this._ModifiedIsBoundary(modifiedEnd - 1) || this._ModifiedIsBoundary(modifiedEnd)) {
return true;
}
@@ -868,8 +924,8 @@ export class LcsDiff {
}
private _boundaryScore(originalStart: number, originalLength: number, modifiedStart: number, modifiedLength: number): number {
let originalScore = (this._OriginalRegionIsBoundary(originalStart, originalLength) ? 1 : 0);
let modifiedScore = (this._ModifiedRegionIsBoundary(modifiedStart, modifiedLength) ? 1 : 0);
const originalScore = (this._OriginalRegionIsBoundary(originalStart, originalLength) ? 1 : 0);
const modifiedScore = (this._ModifiedRegionIsBoundary(modifiedStart, modifiedLength) ? 1 : 0);
return (originalScore + modifiedScore);
}
@@ -890,14 +946,14 @@ export class LcsDiff {
// might recurse in the middle of a change thereby splitting it into
// two changes. Here in the combining stage, we detect and fuse those
// changes back together
let result = new Array<DiffChange>(left.length + right.length - 1);
const result = new Array<DiffChange>(left.length + right.length - 1);
MyArray.Copy(left, 0, result, 0, left.length - 1);
result[left.length - 1] = mergedChangeArr[0];
MyArray.Copy(right, 1, result, left.length, right.length - 1);
return result;
} else {
let result = new Array<DiffChange>(left.length + right.length);
const result = new Array<DiffChange>(left.length + right.length);
MyArray.Copy(left, 0, result, 0, left.length);
MyArray.Copy(right, 0, result, left.length, right.length);
@@ -918,9 +974,9 @@ export class LcsDiff {
Debug.Assert(left.modifiedStart <= right.modifiedStart, 'Left change is not less than or equal to right change');
if (left.originalStart + left.originalLength >= right.originalStart || left.modifiedStart + left.modifiedLength >= right.modifiedStart) {
let originalStart = left.originalStart;
const originalStart = left.originalStart;
let originalLength = left.originalLength;
let modifiedStart = left.modifiedStart;
const modifiedStart = left.modifiedStart;
let modifiedLength = left.modifiedLength;
if (left.originalStart + left.originalLength >= right.originalStart) {
@@ -958,15 +1014,15 @@ export class LcsDiff {
// diagonalsBelow: The number of diagonals below the reference diagonal
// diagonalsAbove: The number of diagonals above the reference diagonal
let diagonalsBelow = diagonalBaseIndex;
let diagonalsAbove = numDiagonals - diagonalBaseIndex - 1;
let diffEven = (numDifferences % 2 === 0);
const diagonalsBelow = diagonalBaseIndex;
const diagonalsAbove = numDiagonals - diagonalBaseIndex - 1;
const diffEven = (numDifferences % 2 === 0);
if (diagonal < 0) {
let lowerBoundEven = (diagonalsBelow % 2 === 0);
const lowerBoundEven = (diagonalsBelow % 2 === 0);
return (diffEven === lowerBoundEven) ? 0 : 1;
} else {
let upperBoundEven = (diagonalsAbove % 2 === 0);
const upperBoundEven = (diagonalsAbove % 2 === 0);
return (diffEven === upperBoundEven) ? numDiagonals - 1 : numDiagonals - 2;
}
}

View File

@@ -36,7 +36,7 @@ function booleanHash(b: boolean, initialHashVal: number): number {
return numberHash(b ? 433 : 863, initialHashVal);
}
function stringHash(s: string, hashVal: number) {
export function stringHash(s: string, hashVal: number) {
hashVal = numberHash(149417, hashVal);
for (let i = 0, length = s.length; i < length; i++) {
hashVal = numberHash(s.charCodeAt(i), hashVal);

View File

@@ -7,23 +7,27 @@ import { equals } from 'vs/base/common/arrays';
import { UriComponents } from 'vs/base/common/uri';
export interface IMarkdownString {
value: string;
isTrusted?: boolean;
readonly value: string;
readonly isTrusted?: boolean;
uris?: { [href: string]: UriComponents };
}
export class MarkdownString implements IMarkdownString {
value: string;
isTrusted?: boolean;
private _value: string;
private _isTrusted: boolean;
constructor(value: string = '') {
this.value = value;
constructor(value: string = '', isTrusted = false) {
this._value = value;
this._isTrusted = isTrusted;
}
get value() { return this._value; }
get isTrusted() { return this._isTrusted; }
appendText(value: string): MarkdownString {
// escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
this.value += value
this._value += value
.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&')
.replace('\n', '\n\n');
@@ -31,16 +35,16 @@ export class MarkdownString implements IMarkdownString {
}
appendMarkdown(value: string): MarkdownString {
this.value += value;
this._value += value;
return this;
}
appendCodeblock(langId: string, code: string): MarkdownString {
this.value += '\n```';
this.value += langId;
this.value += '\n';
this.value += code;
this.value += '\n```\n';
this._value += '\n```';
this._value += langId;
this._value += '\n';
this._value += code;
this._value += '\n```\n';
return this;
}
}

View File

@@ -60,7 +60,7 @@ export module Iterator {
};
}
export function fromArray<T>(array: T[], index = 0, length = array.length): Iterator<T> {
export function fromArray<T>(array: ReadonlyArray<T>, index = 0, length = array.length): Iterator<T> {
return {
next(): IteratorResult<T> {
if (index >= length) {

View File

@@ -4,12 +4,11 @@
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import { sep, posix, normalize } from 'vs/base/common/path';
import { sep, posix, normalize, win32 } from 'vs/base/common/path';
import { endsWith, 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, basename, relativePath } from 'vs/base/common/resources';
import { CharCode } from 'vs/base/common/charCode';
export interface IWorkspaceFolderProvider {
getWorkspaceFolder(resource: URI): { uri: URI, name?: string } | null;
@@ -44,7 +43,7 @@ export function getPathLabel(resource: URI | string, userHomeProvider?: IUserHom
}
if (hasMultipleRoots) {
const rootName = (baseResource && baseResource.name) ? baseResource.name : basename(baseResource.uri);
const rootName = baseResource.name ? baseResource.name : basename(baseResource.uri);
pathLabel = pathLabel ? (rootName + ' • ' + pathLabel) : rootName; // always show root basename if there are multiple
}
@@ -388,11 +387,12 @@ export function unmnemonicLabel(label: string): string {
* Splits a path in name and parent path, supporting both '/' and '\'
*/
export function splitName(fullPath: string): { name: string, parentPath: string } {
for (let i = fullPath.length - 1; i >= 1; i--) {
const code = fullPath.charCodeAt(i);
if (code === CharCode.Slash || code === CharCode.Backslash) {
return { parentPath: fullPath.substr(0, i), name: fullPath.substr(i + 1) };
}
const p = fullPath.indexOf('/') !== -1 ? posix : win32;
const name = p.basename(fullPath);
const parentPath = p.dirname(fullPath);
if (name.length) {
return { name, parentPath };
}
return { parentPath: '', name: fullPath };
// only the root segment
return { name: parentPath, parentPath: '' };
}

View File

@@ -0,0 +1,65 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* A value that is resolved synchronously when it is first needed.
*/
export interface Lazy<T> {
hasValue(): boolean;
getValue(): T;
map<R>(f: (x: T) => R): Lazy<R>;
}
export class Lazy<T> {
private _didRun: boolean = false;
private _value?: T;
private _error: any;
constructor(
private readonly executor: () => T,
) { }
/**
* True if the lazy value has been resolved.
*/
hasValue() { return this._didRun; }
/**
* Get the wrapped value.
*
* This will force evaluation of the lazy value if it has not been resolved yet. Lazy values are only
* resolved once. `getValue` will re-throw exceptions that are hit while resolving the value
*/
getValue(): T {
if (!this._didRun) {
try {
this._value = this.executor();
} catch (err) {
this._error = err;
} finally {
this._didRun = true;
}
}
if (this._error) {
throw this._error;
}
return this._value!;
}
/**
* Create a new lazy value that is the result of applying `f` to the wrapped value.
*
* This does not force the evaluation of the current lazy value.
*/
map<R>(f: (x: T) => R): Lazy<R> {
return new Lazy<R>(() => f(this.getValue()));
}
}

View File

@@ -138,7 +138,7 @@ export class DisposableStore implements IDisposable {
export abstract class Disposable implements IDisposable {
static None = Object.freeze<IDisposable>({ dispose() { } });
static readonly None = Object.freeze<IDisposable>({ dispose() { } });
private readonly _store = new DisposableStore();

View File

@@ -117,6 +117,8 @@ export class PathIterator implements IKeyIterator {
private _from!: number;
private _to!: number;
constructor(private _splitOnBackslash: boolean = true) { }
reset(key: string): this {
this._value = key.replace(/\\$|\/$/, '');
this._from = 0;
@@ -134,7 +136,7 @@ export class PathIterator implements IKeyIterator {
let justSeps = true;
for (; this._to < this._value.length; this._to++) {
const ch = this._value.charCodeAt(this._to);
if (ch === CharCode.Slash || ch === CharCode.Backslash) {
if (ch === CharCode.Slash || this._splitOnBackslash && ch === CharCode.Backslash) {
if (justSeps) {
this._from++;
} else {

View File

@@ -56,53 +56,49 @@ export namespace Schemas {
}
class RemoteAuthoritiesImpl {
private readonly _hosts: { [authority: string]: string; };
private readonly _ports: { [authority: string]: number; };
private readonly _connectionTokens: { [authority: string]: string; };
private _preferredWebSchema: 'http' | 'https';
private _delegate: ((uri: URI) => URI) | null;
private readonly _hosts: { [authority: string]: string | undefined; } = Object.create(null);
private readonly _ports: { [authority: string]: number | undefined; } = Object.create(null);
private readonly _connectionTokens: { [authority: string]: string | undefined; } = Object.create(null);
private _preferredWebSchema: 'http' | 'https' = 'http';
private _delegate: ((uri: URI) => URI) | null = null;
constructor() {
this._hosts = Object.create(null);
this._ports = Object.create(null);
this._connectionTokens = Object.create(null);
this._preferredWebSchema = 'http';
this._delegate = null;
}
public setPreferredWebSchema(schema: 'http' | 'https') {
setPreferredWebSchema(schema: 'http' | 'https') {
this._preferredWebSchema = schema;
}
public setDelegate(delegate: (uri: URI) => URI): void {
setDelegate(delegate: (uri: URI) => URI): void {
this._delegate = delegate;
}
public set(authority: string, host: string, port: number): void {
set(authority: string, host: string, port: number): void {
this._hosts[authority] = host;
this._ports[authority] = port;
}
public setConnectionToken(authority: string, connectionToken: string): void {
setConnectionToken(authority: string, connectionToken: string): void {
this._connectionTokens[authority] = connectionToken;
}
public rewrite(uri: URI): URI {
rewrite(uri: URI): URI {
if (this._delegate) {
return this._delegate(uri);
}
const authority = uri.authority;
let host = this._hosts[authority];
if (host.indexOf(':') !== -1) {
if (host && host.indexOf(':') !== -1) {
host = `[${host}]`;
}
const port = this._ports[authority];
const connectionToken = this._connectionTokens[authority];
let query = `path=${encodeURIComponent(uri.path)}`;
if (typeof connectionToken === 'string') {
query += `&tkn=${encodeURIComponent(connectionToken)}`;
}
return URI.from({
scheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource,
authority: `${host}:${port}`,
path: `/vscode-remote-resource`,
query: `path=${encodeURIComponent(uri.path)}&tkn=${encodeURIComponent(connectionToken)}`
query
});
}
}

View File

@@ -1,126 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { matchesFuzzy, IMatch } from 'vs/base/common/filters';
import { ltrim } from 'vs/base/common/strings';
const octiconStartMarker = '$(';
export interface IParsedOcticons {
text: string;
octiconOffsets?: number[];
}
export function parseOcticons(text: string): IParsedOcticons {
const firstOcticonIndex = text.indexOf(octiconStartMarker);
if (firstOcticonIndex === -1) {
return { text }; // return early if the word does not include an octicon
}
return doParseOcticons(text, firstOcticonIndex);
}
function doParseOcticons(text: string, firstOcticonIndex: number): IParsedOcticons {
const octiconOffsets: number[] = [];
let textWithoutOcticons: string = '';
function appendChars(chars: string) {
if (chars) {
textWithoutOcticons += chars;
for (const _ of chars) {
octiconOffsets.push(octiconsOffset); // make sure to fill in octicon offsets
}
}
}
let currentOcticonStart = -1;
let currentOcticonValue: string = '';
let octiconsOffset = 0;
let char: string;
let nextChar: string;
let offset = firstOcticonIndex;
const length = text.length;
// Append all characters until the first octicon
appendChars(text.substr(0, firstOcticonIndex));
// example: $(file-symlink-file) my cool $(other-octicon) entry
while (offset < length) {
char = text[offset];
nextChar = text[offset + 1];
// beginning of octicon: some value $( <--
if (char === octiconStartMarker[0] && nextChar === octiconStartMarker[1]) {
currentOcticonStart = offset;
// if we had a previous potential octicon value without
// the closing ')', it was actually not an octicon and
// so we have to add it to the actual value
appendChars(currentOcticonValue);
currentOcticonValue = octiconStartMarker;
offset++; // jump over '('
}
// end of octicon: some value $(some-octicon) <--
else if (char === ')' && currentOcticonStart !== -1) {
const currentOcticonLength = offset - currentOcticonStart + 1; // +1 to include the closing ')'
octiconsOffset += currentOcticonLength;
currentOcticonStart = -1;
currentOcticonValue = '';
}
// within octicon
else if (currentOcticonStart !== -1) {
currentOcticonValue += char;
}
// any value outside of octicons
else {
appendChars(char);
}
offset++;
}
// if we had a previous potential octicon value without
// the closing ')', it was actually not an octicon and
// so we have to add it to the actual value
appendChars(currentOcticonValue);
return { text: textWithoutOcticons, octiconOffsets };
}
export function matchesFuzzyOcticonAware(query: string, target: IParsedOcticons, enableSeparateSubstringMatching = false): IMatch[] | null {
const { text, octiconOffsets } = target;
// Return early if there are no octicon markers in the word to match against
if (!octiconOffsets || octiconOffsets.length === 0) {
return matchesFuzzy(query, text, enableSeparateSubstringMatching);
}
// Trim the word to match against because it could have leading
// whitespace now if the word started with an octicon
const wordToMatchAgainstWithoutOcticonsTrimmed = ltrim(text, ' ');
const leadingWhitespaceOffset = text.length - wordToMatchAgainstWithoutOcticonsTrimmed.length;
// match on value without octicons
const matches = matchesFuzzy(query, wordToMatchAgainstWithoutOcticonsTrimmed, enableSeparateSubstringMatching);
// Map matches back to offsets with octicons and trimming
if (matches) {
for (const match of matches) {
const octiconOffset = octiconOffsets[match.start + leadingWhitespaceOffset] /* octicon offsets at index */ + leadingWhitespaceOffset /* overall leading whitespace offset */;
match.start += octiconOffset;
match.end += octiconOffset;
}
}
return matches;
}

View File

@@ -169,7 +169,7 @@ function _format(sep: string, pathObject: ParsedPath) {
return dir + sep + base;
}
interface ParsedPath {
export interface ParsedPath {
root: string;
dir: string;
base: string;
@@ -177,7 +177,7 @@ interface ParsedPath {
name: string;
}
interface IPath {
export interface IPath {
normalize(path: string): string;
isAbsolute(path: string): boolean;
join(...paths: string[]): string;

View File

@@ -164,6 +164,34 @@ export const setImmediate: ISetImmediate = (function defineSetImmediate() {
if (globals.setImmediate) {
return globals.setImmediate.bind(globals);
}
if (typeof globals.postMessage === 'function' && !globals.importScripts) {
interface IQueueElement {
id: number;
callback: () => void;
}
let pending: IQueueElement[] = [];
globals.addEventListener('message', (e: MessageEvent) => {
if (e.data && e.data.vscodeSetImmediateId) {
for (let i = 0, len = pending.length; i < len; i++) {
const candidate = pending[i];
if (candidate.id === e.data.vscodeSetImmediateId) {
pending.splice(i, 1);
candidate.callback();
return;
}
}
}
});
let lastId = 0;
return (callback: () => void) => {
const myId = ++lastId;
pending.push({
id: myId,
callback: callback
});
globals.postMessage({ vscodeSetImmediateId: myId });
};
}
if (typeof process !== 'undefined' && typeof process.nextTick === 'function') {
return process.nextTick.bind(process);
}

View File

@@ -9,93 +9,77 @@ import { Iterator } from 'vs/base/common/iterator';
import { relativePath, joinPath } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { mapValues } from 'vs/base/common/collections';
import { PathIterator } from 'vs/base/common/map';
export interface ILeafNode<T, C = void> {
export interface IResourceNode<T, C = void> {
readonly uri: URI;
readonly relativePath: string;
readonly name: string;
readonly element: T;
readonly element: T | undefined;
readonly children: Iterator<IResourceNode<T, C>>;
readonly childrenCount: number;
readonly parent: IResourceNode<T, C> | undefined;
readonly context: C;
get(childName: string): IResourceNode<T, C> | undefined;
}
export interface IBranchNode<T, C = void> {
readonly uri: URI;
readonly relativePath: string;
readonly name: string;
readonly size: number;
readonly children: Iterator<INode<T, C>>;
readonly parent: IBranchNode<T, C> | undefined;
readonly context: C;
get(childName: string): INode<T, C> | undefined;
}
class Node<T, C> implements IResourceNode<T, C> {
export type INode<T, C> = IBranchNode<T, C> | ILeafNode<T, C>;
private _children = new Map<string, Node<T, C>>();
// Internals
class Node<C> {
@memoize
get name(): string { return paths.posix.basename(this.relativePath); }
constructor(readonly uri: URI, readonly relativePath: string, readonly context: C) { }
}
class BranchNode<T, C> extends Node<C> implements IBranchNode<T, C> {
private _children = new Map<string, BranchNode<T, C> | LeafNode<T, C>>();
get size(): number {
get childrenCount(): number {
return this._children.size;
}
get children(): Iterator<BranchNode<T, C> | LeafNode<T, C>> {
get children(): Iterator<Node<T, C>> {
return Iterator.fromArray(mapValues(this._children));
}
constructor(uri: URI, relativePath: string, context: C, readonly parent: IBranchNode<T, C> | undefined = undefined) {
super(uri, relativePath, context);
@memoize
get name(): string {
return paths.posix.basename(this.relativePath);
}
get(path: string): BranchNode<T, C> | LeafNode<T, C> | undefined {
constructor(
readonly uri: URI,
readonly relativePath: string,
readonly context: C,
public element: T | undefined = undefined,
readonly parent: IResourceNode<T, C> | undefined = undefined
) { }
get(path: string): Node<T, C> | undefined {
return this._children.get(path);
}
set(path: string, child: BranchNode<T, C> | LeafNode<T, C>): void {
set(path: string, child: Node<T, C>): void {
this._children.set(path, child);
}
delete(path: string): void {
this._children.delete(path);
}
}
class LeafNode<T, C> extends Node<C> implements ILeafNode<T, C> {
constructor(uri: URI, path: string, context: C, readonly element: T) {
super(uri, path, context);
clear(): void {
this._children.clear();
}
}
function collect<T, C>(node: INode<T, C>, result: T[]): T[] {
if (ResourceTree.isBranchNode(node)) {
Iterator.forEach(node.children, child => collect(child, result));
} else {
function collect<T, C>(node: IResourceNode<T, C>, result: T[]): T[] {
if (typeof node.element !== 'undefined') {
result.push(node.element);
}
Iterator.forEach(node.children, child => collect(child, result));
return result;
}
export class ResourceTree<T extends NonNullable<any>, C> {
readonly root: BranchNode<T, C>;
readonly root: Node<T, C>;
static isBranchNode<T, C>(obj: any): obj is IBranchNode<T, C> {
return obj instanceof BranchNode;
}
static getRoot<T, C>(node: IBranchNode<T, C>): IBranchNode<T, C> {
static getRoot<T, C>(node: IResourceNode<T, C>): IResourceNode<T, C> {
while (node.parent) {
node = node.parent;
}
@@ -103,89 +87,101 @@ export class ResourceTree<T extends NonNullable<any>, C> {
return node;
}
static collect<T, C>(node: INode<T, C>): T[] {
static collect<T, C>(node: IResourceNode<T, C>): T[] {
return collect(node, []);
}
static isResourceNode<T, C>(obj: any): obj is IResourceNode<T, C> {
return obj instanceof Node;
}
constructor(context: C, rootURI: URI = URI.file('/')) {
this.root = new BranchNode(rootURI, '', context);
this.root = new Node(rootURI, '', context);
}
add(uri: URI, element: T): void {
const key = relativePath(this.root.uri, uri) || uri.fsPath;
const parts = key.split(/[\\\/]/).filter(p => !!p);
const iterator = new PathIterator(false).reset(key);
let node = this.root;
let path = '';
for (let i = 0; i < parts.length; i++) {
const name = parts[i];
while (true) {
const name = iterator.value();
path = path + '/' + name;
let child = node.get(name);
if (!child) {
if (i < parts.length - 1) {
child = new BranchNode(joinPath(this.root.uri, path), path, this.root.context, node);
node.set(name, child);
} else {
child = new LeafNode(uri, path, this.root.context, element);
node.set(name, child);
return;
}
}
child = new Node(
joinPath(this.root.uri, path),
path,
this.root.context,
iterator.hasNext() ? undefined : element,
node
);
if (!(child instanceof BranchNode)) {
if (i < parts.length - 1) {
throw new Error('Inconsistent tree: can\'t override leaf with branch.');
}
// replace
node.set(name, new LeafNode(uri, path, this.root.context, element));
return;
} else if (i === parts.length - 1) {
throw new Error('Inconsistent tree: can\'t override branch with leaf.');
node.set(name, child);
} else if (!iterator.hasNext()) {
child.element = element;
}
node = child;
if (!iterator.hasNext()) {
return;
}
iterator.next();
}
}
delete(uri: URI): T | undefined {
const key = relativePath(this.root.uri, uri) || uri.fsPath;
const parts = key.split(/[\\\/]/).filter(p => !!p);
return this._delete(this.root, parts, 0);
const iterator = new PathIterator(false).reset(key);
return this._delete(this.root, iterator);
}
private _delete(node: BranchNode<T, C>, parts: string[], index: number): T | undefined {
const name = parts[index];
private _delete(node: Node<T, C>, iterator: PathIterator): T | undefined {
const name = iterator.value();
const child = node.get(name);
if (!child) {
return undefined;
}
// not at end
if (index < parts.length - 1) {
if (child instanceof BranchNode) {
const result = this._delete(child, parts, index + 1);
if (iterator.hasNext()) {
const result = this._delete(child, iterator.next());
if (typeof result !== 'undefined' && child.size === 0) {
node.delete(name);
}
return result;
} else {
throw new Error('Inconsistent tree: Expected a branch, found a leaf instead.');
if (typeof result !== 'undefined' && child.childrenCount === 0) {
node.delete(name);
}
}
//at end
if (child instanceof BranchNode) {
// TODO: maybe we can allow this
throw new Error('Inconsistent tree: Expected a leaf, found a branch instead.');
return result;
}
node.delete(name);
return child.element;
}
clear(): void {
this.root.clear();
}
getNode(uri: URI): IResourceNode<T, C> | undefined {
const key = relativePath(this.root.uri, uri) || uri.fsPath;
const iterator = new PathIterator(false).reset(key);
let node = this.root;
while (true) {
const name = iterator.value();
const child = node.get(name);
if (!child || !iterator.hasNext()) {
return child;
}
node = child;
iterator.next();
}
}
}

View File

@@ -7,20 +7,19 @@ import * as strings from './strings';
export function buildReplaceStringWithCasePreserved(matches: string[] | null, pattern: string): string {
if (matches && (matches[0] !== '')) {
const containsHyphens = validateSpecificSpecialCharacter(matches, pattern, '-');
const containsUnderscores = validateSpecificSpecialCharacter(matches, pattern, '_');
if (containsHyphens && !containsUnderscores) {
return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '-');
} else if (!containsHyphens && containsUnderscores) {
return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '_');
}
if (matches[0].toUpperCase() === matches[0]) {
return pattern.toUpperCase();
} else if (matches[0].toLowerCase() === matches[0]) {
return pattern.toLowerCase();
} else if (strings.containsUppercaseCharacter(matches[0][0])) {
const containsHyphens = validateSpecificSpecialCharacter(matches, pattern, '-');
const containsUnderscores = validateSpecificSpecialCharacter(matches, pattern, '_');
if (containsHyphens && !containsUnderscores) {
return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '-');
} else if (!containsHyphens && containsUnderscores) {
return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '_');
} else {
return pattern[0].toUpperCase() + pattern.substr(1);
}
return pattern[0].toUpperCase() + pattern.substr(1);
} else {
// we don't understand its pattern yet.
return pattern;

View File

@@ -350,21 +350,10 @@ function isAsciiLetter(code: number): boolean {
}
export function equalsIgnoreCase(a: string, b: string): boolean {
const len1 = a ? a.length : 0;
const len2 = b ? b.length : 0;
if (len1 !== len2) {
return false;
}
return doEqualsIgnoreCase(a, b);
return a.length === b.length && doEqualsIgnoreCase(a, b);
}
function doEqualsIgnoreCase(a: string, b: string, stopAt = a.length): boolean {
if (typeof a !== 'string' || typeof b !== 'string') {
return false;
}
for (let i = 0; i < stopAt; i++) {
const codeA = a.charCodeAt(i);
const codeB = b.charCodeAt(i);

View File

@@ -93,6 +93,39 @@ export function isUndefinedOrNull(obj: any): obj is undefined | null {
return isUndefined(obj) || obj === null;
}
/**
* Asserts that the argument passed in is neither undefined nor null.
*/
export function assertIsDefined<T>(arg: T | null | undefined): T {
if (isUndefinedOrNull(arg)) {
throw new Error('Assertion Failed: argument is undefined or null');
}
return arg;
}
/**
* Asserts that each argument passed in is neither undefined nor null.
*/
export function assertAllDefined<T1, T2>(t1: T1 | null | undefined, t2: T2 | null | undefined): [T1, T2];
export function assertAllDefined<T1, T2, T3>(t1: T1 | null | undefined, t2: T2 | null | undefined, t3: T3 | null | undefined): [T1, T2, T3];
export function assertAllDefined<T1, T2, T3, T4>(t1: T1 | null | undefined, t2: T2 | null | undefined, t3: T3 | null | undefined, t4: T4 | null | undefined): [T1, T2, T3, T4];
export function assertAllDefined(...args: (unknown | null | undefined)[]): unknown[] {
const result = [];
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (isUndefinedOrNull(arg)) {
throw new Error(`Assertion Failed: argument at index ${i} is undefined or null`);
}
result.push(arg);
}
return result;
}
const hasOwnProperty = Object.prototype.hasOwnProperty;
/**

View File

@@ -0,0 +1,68 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export const enum Constants {
/**
* MAX SMI (SMall Integer) as defined in v8.
* one bit is lost for boxing/unboxing flag.
* one bit is lost for sign flag.
* See https://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/#tagged-values
*/
MAX_SAFE_SMALL_INTEGER = 1 << 30,
/**
* MIN SMI (SMall Integer) as defined in v8.
* one bit is lost for boxing/unboxing flag.
* one bit is lost for sign flag.
* See https://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/#tagged-values
*/
MIN_SAFE_SMALL_INTEGER = -(1 << 30),
/**
* Max unsigned integer that fits on 8 bits.
*/
MAX_UINT_8 = 255, // 2^8 - 1
/**
* Max unsigned integer that fits on 16 bits.
*/
MAX_UINT_16 = 65535, // 2^16 - 1
/**
* Max unsigned integer that fits on 32 bits.
*/
MAX_UINT_32 = 4294967295, // 2^32 - 1
}
export function toUint8(v: number): number {
if (v < 0) {
return 0;
}
if (v > Constants.MAX_UINT_8) {
return Constants.MAX_UINT_8;
}
return v | 0;
}
export function toUint32(v: number): number {
if (v < 0) {
return 0;
}
if (v > Constants.MAX_UINT_32) {
return Constants.MAX_UINT_32;
}
return v | 0;
}
export function toUint32Array(arr: number[]): Uint32Array {
const len = arr.length;
const r = new Uint32Array(len);
for (let i = 0; i < len; i++) {
r[i] = toUint32(arr[i]);
}
return r;
}

View File

@@ -10,26 +10,11 @@ const _schemePattern = /^\w[\w\d+.-]*$/;
const _singleSlashStart = /^\//;
const _doubleSlashStart = /^\/\//;
let _throwOnMissingSchema: boolean = true;
/**
* @internal
*/
export function setUriThrowOnMissingScheme(value: boolean): boolean {
const old = _throwOnMissingSchema;
_throwOnMissingSchema = value;
return old;
}
function _validateUri(ret: URI, _strict?: boolean): void {
function _validateUri(ret: URI): void {
// scheme, must be set
if (!ret.scheme) {
if (_strict || _throwOnMissingSchema) {
throw new Error(`[UriError]: Scheme is missing: {scheme: "", authority: "${ret.authority}", path: "${ret.path}", query: "${ret.query}", fragment: "${ret.fragment}"}`);
} else {
console.warn(`[UriError]: Scheme is missing: {scheme: "", authority: "${ret.authority}", path: "${ret.path}", query: "${ret.query}", fragment: "${ret.fragment}"}`);
}
throw new Error(`[UriError]: Scheme is missing: {scheme: "", authority: "${ret.authority}", path: "${ret.path}", query: "${ret.query}", fragment: "${ret.fragment}"}`);
}
// scheme, https://tools.ietf.org/html/rfc3986#section-3.1
@@ -56,14 +41,8 @@ function _validateUri(ret: URI, _strict?: boolean): void {
}
}
// for a while we allowed uris *without* schemes and this is the migration
// for them, e.g. an uri without scheme and without strict-mode warns and falls
// back to the file-scheme. that should cause the least carnage and still be a
// clear warning
function _schemeFix(scheme: string, _strict: boolean): string {
if (_strict || _throwOnMissingSchema) {
return scheme || _empty;
}
// graceful behaviour when scheme is missing: fallback to using 'file'-scheme
function _schemeFix(scheme: string): string {
if (!scheme) {
console.trace('BAD uri lacks scheme, falling back to file-scheme.');
scheme = 'file';
@@ -159,7 +138,7 @@ export class URI implements UriComponents {
/**
* @internal
*/
protected constructor(scheme: string, authority?: string, path?: string, query?: string, fragment?: string, _strict?: boolean);
protected constructor(scheme: string, authority?: string, path?: string, query?: string, fragment?: string);
/**
* @internal
@@ -169,7 +148,7 @@ export class URI implements UriComponents {
/**
* @internal
*/
protected constructor(schemeOrData: string | UriComponents, authority?: string, path?: string, query?: string, fragment?: string, _strict: boolean = false) {
protected constructor(schemeOrData: string | UriComponents, authority?: string, path?: string, query?: string, fragment?: string) {
if (typeof schemeOrData === 'object') {
this.scheme = schemeOrData.scheme || _empty;
@@ -181,13 +160,13 @@ export class URI implements UriComponents {
// that creates uri components.
// _validateUri(this);
} else {
this.scheme = _schemeFix(schemeOrData, _strict);
this.scheme = _schemeFix(schemeOrData);
this.authority = authority || _empty;
this.path = _referenceResolution(this.scheme, path || _empty);
this.query = query || _empty;
this.fragment = fragment || _empty;
_validateUri(this, _strict);
_validateUri(this);
}
}
@@ -226,7 +205,7 @@ export class URI implements UriComponents {
// ---- modify to new -------------------------
with(change: { scheme?: string; authority?: string | null; path?: string | null; query?: string | null; fragment?: string | null }): URI {
with(change: { scheme?: string; authority?: string | null; path?: string | null; query?: string | null; fragment?: string | null; }): URI {
if (!change) {
return this;
@@ -279,7 +258,7 @@ export class URI implements UriComponents {
*
* @param value A string which represents an URI (see `URI#toString`).
*/
static parse(value: string, _strict: boolean = false): URI {
static parse(value: string): URI {
const match = _regexp.exec(value);
if (!match) {
return new _URI(_empty, _empty, _empty, _empty, _empty);
@@ -289,8 +268,7 @@ export class URI implements UriComponents {
decodeURIComponent(match[4] || _empty),
decodeURIComponent(match[5] || _empty),
decodeURIComponent(match[7] || _empty),
decodeURIComponent(match[9] || _empty),
_strict
decodeURIComponent(match[9] || _empty)
);
}
@@ -342,7 +320,7 @@ export class URI implements UriComponents {
return new _URI('file', authority, path, _empty, _empty);
}
static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string }): URI {
static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string; }): URI {
return new _URI(
components.scheme,
components.authority,
@@ -467,7 +445,7 @@ class _URI extends URI {
}
// reserved characters: https://tools.ietf.org/html/rfc3986#section-2.2
const encodeTable: { [ch: number]: string } = {
const encodeTable: { [ch: number]: string; } = {
[CharCode.Colon]: '%3A', // gen-delims
[CharCode.Slash]: '%2F',
[CharCode.QuestionMark]: '%3F',