Merge from vscode ad407028575a77ea387eb7cc219b323dc017b686

This commit is contained in:
ADS Merger
2020-08-22 06:06:52 +00:00
committed by Anthony Dresser
parent 404260b8a0
commit 4ad73d381c
480 changed files with 14360 additions and 14122 deletions

View File

@@ -256,7 +256,12 @@ export class Separator extends Action {
export type SubmenuActions = IAction[] | (() => IAction[]);
export class SubmenuAction extends Action {
constructor(id: string, label: string, readonly actions: SubmenuActions, cssClass?: string) {
get actions(): IAction[] {
return Array.isArray(this._actions) ? this._actions : this._actions();
}
constructor(id: string, label: string, private _actions: SubmenuActions, cssClass?: string) {
super(id, label, cssClass, true);
}
}

View File

@@ -590,6 +590,9 @@ export function asArray<T>(x: T | T[]): T[] {
return Array.isArray(x) ? x : [x];
}
/**
* @deprecated Use `Array.from` or `[...iter]`
*/
export function toArray<T>(iterable: IterableIterator<T>): T[] {
const result: T[] = [];
for (let element of iterable) {

View File

@@ -33,8 +33,7 @@ const intlFileNameCollatorNumericCaseInsenstive: IdleValue<{ collator: Intl.Coll
return {
collator: collator
};
});
});/** Compares filenames without distinguishing the name from the extension. Disambiguates by unicode comparison. */
export function compareFileNames(one: string | null, other: string | null, caseSensitive = false): number {
const a = one || '';
const b = other || '';
@@ -49,36 +48,16 @@ export function compareFileNames(one: string | null, other: string | null, caseS
return result;
}
/** Compares filenames by name then extension, sorting numbers numerically instead of alphabetically. */
export function compareFileNamesNumeric(one: string | null, other: string | null): number {
const [oneName, oneExtension] = extractNameAndExtension(one, true);
const [otherName, otherExtension] = extractNameAndExtension(other, true);
/** Compares filenames without distinguishing the name from the extension. Disambiguates by length, not unicode comparison. */
export function compareFileNamesDefault(one: string | null, other: string | null): number {
const collatorNumeric = intlFileNameCollatorNumeric.value.collator;
const collatorNumericCaseInsensitive = intlFileNameCollatorNumericCaseInsenstive.value.collator;
let result;
one = one || '';
other = other || '';
// Check for name differences, comparing numbers numerically instead of alphabetically.
result = compareAndDisambiguateByLength(collatorNumeric, oneName, otherName);
if (result !== 0) {
return result;
}
// Check for case insensitive extension differences, comparing numbers numerically instead of alphabetically.
result = compareAndDisambiguateByLength(collatorNumericCaseInsensitive, oneExtension, otherExtension);
if (result !== 0) {
return result;
}
// Disambiguate the extension case if needed.
if (oneExtension !== otherExtension) {
return collatorNumeric.compare(oneExtension, otherExtension);
}
return 0;
// Compare the entire filename - both name and extension - and disambiguate by length if needed
return compareAndDisambiguateByLength(collatorNumeric, one, other);
}
const FileNameMatch = /^(.*?)(\.([^.]*))?$/;
export function noIntlCompareFileNames(one: string | null, other: string | null, caseSensitive = false): number {
if (!caseSensitive) {
one = one && one.toLowerCase();
@@ -123,10 +102,12 @@ export function compareFileExtensions(one: string | null, other: string | null):
return result;
}
/** Compares filenames by extenson, then by name. Sorts numbers numerically, not alphabetically. */
export function compareFileExtensionsNumeric(one: string | null, other: string | null): number {
const [oneName, oneExtension] = extractNameAndExtension(one, true);
const [otherName, otherExtension] = extractNameAndExtension(other, true);
/** Compares filenames by extenson, then by full filename */
export function compareFileExtensionsDefault(one: string | null, other: string | null): number {
one = one || '';
other = other || '';
const oneExtension = extractExtension(one);
const otherExtension = extractExtension(other);
const collatorNumeric = intlFileNameCollatorNumeric.value.collator;
const collatorNumericCaseInsensitive = intlFileNameCollatorNumericCaseInsenstive.value.collator;
let result;
@@ -137,20 +118,12 @@ export function compareFileExtensionsNumeric(one: string | null, other: string |
return result;
}
// Compare names.
result = compareAndDisambiguateByLength(collatorNumeric, oneName, otherName);
if (result !== 0) {
return result;
}
// Disambiguate extension case if needed.
if (oneExtension !== otherExtension) {
return collatorNumeric.compare(oneExtension, otherExtension);
}
return 0;
// Compare full filenames
return compareAndDisambiguateByLength(collatorNumeric, one, other);
}
const FileNameMatch = /^(.*?)(\.([^.]*))?$/;
/** Extracts the name and extension from a full filename, with optional special handling for dotfiles */
function extractNameAndExtension(str?: string | null, dotfilesAsNames = false): [string, string] {
const match = str ? FileNameMatch.exec(str) as Array<string> : ([] as Array<string>);
@@ -166,6 +139,13 @@ function extractNameAndExtension(str?: string | null, dotfilesAsNames = false):
return result;
}
/** Extracts the extension from a full filename. Treats dotfiles as names, not extensions. */
function extractExtension(str?: string | null): string {
const match = str ? FileNameMatch.exec(str) as Array<string> : ([] as Array<string>);
return (match && match[1] && match[1].charAt(0) !== '.' && match[3]) || '';
}
function compareAndDisambiguateByLength(collator: Intl.Collator, one: string, other: string) {
// Check for differences
let result = collator.compare(one, other);

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { compareAnything } from 'vs/base/common/comparers';
import { matchesPrefix, IMatch, matchesCamelCase, isUpper, fuzzyScore, createMatches as createFuzzyMatches, matchesStrictPrefix } from 'vs/base/common/filters';
import { matchesPrefix, IMatch, isUpper, fuzzyScore, createMatches as createFuzzyMatches, matchesStrictPrefix } from 'vs/base/common/filters';
import { sep } from 'vs/base/common/path';
import { isWindows, isLinux } from 'vs/base/common/platform';
import { stripWildcards, equalsIgnoreCase } from 'vs/base/common/strings';
@@ -168,7 +168,7 @@ function computeCharScore(queryCharAtIndex: string, queryLowerCharAtIndex: strin
score += 1;
// if (DEBUG) {
// console.groupCollapsed(`%cCharacter match bonus: +1 (char: ${queryLower[queryIndex]} at index ${targetIndex}, total score: ${score})`, 'font-weight: normal');
// console.groupCollapsed(`%cCharacter match bonus: +1 (char: ${queryLowerCharAtIndex} at index ${targetIndex}, total score: ${score})`, 'font-weight: normal');
// }
// Consecutive match bonus
@@ -176,7 +176,7 @@ function computeCharScore(queryCharAtIndex: string, queryLowerCharAtIndex: strin
score += (matchesSequenceLength * 5);
// if (DEBUG) {
// console.log('Consecutive match bonus: ' + (matchesSequenceLength * 5));
// console.log(`Consecutive match bonus: +${matchesSequenceLength * 5}`);
// }
}
@@ -206,16 +206,16 @@ function computeCharScore(queryCharAtIndex: string, queryLowerCharAtIndex: strin
score += separatorBonus;
// if (DEBUG) {
// console.log('After separtor bonus: +4');
// console.log(`After separtor bonus: +${separatorBonus}`);
// }
}
// Inside word upper case bonus (camel case)
else if (isUpper(target.charCodeAt(targetIndex))) {
score += 1;
score += 2;
// if (DEBUG) {
// console.log('Inside word upper case bonus: +1');
// console.log('Inside word upper case bonus: +2');
// }
}
}
@@ -371,8 +371,7 @@ export interface IItemAccessor<T> {
const PATH_IDENTITY_SCORE = 1 << 18;
const LABEL_PREFIX_SCORE_MATCHCASE = 1 << 17;
const LABEL_PREFIX_SCORE_IGNORECASE = 1 << 16;
const LABEL_CAMELCASE_SCORE = 1 << 15;
const LABEL_SCORE_THRESHOLD = 1 << 14;
const LABEL_SCORE_THRESHOLD = 1 << 15;
export function scoreItemFuzzy<T>(item: T, query: IPreparedQuery, fuzzy: boolean, accessor: IItemAccessor<T>, cache: FuzzyScorerCache): IItemScore {
if (!item || !query.normalized) {
@@ -386,11 +385,17 @@ export function scoreItemFuzzy<T>(item: T, query: IPreparedQuery, fuzzy: boolean
const description = accessor.getItemDescription(item);
// in order to speed up scoring, we cache the score with a unique hash based on:
// - label
// - description (if provided)
// - query (normalized)
// - number of query pieces (i.e. 'hello world' and 'helloworld' are different)
// - wether fuzzy matching is enabled or not
let cacheHash: string;
if (description) {
cacheHash = `${label}${description}${query.normalized}${fuzzy}`;
cacheHash = `${label}${description}${query.normalized}${Array.isArray(query.values) ? query.values.length : ''}${fuzzy}`;
} else {
cacheHash = `${label}${query.normalized}${fuzzy}`;
cacheHash = `${label}${query.normalized}${Array.isArray(query.values) ? query.values.length : ''}${fuzzy}`;
}
const cached = cache[cacheHash];
@@ -465,13 +470,7 @@ function doScoreItemFuzzySingle(label: string, description: string | undefined,
return { score: prefixLabelMatchStrictCase ? LABEL_PREFIX_SCORE_MATCHCASE : LABEL_PREFIX_SCORE_IGNORECASE, labelMatch: prefixLabelMatchStrictCase || prefixLabelMatchIgnoreCase };
}
// Treat camelcase matches on the label second highest
const camelcaseLabelMatch = matchesCamelCase(query.normalized, label);
if (camelcaseLabelMatch) {
return { score: LABEL_CAMELCASE_SCORE, labelMatch: camelcaseLabelMatch };
}
// Prefer scores on the label if any
// Second, score fuzzy
const [labelScore, labelPositions] = scoreFuzzy(label, query.normalized, query.normalizedLowercase, fuzzy);
if (labelScore) {
return { score: labelScore + LABEL_SCORE_THRESHOLD, labelMatch: createMatches(labelPositions) };
@@ -594,7 +593,7 @@ export function compareItemsByFuzzyScore<T>(itemA: T, itemB: T, query: IPrepared
const scoreA = itemScoreA.score;
const scoreB = itemScoreB.score;
// 1.) prefer identity matches
// 1.) identity matches have highest score
if (scoreA === PATH_IDENTITY_SCORE || scoreB === PATH_IDENTITY_SCORE) {
if (scoreA !== scoreB) {
return scoreA === PATH_IDENTITY_SCORE ? -1 : 1;
@@ -631,44 +630,32 @@ export function compareItemsByFuzzyScore<T>(itemA: T, itemB: T, query: IPrepared
}
}
// 4.) prefer camelcase matches
if (scoreA === LABEL_CAMELCASE_SCORE || scoreB === LABEL_CAMELCASE_SCORE) {
// 4.) matches on label are considered higher compared to label+description matches
if (scoreA > LABEL_SCORE_THRESHOLD || scoreB > LABEL_SCORE_THRESHOLD) {
if (scoreA !== scoreB) {
return scoreA === LABEL_CAMELCASE_SCORE ? -1 : 1;
return scoreA > scoreB ? -1 : 1;
}
const labelA = accessor.getItemLabel(itemA) || '';
const labelB = accessor.getItemLabel(itemB) || '';
// prefer more compact camel case matches over longer
// prefer more compact matches over longer in label
const comparedByMatchLength = compareByMatchLength(itemScoreA.labelMatch, itemScoreB.labelMatch);
if (comparedByMatchLength !== 0) {
return comparedByMatchLength;
}
// prefer shorter names when both match on label camelcase
// prefer shorter labels over longer labels
const labelA = accessor.getItemLabel(itemA) || '';
const labelB = accessor.getItemLabel(itemB) || '';
if (labelA.length !== labelB.length) {
return labelA.length - labelB.length;
}
}
// 5.) prefer label scores
if (scoreA > LABEL_SCORE_THRESHOLD || scoreB > LABEL_SCORE_THRESHOLD) {
if (scoreB < LABEL_SCORE_THRESHOLD) {
return -1;
}
if (scoreA < LABEL_SCORE_THRESHOLD) {
return 1;
}
}
// 6.) compare by score
// 5.) compare by score in label+description
if (scoreA !== scoreB) {
return scoreA > scoreB ? -1 : 1;
}
// 7.) prefer matches in label over non-label matches
// 6.) scores are identical: prefer matches in label over non-label matches
const itemAHasLabelMatches = Array.isArray(itemScoreA.labelMatch) && itemScoreA.labelMatch.length > 0;
const itemBHasLabelMatches = Array.isArray(itemScoreB.labelMatch) && itemScoreB.labelMatch.length > 0;
if (itemAHasLabelMatches && !itemBHasLabelMatches) {
@@ -677,15 +664,14 @@ export function compareItemsByFuzzyScore<T>(itemA: T, itemB: T, query: IPrepared
return 1;
}
// 8.) scores are identical, prefer more compact matches (label and description)
// 7.) scores are identical: prefer more compact matches (label and description)
const itemAMatchDistance = computeLabelAndDescriptionMatchDistance(itemA, itemScoreA, accessor);
const itemBMatchDistance = computeLabelAndDescriptionMatchDistance(itemB, itemScoreB, accessor);
if (itemAMatchDistance && itemBMatchDistance && itemAMatchDistance !== itemBMatchDistance) {
return itemBMatchDistance > itemAMatchDistance ? -1 : 1;
}
// 9.) at this point, scores are identical and match compactness as well
// for both items so we start to use the fallback compare
// 8.) scores are identical: start to use the fallback compare
return fallbackCompare(itemA, itemB, query, accessor);
}

View File

@@ -8,7 +8,12 @@ import * as strings from 'vs/base/common/strings';
/**
* Return a hash value for an object.
*/
export function hash(obj: any, hashVal = 0): number {
export function hash(obj: any): number {
return doHash(obj, 0);
}
export function doHash(obj: any, hashVal: number): number {
switch (typeof obj) {
case 'object':
if (obj === null) {
@@ -24,9 +29,9 @@ export function hash(obj: any, hashVal = 0): number {
case 'number':
return numberHash(obj, hashVal);
case 'undefined':
return numberHash(0, 937);
return numberHash(937, hashVal);
default:
return numberHash(0, 617);
return numberHash(617, hashVal);
}
}
@@ -48,14 +53,14 @@ export function stringHash(s: string, hashVal: number) {
function arrayHash(arr: any[], initialHashVal: number): number {
initialHashVal = numberHash(104579, initialHashVal);
return arr.reduce((hashVal, item) => hash(item, hashVal), initialHashVal);
return arr.reduce((hashVal, item) => doHash(item, hashVal), initialHashVal);
}
function objectHash(obj: any, initialHashVal: number): number {
initialHashVal = numberHash(181387, initialHashVal);
return Object.keys(obj).sort().reduce((hashVal, key) => {
hashVal = stringHash(key, hashVal);
return hash(obj[key], hashVal);
return doHash(obj[key], hashVal);
}, initialHashVal);
}
@@ -68,7 +73,7 @@ export class Hasher {
}
hash(obj: any): number {
this._value = hash(obj, this._value);
this._value = doHash(obj, this._value);
return this._value;
}
}

View File

@@ -45,6 +45,14 @@ function trackDisposable<T extends IDisposable>(x: T): T {
return x;
}
export class MultiDisposeError extends Error {
constructor(
public readonly errors: any[]
) {
super(`Encounter errors while disposing of store. Errors: [${errors.join(', ')}]`);
}
}
export interface IDisposable {
dispose(): void;
}
@@ -60,12 +68,25 @@ export function dispose<T extends IDisposable>(disposables: Array<T>): Array<T>;
export function dispose<T extends IDisposable>(disposables: ReadonlyArray<T>): ReadonlyArray<T>;
export function dispose<T extends IDisposable>(arg: T | IterableIterator<T> | undefined): any {
if (Iterable.is(arg)) {
for (let d of arg) {
let errors: any[] = [];
for (const d of arg) {
if (d) {
markTracked(d);
d.dispose();
try {
d.dispose();
} catch (e) {
errors.push(e);
}
}
}
if (errors.length === 1) {
throw errors[0];
} else if (errors.length > 1) {
throw new MultiDisposeError(errors);
}
return Array.isArray(arg) ? [] : arg;
} else if (arg) {
markTracked(arg);
@@ -116,8 +137,11 @@ export class DisposableStore implements IDisposable {
* Dispose of all registered disposables but do not mark this object as disposed.
*/
public clear(): void {
this._toDispose.forEach(item => item.dispose());
this._toDispose.clear();
try {
dispose(this._toDispose.values());
} finally {
this._toDispose.clear();
}
}
public add<T extends IDisposable>(t: T): T {

File diff suppressed because it is too large Load Diff

View File

@@ -58,6 +58,8 @@ export namespace Schemas {
export const vscodeNotebook = 'vscode-notebook';
export const vscodeNotebookCell = 'vscode-notebook-cell';
export const vscodeSettings = 'vscode-settings';
export const webviewPanel = 'webview-panel';

View File

@@ -855,10 +855,6 @@ export function stripUTF8BOM(str: string): string {
return startsWithUTF8BOM(str) ? str.substr(1) : str;
}
export function safeBtoa(str: string): string {
return btoa(encodeURIComponent(str)); // we use encodeURIComponent because btoa fails for non Latin 1 values
}
/**
* @deprecated ES6
*/