Merge from vscode 7eaf220cafb9d9e901370ffce02229171cbf3ea6

This commit is contained in:
ADS Merger
2020-09-03 02:34:56 +00:00
committed by Anthony Dresser
parent 39d9eed585
commit a63578e6f7
519 changed files with 14338 additions and 6670 deletions

View File

@@ -590,17 +590,6 @@ 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) {
result.push(element);
}
return result;
}
export function getRandomElement<T>(arr: T[]): T | undefined {
return arr[Math.floor(Math.random() * arr.length)];
}

View File

@@ -170,6 +170,25 @@ export class Sequencer {
}
}
export class SequencerByKey<TKey> {
private promiseMap = new Map<TKey, Promise<any>>();
queue<T>(key: TKey, promiseTask: ITask<Promise<T>>): Promise<T> {
const runningPromise = this.promiseMap.get(key) ?? Promise.resolve();
const newPromise = runningPromise
.catch(() => { })
.then(promiseTask)
.finally(() => {
if (this.promiseMap.get(key) === newPromise) {
this.promiseMap.delete(key);
}
});
this.promiseMap.set(key, newPromise);
return newPromise;
}
}
/**
* A helper to delay execution of a task that is being requested often.
*

View File

@@ -499,7 +499,11 @@ export function markdownUnescapeCodicons(text: string): string {
return text.replace(markdownUnescapeCodiconsRegex, (match, escaped, codicon) => escaped ? match : `$(${codicon})`);
}
const renderCodiconsRegex = /(\\)?\$\((([a-z0-9\-]+?)(?:~([a-z0-9\-]*?))?)\)/gi;
export const renderCodiconsRegex = /(\\)?\$\((([a-z0-9\-]+?)(?:~([a-z0-9\-]*?))?)\)/gi;
/**
* @deprecated Use `renderCodiconsAsElement` instead
*/
export function renderCodicons(text: string): string {
return text.replace(renderCodiconsRegex, (_, escaped, codicon, name, animation) => {
// If the class for codicons is changed, it should also be updated in src\vs\base\browser\markdownRenderer.ts

View File

@@ -142,7 +142,7 @@ export function isUNC(path: string): boolean {
// Reference: https://en.wikipedia.org/wiki/Filename
const WINDOWS_INVALID_FILE_CHARS = /[\\/:\*\?"<>\|]/g;
const UNIX_INVALID_FILE_CHARS = /[\\/]/g;
const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])$/i;
const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])(\.(.*?))?$/i;
export function isValidBasename(name: string | null | undefined, isWindowsOS: boolean = isWindows): boolean {
const invalidFileChars = isWindowsOS ? WINDOWS_INVALID_FILE_CHARS : UNIX_INVALID_FILE_CHARS;

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { compareAnything } from 'vs/base/common/comparers';
import { matchesPrefix, IMatch, isUpper, fuzzyScore, createMatches as createFuzzyMatches, matchesStrictPrefix } from 'vs/base/common/filters';
import { matchesPrefix, IMatch, isUpper, fuzzyScore, createMatches as createFuzzyMatches } 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';
@@ -369,9 +369,8 @@ 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_SCORE_THRESHOLD = 1 << 15;
const LABEL_PREFIX_SCORE_THRESHOLD = 1 << 17;
const LABEL_SCORE_THRESHOLD = 1 << 16;
export function scoreItemFuzzy<T>(item: T, query: IPreparedQuery, fuzzy: boolean, accessor: IItemAccessor<T>, cache: FuzzyScorerCache): IItemScore {
if (!item || !query.normalized) {
@@ -460,20 +459,33 @@ function doScoreItemFuzzyMultiple(label: string, description: string | undefined
function doScoreItemFuzzySingle(label: string, description: string | undefined, path: string | undefined, query: IPreparedQueryPiece, preferLabelMatches: boolean, fuzzy: boolean): IItemScore {
// Prefer label matches if told so
if (preferLabelMatches) {
// Treat prefix matches on the label highest
const prefixLabelMatchIgnoreCase = matchesPrefix(query.normalized, label);
if (prefixLabelMatchIgnoreCase) {
const prefixLabelMatchStrictCase = matchesStrictPrefix(query.normalized, label);
return { score: prefixLabelMatchStrictCase ? LABEL_PREFIX_SCORE_MATCHCASE : LABEL_PREFIX_SCORE_IGNORECASE, labelMatch: prefixLabelMatchStrictCase || prefixLabelMatchIgnoreCase };
}
// Second, score fuzzy
// Prefer label matches if told so or we have no description
if (preferLabelMatches || !description) {
const [labelScore, labelPositions] = scoreFuzzy(label, query.normalized, query.normalizedLowercase, fuzzy);
if (labelScore) {
return { score: labelScore + LABEL_SCORE_THRESHOLD, labelMatch: createMatches(labelPositions) };
// If we have a prefix match on the label, we give a much
// higher baseScore to elevate these matches over others
// This ensures that typing a file name wins over results
// that are present somewhere in the label, but not the
// beginning.
const labelPrefixMatch = matchesPrefix(query.normalized, label);
let baseScore: number;
if (labelPrefixMatch) {
baseScore = LABEL_PREFIX_SCORE_THRESHOLD;
// We give another boost to labels that are short, e.g. given
// files "window.ts" and "windowActions.ts" and a query of
// "window", we want "window.ts" to receive a higher score.
// As such we compute the percentage the query has within the
// label and add that to the baseScore.
const prefixLengthBoost = Math.round((query.normalized.length / label.length) * 100);
baseScore += prefixLengthBoost;
} else {
baseScore = LABEL_SCORE_THRESHOLD;
}
return { score: baseScore + labelScore, labelMatch: labelPrefixMatch || createMatches(labelPositions) };
}
}
@@ -600,46 +612,19 @@ export function compareItemsByFuzzyScore<T>(itemA: T, itemB: T, query: IPrepared
}
}
// 2.) prefer label prefix matches (match case)
if (scoreA === LABEL_PREFIX_SCORE_MATCHCASE || scoreB === LABEL_PREFIX_SCORE_MATCHCASE) {
if (scoreA !== scoreB) {
return scoreA === LABEL_PREFIX_SCORE_MATCHCASE ? -1 : 1;
}
const labelA = accessor.getItemLabel(itemA) || '';
const labelB = accessor.getItemLabel(itemB) || '';
// prefer shorter names when both match on label prefix
if (labelA.length !== labelB.length) {
return labelA.length - labelB.length;
}
}
// 3.) prefer label prefix matches (ignore case)
if (scoreA === LABEL_PREFIX_SCORE_IGNORECASE || scoreB === LABEL_PREFIX_SCORE_IGNORECASE) {
if (scoreA !== scoreB) {
return scoreA === LABEL_PREFIX_SCORE_IGNORECASE ? -1 : 1;
}
const labelA = accessor.getItemLabel(itemA) || '';
const labelB = accessor.getItemLabel(itemB) || '';
// prefer shorter names when both match on label prefix
if (labelA.length !== labelB.length) {
return labelA.length - labelB.length;
}
}
// 4.) matches on label are considered higher compared to label+description matches
// 2.) 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 > scoreB ? -1 : 1;
}
// prefer more compact matches over longer in label
const comparedByMatchLength = compareByMatchLength(itemScoreA.labelMatch, itemScoreB.labelMatch);
if (comparedByMatchLength !== 0) {
return comparedByMatchLength;
// prefer more compact matches over longer in label (unless this is a prefix match where
// longer prefix matches are actually preferred)
if (scoreA < LABEL_PREFIX_SCORE_THRESHOLD && scoreB < LABEL_PREFIX_SCORE_THRESHOLD) {
const comparedByMatchLength = compareByMatchLength(itemScoreA.labelMatch, itemScoreB.labelMatch);
if (comparedByMatchLength !== 0) {
return comparedByMatchLength;
}
}
// prefer shorter labels over longer labels
@@ -650,12 +635,12 @@ export function compareItemsByFuzzyScore<T>(itemA: T, itemB: T, query: IPrepared
}
}
// 5.) compare by score in label+description
// 3.) compare by score in label+description
if (scoreA !== scoreB) {
return scoreA > scoreB ? -1 : 1;
}
// 6.) scores are identical: prefer matches in label over non-label matches
// 4.) 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) {
@@ -664,14 +649,14 @@ export function compareItemsByFuzzyScore<T>(itemA: T, itemB: T, query: IPrepared
return 1;
}
// 7.) scores are identical: prefer more compact matches (label and description)
// 5.) 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;
}
// 8.) scores are identical: start to use the fallback compare
// 6.) scores are identical: start to use the fallback compare
return fallbackCompare(itemA, itemB, query, accessor);
}

View File

@@ -45,7 +45,7 @@ export class MarkdownString implements IMarkdownString {
// escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
this._value += (this._supportThemeIcons ? escapeCodicons(value) : value)
.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&')
.replace('\n', '\n\n');
.replace(/\n/g, '\n\n');
return this;
}

View File

@@ -5,7 +5,7 @@
import { VSBuffer } from 'vs/base/common/buffer';
import { regExpFlags } from 'vs/base/common/strings';
import { URI } from 'vs/base/common/uri';
import { URI, UriComponents } from 'vs/base/common/uri';
export function stringify(obj: any): string {
return JSON.stringify(obj, replacer);
@@ -33,7 +33,15 @@ function replacer(key: string, value: any): any {
return value;
}
export function revive(obj: any, depth = 0): any {
type Deserialize<T> = T extends UriComponents ? URI
: T extends object
? Revived<T>
: T;
export type Revived<T> = { [K in keyof T]: Deserialize<T[K]> };
export function revive<T = any>(obj: any, depth = 0): Revived<T> {
if (!obj || depth > 200) {
return obj;
}
@@ -41,15 +49,15 @@ export function revive(obj: any, depth = 0): any {
if (typeof obj === 'object') {
switch ((<MarshalledObject>obj).$mid) {
case 1: return URI.revive(obj);
case 2: return new RegExp(obj.source, obj.flags);
case 1: return <any>URI.revive(obj);
case 2: return <any>new RegExp(obj.source, obj.flags);
}
if (
obj instanceof VSBuffer
|| obj instanceof Uint8Array
) {
return obj;
return <any>obj;
}
if (Array.isArray(obj)) {

View File

@@ -33,7 +33,7 @@ export interface ReadableStreamEvents<T> {
/**
* A interface that emulates the API shape of a node.js readable
* stream for use in desktop and web environments.
* stream for use in native and web environments.
*/
export interface ReadableStream<T> extends ReadableStreamEvents<T> {
@@ -60,7 +60,7 @@ export interface ReadableStream<T> extends ReadableStreamEvents<T> {
/**
* A interface that emulates the API shape of a node.js readable
* for use in desktop and web environments.
* for use in native and web environments.
*/
export interface Readable<T> {
@@ -73,7 +73,7 @@ export interface Readable<T> {
/**
* A interface that emulates the API shape of a node.js writeable
* stream for use in desktop and web environments.
* stream for use in native and web environments.
*/
export interface WriteableStream<T> extends ReadableStream<T> {

View File

@@ -258,14 +258,12 @@ export type UriDto<T> = { [K in keyof T]: T[K] extends URI
/**
* Mapped-type that replaces all occurrences of URI with UriComponents and
* drops all functions.
* todo@joh use toJSON-results
*/
export type Dto<T> = { [K in keyof T]: T[K] extends URI
? UriComponents
: T[K] extends Function
? never
: UriDto<T[K]> };
export type Dto<T> = T extends { toJSON(): infer U }
? U
: T extends object
? { [k in keyof T]: Dto<T[k]>; }
: T;
export function NotImplementedProxy<T>(name: string): { new(): T } {
return <any>class {