chore(vscode): update to 1.55.2

This commit is contained in:
Akash Satheesan
2021-04-09 11:32:27 +05:30
1102 changed files with 39988 additions and 23544 deletions

View File

@@ -383,6 +383,7 @@ export class SelectActionViewItem extends BaseActionViewItem {
super(ctx, action);
this.selectBox = new SelectBox(options, selected, contextViewProvider, undefined, selectBoxOptions);
this.selectBox.setFocusable(false);
this._register(this.selectBox);
this.registerListeners();
@@ -406,6 +407,10 @@ export class SelectActionViewItem extends BaseActionViewItem {
return option;
}
setFocusable(focusable: boolean): void {
this.selectBox.setFocusable(focusable);
}
focus(): void {
if (this.selectBox) {
this.selectBox.focus();

View File

@@ -20,10 +20,6 @@
display: inline-block;
}
.monaco-action-bar.reverse .actions-container {
flex-direction: row-reverse;
}
.monaco-action-bar .action-item {
cursor: pointer;
display: inline-block;

View File

@@ -28,9 +28,7 @@ export interface IActionViewItemProvider {
export const enum ActionsOrientation {
HORIZONTAL,
HORIZONTAL_REVERSE,
VERTICAL,
VERTICAL_REVERSE,
}
export interface ActionTrigger {
@@ -135,21 +133,11 @@ export class ActionBar extends Disposable implements IActionRunner {
previousKeys = [KeyCode.LeftArrow];
nextKeys = [KeyCode.RightArrow];
break;
case ActionsOrientation.HORIZONTAL_REVERSE:
previousKeys = [KeyCode.RightArrow];
nextKeys = [KeyCode.LeftArrow];
this.domNode.className += ' reverse';
break;
case ActionsOrientation.VERTICAL:
previousKeys = [KeyCode.UpArrow];
nextKeys = [KeyCode.DownArrow];
this.domNode.className += ' vertical';
break;
case ActionsOrientation.VERTICAL_REVERSE:
previousKeys = [KeyCode.DownArrow];
nextKeys = [KeyCode.UpArrow];
this.domNode.className += ' vertical reverse';
break;
}
this._register(DOM.addDisposableListener(this.domNode, DOM.EventType.KEY_DOWN, e => {
@@ -163,8 +151,12 @@ export class ActionBar extends Disposable implements IActionRunner {
eventHandled = this.focusNext();
} else if (event.equals(KeyCode.Escape) && this.cancelHasListener) {
this._onDidCancel.fire();
} else if (event.equals(KeyCode.Home)) {
eventHandled = this.focusFirst();
} else if (event.equals(KeyCode.End)) {
eventHandled = this.focusLast();
} else if (event.equals(KeyCode.Tab) && focusedItem instanceof BaseActionViewItem && focusedItem.trapsArrowNavigation) {
this.focusNext();
eventHandled = this.focusNext();
} else if (this.isTriggerKeyEvent(event)) {
// Staying out of the else branch even if not triggered
if (this._triggerKeys.keyDown) {
@@ -425,9 +417,21 @@ export class ActionBar extends Disposable implements IActionRunner {
}
}
private focusFirst(): boolean {
this.focusedItem = this.length() > 1 ? 1 : 0;
return this.focusPrevious();
}
private focusLast(): boolean {
this.focusedItem = this.length() < 2 ? 0 : this.length() - 2;
return this.focusNext();
}
protected focusNext(): boolean {
if (typeof this.focusedItem === 'undefined') {
this.focusedItem = this.viewItems.length - 1;
} else if (this.viewItems.length <= 1) {
return false;
}
const startIndex = this.focusedItem;
@@ -450,6 +454,8 @@ export class ActionBar extends Disposable implements IActionRunner {
protected focusPrevious(): boolean {
if (typeof this.focusedItem === 'undefined') {
this.focusedItem = 0;
} else if (this.viewItems.length <= 1) {
return false;
}
const startIndex = this.focusedItem;

View File

@@ -14,6 +14,10 @@
align-items: center;
}
.monaco-text-button:focus {
outline-offset: 2px !important;
}
.monaco-text-button:hover {
text-decoration: none !important;
}

View File

@@ -20,4 +20,5 @@ export interface IHoverDelegateOptions {
export interface IHoverDelegate {
showHover(options: IHoverDelegateOptions): IDisposable | undefined;
delay: number;
}

View File

@@ -10,7 +10,6 @@ import { IMatch } from 'vs/base/common/filters';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { Range } from 'vs/base/common/range';
import { equals } from 'vs/base/common/objects';
import { isMacintosh } from 'vs/base/common/platform';
import { IHoverDelegate, IHoverDelegateOptions, IHoverDelegateTarget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';
import { AnchorPosition } from 'vs/base/browser/ui/contextview/contextview';
import { IMarkdownString } from 'vs/base/common/htmlContent';
@@ -218,9 +217,6 @@ export class IconLabel extends Disposable {
htmlElement.removeAttribute('title');
let tooltip = this.getTooltipForCustom(markdownTooltip);
// Testing has indicated that on Windows and Linux 500 ms matches the native hovers most closely.
// On Mac, the delay is 1500.
const hoverDelay = isMacintosh ? 1500 : 500;
let hoverOptions: IHoverDelegateOptions | undefined;
let mouseX: number | undefined;
let isHovering = false;
@@ -232,9 +228,12 @@ export class IconLabel extends Disposable {
}
tokenSource = new CancellationTokenSource();
function mouseLeaveOrDown(this: HTMLElement, e: MouseEvent): any {
if ((e.type === dom.EventType.MOUSE_DOWN) || (<any>e).fromElement === htmlElement) {
const isMouseDown = e.type === dom.EventType.MOUSE_DOWN;
if (isMouseDown) {
hoverDisposable?.dispose();
hoverDisposable = undefined;
}
if (isMouseDown || (<any>e).fromElement === htmlElement) {
isHovering = false;
hoverOptions = undefined;
tokenSource.dispose(true);
@@ -282,7 +281,7 @@ export class IconLabel extends Disposable {
}
mouseMoveDisposable.dispose();
}, hoverDelay);
}, hoverDelegate.delay);
}
const mouseOverDisposable = this._register(domEvent(htmlElement, dom.EventType.MOUSE_OVER, true)(mouseOver.bind(htmlElement)));
this.customHovers.set(htmlElement, mouseOverDisposable);

View File

@@ -27,6 +27,7 @@ const $ = dom.$;
export interface IInputOptions extends IInputBoxStyles {
readonly placeholder?: string;
readonly tooltip?: string;
readonly ariaLabel?: string;
readonly type?: string;
readonly validationOptions?: IInputValidationOptions;
@@ -95,6 +96,7 @@ export class InputBox extends Widget {
private options: IInputOptions;
private message: IMessage | null;
private placeholder: string;
private tooltip: string;
private ariaLabel: string;
private validation?: IInputValidator;
private state: 'idle' | 'open' | 'closed' = 'idle';
@@ -133,6 +135,7 @@ export class InputBox extends Widget {
mixin(this.options, defaultOpts, false);
this.message = null;
this.placeholder = this.options.placeholder || '';
this.tooltip = this.options.tooltip ?? (this.placeholder || '');
this.ariaLabel = this.options.ariaLabel || '';
this.inputBackground = this.options.inputBackground;
@@ -207,6 +210,10 @@ export class InputBox extends Widget {
this.setPlaceHolder(this.placeholder);
}
if (this.tooltip) {
this.setTooltip(this.tooltip);
}
this.oninput(this.input, () => this.onValueChange());
this.onblur(this.input, () => this.onBlur());
this.onfocus(this.input, () => this.onFocus());
@@ -235,7 +242,11 @@ export class InputBox extends Widget {
public setPlaceHolder(placeHolder: string): void {
this.placeholder = placeHolder;
this.input.setAttribute('placeholder', placeHolder);
this.input.title = placeHolder;
}
public setTooltip(tooltip: string): void {
this.tooltip = tooltip;
this.input.title = tooltip;
}
public setAriaLabel(label: string): void {

View File

@@ -226,6 +226,14 @@ export class PagedList<T> implements IThemable, IDisposable {
this.list.scrollLeft = scrollLeft;
}
setAnchor(index: number | undefined): void {
this.list.setAnchor(index);
}
getAnchor(): number | undefined {
return this.list.getAnchor();
}
setFocus(indexes: number[]): void {
this.list.setFocus(indexes);
}
@@ -238,12 +246,20 @@ export class PagedList<T> implements IThemable, IDisposable {
this.list.focusPrevious(n, loop);
}
focusNextPage(): void {
this.list.focusNextPage();
focusNextPage(): Promise<void> {
return this.list.focusNextPage();
}
focusPreviousPage(): void {
this.list.focusPreviousPage();
focusPreviousPage(): Promise<void> {
return this.list.focusPreviousPage();
}
focusLast(): void {
this.list.focusLast();
}
focusFirst(): void {
this.list.focusFirst();
}
getFocus(): number[] {

View File

@@ -6,7 +6,7 @@
import 'vs/css!./list';
import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';
import { isNumber } from 'vs/base/common/types';
import { range, binarySearch } from 'vs/base/common/arrays';
import { range, binarySearch, firstOrDefault } from 'vs/base/common/arrays';
import { memoize } from 'vs/base/common/decorators';
import * as platform from 'vs/base/common/platform';
import { Gesture } from 'vs/base/browser/touch';
@@ -27,6 +27,7 @@ import { IDragAndDropData } from 'vs/base/browser/dnd';
import { alert } from 'vs/base/browser/ui/aria/aria';
import { IThemable } from 'vs/base/common/styler';
import { createStyleSheet } from 'vs/base/browser/dom';
import { timeout } from 'vs/base/common/async';
interface ITraitChangeEvent {
indexes: number[];
@@ -617,27 +618,25 @@ export class MouseController<T> implements IDisposable {
return;
}
let reference = this.list.getFocus()[0];
const selection = this.list.getSelection();
reference = reference === undefined ? selection[0] : reference;
const focus = e.index;
if (typeof focus === 'undefined') {
this.list.setFocus([], e.browserEvent);
this.list.setSelection([], e.browserEvent);
this.list.setAnchor(undefined);
return;
}
if (this.multipleSelectionSupport && this.isSelectionRangeChangeEvent(e)) {
return this.changeSelection(e, reference);
return this.changeSelection(e);
}
if (this.multipleSelectionSupport && this.isSelectionChangeEvent(e)) {
return this.changeSelection(e, reference);
return this.changeSelection(e);
}
this.list.setFocus([focus], e.browserEvent);
this.list.setAnchor(focus);
if (!isMouseRightClick(e.browserEvent)) {
this.list.setSelection([focus], e.browserEvent);
@@ -659,15 +658,16 @@ export class MouseController<T> implements IDisposable {
this.list.setSelection(focus, e.browserEvent);
}
private changeSelection(e: IListMouseEvent<T> | IListTouchEvent<T>, reference: number | undefined): void {
private changeSelection(e: IListMouseEvent<T> | IListTouchEvent<T>): void {
const focus = e.index!;
const anchor = this.list.getAnchor();
if (this.isSelectionRangeChangeEvent(e) && reference !== undefined) {
const min = Math.min(reference, focus);
const max = Math.max(reference, focus);
if (this.isSelectionRangeChangeEvent(e) && typeof anchor === 'number') {
const min = Math.min(anchor, focus);
const max = Math.max(anchor, focus);
const rangeSelection = range(min, max + 1);
const selection = this.list.getSelection();
const contiguousRange = getContiguousRangeContaining(disjunction(selection, [reference]), reference);
const contiguousRange = getContiguousRangeContaining(disjunction(selection, [anchor]), anchor);
if (contiguousRange.length === 0) {
return;
@@ -675,12 +675,14 @@ export class MouseController<T> implements IDisposable {
const newSelection = disjunction(rangeSelection, relativeComplement(selection, contiguousRange));
this.list.setSelection(newSelection, e.browserEvent);
this.list.setFocus([focus], e.browserEvent);
} else if (this.isSelectionSingleChangeEvent(e)) {
const selection = this.list.getSelection();
const newSelection = selection.filter(i => i !== focus);
this.list.setFocus([focus]);
this.list.setAnchor(focus);
if (selection.length === newSelection.length) {
this.list.setSelection([...newSelection, focus], e.browserEvent);
@@ -1130,8 +1132,9 @@ export interface IListOptionsUpdate extends IListViewOptionsUpdate {
export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
private focus: Trait<T>;
private focus = new Trait<T>('focused');
private selection: Trait<T>;
private anchor = new Trait<T>('anchor');
private eventBufferer = new EventBufferer();
protected view: ListView<T>;
private spliceable: ISpliceable<T>;
@@ -1223,7 +1226,6 @@ export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
) {
const role = this._options.accessibilityProvider && this._options.accessibilityProvider.getWidgetRole ? this._options.accessibilityProvider?.getWidgetRole() : 'list';
this.selection = new SelectionTrait(role !== 'listbox');
this.focus = new Trait('focused');
mixin(_options, defaultStyles, false);
@@ -1259,11 +1261,13 @@ export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
this.spliceable = new CombinedSpliceable([
new TraitSpliceable(this.focus, this.view, _options.identityProvider),
new TraitSpliceable(this.selection, this.view, _options.identityProvider),
new TraitSpliceable(this.anchor, this.view, _options.identityProvider),
this.view
]);
this.disposables.add(this.focus);
this.disposables.add(this.selection);
this.disposables.add(this.anchor);
this.disposables.add(this.view);
this.disposables.add(this._onDidDispose);
@@ -1436,6 +1440,23 @@ export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
return this.getSelection().map(i => this.view.element(i));
}
setAnchor(index: number | undefined): void {
if (typeof index === 'undefined') {
this.anchor.set([]);
return;
}
if (index < 0 || index >= this.length) {
throw new ListError(this.user, `Invalid index ${index}`);
}
this.anchor.set([index]);
}
getAnchor(): number | undefined {
return firstOrDefault(this.anchor.get(), undefined);
}
setFocus(indexes: number[], browserEvent?: UIEvent): void {
for (const index of indexes) {
if (index < 0 || index >= this.length) {
@@ -1468,7 +1489,7 @@ export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
}
}
focusNextPage(browserEvent?: UIEvent, filter?: (element: T) => boolean): void {
async focusNextPage(browserEvent?: UIEvent, filter?: (element: T) => boolean): Promise<void> {
let lastPageIndex = this.view.indexAt(this.view.getScrollTop() + this.view.renderHeight);
lastPageIndex = lastPageIndex === 0 ? 0 : lastPageIndex - 1;
const lastPageElement = this.view.element(lastPageIndex);
@@ -1490,12 +1511,13 @@ export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
this.setFocus([]);
// Let the scroll event listener run
setTimeout(() => this.focusNextPage(browserEvent, filter), 0);
await timeout(0);
await this.focusNextPage(browserEvent, filter);
}
}
}
focusPreviousPage(browserEvent?: UIEvent, filter?: (element: T) => boolean): void {
async focusPreviousPage(browserEvent?: UIEvent, filter?: (element: T) => boolean): Promise<void> {
let firstPageIndex: number;
const scrollTop = this.view.getScrollTop();
@@ -1524,7 +1546,8 @@ export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
this.setFocus([]);
// Let the scroll event listener run
setTimeout(() => this.focusPreviousPage(browserEvent, filter), 0);
await timeout(0);
await this.focusPreviousPage(browserEvent, filter);
}
}
}

View File

@@ -85,3 +85,11 @@
.menubar.compact .toolbar-toggle-more::before {
content: "\eb94" !important;
}
/* Match behavior of outline for activity bar icons */
.menubar.compact > .menubar-menu-button.open,
.menubar.compact > .menubar-menu-button:focus,
.menubar.compact > .menubar-menu-button:hover {
outline-width: 1px !important;
outline-offset: -8px !important;
}

View File

@@ -976,7 +976,7 @@ export class MenuBar extends Disposable {
menuHolder.style.right = `${this.container.clientWidth}px`;
menuHolder.style.left = 'auto';
} else {
menuHolder.style.top = `${this.container.clientHeight}px`;
menuHolder.style.top = `${buttonBoundingRect.bottom}px`;
menuHolder.style.left = `${buttonBoundingRect.left}px`;
}

View File

@@ -85,27 +85,42 @@
}
.monaco-sash.vertical > .orthogonal-drag-handle.start {
left: calc(var(--sash-size) / -2);
left: calc(var(--sash-size) * -0.5);
top: calc(var(--sash-size) * -1);
}
.monaco-sash.vertical > .orthogonal-drag-handle.end {
left: calc(var(--sash-size) / -2);
left: calc(var(--sash-size) * -0.5);
bottom: calc(var(--sash-size) * -1);
}
.monaco-sash.horizontal > .orthogonal-drag-handle.start {
top: calc(var(--sash-size) / -2);
top: calc(var(--sash-size) * -0.5);
left: calc(var(--sash-size) * -1);
}
.monaco-sash.horizontal > .orthogonal-drag-handle.end {
top: calc(var(--sash-size) / -2);
top: calc(var(--sash-size) * -0.5);
right: calc(var(--sash-size) * -1);
}
.monaco-sash {
.monaco-sash:before {
content: '';
pointer-events: none;
position: absolute;
width: 100%;
height: 100%;
transition: background-color 0.1s ease-out;
background: transparent;
}
.monaco-sash.vertical:before {
width: var(--sash-hover-size);
left: calc(50% - (var(--sash-hover-size) / 2));
}
.monaco-sash.horizontal:before {
height: var(--sash-hover-size);
top: calc(50% - (var(--sash-hover-size) / 2));
}
/** Debug **/
.monaco-sash.debug {

View File

@@ -81,6 +81,13 @@ export function setGlobalSashSize(size: number): void {
onDidChangeGlobalSize.fire(size);
}
let globalHoverDelay = 300;
const onDidChangeHoverDelay = new Emitter<number>();
export function setGlobalHoverDelay(size: number): void {
globalHoverDelay = size;
onDidChangeHoverDelay.fire(size);
}
export class Sash extends Disposable {
private el: HTMLElement;
@@ -88,7 +95,8 @@ export class Sash extends Disposable {
private hidden: boolean;
private orientation!: Orientation;
private size: number;
private hoverDelayer = this._register(new Delayer(300));
private hoverDelay = globalHoverDelay;
private hoverDelayer = this._register(new Delayer(this.hoverDelay));
private _state: SashState = SashState.Enabled;
get state(): SashState { return this._state; }
@@ -221,6 +229,8 @@ export class Sash extends Disposable {
}));
}
this._register(onDidChangeHoverDelay.event(delay => this.hoverDelay = delay));
this.hidden = false;
this.layoutProvider = layoutProvider;
@@ -403,7 +413,7 @@ export class Sash extends Disposable {
sash.hoverDelayer.cancel();
sash.el.classList.add('hover');
} else {
sash.hoverDelayer.trigger(() => sash.el.classList.add('hover'));
sash.hoverDelayer.trigger(() => sash.el.classList.add('hover'), sash.hoverDelay).then(undefined, () => { });
}
if (!fromLinkedSash && sash.linkedSash) {

View File

@@ -29,6 +29,7 @@ export interface ISelectBoxDelegate extends IDisposable {
setAriaLabel(label: string): void;
focus(): void;
blur(): void;
setFocusable(focus: boolean): void;
// Delegated Widget interface
render(container: HTMLElement): void;
@@ -93,41 +94,43 @@ export class SelectBox extends Widget implements ISelectBoxDelegate {
// Public SelectBox Methods - routed through delegate interface
public get onDidSelect(): Event<ISelectData> {
get onDidSelect(): Event<ISelectData> {
return this.selectBoxDelegate.onDidSelect;
}
public setOptions(options: ISelectOptionItem[], selected?: number): void {
setOptions(options: ISelectOptionItem[], selected?: number): void {
this.selectBoxDelegate.setOptions(options, selected);
}
public select(index: number): void {
select(index: number): void {
this.selectBoxDelegate.select(index);
}
public setAriaLabel(label: string): void {
setAriaLabel(label: string): void {
this.selectBoxDelegate.setAriaLabel(label);
}
public focus(): void {
focus(): void {
this.selectBoxDelegate.focus();
}
public blur(): void {
blur(): void {
this.selectBoxDelegate.blur();
}
// Public Widget Methods - routed through delegate interface
setFocusable(focusable: boolean): void {
this.selectBoxDelegate.setFocusable(focusable);
}
public render(container: HTMLElement): void {
render(container: HTMLElement): void {
this.selectBoxDelegate.render(container);
}
public style(styles: ISelectBoxStyles): void {
style(styles: ISelectBoxStyles): void {
this.selectBoxDelegate.style(styles);
}
public applyStyles(): void {
applyStyles(): void {
this.selectBoxDelegate.applyStyles();
}
}

View File

@@ -293,16 +293,22 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
public focus(): void {
if (this.selectElement) {
this.selectElement.tabIndex = 0;
this.selectElement.focus();
}
}
public blur(): void {
if (this.selectElement) {
this.selectElement.tabIndex = -1;
this.selectElement.blur();
}
}
public setFocusable(focusable: boolean): void {
this.selectElement.tabIndex = focusable ? 0 : -1;
}
public render(container: HTMLElement): void {
this.container = container;
container.classList.add('select-container');

View File

@@ -132,16 +132,22 @@ export class SelectBoxNative extends Disposable implements ISelectBoxDelegate {
public focus(): void {
if (this.selectElement) {
this.selectElement.tabIndex = 0;
this.selectElement.focus();
}
}
public blur(): void {
if (this.selectElement) {
this.selectElement.tabIndex = -1;
this.selectElement.blur();
}
}
public setFocusable(focusable: boolean): void {
this.selectElement.tabIndex = focusable ? 0 : -1;
}
public render(container: HTMLElement): void {
container.classList.add('select-container');
container.appendChild(this.selectElement);

View File

@@ -73,6 +73,7 @@
align-items: center;
justify-content: center;
color: inherit;
outline-offset: -2px;
}
.monaco-pane-view .pane > .pane-header .monaco-action-bar .action-item.select-container {

View File

@@ -22,6 +22,7 @@
.monaco-table-tr {
display: flex;
height: 100%;
}
.monaco-table-th {
@@ -35,18 +36,12 @@
.monaco-table-th,
.monaco-table-td {
box-sizing: border-box;
padding-left: 10px;
flex-shrink: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.monaco-table-th[data-col-index="0"],
.monaco-table-td[data-col-index="0"] {
padding-left: 20px;
}
.monaco-table > .monaco-split-view2 .monaco-sash.vertical::before {
content: "";
position: absolute;

View File

@@ -250,7 +250,10 @@ export class Table<TRow> implements ISpliceable<TRow>, IThemable, IDisposable {
this.cachedHeight = height;
this.splitview.layout(width);
this.list.layout(height - this.virtualDelegate.headerRowHeight, width);
const listHeight = height - this.virtualDelegate.headerRowHeight;
this.list.getHTMLElement().style.height = `${listHeight}px`;
this.list.layout(listHeight, width);
}
toggleKeyboardNavigation(): void {
@@ -273,6 +276,14 @@ export class Table<TRow> implements ISpliceable<TRow>, IThemable, IDisposable {
this.list.domFocus();
}
setAnchor(index: number | undefined): void {
this.list.setAnchor(index);
}
getAnchor(): number | undefined {
return this.list.getAnchor();
}
getSelectedElements(): TRow[] {
return this.list.getSelectedElements();
}
@@ -297,12 +308,12 @@ export class Table<TRow> implements ISpliceable<TRow>, IThemable, IDisposable {
this.list.focusPrevious(n, loop, browserEvent);
}
focusNextPage(browserEvent?: UIEvent): void {
this.list.focusNextPage(browserEvent);
focusNextPage(browserEvent?: UIEvent): Promise<void> {
return this.list.focusNextPage(browserEvent);
}
focusPreviousPage(browserEvent?: UIEvent): void {
this.list.focusPreviousPage(browserEvent);
focusPreviousPage(browserEvent?: UIEvent): Promise<void> {
return this.list.focusPreviousPage(browserEvent);
}
focusFirst(browserEvent?: UIEvent): void {
@@ -317,6 +328,10 @@ export class Table<TRow> implements ISpliceable<TRow>, IThemable, IDisposable {
return this.list.getFocus();
}
getFocusedElements(): TRow[] {
return this.list.getFocusedElements();
}
reveal(index: number, relativeTop?: number): void {
this.list.reveal(index, relativeTop);
}

View File

@@ -14,7 +14,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
import { ITreeModel, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeFilter, ITreeNavigator, ICollapseStateChangeEvent, ITreeDragAndDrop, TreeDragOverBubble, TreeVisibility, TreeFilterResult, ITreeModelSpliceEvent, TreeMouseEventTarget } from 'vs/base/browser/ui/tree/tree';
import { ISpliceable } from 'vs/base/common/sequence';
import { IDragAndDropData, StaticDND, DragAndDropData } from 'vs/base/browser/dnd';
import { range, equals, distinctES6 } from 'vs/base/common/arrays';
import { range, equals, distinctES6, firstOrDefault } from 'vs/base/common/arrays';
import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView';
import { domEvent } from 'vs/base/browser/event';
import { fuzzyScore, FuzzyScore } from 'vs/base/common/filters';
@@ -683,6 +683,7 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
if (typeof options.filterOnType !== 'undefined') {
this._filterOnType = !!options.filterOnType;
this.filterOnTypeDomNode.checked = this._filterOnType;
this.updateFilterOnTypeTitleAndIcon();
}
if (typeof options.automaticKeyboardNavigation !== 'undefined') {
@@ -1168,6 +1169,7 @@ class TreeNodeList<T, TFilterData, TRef> extends List<ITreeNode<T, TFilterData>>
renderers: IListRenderer<any /* TODO@joao */, any>[],
private focusTrait: Trait<T>,
private selectionTrait: Trait<T>,
private anchorTrait: Trait<T>,
options: ITreeNodeListOptions<T, TFilterData, TRef>
) {
super(user, container, virtualDelegate, renderers, options);
@@ -1186,6 +1188,7 @@ class TreeNodeList<T, TFilterData, TRef> extends List<ITreeNode<T, TFilterData>>
const additionalFocus: number[] = [];
const additionalSelection: number[] = [];
let anchor: number | undefined;
elements.forEach((node, index) => {
if (this.focusTrait.has(node)) {
@@ -1195,6 +1198,10 @@ class TreeNodeList<T, TFilterData, TRef> extends List<ITreeNode<T, TFilterData>>
if (this.selectionTrait.has(node)) {
additionalSelection.push(start + index);
}
if (this.anchorTrait.has(node)) {
anchor = start + index;
}
});
if (additionalFocus.length > 0) {
@@ -1204,6 +1211,10 @@ class TreeNodeList<T, TFilterData, TRef> extends List<ITreeNode<T, TFilterData>>
if (additionalSelection.length > 0) {
super.setSelection(distinctES6([...super.getSelection(), ...additionalSelection]));
}
if (typeof anchor === 'number') {
super.setAnchor(anchor);
}
}
setFocus(indexes: number[], browserEvent?: UIEvent, fromAPI = false): void {
@@ -1221,6 +1232,18 @@ class TreeNodeList<T, TFilterData, TRef> extends List<ITreeNode<T, TFilterData>>
this.selectionTrait.set(indexes.map(i => this.element(i)), browserEvent);
}
}
setAnchor(index: number | undefined, fromAPI = false): void {
super.setAnchor(index);
if (!fromAPI) {
if (typeof index === 'undefined') {
this.anchorTrait.set([]);
} else {
this.anchorTrait.set([this.element(index)]);
}
}
}
}
export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable {
@@ -1230,6 +1253,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
protected model: ITreeModel<T, TFilterData, TRef>;
private focus: Trait<T>;
private selection: Trait<T>;
private anchor: Trait<T>;
private eventBufferer = new EventBufferer();
private typeFilterController?: TypeFilterController<T, TFilterData>;
private focusNavigationFilter: ((node: ITreeNode<T, TFilterData>) => boolean) | undefined;
@@ -1298,7 +1322,8 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
this.focus = new Trait(_options.identityProvider);
this.selection = new Trait(_options.identityProvider);
this.view = new TreeNodeList(user, container, treeDelegate, this.renderers, this.focus, this.selection, { ...asListOptions(() => this.model, _options), tree: this });
this.anchor = new Trait(_options.identityProvider);
this.view = new TreeNodeList(user, container, treeDelegate, this.renderers, this.focus, this.selection, this.anchor, { ...asListOptions(() => this.model, _options), tree: this });
this.model = this.createModel(user, this.view, _options);
onDidChangeCollapseStateRelay.input = this.model.onDidChangeCollapseState;
@@ -1552,6 +1577,25 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
this.model.refilter();
}
setAnchor(element: TRef | undefined): void {
if (typeof element === 'undefined') {
return this.view.setAnchor(undefined);
}
const node = this.model.getNode(element);
this.anchor.set([node]);
const index = this.model.getListIndex(element);
if (index > -1) {
this.view.setAnchor(index, true);
}
}
getAnchor(): T | undefined {
return firstOrDefault(this.anchor.get(), undefined);
}
setSelection(elements: TRef[], browserEvent?: UIEvent): void {
const nodes = elements.map(e => this.model.getNode(e));
this.selection.set(nodes, browserEvent);
@@ -1580,12 +1624,12 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
this.view.focusPrevious(n, loop, browserEvent, filter);
}
focusNextPage(browserEvent?: UIEvent, filter = this.focusNavigationFilter): void {
this.view.focusNextPage(browserEvent, filter);
focusNextPage(browserEvent?: UIEvent, filter = this.focusNavigationFilter): Promise<void> {
return this.view.focusNextPage(browserEvent, filter);
}
focusPreviousPage(browserEvent?: UIEvent, filter = this.focusNavigationFilter): void {
this.view.focusPreviousPage(browserEvent, filter);
focusPreviousPage(browserEvent?: UIEvent, filter = this.focusNavigationFilter): Promise<void> {
return this.view.focusPreviousPage(browserEvent, filter);
}
focusLast(browserEvent?: UIEvent, filter = this.focusNavigationFilter): void {

View File

@@ -616,7 +616,7 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
return this.tree.isCollapsible(this.getDataNode(element));
}
isCollapsed(element: T): boolean {
isCollapsed(element: TInput | T): boolean {
return this.tree.isCollapsed(this.getDataNode(element));
}
@@ -628,6 +628,15 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
this.tree.refilter();
}
setAnchor(element: T | undefined): void {
this.tree.setAnchor(typeof element === 'undefined' ? undefined : this.getDataNode(element));
}
getAnchor(): T | undefined {
const node = this.tree.getAnchor();
return node?.element as T;
}
setSelection(elements: T[], browserEvent?: UIEvent): void {
const nodes = elements.map(e => this.getDataNode(e));
this.tree.setSelection(nodes, browserEvent);
@@ -651,12 +660,12 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
this.tree.focusPrevious(n, loop, browserEvent);
}
focusNextPage(browserEvent?: UIEvent): void {
this.tree.focusNextPage(browserEvent);
focusNextPage(browserEvent?: UIEvent): Promise<void> {
return this.tree.focusNextPage(browserEvent);
}
focusPreviousPage(browserEvent?: UIEvent): void {
this.tree.focusPreviousPage(browserEvent);
focusPreviousPage(browserEvent?: UIEvent): Promise<void> {
return this.tree.focusPreviousPage(browserEvent);
}
focusLast(browserEvent?: UIEvent): void {

View File

@@ -8,7 +8,6 @@ import { IndexTreeModel, IIndexTreeModelOptions, IList, IIndexTreeModelSpliceOpt
import { Event } from 'vs/base/common/event';
import { ITreeModel, ITreeNode, ITreeElement, ITreeSorter, ICollapseStateChangeEvent, ITreeModelSpliceEvent, TreeError } from 'vs/base/browser/ui/tree/tree';
import { IIdentityProvider } from 'vs/base/browser/ui/list/list';
import { mergeSort } from 'vs/base/common/arrays';
export type ITreeNodeCallback<T, TFilterData> = (node: ITreeNode<T, TFilterData>) => void;
@@ -130,7 +129,7 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
private preserveCollapseState(elements: Iterable<ITreeElement<T>> = Iterable.empty()): Iterable<ITreeElement<T>> {
if (this.sorter) {
elements = mergeSort([...elements], this.sorter.compare.bind(this.sorter));
elements = [...elements].sort(this.sorter.compare.bind(this.sorter));
}
return Iterable.map(elements, treeElement => {
@@ -185,7 +184,7 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
let childrenNodes = [...node.children] as ITreeNode<T, TFilterData>[];
if (recursive || first) {
childrenNodes = mergeSort(childrenNodes, this.sorter!.compare.bind(this.sorter));
childrenNodes = childrenNodes.sort(this.sorter!.compare.bind(this.sorter));
}
return Iterable.map<ITreeNode<T | null, TFilterData>, ITreeElement<T>>(childrenNodes, node => ({