diff --git a/src/vs/base/browser/ui/table/table.css b/src/vs/base/browser/ui/table/table.css index 19ae63929ad..f6b5ab93b87 100644 --- a/src/vs/base/browser/ui/table/table.css +++ b/src/vs/base/browser/ui/table/table.css @@ -22,6 +22,7 @@ .monaco-table-tr { display: flex; + height: 100%; } .monaco-table-th { diff --git a/src/vs/base/browser/ui/table/tableWidget.ts b/src/vs/base/browser/ui/table/tableWidget.ts index 183200e2eb5..3e235c77a37 100644 --- a/src/vs/base/browser/ui/table/tableWidget.ts +++ b/src/vs/base/browser/ui/table/tableWidget.ts @@ -317,6 +317,10 @@ export class Table implements ISpliceable, IThemable, IDisposable { return this.list.getFocus(); } + getFocusedElements(): TRow[] { + return this.list.getFocusedElements(); + } + reveal(index: number, relativeTop?: number): void { this.list.reveal(index, relativeTop); } diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 0262b0e4a05..e7195eeb891 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -427,7 +427,7 @@ export interface IWorkbenchTableOptionsUpdate extends ITableOptionsUpdate { readonly overrideStyles?: IColorMapping; } -export interface IWorkbenchTableOptions extends IWorkbenchTableOptionsUpdate, ITableOptions { } +export interface IWorkbenchTableOptions extends IWorkbenchTableOptionsUpdate, IResourceNavigatorOptions, ITableOptions { } export class WorkbenchTable extends Table { diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index 04fd316a869..5a5271d6b77 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -8,7 +8,7 @@ import { localize } from 'vs/nls'; import { Delayer } from 'vs/base/common/async'; import * as DOM from 'vs/base/browser/dom'; import { OS } from 'vs/base/common/platform'; -import { dispose, Disposable, IDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { CheckboxActionViewItem } from 'vs/base/browser/ui/checkbox/checkbox'; import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel'; @@ -25,15 +25,14 @@ import { DefineKeybindingWidget, KeybindingsSearchWidget } from 'vs/workbench/co import { CONTEXT_KEYBINDING_FOCUS, CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_ADD } from 'vs/workbench/contrib/preferences/common/preferences'; import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IKeybindingEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing'; -import { IListVirtualDelegate, IListRenderer, IListContextMenuEvent, IListEvent } from 'vs/base/browser/ui/list/list'; +import { IListContextMenuEvent, IListEvent } from 'vs/base/browser/ui/list/list'; import { IThemeService, registerThemingParticipant, IColorTheme, ICssStyleCollector, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IContextKeyService, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode, ResolvedKeybinding } from 'vs/base/common/keyCodes'; import { listHighlightForeground, badgeBackground, contrastBorder, badgeForeground, listActiveSelectionForeground, listInactiveSelectionForeground, listHoverForeground, listFocusForeground, editorBackground, foreground, listActiveSelectionBackground, listInactiveSelectionBackground, listFocusBackground, listHoverBackground } from 'vs/platform/theme/common/colorRegistry'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; -import { WorkbenchList } from 'vs/platform/list/browser/listService'; +import { WorkbenchTable } from 'vs/platform/list/browser/listService'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { KeybindingsEditorInput } from 'vs/workbench/services/preferences/browser/preferencesEditorInput'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -48,16 +47,11 @@ import { WORKBENCH_BACKGROUND } from 'vs/workbench/common/theme'; import { IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems'; import { IKeybindingItemEntry, IKeybindingsEditorPane } from 'vs/workbench/services/preferences/common/preferences'; import { keybindingsRecordKeysIcon, keybindingsSortIcon, keybindingsAddIcon, preferencesClearInputIcon, keybindingsEditIcon } from 'vs/workbench/contrib/preferences/browser/preferencesIcons'; +import { ITableRenderer, ITableVirtualDelegate } from 'vs/base/browser/ui/table/table'; const $ = DOM.$; -interface ColumnItem { - column: HTMLElement; - proportion?: number; - width: number; -} - -const oddRowBackgroundColor = new Color(new RGBA(130, 130, 130, 0.04)); +const evenRowBackgroundColor = new Color(new RGBA(130, 130, 130, 0.04)); class ThemableCheckboxActionViewItem extends CheckboxActionViewItem { @@ -93,11 +87,10 @@ export class KeybindingsEditor extends EditorPane implements IKeybindingsEditorP private overlayContainer!: HTMLElement; private defineKeybindingWidget!: DefineKeybindingWidget; - private columnItems: ColumnItem[] = []; - private keybindingsListContainer!: HTMLElement; private unAssignedKeybindingItemToRevealAndFocus: IKeybindingItemEntry | null = null; - private listEntries: IKeybindingItemEntry[] = []; - private keybindingsList!: WorkbenchList; + private tableEntries: IKeybindingItemEntry[] = []; + private keybindingsTableContainer!: HTMLElement; + private keybindingsTable!: WorkbenchTable; private dimension: DOM.Dimension | null = null; private delayedFiltering: Delayer; @@ -173,24 +166,10 @@ export class KeybindingsEditor extends EditorPane implements IKeybindingsEditorP this.overlayContainer.style.height = dimension.height + 'px'; this.defineKeybindingWidget.layout(this.dimension); - this.columnItems.forEach(columnItem => { - if (columnItem.proportion) { - columnItem.width = 0; - } - }); - this.layoutKeybindingsList(); + this.layoutKeybindingsTable(); this._onLayout.fire(); } - layoutColumns(columns: HTMLElement[]): void { - if (this.columnItems) { - columns.forEach((column, index) => { - column.style.paddingRight = `6px`; - column.style.width = `${this.columnItems[index].width}px`; - }); - } - } - focus(): void { const activeKeybindingEntry = this.activeKeybindingEntry; if (activeKeybindingEntry) { @@ -201,7 +180,7 @@ export class KeybindingsEditor extends EditorPane implements IKeybindingsEditorP } get activeKeybindingEntry(): IKeybindingItemEntry | null { - const focusedElement = this.keybindingsList.getFocusedElements()[0]; + const focusedElement = this.keybindingsTable.getFocusedElements()[0]; return focusedElement && focusedElement.templateId === KEYBINDING_ENTRY_TEMPLATE_ID ? focusedElement : null; } @@ -448,72 +427,90 @@ export class KeybindingsEditor extends EditorPane implements IKeybindingsEditorP private createBody(parent: HTMLElement): void { const bodyContainer = DOM.append(parent, $('.keybindings-body')); - this.createListHeader(bodyContainer); - this.createList(bodyContainer); + this.createTable(bodyContainer); } - private createListHeader(parent: HTMLElement): void { - const keybindingsListHeader = DOM.append(parent, $('.keybindings-list-header')); - keybindingsListHeader.style.height = '30px'; - keybindingsListHeader.style.lineHeight = '30px'; - - this.columnItems = []; - let column = $('.header.actions'); - this.columnItems.push({ column, width: 30 }); - - column = $('.header.command', undefined, localize('command', "Command")); - this.columnItems.push({ column, proportion: 0.3, width: 0 }); - - column = $('.header.keybinding', undefined, localize('keybinding', "Keybinding")); - this.columnItems.push({ column, proportion: 0.2, width: 0 }); - - column = $('.header.when', undefined, localize('when', "When")); - this.columnItems.push({ column, proportion: 0.4, width: 0 }); - - column = $('.header.source', undefined, localize('source', "Source")); - this.columnItems.push({ column, proportion: 0.1, width: 0 }); - - DOM.append(keybindingsListHeader, ...this.columnItems.map(({ column }) => column)); - } - - private createList(parent: HTMLElement): void { - this.keybindingsListContainer = DOM.append(parent, $('.keybindings-list-container')); - this.keybindingsList = this._register(this.instantiationService.createInstance(WorkbenchList, 'KeybindingsEditor', this.keybindingsListContainer, new Delegate(), [new KeybindingItemRenderer(this, this.instantiationService)], { - identityProvider: { getId: (e: IKeybindingItemEntry) => e.id }, - setRowLineHeight: false, - horizontalScrolling: false, - accessibilityProvider: new AccessibilityProvider(), - keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IKeybindingItemEntry) => e.keybindingItem.commandLabel || e.keybindingItem.command }, - overrideStyles: { - listBackground: editorBackground + private createTable(parent: HTMLElement): void { + this.keybindingsTableContainer = DOM.append(parent, $('.keybindings-table-container')); + this.keybindingsTable = this._register(this.instantiationService.createInstance(WorkbenchTable, + 'KeybindingsEditor', + this.keybindingsTableContainer, + new Delegate(), + [ + { + label: '', + tooltip: '', + weight: 0, + minimumWidth: 40, + maximumWidth: 40, + templateId: ActionsColumnRenderer.TEMPLATE_ID, + project(row: IKeybindingItemEntry): IKeybindingItemEntry { return row; } + }, + { + label: localize('command', "Command"), + tooltip: '', + weight: 0.3, + templateId: CommandColumnRenderer.TEMPLATE_ID, + project(row: IKeybindingItemEntry): IKeybindingItemEntry { return row; } + }, + { + label: localize('keybinding', "Keybinding"), + tooltip: '', + weight: 0.2, + templateId: KeybindingColumnRenderer.TEMPLATE_ID, + project(row: IKeybindingItemEntry): IKeybindingItemEntry { return row; } + }, + { + label: localize('when', "When"), + tooltip: '', + weight: 0.4, + templateId: WhenColumnRenderer.TEMPLATE_ID, + project(row: IKeybindingItemEntry): IKeybindingItemEntry { return row; } + }, + { + label: localize('source', "Source"), + tooltip: '', + weight: 0.1, + templateId: SourceColumnRenderer.TEMPLATE_ID, + project(row: IKeybindingItemEntry): IKeybindingItemEntry { return row; } + }, + ], + [ + this.instantiationService.createInstance(ActionsColumnRenderer, this), + this.instantiationService.createInstance(CommandColumnRenderer), + this.instantiationService.createInstance(KeybindingColumnRenderer), + this.instantiationService.createInstance(WhenColumnRenderer, this), + this.instantiationService.createInstance(SourceColumnRenderer), + ], + { + identityProvider: { getId: (e: IKeybindingItemEntry) => e.id }, + horizontalScrolling: false, + accessibilityProvider: new AccessibilityProvider(), + keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IKeybindingItemEntry) => e.keybindingItem.commandLabel || e.keybindingItem.command }, + overrideStyles: { + listBackground: editorBackground + }, + multipleSelectionSupport: false, + setRowLineHeight: false, + openOnSingleClick: false, } - })) as WorkbenchList; + )) as WorkbenchTable; - this._register(this.keybindingsList.onContextMenu(e => this.onContextMenu(e))); - this._register(this.keybindingsList.onDidChangeFocus(e => this.onFocusChange(e))); - this._register(this.keybindingsList.onDidFocus(() => { - this.keybindingsList.getHTMLElement().classList.add('focused'); + this._register(this.keybindingsTable.onContextMenu(e => this.onContextMenu(e))); + this._register(this.keybindingsTable.onDidChangeFocus(e => this.onFocusChange(e))); + this._register(this.keybindingsTable.onDidFocus(() => { + this.keybindingsTable.getHTMLElement().classList.add('focused'); })); - this._register(this.keybindingsList.onDidBlur(() => { - this.keybindingsList.getHTMLElement().classList.remove('focused'); + this._register(this.keybindingsTable.onDidBlur(() => { + this.keybindingsTable.getHTMLElement().classList.remove('focused'); this.keybindingFocusContextKey.reset(); })); - this._register(this.keybindingsList.onMouseDblClick(() => { + this._register(this.keybindingsTable.onDidOpen((e) => { const activeKeybindingEntry = this.activeKeybindingEntry; if (activeKeybindingEntry) { this.defineKeybinding(activeKeybindingEntry, false); } })); - this._register(this.keybindingsList.onKeyDown(e => { - const event = new StandardKeyboardEvent(e); - if (event.keyCode === KeyCode.Enter) { - const keybindingEntry = this.activeKeybindingEntry; - if (keybindingEntry) { - this.defineKeybinding(keybindingEntry, false); - } - e.stopPropagation(); - } - })); } private async render(preserveFocus: boolean): Promise { @@ -565,23 +562,23 @@ export class KeybindingsEditor extends EditorPane implements IKeybindingsEditorP if (keybindingsEntries.length === 0) { this.latestEmptyFilters.push(filter); } - const currentSelectedIndex = this.keybindingsList.getSelection()[0]; - this.listEntries = keybindingsEntries; - this.keybindingsList.splice(0, this.keybindingsList.length, this.listEntries); - this.layoutKeybindingsList(); + const currentSelectedIndex = this.keybindingsTable.getSelection()[0]; + this.tableEntries = keybindingsEntries; + this.keybindingsTable.splice(0, this.keybindingsTable.length, this.tableEntries); + this.layoutKeybindingsTable(); if (reset) { - this.keybindingsList.setSelection([]); - this.keybindingsList.setFocus([]); + this.keybindingsTable.setSelection([]); + this.keybindingsTable.setFocus([]); } else { if (this.unAssignedKeybindingItemToRevealAndFocus) { const index = this.getNewIndexOfUnassignedKeybinding(this.unAssignedKeybindingItemToRevealAndFocus); if (index !== -1) { - this.keybindingsList.reveal(index, 0.2); + this.keybindingsTable.reveal(index, 0.2); this.selectEntry(index); } this.unAssignedKeybindingItemToRevealAndFocus = null; - } else if (currentSelectedIndex !== -1 && currentSelectedIndex < this.listEntries.length) { + } else if (currentSelectedIndex !== -1 && currentSelectedIndex < this.tableEntries.length) { this.selectEntry(currentSelectedIndex, preserveFocus); } else if (this.editorService.activeEditorPane === this && !preserveFocus) { this.focus(); @@ -598,33 +595,21 @@ export class KeybindingsEditor extends EditorPane implements IKeybindingsEditorP } } - private layoutKeybindingsList(): void { + private layoutKeybindingsTable(): void { if (!this.dimension) { return; } - let width = this.dimension.width - 27; - for (const columnItem of this.columnItems) { - if (columnItem.width && !columnItem.proportion) { - width = width - columnItem.width; - } - } - for (const columnItem of this.columnItems) { - if (columnItem.proportion && !columnItem.width) { - columnItem.width = width * columnItem.proportion; - } - } - this.layoutColumns(this.columnItems.map(({ column }) => column)); - const listHeight = this.dimension.height - (DOM.getDomNodePagePosition(this.headerContainer).height + 12 /*padding*/ + 30 /*list header*/); - this.keybindingsListContainer.style.height = `${listHeight}px`; - this.keybindingsList.layout(listHeight); + const tableHeight = this.dimension.height - (DOM.getDomNodePagePosition(this.headerContainer).height + 12 /*padding*/); + this.keybindingsTableContainer.style.height = `${tableHeight}px`; + this.keybindingsTable.layout(tableHeight); } private getIndexOf(listEntry: IKeybindingItemEntry): number { - const index = this.listEntries.indexOf(listEntry); + const index = this.tableEntries.indexOf(listEntry); if (index === -1) { - for (let i = 0; i < this.listEntries.length; i++) { - if (this.listEntries[i].id === listEntry.id) { + for (let i = 0; i < this.tableEntries.length; i++) { + if (this.tableEntries[i].id === listEntry.id) { return i; } } @@ -633,8 +618,8 @@ export class KeybindingsEditor extends EditorPane implements IKeybindingsEditorP } private getNewIndexOfUnassignedKeybinding(unassignedKeybinding: IKeybindingItemEntry): number { - for (let index = 0; index < this.listEntries.length; index++) { - const entry = this.listEntries[index]; + for (let index = 0; index < this.tableEntries.length; index++) { + const entry = this.tableEntries[index]; if (entry.templateId === KEYBINDING_ENTRY_TEMPLATE_ID) { const keybindingItemEntry = (entry); if (keybindingItemEntry.keybindingItem.command === unassignedKeybinding.keybindingItem.command) { @@ -649,17 +634,17 @@ export class KeybindingsEditor extends EditorPane implements IKeybindingsEditorP const index = typeof keybindingItemEntry === 'number' ? keybindingItemEntry : this.getIndexOf(keybindingItemEntry); if (index !== -1) { if (focus) { - this.keybindingsList.getHTMLElement().focus(); - this.keybindingsList.setFocus([index]); + this.keybindingsTable.domFocus(); + this.keybindingsTable.setFocus([index]); } - this.keybindingsList.setSelection([index]); + this.keybindingsTable.setSelection([index]); } } focusKeybindings(): void { - this.keybindingsList.getHTMLElement().focus(); - const currentFocusIndices = this.keybindingsList.getFocus(); - this.keybindingsList.setFocus([currentFocusIndices.length ? currentFocusIndices[0] : 0]); + this.keybindingsTable.domFocus(); + const currentFocusIndices = this.keybindingsTable.getFocus(); + this.keybindingsTable.setFocus([currentFocusIndices.length ? currentFocusIndices[0] : 0]); } selectKeybinding(keybindingItemEntry: IKeybindingItemEntry): void { @@ -821,7 +806,9 @@ export class KeybindingsEditor extends EditorPane implements IKeybindingsEditorP } } -class Delegate implements IListVirtualDelegate { +class Delegate implements ITableVirtualDelegate { + + readonly headerRowHeight = 30; getHeight(element: IKeybindingItemEntry) { if (element.templateId === KEYBINDING_ENTRY_TEMPLATE_ID) { @@ -837,98 +824,39 @@ class Delegate implements IListVirtualDelegate { return 24; } - getTemplateId(element: IKeybindingItemEntry) { - return element.templateId; - } } -interface KeybindingItemTemplate { - parent: HTMLElement; - columns: Column[]; - disposable: IDisposable; +interface IActionsColumnTemplateData { + readonly actionBar: ActionBar; } -class KeybindingItemRenderer implements IListRenderer { +class ActionsColumnRenderer implements ITableRenderer { - get templateId(): string { return KEYBINDING_ENTRY_TEMPLATE_ID; } + static readonly TEMPLATE_ID = 'actions'; + + readonly templateId: string = ActionsColumnRenderer.TEMPLATE_ID; constructor( - private keybindingsEditor: KeybindingsEditor, - private instantiationService: IInstantiationService - ) { } - - renderTemplate(parent: HTMLElement): KeybindingItemTemplate { - parent.classList.add('keybinding-item'); - - const actions = this.instantiationService.createInstance(ActionsColumn, parent, this.keybindingsEditor); - const command = this.instantiationService.createInstance(CommandColumn, parent, this.keybindingsEditor); - const keybinding = this.instantiationService.createInstance(KeybindingColumn, parent, this.keybindingsEditor); - const when = this.instantiationService.createInstance(WhenColumn, parent, this.keybindingsEditor); - const source = this.instantiationService.createInstance(SourceColumn, parent, this.keybindingsEditor); - - const columns: Column[] = [actions, command, keybinding, when, source]; - const disposables = combinedDisposable(...columns); - const elements = columns.map(({ element }) => element); - - this.keybindingsEditor.layoutColumns(elements); - this.keybindingsEditor.onLayout(() => this.keybindingsEditor.layoutColumns(elements)); - - return { - parent, - columns, - disposable: disposables - }; - } - - renderElement(keybindingEntry: IKeybindingItemEntry, index: number, template: KeybindingItemTemplate): void { - template.parent.classList.toggle('odd', index % 2 === 1); - for (const column of template.columns) { - column.render(keybindingEntry); - } - } - - disposeTemplate(template: KeybindingItemTemplate): void { - template.disposable.dispose(); - } -} - -abstract class Column extends Disposable { - - static COUNTER = 0; - - abstract readonly element: HTMLElement; - abstract render(keybindingItemEntry: IKeybindingItemEntry): void; - - constructor(protected keybindingsEditor: IKeybindingsEditorPane) { - super(); - } - -} - -class ActionsColumn extends Column { - - private readonly actionBar: ActionBar; - readonly element: HTMLElement; - - constructor( - parent: HTMLElement, - keybindingsEditor: IKeybindingsEditorPane, - @IKeybindingService private keybindingsService: IKeybindingService + private readonly keybindingsEditor: KeybindingsEditor, + @IKeybindingService private readonly keybindingsService: IKeybindingService ) { - super(keybindingsEditor); - this.element = DOM.append(parent, $('.column.actions', { id: 'actions_' + ++Column.COUNTER })); - this.actionBar = new ActionBar(this.element, { animated: false }); } - render(keybindingItemEntry: IKeybindingItemEntry): void { - this.actionBar.clear(); + renderTemplate(container: HTMLElement): IActionsColumnTemplateData { + const element = DOM.append(container, $('.actions')); + const actionBar = new ActionBar(element, { animated: false }); + return { actionBar }; + } + + renderElement(keybindingItemEntry: IKeybindingItemEntry, index: number, templateData: IActionsColumnTemplateData, height: number | undefined): void { + templateData.actionBar.clear(); const actions: IAction[] = []; if (keybindingItemEntry.keybindingItem.keybinding) { actions.push(this.createEditAction(keybindingItemEntry)); } else { actions.push(this.createAddAction(keybindingItemEntry)); } - this.actionBar.push(actions, { icon: true }); + templateData.actionBar.push(actions, { icon: true }); } private createEditAction(keybindingItemEntry: IKeybindingItemEntry): IAction { @@ -953,117 +881,155 @@ class ActionsColumn extends Column { }; } - dispose(): void { - super.dispose(); - dispose(this.actionBar); + disposeTemplate(templateData: IActionsColumnTemplateData): void { + templateData.actionBar.dispose(); } + } -class CommandColumn extends Column { +interface ICommandColumnTemplateData { + commandColumn: HTMLElement; + commandLabelContainer: HTMLElement; + commandLabel: HighlightedLabel; + commandDefaultLabelContainer: HTMLElement; + commandDefaultLabel: HighlightedLabel; + commandIdLabelContainer: HTMLElement; + commandIdLabel: HighlightedLabel; +} - private readonly commandColumn: HTMLElement; - readonly element: HTMLElement; +class CommandColumnRenderer implements ITableRenderer { - constructor( - parent: HTMLElement, - keybindingsEditor: IKeybindingsEditorPane, - ) { - super(keybindingsEditor); - this.element = this.commandColumn = DOM.append(parent, $('.column.command', { id: 'command_' + ++Column.COUNTER })); + static readonly TEMPLATE_ID = 'commands'; + + readonly templateId: string = CommandColumnRenderer.TEMPLATE_ID; + + renderTemplate(container: HTMLElement): ICommandColumnTemplateData { + const commandColumn = DOM.append(container, $('.command')); + const commandLabelContainer = DOM.append(commandColumn, $('.command-label')); + const commandLabel = new HighlightedLabel(commandLabelContainer, false); + const commandDefaultLabelContainer = DOM.append(commandColumn, $('.command-default-label')); + const commandDefaultLabel = new HighlightedLabel(commandDefaultLabelContainer, false); + const commandIdLabelContainer = DOM.append(commandColumn, $('.command-id.code')); + const commandIdLabel = new HighlightedLabel(commandIdLabelContainer, false); + return { commandColumn, commandLabelContainer, commandLabel, commandDefaultLabelContainer, commandDefaultLabel, commandIdLabelContainer, commandIdLabel }; } - render(keybindingItemEntry: IKeybindingItemEntry): void { - DOM.clearNode(this.commandColumn); + renderElement(keybindingItemEntry: IKeybindingItemEntry, index: number, templateData: ICommandColumnTemplateData, height: number | undefined): void { const keybindingItem = keybindingItemEntry.keybindingItem; const commandIdMatched = !!(keybindingItem.commandLabel && keybindingItemEntry.commandIdMatches); const commandDefaultLabelMatched = !!keybindingItemEntry.commandDefaultLabelMatches; - this.commandColumn.classList.toggle('vertical-align-column', commandIdMatched || commandDefaultLabelMatched); - let commandLabel: HighlightedLabel | undefined; + + templateData.commandColumn.classList.toggle('vertical-align-column', commandIdMatched || commandDefaultLabelMatched); + templateData.commandColumn.title = keybindingItem.commandLabel ? localize('title', "{0} ({1})", keybindingItem.commandLabel, keybindingItem.command) : keybindingItem.command; + if (keybindingItem.commandLabel) { - commandLabel = new HighlightedLabel(this.commandColumn, false); - commandLabel.set(keybindingItem.commandLabel, keybindingItemEntry.commandLabelMatches); + templateData.commandLabelContainer.classList.remove('hide'); + templateData.commandLabel.set(keybindingItem.commandLabel, keybindingItemEntry.commandLabelMatches); + } else { + templateData.commandLabelContainer.classList.add('hide'); + templateData.commandLabel.set(undefined); } + if (keybindingItemEntry.commandDefaultLabelMatches) { - commandLabel = new HighlightedLabel(DOM.append(this.commandColumn, $('.command-default-label')), false); - commandLabel.set(keybindingItem.commandDefaultLabel, keybindingItemEntry.commandDefaultLabelMatches); + templateData.commandDefaultLabelContainer.classList.remove('hide'); + templateData.commandDefaultLabel.set(keybindingItem.commandDefaultLabel, keybindingItemEntry.commandDefaultLabelMatches); + } else { + templateData.commandDefaultLabelContainer.classList.add('hide'); + templateData.commandDefaultLabel.set(undefined); } + if (keybindingItemEntry.commandIdMatches || !keybindingItem.commandLabel) { - commandLabel = new HighlightedLabel(DOM.append(this.commandColumn, $('.code')), false); - commandLabel.set(keybindingItem.command, keybindingItemEntry.commandIdMatches); - } - if (commandLabel) { - commandLabel.element.title = keybindingItem.commandLabel ? localize('title', "{0} ({1})", keybindingItem.commandLabel, keybindingItem.command) : keybindingItem.command; + templateData.commandIdLabelContainer.classList.remove('hide'); + templateData.commandIdLabel.set(keybindingItem.command, keybindingItemEntry.commandIdMatches); + } else { + templateData.commandIdLabelContainer.classList.add('hide'); + templateData.commandIdLabel.set(undefined); } } + + disposeTemplate(templateData: ICommandColumnTemplateData): void { } } -class KeybindingColumn extends Column { +interface IKeybindingColumnTemplateData { + keybindingLabel: KeybindingLabel; +} - private readonly keybindingLabel: HTMLElement; - readonly element: HTMLElement; +class KeybindingColumnRenderer implements ITableRenderer { - constructor( - parent: HTMLElement, - keybindingsEditor: IKeybindingsEditorPane, - ) { - super(keybindingsEditor); + static readonly TEMPLATE_ID = 'keybindings'; - this.element = DOM.append(parent, $('.column.keybinding', { id: 'keybinding_' + ++Column.COUNTER })); - this.keybindingLabel = DOM.append(this.element, $('div.keybinding-label')); + readonly templateId: string = KeybindingColumnRenderer.TEMPLATE_ID; + + renderTemplate(container: HTMLElement): IKeybindingColumnTemplateData { + const element = DOM.append(container, $('.keybinding')); + const keybindingLabel = new KeybindingLabel(DOM.append(element, $('div.keybinding-label')), OS); + return { keybindingLabel }; } - render(keybindingItemEntry: IKeybindingItemEntry): void { - DOM.clearNode(this.keybindingLabel); + renderElement(keybindingItemEntry: IKeybindingItemEntry, index: number, templateData: IKeybindingColumnTemplateData, height: number | undefined): void { if (keybindingItemEntry.keybindingItem.keybinding) { - new KeybindingLabel(this.keybindingLabel, OS).set(keybindingItemEntry.keybindingItem.keybinding, keybindingItemEntry.keybindingMatches); + templateData.keybindingLabel.set(keybindingItemEntry.keybindingItem.keybinding, keybindingItemEntry.keybindingMatches); + } else { + templateData.keybindingLabel.set(undefined, undefined); } } + + disposeTemplate(templateData: IKeybindingColumnTemplateData): void { } } -class SourceColumn extends Column { - - private readonly sourceColumn: HTMLElement; - readonly element: HTMLElement; - - constructor( - parent: HTMLElement, - keybindingsEditor: IKeybindingsEditorPane, - ) { - super(keybindingsEditor); - this.element = this.sourceColumn = DOM.append(parent, $('.column.source', { id: 'source_' + ++Column.COUNTER })); - } - - render(keybindingItemEntry: IKeybindingItemEntry): void { - DOM.clearNode(this.sourceColumn); - new HighlightedLabel(this.sourceColumn, false).set(keybindingItemEntry.keybindingItem.source, keybindingItemEntry.sourceMatches); - } +interface ISourceColumnTemplateData { + highlightedLabel: HighlightedLabel; } -class WhenColumn extends Column { +class SourceColumnRenderer implements ITableRenderer { + static readonly TEMPLATE_ID = 'source'; + + readonly templateId: string = SourceColumnRenderer.TEMPLATE_ID; + + renderTemplate(container: HTMLElement): ISourceColumnTemplateData { + const sourceColumn = DOM.append(container, $('.source')); + const highlightedLabel = new HighlightedLabel(sourceColumn, false); + return { highlightedLabel }; + } + + renderElement(keybindingItemEntry: IKeybindingItemEntry, index: number, templateData: ISourceColumnTemplateData, height: number | undefined): void { + templateData.highlightedLabel.set(keybindingItemEntry.keybindingItem.source, keybindingItemEntry.sourceMatches); + } + + disposeTemplate(templateData: ISourceColumnTemplateData): void { } +} + +interface IWhenColumnTemplateData { readonly element: HTMLElement; - private readonly whenLabel: HTMLElement; - private readonly whenInput: InputBox; - private readonly renderDisposables = this._register(new DisposableStore()); + readonly whenContainer: HTMLElement; + readonly whenLabel: HighlightedLabel; + readonly whenInput: InputBox + readonly renderDisposables: DisposableStore; + readonly onDidAccept: Event; + readonly onDidReject: Event; + readonly disposables: DisposableStore; +} - private _onDidAccept: Emitter = this._register(new Emitter()); - private readonly onDidAccept: Event = this._onDidAccept.event; +class WhenColumnRenderer implements ITableRenderer { - private _onDidReject: Emitter = this._register(new Emitter()); - private readonly onDidReject: Event = this._onDidReject.event; + static readonly TEMPLATE_ID = 'when'; + + readonly templateId: string = WhenColumnRenderer.TEMPLATE_ID; constructor( - parent: HTMLElement, - keybindingsEditor: IKeybindingsEditorPane, + private readonly keybindingsEditor: KeybindingsEditor, @IContextViewService private readonly contextViewService: IContextViewService, @IThemeService private readonly themeService: IThemeService ) { - super(keybindingsEditor); + } - this.element = DOM.append(parent, $('.column.when', { id: 'when_' + ++Column.COUNTER })); + renderTemplate(container: HTMLElement): IWhenColumnTemplateData { + const element = DOM.append(container, $('.when')); - this.whenLabel = DOM.append(this.element, $('div.when-label')); - this.whenInput = new InputBox(this.element, this.contextViewService, { + const whenContainer = DOM.append(element, $('div.when-label')); + const whenLabel = new HighlightedLabel(whenContainer, false); + const whenInput = new InputBox(element, this.contextViewService, { validationOptions: { validation: (value) => { try { @@ -1080,71 +1046,90 @@ class WhenColumn extends Column { }, ariaLabel: localize('whenContextInputAriaLabel', "Type when context. Press Enter to confirm or Escape to cancel.") }); - this._register(attachInputBoxStyler(this.whenInput, this.themeService)); - this._register(DOM.addStandardDisposableListener(this.whenInput.inputElement, DOM.EventType.KEY_DOWN, e => this.onInputKeyDown(e))); - this._register(DOM.addDisposableListener(this.whenInput.inputElement, DOM.EventType.BLUR, () => this.cancelEditing())); - } - private onInputKeyDown(e: IKeyboardEvent): void { - let handled = false; - if (e.equals(KeyCode.Enter)) { - this.finishEditing(); - handled = true; - } else if (e.equals(KeyCode.Escape)) { - this.cancelEditing(); - handled = true; - } - if (handled) { - e.preventDefault(); - e.stopPropagation(); - } - } + const disposables = new DisposableStore(); + disposables.add(attachInputBoxStyler(whenInput, this.themeService)); - private startEditing(): void { - this.element.classList.add('input-mode'); - this.whenInput.focus(); - this.whenInput.select(); - } + const _onDidAccept: Emitter = disposables.add(new Emitter()); + const onDidAccept: Event = _onDidAccept.event; - private finishEditing(): void { - this.element.classList.remove('input-mode'); - this._onDidAccept.fire(); - } + const _onDidReject: Emitter = disposables.add(new Emitter()); + const onDidReject: Event = _onDidReject.event; - private cancelEditing(): void { - this.element.classList.remove('input-mode'); - this._onDidReject.fire(); - } - - render(keybindingItemEntry: IKeybindingItemEntry): void { - this.renderDisposables.clear(); - DOM.clearNode(this.whenLabel); - - this.keybindingsEditor.onDefineWhenExpression(e => { - if (keybindingItemEntry === e) { - this.startEditing(); + disposables.add(DOM.addStandardDisposableListener(whenInput.inputElement, DOM.EventType.KEY_DOWN, e => { + let handled = false; + if (e.equals(KeyCode.Enter)) { + element.classList.remove('input-mode'); + _onDidAccept.fire(); + handled = true; + } else if (e.equals(KeyCode.Escape)) { + element.classList.remove('input-mode'); + _onDidReject.fire(); + handled = true; } - }, this, this.renderDisposables); - this.whenInput.value = keybindingItemEntry.keybindingItem.when || ''; - this.whenLabel.classList.toggle('code', !!keybindingItemEntry.keybindingItem.when); - this.whenLabel.classList.toggle('empty', !keybindingItemEntry.keybindingItem.when); + if (handled) { + e.preventDefault(); + e.stopPropagation(); + } + })); + disposables.add((DOM.addDisposableListener(whenInput.inputElement, DOM.EventType.BLUR, () => { + element.classList.remove('input-mode'); + _onDidReject.fire(); + }))); + + const renderDisposables = disposables.add(new DisposableStore()); + + return { + element, + whenContainer, + whenLabel, + whenInput, + onDidAccept, + onDidReject, + renderDisposables, + disposables, + }; + } + + renderElement(keybindingItemEntry: IKeybindingItemEntry, index: number, templateData: IWhenColumnTemplateData, height: number | undefined): void { + templateData.renderDisposables.clear(); + + templateData.renderDisposables.add(this.keybindingsEditor.onDefineWhenExpression(e => { + if (keybindingItemEntry === e) { + templateData.element.classList.add('input-mode'); + templateData.whenInput.focus(); + templateData.whenInput.select(); + } + })); + + templateData.whenInput.value = keybindingItemEntry.keybindingItem.when || ''; + templateData.whenContainer.classList.toggle('code', !!keybindingItemEntry.keybindingItem.when); + templateData.whenContainer.classList.toggle('empty', !keybindingItemEntry.keybindingItem.when); + if (keybindingItemEntry.keybindingItem.when) { - const whenLabel = new HighlightedLabel(this.whenLabel, false); - whenLabel.set(keybindingItemEntry.keybindingItem.when, keybindingItemEntry.whenMatches); - this.element.title = keybindingItemEntry.keybindingItem.when; - whenLabel.element.title = keybindingItemEntry.keybindingItem.when; + templateData.whenLabel.set(keybindingItemEntry.keybindingItem.when, keybindingItemEntry.whenMatches); + templateData.whenLabel.element.title = keybindingItemEntry.keybindingItem.when; + templateData.element.title = keybindingItemEntry.keybindingItem.when; } else { - this.whenLabel.textContent = '—'; - this.element.title = ''; + templateData.whenLabel.set('-'); + templateData.whenLabel.element.title = ''; + templateData.element.title = ''; } - this.onDidAccept(() => { - this.keybindingsEditor.updateKeybinding(keybindingItemEntry, keybindingItemEntry.keybindingItem.keybinding ? keybindingItemEntry.keybindingItem.keybinding.getUserSettingsLabel() || '' : '', this.whenInput.value); + + templateData.renderDisposables.add(templateData.onDidAccept(() => { + this.keybindingsEditor.updateKeybinding(keybindingItemEntry, keybindingItemEntry.keybindingItem.keybinding ? keybindingItemEntry.keybindingItem.keybinding.getUserSettingsLabel() || '' : '', templateData.whenInput.value); this.keybindingsEditor.selectKeybinding(keybindingItemEntry); - }, this, this.renderDisposables); - this.onDidReject(() => { - this.whenInput.value = keybindingItemEntry.keybindingItem.when || ''; + })); + + templateData.renderDisposables.add(templateData.onDidReject(() => { + templateData.whenInput.value = keybindingItemEntry.keybindingItem.when || ''; this.keybindingsEditor.selectKeybinding(keybindingItemEntry); - }, this, this.renderDisposables); + })); + } + + disposeTemplate(templateData: IWhenColumnTemplateData): void { + templateData.disposables.dispose(); + templateData.renderDisposables.dispose(); } } @@ -1165,68 +1150,64 @@ class AccessibilityProvider implements IListAccessibilityProvider { - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-header { background-color: ${oddRowBackgroundColor}; }`); - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row.odd:not(.focused):not(.selected):not(:hover) { background-color: ${oddRowBackgroundColor}; }`); - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list:not(:focus) .monaco-list-row.focused.odd:not(.selected):not(:hover) { background-color: ${oddRowBackgroundColor}; }`); - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list:not(.focused) .monaco-list-row.focused.odd:not(.selected):not(:hover) { background-color: ${oddRowBackgroundColor}; }`); + collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table .monaco-table-th { background-color: ${evenRowBackgroundColor}; }`); + collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table .monaco-list-row:nth-child(even):not(.focused):not(.selected):not(:hover) .monaco-table-tr { background-color: ${evenRowBackgroundColor}; }`); + collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table .monaco-list:not(:focus) .monaco-list-row:nth-child(even).focused:not(.selected):not(:hover) .monaco-table-tr { background-color: ${evenRowBackgroundColor}; }`); + collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table .monaco-list:not(.focused) .monaco-list-row:nth-child(even).focused:not(.selected):not(:hover) .monaco-table-tr { background-color: ${evenRowBackgroundColor}; }`); const foregroundColor = theme.getColor(foreground); if (foregroundColor) { const whenForegroundColor = foregroundColor.transparent(.8).makeOpaque(WORKBENCH_BACKGROUND(theme)); - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column > .code { color: ${whenForegroundColor}; }`); - const whenForegroundColorForOddRow = foregroundColor.transparent(.8).makeOpaque(oddRowBackgroundColor); - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row.odd > .column > .code { color: ${whenForegroundColorForOddRow}; }`); + collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table .monaco-table-tr .monaco-table-td .code { color: ${whenForegroundColor}; }`); + const whenForegroundColorForEvenRow = foregroundColor.transparent(.8).makeOpaque(evenRowBackgroundColor); + collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table .monaco-list-row:nth-child(even) .monaco-table-tr .monaco-table-td .code { color: ${whenForegroundColorForEvenRow}; }`); } const listActiveSelectionForegroundColor = theme.getColor(listActiveSelectionForeground); const listActiveSelectionBackgroundColor = theme.getColor(listActiveSelectionBackground); if (listActiveSelectionForegroundColor && listActiveSelectionBackgroundColor) { const whenForegroundColor = listActiveSelectionForegroundColor.transparent(.8).makeOpaque(listActiveSelectionBackgroundColor); - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list:focus .monaco-list-row.selected > .column > .code { color: ${whenForegroundColor}; }`); - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list:focus .monaco-list-row.odd.selected > .column > .code { color: ${whenForegroundColor}; }`); + collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table.focused .monaco-list-row.selected .monaco-table-tr .monaco-table-td .code { color: ${whenForegroundColor}; }`); } const listInactiveSelectionForegroundColor = theme.getColor(listInactiveSelectionForeground); const listInactiveSelectionBackgroundColor = theme.getColor(listInactiveSelectionBackground); if (listInactiveSelectionForegroundColor && listInactiveSelectionBackgroundColor) { const whenForegroundColor = listInactiveSelectionForegroundColor.transparent(.8).makeOpaque(listInactiveSelectionBackgroundColor); - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list .monaco-list-row.selected > .column > .code { color: ${whenForegroundColor}; }`); - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list .monaco-list-row.odd.selected > .column > .code { color: ${whenForegroundColor}; }`); + collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table .monaco-list-row.selected .monaco-table-tr .monaco-table-td .code { color: ${whenForegroundColor}; }`); } const listFocusForegroundColor = theme.getColor(listFocusForeground); const listFocusBackgroundColor = theme.getColor(listFocusBackground); if (listFocusForegroundColor && listFocusBackgroundColor) { const whenForegroundColor = listFocusForegroundColor.transparent(.8).makeOpaque(listFocusBackgroundColor); - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list:focus .monaco-list-row.focused > .column > .code { color: ${whenForegroundColor}; }`); - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list:focus .monaco-list-row.odd.focused > .column > .code { color: ${whenForegroundColor}; }`); + collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table.focused .monaco-list-row.focused .monaco-table-tr .monaco-table-td .code { color: ${whenForegroundColor}; }`); } const listHoverForegroundColor = theme.getColor(listHoverForeground); const listHoverBackgroundColor = theme.getColor(listHoverBackground); if (listHoverForegroundColor && listHoverBackgroundColor) { const whenForegroundColor = listHoverForegroundColor.transparent(.8).makeOpaque(listHoverBackgroundColor); - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list:focus .monaco-list-row:hover:not(.focused):not(.selected) > .column > .code { color: ${whenForegroundColor}; }`); - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list:focus .monaco-list-row.odd:hover:not(.focused):not(.selected) > .column > .code { color: ${whenForegroundColor}; }`); + collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table.focused .monaco-list-row:hover:not(.focused):not(.selected) .monaco-table-tr .monaco-table-td .code { color: ${whenForegroundColor}; }`); } const listHighlightForegroundColor = theme.getColor(listHighlightForeground); if (listHighlightForegroundColor) { - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column .highlight { color: ${listHighlightForegroundColor}; }`); + collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table .monaco-table-tr .monaco-table-td .highlight { color: ${listHighlightForegroundColor}; }`); } if (listActiveSelectionForegroundColor) { - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list:focus .monaco-list-row.selected.focused > .column .monaco-keybinding-key { color: ${listActiveSelectionForegroundColor}; }`); - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list:focus .monaco-list-row.selected > .column .monaco-keybinding-key { color: ${listActiveSelectionForegroundColor}; }`); + collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table.focused .monaco-list-row.selected.focused .monaco-table-tr .monaco-table-td .monaco-keybinding-key { color: ${listActiveSelectionForegroundColor}; }`); + collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table.focused .monaco-list-row.selected .monaco-table-tr .monaco-table-td .monaco-keybinding-key { color: ${listActiveSelectionForegroundColor}; }`); } const listInactiveFocusAndSelectionForegroundColor = theme.getColor(listInactiveSelectionForeground); if (listInactiveFocusAndSelectionForegroundColor) { - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list .monaco-list-row.selected > .column .monaco-keybinding-key { color: ${listInactiveFocusAndSelectionForegroundColor}; }`); + collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table .monaco-list-row.selected .monaco-table-tr .monaco-table-td .monaco-keybinding-key { color: ${listInactiveFocusAndSelectionForegroundColor}; }`); } if (listHoverForegroundColor) { - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list .monaco-list-row:hover:not(.selected):not(.focused) > .column .monaco-keybinding-key { color: ${listHoverForegroundColor}; }`); + collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table .monaco-list-row:hover:not(.selected):not(.focused) .monaco-table-tr .monaco-table-td .monaco-keybinding-key { color: ${listHoverForegroundColor}; }`); } if (listFocusForegroundColor) { - collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list .monaco-list-row.focused > .column .monaco-keybinding-key { color: ${listFocusForegroundColor}; }`); + collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table .monaco-list-row.focused .monaco-table-tr .monaco-table-td .monaco-keybinding-key { color: ${listFocusForegroundColor}; }`); } }); diff --git a/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css b/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css index 54ad28fd56e..fc06ede873e 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css +++ b/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css @@ -69,110 +69,123 @@ opacity: 1; } -/** List based styling **/ +/** Table styling **/ -.keybindings-editor > .keybindings-body > .keybindings-list-header, -.keybindings-editor > .keybindings-body .keybindings-list-container { +.keybindings-editor > .keybindings-body .keybindings-table-container { width: 100%; border-spacing: 0; border-collapse: separate; } -.keybindings-editor > .keybindings-body > .keybindings-list-header, -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row { +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr { cursor: default; - display: flex; } -.keybindings-editor > .keybindings-body > .keybindings-list-header > .header { - text-align: left; - font-weight: bold; -} - -.keybindings-editor > .keybindings-body > .keybindings-list-header > .header, -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .column { +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td { align-items: center; display: flex; overflow: hidden; } -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .command.vertical-align-column { +/** Actions column styling **/ + +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .actions .monaco-action-bar { + display: none; + flex: 1; +} + +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-list-row.selected .monaco-table-tr .monaco-table-td .actions .monaco-action-bar, +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table.focused .monaco-list-row.focused .monaco-table-tr .monaco-table-td .actions .monaco-action-bar, +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-list-row:hover .monaco-table-tr .monaco-table-td .actions .monaco-action-bar { + display: flex; +} + +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .monaco-action-bar .action-item > .icon { + width:16px; + height: 16px; + cursor: pointer; + margin-top: 3px; +} + +/** Command column styling **/ + +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .command .hide { + display: none; +} + +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .command.vertical-align-column { flex-direction: column; align-items: flex-start; justify-content: center; } -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .command .command-default-label { +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .command .command-default-label { opacity: 0.8; margin-top: 2px; } -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .keybinding .monaco-highlighted-label { +/** Keybinding column styling **/ + +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .keybinding .monaco-highlighted-label { padding-left: 10px; } -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when .empty { +/** When column styling **/ + +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .when { + width: 100%; +} + +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .when .empty { padding-left: 4px; } -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when:not(.input-mode) .monaco-inputbox, -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when.input-mode .when-label { +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .when:not(.input-mode) .monaco-inputbox, +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .when.input-mode .when-label { display: none; } -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when .monaco-inputbox { - width: 100%; +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .when .monaco-inputbox { line-height: normal; + margin-right: 10px; } -.monaco-workbench.mac .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when .monaco-inputbox, -.monaco-workbench.mac .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when .monaco-inputbox { +.monaco-workbench.mac .keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .when .monaco-inputbox, +.monaco-workbench.mac .keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .when .monaco-inputbox { height: 24px; } -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .command .monaco-highlighted-label, -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .source .monaco-highlighted-label, -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .when .monaco-highlighted-label { +/** columns styling **/ + +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .command, +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .command > .command-label, +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .command > .command-default-label, +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .command > .command-id-label, +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .command .monaco-highlighted-label, +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .source .monaco-highlighted-label, +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .when .monaco-highlighted-label { overflow: hidden; text-overflow: ellipsis; } -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column > .code { +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .code { font-family: var(--monaco-monospace-font); font-size: 90%; display: flex; overflow: hidden; } -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column > .code.strong { +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .code.strong { padding: 1px 4px; background-color: rgba(128, 128, 128, 0.17); border-radius: 4px; } -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column .highlight { +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .highlight { font-weight: bold; } -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list:focus .monaco-list-row.selected > .column .highlight, -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list:focus .monaco-list-row.selected.focused > .column .highlight { +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table.focused .monaco-list-row.selected .monaco-table-td .highlight, +.keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table.focused .monaco-list-row.selected.focused .monaco-table-td .highlight { color: inherit; } - -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column.actions .monaco-action-bar { - display: none; - flex: 1; -} - -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row.selected > .column.actions .monaco-action-bar, -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list.focused .monaco-list-row.focused > .column.actions .monaco-action-bar, -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row:hover > .column.actions .monaco-action-bar { - display: flex; -} - -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column .monaco-action-bar .action-item > .icon { - width:16px; - height: 16px; - cursor: pointer; - margin-top: 3px; -} diff --git a/test/automation/src/keybindings.ts b/test/automation/src/keybindings.ts index 4978ad09cd4..0bda12388ea 100644 --- a/test/automation/src/keybindings.ts +++ b/test/automation/src/keybindings.ts @@ -22,13 +22,13 @@ export class KeybindingsEditor { await this.code.waitForSetValue(SEARCH_INPUT, `@command:${command}`); const commandTitle = commandName ? `${commandName} (${command})` : command; - await this.code.waitAndClick(`.keybindings-list-container .monaco-list-row.keybinding-item .command span.monaco-highlighted-label[title="${commandTitle}"]`); - await this.code.waitForElement(`.keybindings-list-container .monaco-list-row.keybinding-item.focused.selected .command span.monaco-highlighted-label[title="${commandTitle}"]`); + await this.code.waitAndClick(`.keybindings-table-container .monaco-list-row .command span.monaco-highlighted-label[title="${commandTitle}"]`); + await this.code.waitForElement(`.keybindings-table-container .monaco-list-row.focused.selected .command span.monaco-highlighted-label[title="${commandTitle}"]`); await this.code.dispatchKeybinding('enter'); await this.code.waitForActiveElement('.defineKeybindingWidget .monaco-inputbox input'); await this.code.dispatchKeybinding(keybinding); await this.code.dispatchKeybinding('enter'); - await this.code.waitForElement(`.keybindings-list-container .keybinding-label div[title="${keybindingTitle}"]`); + await this.code.waitForElement(`.keybindings-table-container .keybinding-label div[title="${keybindingTitle}"]`); } }