diff --git a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts index 68f21480418d7..222325edf6f88 100644 --- a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts +++ b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts @@ -56,6 +56,7 @@ export interface IBreadcrumbsItemEvent { type: 'select' | 'focus'; item: BreadcrumbsItem; node: HTMLElement; + payload: any; } export class BreadcrumbsWidget { @@ -164,23 +165,23 @@ export class BreadcrumbsWidget { return this._items[this._focusedItemIdx]; } - setFocused(item: BreadcrumbsItem): void { - this._focus(this._items.indexOf(item)); + setFocused(item: BreadcrumbsItem, payload?: any): void { + this._focus(this._items.indexOf(item), payload); } - focusPrev(): any { + focusPrev(payload?: any): any { if (this._focusedItemIdx > 0) { - this._focus(this._focusedItemIdx - 1); + this._focus(this._focusedItemIdx - 1, payload); } } - focusNext(): any { + focusNext(payload?: any): any { if (this._focusedItemIdx + 1 < this._nodes.length) { - this._focus(this._focusedItemIdx + 1); + this._focus(this._focusedItemIdx + 1, payload); } } - private _focus(nth: number): void { + private _focus(nth: number, payload: any): void { this._focusedItemIdx = -1; for (let i = 0; i < this._nodes.length; i++) { const node = this._nodes[i]; @@ -192,7 +193,7 @@ export class BreadcrumbsWidget { } } this._reveal(this._focusedItemIdx); - this._onDidFocusItem.fire({ type: 'focus', item: this._items[this._focusedItemIdx], node: this._nodes[this._focusedItemIdx] }); + this._onDidFocusItem.fire({ type: 'focus', item: this._items[this._focusedItemIdx], node: this._nodes[this._focusedItemIdx], payload }); } reveal(item: BreadcrumbsItem): void { @@ -213,11 +214,11 @@ export class BreadcrumbsWidget { return this._items[this._selectedItemIdx]; } - setSelection(item: BreadcrumbsItem): void { - this._select(this._items.indexOf(item)); + setSelection(item: BreadcrumbsItem, payload?: any): void { + this._select(this._items.indexOf(item), payload); } - private _select(nth: number): void { + private _select(nth: number, payload: any): void { this._selectedItemIdx = -1; for (let i = 0; i < this._nodes.length; i++) { const node = this._nodes[i]; @@ -228,7 +229,7 @@ export class BreadcrumbsWidget { dom.addClass(node, 'selected'); } } - this._onDidSelectItem.fire({ type: 'select', item: this._items[this._selectedItemIdx], node: this._nodes[this._selectedItemIdx] }); + this._onDidSelectItem.fire({ type: 'select', item: this._items[this._selectedItemIdx], node: this._nodes[this._selectedItemIdx], payload }); } setItems(items: BreadcrumbsItem[]): void { @@ -236,7 +237,7 @@ export class BreadcrumbsWidget { let removed = this._items.splice(prefix, this._items.length - prefix, ...items.slice(prefix)); this._render(prefix); dispose(removed); - this._focus(-1); + this._focus(-1, undefined); } private _render(start: number): void { @@ -275,8 +276,8 @@ export class BreadcrumbsWidget { for (let el = event.target; el; el = el.parentElement) { let idx = this._nodes.indexOf(el as any); if (idx >= 0) { - this._focus(idx); - this._select(idx); + this._focus(idx, event); + this._select(idx, event); break; } } diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index e138f5ddc3c64..0b41ca11d7cd7 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -32,6 +32,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorG import { IBreadcrumbsService } from 'vs/workbench/browser/parts/editor/breadcrumbs'; import { symbolKindToCssClass } from 'vs/editor/common/modes'; import { BreadcrumbsPicker, BreadcrumbsFilePicker, BreadcrumbsOutlinePicker } from 'vs/workbench/browser/parts/editor/breadcrumbsPicker'; +import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; class Item extends BreadcrumbsItem { @@ -113,6 +114,9 @@ export class BreadcrumbsControl { static HEIGHT = 25; + static readonly Payload_Reveal = {}; + static readonly Payload_Pick = {}; + static CK_BreadcrumbsVisible = new RawContextKey('breadcrumbsVisible', false); static CK_BreadcrumbsActive = new RawContextKey('breadcrumbsActive', false); @@ -223,39 +227,29 @@ export class BreadcrumbsControl { } this._editorGroup.focus(); + const { element } = event.item as Item; + + if (this._shouldRevealItem(event)) { + // reveal the item + this._widget.setSelection(undefined); + this._revealInEditor(element); + return; + } + + // show picker this._contextViewService.showContextView({ getAnchor() { return event.node; }, render: (parent: HTMLElement) => { - let { element } = event.item as Item; let ctor: IConstructorSignature2 = element instanceof FileElement ? BreadcrumbsFilePicker : BreadcrumbsOutlinePicker; let res = this._instantiationService.createInstance(ctor, parent, element); res.layout({ width: 220, height: 330 }); let listener = res.onDidPickElement(data => { this._contextViewService.hideContextView(); this._widget.setSelection(undefined); - if (!data) { - return; - } - if (URI.isUri(data)) { - // open new editor - this._editorService.openEditor({ resource: data }); - - } else if (data instanceof OutlineElement) { - - let resource: URI; - let candidate = data.parent; - while (candidate) { - if (candidate instanceof OutlineModel) { - resource = candidate.textModel.uri; - break; - } - candidate = candidate.parent; - } - - this._editorService.openEditor({ resource, options: { selection: Range.collapseToStart(data.symbol.selectionRange) } }); - + if (data) { + this._revealInEditor(data); } }); this._breadcrumbsPickerShowing = true; @@ -274,6 +268,28 @@ export class BreadcrumbsControl { const value = this._widget.isDOMFocused() || this._breadcrumbsPickerShowing; this._ckBreadcrumbsActive.set(value); } + + private _revealInEditor(data: any): void { + if (URI.isUri(data)) { + // open new editor + this._editorService.openEditor({ resource: data }); + } else if (data instanceof FileElement) { + // + this._editorService.openEditor({ resource: data.uri }); + + } else if (data instanceof OutlineElement) { + // + let model = OutlineModel.get(data); + this._editorService.openEditor({ + resource: model.textModel.uri, + options: { selection: Range.collapseToStart(data.symbol.selectionRange) } + }); + } + } + + private _shouldRevealItem({ payload }: IBreadcrumbsItemEvent): boolean { + return payload === BreadcrumbsControl.Payload_Reveal || (payload instanceof StandardMouseEvent && payload.metaKey); + } } //#region commands @@ -318,13 +334,26 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ id: 'breadcrumbs.selectFocused', weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), primary: KeyCode.Enter, - secondary: [KeyCode.DownArrow, KeyCode.Space], + secondary: [KeyCode.DownArrow], + when: ContextKeyExpr.and(BreadcrumbsControl.CK_BreadcrumbsVisible, BreadcrumbsControl.CK_BreadcrumbsActive), + handler(accessor) { + const groups = accessor.get(IEditorGroupsService); + const breadcrumbs = accessor.get(IBreadcrumbsService); + const widget = breadcrumbs.getWidget(groups.activeGroup.id); + widget.setSelection(widget.getFocused(), BreadcrumbsControl.Payload_Pick); + } +}); +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'breadcrumbs.revealFocused', + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), + primary: KeyMod.Shift | KeyCode.Enter, + secondary: [KeyCode.Space], when: ContextKeyExpr.and(BreadcrumbsControl.CK_BreadcrumbsVisible, BreadcrumbsControl.CK_BreadcrumbsActive), handler(accessor) { const groups = accessor.get(IEditorGroupsService); const breadcrumbs = accessor.get(IBreadcrumbsService); const widget = breadcrumbs.getWidget(groups.activeGroup.id); - widget.setSelection(widget.getFocused()); + widget.setSelection(widget.getFocused(), BreadcrumbsControl.Payload_Reveal); } }); KeybindingsRegistry.registerCommandAndKeybindingRule({