Folded cells run-in-section (#205315)

* initial functionality, needs css tweaks

* update button css + add executing spinner

* mutable disposable to avoid leaking listeners
This commit is contained in:
Michael Lively
2024-02-28 11:28:09 -08:00
committed by GitHub
parent 7368a8944c
commit eb4e516a8a
3 changed files with 75 additions and 2 deletions

View File

@@ -46,6 +46,8 @@
.monaco-workbench .notebookOverlay > .cell-list-container .notebook-folded-hint {
position: absolute;
user-select: none;
display: flex;
align-items: center;
}
.monaco-workbench .notebookOverlay > .cell-list-container .notebook-folded-hint-label {
@@ -55,6 +57,22 @@
opacity: 0.7;
}
.monaco-workbench .notebookOverlay > .cell-list-container .folded-cell-run-section-button {
position: relative;
left: 0px;
padding: 2px;
border-radius: 5px;
margin-right: 4px;
height: 16px;
width: 16px;
z-index: var(--z-index-notebook-cell-expand-part-button);
}
.monaco-workbench .notebookOverlay > .cell-list-container .folded-cell-run-section-button:hover {
background-color: var(--vscode-editorStickyScrollHover-background);
cursor: pointer;
}
.monaco-workbench .notebookOverlay .cell-editor-container .monaco-editor .margin-view-overlays .codicon-folding-expanded,
.monaco-workbench .notebookOverlay .cell-editor-container .monaco-editor .margin-view-overlays .codicon-folding-collapsed {
margin-left: 0;

View File

@@ -11,12 +11,21 @@ import { FoldingController } from 'vs/workbench/contrib/notebook/browser/control
import { CellEditState, CellFoldingState, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellContentPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart';
import { MarkupCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel';
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
import { executingStateIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons';
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
import { NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { MutableDisposable } from 'vs/base/common/lifecycle';
export class FoldedCellHint extends CellContentPart {
private readonly _runButtonListener = this._register(new MutableDisposable());
private readonly _cellExecutionListener = this._register(new MutableDisposable());
constructor(
private readonly _notebookEditor: INotebookEditor,
private readonly _container: HTMLElement,
@INotebookExecutionStateService private readonly _notebookExecutionStateService: INotebookExecutionStateService
) {
super();
}
@@ -27,20 +36,27 @@ export class FoldedCellHint extends CellContentPart {
private update(element: MarkupCellViewModel) {
if (!this._notebookEditor.hasModel()) {
this._cellExecutionListener.clear();
this._runButtonListener.clear();
return;
}
if (element.isInputCollapsed || element.getEditState() === CellEditState.Editing) {
this._cellExecutionListener.clear();
this._runButtonListener.clear();
DOM.hide(this._container);
} else if (element.foldingState === CellFoldingState.Collapsed) {
const idx = this._notebookEditor.getViewModel().getCellIndex(element);
const length = this._notebookEditor.getViewModel().getFoldedLength(idx);
DOM.reset(this._container, this.getHiddenCellsLabel(length), this.getHiddenCellHintButton(element));
DOM.reset(this._container, this.getRunFoldedSectionButton({ start: idx, end: idx + length }), this.getHiddenCellsLabel(length), this.getHiddenCellHintButton(element));
DOM.show(this._container);
const foldHintTop = element.layoutInfo.previewHeight;
this._container.style.top = `${foldHintTop}px`;
} else {
this._cellExecutionListener.clear();
this._runButtonListener.clear();
DOM.hide(this._container);
}
}
@@ -67,6 +83,40 @@ export class FoldedCellHint extends CellContentPart {
return expandIcon;
}
private getRunFoldedSectionButton(range: ICellRange): HTMLElement {
const runAllContainer = DOM.$('span.folded-cell-run-section-button');
const cells = this._notebookEditor.getCellsInRange(range);
const isRunning = cells.some(cell => {
const cellExecution = this._notebookExecutionStateService.getCellExecution(cell.uri);
return cellExecution && cellExecution.state === NotebookCellExecutionState.Executing;
});
const runAllIcon = isRunning ?
ThemeIcon.modify(executingStateIcon, 'spin') :
Codicon.play;
runAllContainer.classList.add(...ThemeIcon.asClassNameArray(runAllIcon));
this._runButtonListener.value = DOM.addDisposableListener(runAllContainer, DOM.EventType.CLICK, () => {
this._notebookEditor.executeNotebookCells(cells);
});
this._cellExecutionListener.value = this._notebookExecutionStateService.onDidChangeExecution(() => {
const isRunning = cells.some(cell => {
const cellExecution = this._notebookExecutionStateService.getCellExecution(cell.uri);
return cellExecution && cellExecution.state === NotebookCellExecutionState.Executing;
});
const runAllIcon = isRunning ?
ThemeIcon.modify(executingStateIcon, 'spin') :
Codicon.play;
runAllContainer.className = '';
runAllContainer.classList.add('folded-cell-run-section-button', ...ThemeIcon.asClassNameArray(runAllIcon));
});
return runAllContainer;
}
override updateInternalLayoutNow(element: MarkupCellViewModel) {
this.update(element);
}

View File

@@ -49,6 +49,7 @@ import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewMod
import { MarkupCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel';
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModelImpl';
import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
const $ = DOM.$;
@@ -109,6 +110,8 @@ abstract class AbstractCellRenderer {
export class MarkupCellRenderer extends AbstractCellRenderer implements IListRenderer<MarkupCellViewModel, MarkdownCellRenderTemplate> {
static readonly TEMPLATE_ID = 'markdown_cell';
private _notebookExecutionStateService: INotebookExecutionStateService;
constructor(
notebookEditor: INotebookEditorDelegate,
dndController: CellDragAndDropController,
@@ -120,8 +123,10 @@ export class MarkupCellRenderer extends AbstractCellRenderer implements IListRen
@IMenuService menuService: IMenuService,
@IKeybindingService keybindingService: IKeybindingService,
@INotificationService notificationService: INotificationService,
@INotebookExecutionStateService notebookExecutionStateService: INotebookExecutionStateService
) {
super(instantiationService, notebookEditor, contextMenuService, menuService, configurationService, keybindingService, notificationService, contextKeyServiceProvider, 'markdown', dndController);
this._notebookExecutionStateService = notebookExecutionStateService;
}
get templateId() {
@@ -169,7 +174,7 @@ export class MarkupCellRenderer extends AbstractCellRenderer implements IListRen
templateDisposables.add(scopedInstaService.createInstance(CellChatPart, this.notebookEditor, cellChatPart)),
templateDisposables.add(scopedInstaService.createInstance(CellEditorStatusBar, this.notebookEditor, container, editorPart, undefined)),
templateDisposables.add(new CellFocusIndicator(this.notebookEditor, titleToolbar, focusIndicatorTop, focusIndicatorLeft, focusIndicatorRight, focusIndicatorBottom)),
templateDisposables.add(new FoldedCellHint(this.notebookEditor, DOM.append(container, $('.notebook-folded-hint')))),
templateDisposables.add(new FoldedCellHint(this.notebookEditor, DOM.append(container, $('.notebook-folded-hint')), this._notebookExecutionStateService)),
templateDisposables.add(new CellDecorations(rootContainer, decorationContainer)),
templateDisposables.add(scopedInstaService.createInstance(CellComments, this.notebookEditor, cellCommentPartContainer)),
templateDisposables.add(new CollapsedCellInput(this.notebookEditor, cellInputCollapsedContainer)),