Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add markdown cell toolbar entry for run in section #234387

Merged
merged 2 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading