mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Merge from vscode 817eb6b0c720a4ecbc13c020afbbebfed667aa09 (#7356)
This commit is contained in:
@@ -11,6 +11,7 @@ export function getPathFromAmdModule(requirefn: typeof require, relativePath: st
|
||||
|
||||
/**
|
||||
* Reference a resource that might be inlined.
|
||||
* Do not inline icons that will be used by the native mac touchbar.
|
||||
* Do not rename this method unless you adopt the build scripts.
|
||||
*/
|
||||
export function registerAndGetAmdImageURL(absolutePath: string): string {
|
||||
|
||||
@@ -372,6 +372,12 @@ export function distinctES6<T>(array: ReadonlyArray<T>): T[] {
|
||||
});
|
||||
}
|
||||
|
||||
export function fromSet<T>(set: Set<T>): T[] {
|
||||
const result: T[] = [];
|
||||
set.forEach(o => result.push(o));
|
||||
return result;
|
||||
}
|
||||
|
||||
export function uniqueFilter<T>(keyFn: (t: T) => string): (t: T) => boolean {
|
||||
const seen: { [key: string]: boolean; } = Object.create(null);
|
||||
|
||||
@@ -418,6 +424,12 @@ export function first<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean, notF
|
||||
return index < 0 ? notFoundValue : array[index];
|
||||
}
|
||||
|
||||
export function firstOrDefault<T, NotFound = T>(array: ReadonlyArray<T>, notFoundValue: NotFound): T | NotFound;
|
||||
export function firstOrDefault<T>(array: ReadonlyArray<T>): T | undefined;
|
||||
export function firstOrDefault<T, NotFound = T>(array: ReadonlyArray<T>, notFoundValue?: NotFound): T | NotFound | undefined {
|
||||
return array.length > 0 ? array[0] : notFoundValue;
|
||||
}
|
||||
|
||||
export function commonPrefixLength<T>(one: ReadonlyArray<T>, other: ReadonlyArray<T>, equals: (a: T, b: T) => boolean = (a, b) => a === b): number {
|
||||
let result = 0;
|
||||
|
||||
|
||||
@@ -97,6 +97,12 @@ export function fromMap<T>(original: Map<string, T>): IStringDictionary<T> {
|
||||
return result;
|
||||
}
|
||||
|
||||
export function mapValues<V>(map: Map<any, V>): V[] {
|
||||
const result: V[] = [];
|
||||
map.forEach(v => result.push(v));
|
||||
return result;
|
||||
}
|
||||
|
||||
export class SetMap<K, V> {
|
||||
|
||||
private map = new Map<K, Set<V>>();
|
||||
|
||||
@@ -24,40 +24,64 @@ export function createDecorator(mapFn: (fn: Function, key: string) => Function):
|
||||
};
|
||||
}
|
||||
|
||||
export function memoize(target: any, key: string, descriptor: any) {
|
||||
let fnKey: string | null = null;
|
||||
let fn: Function | null = null;
|
||||
let memoizeId = 0;
|
||||
export function createMemoizer() {
|
||||
const memoizeKeyPrefix = `$memoize${memoizeId++}`;
|
||||
let self: any = undefined;
|
||||
|
||||
if (typeof descriptor.value === 'function') {
|
||||
fnKey = 'value';
|
||||
fn = descriptor.value;
|
||||
const result = function memoize(target: any, key: string, descriptor: any) {
|
||||
let fnKey: string | null = null;
|
||||
let fn: Function | null = null;
|
||||
|
||||
if (fn!.length !== 0) {
|
||||
console.warn('Memoize should only be used in functions with zero parameters');
|
||||
}
|
||||
} else if (typeof descriptor.get === 'function') {
|
||||
fnKey = 'get';
|
||||
fn = descriptor.get;
|
||||
}
|
||||
if (typeof descriptor.value === 'function') {
|
||||
fnKey = 'value';
|
||||
fn = descriptor.value;
|
||||
|
||||
if (!fn) {
|
||||
throw new Error('not supported');
|
||||
}
|
||||
|
||||
const memoizeKey = `$memoize$${key}`;
|
||||
|
||||
descriptor[fnKey!] = function (...args: any[]) {
|
||||
if (!this.hasOwnProperty(memoizeKey)) {
|
||||
Object.defineProperty(this, memoizeKey, {
|
||||
configurable: false,
|
||||
enumerable: false,
|
||||
writable: false,
|
||||
value: fn!.apply(this, args)
|
||||
});
|
||||
if (fn!.length !== 0) {
|
||||
console.warn('Memoize should only be used in functions with zero parameters');
|
||||
}
|
||||
} else if (typeof descriptor.get === 'function') {
|
||||
fnKey = 'get';
|
||||
fn = descriptor.get;
|
||||
}
|
||||
|
||||
return this[memoizeKey];
|
||||
if (!fn) {
|
||||
throw new Error('not supported');
|
||||
}
|
||||
|
||||
const memoizeKey = `${memoizeKeyPrefix}:${key}`;
|
||||
descriptor[fnKey!] = function (...args: any[]) {
|
||||
self = this;
|
||||
|
||||
if (!this.hasOwnProperty(memoizeKey)) {
|
||||
Object.defineProperty(this, memoizeKey, {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
value: fn!.apply(this, args)
|
||||
});
|
||||
}
|
||||
|
||||
return this[memoizeKey];
|
||||
};
|
||||
};
|
||||
|
||||
result.clear = () => {
|
||||
if (typeof self === 'undefined') {
|
||||
return;
|
||||
}
|
||||
Object.getOwnPropertyNames(self).forEach(property => {
|
||||
if (property.indexOf(memoizeKeyPrefix) === 0) {
|
||||
delete self[property];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function memoize(target: any, key: string, descriptor: any) {
|
||||
return createMemoizer()(target, key, descriptor);
|
||||
}
|
||||
|
||||
export interface IDebouceReducer<T> {
|
||||
@@ -87,4 +111,4 @@ export function debounce<T>(delay: number, reducer?: IDebouceReducer<T>, initial
|
||||
}, delay);
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,7 +451,7 @@ class LeakageMonitor {
|
||||
* Sample:
|
||||
class Document {
|
||||
|
||||
private _onDidChange = new Emitter<(value:string)=>any>();
|
||||
private readonly _onDidChange = new Emitter<(value:string)=>any>();
|
||||
|
||||
public onDidChange = this._onDidChange.event;
|
||||
|
||||
@@ -808,7 +808,7 @@ export class Relay<T> implements IDisposable {
|
||||
private inputEvent: Event<T> = Event.None;
|
||||
private inputEventListener: IDisposable = Disposable.None;
|
||||
|
||||
private emitter = new Emitter<T>({
|
||||
private readonly emitter = new Emitter<T>({
|
||||
onFirstListenerDidAdd: () => {
|
||||
this.listening = true;
|
||||
this.inputEventListener = this.inputEvent(this.emitter.fire, this.emitter);
|
||||
|
||||
@@ -11,7 +11,7 @@ export class HistoryNavigator<T> implements INavigator<T> {
|
||||
private _limit: number;
|
||||
private _navigator!: ArrayNavigator<T>;
|
||||
|
||||
constructor(history: T[] = [], limit: number = 10) {
|
||||
constructor(history: readonly T[] = [], limit: number = 10) {
|
||||
this._initialize(history);
|
||||
this._limit = limit;
|
||||
this._onChange();
|
||||
@@ -62,7 +62,8 @@ export class HistoryNavigator<T> implements INavigator<T> {
|
||||
|
||||
private _onChange() {
|
||||
this._reduceToLimit();
|
||||
this._navigator = new ArrayNavigator(this._elements, 0, this._elements.length, this._elements.length);
|
||||
const elements = this._elements;
|
||||
this._navigator = new ArrayNavigator(elements, 0, elements.length, elements.length);
|
||||
}
|
||||
|
||||
private _reduceToLimit() {
|
||||
@@ -72,7 +73,7 @@ export class HistoryNavigator<T> implements INavigator<T> {
|
||||
}
|
||||
}
|
||||
|
||||
private _initialize(history: T[]): void {
|
||||
private _initialize(history: readonly T[]): void {
|
||||
this._history = new Set();
|
||||
for (const entry of history) {
|
||||
this._history.add(entry);
|
||||
|
||||
@@ -18,6 +18,22 @@ export interface Iterator<T> {
|
||||
next(): IteratorResult<T>;
|
||||
}
|
||||
|
||||
interface NativeIteratorYieldResult<TYield> {
|
||||
done?: false;
|
||||
value: TYield;
|
||||
}
|
||||
|
||||
interface NativeIteratorReturnResult<TReturn> {
|
||||
done: true;
|
||||
value: TReturn;
|
||||
}
|
||||
|
||||
type NativeIteratorResult<T, TReturn = any> = NativeIteratorYieldResult<T> | NativeIteratorReturnResult<TReturn>;
|
||||
|
||||
export interface NativeIterator<T> {
|
||||
next(): NativeIteratorResult<T>;
|
||||
}
|
||||
|
||||
export module Iterator {
|
||||
const _empty: Iterator<any> = {
|
||||
next() {
|
||||
@@ -56,6 +72,20 @@ export module Iterator {
|
||||
};
|
||||
}
|
||||
|
||||
export function fromNativeIterator<T>(it: NativeIterator<T>): Iterator<T> {
|
||||
return {
|
||||
next(): IteratorResult<T> {
|
||||
const result = it.next();
|
||||
|
||||
if (result.done) {
|
||||
return FIN;
|
||||
}
|
||||
|
||||
return { done: false, value: result.value };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function from<T>(elements: Iterator<T> | T[] | undefined): Iterator<T> {
|
||||
if (!elements) {
|
||||
return Iterator.empty();
|
||||
@@ -160,12 +190,12 @@ export interface INextIterator<T> {
|
||||
|
||||
export class ArrayIterator<T> implements INextIterator<T> {
|
||||
|
||||
private items: T[];
|
||||
private readonly items: readonly T[];
|
||||
protected start: number;
|
||||
protected end: number;
|
||||
protected index: number;
|
||||
|
||||
constructor(items: T[], start: number = 0, end: number = items.length, index = start - 1) {
|
||||
constructor(items: readonly T[], start: number = 0, end: number = items.length, index = start - 1) {
|
||||
this.items = items;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
@@ -193,7 +223,7 @@ export class ArrayIterator<T> implements INextIterator<T> {
|
||||
|
||||
export class ArrayNavigator<T> extends ArrayIterator<T> implements INavigator<T> {
|
||||
|
||||
constructor(items: T[], start: number = 0, end: number = items.length, index = start - 1) {
|
||||
constructor(items: readonly T[], start: number = 0, end: number = items.length, index = start - 1) {
|
||||
super(items, start, end, index);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ export interface IJSONSchema {
|
||||
markdownDescription?: string; // VSCode extension
|
||||
doNotSuggest?: boolean; // VSCode extension
|
||||
allowComments?: boolean; // VSCode extension
|
||||
allowsTrailingCommas?: boolean; // VSCode extension
|
||||
allowTrailingCommas?: boolean; // VSCode extension
|
||||
}
|
||||
|
||||
export interface IJSONSchemaMap {
|
||||
|
||||
191
src/vs/base/common/resourceTree.ts
Normal file
191
src/vs/base/common/resourceTree.ts
Normal file
@@ -0,0 +1,191 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import * as paths from 'vs/base/common/path';
|
||||
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';
|
||||
|
||||
export interface ILeafNode<T, C = void> {
|
||||
readonly uri: URI;
|
||||
readonly relativePath: string;
|
||||
readonly name: string;
|
||||
readonly element: T;
|
||||
readonly context: C;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
export type INode<T, C> = IBranchNode<T, C> | ILeafNode<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 {
|
||||
return this._children.size;
|
||||
}
|
||||
|
||||
get children(): Iterator<BranchNode<T, C> | LeafNode<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);
|
||||
}
|
||||
|
||||
get(path: string): BranchNode<T, C> | LeafNode<T, C> | undefined {
|
||||
return this._children.get(path);
|
||||
}
|
||||
|
||||
set(path: string, child: BranchNode<T, C> | LeafNode<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);
|
||||
}
|
||||
}
|
||||
|
||||
function collect<T, C>(node: INode<T, C>, result: T[]): T[] {
|
||||
if (ResourceTree.isBranchNode(node)) {
|
||||
Iterator.forEach(node.children, child => collect(child, result));
|
||||
} else {
|
||||
result.push(node.element);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export class ResourceTree<T extends NonNullable<any>, C> {
|
||||
|
||||
readonly root: BranchNode<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> {
|
||||
while (node.parent) {
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static collect<T, C>(node: INode<T, C>): T[] {
|
||||
return collect(node, []);
|
||||
}
|
||||
|
||||
constructor(context: C, rootURI: URI = URI.file('/')) {
|
||||
this.root = new BranchNode(rootURI, '', context);
|
||||
}
|
||||
|
||||
add(uri: URI, element: T): void {
|
||||
const key = relativePath(this.root.uri, uri) || uri.fsPath;
|
||||
const parts = key.split(/[\\\/]/).filter(p => !!p);
|
||||
let node = this.root;
|
||||
let path = '';
|
||||
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
const name = parts[i];
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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 = child;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private _delete(node: BranchNode<T, C>, parts: string[], index: number): T | undefined {
|
||||
const name = parts[index];
|
||||
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 (typeof result !== 'undefined' && child.size === 0) {
|
||||
node.delete(name);
|
||||
}
|
||||
|
||||
return result;
|
||||
} else {
|
||||
throw new Error('Inconsistent tree: Expected a branch, found a leaf instead.');
|
||||
}
|
||||
}
|
||||
|
||||
//at end
|
||||
if (child instanceof BranchNode) {
|
||||
// TODO: maybe we can allow this
|
||||
throw new Error('Inconsistent tree: Expected a leaf, found a branch instead.');
|
||||
}
|
||||
|
||||
node.delete(name);
|
||||
return child.element;
|
||||
}
|
||||
}
|
||||
@@ -24,11 +24,11 @@ export class Sequence<T> implements ISequence<T>, ISpliceable<T> {
|
||||
|
||||
readonly elements: T[] = [];
|
||||
|
||||
private _onDidSplice = new Emitter<ISplice<T>>();
|
||||
private readonly _onDidSplice = new Emitter<ISplice<T>>();
|
||||
readonly onDidSplice: Event<ISplice<T>> = this._onDidSplice.event;
|
||||
|
||||
splice(start: number, deleteCount: number, toInsert: T[] = []): void {
|
||||
this.elements.splice(start, deleteCount, ...toInsert);
|
||||
this._onDidSplice.fire({ start, deleteCount, toInsert });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user