mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 17:19:48 +01:00
Unified go to actions (#201166)
* Unified go to actions * Update for labeless and dynamic
This commit is contained in:
@@ -171,6 +171,7 @@ export class MenuId {
|
||||
static readonly NotebookCellBetween = new MenuId('NotebookCellBetween');
|
||||
static readonly NotebookCellListTop = new MenuId('NotebookCellTop');
|
||||
static readonly NotebookCellExecute = new MenuId('NotebookCellExecute');
|
||||
static readonly NotebookCellExecuteGoTo = new MenuId('NotebookCellExecuteGoTo');
|
||||
static readonly NotebookCellExecutePrimary = new MenuId('NotebookCellExecutePrimary');
|
||||
static readonly NotebookDiffCellInputTitle = new MenuId('NotebookDiffCellInputTitle');
|
||||
static readonly NotebookDiffCellMetadataTitle = new MenuId('NotebookDiffCellMetadataTitle');
|
||||
|
||||
@@ -11,7 +11,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { ILanguageService } from 'vs/editor/common/languages/language';
|
||||
import { localize } from 'vs/nls';
|
||||
import { MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -622,13 +622,21 @@ registerAction2(class InterruptNotebook extends CancelNotebook {
|
||||
});
|
||||
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.NotebookToolbar, {
|
||||
title: localize('revealRunningCellShort', "Go To"),
|
||||
submenu: MenuId.NotebookCellExecuteGoTo,
|
||||
group: 'navigation/execute',
|
||||
order: 20,
|
||||
icon: ThemeIcon.modify(icons.executingStateIcon, 'spin')
|
||||
});
|
||||
|
||||
registerAction2(class RevealRunningCellAction extends NotebookAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: REVEAL_RUNNING_CELL,
|
||||
title: localize('revealRunningCell', "Go to Running Cell"),
|
||||
tooltip: localize('revealRunningCell', "Go to Running Cell"),
|
||||
shortTitle: localize('revealRunningCellShort', "Go To"),
|
||||
shortTitle: localize('revealRunningCell', "Go to Running Cell"),
|
||||
precondition: NOTEBOOK_HAS_RUNNING_CELL,
|
||||
menu: [
|
||||
{
|
||||
@@ -642,7 +650,7 @@ registerAction2(class RevealRunningCellAction extends NotebookAction {
|
||||
order: 0
|
||||
},
|
||||
{
|
||||
id: MenuId.NotebookToolbar,
|
||||
id: MenuId.NotebookCellExecuteGoTo,
|
||||
when: ContextKeyExpr.and(
|
||||
NOTEBOOK_IS_ACTIVE_EDITOR,
|
||||
NOTEBOOK_HAS_RUNNING_CELL,
|
||||
@@ -703,7 +711,7 @@ registerAction2(class RevealLastFailedCellAction extends NotebookAction {
|
||||
id: REVEAL_LAST_FAILED_CELL,
|
||||
title: localize('revealLastFailedCell', "Go to Most Recently Failed Cell"),
|
||||
tooltip: localize('revealLastFailedCell', "Go to Most Recently Failed Cell"),
|
||||
shortTitle: localize('revealLastFailedCellShort', "Go To"),
|
||||
shortTitle: localize('revealLastFailedCellShort', "Go to Most Recently Failed Cell"),
|
||||
precondition: NOTEBOOK_LAST_CELL_FAILED,
|
||||
menu: [
|
||||
{
|
||||
@@ -718,7 +726,7 @@ registerAction2(class RevealLastFailedCellAction extends NotebookAction {
|
||||
order: 0
|
||||
},
|
||||
{
|
||||
id: MenuId.NotebookToolbar,
|
||||
id: MenuId.NotebookCellExecuteGoTo,
|
||||
when: ContextKeyExpr.and(
|
||||
NOTEBOOK_IS_ACTIVE_EDITOR,
|
||||
NOTEBOOK_LAST_CELL_FAILED,
|
||||
|
||||
@@ -5,7 +5,14 @@
|
||||
|
||||
import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IMenuEntryActionViewItemOptions, MenuEntryActionViewItem, SubmenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IActionProvider } from 'vs/base/browser/ui/dropdown/dropdown';
|
||||
import { MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { ThemeIcon } from 'vs/base/common/themables';
|
||||
|
||||
export class CodiconActionViewItem extends MenuEntryActionViewItem {
|
||||
|
||||
@@ -35,3 +42,61 @@ export class ActionViewWithLabel extends MenuEntryActionViewItem {
|
||||
}
|
||||
}
|
||||
}
|
||||
export class UnifiedSubmenuActionView extends SubmenuEntryActionViewItem {
|
||||
private _actionLabel?: HTMLAnchorElement;
|
||||
|
||||
constructor(
|
||||
action: SubmenuItemAction,
|
||||
options: IMenuEntryActionViewItemOptions | undefined,
|
||||
readonly renderLabel: boolean,
|
||||
readonly subActionProvider: IActionProvider,
|
||||
readonly subActionViewItemProvider: IActionViewItemProvider | undefined,
|
||||
@IKeybindingService _keybindingService: IKeybindingService,
|
||||
@IContextMenuService _contextMenuService: IContextMenuService,
|
||||
@IThemeService _themeService: IThemeService
|
||||
) {
|
||||
super(action, options, _keybindingService, _contextMenuService, _themeService);
|
||||
}
|
||||
|
||||
override render(container: HTMLElement): void {
|
||||
super.render(container);
|
||||
container.classList.add('notebook-action-view-item');
|
||||
this._actionLabel = document.createElement('a');
|
||||
container.appendChild(this._actionLabel);
|
||||
this.updateLabel();
|
||||
}
|
||||
|
||||
protected override updateLabel() {
|
||||
const actions = this.subActionProvider.getActions();
|
||||
if (this._actionLabel) {
|
||||
const primaryAction = actions[0];
|
||||
|
||||
if (primaryAction && primaryAction instanceof MenuItemAction) {
|
||||
const element = this.element;
|
||||
|
||||
if (element && primaryAction.item.icon && ThemeIcon.isThemeIcon(primaryAction.item.icon)) {
|
||||
const iconClasses = ThemeIcon.asClassNameArray(primaryAction.item.icon);
|
||||
// remove all classes started with 'codicon-'
|
||||
element.classList.forEach((cl) => {
|
||||
if (cl.startsWith('codicon-')) {
|
||||
element.classList.remove(cl);
|
||||
}
|
||||
});
|
||||
element.classList.add(...iconClasses);
|
||||
}
|
||||
|
||||
if (this.renderLabel) {
|
||||
this._actionLabel.classList.add('notebook-label');
|
||||
this._actionLabel.innerText = this._action.label;
|
||||
this._actionLabel.title = primaryAction.tooltip.length ? primaryAction.tooltip : primaryAction.label;
|
||||
}
|
||||
} else {
|
||||
if (this.renderLabel) {
|
||||
this._actionLabel.classList.add('notebook-label');
|
||||
this._actionLabel.innerText = this._action.label;
|
||||
this._actionLabel.title = this._action.tooltip.length ? this._action.tooltip : this._action.label;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { IAction, Separator } from 'vs/base/common/actions';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { MenuEntryActionViewItem, SubmenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IMenu, IMenuService, MenuId, MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -21,13 +21,12 @@ import { SELECT_KERNEL_ID } from 'vs/workbench/contrib/notebook/browser/controll
|
||||
import { NOTEBOOK_EDITOR_ID, NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { INotebookEditorDelegate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { NotebooKernelActionViewItem } from 'vs/workbench/contrib/notebook/browser/viewParts/notebookKernelView';
|
||||
import { ActionViewWithLabel } from 'vs/workbench/contrib/notebook/browser/view/cellParts/cellActionView';
|
||||
import { ActionViewWithLabel, UnifiedSubmenuActionView } from 'vs/workbench/contrib/notebook/browser/view/cellParts/cellActionView';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IWorkbenchAssignmentService } from 'vs/workbench/services/assignment/common/assignmentService';
|
||||
import { NotebookOptions } from 'vs/workbench/contrib/notebook/browser/notebookOptions';
|
||||
import { IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IActionViewItem, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { disposableTimeout } from 'vs/base/common/async';
|
||||
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
|
||||
import { HiddenItemStrategy, IWorkbenchToolBarOptions, WorkbenchToolBar } from 'vs/platform/actions/browser/toolbar';
|
||||
|
||||
interface IActionModel {
|
||||
@@ -73,15 +72,28 @@ class WorkbenchAlwaysLabelStrategy implements IActionLayoutStrategy {
|
||||
constructor(
|
||||
readonly notebookEditor: INotebookEditorDelegate,
|
||||
readonly editorToolbar: NotebookEditorWorkbenchToolbar,
|
||||
readonly goToMenu: IMenu,
|
||||
readonly instantiationService: IInstantiationService) { }
|
||||
|
||||
actionProvider(action: IAction): ActionViewItem | undefined {
|
||||
actionProvider(action: IAction): IActionViewItem | undefined {
|
||||
if (action.id === SELECT_KERNEL_ID) {
|
||||
// this is being disposed by the consumer
|
||||
return this.instantiationService.createInstance(NotebooKernelActionViewItem, action, this.notebookEditor);
|
||||
}
|
||||
|
||||
return action instanceof MenuItemAction ? this.instantiationService.createInstance(ActionViewWithLabel, action, undefined) : undefined;
|
||||
if (action instanceof MenuItemAction) {
|
||||
return this.instantiationService.createInstance(ActionViewWithLabel, action, undefined);
|
||||
}
|
||||
|
||||
if (action instanceof SubmenuItemAction && action.item.submenu.id === MenuId.NotebookCellExecuteGoTo.id) {
|
||||
return this.instantiationService.createInstance(UnifiedSubmenuActionView, action, undefined, true, {
|
||||
getActions: () => {
|
||||
return this.goToMenu.getActions().find(([group]) => group === 'navigation/execute')?.[1] ?? [];
|
||||
}
|
||||
}, this.actionProvider.bind(this));
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
calculateActions(leftToolbarContainerMaxWidth: number): { primaryActions: IAction[]; secondaryActions: IAction[] } {
|
||||
@@ -100,15 +112,32 @@ class WorkbenchNeverLabelStrategy implements IActionLayoutStrategy {
|
||||
constructor(
|
||||
readonly notebookEditor: INotebookEditorDelegate,
|
||||
readonly editorToolbar: NotebookEditorWorkbenchToolbar,
|
||||
readonly goToMenu: IMenu,
|
||||
readonly instantiationService: IInstantiationService) { }
|
||||
|
||||
actionProvider(action: IAction): ActionViewItem | undefined {
|
||||
actionProvider(action: IAction): IActionViewItem | undefined {
|
||||
if (action.id === SELECT_KERNEL_ID) {
|
||||
// this is being disposed by the consumer
|
||||
return this.instantiationService.createInstance(NotebooKernelActionViewItem, action, this.notebookEditor);
|
||||
}
|
||||
|
||||
return action instanceof MenuItemAction ? this.instantiationService.createInstance(MenuEntryActionViewItem, action, undefined) : undefined;
|
||||
if (action instanceof MenuItemAction) {
|
||||
return this.instantiationService.createInstance(MenuEntryActionViewItem, action, undefined);
|
||||
}
|
||||
|
||||
if (action instanceof SubmenuItemAction) {
|
||||
if (action.item.submenu.id === MenuId.NotebookCellExecuteGoTo.id) {
|
||||
return this.instantiationService.createInstance(UnifiedSubmenuActionView, action, undefined, false, {
|
||||
getActions: () => {
|
||||
return this.goToMenu.getActions().find(([group]) => group === 'navigation/execute')?.[1] ?? [];
|
||||
}
|
||||
}, this.actionProvider.bind(this));
|
||||
} else {
|
||||
return this.instantiationService.createInstance(SubmenuEntryActionViewItem, action, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
calculateActions(leftToolbarContainerMaxWidth: number): { primaryActions: IAction[]; secondaryActions: IAction[] } {
|
||||
@@ -127,9 +156,10 @@ class WorkbenchDynamicLabelStrategy implements IActionLayoutStrategy {
|
||||
constructor(
|
||||
readonly notebookEditor: INotebookEditorDelegate,
|
||||
readonly editorToolbar: NotebookEditorWorkbenchToolbar,
|
||||
readonly goToMenu: IMenu,
|
||||
readonly instantiationService: IInstantiationService) { }
|
||||
|
||||
actionProvider(action: IAction): ActionViewItem | undefined {
|
||||
actionProvider(action: IAction): IActionViewItem | undefined {
|
||||
if (action.id === SELECT_KERNEL_ID) {
|
||||
// this is being disposed by the consumer
|
||||
return this.instantiationService.createInstance(NotebooKernelActionViewItem, action, this.notebookEditor);
|
||||
@@ -137,9 +167,37 @@ class WorkbenchDynamicLabelStrategy implements IActionLayoutStrategy {
|
||||
|
||||
const a = this.editorToolbar.primaryActions.find(a => a.action.id === action.id);
|
||||
if (!a || a.renderLabel) {
|
||||
return action instanceof MenuItemAction ? this.instantiationService.createInstance(ActionViewWithLabel, action, undefined) : undefined;
|
||||
if (action instanceof MenuItemAction) {
|
||||
return this.instantiationService.createInstance(ActionViewWithLabel, action, undefined);
|
||||
}
|
||||
|
||||
if (action instanceof SubmenuItemAction && action.item.submenu.id === MenuId.NotebookCellExecuteGoTo.id) {
|
||||
return this.instantiationService.createInstance(UnifiedSubmenuActionView, action, undefined, true, {
|
||||
getActions: () => {
|
||||
return this.goToMenu.getActions().find(([group]) => group === 'navigation/execute')?.[1] ?? [];
|
||||
}
|
||||
}, this.actionProvider.bind(this));
|
||||
}
|
||||
|
||||
return undefined;
|
||||
} else {
|
||||
return action instanceof MenuItemAction ? this.instantiationService.createInstance(MenuEntryActionViewItem, action, undefined) : undefined;
|
||||
if (action instanceof MenuItemAction) {
|
||||
this.instantiationService.createInstance(MenuEntryActionViewItem, action, undefined);
|
||||
}
|
||||
|
||||
if (action instanceof SubmenuItemAction) {
|
||||
if (action.item.submenu.id === MenuId.NotebookCellExecuteGoTo.id) {
|
||||
return this.instantiationService.createInstance(UnifiedSubmenuActionView, action, undefined, false, {
|
||||
getActions: () => {
|
||||
return this.goToMenu.getActions().find(([group]) => group === 'navigation/execute')?.[1] ?? [];
|
||||
}
|
||||
}, this.actionProvider.bind(this));
|
||||
} else {
|
||||
return this.instantiationService.createInstance(SubmenuEntryActionViewItem, action, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,6 +218,7 @@ export class NotebookEditorWorkbenchToolbar extends Disposable {
|
||||
private _notebookTopLeftToolbarContainer!: HTMLElement;
|
||||
private _notebookTopRightToolbarContainer!: HTMLElement;
|
||||
private _notebookGlobalActionsMenu!: IMenu;
|
||||
private _executeGoToActionsMenu!: IMenu;
|
||||
private _notebookLeftToolbar!: WorkbenchToolBar;
|
||||
private _primaryActions: IActionModel[];
|
||||
get primaryActions(): IActionModel[] {
|
||||
@@ -251,7 +310,7 @@ export class NotebookEditorWorkbenchToolbar extends Disposable {
|
||||
|
||||
private _registerNotebookActionsToolbar() {
|
||||
this._notebookGlobalActionsMenu = this._register(this.menuService.createMenu(this.notebookEditor.creationOptions.menuIds.notebookToolbar, this.contextKeyService));
|
||||
this._register(this._notebookGlobalActionsMenu);
|
||||
this._executeGoToActionsMenu = this._register(this.menuService.createMenu(MenuId.NotebookCellExecuteGoTo, this.contextKeyService));
|
||||
|
||||
this._useGlobalToolbar = this.notebookOptions.getDisplayOptions().globalToolbar;
|
||||
this._renderLabel = this._convertConfiguration(this.configurationService.getValue(NotebookSetting.globalToolbarShowLabel));
|
||||
@@ -379,13 +438,13 @@ export class NotebookEditorWorkbenchToolbar extends Disposable {
|
||||
private _updateStrategy() {
|
||||
switch (this._renderLabel) {
|
||||
case RenderLabel.Always:
|
||||
this._strategy = new WorkbenchAlwaysLabelStrategy(this.notebookEditor, this, this.instantiationService);
|
||||
this._strategy = new WorkbenchAlwaysLabelStrategy(this.notebookEditor, this, this._executeGoToActionsMenu, this.instantiationService);
|
||||
break;
|
||||
case RenderLabel.Never:
|
||||
this._strategy = new WorkbenchNeverLabelStrategy(this.notebookEditor, this, this.instantiationService);
|
||||
this._strategy = new WorkbenchNeverLabelStrategy(this.notebookEditor, this, this._executeGoToActionsMenu, this.instantiationService);
|
||||
break;
|
||||
case RenderLabel.Dynamic:
|
||||
this._strategy = new WorkbenchDynamicLabelStrategy(this.notebookEditor, this, this.instantiationService);
|
||||
this._strategy = new WorkbenchDynamicLabelStrategy(this.notebookEditor, this, this._executeGoToActionsMenu, this.instantiationService);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user