Skip to content

Commit

Permalink
Add markdown cell toolbar entry for run in section (#234387)
Browse files Browse the repository at this point in the history
* add markdown cell toolbar entry for run in section

* remove unnecesasry context key and
  • Loading branch information
Yoyokrazy authored Nov 21, 2024
1 parent 927f53d commit d94c69f
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import { Action2, IMenu, IMenuService, MenuId, MenuItemAction, MenuRegistry, reg
import { ContextKeyExpr, IContextKeyService, RawContextKey } from '../../../../../../platform/contextkey/common/contextkey.js';
import { MenuEntryActionViewItem, getActionBarActions } from '../../../../../../platform/actions/browser/menuEntryActionViewItem.js';
import { IAction } from '../../../../../../base/common/actions.js';
import { NotebookSectionArgs } from '../../controller/sectionActions.js';
import { NotebookOutlineEntryArgs } from '../../controller/sectionActions.js';
import { MarkupCellViewModel } from '../../viewModel/markupCellViewModel.js';
import { Delayer, disposableTimeout } from '../../../../../../base/common/async.js';
import { IOutlinePane } from '../../../../outline/browser/outline.js';
Expand Down Expand Up @@ -153,8 +153,12 @@ class NotebookOutlineRenderer implements ITreeRenderer<OutlineEntry, FuzzyScore,
}

if (this._target === OutlineTarget.OutlinePane) {
if (!this._editor) {
return;
}

const nbCell = node.element.cell;
const nbViewModel = this._editor?.getViewModel();
const nbViewModel = this._editor.getViewModel();
if (!nbViewModel) {
return;
}
Expand All @@ -181,7 +185,7 @@ class NotebookOutlineRenderer implements ITreeRenderer<OutlineEntry, FuzzyScore,
const actions = getOutlineToolbarActions(menu, { notebookEditor: this._editor, outlineEntry: node.element });
outlineEntryToolbar.setActions(actions.primary, actions.secondary);

this.setupToolbarListeners(outlineEntryToolbar, menu, actions, node.element, template);
this.setupToolbarListeners(this._editor, outlineEntryToolbar, menu, actions, node.element, template);
template.actionMenu.style.padding = '0 0.8em 0 0.4em';
}
}
Expand Down Expand Up @@ -210,21 +214,21 @@ class NotebookOutlineRenderer implements ITreeRenderer<OutlineEntry, FuzzyScore,
}
}

private setupToolbarListeners(toolbar: ToolBar, menu: IMenu, initActions: { primary: IAction[]; secondary: IAction[] }, entry: OutlineEntry, templateData: NotebookOutlineTemplate): void {
private setupToolbarListeners(editor: INotebookEditor, toolbar: ToolBar, menu: IMenu, initActions: { primary: IAction[]; secondary: IAction[] }, entry: OutlineEntry, templateData: NotebookOutlineTemplate): void {
// same fix as in cellToolbars setupListeners re #103926
let dropdownIsVisible = false;
let deferredUpdate: (() => void) | undefined;

toolbar.setActions(initActions.primary, initActions.secondary);
templateData.elementDisposables.add(menu.onDidChange(() => {
if (dropdownIsVisible) {
const actions = getOutlineToolbarActions(menu, { notebookEditor: this._editor, outlineEntry: entry });
const actions = getOutlineToolbarActions(menu, { notebookEditor: editor, outlineEntry: entry });
deferredUpdate = () => toolbar.setActions(actions.primary, actions.secondary);

return;
}

const actions = getOutlineToolbarActions(menu, { notebookEditor: this._editor, outlineEntry: entry });
const actions = getOutlineToolbarActions(menu, { notebookEditor: editor, outlineEntry: entry });
toolbar.setActions(actions.primary, actions.secondary);
}));

Expand All @@ -249,9 +253,8 @@ class NotebookOutlineRenderer implements ITreeRenderer<OutlineEntry, FuzzyScore,
}
}

function getOutlineToolbarActions(menu: IMenu, args?: NotebookSectionArgs): { primary: IAction[]; secondary: IAction[] } {
// TODO: @Yoyokrazy bring the "inline" back when there's an appropriate run in section icon
return getActionBarActions(menu.getActions({ shouldForwardArgs: true, arg: args })); //, g => /^inline/.test(g));
function getOutlineToolbarActions(menu: IMenu, args?: NotebookOutlineEntryArgs): { primary: IAction[]; secondary: IAction[] } {
return getActionBarActions(menu.getActions({ shouldForwardArgs: true, arg: args }), g => /^inline/.test(g));
}

class NotebookOutlineAccessibility implements IListAccessibilityProvider<OutlineEntry> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const NOTEBOOK_EDITOR_WIDGET_ACTION_WEIGHT = KeybindingWeight.EditorContr
export const NOTEBOOK_OUTPUT_WEBVIEW_ACTION_WEIGHT = KeybindingWeight.WorkbenchContrib + 1; // higher than Workbench contribution (such as Notebook List View), etc

export const enum CellToolbarOrder {
RunSection,
EditCell,
ExecuteAboveCells,
ExecuteCellAndBelow,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ export const executeThisCellCondition = ContextKeyExpr.and(
executeCondition,
NOTEBOOK_CELL_EXECUTING.toNegated());

export const executeSectionCondition = ContextKeyExpr.and(
NOTEBOOK_CELL_TYPE.isEqualTo('markup'),
);

function renderAllMarkdownCells(context: INotebookActionContext): void {
for (let i = 0; i < context.notebookEditor.getLength(); i++) {
const cell = context.notebookEditor.cellAt(i);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,22 @@ import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contex
import { ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js';
import { NotebookOutlineContext } from '../contrib/outline/notebookOutline.js';
import { FoldingController } from './foldingController.js';
import { CellFoldingState, INotebookEditor } from '../notebookBrowser.js';
import { CellFoldingState, ICellViewModel, INotebookEditor } from '../notebookBrowser.js';
import * as icons from '../notebookIcons.js';
import { OutlineEntry } from '../viewModel/OutlineEntry.js';
import { CellKind } from '../../common/notebookCommon.js';
import { OutlineTarget } from '../../../../services/outline/browser/outline.js';
import { CELL_TITLE_CELL_GROUP_ID, CellToolbarOrder } from './coreActions.js';
import { executeSectionCondition } from './executeActions.js';

export type NotebookSectionArgs = {
notebookEditor: INotebookEditor | undefined;
export type NotebookOutlineEntryArgs = {
notebookEditor: INotebookEditor;
outlineEntry: OutlineEntry;
};

export type ValidNotebookSectionArgs = {
export type NotebookCellArgs = {
notebookEditor: INotebookEditor;
outlineEntry: OutlineEntry;
cell: ICellViewModel;
};

export class NotebookRunSingleCellInSection extends Action2 {
Expand Down Expand Up @@ -51,8 +53,8 @@ export class NotebookRunSingleCellInSection extends Action2 {
});
}

override async run(_accessor: ServicesAccessor, context: NotebookSectionArgs): Promise<void> {
if (!checkSectionContext(context)) {
override async run(_accessor: ServicesAccessor, context: any): Promise<void> {
if (!checkOutlineEntryContext(context)) {
return;
}

Expand All @@ -69,7 +71,7 @@ export class NotebookRunCellsInSection extends Action2 {
mnemonicTitle: localize({ key: 'mirunCellsInSection', comment: ['&& denotes a mnemonic'] }, "&&Run Cells In Section"),
},
shortTitle: localize('runCellsInSection', "Run Cells In Section"),
// icon: icons.executeBelowIcon, // TODO @Yoyokrazy replace this with new icon later
icon: icons.executeIcon, // TODO @Yoyokrazy replace this with new icon later
menu: [
{
id: MenuId.NotebookStickyScrollContext,
Expand All @@ -86,17 +88,27 @@ export class NotebookRunCellsInSection extends Action2 {
NotebookOutlineContext.CellHasChildren,
NotebookOutlineContext.CellHasHeader,
)
},
{
id: MenuId.NotebookCellTitle,
order: CellToolbarOrder.RunSection,
group: CELL_TITLE_CELL_GROUP_ID,
when: executeSectionCondition
}
]
});
}

override async run(_accessor: ServicesAccessor, context: NotebookSectionArgs): Promise<void> {
if (!checkSectionContext(context)) {
override async run(_accessor: ServicesAccessor, context: any): Promise<void> {
let cell: ICellViewModel;
if (checkOutlineEntryContext(context)) {
cell = context.outlineEntry.cell;
} else if (checkNotebookCellContext(context)) {
cell = context.cell;
} else {
return;
}

const cell = context.outlineEntry.cell;
const idx = context.notebookEditor.getViewModel()?.getCellIndex(cell);
if (idx === undefined) {
return;
Expand Down Expand Up @@ -137,8 +149,8 @@ export class NotebookFoldSection extends Action2 {
});
}

override async run(_accessor: ServicesAccessor, context: NotebookSectionArgs): Promise<void> {
if (!checkSectionContext(context)) {
override async run(_accessor: ServicesAccessor, context: any): Promise<void> {
if (!checkOutlineEntryContext(context)) {
return;
}

Expand Down Expand Up @@ -181,8 +193,8 @@ export class NotebookExpandSection extends Action2 {
});
}

override async run(_accessor: ServicesAccessor, context: NotebookSectionArgs): Promise<void> {
if (!checkSectionContext(context)) {
override async run(_accessor: ServicesAccessor, context: any): Promise<void> {
if (!checkOutlineEntryContext(context)) {
return;
}

Expand All @@ -200,15 +212,27 @@ export class NotebookExpandSection extends Action2 {
}

/**
* Take in context args and check if they exist
* Take in context args and check if they exist. True if action is run from notebook sticky scroll context menu or
* notebook outline context menu.
*
* @param context - Notebook Section Context containing a notebook editor and outline entry
* @param context - Notebook Outline Context containing a notebook editor and outline entry
* @returns true if context is valid, false otherwise
*/
function checkSectionContext(context: NotebookSectionArgs): context is ValidNotebookSectionArgs {
function checkOutlineEntryContext(context: any): context is NotebookOutlineEntryArgs {
return !!(context && context.notebookEditor && context.outlineEntry);
}

/**
* Take in context args and check if they exist. True if action is run from a cell toolbar menu (potentially from the
* notebook cell container or cell editor context menus, but not tested or implemented atm)
*
* @param context - Notebook Outline Context containing a notebook editor and outline entry
* @returns true if context is valid, false otherwise
*/
function checkNotebookCellContext(context: any): context is NotebookCellArgs {
return !!(context && context.notebookEditor && context.cell);
}

registerAction2(NotebookRunSingleCellInSection);
registerAction2(NotebookRunCellsInSection);
registerAction2(NotebookFoldSection);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { foldingCollapsedIcon, foldingExpandedIcon } from '../../../../../editor
import { MarkupCellViewModel } from '../viewModel/markupCellViewModel.js';
import { FoldingController } from '../controller/foldingController.js';
import { NotebookOptionsChangeEvent } from '../notebookOptions.js';
import { NotebookSectionArgs } from '../controller/sectionActions.js';
import { NotebookOutlineEntryArgs } from '../controller/sectionActions.js';
import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js';
import { INotebookCellOutlineDataSourceFactory } from '../viewModel/notebookOutlineDataSourceFactory.js';

Expand Down Expand Up @@ -175,7 +175,7 @@ export class NotebookStickyScroll extends Disposable {
return;
}

const args: NotebookSectionArgs = {
const args: NotebookOutlineEntryArgs = {
outlineEntry: selectedOutlineEntry,
notebookEditor: this.notebookEditor,
};
Expand Down

0 comments on commit d94c69f

Please sign in to comment.