Merge from vscode 10492ba146318412cbee8b76a8c630f226914734

This commit is contained in:
ADS Merger
2020-04-08 06:33:38 +00:00
parent fca2344c2e
commit 1868a7d370
339 changed files with 3795 additions and 3146 deletions

View File

@@ -51,6 +51,8 @@ export const BrowserFeatures = {
return KeyboardSupport.None;
})(),
touch: 'ontouchstart' in window || navigator.maxTouchPoints > 0 || window.navigator.msMaxTouchPoints > 0,
pointerEvents: window.PointerEvent && ('ontouchstart' in window || window.navigator.maxTouchPoints > 0 || navigator.maxTouchPoints > 0 || window.navigator.msMaxTouchPoints > 0)
// 'ontouchstart' in window always evaluates to true with typescript's modern typings. This causes `window` to be
// `never` later in `window.navigator`. That's why we need the explicit `window as Window` cast
touch: 'ontouchstart' in window || navigator.maxTouchPoints > 0 || (window as Window).navigator.msMaxTouchPoints > 0,
pointerEvents: window.PointerEvent && ('ontouchstart' in window || (window as Window).navigator.maxTouchPoints > 0 || navigator.maxTouchPoints > 0 || (window as Window).navigator.msMaxTouchPoints > 0)
};

View File

@@ -131,7 +131,9 @@ export class Gesture extends Disposable {
@memoize
private static isTouchDevice(): boolean {
return 'ontouchstart' in window || navigator.maxTouchPoints > 0 || window.navigator.msMaxTouchPoints > 0;
// `'ontouchstart' in window` always evaluates to true with typescript's modern typings. This causes `window` to be
// `never` later in `window.navigator`. That's why we need the explicit `window as Window` cast
return 'ontouchstart' in window || navigator.maxTouchPoints > 0 || (window as Window).navigator.msMaxTouchPoints > 0;
}
public dispose(): void {

View File

@@ -1041,9 +1041,10 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
// Util
private getItemIndexFromEventTarget(target: EventTarget | null): number | undefined {
const scrollableElement = this.scrollableElement.getDomNode();
let element: HTMLElement | null = target as (HTMLElement | null);
while (element instanceof HTMLElement && element !== this.rowsContainer) {
while (element instanceof HTMLElement && element !== this.rowsContainer && scrollableElement.contains(element)) {
const rawIndex = element.getAttribute('data-index');
if (rawIndex) {

View File

@@ -11,7 +11,7 @@ import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'
import { Emitter, Event } from 'vs/base/common/event';
import { timeout, CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
import { IListStyles } from 'vs/base/browser/ui/list/listWidget';
import { Iterator } from 'vs/base/common/iterator';
import { Iterable } from 'vs/base/common/iterator';
import { IDragAndDropData } from 'vs/base/browser/dnd';
import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView';
import { isPromiseCanceledError, onUnexpectedError } from 'vs/base/common/errors';
@@ -313,7 +313,7 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
private readonly collapseByDefault?: { (e: T): boolean; };
private readonly subTreeRefreshPromises = new Map<IAsyncDataTreeNode<TInput, T>, Promise<void>>();
private readonly refreshPromises = new Map<IAsyncDataTreeNode<TInput, T>, CancelablePromise<T[]>>();
private readonly refreshPromises = new Map<IAsyncDataTreeNode<TInput, T>, CancelablePromise<Iterable<T>>>();
protected readonly identityProvider?: IIdentityProvider<T>;
private readonly autoExpandSingleChildren: boolean;
@@ -740,10 +740,10 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
private async doRefreshNode(node: IAsyncDataTreeNode<TInput, T>, recursive: boolean, viewStateContext?: IAsyncDataTreeViewStateContext<TInput, T>): Promise<IAsyncDataTreeNode<TInput, T>[]> {
node.hasChildren = !!this.dataSource.hasChildren(node.element!);
let childrenPromise: Promise<T[]>;
let childrenPromise: Promise<Iterable<T>>;
if (!node.hasChildren) {
childrenPromise = Promise.resolve([]);
childrenPromise = Promise.resolve(Iterable.empty());
} else {
const slowTimeout = timeout(800);
@@ -777,7 +777,7 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
}
}
private doGetChildren(node: IAsyncDataTreeNode<TInput, T>): Promise<T[]> {
private doGetChildren(node: IAsyncDataTreeNode<TInput, T>): Promise<Iterable<T>> {
let result = this.refreshPromises.get(node);
if (result) {
@@ -809,7 +809,9 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
}
}
private setChildren(node: IAsyncDataTreeNode<TInput, T>, childrenElements: T[], recursive: boolean, viewStateContext?: IAsyncDataTreeViewStateContext<TInput, T>): IAsyncDataTreeNode<TInput, T>[] {
private setChildren(node: IAsyncDataTreeNode<TInput, T>, childrenElementsIterable: Iterable<T>, recursive: boolean, viewStateContext?: IAsyncDataTreeViewStateContext<TInput, T>): IAsyncDataTreeNode<TInput, T>[] {
const childrenElements = [...childrenElementsIterable];
// perf: if the node was and still is a leaf, avoid all this hassle
if (node.children.length === 0 && childrenElements.length === 0) {
return [];
@@ -943,15 +945,15 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
return {
element: node,
children: node.hasChildren ? Iterator.map(Iterator.fromArray(node.children), child => this.asTreeElement(child, viewStateContext)) : [],
children: node.hasChildren ? Iterable.map(node.children, child => this.asTreeElement(child, viewStateContext)) : [],
collapsible: node.hasChildren,
collapsed
};
}
protected processChildren(children: T[]): T[] {
protected processChildren(children: Iterable<T>): Iterable<T> {
if (this.sorter) {
children.sort(this.sorter.compare.bind(this.sorter));
children = [...children].sort(this.sorter.compare.bind(this.sorter));
}
return children;
@@ -1243,9 +1245,9 @@ export class CompressibleAsyncDataTree<TInput, T, TFilterData = void> extends As
// For compressed async data trees, `TreeVisibility.Recurse` doesn't currently work
// and we have to filter everything beforehand
// Related to #85193 and #85835
protected processChildren(children: T[]): T[] {
protected processChildren(children: Iterable<T>): Iterable<T> {
if (this.filter) {
children = children.filter(e => {
children = Iterable.filter(children, e => {
const result = this.filter!.filter(e, TreeVisibility.Visible);
const visibility = getVisibility(result);

View File

@@ -4,14 +4,14 @@
*--------------------------------------------------------------------------------------------*/
import { ISpliceable } from 'vs/base/common/sequence';
import { Iterator, ISequence } from 'vs/base/common/iterator';
import { Iterable } from 'vs/base/common/iterator';
import { Event } from 'vs/base/common/event';
import { ITreeModel, ITreeNode, ITreeElement, ICollapseStateChangeEvent, ITreeModelSpliceEvent, TreeError, TreeFilterResult, TreeVisibility, WeakMapper } from 'vs/base/browser/ui/tree/tree';
import { IObjectTreeModelOptions, ObjectTreeModel, IObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel';
// Exported only for test reasons, do not use directly
export interface ICompressedTreeElement<T> extends ITreeElement<T> {
readonly children?: ISequence<ICompressedTreeElement<T>>;
readonly children?: Iterable<ICompressedTreeElement<T>>;
readonly incompressible?: boolean;
}
@@ -27,7 +27,7 @@ function noCompress<T>(element: ICompressedTreeElement<T>): ITreeElement<ICompre
return {
element: { elements, incompressible },
children: Iterator.map(Iterator.from(element.children), noCompress),
children: Iterable.map(Iterable.from(element.children), noCompress),
collapsible: element.collapsible,
collapsed: element.collapsed
};
@@ -38,12 +38,11 @@ export function compress<T>(element: ICompressedTreeElement<T>): ITreeElement<IC
const elements = [element.element];
const incompressible = element.incompressible || false;
let childrenIterator: Iterator<ITreeElement<T>>;
let childrenIterator: Iterable<ITreeElement<T>>;
let children: ITreeElement<T>[];
while (true) {
childrenIterator = Iterator.from(element.children);
children = Iterator.collect(childrenIterator, 2);
[children, childrenIterator] = Iterable.consume(Iterable.from(element.children), 2);
if (children.length !== 1) {
break;
@@ -60,19 +59,19 @@ export function compress<T>(element: ICompressedTreeElement<T>): ITreeElement<IC
return {
element: { elements, incompressible },
children: Iterator.map(Iterator.concat(Iterator.fromArray(children), childrenIterator), compress),
children: Iterable.map(Iterable.concat(children, childrenIterator), compress),
collapsible: element.collapsible,
collapsed: element.collapsed
};
}
function _decompress<T>(element: ITreeElement<ICompressedTreeNode<T>>, index = 0): ICompressedTreeElement<T> {
let children: Iterator<ICompressedTreeElement<T>>;
let children: Iterable<ICompressedTreeElement<T>>;
if (index < element.element.elements.length - 1) {
children = Iterator.single(_decompress(element, index + 1));
children = [_decompress(element, index + 1)];
} else {
children = Iterator.map(Iterator.from(element.children), el => _decompress(el, 0));
children = Iterable.map(Iterable.from(element.children), el => _decompress(el, 0));
}
if (index === 0 && element.element.incompressible) {
@@ -98,12 +97,12 @@ export function decompress<T>(element: ITreeElement<ICompressedTreeNode<T>>): IC
return _decompress(element, 0);
}
function splice<T>(treeElement: ICompressedTreeElement<T>, element: T, children: Iterator<ICompressedTreeElement<T>>): ICompressedTreeElement<T> {
function splice<T>(treeElement: ICompressedTreeElement<T>, element: T, children: Iterable<ICompressedTreeElement<T>>): ICompressedTreeElement<T> {
if (treeElement.element === element) {
return { ...treeElement, children };
}
return { ...treeElement, children: Iterator.map(Iterator.from(treeElement.children), e => splice(e, element, children)) };
return { ...treeElement, children: Iterable.map(Iterable.from(treeElement.children), e => splice(e, element, children)) };
}
interface ICompressedObjectTreeModelOptions<T, TFilterData> extends IObjectTreeModelOptions<ICompressedTreeNode<T>, TFilterData> {
@@ -136,10 +135,10 @@ export class CompressedObjectTreeModel<T extends NonNullable<any>, TFilterData e
setChildren(
element: T | null,
children: ISequence<ICompressedTreeElement<T>> | undefined
children: Iterable<ICompressedTreeElement<T>> = Iterable.empty()
): void {
if (element === null) {
const compressedChildren = Iterator.map(Iterator.from(children), this.enabled ? compress : noCompress);
const compressedChildren = Iterable.map(children, this.enabled ? compress : noCompress);
this._setChildren(null, compressedChildren);
return;
}
@@ -155,7 +154,7 @@ export class CompressedObjectTreeModel<T extends NonNullable<any>, TFilterData e
const parent = this.model.getNode(compressedParentNode) as ITreeNode<ICompressedTreeNode<T>, TFilterData>;
const decompressedElement = decompress(node);
const splicedElement = splice(decompressedElement, element, Iterator.from(children));
const splicedElement = splice(decompressedElement, element, children);
const recompressedElement = (this.enabled ? compress : noCompress)(splicedElement);
const parentChildren = parent.children
@@ -176,15 +175,15 @@ export class CompressedObjectTreeModel<T extends NonNullable<any>, TFilterData e
this.enabled = enabled;
const root = this.model.getNode();
const rootChildren = Iterator.from((root.children as unknown) as ITreeNode<ICompressedTreeNode<T>>[]); // {{SQL CARBON EDIT}} strict-null-checks
const decompressedRootChildren = Iterator.map(rootChildren, decompress);
const recompressedRootChildren = Iterator.map(decompressedRootChildren, enabled ? compress : noCompress);
const rootChildren = root.children as ITreeNode<ICompressedTreeNode<T>>[];
const decompressedRootChildren = Iterable.map(rootChildren, decompress);
const recompressedRootChildren = Iterable.map(decompressedRootChildren, enabled ? compress : noCompress);
this._setChildren(null, recompressedRootChildren);
}
private _setChildren(
node: ICompressedTreeNode<T> | null,
children: ISequence<ITreeElement<ICompressedTreeNode<T>>> | undefined
children: Iterable<ITreeElement<ICompressedTreeNode<T>>>
): void {
const insertedElements = new Set<T | null>();
const _onDidCreateNode = (node: ITreeNode<ICompressedTreeNode<T>, TFilterData>) => {
@@ -413,7 +412,7 @@ export class CompressibleObjectTreeModel<T extends NonNullable<any>, TFilterData
this.model = new CompressedObjectTreeModel(user, mapList(this.nodeMapper, list), mapOptions(compressedNodeUnwrapper, options));
}
setChildren(element: T | null, children?: ISequence<ICompressedTreeElement<T>>): void {
setChildren(element: T | null, children: Iterable<ICompressedTreeElement<T>> = Iterable.empty()): void {
this.model.setChildren(element, children);
}

View File

@@ -8,7 +8,7 @@ import { ISpliceable } from 'vs/base/common/sequence';
import { ITreeNode, ITreeModel, ITreeElement, ITreeRenderer, ITreeSorter, IDataSource, TreeError } from 'vs/base/browser/ui/tree/tree';
import { ObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel';
import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list';
import { Iterator } from 'vs/base/common/iterator';
import { Iterable } from 'vs/base/common/iterator';
export interface IDataTreeOptions<T, TFilterData = void> extends IAbstractTreeOptions<T, TFilterData> {
readonly sorter?: ITreeSorter<T>;
@@ -158,9 +158,9 @@ export class DataTree<TInput, T, TFilterData = void> extends AbstractTree<T | nu
this.model.setChildren((element === this.input ? null : element) as T, this.iterate(element, isCollapsed).elements, onDidCreateNode, onDidDeleteNode);
}
private iterate(element: TInput | T, isCollapsed?: (el: T) => boolean | undefined): { elements: Iterator<ITreeElement<T>>, size: number } {
const children = this.dataSource.getChildren(element);
const elements = Iterator.map<any, ITreeElement<T>>(Iterator.fromArray(children), element => {
private iterate(element: TInput | T, isCollapsed?: (el: T) => boolean | undefined): { elements: Iterable<ITreeElement<T>>, size: number } {
const children = [...this.dataSource.getChildren(element)];
const elements = Iterable.map(children, element => {
const { elements: children, size } = this.iterate(element, isCollapsed);
const collapsible = this.dataSource.hasChildren ? this.dataSource.hasChildren(element) : undefined;
const collapsed = size === 0 ? undefined : (isCollapsed && isCollapsed(element));

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/tree';
import { Iterator, ISequence } from 'vs/base/common/iterator';
import { Iterable } from 'vs/base/common/iterator';
import { AbstractTree, IAbstractTreeOptions } from 'vs/base/browser/ui/tree/abstractTree';
import { ISpliceable } from 'vs/base/common/sequence';
import { IndexTreeModel } from 'vs/base/browser/ui/tree/indexTreeModel';
@@ -28,7 +28,7 @@ export class IndexTree<T, TFilterData = void> extends AbstractTree<T, TFilterDat
super(user, container, delegate, renderers, options);
}
splice(location: number[], deleteCount: number, toInsert: ISequence<ITreeElement<T>> = Iterator.empty()): void {
splice(location: number[], deleteCount: number, toInsert: Iterable<ITreeElement<T>> = Iterable.empty()): void {
this.model.splice(location, deleteCount, toInsert);
}

View File

@@ -6,7 +6,7 @@
import { ICollapseStateChangeEvent, ITreeElement, ITreeFilter, ITreeFilterDataResult, ITreeModel, ITreeNode, TreeVisibility, ITreeModelSpliceEvent, TreeError } from 'vs/base/browser/ui/tree/tree';
import { tail2 } from 'vs/base/common/arrays';
import { Emitter, Event, EventBufferer } from 'vs/base/common/event';
import { ISequence, Iterator } from 'vs/base/common/iterator';
import { Iterable } from 'vs/base/common/iterator';
import { ISpliceable } from 'vs/base/common/sequence';
// Exported for tests
@@ -103,7 +103,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
splice(
location: number[],
deleteCount: number,
toInsert?: ISequence<ITreeElement<T>>,
toInsert: Iterable<ITreeElement<T>> = Iterable.empty(),
onDidCreateNode?: (node: ITreeNode<T, TFilterData>) => void,
onDidDeleteNode?: (node: ITreeNode<T, TFilterData>) => void
): void {
@@ -113,7 +113,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
const { parentNode, listIndex, revealed, visible } = this.getParentNodeWithListIndex(location);
const treeListElementsToInsert: ITreeNode<T, TFilterData>[] = [];
const nodesToInsertIterator = Iterator.map(Iterator.from(toInsert), el => this.createTreeNode(el, parentNode, parentNode.visible ? TreeVisibility.Visible : TreeVisibility.Hidden, revealed, treeListElementsToInsert, onDidCreateNode));
const nodesToInsertIterator = Iterable.map(toInsert, el => this.createTreeNode(el, parentNode, parentNode.visible ? TreeVisibility.Visible : TreeVisibility.Hidden, revealed, treeListElementsToInsert, onDidCreateNode));
const lastIndex = location[location.length - 1];
@@ -134,14 +134,14 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
let insertedVisibleChildrenCount = 0;
let renderNodeCount = 0;
Iterator.forEach(nodesToInsertIterator, child => {
for (const child of nodesToInsertIterator) {
nodesToInsert.push(child);
renderNodeCount += child.renderNodeCount;
if (child.visible) {
child.visibleChildIndex = visibleChildStartIndex + insertedVisibleChildrenCount++;
}
});
}
const deletedNodes = parentNode.children.splice(lastIndex, deleteCount, ...nodesToInsert);
@@ -365,21 +365,21 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
treeListElements.push(node);
}
const childElements = Iterator.from(treeElement.children);
const childElements = treeElement.children || Iterable.empty();
const childRevealed = revealed && visibility !== TreeVisibility.Hidden && !node.collapsed;
const childNodes = Iterator.map(childElements, el => this.createTreeNode(el, node, visibility, childRevealed, treeListElements, onDidCreateNode));
const childNodes = Iterable.map(childElements, el => this.createTreeNode(el, node, visibility, childRevealed, treeListElements, onDidCreateNode));
let visibleChildrenCount = 0;
let renderNodeCount = 1;
Iterator.forEach(childNodes, child => {
for (const child of childNodes) {
node.children.push(child);
renderNodeCount += child.renderNodeCount;
if (child.visible) {
child.visibleChildIndex = visibleChildrenCount++;
}
});
}
node.collapsible = node.collapsible || node.children.length > 0;
node.visibleChildrenCount = visibleChildrenCount;

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ISequence } from 'vs/base/common/iterator';
import { Iterable } from 'vs/base/common/iterator';
import { AbstractTree, IAbstractTreeOptions, IAbstractTreeOptionsUpdate } from 'vs/base/browser/ui/tree/abstractTree';
import { ISpliceable } from 'vs/base/common/sequence';
import { ITreeNode, ITreeModel, ITreeElement, ITreeRenderer, ITreeSorter, ICollapseStateChangeEvent } from 'vs/base/browser/ui/tree/tree';
@@ -33,7 +33,7 @@ export class ObjectTree<T extends NonNullable<any>, TFilterData = void> extends
super(user, container, delegate, renderers, options as IObjectTreeOptions<T | null, TFilterData>);
}
setChildren(element: T | null, children?: ISequence<ITreeElement<T>>): void {
setChildren(element: T | null, children: Iterable<ITreeElement<T>> = Iterable.empty()): void {
this.model.setChildren(element, children);
}
@@ -184,7 +184,7 @@ export class CompressibleObjectTree<T extends NonNullable<any>, TFilterData = vo
super(user, container, delegate, compressibleRenderers, asObjectTreeOptions<T, TFilterData>(compressedTreeNodeProvider, options));
}
setChildren(element: T | null, children?: ISequence<ICompressedTreeElement<T>>): void {
setChildren(element: T | null, children: Iterable<ICompressedTreeElement<T>> = Iterable.empty()): void {
this.model.setChildren(element, children);
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { ISpliceable } from 'vs/base/common/sequence';
import { Iterator, ISequence, getSequenceIterator } from 'vs/base/common/iterator';
import { Iterable } from 'vs/base/common/iterator';
import { IndexTreeModel, IIndexTreeModelOptions } from 'vs/base/browser/ui/tree/indexTreeModel';
import { Event } from 'vs/base/common/event';
import { ITreeModel, ITreeNode, ITreeElement, ITreeSorter, ICollapseStateChangeEvent, ITreeModelSpliceEvent, TreeError } from 'vs/base/browser/ui/tree/tree';
@@ -14,7 +14,7 @@ import { mergeSort } from 'vs/base/common/arrays';
export type ITreeNodeCallback<T, TFilterData> = (node: ITreeNode<T, TFilterData>) => void;
export interface IObjectTreeModel<T extends NonNullable<any>, TFilterData extends NonNullable<any> = void> extends ITreeModel<T | null, TFilterData, T | null> {
setChildren(element: T | null, children: ISequence<ITreeElement<T>> | undefined): void;
setChildren(element: T | null, children: Iterable<ITreeElement<T>> | undefined): void;
resort(element?: T | null, recursive?: boolean): void;
}
@@ -62,7 +62,7 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
setChildren(
element: T | null,
children: ISequence<ITreeElement<T>> | undefined,
children: Iterable<ITreeElement<T>> = Iterable.empty(),
onDidCreateNode?: ITreeNodeCallback<T, TFilterData>,
onDidDeleteNode?: ITreeNodeCallback<T, TFilterData>
): void {
@@ -72,7 +72,7 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
private _setChildren(
location: number[],
children: ISequence<ITreeElement<T>> | undefined,
children: Iterable<ITreeElement<T>> = Iterable.empty(),
onDidCreateNode?: ITreeNodeCallback<T, TFilterData>,
onDidDeleteNode?: ITreeNodeCallback<T, TFilterData>
): void {
@@ -132,14 +132,12 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
);
}
private preserveCollapseState(elements: ISequence<ITreeElement<T>> | undefined): ISequence<ITreeElement<T>> {
let iterator = elements ? getSequenceIterator(elements) : Iterator.empty<ITreeElement<T>>();
private preserveCollapseState(elements: Iterable<ITreeElement<T>> = Iterable.empty()): Iterable<ITreeElement<T>> {
if (this.sorter) {
iterator = Iterator.fromArray(mergeSort(Iterator.collect(iterator), this.sorter.compare.bind(this.sorter)));
elements = mergeSort([...elements], this.sorter.compare.bind(this.sorter));
}
return Iterator.map(iterator, treeElement => {
return Iterable.map(elements, treeElement => {
let node = this.nodes.get(treeElement.element);
if (!node && this.identityProvider) {
@@ -182,14 +180,14 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
this._setChildren(location, this.resortChildren(node, recursive));
}
private resortChildren(node: ITreeNode<T | null, TFilterData>, recursive: boolean, first = true): ISequence<ITreeElement<T>> {
let childrenNodes = Iterator.fromArray(node.children as ITreeNode<T, TFilterData>[]);
private resortChildren(node: ITreeNode<T | null, TFilterData>, recursive: boolean, first = true): Iterable<ITreeElement<T>> {
let childrenNodes = [...node.children] as ITreeNode<T, TFilterData>[];
if (recursive || first) {
childrenNodes = Iterator.fromArray(Iterator.collect(childrenNodes).sort(this.sorter!.compare.bind(this.sorter)));
childrenNodes = mergeSort(childrenNodes, this.sorter!.compare.bind(this.sorter)) as ITreeNode<T, TFilterData>[];
}
return Iterator.map<ITreeNode<T | null, TFilterData>, ITreeElement<T>>(childrenNodes, node => ({
return Iterable.map<ITreeNode<T | null, TFilterData>, ITreeElement<T>>(childrenNodes, node => ({
element: node.element as T,
collapsible: node.collapsible,
collapsed: node.collapsed,

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { Event } from 'vs/base/common/event';
import { Iterator } from 'vs/base/common/iterator';
import { IListRenderer, IListDragOverReaction, IListDragAndDrop, ListDragOverEffect } from 'vs/base/browser/ui/list/list';
import { IDragAndDropData } from 'vs/base/browser/dnd';
@@ -74,7 +73,7 @@ export interface ITreeSorter<T> {
export interface ITreeElement<T> {
readonly element: T;
readonly children?: Iterator<ITreeElement<T>> | ITreeElement<T>[];
readonly children?: Iterable<ITreeElement<T>>;
readonly collapsible?: boolean;
readonly collapsed?: boolean;
}
@@ -167,12 +166,12 @@ export interface ITreeNavigator<T> {
export interface IDataSource<TInput, T> {
hasChildren?(element: TInput | T): boolean;
getChildren(element: TInput | T): T[];
getChildren(element: TInput | T): Iterable<T>;
}
export interface IAsyncDataSource<TInput, T> {
hasChildren(element: TInput | T): boolean;
getChildren(element: TInput | T): T[] | Promise<T[]>;
getChildren(element: TInput | T): Iterable<T> | Promise<Iterable<T>>;
}
export const enum TreeDragOverBubble {

View File

@@ -19,6 +19,10 @@ export function fromNow(date: number | Date, appendAgoLabel?: boolean): string {
}
const seconds = Math.round((new Date().getTime() - date) / 1000);
if (seconds < -30) {
return localize('date.fromNow.in', 'in {0}', fromNow(new Date().getTime() + seconds * 1000, false));
}
if (seconds < 30) {
return localize('date.fromNow.now', 'now');
}

View File

@@ -559,6 +559,8 @@ export function fuzzyScore(pattern: string, patternLow: string, patternStart: nu
let patternPos = patternStart;
let wordPos = wordStart;
let hasStrongFirstMatch = false;
// There will be a match, fill in tables
for (row = 1, patternPos = patternStart; patternPos < patternLen; row++, patternPos++) {
@@ -566,6 +568,10 @@ export function fuzzyScore(pattern: string, patternLow: string, patternStart: nu
const score = _doScore(pattern, patternLow, patternPos, patternStart, word, wordLow, wordPos);
if (patternPos === patternStart && score > 1) {
hasStrongFirstMatch = true;
}
_scores[row][column] = score;
const diag = _table[row - 1][column - 1] + (score > 1 ? 1 : score);
@@ -604,6 +610,10 @@ export function fuzzyScore(pattern: string, patternLow: string, patternStart: nu
printTables(pattern, patternStart, word, wordStart);
}
if (!hasStrongFirstMatch && !firstMatchCanBeWeak) {
return undefined;
}
_matchesCount = 0;
_topScore = -100;
_wordStart = wordStart;

View File

@@ -526,15 +526,45 @@ function createMatches(offsets: number[] | undefined): IMatch[] {
}
function normalizeMatches(matches: IMatch[]): IMatch[] {
const positions = new Set<number>();
for (const match of matches) {
for (let i = match.start; i < match.end; i++) {
positions.add(i);
// sort matches by start to be able to normalize
const sortedMatches = matches.sort((matchA, matchB) => {
return matchA.start - matchB.start;
});
// merge matches that overlap
const normalizedMatches: IMatch[] = [];
let currentMatch: IMatch | undefined = undefined;
for (const match of sortedMatches) {
// if we have no current match or the matches
// do not overlap, we take it as is and remember
// it for future merging
if (!currentMatch || !matchOverlaps(currentMatch, match)) {
currentMatch = match;
normalizedMatches.push(match);
}
// otherwise we merge the matches
else {
currentMatch.start = Math.min(currentMatch.start, match.start);
currentMatch.end = Math.max(currentMatch.end, match.end);
}
}
return createMatches(Array.from(positions.values()).sort((a, b) => a - b));
return normalizedMatches;
}
function matchOverlaps(matchA: IMatch, matchB: IMatch): boolean {
if (matchA.end < matchB.start) {
return false; // A ends before B starts
}
if (matchB.end < matchA.start) {
return false; // B ends before A starts
}
return true;
}
//#endregion

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { INavigator, ArrayNavigator } from 'vs/base/common/iterator';
import { INavigator, ArrayNavigator } from 'vs/base/common/navigator';
export class HistoryNavigator<T> implements INavigator<T> {
@@ -45,10 +45,6 @@ export class HistoryNavigator<T> implements INavigator<T> {
return this._navigator.current();
}
public parent(): null {
return null;
}
public first(): T | null {
return this._navigator.first();
}

View File

@@ -3,39 +3,17 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export interface IteratorDefinedResult<T> {
readonly done: false;
readonly value: T;
}
export interface IteratorUndefinedResult {
readonly done: true;
readonly value: undefined;
}
export const FIN: IteratorUndefinedResult = { done: true, value: undefined };
export type IteratorResult<T> = IteratorDefinedResult<T> | IteratorUndefinedResult;
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 namespace Iterable {
const _empty: Iterable<any> = Object.freeze([]);
export function empty<T>(): Iterable<T> {
return _empty;
}
export function from<T>(iterable: Iterable<T> | undefined | null): Iterable<T> {
return iterable || _empty;
}
export function first<T>(iterable: Iterable<T>): T | undefined {
return iterable[Symbol.iterator]().next().value;
}
@@ -52,291 +30,48 @@ export namespace Iterable {
export function* filter<T>(iterable: Iterable<T>, predicate: (t: T) => boolean): Iterable<T> {
for (const element of iterable) {
if (predicate(element)) {
return yield element;
yield element;
}
}
}
export function* map<T, R>(iterable: Iterable<T>, fn: (t: T) => R): Iterable<R> {
for (const element of iterable) {
return yield fn(element);
}
}
}
export module Iterator {
const _empty: Iterator<any> = {
next() {
return FIN;
}
};
export function empty<T>(): Iterator<T> {
return _empty;
}
export function single<T>(value: T): Iterator<T> {
let done = false;
return {
next(): IteratorResult<T> {
if (done) {
return FIN;
}
done = true;
return { done: false, value };
}
};
}
export function fromArray<T>(array: ReadonlyArray<T>, index = 0, length = array.length): Iterator<T> {
return {
next(): IteratorResult<T> {
if (index >= length) {
return FIN;
}
return { done: false, value: array[index++] };
}
};
}
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();
} else if (Array.isArray(elements)) {
return Iterator.fromArray(elements);
} else {
return elements;
yield fn(element);
}
}
export function map<T, R>(iterator: Iterator<T>, fn: (t: T) => R): Iterator<R> {
return {
next() {
const element = iterator.next();
if (element.done) {
return FIN;
} else {
return { done: false, value: fn(element.value) };
}
}
};
}
export function filter<T>(iterator: Iterator<T>, fn: (t: T) => boolean): Iterator<T> {
return {
next() {
while (true) {
const element = iterator.next();
if (element.done) {
return FIN;
}
if (fn(element.value)) {
return { done: false, value: element.value };
}
}
}
};
}
export function some<T>(iterator: Iterator<T> | NativeIterator<T>, fn: (t: T) => boolean): boolean {
while (true) {
const element = iterator.next();
if (element.done) {
return false;
}
if (fn(element.value)) {
return true;
export function* concat<T>(...iterables: Iterable<T>[]): Iterable<T> {
for (const iterable of iterables) {
for (const element of iterable) {
yield element;
}
}
}
export function forEach<T>(iterator: Iterator<T>, fn: (t: T) => void): void {
for (let next = iterator.next(); !next.done; next = iterator.next()) {
fn(next.value);
}
}
export function collect<T>(iterator: Iterator<T>, atMost: number = Number.POSITIVE_INFINITY): T[] {
const result: T[] = [];
/**
* Consumes `atMost` elements from iterable and returns the consumed elements,
* and an iterable for the rest of the elements.
*/
export function consume<T>(iterable: Iterable<T>, atMost: number = Number.POSITIVE_INFINITY): [T[], Iterable<T>] {
const consumed: T[] = [];
if (atMost === 0) {
return result;
return [consumed, iterable];
}
let i = 0;
const iterator = iterable[Symbol.iterator]();
for (let next = iterator.next(); !next.done; next = iterator.next()) {
result.push(next.value);
for (let i = 0; i < atMost; i++) {
const next = iterator.next();
if (++i >= atMost) {
break;
if (next.done) {
return [consumed, Iterable.empty()];
}
consumed.push(next.value);
}
return result;
}
export function concat<T>(...iterators: Iterator<T>[]): Iterator<T> {
let i = 0;
return {
next() {
if (i >= iterators.length) {
return FIN;
}
const iterator = iterators[i];
const result = iterator.next();
if (result.done) {
i++;
return this.next();
}
return result;
}
};
}
export function chain<T>(iterator: Iterator<T>): ChainableIterator<T> {
return new ChainableIterator(iterator);
return [consumed, { [Symbol.iterator]() { return iterator; } }];
}
}
export class ChainableIterator<T> implements Iterator<T> {
constructor(private it: Iterator<T>) { }
next(): IteratorResult<T> { return this.it.next(); }
map<R>(fn: (t: T) => R): ChainableIterator<R> { return new ChainableIterator(Iterator.map(this.it, fn)); }
filter(fn: (t: T) => boolean): ChainableIterator<T> { return new ChainableIterator(Iterator.filter(this.it, fn)); }
}
export type ISequence<T> = Iterator<T> | T[];
export function getSequenceIterator<T>(arg: ISequence<T> | undefined): Iterator<T> {
if (Array.isArray(arg)) {
return Iterator.fromArray(arg);
} else if (!arg) {
return Iterator.empty();
} else {
return arg;
}
}
export interface INextIterator<T> {
next(): T | null;
}
export class ArrayIterator<T> implements INextIterator<T> {
private readonly items: readonly T[];
protected start: number;
protected end: number;
protected index: number;
constructor(items: readonly T[], start: number = 0, end: number = items.length, index = start - 1) {
this.items = items;
this.start = start;
this.end = end;
this.index = index;
}
public first(): T | null {
this.index = this.start;
return this.current();
}
public next(): T | null {
this.index = Math.min(this.index + 1, this.end);
return this.current();
}
protected current(): T | null {
if (this.index === this.start - 1 || this.index === this.end) {
return null;
}
return this.items[this.index];
}
}
export class ArrayNavigator<T> extends ArrayIterator<T> implements INavigator<T> {
constructor(items: readonly T[], start: number = 0, end: number = items.length, index = start - 1) {
super(items, start, end, index);
}
public current(): T | null {
return super.current();
}
public previous(): T | null {
this.index = Math.max(this.index - 1, this.start - 1);
return this.current();
}
public first(): T | null {
this.index = this.start;
return this.current();
}
public last(): T | null {
this.index = this.end - 1;
return this.current();
}
public parent(): T | null {
return null;
}
}
export class MappedIterator<T, R> implements INextIterator<R> {
constructor(protected iterator: INextIterator<T>, protected fn: (item: T | null) => R) {
// noop
}
next() { return this.fn(this.iterator.next()); }
}
export interface INavigator<T> extends INextIterator<T> {
current(): T | null;
previous(): T | null;
parent(): T | null;
first(): T | null;
last(): T | null;
next(): T | null;
}
export class MappedNavigator<T, R> extends MappedIterator<T, R> implements INavigator<R> {
constructor(protected navigator: INavigator<T>, fn: (item: T | null) => R) {
super(navigator, fn);
}
current() { return this.fn(this.navigator.current()); }
previous() { return this.fn(this.navigator.previous()); }
parent() { return this.fn(this.navigator.parent()); }
first() { return this.fn(this.navigator.first()); }
last() { return this.fn(this.navigator.last()); }
next() { return this.fn(this.navigator.next()); }
}

View File

@@ -18,7 +18,7 @@ export interface IWorkspaceFolderProvider {
}
export interface IUserHomeProvider {
userHome: string;
userHome?: URI;
}
/**
@@ -63,8 +63,8 @@ export function getPathLabel(resource: URI | string, userHomeProvider?: IUserHom
// normalize and tildify (macOS, Linux only)
let res = normalize(resource.fsPath);
if (!isWindows && userHomeProvider) {
res = tildify(res, userHomeProvider.userHome);
if (!isWindows && userHomeProvider?.userHome) {
res = tildify(res, userHomeProvider.userHome.fsPath);
}
return res;

View File

@@ -5,7 +5,7 @@
import { URI } from 'vs/base/common/uri';
import { CharCode } from 'vs/base/common/charCode';
import { FIN } from './iterator';
import { compareIgnoreCase, compare } from 'vs/base/common/strings';
/**
* @deprecated ES6: use `[...SetOrMap.values()]`
@@ -56,8 +56,8 @@ export function setToString<K>(set: Set<K>): string {
return `Set(${set.size}) {${entries.join(', ')}}`;
}
export interface IKeyIterator {
reset(key: string): this;
export interface IKeyIterator<K> {
reset(key: K): this;
next(): this;
hasNext(): boolean;
@@ -65,7 +65,7 @@ export interface IKeyIterator {
value(): string;
}
export class StringIterator implements IKeyIterator {
export class StringIterator implements IKeyIterator<string> {
private _value: string = '';
private _pos: number = 0;
@@ -96,7 +96,7 @@ export class StringIterator implements IKeyIterator {
}
}
export class PathIterator implements IKeyIterator {
export class PathIterator implements IKeyIterator<string> {
private _value!: string;
private _from!: number;
@@ -163,33 +163,118 @@ export class PathIterator implements IKeyIterator {
}
}
class TernarySearchTreeNode<E> {
const enum UriIteratorState {
Scheme = 1, Authority = 2, Path = 3, Query = 4, Fragment = 5
}
export class UriIterator implements IKeyIterator<URI> {
private _pathIterator = new PathIterator(false);
private _value!: URI;
private _states: UriIteratorState[] = [];
private _stateIdx: number = 0;
reset(key: URI): this {
this._value = key;
this._states = [];
if (this._value.scheme) {
this._states.push(UriIteratorState.Scheme);
}
if (this._value.authority) {
this._states.push(UriIteratorState.Authority);
}
if (this._value.path) {
this._pathIterator.reset(key.path);
if (this._pathIterator.value()) {
this._states.push(UriIteratorState.Path);
}
}
if (this._value.query) {
this._states.push(UriIteratorState.Query);
}
if (this._value.fragment) {
this._states.push(UriIteratorState.Fragment);
}
this._stateIdx = 0;
return this;
}
next(): this {
if (this._states[this._stateIdx] === UriIteratorState.Path && this._pathIterator.hasNext()) {
this._pathIterator.next();
} else {
this._stateIdx += 1;
}
return this;
}
hasNext(): boolean {
return (this._states[this._stateIdx] === UriIteratorState.Path && this._pathIterator.hasNext())
|| this._stateIdx < this._states.length - 1;
}
cmp(a: string): number {
if (this._states[this._stateIdx] === UriIteratorState.Scheme) {
return compareIgnoreCase(a, this._value.scheme);
} else if (this._states[this._stateIdx] === UriIteratorState.Authority) {
return compareIgnoreCase(a, this._value.authority);
} else if (this._states[this._stateIdx] === UriIteratorState.Path) {
return this._pathIterator.cmp(a);
} else if (this._states[this._stateIdx] === UriIteratorState.Query) {
return compare(a, this._value.query);
} else if (this._states[this._stateIdx] === UriIteratorState.Fragment) {
return compare(a, this._value.fragment);
}
throw new Error();
}
value(): string {
if (this._states[this._stateIdx] === UriIteratorState.Scheme) {
return this._value.scheme;
} else if (this._states[this._stateIdx] === UriIteratorState.Authority) {
return this._value.authority;
} else if (this._states[this._stateIdx] === UriIteratorState.Path) {
return this._pathIterator.value();
} else if (this._states[this._stateIdx] === UriIteratorState.Query) {
return this._value.query;
} else if (this._states[this._stateIdx] === UriIteratorState.Fragment) {
return this._value.fragment;
}
throw new Error();
}
}
class TernarySearchTreeNode<K, V> {
segment!: string;
value: E | undefined;
key!: string;
left: TernarySearchTreeNode<E> | undefined;
mid: TernarySearchTreeNode<E> | undefined;
right: TernarySearchTreeNode<E> | undefined;
value: V | undefined;
key!: K;
left: TernarySearchTreeNode<K, V> | undefined;
mid: TernarySearchTreeNode<K, V> | undefined;
right: TernarySearchTreeNode<K, V> | undefined;
isEmpty(): boolean {
return !this.left && !this.mid && !this.right && !this.value;
}
}
export class TernarySearchTree<E> {
export class TernarySearchTree<K, V> {
static forPaths<E>(): TernarySearchTree<E> {
return new TernarySearchTree<E>(new PathIterator());
static forUris<E>(): TernarySearchTree<URI, E> {
return new TernarySearchTree<URI, E>(new UriIterator());
}
static forStrings<E>(): TernarySearchTree<E> {
return new TernarySearchTree<E>(new StringIterator());
static forPaths<E>(): TernarySearchTree<string, E> {
return new TernarySearchTree<string, E>(new PathIterator());
}
private _iter: IKeyIterator;
private _root: TernarySearchTreeNode<E> | undefined;
static forStrings<E>(): TernarySearchTree<string, E> {
return new TernarySearchTree<string, E>(new StringIterator());
}
constructor(segments: IKeyIterator) {
private _iter: IKeyIterator<K>;
private _root: TernarySearchTreeNode<K, V> | undefined;
constructor(segments: IKeyIterator<K>) {
this._iter = segments;
}
@@ -197,12 +282,12 @@ export class TernarySearchTree<E> {
this._root = undefined;
}
set(key: string, element: E): E | undefined {
set(key: K, element: V): V | undefined {
const iter = this._iter.reset(key);
let node: TernarySearchTreeNode<E>;
let node: TernarySearchTreeNode<K, V>;
if (!this._root) {
this._root = new TernarySearchTreeNode<E>();
this._root = new TernarySearchTreeNode<K, V>();
this._root.segment = iter.value();
}
@@ -212,7 +297,7 @@ export class TernarySearchTree<E> {
if (val > 0) {
// left
if (!node.left) {
node.left = new TernarySearchTreeNode<E>();
node.left = new TernarySearchTreeNode<K, V>();
node.left.segment = iter.value();
}
node = node.left;
@@ -220,7 +305,7 @@ export class TernarySearchTree<E> {
} else if (val < 0) {
// right
if (!node.right) {
node.right = new TernarySearchTreeNode<E>();
node.right = new TernarySearchTreeNode<K, V>();
node.right.segment = iter.value();
}
node = node.right;
@@ -229,7 +314,7 @@ export class TernarySearchTree<E> {
// mid
iter.next();
if (!node.mid) {
node.mid = new TernarySearchTreeNode<E>();
node.mid = new TernarySearchTreeNode<K, V>();
node.mid.segment = iter.value();
}
node = node.mid;
@@ -243,7 +328,7 @@ export class TernarySearchTree<E> {
return oldElement;
}
get(key: string): E | undefined {
get(key: K): V | undefined {
const iter = this._iter.reset(key);
let node = this._root;
while (node) {
@@ -265,10 +350,10 @@ export class TernarySearchTree<E> {
return node ? node.value : undefined;
}
delete(key: string): void {
delete(key: K): void {
const iter = this._iter.reset(key);
const stack: [-1 | 0 | 1, TernarySearchTreeNode<E>][] = [];
const stack: [-1 | 0 | 1, TernarySearchTreeNode<K, V>][] = [];
let node = this._root;
// find and unset node
@@ -306,10 +391,10 @@ export class TernarySearchTree<E> {
}
}
findSubstr(key: string): E | undefined {
findSubstr(key: K): V | undefined {
const iter = this._iter.reset(key);
let node = this._root;
let candidate: E | undefined = undefined;
let candidate: V | undefined = undefined;
while (node) {
const val = iter.cmp(node.segment);
if (val > 0) {
@@ -330,7 +415,7 @@ export class TernarySearchTree<E> {
return node && node.value || candidate;
}
findSuperstr(key: string): Iterator<E> | undefined {
findSuperstr(key: K): Iterator<V> | undefined {
const iter = this._iter.reset(key);
let node = this._root;
while (node) {
@@ -357,11 +442,11 @@ export class TernarySearchTree<E> {
return undefined;
}
private _nodeIterator(node: TernarySearchTreeNode<E>): Iterator<E> {
let res: { done: false; value: E; };
private _nodeIterator(node: TernarySearchTreeNode<K, V>): Iterator<V> {
let res: { done: false; value: V; };
let idx: number;
let data: E[];
const next = (): IteratorResult<E> => {
let data: V[];
const next = (): IteratorResult<V> => {
if (!data) {
// lazy till first invocation
data = [];
@@ -369,7 +454,7 @@ export class TernarySearchTree<E> {
this._forEach(node, value => data.push(value));
}
if (idx >= data.length) {
return FIN;
return { done: true, value: undefined };
}
if (!res) {
@@ -382,11 +467,11 @@ export class TernarySearchTree<E> {
return { next };
}
forEach(callback: (value: E, index: string) => any) {
forEach(callback: (value: V, index: K) => any) {
this._forEach(this._root, callback);
}
private _forEach(node: TernarySearchTreeNode<E> | undefined, callback: (value: E, index: string) => any) {
private _forEach(node: TernarySearchTreeNode<K, V> | undefined, callback: (value: V, index: K) => any) {
if (node) {
// left
this._forEach(node.left, callback);

View File

@@ -0,0 +1,50 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export interface INavigator<T> {
current(): T | null;
previous(): T | null;
first(): T | null;
last(): T | null;
next(): T | null;
}
export class ArrayNavigator<T> implements INavigator<T> {
constructor(
private readonly items: readonly T[],
protected start: number = 0,
protected end: number = items.length,
protected index = start - 1
) { }
current(): T | null {
if (this.index === this.start - 1 || this.index === this.end) {
return null;
}
return this.items[this.index];
}
next(): T | null {
this.index = Math.min(this.index + 1, this.end);
return this.current();
}
previous(): T | null {
this.index = Math.max(this.index - 1, this.start - 1);
return this.current();
}
first(): T | null {
this.index = this.start;
return this.current();
}
last(): T | null {
this.index = this.end - 1;
return this.current();
}
}

View File

@@ -5,7 +5,6 @@
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 { PathIterator, values } from 'vs/base/common/map';
@@ -15,7 +14,7 @@ export interface IResourceNode<T, C = void> {
readonly relativePath: string;
readonly name: string;
readonly element: T | undefined;
readonly children: Iterator<IResourceNode<T, C>>;
readonly children: Iterable<IResourceNode<T, C>>;
readonly childrenCount: number;
readonly parent: IResourceNode<T, C> | undefined;
readonly context: C;
@@ -30,8 +29,8 @@ class Node<T, C> implements IResourceNode<T, C> {
return this._children.size;
}
get children(): Iterator<Node<T, C>> {
return Iterator.fromArray(values(this._children));
get children(): Iterable<Node<T, C>> {
return [...values(this._children)];
}
@memoize
@@ -69,7 +68,9 @@ function collect<T, C>(node: IResourceNode<T, C>, result: T[]): T[] {
result.push(node.element);
}
Iterator.forEach(node.children, child => collect(child, result));
for (const child of node.children) {
collect(child, result);
}
return result;
}

View File

@@ -5,7 +5,7 @@
import * as extpath from 'vs/base/common/extpath';
import * as paths from 'vs/base/common/path';
import { URI } from 'vs/base/common/uri';
import { URI, uriToFsPath } from 'vs/base/common/uri';
import { equalsIgnoreCase } from 'vs/base/common/strings';
import { Schemas } from 'vs/base/common/network';
import { isLinux, isWindows } from 'vs/base/common/platform';
@@ -14,26 +14,7 @@ import { ParsedExpression, IExpression, parse } from 'vs/base/common/glob';
import { TernarySearchTree } from 'vs/base/common/map';
export function originalFSPath(uri: URI): string {
let value: string;
const uriPath = uri.path;
if (uri.authority && uriPath.length > 1 && uri.scheme === 'file') {
// unc path: file://shares/c$/far/boo
value = `//${uri.authority}${uriPath}`;
} else if (
isWindows
&& uriPath.charCodeAt(0) === CharCode.Slash
&& extpath.isWindowsDriveLetter(uriPath.charCodeAt(1))
&& uriPath.charCodeAt(2) === CharCode.Colon
) {
value = uriPath.substr(1);
} else {
// other path
value = uriPath;
}
if (isWindows) {
value = value.replace(/\//g, '\\');
}
return value;
return uriToFsPath(uri, true);
}
/**
@@ -336,7 +317,7 @@ export namespace DataUri {
export class ResourceGlobMatcher {
private readonly globalExpression: ParsedExpression;
private readonly expressionsByRoot: TernarySearchTree<{ root: URI, expression: ParsedExpression }> = TernarySearchTree.forPaths<{ root: URI, expression: ParsedExpression }>();
private readonly expressionsByRoot: TernarySearchTree<string, { root: URI, expression: ParsedExpression }> = TernarySearchTree.forPaths<{ root: URI, expression: ParsedExpression }>();
constructor(
globalExpression: IExpression,

View File

@@ -295,11 +295,12 @@ export function compare(a: string, b: string): number {
}
}
export function compareIgnoreCase(a: string, b: string): number {
const len = Math.min(a.length, b.length);
for (let i = 0; i < len; i++) {
let codeA = a.charCodeAt(i);
let codeB = b.charCodeAt(i);
export function compareIgnoreCase(a: string, b: string, aStart: number = 0, aEnd: number = a.length, bStart: number = 0, bEnd: number = b.length): number {
for (; aStart < aEnd && bStart < bEnd; aStart++, bStart++) {
let codeA = a.charCodeAt(aStart);
let codeB = b.charCodeAt(bStart);
if (codeA === codeB) {
// equal
@@ -329,13 +330,16 @@ export function compareIgnoreCase(a: string, b: string): number {
}
}
if (a.length < b.length) {
const aLen = aEnd - aStart;
const bLen = bEnd - bStart;
if (aLen < bLen) {
return -1;
} else if (a.length > b.length) {
} else if (aLen > bLen) {
return 1;
} else {
return 0;
}
return 0;
}
export function isLowerAsciiLetter(code: number): boolean {

View File

@@ -205,7 +205,7 @@ export class URI implements UriComponents {
// if (this.scheme !== 'file') {
// console.warn(`[UriError] calling fsPath with scheme ${this.scheme}`);
// }
return _makeFsPath(this, false);
return uriToFsPath(this, false);
}
// ---- modify to new -------------------------
@@ -349,7 +349,7 @@ export class URI implements UriComponents {
}
let newPath: string;
if (isWindows && uri.scheme === 'file') {
newPath = URI.file(paths.win32.join(_makeFsPath(uri, true), ...pathFragment)).path;
newPath = URI.file(paths.win32.join(uriToFsPath(uri, true), ...pathFragment)).path;
} else {
newPath = paths.posix.join(uri.path, ...pathFragment);
}
@@ -421,7 +421,7 @@ class _URI extends URI {
get fsPath(): string {
if (!this._fsPath) {
this._fsPath = _makeFsPath(this, false);
this._fsPath = uriToFsPath(this, false);
}
return this._fsPath;
}
@@ -577,7 +577,7 @@ function encodeURIComponentMinimal(path: string): string {
/**
* Compute `fsPath` for the given uri
*/
function _makeFsPath(uri: URI, keepDriveLetterCasing: boolean): string {
export function uriToFsPath(uri: URI, keepDriveLetterCasing: boolean): string {
let value: string;
if (uri.authority && uri.path.length > 1 && uri.scheme === 'file') {

View File

@@ -21,7 +21,7 @@ import { getMac } from 'vs/base/node/macAddress';
// Sun xVM VirtualBox 08-00-27
export const virtualMachineHint: { value(): number } = new class {
private _virtualMachineOUIs?: TernarySearchTree<boolean>;
private _virtualMachineOUIs?: TernarySearchTree<string, boolean>;
private _value?: number;
private _isVirtualMachineMacAdress(mac: string): boolean {

View File

@@ -201,7 +201,8 @@
flex: 1; /* make sure the icon label grows within the row */
}
.quick-input-list .quick-input-list-rows > .quick-input-list-row .codicon {
.quick-input-list .quick-input-list-rows > .quick-input-list-row .codicon[class*='codicon-'] {
color: currentColor !important;
vertical-align: sub;
}
@@ -237,7 +238,7 @@
.quick-input-list .quick-input-list-entry-action-bar .action-label {
/*
* By default, actions in the quick input action bar are hidden
* until hovered over them or selected.
* until hovered over them or selected.
*/
display: none;
}

View File

@@ -825,7 +825,16 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
if (!this.visible) {
return;
}
const hideInput = !!this._hideInput && this._items.length > 0; // do not allow to hide input without items
let hideInput = false;
let inputShownJustForScreenReader = false;
if (!!this._hideInput && this._items.length > 0) {
if (this.ui.isScreenReaderOptimized()) {
// Always show input if screen reader attached https://github.com/microsoft/vscode/issues/94360
inputShownJustForScreenReader = true;
} else {
hideInput = true;
}
}
dom.toggleClass(this.ui.container, 'hidden-input', hideInput);
const visibilities: Visibilities = {
title: !!this.title || !!this.step,
@@ -852,7 +861,9 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
if (this.ui.inputBox.placeholder !== (this.placeholder || '')) {
this.ui.inputBox.placeholder = (this.placeholder || '');
}
if (this.ui.inputBox.ariaLabel !== this.ariaLabel) {
if (inputShownJustForScreenReader) {
this.ui.inputBox.ariaLabel = '';
} else if (this.ui.inputBox.ariaLabel !== this.ariaLabel) {
this.ui.inputBox.ariaLabel = this.ariaLabel;
}
this.ui.list.matchOnDescription = this.matchOnDescription;
@@ -1072,6 +1083,8 @@ export class QuickInputController extends Disposable {
private onHideEmitter = new Emitter<void>();
readonly onHide = this.onHideEmitter.event;
private previousFocusElement?: HTMLElement;
constructor(private options: IQuickInputOptions) {
super();
this.idPrefix = options.idPrefix;
@@ -1188,7 +1201,11 @@ export class QuickInputController extends Disposable {
const focusTracker = dom.trackFocus(container);
this._register(focusTracker);
this._register(dom.addDisposableListener(container, dom.EventType.FOCUS, e => {
this.previousFocusElement = e.relatedTarget instanceof HTMLElement ? e.relatedTarget : undefined;
}, true));
this._register(focusTracker.onDidBlur(() => {
this.previousFocusElement = undefined;
if (!this.getUI().ignoreFocusOut && !this.options.ignoreFocusOut()) {
this.hide(true);
}
@@ -1538,7 +1555,12 @@ export class QuickInputController extends Disposable {
this.onHideEmitter.fire();
this.getUI().container.style.display = 'none';
if (!focusLost) {
this.options.returnFocus();
if (this.previousFocusElement && this.previousFocusElement.offsetParent) {
this.previousFocusElement.focus();
this.previousFocusElement = undefined;
} else {
this.options.returnFocus();
}
}
controller.didHide();
}

View File

@@ -692,6 +692,10 @@ function compareEntries(elementA: ListElement, elementB: ListElement, lookFor: s
return 1;
}
if (labelHighlightsA.length === 0 && labelHighlightsB.length === 0) {
return 0;
}
return compareAnything(elementA.saneLabel, elementB.saneLabel, lookFor);
}

View File

@@ -6,7 +6,7 @@
import * as Touch from 'vs/base/browser/touch';
import * as Mouse from 'vs/base/browser/mouseEvent';
import * as Keyboard from 'vs/base/browser/keyboardEvent';
import { INavigator } from 'vs/base/common/iterator';
import { INavigator } from 'sql/base/common/navigator';
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
import { Event } from 'vs/base/common/event';
import { IAction } from 'vs/base/common/actions';

View File

@@ -8,7 +8,7 @@ import * as TreeDefaults from 'vs/base/parts/tree/browser/treeDefaults';
import * as Model from 'vs/base/parts/tree/browser/treeModel';
import * as View from './treeView';
import * as _ from 'vs/base/parts/tree/browser/tree';
import { INavigator, MappedNavigator } from 'vs/base/common/iterator';
import { INavigator, MappedNavigator } from 'sql/base/common/navigator';
import { Event, Emitter, Relay } from 'vs/base/common/event';
import { Color } from 'vs/base/common/color';
import { mixin } from 'vs/base/common/objects';

View File

@@ -6,7 +6,7 @@
import * as Assert from 'vs/base/common/assert';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IDisposable, combinedDisposable, Disposable } from 'vs/base/common/lifecycle';
import { INavigator } from 'vs/base/common/iterator';
import { INavigator } from 'sql/base/common/navigator';
import * as _ from './tree';
import { Event, Emitter, EventMultiplexer, Relay } from 'vs/base/common/event';

View File

@@ -14,7 +14,7 @@ import * as Mouse from 'vs/base/browser/mouseEvent';
import * as Keyboard from 'vs/base/browser/keyboardEvent';
import * as Model from 'vs/base/parts/tree/browser/treeModel';
import * as dnd from './treeDnd';
import { ArrayIterator, MappedIterator } from 'vs/base/common/iterator';
import { ArrayNavigator } from 'vs/base/common/navigator';
import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
import { HeightMap, IViewItem } from 'vs/base/parts/tree/browser/treeViewModel';
@@ -24,6 +24,7 @@ import { Event, Emitter } from 'vs/base/common/event';
import { DataTransfers, StaticDND, IDragAndDropData } from 'vs/base/browser/dnd';
import { DefaultTreestyler } from './treeDefaults';
import { Delayer, timeout } from 'vs/base/common/async';
import { MappedNavigator } from 'sql/base/common/navigator';
export interface IRow {
element: HTMLElement | null;
@@ -829,7 +830,7 @@ export class TreeView extends HeightMap {
private onClearingInput(e: Model.IInputEvent): void {
let item = <Model.Item>e.item;
if (item) {
this.onRemoveItems(new MappedIterator(item.getNavigator(), item => item && item.id));
this.onRemoveItems(new MappedNavigator(item.getNavigator(), item => item && item.id));
this.onRowsChanged();
}
}
@@ -925,20 +926,20 @@ export class TreeView extends HeightMap {
for (const diffChange of diff) {
if (diffChange.originalLength > 0) {
this.onRemoveItems(new ArrayIterator(previousChildrenIds, diffChange.originalStart, diffChange.originalStart + diffChange.originalLength));
this.onRemoveItems(new ArrayNavigator(previousChildrenIds, diffChange.originalStart, diffChange.originalStart + diffChange.originalLength));
}
if (diffChange.modifiedLength > 0) {
let beforeItem: Model.Item | null = afterModelItems[diffChange.modifiedStart - 1] || item;
beforeItem = beforeItem.getDepth() > 0 ? beforeItem : null;
this.onInsertItems(new ArrayIterator(afterModelItems, diffChange.modifiedStart, diffChange.modifiedStart + diffChange.modifiedLength), beforeItem ? beforeItem.id : null);
this.onInsertItems(new ArrayNavigator(afterModelItems, diffChange.modifiedStart, diffChange.modifiedStart + diffChange.modifiedLength), beforeItem ? beforeItem.id : null);
}
}
} else if (skipDiff || diff.length) {
this.onRemoveItems(new ArrayIterator(previousChildrenIds));
this.onInsertItems(new ArrayIterator(afterModelItems), item.getDepth() > 0 ? item.id : null);
this.onRemoveItems(new ArrayNavigator(previousChildrenIds));
this.onInsertItems(new ArrayNavigator(afterModelItems), item.getDepth() > 0 ? item.id : null);
}
if (skipDiff || diff.length) {
@@ -985,7 +986,7 @@ export class TreeView extends HeightMap {
let viewItem = this.items[item.id];
if (viewItem) {
viewItem.expanded = false;
this.onRemoveItems(new MappedIterator(item.getNavigator(), item => item && item.id));
this.onRemoveItems(new MappedNavigator(item.getNavigator(), item => item && item.id));
this.onRowsChanged();
}
}

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { INextIterator, ArrayIterator } from 'vs/base/common/iterator';
import { ArrayNavigator, INavigator } from 'vs/base/common/navigator';
import { Item } from './treeModel';
export interface IViewItem {
@@ -23,7 +23,7 @@ export class HeightMap {
return !last ? 0 : last.top + last.height;
}
onInsertItems(iterator: INextIterator<Item>, afterItemId: string | null = null): number | undefined {
onInsertItems(iterator: INavigator<Item>, afterItemId: string | null = null): number | undefined {
let item: Item | null = null;
let viewItem: IViewItem;
let i: number, j: number;
@@ -81,7 +81,7 @@ export class HeightMap {
}
// Contiguous items
onRemoveItems(iterator: INextIterator<string>): void {
onRemoveItems(iterator: INavigator<string>): void {
let itemId: string | null = null;
let viewItem: IViewItem;
let startIndex: number | null = null;
@@ -126,11 +126,11 @@ export class HeightMap {
onRefreshItemSet(items: Item[]): void {
let sortedItems = items.sort((a, b) => this.indexes[a.id] - this.indexes[b.id]);
this.onRefreshItems(new ArrayIterator(sortedItems));
this.onRefreshItems(new ArrayNavigator(sortedItems));
}
// Ordered, but not necessarily contiguous items
onRefreshItems(iterator: INextIterator<Item>): void {
onRefreshItems(iterator: INavigator<Item>): void {
let item: Item | null = null;
let viewItem: IViewItem;
let newHeight: number;

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { ArrayIterator } from 'vs/base/common/iterator';
import { ArrayNavigator } from 'vs/base/common/navigator';
import { HeightMap, IViewItem } from 'vs/base/parts/tree/browser/treeViewModel';
function makeItem(id: any, height: any): any {
@@ -139,7 +139,7 @@ suite('TreeView - HeightMap', () => {
});
test('onRemoveItems at beginning', () => {
rangeMap.onRemoveItems(new ArrayIterator(['a', 'b']));
rangeMap.onRemoveItems(new ArrayNavigator(['a', 'b']));
assert.equal(rangeMap.itemAt(0), 'c');
assert.equal(rangeMap.itemAt(24), 'c');
@@ -149,7 +149,7 @@ suite('TreeView - HeightMap', () => {
});
test('onRemoveItems in middle', () => {
rangeMap.onRemoveItems(new ArrayIterator(['c']));
rangeMap.onRemoveItems(new ArrayNavigator(['c']));
assert.equal(rangeMap.itemAt(0), 'a');
assert.equal(rangeMap.itemAt(2), 'a');
@@ -161,7 +161,7 @@ suite('TreeView - HeightMap', () => {
});
test('onRemoveItems at end', () => {
rangeMap.onRemoveItems(new ArrayIterator(['c', 'd']));
rangeMap.onRemoveItems(new ArrayNavigator(['c', 'd']));
assert.equal(rangeMap.itemAt(0), 'a');
assert.equal(rangeMap.itemAt(2), 'a');

View File

@@ -5,7 +5,7 @@
import * as assert from 'assert';
import { compress, ICompressedTreeElement, ICompressedTreeNode, decompress, CompressedObjectTreeModel } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
import { Iterator } from 'vs/base/common/iterator';
import { Iterable } from 'vs/base/common/iterator';
import { ITreeNode } from 'vs/base/browser/ui/tree/tree';
import { ISpliceable } from 'vs/base/common/sequence';
@@ -16,7 +16,7 @@ interface IResolvedCompressedTreeElement<T> extends ICompressedTreeElement<T> {
function resolve<T>(treeElement: ICompressedTreeElement<T>): IResolvedCompressedTreeElement<T> {
const result: any = { element: treeElement.element };
const children = Iterator.collect(Iterator.map(Iterator.from(treeElement.children), resolve));
const children = [...Iterable.map(Iterable.from(treeElement.children), resolve)];
if (treeElement.incompressible) {
result.incompressible = true;
@@ -315,25 +315,25 @@ suite('CompressedObjectTree', function () {
const list: ITreeNode<ICompressedTreeNode<number>>[] = [];
const model = new CompressedObjectTreeModel<number>('test', toSpliceable(list));
model.setChildren(null, Iterator.fromArray([
model.setChildren(null, [
{ element: 0 },
{ element: 1 },
{ element: 2 }
]));
]);
assert.deepEqual(toArray(list), [[0], [1], [2]]);
assert.equal(model.size, 3);
model.setChildren(null, Iterator.fromArray([
model.setChildren(null, [
{ element: 3 },
{ element: 4 },
{ element: 5 },
]));
]);
assert.deepEqual(toArray(list), [[3], [4], [5]]);
assert.equal(model.size, 3);
model.setChildren(null, Iterator.empty());
model.setChildren(null);
assert.deepEqual(toArray(list), []);
assert.equal(model.size, 0);
});
@@ -342,34 +342,34 @@ suite('CompressedObjectTree', function () {
const list: ITreeNode<ICompressedTreeNode<number>>[] = [];
const model = new CompressedObjectTreeModel<number>('test', toSpliceable(list));
model.setChildren(null, Iterator.fromArray([
model.setChildren(null, [
{
element: 0, children: Iterator.fromArray([
element: 0, children: [
{ element: 10 },
{ element: 11 },
{ element: 12 },
])
]
},
{ element: 1 },
{ element: 2 }
]));
]);
assert.deepEqual(toArray(list), [[0], [10], [11], [12], [1], [2]]);
assert.equal(model.size, 6);
model.setChildren(12, Iterator.fromArray([
model.setChildren(12, [
{ element: 120 },
{ element: 121 }
]));
]);
assert.deepEqual(toArray(list), [[0], [10], [11], [12], [120], [121], [1], [2]]);
assert.equal(model.size, 8);
model.setChildren(0, Iterator.empty());
model.setChildren(0);
assert.deepEqual(toArray(list), [[0], [1], [2]]);
assert.equal(model.size, 3);
model.setChildren(null, Iterator.empty());
model.setChildren(null);
assert.deepEqual(toArray(list), []);
assert.equal(model.size, 0);
});
@@ -378,50 +378,50 @@ suite('CompressedObjectTree', function () {
const list: ITreeNode<ICompressedTreeNode<number>>[] = [];
const model = new CompressedObjectTreeModel<number>('test', toSpliceable(list));
model.setChildren(null, Iterator.fromArray([
model.setChildren(null, [
{
element: 1, children: Iterator.fromArray([{
element: 11, children: Iterator.fromArray([{
element: 111, children: Iterator.fromArray([
element: 1, children: [{
element: 11, children: [{
element: 111, children: [
{ element: 1111 },
{ element: 1112 },
{ element: 1113 },
])
}])
}])
]
}]
}]
}
]));
]);
assert.deepEqual(toArray(list), [[1, 11, 111], [1111], [1112], [1113]]);
assert.equal(model.size, 6);
model.setChildren(11, Iterator.fromArray([
model.setChildren(11, [
{ element: 111 },
{ element: 112 },
{ element: 113 },
]));
]);
assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113]]);
assert.equal(model.size, 5);
model.setChildren(113, Iterator.fromArray([
model.setChildren(113, [
{ element: 1131 }
]));
]);
assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113, 1131]]);
assert.equal(model.size, 6);
model.setChildren(1131, Iterator.fromArray([
model.setChildren(1131, [
{ element: 1132 }
]));
]);
assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113, 1131, 1132]]);
assert.equal(model.size, 7);
model.setChildren(1131, Iterator.fromArray([
model.setChildren(1131, [
{ element: 1132 },
{ element: 1133 },
]));
]);
assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113, 1131], [1132], [1133]]);
assert.equal(model.size, 8);

View File

@@ -6,7 +6,6 @@
import * as assert from 'assert';
import { ITreeNode, ITreeFilter, TreeVisibility } from 'vs/base/browser/ui/tree/tree';
import { ISpliceable } from 'vs/base/common/sequence';
import { Iterator } from 'vs/base/common/iterator';
import { IndexTreeModel, IIndexTreeNode } from 'vs/base/browser/ui/tree/indexTreeModel';
function toSpliceable<T>(arr: T[]): ISpliceable<T> {
@@ -34,11 +33,11 @@ suite('IndexTreeModel', function () {
const list: ITreeNode<number>[] = [];
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{ element: 0 },
{ element: 1 },
{ element: 2 }
]));
]);
assert.deepEqual(list.length, 3);
assert.deepEqual(list[0].element, 0);
@@ -56,17 +55,17 @@ suite('IndexTreeModel', function () {
const list: ITreeNode<number>[] = [];
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{
element: 0, children: Iterator.fromArray([
element: 0, children: [
{ element: 10 },
{ element: 11 },
{ element: 12 },
])
]
},
{ element: 1 },
{ element: 2 }
]));
]);
assert.deepEqual(list.length, 6);
assert.deepEqual(list[0].element, 0);
@@ -93,17 +92,17 @@ suite('IndexTreeModel', function () {
const list: ITreeNode<number>[] = [];
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{
element: 0, collapsed: true, children: Iterator.fromArray([
element: 0, collapsed: true, children: [
{ element: 10 },
{ element: 11 },
{ element: 12 },
])
]
},
{ element: 1 },
{ element: 2 }
]));
]);
assert.deepEqual(list.length, 3);
assert.deepEqual(list[0].element, 0);
@@ -121,11 +120,11 @@ suite('IndexTreeModel', function () {
const list: ITreeNode<number>[] = [];
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{ element: 0 },
{ element: 1 },
{ element: 2 }
]));
]);
assert.deepEqual(list.length, 3);
@@ -146,17 +145,17 @@ suite('IndexTreeModel', function () {
const list: ITreeNode<number>[] = [];
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{
element: 0, children: Iterator.fromArray([
element: 0, children: [
{ element: 10 },
{ element: 11 },
{ element: 12 },
])
]
},
{ element: 1 },
{ element: 2 }
]));
]);
assert.deepEqual(list.length, 6);
@@ -180,17 +179,17 @@ suite('IndexTreeModel', function () {
const list: ITreeNode<number>[] = [];
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{
element: 0, children: Iterator.fromArray([
element: 0, children: [
{ element: 10 },
{ element: 11 },
{ element: 12 },
])
]
},
{ element: 1 },
{ element: 2 }
]));
]);
assert.deepEqual(list.length, 6);
@@ -208,17 +207,17 @@ suite('IndexTreeModel', function () {
const list: ITreeNode<number>[] = [];
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{
element: 0, collapsed: true, children: Iterator.fromArray([
element: 0, collapsed: true, children: [
{ element: 10 },
{ element: 11 },
{ element: 12 },
])
]
},
{ element: 1 },
{ element: 2 }
]));
]);
assert.deepEqual(list.length, 3);
@@ -233,17 +232,17 @@ suite('IndexTreeModel', function () {
const list: ITreeNode<number>[] = [];
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{
element: 0, children: Iterator.fromArray([
element: 0, children: [
{ element: 10 },
{ element: 11 },
{ element: 12 },
])
]
},
{ element: 1 },
{ element: 2 }
]));
]);
assert.deepEqual(list.length, 6);
@@ -264,17 +263,17 @@ suite('IndexTreeModel', function () {
const list: ITreeNode<number>[] = [];
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{
element: 0, collapsed: true, children: Iterator.fromArray([
element: 0, collapsed: true, children: [
{ element: 10 },
{ element: 11 },
{ element: 12 },
])
]
},
{ element: 1 },
{ element: 2 }
]));
]);
assert.deepEqual(list.length, 3);
@@ -304,7 +303,7 @@ suite('IndexTreeModel', function () {
const list: ITreeNode<number>[] = [];
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{
element: 1, children: [
{
@@ -319,7 +318,7 @@ suite('IndexTreeModel', function () {
{ element: 21 }
]
}
]));
]);
assert.deepEqual(list.length, 5);
assert.deepEqual(toArray(list), [1, 11, 111, 2, 21]);
@@ -337,13 +336,13 @@ suite('IndexTreeModel', function () {
const list: ITreeNode<number>[] = [];
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{
element: 0, children: Iterator.fromArray([
element: 0, children: [
{ element: 10 }
])
]
}
]));
]);
assert.deepEqual(list.length, 2);
@@ -406,7 +405,7 @@ suite('IndexTreeModel', function () {
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1, { filter });
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{
element: 0, children: [
{ element: 1 },
@@ -418,7 +417,7 @@ suite('IndexTreeModel', function () {
{ element: 7 }
]
}
]));
]);
assert.deepEqual(list.length, 4);
assert.deepEqual(toArray(list), [0, 2, 4, 6]);
@@ -440,14 +439,14 @@ suite('IndexTreeModel', function () {
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1, { filter });
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{
element: 0, children: [
{ element: 1 },
{ element: 2 }
]
}
]));
]);
assert.deepEqual(toArray(list), []);
});
@@ -463,7 +462,7 @@ suite('IndexTreeModel', function () {
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1, { filter });
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{
element: 0, children: [
{ element: 1 },
@@ -475,7 +474,7 @@ suite('IndexTreeModel', function () {
{ element: 7 }
]
},
]));
]);
assert.deepEqual(toArray(list), [0, 1, 2, 3, 4, 5, 6, 7]);
@@ -502,7 +501,7 @@ suite('IndexTreeModel', function () {
const model = new IndexTreeModel<string>('test', toSpliceable(list), 'root', { filter });
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{
element: 'vscode', children: [
{ element: '.build' },
@@ -522,7 +521,7 @@ suite('IndexTreeModel', function () {
}
]
},
]));
]);
assert.deepEqual(list.length, 10);
@@ -548,7 +547,7 @@ suite('IndexTreeModel', function () {
const model = new IndexTreeModel<string>('test', toSpliceable(list), 'root', { filter });
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{
element: 'vscode', children: [
{ element: '.build' },
@@ -568,7 +567,7 @@ suite('IndexTreeModel', function () {
}
]
},
]));
]);
assert.deepEqual(list.length, 10);
@@ -594,7 +593,7 @@ suite('IndexTreeModel', function () {
const model = new IndexTreeModel<string>('test', toSpliceable(list), 'root', { filter });
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{
element: 'vscode', collapsed: true, children: [
{ element: '.build' },
@@ -614,7 +613,7 @@ suite('IndexTreeModel', function () {
}
]
},
]));
]);
assert.deepEqual(toArray(list), ['vscode']);
@@ -642,17 +641,17 @@ suite('IndexTreeModel', function () {
const list: IIndexTreeNode<number>[] = [];
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1);
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{
element: 0, children: Iterator.fromArray([
element: 0, children: [
{ element: 10 },
{ element: 11 },
{ element: 12 },
])
]
},
{ element: 1 },
{ element: 2 }
]));
]);
assert.deepEqual(model.getNodeLocation(list[0]), [0]);
assert.deepEqual(model.getNodeLocation(list[1]), [0, 0]);
@@ -672,7 +671,7 @@ suite('IndexTreeModel', function () {
const model = new IndexTreeModel<number>('test', toSpliceable(list), -1, { filter });
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{
element: 0, children: [
{ element: 1 },
@@ -684,7 +683,7 @@ suite('IndexTreeModel', function () {
{ element: 7 }
]
}
]));
]);
assert.deepEqual(model.getNodeLocation(list[0]), [0]);
assert.deepEqual(model.getNodeLocation(list[1]), [0, 1]);
@@ -704,11 +703,11 @@ suite('IndexTreeModel', function () {
const model = new IndexTreeModel<string>('test', toSpliceable(list), 'root', { filter });
model.splice([0], 0, Iterator.fromArray([
model.splice([0], 0, [
{ element: 'silver' },
{ element: 'gold' },
{ element: 'platinum' }
]));
]);
assert.deepEqual(toArray(list), ['silver', 'gold', 'platinum']);
@@ -716,11 +715,11 @@ suite('IndexTreeModel', function () {
model.refilter();
assert.deepEqual(toArray(list), ['platinum']);
model.splice([0], Number.POSITIVE_INFINITY, Iterator.fromArray([
model.splice([0], Number.POSITIVE_INFINITY, [
{ element: 'silver' },
{ element: 'gold' },
{ element: 'platinum' }
]));
]);
assert.deepEqual(toArray(list), ['platinum']);
model.refilter();

View File

@@ -7,7 +7,6 @@ import * as assert from 'assert';
import { ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree';
import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list';
import { ObjectTree, CompressibleObjectTree, ICompressibleTreeRenderer } from 'vs/base/browser/ui/tree/objectTree';
import { Iterator } from 'vs/base/common/iterator';
import { ICompressedTreeNode } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
suite('ObjectTree', function () {
@@ -46,17 +45,17 @@ suite('ObjectTree', function () {
});
test('should be able to navigate', () => {
tree.setChildren(null, Iterator.fromArray([
tree.setChildren(null, [
{
element: 0, children: Iterator.fromArray([
element: 0, children: [
{ element: 10 },
{ element: 11 },
{ element: 12 },
])
]
},
{ element: 1 },
{ element: 2 }
]));
]);
const navigator = tree.navigate();
@@ -87,17 +86,17 @@ suite('ObjectTree', function () {
});
test('should skip collapsed nodes', () => {
tree.setChildren(null, Iterator.fromArray([
tree.setChildren(null, [
{
element: 0, collapsed: true, children: Iterator.fromArray([
element: 0, collapsed: true, children: [
{ element: 10 },
{ element: 11 },
{ element: 12 },
])
]
},
{ element: 1 },
{ element: 2 }
]));
]);
const navigator = tree.navigate();
@@ -118,17 +117,17 @@ suite('ObjectTree', function () {
test('should skip filtered elements', () => {
filter = el => el % 2 === 0;
tree.setChildren(null, Iterator.fromArray([
tree.setChildren(null, [
{
element: 0, children: Iterator.fromArray([
element: 0, children: [
{ element: 10 },
{ element: 11 },
{ element: 12 },
])
]
},
{ element: 1 },
{ element: 2 }
]));
]);
const navigator = tree.navigate();
@@ -150,17 +149,17 @@ suite('ObjectTree', function () {
});
test('should be able to start from node', () => {
tree.setChildren(null, Iterator.fromArray([
tree.setChildren(null, [
{
element: 0, children: Iterator.fromArray([
element: 0, children: [
{ element: 10 },
{ element: 11 },
{ element: 12 },
])
]
},
{ element: 1 },
{ element: 2 }
]));
]);
const navigator = tree.navigate(1);
@@ -291,50 +290,50 @@ suite('CompressibleObjectTree', function () {
const tree = new CompressibleObjectTree<number>('test', container, new Delegate(), [new Renderer()]);
tree.layout(200);
tree.setChildren(null, Iterator.fromArray([
tree.setChildren(null, [
{
element: 1, children: Iterator.fromArray([{
element: 11, children: Iterator.fromArray([{
element: 111, children: Iterator.fromArray([
element: 1, children: [{
element: 11, children: [{
element: 111, children: [
{ element: 1111 },
{ element: 1112 },
{ element: 1113 },
])
}])
}])
]
}]
}]
}
]));
]);
let rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent);
assert.deepEqual(rows, ['1/11/111', '1111', '1112', '1113']);
tree.setChildren(11, Iterator.fromArray([
tree.setChildren(11, [
{ element: 111 },
{ element: 112 },
{ element: 113 },
]));
]);
rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent);
assert.deepEqual(rows, ['1/11', '111', '112', '113']);
tree.setChildren(113, Iterator.fromArray([
tree.setChildren(113, [
{ element: 1131 }
]));
]);
rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent);
assert.deepEqual(rows, ['1/11', '111', '112', '113/1131']);
tree.setChildren(1131, Iterator.fromArray([
tree.setChildren(1131, [
{ element: 1132 }
]));
]);
rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent);
assert.deepEqual(rows, ['1/11', '111', '112', '113/1131/1132']);
tree.setChildren(1131, Iterator.fromArray([
tree.setChildren(1131, [
{ element: 1132 },
{ element: 1133 },
]));
]);
rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent);
assert.deepEqual(rows, ['1/11', '111', '112', '113/1131', '1132', '1133']);
@@ -348,19 +347,19 @@ suite('CompressibleObjectTree', function () {
const tree = new CompressibleObjectTree<number>('test', container, new Delegate(), [new Renderer()]);
tree.layout(200);
tree.setChildren(null, Iterator.fromArray([
tree.setChildren(null, [
{
element: 1, children: Iterator.fromArray([{
element: 11, children: Iterator.fromArray([{
element: 111, children: Iterator.fromArray([
element: 1, children: [{
element: 11, children: [{
element: 111, children: [
{ element: 1111 },
{ element: 1112 },
{ element: 1113 },
])
}])
}])
]
}]
}]
}
]));
]);
let rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent);
assert.deepEqual(rows, ['1/11/111', '1111', '1112', '1113']);

View File

@@ -7,7 +7,6 @@ import * as assert from 'assert';
import { ITreeNode } from 'vs/base/browser/ui/tree/tree';
import { ISpliceable } from 'vs/base/common/sequence';
import { ObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel';
import { Iterator } from 'vs/base/common/iterator';
function toSpliceable<T>(arr: T[]): ISpliceable<T> {
return {
@@ -35,25 +34,25 @@ suite('ObjectTreeModel', function () {
const list: ITreeNode<number>[] = [];
const model = new ObjectTreeModel<number>('test', toSpliceable(list));
model.setChildren(null, Iterator.fromArray([
model.setChildren(null, [
{ element: 0 },
{ element: 1 },
{ element: 2 }
]));
]);
assert.deepEqual(toArray(list), [0, 1, 2]);
assert.equal(model.size, 3);
model.setChildren(null, Iterator.fromArray([
model.setChildren(null, [
{ element: 3 },
{ element: 4 },
{ element: 5 },
]));
]);
assert.deepEqual(toArray(list), [3, 4, 5]);
assert.equal(model.size, 3);
model.setChildren(null, Iterator.empty());
model.setChildren(null);
assert.deepEqual(toArray(list), []);
assert.equal(model.size, 0);
});
@@ -62,34 +61,34 @@ suite('ObjectTreeModel', function () {
const list: ITreeNode<number>[] = [];
const model = new ObjectTreeModel<number>('test', toSpliceable(list));
model.setChildren(null, Iterator.fromArray([
model.setChildren(null, [
{
element: 0, children: Iterator.fromArray([
element: 0, children: [
{ element: 10 },
{ element: 11 },
{ element: 12 },
])
]
},
{ element: 1 },
{ element: 2 }
]));
]);
assert.deepEqual(toArray(list), [0, 10, 11, 12, 1, 2]);
assert.equal(model.size, 6);
model.setChildren(12, Iterator.fromArray([
model.setChildren(12, [
{ element: 120 },
{ element: 121 }
]));
]);
assert.deepEqual(toArray(list), [0, 10, 11, 12, 120, 121, 1, 2]);
assert.equal(model.size, 8);
model.setChildren(0, Iterator.empty());
model.setChildren(0);
assert.deepEqual(toArray(list), [0, 1, 2]);
assert.equal(model.size, 3);
model.setChildren(null, Iterator.empty());
model.setChildren(null);
assert.deepEqual(toArray(list), []);
assert.equal(model.size, 0);
});
@@ -98,16 +97,16 @@ suite('ObjectTreeModel', function () {
const list: ITreeNode<number>[] = [];
const model = new ObjectTreeModel<number>('test', toSpliceable(list));
model.setChildren(null, Iterator.fromArray([
model.setChildren(null, [
{ element: 0, collapsed: true }
]));
]);
assert.deepEqual(toArray(list), [0]);
model.setChildren(0, Iterator.fromArray([
model.setChildren(0, [
{ element: 1 },
{ element: 2 }
]));
]);
assert.deepEqual(toArray(list), [0]);

View File

@@ -343,6 +343,36 @@ suite('Filters', () => {
);
});
test('Freeze when fjfj -> jfjf, https://github.com/microsoft/vscode/issues/91807', function () {
assertMatches(
'jfjfj',
'fjfjfjfjfjfjfjfjfjfjfj',
undefined, fuzzyScore
);
assertMatches(
'jfjfjfjfjfjfjfjfjfj',
'fjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfj',
undefined, fuzzyScore
);
assertMatches(
'jfjfjfjfjfjfjfjfjfjjfjfjfjfjfjfjfjfjfjjfjfjfjfjfjfjfjfjfjjfjfjfjfjfjfjfjfjfjjfjfjfjfjfjfjfjfjfjjfjfjfjfjfjfjfjfjfj',
'fjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfj',
undefined, fuzzyScore
);
assertMatches(
'jfjfjfjfjfjfjfjfjfj',
'fJfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfj',
'f^J^f^j^f^j^f^j^f^j^f^j^f^j^f^j^f^j^f^jfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfj', // strong match
fuzzyScore
);
assertMatches(
'jfjfjfjfjfjfjfjfjfj',
'fjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfj',
'f^j^f^j^f^j^f^j^f^j^f^j^f^j^f^j^f^j^f^jfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfj', // any match
fuzzyScore, { firstMatchCanBeWeak: true }
);
});
test('fuzzyScore, issue #26423', function () {
assertMatches('baba', 'abababab', undefined, fuzzyScore);

View File

@@ -4,19 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { Iterator, Iterable } from 'vs/base/common/iterator';
suite('Iterator', () => {
test('concat', () => {
const first = Iterator.fromArray([1, 2, 3]);
const second = Iterator.fromArray([4, 5, 6]);
const third = Iterator.fromArray([7, 8, 9]);
const actualIterator = Iterator.concat(first, second, third);
const actual = Iterator.collect(actualIterator);
assert.deepEqual(actual, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
});
});
import { Iterable } from 'vs/base/common/iterator';
suite('Iterable', function () {

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ResourceMap, TernarySearchTree, PathIterator, StringIterator, LinkedMap, Touch, LRUCache } from 'vs/base/common/map';
import { ResourceMap, TernarySearchTree, PathIterator, StringIterator, LinkedMap, Touch, LRUCache, UriIterator } from 'vs/base/common/map';
import * as assert from 'assert';
import { URI } from 'vs/base/common/uri';
@@ -312,7 +312,64 @@ suite('Map', () => {
assert.equal(iter.hasNext(), false);
});
function assertTernarySearchTree<E>(trie: TernarySearchTree<E>, ...elements: [string, E][]) {
test('URIIterator', function () {
const iter = new UriIterator();
iter.reset(URI.parse('file:///usr/bin/file.txt'));
assert.equal(iter.value(), 'file');
assert.equal(iter.cmp('FILE'), 0);
assert.equal(iter.hasNext(), true);
iter.next();
assert.equal(iter.value(), 'usr');
assert.equal(iter.hasNext(), true);
iter.next();
assert.equal(iter.value(), 'bin');
assert.equal(iter.hasNext(), true);
iter.next();
assert.equal(iter.value(), 'file.txt');
assert.equal(iter.hasNext(), false);
iter.reset(URI.parse('file://share/usr/bin/file.txt?foo'));
// scheme
assert.equal(iter.value(), 'file');
assert.equal(iter.cmp('FILE'), 0);
assert.equal(iter.hasNext(), true);
iter.next();
// authority
assert.equal(iter.value(), 'share');
assert.equal(iter.cmp('SHARe'), 0);
assert.equal(iter.hasNext(), true);
iter.next();
// path
assert.equal(iter.value(), 'usr');
assert.equal(iter.hasNext(), true);
iter.next();
// path
assert.equal(iter.value(), 'bin');
assert.equal(iter.hasNext(), true);
iter.next();
// path
assert.equal(iter.value(), 'file.txt');
assert.equal(iter.hasNext(), true);
iter.next();
// query
assert.equal(iter.value(), 'foo');
assert.equal(iter.cmp('z') > 0, true);
assert.equal(iter.cmp('a') < 0, true);
assert.equal(iter.hasNext(), false);
});
function assertTernarySearchTree<E>(trie: TernarySearchTree<string, E>, ...elements: [string, E][]) {
const map = new Map<string, E>();
for (const [key, value] of elements) {
map.set(key, value);
@@ -378,7 +435,7 @@ suite('Map', () => {
});
test('TernarySearchTree - basics', function () {
let trie = new TernarySearchTree<number>(new StringIterator());
let trie = new TernarySearchTree<string, number>(new StringIterator());
trie.set('foo', 1);
trie.set('bar', 2);
@@ -408,7 +465,7 @@ suite('Map', () => {
});
test('TernarySearchTree - delete & cleanup', function () {
let trie = new TernarySearchTree<number>(new StringIterator());
let trie = new TernarySearchTree<string, number>(new StringIterator());
trie.set('foo', 1);
trie.set('foobar', 2);
trie.set('bar', 3);
@@ -418,7 +475,7 @@ suite('Map', () => {
});
test('TernarySearchTree (PathSegments) - basics', function () {
let trie = new TernarySearchTree<number>(new PathIterator());
let trie = new TernarySearchTree<string, number>(new PathIterator());
trie.set('/user/foo/bar', 1);
trie.set('/user/foo', 2);
@@ -442,7 +499,7 @@ suite('Map', () => {
test('TernarySearchTree (PathSegments) - lookup', function () {
const map = new TernarySearchTree<number>(new PathIterator());
const map = new TernarySearchTree<string, number>(new PathIterator());
map.set('/user/foo/bar', 1);
map.set('/user/foo', 2);
map.set('/user/foo/flip/flop', 3);
@@ -456,7 +513,7 @@ suite('Map', () => {
test('TernarySearchTree (PathSegments) - superstr', function () {
const map = new TernarySearchTree<number>(new PathIterator());
const map = new TernarySearchTree<string, number>(new PathIterator());
map.set('/user/foo/bar', 1);
map.set('/user/foo', 2);
map.set('/user/foo/flip/flop', 3);
@@ -493,6 +550,100 @@ suite('Map', () => {
assert.equal(map.findSuperstr('/userr'), undefined);
});
test('TernarySearchTree (URI) - basics', function () {
let trie = new TernarySearchTree<URI, number>(new UriIterator());
trie.set(URI.file('/user/foo/bar'), 1);
trie.set(URI.file('/user/foo'), 2);
trie.set(URI.file('/user/foo/flip/flop'), 3);
assert.equal(trie.get(URI.file('/user/foo/bar')), 1);
assert.equal(trie.get(URI.file('/user/foo')), 2);
assert.equal(trie.get(URI.file('/user/foo/flip/flop')), 3);
assert.equal(trie.findSubstr(URI.file('/user/bar')), undefined);
assert.equal(trie.findSubstr(URI.file('/user/foo')), 2);
assert.equal(trie.findSubstr(URI.file('/user/foo/ba')), 2);
assert.equal(trie.findSubstr(URI.file('/user/foo/far/boo')), 2);
assert.equal(trie.findSubstr(URI.file('/user/foo/bar')), 1);
assert.equal(trie.findSubstr(URI.file('/user/foo/bar/far/boo')), 1);
});
test('TernarySearchTree (URI) - lookup', function () {
const map = new TernarySearchTree<URI, number>(new UriIterator());
map.set(URI.parse('http://foo.bar/user/foo/bar'), 1);
map.set(URI.parse('http://foo.bar/user/foo?query'), 2);
map.set(URI.parse('http://foo.bar/user/foo?QUERY'), 3);
map.set(URI.parse('http://foo.bar/user/foo/flip/flop'), 3);
assert.equal(map.get(URI.parse('http://foo.bar/foo')), undefined);
assert.equal(map.get(URI.parse('http://foo.bar/user')), undefined);
assert.equal(map.get(URI.parse('http://foo.bar/user/foo/bar')), 1);
assert.equal(map.get(URI.parse('http://foo.bar/user/foo?query')), 2);
assert.equal(map.get(URI.parse('http://foo.bar/user/foo?Query')), undefined);
assert.equal(map.get(URI.parse('http://foo.bar/user/foo?QUERY')), 3);
assert.equal(map.get(URI.parse('http://foo.bar/user/foo/bar/boo')), undefined);
});
test('TernarySearchTree (PathSegments) - superstr', function () {
const map = new TernarySearchTree<URI, number>(new UriIterator());
map.set(URI.file('/user/foo/bar'), 1);
map.set(URI.file('/user/foo'), 2);
map.set(URI.file('/user/foo/flip/flop'), 3);
map.set(URI.file('/usr/foo'), 4);
let item: IteratorResult<number>;
let iter = map.findSuperstr(URI.file('/user'))!;
item = iter.next();
assert.equal(item.value, 2);
assert.equal(item.done, false);
item = iter.next();
assert.equal(item.value, 1);
assert.equal(item.done, false);
item = iter.next();
assert.equal(item.value, 3);
assert.equal(item.done, false);
item = iter.next();
assert.equal(item.value, undefined);
assert.equal(item.done, true);
iter = map.findSuperstr(URI.file('/usr'))!;
item = iter.next();
assert.equal(item.value, 4);
assert.equal(item.done, false);
item = iter.next();
assert.equal(item.value, undefined);
assert.equal(item.done, true);
iter = map.findSuperstr(URI.file('/'))!;
item = iter.next();
assert.equal(item.value, 2);
assert.equal(item.done, false);
item = iter.next();
assert.equal(item.value, 1);
assert.equal(item.done, false);
item = iter.next();
assert.equal(item.value, 3);
assert.equal(item.done, false);
item = iter.next();
assert.equal(item.value, 4);
assert.equal(item.done, false);
item = iter.next();
assert.equal(item.value, undefined);
assert.equal(item.done, true);
assert.equal(map.findSuperstr(URI.file('/not')), undefined);
assert.equal(map.findSuperstr(URI.file('/us')), undefined);
assert.equal(map.findSuperstr(URI.file('/usrr')), undefined);
assert.equal(map.findSuperstr(URI.file('/userr')), undefined);
});
test('ResourceMap - basics', function () {
const map = new ResourceMap<any>();

View File

@@ -81,6 +81,27 @@ suite('Strings', () => {
assertCompareIgnoreCase('O', '/');
});
test('compareIgnoreCase (substring)', () => {
function assertCompareIgnoreCase(a: string, b: string, aStart: number, aEnd: number, bStart: number, bEnd: number, recurse = true): void {
let actual = strings.compareIgnoreCase(a, b, aStart, aEnd, bStart, bEnd);
actual = actual > 0 ? 1 : actual < 0 ? -1 : actual;
let expected = strings.compare(a.toLowerCase().substring(aStart, aEnd), b.toLowerCase().substring(bStart, bEnd));
expected = expected > 0 ? 1 : expected < 0 ? -1 : expected;
assert.equal(actual, expected, `${a} <> ${b}`);
if (recurse) {
assertCompareIgnoreCase(b, a, bStart, bEnd, aStart, aEnd, false);
}
}
assertCompareIgnoreCase('', '', 0, 0, 0, 0);
assertCompareIgnoreCase('abc', 'ABC', 0, 1, 0, 1);
assertCompareIgnoreCase('abc', 'Aabc', 0, 3, 1, 4);
assertCompareIgnoreCase('abcABc', 'ABcd', 3, 6, 0, 4);
});
test('format', () => {
assert.strictEqual(strings.format('Foo Bar'), 'Foo Bar');
assert.strictEqual(strings.format('Foo {0} Bar'), 'Foo {0} Bar');

View File

@@ -538,7 +538,7 @@ suite('URI', () => {
assert.throws(() => assertJoined(('foo:'), 'bazz', ''));
assert.throws(() => new URL('bazz', 'foo:'));
assert.throws(() => assertJoined(('foo://bar'), 'bazz', ''));
// assert.throws(() => new URL('bazz', 'foo://bar')); Edge,Chrome => throw, Safari => foo://bar/bazz, Firefox ??
// assert.throws(() => new URL('bazz', 'foo://bar')); Edge, Chrome => THROW, Firefox, Safari => foo://bar/bazz
});
test('URI#joinPath (posix)', function () {
@@ -549,8 +549,8 @@ suite('URI', () => {
assertJoined(('file://server/share/c:/'), '../../bazz', 'file://server/bazz', false);
assertJoined(('file://server/share/c:'), '../../bazz', 'file://server/bazz', false);
assertJoined(('file://ser/foo/'), '../../bazz', 'file://ser/bazz');
assertJoined(('file://ser/foo'), '../../bazz', 'file://ser/bazz');
assertJoined(('file://ser/foo/'), '../../bazz', 'file://ser/bazz', false); // Firefox -> Different, Edge, Chrome, Safar -> OK
assertJoined(('file://ser/foo'), '../../bazz', 'file://ser/bazz', false); // Firefox -> Different, Edge, Chrome, Safar -> OK
});
test('URI#joinPath (windows)', function () {