diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 0a26a9aebf49fc301a0129decd177919c78f0e85..0d73ae922297bf87839e22897dfacdba022f7fed 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -3,32 +3,26 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { addClass, addStandardDisposableListener, createStyleSheet, getTotalHeight, removeClass } from 'vs/base/browser/dom'; -import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { IInputOptions, InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; +import { createStyleSheet } from 'vs/base/browser/dom'; import { IListMouseEvent, IListTouchEvent, IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { IPagedRenderer, PagedList } from 'vs/base/browser/ui/list/listPaging'; import { DefaultStyleController, IListOptions, IMultipleSelectionController, IOpenController, isSelectionRangeChangeEvent, isSelectionSingleChangeEvent, List } from 'vs/base/browser/ui/list/listWidget'; -import { canceled, onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; -import { FuzzyScore } from 'vs/base/common/filters'; -import { KeyCode } from 'vs/base/common/keyCodes'; import { combinedDisposable, Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { isUndefinedOrNull } from 'vs/base/common/types'; -import { IFilter, ITree, ITreeConfiguration, ITreeOptions } from 'vs/base/parts/tree/browser/tree'; +import { ITree, ITreeConfiguration, ITreeOptions } from 'vs/base/parts/tree/browser/tree'; import { ClickBehavior, DefaultController, DefaultTreestyler, IControllerOptions, OpenMode } from 'vs/base/parts/tree/browser/treeDefaults'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; import { localize } from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IEditorOptions } from 'vs/platform/editor/common/editor'; import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { Registry } from 'vs/platform/registry/common/platform'; -import { attachInputBoxStyler, attachListStyler, computeStyles, defaultListStyles } from 'vs/platform/theme/common/styler'; +import { attachListStyler, computeStyles, defaultListStyles } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { InputFocusedContextKey } from 'vs/platform/workbench/common/contextkeys'; import { ObjectTree, IObjectTreeOptions } from 'vs/base/browser/ui/tree/objectTree'; @@ -722,241 +716,6 @@ export class TreeResourceNavigator2 extends Disposable { } } -export interface IHighlighter { - getHighlights(tree: ITree, element: any, pattern: string): FuzzyScore; - getHighlightsStorageKey?(element: any): any; -} - -export interface IHighlightingTreeConfiguration extends ITreeConfiguration { - highlighter: IHighlighter; -} - -export interface IHighlightingTreeOptions extends ITreeOptions { - filterOnType?: boolean; -} - -export class HighlightingTreeController extends WorkbenchTreeController { - - constructor( - options: IControllerOptions, - private readonly onType: () => any, - @IConfigurationService configurationService: IConfigurationService, - @IKeybindingService private readonly _keybindingService: IKeybindingService, - ) { - super(options, configurationService); - } - - onKeyDown(tree: ITree, event: IKeyboardEvent) { - let handled = super.onKeyDown(tree, event); - if (handled) { - return true; - } - if (this.upKeyBindingDispatcher.has(event.keyCode)) { - return false; - } - if (this._keybindingService.mightProducePrintableCharacter(event)) { - this.onType(); - return true; - } - return false; - } -} - -class HightlightsFilter implements IFilter { - - static add(config: ITreeConfiguration, options: IHighlightingTreeOptions): ITreeConfiguration { - const myFilter = new HightlightsFilter(); - myFilter.enabled = !!options.filterOnType; - if (!config.filter) { - config.filter = myFilter; - } else { - let otherFilter = config.filter; - config.filter = { - isVisible(tree: ITree, element: any): boolean { - return myFilter.isVisible(tree, element) && otherFilter.isVisible(tree, element); - } - }; - } - return config; - } - - enabled: boolean = true; - - isVisible(tree: ITree, element: any): boolean { - if (!this.enabled) { - return true; - } - let tree2 = (tree as HighlightingWorkbenchTree); - if (!tree2.isHighlighterScoring()) { - return true; - } - if (tree2.getHighlighterScore(element)) { - return true; - } - return false; - } -} - -export class HighlightingWorkbenchTree extends WorkbenchTree { - - protected readonly domNode: HTMLElement; - protected readonly inputContainer: HTMLElement; - protected readonly input: InputBox; - - protected readonly highlighter: IHighlighter; - protected readonly highlights: Map; - - private readonly _onDidStartFilter: Emitter; - readonly onDidStartFiltering: Event; - - constructor( - parent: HTMLElement, - treeConfiguration: IHighlightingTreeConfiguration, - treeOptions: IHighlightingTreeOptions, - listOptions: IInputOptions, - @IContextKeyService contextKeyService: IContextKeyService, - @IContextViewService contextViewService: IContextViewService, - @IListService listService: IListService, - @IThemeService themeService: IThemeService, - @IInstantiationService instantiationService: IInstantiationService, - @IConfigurationService configurationService: IConfigurationService - ) { - // build html skeleton - const container = document.createElement('div'); - container.className = 'highlighting-tree'; - const inputContainer = document.createElement('div'); - inputContainer.className = 'input'; - const treeContainer = document.createElement('div'); - treeContainer.className = 'tree'; - container.appendChild(inputContainer); - container.appendChild(treeContainer); - parent.appendChild(container); - - // create tree - treeConfiguration.controller = treeConfiguration.controller || instantiationService.createInstance(HighlightingTreeController, {}, () => this.onTypeInTree()); - super(treeContainer, HightlightsFilter.add(treeConfiguration, treeOptions), treeOptions, contextKeyService, listService, themeService, instantiationService, configurationService); - this.highlighter = treeConfiguration.highlighter; - this.highlights = new Map(); - - this.domNode = container; - addClass(this.domNode, 'inactive'); - - // create input - this.inputContainer = inputContainer; - this.input = new InputBox(inputContainer, contextViewService, listOptions); - this.input.setEnabled(false); - this.input.onDidChange(this.updateHighlights, this, this.disposables); - this.disposables.push(attachInputBoxStyler(this.input, themeService)); - this.disposables.push(this.input); - this.disposables.push(addStandardDisposableListener(this.input.inputElement, 'keydown', event => { - //todo@joh make this command/context-key based - switch (event.keyCode) { - case KeyCode.UpArrow: - case KeyCode.DownArrow: - case KeyCode.Tab: - this.domFocus(); - event.preventDefault(); - break; - case KeyCode.Enter: - this.setSelection(this.getSelection()); - event.preventDefault(); - break; - case KeyCode.Escape: - this.input.value = ''; - this.domFocus(); - event.preventDefault(); - break; - } - })); - - this._onDidStartFilter = new Emitter(); - this.onDidStartFiltering = this._onDidStartFilter.event; - this.disposables.push(this._onDidStartFilter); - } - - setInput(element: any): Promise { - this.input.setEnabled(false); - return super.setInput(element).then(value => { - if (!this.input.inputElement) { - // has been disposed in the meantime -> cancel - return Promise.reject(canceled()); - } - this.input.setEnabled(true); - return value; - }); - } - - layout(height?: number, width?: number): void { - this.input.layout(); - super.layout(typeof height !== 'number' || isNaN(height) ? height : height - getTotalHeight(this.inputContainer), width); - } - - private onTypeInTree(): void { - removeClass(this.domNode, 'inactive'); - this.input.focus(); - this.layout(); - this._onDidStartFilter.fire(this); - } - - private lastSelection: any[]; - - private updateHighlights(pattern: string): void { - - // remember old selection - let defaultSelection: any[] = []; - if (!this.lastSelection && pattern) { - this.lastSelection = this.getSelection(); - } else if (this.lastSelection && !pattern) { - defaultSelection = this.lastSelection; - this.lastSelection = []; - } - - let topElement: any; - if (pattern) { - let nav = this.getNavigator(undefined, false); - let topScore: FuzzyScore | undefined; - while (nav.next()) { - let element = nav.current(); - let score = this.highlighter.getHighlights(this, element, pattern); - this.highlights.set(this._getHighlightsStorageKey(element), score); - element.foo = 1; - if (!topScore || score && topScore[0] < score[0]) { - topScore = score; - topElement = element; - } - } - } else { - // no pattern, clear highlights - this.highlights.clear(); - } - - this.refresh().then(() => { - if (topElement) { - this.reveal(topElement, 0.5).then(_ => { - this.setSelection([topElement], this); - this.setFocus(topElement, this); - }); - } else { - this.setSelection(defaultSelection, this); - } - }, onUnexpectedError); - } - - isHighlighterScoring(): boolean { - return this.highlights.size > 0; - } - - getHighlighterScore(element: any): FuzzyScore | undefined { - return this.highlights.get(this._getHighlightsStorageKey(element)); - } - - private _getHighlightsStorageKey(element: any): any { - return typeof this.highlighter.getHighlightsStorageKey === 'function' - ? this.highlighter.getHighlightsStorageKey(element) - : element; - } -} - function createKeyboardNavigationEventFilter(container: HTMLElement, keybindingService: IKeybindingService): IKeyboardNavigationEventFilter { let inChord = false;