Skip to content

Commit

Permalink
Implement cell collapse for outputs
Browse files Browse the repository at this point in the history
  • Loading branch information
roblourens committed Jul 25, 2020
1 parent c53cc65 commit 313381b
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 39 deletions.
20 changes: 10 additions & 10 deletions src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1510,20 +1510,20 @@ registerAction2(class extends NotebookCellAction {
id: COLLAPSE_CELL_OUTPUT_COMMAND_ID,
title: localize('notebookActions.collapseCellOutput', "Collapse Cell Output"),
keybinding: {
when: ContextKeyExpr.and(NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_OUTPUT_COLLAPSED.toNegated(), InputFocusedContext.toNegated()),
when: ContextKeyExpr.and(NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_OUTPUT_COLLAPSED.toNegated(), InputFocusedContext.toNegated(), NOTEBOOK_CELL_HAS_OUTPUTS),
primary: KeyChord(KeyCode.KEY_C, KeyCode.KEY_O),
weight: KeybindingWeight.WorkbenchContrib
},
menu: {
id: MenuId.NotebookCellTitle,
when: ContextKeyExpr.and(NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_OUTPUT_COLLAPSED.toNegated()),
when: ContextKeyExpr.and(NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_OUTPUT_COLLAPSED.toNegated(), NOTEBOOK_CELL_HAS_OUTPUTS),
group: '3_collapse',
}
});
}

async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
context.cell.collapseState = CellCollapseState.Collapsed;
context.cell.outputCollapseState = CellCollapseState.Collapsed;
}
});

Expand All @@ -1534,18 +1534,18 @@ registerAction2(class extends NotebookCellAction {
title: localize('notebookActions.expandCellOutput', "Expand Cell Output"),
keybinding: {
when: ContextKeyExpr.and(NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_OUTPUT_COLLAPSED),
primary: KeyChord(KeyCode.KEY_C, KeyCode.KEY_C),
primary: KeyChord(KeyCode.KEY_C, KeyCode.KEY_O),
weight: KeybindingWeight.WorkbenchContrib
},
// menu: {
// id: MenuId.NotebookCellTitle,
// when: ContextKeyExpr.and(NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_OUTPUT_COLLAPSED),
// group: '3_collapse',
// }
menu: {
id: MenuId.NotebookCellTitle,
when: ContextKeyExpr.and(NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_OUTPUT_COLLAPSED),
group: '3_collapse',
}
});
}

async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
context.cell.collapseState = CellCollapseState.Normal;
context.cell.outputCollapseState = CellCollapseState.Normal;
}
});
8 changes: 4 additions & 4 deletions src/vs/workbench/contrib/notebook/browser/media/notebook.css
Original file line number Diff line number Diff line change
Expand Up @@ -212,14 +212,14 @@
}

.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-collapsed-part {
position: relative;
cursor: pointer;
box-sizing: border-box;
padding-left: 5px;
}

.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-collapsed-part .codicon {
margin-top: 2px;
margin-top: 4px;
position: relative;
left: -23px;
cursor: pointer;
}

.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.collapsed .notebook-folding-indicator,
Expand Down
5 changes: 4 additions & 1 deletion src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,8 @@ export interface INotebookEditor extends IEditor {
* @return The contribution or null if contribution not found.
*/
getContribution<T extends INotebookEditorContribution>(id: string): T;

hideInset(output: IProcessedOutput): void;
}

export interface INotebookCellList {
Expand Down Expand Up @@ -460,12 +462,13 @@ export interface INotebookCellList {
export interface BaseCellRenderTemplate {
editorPart: HTMLElement;
collapsedPart: HTMLElement;
expandButton: HTMLElement;
contextKeyService: IContextKeyService;
container: HTMLElement;
cellContainer: HTMLElement;
toolbar: ToolBar;
betweenCellToolbar: ToolBar;
focusIndicator: HTMLElement;
focusIndicatorLeft: HTMLElement;
disposables: DisposableStore;
elementDisposables: DisposableStore;
bottomCellContainer: HTMLElement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1706,13 +1706,16 @@ registerThemingParticipant((theme, collector) => {
if (focusedCellBackgroundColor) {
collector.addRule(`.notebookOverlay .code-cell-row.focused .cell-focus-indicator,
.notebookOverlay .markdown-cell-row.focused { background-color: ${focusedCellBackgroundColor} !important; }`);
collector.addRule(`.notebookOverlay .code-cell-row.focused .cell-collapsed-part { background-color: ${focusedCellBackgroundColor} !important; }`);
}

const cellHoverBackgroundColor = theme.getColor(cellHoverBackground);
if (cellHoverBackgroundColor) {
collector.addRule(`.notebookOverlay .code-cell-row:not(.focused):hover .cell-focus-indicator,
.notebookOverlay .code-cell-row:not(.focused).cell-output-hover .cell-focus-indicator,
.notebookOverlay .markdown-cell-row:not(.focused):hover { background-color: ${cellHoverBackgroundColor} !important; }`);
collector.addRule(`.notebookOverlay .code-cell-row:not(.focused):hover .cell-collapsed-part,
.notebookOverlay .code-cell-row:not(.focused).cell-output-hover .cell-collapsed-part { background-color: ${cellHoverBackgroundColor}; }`);
}

const focusedCellBorderColor = theme.getColor(focusedCellBorder);
Expand Down Expand Up @@ -1801,9 +1804,9 @@ registerThemingParticipant((theme, collector) => {
collector.addRule(`.notebookOverlay .monaco-list .monaco-list-row.code-cell-row .cell-focus-indicator-left { width: ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px; }`);
collector.addRule(`.notebookOverlay .monaco-list .monaco-list-row.markdown-cell-row .cell-focus-indicator-left { width: ${CODE_CELL_LEFT_MARGIN}px; }`);
collector.addRule(`.notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator.cell-focus-indicator-right { width: ${CELL_MARGIN * 2}px; }`);
collector.addRule(`.notebookOverlay .monaco-list .monaco-list-row.collapsed .cell-focus-indicator.cell-focus-indicator-right { width: initial; left: ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px }`);
// collector.addRule(`.notebookOverlay .monaco-list .monaco-list-row.collapsed .cell-focus-indicator.cell-focus-indicator-right { width: initial; left: ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px }`);
collector.addRule(`.notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-bottom { height: ${CELL_BOTTOM_MARGIN}px; }`);
collector.addRule(`.notebookOverlay .monaco-list .monaco-list-row .cell-shadow-container-bottom { top: ${CELL_BOTTOM_MARGIN}px; }`);

collector.addRule(`.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-collapsed-part { margin-left: ${CODE_CELL_LEFT_MARGIN}px; height: ${COLLAPSED_INDICATOR_HEIGHT}px; }`);
collector.addRule(`.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-collapsed-part { margin-left: ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px; height: ${COLLAPSED_INDICATOR_HEIGHT}px; }`);
});
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import * as UUID from 'vs/base/common/uuid';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener';
import { CELL_MARGIN, CELL_RUN_GUTTER, CODE_CELL_LEFT_MARGIN, CELL_OUTPUT_PADDING } from 'vs/workbench/contrib/notebook/browser/constants';
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellCollapseState, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
import { CellOutputKind, IProcessedOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
Expand Down Expand Up @@ -561,6 +561,10 @@ ${loaderJs}
return;
}

if (cell.outputCollapseState === CellCollapseState.Collapsed) {
return false;
}

let outputCache = this.insetMapping.get(output)!;
let outputIndex = cell.outputs.indexOf(output);
let outputOffset = cellTop + cell.getOutputOffset(outputIndex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,13 +271,13 @@ abstract class AbstractCellRenderer {
if (actions.primary.length || actions.secondary.length) {
templateData.container.classList.add('cell-has-toolbar-actions');
if (isCodeCellRenderTemplate(templateData)) {
templateData.focusIndicator.style.top = `${EDITOR_TOOLBAR_HEIGHT + CELL_TOP_MARGIN}px`;
templateData.focusIndicatorLeft.style.top = `${EDITOR_TOOLBAR_HEIGHT + CELL_TOP_MARGIN}px`;
templateData.focusIndicatorRight.style.top = `${EDITOR_TOOLBAR_HEIGHT + CELL_TOP_MARGIN}px`;
}
} else {
templateData.container.classList.remove('cell-has-toolbar-actions');
if (isCodeCellRenderTemplate(templateData)) {
templateData.focusIndicator.style.top = `${CELL_TOP_MARGIN}px`;
templateData.focusIndicatorLeft.style.top = `${CELL_TOP_MARGIN}px`;
templateData.focusIndicatorRight.style.top = `${CELL_TOP_MARGIN}px`;
}
}
Expand All @@ -300,7 +300,7 @@ abstract class AbstractCellRenderer {
}
}, true));

this.setupCollapsedPart(templateData);
this.addExpandListener(templateData);
}

protected commonRenderElement(element: ICellViewModel, index: number, templateData: BaseCellRenderTemplate): void {
Expand All @@ -311,17 +311,28 @@ abstract class AbstractCellRenderer {
}
}

protected setupCollapsedPart(templateData: BaseCellRenderTemplate): void {
templateData.collapsedPart.innerHTML = renderCodicons('$(unfold)');
DOM.hide(templateData.collapsedPart);
templateData.disposables.add(domEvent(templateData.collapsedPart, DOM.EventType.CLICK)(() => {
protected addExpandListener(templateData: BaseCellRenderTemplate): void {
templateData.disposables.add(domEvent(templateData.expandButton, DOM.EventType.CLICK)(() => {
if (!templateData.currentRenderedCell) {
return;
}

templateData.currentRenderedCell.collapseState = CellCollapseState.Normal;
if (templateData.currentRenderedCell.collapseState === CellCollapseState.Collapsed) {
templateData.currentRenderedCell.collapseState = CellCollapseState.Normal;
} else if (templateData.currentRenderedCell.outputCollapseState === CellCollapseState.Collapsed) {
templateData.currentRenderedCell.outputCollapseState = CellCollapseState.Normal;
}
}));
}

protected setupCollapsedPart(container: HTMLElement): { collapsedPart: HTMLElement, expandButton: HTMLElement } {
const collapsedPart = DOM.append(container, $('.cell.cell-collapsed-part'));
collapsedPart.innerHTML = renderCodicons('$(unfold)');
const expandButton = collapsedPart.querySelector('.codicon') as HTMLElement;
DOM.hide(collapsedPart);

return { collapsedPart, expandButton };
}
}

export class MarkdownCellRenderer extends AbstractCellRenderer implements IListRenderer<MarkdownCellViewModel, MarkdownCellRenderTemplate> {
Expand Down Expand Up @@ -361,7 +372,7 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
const innerContent = DOM.append(container, $('.cell.markdown'));
const foldingIndicator = DOM.append(container, DOM.$('.notebook-folding-indicator'));

const collapsedPart = DOM.append(container, $('.cell.cell-collapsed-part'));
const { collapsedPart, expandButton } = this.setupCollapsedPart(container);

const bottomCellContainer = DOM.append(container, $('.cell-bottom-toolbar-container'));
const betweenCellToolbar = disposables.add(this.createBetweenCellToolbar(bottomCellContainer, disposables, contextKeyService));
Expand All @@ -371,12 +382,13 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR

const templateData: MarkdownCellRenderTemplate = {
collapsedPart,
expandButton,
contextKeyService,
container,
cellContainer: innerContent,
editorPart,
editorContainer,
focusIndicator,
focusIndicatorLeft: focusIndicator,
foldingIndicator,
disposables,
elementDisposables: new DisposableStore(),
Expand All @@ -390,6 +402,7 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
};
this.dndController.registerDragHandle(templateData, () => this.getDragImage(templateData));
this.commonRenderTemplate(templateData);

return templateData;
}

Expand Down Expand Up @@ -673,7 +686,7 @@ export class CellDragAndDropController extends Disposable {

registerDragHandle(templateData: BaseCellRenderTemplate, dragImageProvider: DragImageProvider): void {
const container = templateData.container;
const dragHandle = templateData.focusIndicator;
const dragHandle = templateData.focusIndicatorLeft;

templateData.disposables.add(domEvent(dragHandle, DOM.EventType.DRAG_END)(() => {
// Note, templateData may have a different element rendered into it by now
Expand Down Expand Up @@ -943,7 +956,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende

disposables.add(this.editorOptions.onDidChange(newValue => editor.updateOptions(newValue)));

const collapsedPart = DOM.append(container, $('.cell.cell-collapsed-part'));
const { collapsedPart, expandButton } = this.setupCollapsedPart(container);

const progressBar = new ProgressBar(editorPart);
progressBar.hide();
Expand All @@ -968,6 +981,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
const templateData: CodeCellRenderTemplate = {
editorPart,
collapsedPart,
expandButton,
contextKeyService,
container,
cellContainer,
Expand All @@ -976,7 +990,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
cellStatusMessageContainer: statusBar.cellStatusMessageContainer,
languageStatusBarItem: statusBar.languageStatusBarItem,
progressBar,
focusIndicator,
focusIndicatorLeft: focusIndicator,
focusIndicatorRight,
focusIndicatorBottom,
toolbar,
Expand Down Expand Up @@ -1087,7 +1101,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
}

private updateForLayout(element: CodeCellViewModel, templateData: CodeCellRenderTemplate): void {
templateData.focusIndicator.style.height = `${element.layoutInfo.indicatorHeight}px`;
templateData.focusIndicatorLeft.style.height = `${element.layoutInfo.indicatorHeight}px`;
templateData.focusIndicatorRight.style.height = `${element.layoutInfo.indicatorHeight}px`;
templateData.focusIndicatorBottom.style.top = `${element.layoutInfo.totalHeight - BOTTOM_CELL_TOOLBAR_HEIGHT - CELL_BOTTOM_MARGIN}px`;
templateData.outputContainer.style.top = `${element.layoutInfo.outputContainerOffset}px`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ export class CodeCell extends Disposable {
}

if (e.collapseStateChanged) {
// meh
this.viewCell.layoutChange({});
this.relayoutCell();
}
Expand Down Expand Up @@ -308,25 +307,75 @@ export class CodeCell extends Disposable {
}

private viewUpdate(): void {
if (this.viewCell.collapseState === CellCollapseState.Collapsed) {
this.viewUpdateCollapsed();
if (this.viewCell.collapseState === CellCollapseState.Collapsed && this.viewCell.outputCollapseState === CellCollapseState.Collapsed) {
this.viewUpdateAllCollapsed();
} else if (this.viewCell.collapseState === CellCollapseState.Collapsed) {
this.viewUpdateInputCollapsed();
} else if (this.viewCell.outputCollapseState === CellCollapseState.Collapsed && this.viewCell.outputs.length) {
this.viewUpdateOutputCollapsed();
} else {
this.viewUpdateExpanded();
}
}

private viewUpdateCollapsed(): void {
private viewUpdateShowOutputs(): void {
for (let index = 0; index < this.viewCell.outputs.length; index++) {
const currOutput = this.viewCell.outputs[index];

if (currOutput.outputKind === CellOutputKind.Rich) {
this.renderOutput(currOutput, index, undefined);
}
}
}

private viewUpdateInputCollapsed(): void {
DOM.hide(this.templateData.cellContainer);
DOM.show(this.templateData.collapsedPart);
DOM.show(this.templateData.outputContainer);
this.templateData.container.classList.toggle('collapsed', true);

this.viewUpdateShowOutputs();

this.relayoutCell();
}

private viewUpdateOutputCollapsed(): void {
DOM.show(this.templateData.cellContainer);
DOM.show(this.templateData.collapsedPart);
DOM.hide(this.templateData.outputContainer);

for (let e of this.outputElements.keys()) {
this.notebookEditor.hideInset(e);
}

this.templateData.container.classList.toggle('collapsed', false);
this.templateData.container.classList.toggle('output-collapsed', true);

this.relayoutCell();
}

private viewUpdateAllCollapsed(): void {
DOM.hide(this.templateData.cellContainer);
DOM.show(this.templateData.collapsedPart);
DOM.hide(this.templateData.outputContainer);
this.templateData.container.classList.toggle('collapsed', true);
this.templateData.container.classList.toggle('output-collapsed', true);

for (let e of this.outputElements.keys()) {
this.notebookEditor.hideInset(e);
}

this.relayoutCell();
}

private viewUpdateExpanded(): void {
DOM.show(this.templateData.cellContainer);
DOM.hide(this.templateData.collapsedPart);
DOM.show(this.templateData.outputContainer);
this.templateData.container.classList.toggle('collapsed', false);
this.templateData.container.classList.toggle('output-collapsed', false);

this.viewUpdateShowOutputs();

this.relayoutCell();
}
Expand Down Expand Up @@ -587,7 +636,7 @@ export class CodeCell extends Disposable {
value.dispose();
});

this.templateData.focusIndicator!.style.height = 'initial';
this.templateData.focusIndicatorLeft!.style.height = 'initial';

super.dispose();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export abstract class BaseCellViewModel extends Disposable {
}

public set outputCollapseState(v: CellCollapseState) {
this._collapseState = v;
this._outputCollapseState = v;
this._onDidChangeState.fire({ collapseStateChanged: true });
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
layoutChange(state: CodeCellLayoutChangeEvent) {
// recompute
this._ensureOutputsTop();
const outputTotalHeight = this._outputsTop!.getTotalValue();
let outputTotalHeight = this.outputCollapseState === CellCollapseState.Normal ? this._outputsTop!.getTotalValue() : COLLAPSED_INDICATOR_HEIGHT;

if (this.collapseState === CellCollapseState.Normal) {
let newState: CodeCellLayoutState;
Expand Down Expand Up @@ -138,6 +138,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
layoutState: newState
};
} else {
outputTotalHeight = this.collapseState === CellCollapseState.Collapsed && this.outputCollapseState === CellCollapseState.Collapsed ? 0 : outputTotalHeight;
const indicatorHeight = COLLAPSED_INDICATOR_HEIGHT + outputTotalHeight;
const outputContainerOffset = CELL_TOP_MARGIN + COLLAPSED_INDICATOR_HEIGHT;
const totalHeight = CELL_TOP_MARGIN + COLLAPSED_INDICATOR_HEIGHT + CELL_BOTTOM_MARGIN + BOTTOM_CELL_TOOLBAR_HEIGHT + outputTotalHeight;
Expand Down
Loading

0 comments on commit 313381b

Please sign in to comment.