diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index d51c30ccc50f1..a7087c66a5dc8 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -183,6 +183,7 @@ export class MenuId { static readonly NotebookDiffCellMetadataTitle = new MenuId('NotebookDiffCellMetadataTitle'); static readonly NotebookDiffCellOutputsTitle = new MenuId('NotebookDiffCellOutputsTitle'); static readonly NotebookOutputToolbar = new MenuId('NotebookOutputToolbar'); + static readonly NotebookOutlineActionMenu = new MenuId('NotebookOutlineActionMenu'); static readonly NotebookEditorLayoutConfigure = new MenuId('NotebookEditorLayoutConfigure'); static readonly NotebookKernelSource = new MenuId('NotebookKernelSource'); static readonly BulkEditTitle = new MenuId('BulkEditTitle'); diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts b/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts index 67ac4131d0d63..069f805cb0942 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; +import * as DOM from 'vs/base/browser/dom'; +import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { IIconLabelValueOptions, IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { IKeyboardNavigationLabelProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; @@ -25,7 +27,7 @@ import { listErrorForeground, listWarningForeground } from 'vs/platform/theme/co import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IEditorPane } from 'vs/workbench/common/editor'; -import { CellRevealType, ICellModelDecorations, ICellModelDeltaDecorations, INotebookEditorOptions, INotebookEditorPane } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellFoldingState, CellRevealType, ICellModelDecorations, ICellModelDeltaDecorations, ICellViewModel, INotebookEditor, INotebookEditorOptions, INotebookEditorPane, INotebookViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookEditor'; import { NotebookCellOutlineProvider } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookOutlineProvider'; import { CellKind, NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; @@ -37,7 +39,14 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { IModelDeltaDecoration } from 'vs/editor/common/model'; import { Range } from 'vs/editor/common/core/range'; import { mainWindow } from 'vs/base/browser/window'; -import { WindowIdleValue } from 'vs/base/browser/dom'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IMenu, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; +import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { MenuEntryActionViewItem, createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { IAction } from 'vs/base/common/actions'; +import { NotebookSectionArgs } from 'vs/workbench/contrib/notebook/browser/controller/sectionActions'; +import { MarkupCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel'; +import { disposableTimeout } from 'vs/base/common/async'; class NotebookOutlineTemplate { @@ -47,7 +56,9 @@ class NotebookOutlineTemplate { readonly container: HTMLElement, readonly iconClass: HTMLElement, readonly iconLabel: IconLabel, - readonly decoration: HTMLElement + readonly decoration: HTMLElement, + readonly actionMenu: HTMLElement, + readonly elementDisposables: DisposableStore, ) { } } @@ -56,11 +67,19 @@ class NotebookOutlineRenderer implements ITreeRenderer, _index: number, template: NotebookOutlineTemplate, _height: number | undefined): void { @@ -79,7 +102,8 @@ class NotebookOutlineRenderer implements ITreeRenderer 0); + NotebookOutlineContext.CellHasHeader.bindTo(scopedContextKeyService).set(node.element.level !== 7); + NotebookOutlineContext.OutlineElementTarget.bindTo(scopedContextKeyService).set(this._target); + this.setupFolding(isCodeCell, nbViewModel, scopedContextKeyService, template, nbCell); + + const outlineEntryToolbar = template.elementDisposables.add(new ToolBar(template.actionMenu, this._contextMenuService, { + actionViewItemProvider: action => { + if (action instanceof MenuItemAction) { + return this._instantiationService.createInstance(MenuEntryActionViewItem, action, undefined); + } + return undefined; + }, + })); + + const menu = template.elementDisposables.add(this._menuService.createMenu(MenuId.NotebookOutlineActionMenu, scopedContextKeyService)); + const actions = getOutlineToolbarActions(menu, { notebookEditor: this._editor, outlineEntry: node.element }); + outlineEntryToolbar.setActions(actions.primary, actions.secondary); + + this.setupToolbarListeners(outlineEntryToolbar, menu, actions, node.element, template); + } } disposeTemplate(templateData: NotebookOutlineTemplate): void { templateData.iconLabel.dispose(); + templateData.elementDisposables.clear(); + } + + disposeElement(element: ITreeNode, index: number, templateData: NotebookOutlineTemplate, height: number | undefined): void { + templateData.elementDisposables.clear(); + DOM.clearNode(templateData.actionMenu); + } + + private setupFolding(isCodeCell: boolean, nbViewModel: INotebookViewModel, scopedContextKeyService: IContextKeyService, template: NotebookOutlineTemplate, nbCell: ICellViewModel) { + const foldingState = isCodeCell ? CellFoldingState.None : ((nbCell as MarkupCellViewModel).foldingState); + const foldingStateCtx = NotebookOutlineContext.CellFoldingState.bindTo(scopedContextKeyService); + foldingStateCtx.set(foldingState); + + if (!isCodeCell) { + template.elementDisposables.add(nbViewModel.onDidFoldingStateChanged(() => { + const foldingState = (nbCell as MarkupCellViewModel).foldingState; + NotebookOutlineContext.CellFoldingState.bindTo(scopedContextKeyService).set(foldingState); + foldingStateCtx.set(foldingState); + })); + } + } + + private setupToolbarListeners(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 }); + deferredUpdate = () => toolbar.setActions(actions.primary, actions.secondary); + + return; + } + + const actions = getOutlineToolbarActions(menu, { notebookEditor: this._editor, outlineEntry: entry }); + toolbar.setActions(actions.primary, actions.secondary); + })); + + templateData.container.classList.remove('notebook-outline-toolbar-dropdown-active'); + templateData.elementDisposables.add(toolbar.onDidChangeDropdownVisibility(visible => { + dropdownIsVisible = visible; + if (visible) { + templateData.container.classList.add('notebook-outline-toolbar-dropdown-active'); + } else { + templateData.container.classList.remove('notebook-outline-toolbar-dropdown-active'); + } + + if (deferredUpdate && !visible) { + disposableTimeout(() => { + deferredUpdate?.(); + }, 0, templateData.elementDisposables); + + deferredUpdate = undefined; + } + })); + } } +function getOutlineToolbarActions(menu: IMenu, args?: NotebookSectionArgs): { primary: IAction[]; secondary: IAction[] } { + const primary: IAction[] = []; + const secondary: IAction[] = []; + const result = { primary, secondary }; + + // TODO: @Yoyokrazy bring the "inline" back when there's an appropriate run in section icon + createAndFillInActionBarActions(menu, { shouldForwardArgs: true, arg: args }, result); //, g => /^inline/.test(g)); + + return result; +} + class NotebookOutlineAccessibility implements IListAccessibilityProvider { getAriaLabel(element: OutlineEntry): string | null { return element.label; @@ -183,7 +308,7 @@ class NotebookQuickPickProvider implements IQuickPickDataSource { class NotebookComparator implements IOutlineComparator { - private readonly _collator = new WindowIdleValue(mainWindow, () => new Intl.Collator(undefined, { numeric: true })); + private readonly _collator = new DOM.WindowIdleValue(mainWindow, () => new Intl.Collator(undefined, { numeric: true })); compareByPosition(a: OutlineEntry, b: OutlineEntry): number { return a.index - b.index; @@ -251,7 +376,7 @@ export class NotebookCellOutline implements IOutline { installSelectionListener(); const treeDataSource: IDataSource = { getChildren: parent => parent instanceof NotebookCellOutline ? (this._outlineProvider?.entries ?? []) : parent.children }; const delegate = new NotebookOutlineVirtualDelegate(); - const renderers = [instantiationService.createInstance(NotebookOutlineRenderer)]; + const renderers = [instantiationService.createInstance(NotebookOutlineRenderer, this._editor.getControl(), _target)]; const comparator = new NotebookComparator(); const options: IWorkbenchDataTreeOptions = { @@ -404,8 +529,15 @@ export class NotebookOutlineCreator implements IOutlineCreator(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NotebookOutlineCreator, LifecyclePhase.Eventually); +export const NotebookOutlineContext = { + CellKind: new RawContextKey('notebookCellKind', undefined), + CellHasChildren: new RawContextKey('notebookCellHasChildren', false), + CellHasHeader: new RawContextKey('notebookCellHasHeader', false), + CellFoldingState: new RawContextKey('notebookCellFoldingState', CellFoldingState.None), + OutlineElementTarget: new RawContextKey('notebookOutlineElementTarget', undefined), +}; +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NotebookOutlineCreator, LifecyclePhase.Eventually); Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ id: 'notebook', diff --git a/src/vs/workbench/contrib/notebook/browser/controller/sectionActions.ts b/src/vs/workbench/contrib/notebook/browser/controller/sectionActions.ts new file mode 100644 index 0000000000000..b4831209b27c3 --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/controller/sectionActions.ts @@ -0,0 +1,215 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { localize, localize2 } from 'vs/nls'; +import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { NotebookOutlineContext } from 'vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline'; +import { FoldingController } from 'vs/workbench/contrib/notebook/browser/controller/foldingController'; +import { CellFoldingState, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import * as icons from 'vs/workbench/contrib/notebook/browser/notebookIcons'; +import { OutlineEntry } from 'vs/workbench/contrib/notebook/browser/viewModel/OutlineEntry'; +import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { OutlineTarget } from 'vs/workbench/services/outline/browser/outline'; + +export type NotebookSectionArgs = { + notebookEditor: INotebookEditor | undefined; + outlineEntry: OutlineEntry; +}; + +export type ValidNotebookSectionArgs = { + notebookEditor: INotebookEditor; + outlineEntry: OutlineEntry; +}; + +export class NotebookRunSingleCellInSection extends Action2 { + constructor() { + super({ + id: 'notebook.section.runSingleCell', + title: { + ...localize2('runCell', "Run Cell"), + mnemonicTitle: localize({ key: 'mirunCell', comment: ['&& denotes a mnemonic'] }, "&&Run Cell"), + }, + shortTitle: localize('runCell', "Run Cell"), + icon: icons.executeIcon, + menu: [ + { + id: MenuId.NotebookOutlineActionMenu, + group: 'inline', + order: 1, + when: ContextKeyExpr.and( + NotebookOutlineContext.CellKind.isEqualTo(CellKind.Code), + NotebookOutlineContext.OutlineElementTarget.isEqualTo(OutlineTarget.OutlinePane), + NotebookOutlineContext.CellHasChildren.toNegated(), + NotebookOutlineContext.CellHasHeader.toNegated(), + ) + } + ] + }); + } + + override async run(_accessor: ServicesAccessor, context: NotebookSectionArgs): Promise { + if (!checkSectionContext(context)) { + return; + } + + context.notebookEditor.executeNotebookCells([context.outlineEntry.cell]); + } +} + +export class NotebookRunCellsInSection extends Action2 { + constructor() { + super({ + id: 'notebook.section.runCells', + title: { + ...localize2('runCellsInSection', "Run Cells In Section"), + 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 + menu: [ + { + id: MenuId.NotebookStickyScrollContext, + group: 'notebookExecution', + order: 1 + }, + { + id: MenuId.NotebookOutlineActionMenu, + group: 'inline', + order: 1, + when: ContextKeyExpr.and( + NotebookOutlineContext.CellKind.isEqualTo(CellKind.Markup), + NotebookOutlineContext.OutlineElementTarget.isEqualTo(OutlineTarget.OutlinePane), + NotebookOutlineContext.CellHasChildren, + NotebookOutlineContext.CellHasHeader, + ) + } + ] + }); + } + + override async run(_accessor: ServicesAccessor, context: NotebookSectionArgs): Promise { + if (!checkSectionContext(context)) { + return; + } + + const cell = context.outlineEntry.cell; + const idx = context.notebookEditor.getViewModel()?.getCellIndex(cell); + if (idx === undefined) { + return; + } + const length = context.notebookEditor.getViewModel()?.getFoldedLength(idx); + if (length === undefined) { + return; + } + + const cells = context.notebookEditor.getCellsInRange({ start: idx, end: idx + length + 1 }); + context.notebookEditor.executeNotebookCells(cells); + } +} + +export class NotebookFoldSection extends Action2 { + constructor() { + super({ + id: 'notebook.section.foldSection', + title: { + ...localize2('foldSection', "Fold Section"), + mnemonicTitle: localize({ key: 'mifoldSection', comment: ['&& denotes a mnemonic'] }, "&&Fold Section"), + }, + shortTitle: localize('foldSection', "Fold Section"), + menu: [ + { + id: MenuId.NotebookOutlineActionMenu, + group: 'notebookFolding', + order: 2, + when: ContextKeyExpr.and( + NotebookOutlineContext.CellKind.isEqualTo(CellKind.Markup), + NotebookOutlineContext.OutlineElementTarget.isEqualTo(OutlineTarget.OutlinePane), + NotebookOutlineContext.CellHasChildren, + NotebookOutlineContext.CellHasHeader, + NotebookOutlineContext.CellFoldingState.isEqualTo(CellFoldingState.Expanded) + ) + } + ] + }); + } + + override async run(_accessor: ServicesAccessor, context: NotebookSectionArgs): Promise { + if (!checkSectionContext(context)) { + return; + } + + this.toggleFoldRange(context.outlineEntry, context.notebookEditor); + } + + private toggleFoldRange(entry: OutlineEntry, notebookEditor: INotebookEditor) { + const foldingController = notebookEditor.getContribution(FoldingController.id); + const index = entry.index; + const headerLevel = entry.level; + const newFoldingState = CellFoldingState.Collapsed; + + foldingController.setFoldingStateDown(index, newFoldingState, headerLevel); + } +} + +export class NotebookExpandSection extends Action2 { + constructor() { + super({ + id: 'notebook.section.expandSection', + title: { + ...localize2('expandSection', "Expand Section"), + mnemonicTitle: localize({ key: 'miexpandSection', comment: ['&& denotes a mnemonic'] }, "&&Expand Section"), + }, + shortTitle: localize('expandSection', "Expand Section"), + menu: [ + { + id: MenuId.NotebookOutlineActionMenu, + group: 'notebookFolding', + order: 2, + when: ContextKeyExpr.and( + NotebookOutlineContext.CellKind.isEqualTo(CellKind.Markup), + NotebookOutlineContext.OutlineElementTarget.isEqualTo(OutlineTarget.OutlinePane), + NotebookOutlineContext.CellHasChildren, + NotebookOutlineContext.CellHasHeader, + NotebookOutlineContext.CellFoldingState.isEqualTo(CellFoldingState.Collapsed) + ) + } + ] + }); + } + + override async run(_accessor: ServicesAccessor, context: NotebookSectionArgs): Promise { + if (!checkSectionContext(context)) { + return; + } + + this.toggleFoldRange(context.outlineEntry, context.notebookEditor); + } + + private toggleFoldRange(entry: OutlineEntry, notebookEditor: INotebookEditor) { + const foldingController = notebookEditor.getContribution(FoldingController.id); + const index = entry.index; + const headerLevel = entry.level; + const newFoldingState = CellFoldingState.Expanded; + + foldingController.setFoldingStateDown(index, newFoldingState, headerLevel); + } +} + +/** + * Take in context args and check if they exist + * + * @param context - Notebook Section Context containing a notebook editor and outline entry + * @returns true if context is valid, false otherwise + */ +function checkSectionContext(context: NotebookSectionArgs): context is ValidNotebookSectionArgs { + return !!(context && context.notebookEditor && context.outlineEntry); +} + +registerAction2(NotebookRunSingleCellInSection); +registerAction2(NotebookRunCellsInSection); +registerAction2(NotebookFoldSection); +registerAction2(NotebookExpandSection); diff --git a/src/vs/workbench/contrib/notebook/browser/media/notebookOutline.css b/src/vs/workbench/contrib/notebook/browser/media/notebookOutline.css index 6e71e660f8752..677f9c89ea790 100644 --- a/src/vs/workbench/contrib/notebook/browser/media/notebookOutline.css +++ b/src/vs/workbench/contrib/notebook/browser/media/notebookOutline.css @@ -43,3 +43,19 @@ /* Don't show markers inline with breadcrumbs */ display: none; } + +.monaco-list-row .notebook-outline-element .action-menu { + display: none; +} + +.monaco-list-row.focused.selected .notebook-outline-element .action-menu { + display: flex; +} + +.monaco-list-row:hover .notebook-outline-element .action-menu { + display: flex; +} + +.monaco-list-row .notebook-outline-element.notebook-outline-toolbar-dropdown-active .action-menu { + display: flex; +} diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts index cf5cf21758746..c36a52fda49f0 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -62,6 +62,7 @@ import { INotebookRendererMessagingService } from 'vs/workbench/contrib/notebook import 'vs/workbench/contrib/notebook/browser/controller/coreActions'; import 'vs/workbench/contrib/notebook/browser/controller/insertCellActions'; import 'vs/workbench/contrib/notebook/browser/controller/executeActions'; +import 'vs/workbench/contrib/notebook/browser/controller/sectionActions'; import 'vs/workbench/contrib/notebook/browser/controller/layoutActions'; import 'vs/workbench/contrib/notebook/browser/controller/editActions'; import 'vs/workbench/contrib/notebook/browser/controller/cellOutputActions'; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 8c8d3a7f64b26..960f2a292d7dc 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -449,6 +449,7 @@ export interface INotebookViewModel { layoutInfo: NotebookLayoutInfo | null; onDidChangeViewCells: Event; onDidChangeSelection: Event; + onDidFoldingStateChanged: Event; getNearestVisibleCellIndexUpwards(index: number): number; getTrackedRange(id: string): ICellRange | null; setTrackedRange(id: string | null, newRange: ICellRange | null, newStickiness: TrackedRangeStickiness): string | null; diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModelImpl.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModelImpl.ts index 6444aa95c45e0..1e17428ab5818 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModelImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModelImpl.ts @@ -177,6 +177,8 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD private readonly _instanceId: string; public readonly id: string; private _foldingRanges: FoldingRegions | null = null; + private _onDidFoldingStateChanged = new Emitter(); + onDidFoldingStateChanged: Event = this._onDidFoldingStateChanged.event; private _hiddenRanges: ICellRange[] = []; private _focused: boolean = true; @@ -470,6 +472,7 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD if (updateHiddenAreas || k < this._hiddenRanges.length) { this._hiddenRanges = newHiddenAreas; + this._onDidFoldingStateChanged.fire(); } this._viewCells.forEach(cell => { diff --git a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorStickyScroll.ts b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorStickyScroll.ts index ec47ab729311e..68e5bc853237e 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorStickyScroll.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorStickyScroll.ts @@ -3,14 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { localize, localize2 } from 'vs/nls'; import * as DOM from 'vs/base/browser/dom'; import { EventType as TouchEventType } from 'vs/base/browser/touch'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; -import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; +import { MenuId } from 'vs/platform/actions/common/actions'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { CellFoldingState, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { INotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon'; @@ -23,46 +21,7 @@ import { foldingCollapsedIcon, foldingExpandedIcon } from 'vs/editor/contrib/fol import { MarkupCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel'; import { FoldingController } from 'vs/workbench/contrib/notebook/browser/controller/foldingController'; import { NotebookOptionsChangeEvent } from 'vs/workbench/contrib/notebook/browser/notebookOptions'; - -type NotebookSectionArgs = { - notebookEditor: INotebookEditor; - outlineEntry: OutlineEntry; -}; - -export class RunInSectionStickyScroll extends Action2 { - constructor() { - super({ - id: 'notebook.action.runInSection', - title: { - ...localize2('runInSectionStickyScroll', "Run Section"), - mnemonicTitle: localize({ key: 'mirunInSectionStickyScroll', comment: ['&& denotes a mnemonic'] }, "&&Run Section"), - }, - menu: [ - { - id: MenuId.NotebookStickyScrollContext, - group: 'notebookExecution', - order: 1 - } - ] - }); - } - - override async run(accessor: ServicesAccessor, context: NotebookSectionArgs, ...args: any[]): Promise { - const cell = context.outlineEntry.cell; - const idx = context.notebookEditor.getViewModel()?.getCellIndex(cell); - if (idx === undefined) { - return; - } - const length = context.notebookEditor.getViewModel()?.getFoldedLength(idx); - if (length === undefined) { - return; - } - const cells = context.notebookEditor.getCellsInRange({ start: idx, end: idx + length + 1 }); - - const notebookEditor: INotebookEditor = context.notebookEditor; - notebookEditor.executeNotebookCells(cells); - } -} +import { NotebookSectionArgs } from 'vs/workbench/contrib/notebook/browser/controller/sectionActions'; export class NotebookStickyLine extends Disposable { constructor( @@ -95,7 +54,7 @@ export class NotebookStickyLine extends Disposable { const headerLevel = this.entry.level; const newFoldingState = (currentState === CellFoldingState.Collapsed) ? CellFoldingState.Expanded : CellFoldingState.Collapsed; - foldingController.setFoldingStateUp(index, newFoldingState, headerLevel); + foldingController.setFoldingStateDown(index, newFoldingState, headerLevel); this.focusCell(); } @@ -501,5 +460,3 @@ export function computeContent(notebookEditor: INotebookEditor, notebookCellList const newMap = NotebookStickyScroll.checkCollapsedStickyLines(cellEntry, linesToRender, notebookEditor); return newMap; } - -registerAction2(RunInSectionStickyScroll);