Skip to content

Commit

Permalink
Merge pull request #225011 from microsoft/don/issue174152HideCells
Browse files Browse the repository at this point in the history
Hide unchanged cells
  • Loading branch information
DonJayamanne authored Aug 9, 2024
2 parents aefef1e + 81e2e6b commit 6fb8d2a
Show file tree
Hide file tree
Showing 11 changed files with 908 additions and 168 deletions.
125 changes: 117 additions & 8 deletions src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import * as DOM from 'vs/base/browser/dom';
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { DiffElementViewModelBase, getFormattedMetadataJSON, getFormattedOutputJSON, OutputComparison, outputEqual, OUTPUT_EDITOR_HEIGHT_MAGIC, PropertyFoldingState, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel';
import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DiffSide, DIFF_CELL_MARGIN, INotebookTextDiffEditor, NOTEBOOK_DIFF_CELL_INPUT, NOTEBOOK_DIFF_CELL_PROPERTY, NOTEBOOK_DIFF_CELL_PROPERTY_EXPANDED } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser';
import { DiffElementCellViewModelBase, getFormattedMetadataJSON, getFormattedOutputJSON, OutputComparison, outputEqual, OUTPUT_EDITOR_HEIGHT_MAGIC, PropertyFoldingState, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel, DiffElementPlaceholderViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel';
import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DiffSide, DIFF_CELL_MARGIN, INotebookTextDiffEditor, NOTEBOOK_DIFF_CELL_INPUT, NOTEBOOK_DIFF_CELL_PROPERTY, NOTEBOOK_DIFF_CELL_PROPERTY_EXPANDED, CellDiffPlaceholderRenderTemplate, IDiffCellMarginOverlay } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser';
import { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditor/codeEditorWidget';
import { IModelService } from 'vs/editor/common/services/model';
import { ILanguageService } from 'vs/editor/common/languages/language';
Expand All @@ -31,7 +31,7 @@ import { SuggestController } from 'vs/editor/contrib/suggest/browser/suggestCont
import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreventer';
import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard';
import { TabCompletionController } from 'vs/workbench/contrib/snippets/browser/tabCompletion';
import { renderIcon } from 'vs/base/browser/ui/iconLabel/iconLabels';
import { renderIcon, renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
Expand All @@ -44,6 +44,8 @@ import { IAccessibilityService } from 'vs/platform/accessibility/common/accessib
import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditor/diffEditorWidget';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel';
import { localize } from 'vs/nls';
import { Emitter } from 'vs/base/common/event';

export function getOptimizedNestedCodeEditorWidgetOptions(): ICodeEditorWidgetOptions {
return {
Expand All @@ -59,6 +61,29 @@ export function getOptimizedNestedCodeEditorWidgetOptions(): ICodeEditorWidgetOp
};
}

export class CellDiffPlaceholderElement extends Disposable {
constructor(
placeholder: DiffElementPlaceholderViewModel,
templateData: CellDiffPlaceholderRenderTemplate,
) {
super();
templateData.body.classList.remove('left', 'right', 'full');
const text = (placeholder.hiddenCells.length === 1) ?
localize('hiddenCell', '{0} hidden cell', placeholder.hiddenCells.length) :
localize('hiddenCells', '{0} hidden cells', placeholder.hiddenCells.length);
templateData.placeholder.innerText = text;

this._register(DOM.addDisposableListener(templateData.placeholder, 'dblclick', (e: MouseEvent) => {
if (e.button !== 0) {
return;
}
e.preventDefault();
placeholder.showHiddenCells();
}));
this._register(templateData.marginOverlay.onAction(() => placeholder.showHiddenCells()));
templateData.marginOverlay.show();
}
}

class PropertyHeader extends Disposable {
protected _foldingIndicator!: HTMLElement;
Expand All @@ -69,14 +94,14 @@ class PropertyHeader extends Disposable {
protected _propertyExpanded?: IContextKey<boolean>;

constructor(
readonly cell: DiffElementViewModelBase,
readonly cell: DiffElementCellViewModelBase,
readonly propertyHeaderContainer: HTMLElement,
readonly notebookEditor: INotebookTextDiffEditor,
readonly accessor: {
updateInfoRendering: (renderOutput: boolean) => void;
checkIfModified: (cell: DiffElementViewModelBase) => false | { reason: string | undefined };
getFoldingState: (cell: DiffElementViewModelBase) => PropertyFoldingState;
updateFoldingState: (cell: DiffElementViewModelBase, newState: PropertyFoldingState) => void;
checkIfModified: (cell: DiffElementCellViewModelBase) => false | { reason: string | undefined };
getFoldingState: (cell: DiffElementCellViewModelBase) => PropertyFoldingState;
updateFoldingState: (cell: DiffElementCellViewModelBase, newState: PropertyFoldingState) => void;
unChangedLabel: string;
changedLabel: string;
prefix: string;
Expand Down Expand Up @@ -271,7 +296,7 @@ abstract class AbstractElementRenderer extends Disposable {

constructor(
readonly notebookEditor: INotebookTextDiffEditor,
readonly cell: DiffElementViewModelBase,
readonly cell: DiffElementCellViewModelBase,
readonly templateData: CellDiffSingleSideRenderTemplate | CellDiffSideBySideRenderTemplate,
readonly style: 'left' | 'right' | 'full',
protected readonly instantiationService: IInstantiationService,
Expand Down Expand Up @@ -1361,6 +1386,15 @@ export class ModifiedElement extends AbstractElementRenderer {
container.classList.remove('inserted', 'removed');
}

override buildBody(): void {
super.buildBody();
if (this.cell.displayIconToHideUnmodifiedCells) {
this._register(this.templateData.marginOverlay.onAction(() => this.cell.hideUnchangedCells()));
this.templateData.marginOverlay.show();
} else {
this.templateData.marginOverlay.hide();
}
}
_disposeMetadata() {
this.cell.metadataStatusHeight = 0;
this.cell.metadataHeight = 0;
Expand Down Expand Up @@ -1790,3 +1824,78 @@ export class ModifiedElement extends AbstractElementRenderer {
super.dispose();
}
}


export class CollapsedCellOverlayWidget extends Disposable implements IDiffCellMarginOverlay {
private readonly _nodes = DOM.h('div.diff-hidden-cells', [
DOM.h('div.center@content', { style: { display: 'flex' } }, [
DOM.$('a', {
title: localize('showUnchangedCells', 'Show Unchanged Cells'),
role: 'button',
onclick: () => { this._action.fire(); }
},
...renderLabelWithIcons('$(unfold)'))]
),
]);

private readonly _action = this._register(new Emitter<void>());
public readonly onAction = this._action.event;
constructor(
private readonly container: HTMLElement
) {
super();

this._nodes.root.style.display = 'none';
container.appendChild(this._nodes.root);
}
public show() {
this._nodes.root.style.display = 'block';
}
public hide() {
this._nodes.root.style.display = 'none';
}
public override dispose() {
this.hide();
this.container.removeChild(this._nodes.root);
DOM.reset(this._nodes.root);
super.dispose();
}
}

export class UnchangedCellOverlayWidget extends Disposable implements IDiffCellMarginOverlay {
private readonly _nodes = DOM.h('div.diff-hidden-cells', [
DOM.h('div.center@content', { style: { display: 'flex' } }, [
DOM.$('a', {
title: localize('hideUnchangedCells', 'Hide Unchanged Cells'),
role: 'button',
onclick: () => { this._action.fire(); }
},
...renderLabelWithIcons('$(fold)')
),
]
),
]);

private readonly _action = this._register(new Emitter<void>());
public readonly onAction = this._action.event;
constructor(
private readonly container: HTMLElement
) {
super();

this._nodes.root.style.display = 'none';
container.appendChild(this._nodes.root);
}
public show() {
this._nodes.root.style.display = 'block';
}
public hide() {
this._nodes.root.style.display = 'none';
}
public override dispose() {
this.hide();
this.container.removeChild(this._nodes.root);
DOM.reset(this._nodes.root);
super.dispose();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import * as DOM from 'vs/base/browser/dom';
import * as nls from 'vs/nls';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { DiffElementViewModelBase, SideBySideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel';
import { DiffElementCellViewModelBase, SideBySideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel';
import { DiffSide, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser';
import { ICellOutputViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
Expand All @@ -33,7 +33,7 @@ export class OutputElement extends Disposable {
private _notebookTextModel: NotebookTextModel,
private _notebookService: INotebookService,
private _quickInputService: IQuickInputService,
private _diffElementViewModel: DiffElementViewModelBase,
private _diffElementViewModel: DiffElementCellViewModelBase,
private _diffSide: DiffSide,
private _nestedCell: DiffNestedCellViewModel,
private _outputContainer: HTMLElement,
Expand Down Expand Up @@ -228,7 +228,7 @@ export class OutputContainer extends Disposable {
constructor(
private _editor: INotebookTextDiffEditor,
private _notebookTextModel: NotebookTextModel,
private _diffElementViewModel: DiffElementViewModelBase,
private _diffElementViewModel: DiffElementCellViewModelBase,
private _nestedCellViewModel: DiffNestedCellViewModel,
private _diffSide: DiffSide,
private _outputContainer: HTMLElement,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,77 @@ interface ILayoutInfoDelta extends ILayoutInfoDelta0 {
recomputeOutput?: boolean;
}

export type IDiffElementViewModelBase = DiffElementCellViewModelBase | DiffElementPlaceholderViewModel;

export abstract class DiffElementViewModelBase extends Disposable {
protected _layoutInfoEmitter = this._register(new Emitter<CellDiffViewModelLayoutChangeEvent>());
onDidLayoutChange = this._layoutInfoEmitter.event;
constructor(
public readonly mainDocumentTextModel: INotebookTextModel,
public readonly editorEventDispatcher: NotebookDiffEditorEventDispatcher,
public readonly initData: {
metadataStatusHeight: number;
outputStatusHeight: number;
fontInfo: FontInfo | undefined;
}
) {
super();

this._register(this.editorEventDispatcher.onDidChangeLayout(e => this._layoutInfoEmitter.fire({ outerWidth: true })));
}

abstract layoutChange(): void;
abstract getHeight(lineHeight: number): number;
abstract get totalHeight(): number;
}

export class DiffElementPlaceholderViewModel extends DiffElementViewModelBase {
readonly type: 'placeholder' = 'placeholder';
public hiddenCells: DiffElementCellViewModelBase[] = [];
protected _unfoldHiddenCells = this._register(new Emitter<void>());
onUnfoldHiddenCells = this._unfoldHiddenCells.event;

constructor(
mainDocumentTextModel: INotebookTextModel,
editorEventDispatcher: NotebookDiffEditorEventDispatcher,
initData: {
metadataStatusHeight: number;
outputStatusHeight: number;
fontInfo: FontInfo | undefined;
}
) {
super(mainDocumentTextModel, editorEventDispatcher, initData);

}
get totalHeight() {
return 24 + (2 * DIFF_CELL_MARGIN);
}
getHeight(_: number): number {
return this.totalHeight;
}
override layoutChange(): void {
//
}
showHiddenCells() {
this._unfoldHiddenCells.fire();
}
}

export abstract class DiffElementCellViewModelBase extends DiffElementViewModelBase {
public cellFoldingState: PropertyFoldingState;
public metadataFoldingState: PropertyFoldingState;
public outputFoldingState: PropertyFoldingState;
protected _layoutInfoEmitter = this._register(new Emitter<CellDiffViewModelLayoutChangeEvent>());
onDidLayoutChange = this._layoutInfoEmitter.event;
protected _stateChangeEmitter = this._register(new Emitter<{ renderOutput: boolean }>());
onDidStateChange = this._stateChangeEmitter.event;
protected _layoutInfo!: IDiffElementLayoutInfo;

public displayIconToHideUnmodifiedCells?: boolean;
private _hideUnchangedCells = this._register(new Emitter<void>());
public onHideUnchangedCells = this._hideUnchangedCells.event;

hideUnchangedCells() {
this._hideUnchangedCells.fire();
}
set rawOutputHeight(height: number) {
this._layout({ rawOutputHeight: Math.min(OUTPUT_EDITOR_HEIGHT_MAGIC, height) });
}
Expand Down Expand Up @@ -115,23 +176,27 @@ export abstract class DiffElementViewModelBase extends Disposable {
return this._layoutInfo;
}

get totalHeight() {
return this.layoutInfo.totalHeight;
}

private _sourceEditorViewState: editorCommon.ICodeEditorViewState | editorCommon.IDiffEditorViewState | null = null;
private _outputEditorViewState: editorCommon.ICodeEditorViewState | editorCommon.IDiffEditorViewState | null = null;
private _metadataEditorViewState: editorCommon.ICodeEditorViewState | editorCommon.IDiffEditorViewState | null = null;

constructor(
readonly mainDocumentTextModel: INotebookTextModel,
mainDocumentTextModel: INotebookTextModel,
readonly original: DiffNestedCellViewModel | undefined,
readonly modified: DiffNestedCellViewModel | undefined,
readonly type: 'unchanged' | 'insert' | 'delete' | 'modified',
readonly editorEventDispatcher: NotebookDiffEditorEventDispatcher,
readonly initData: {
editorEventDispatcher: NotebookDiffEditorEventDispatcher,
initData: {
metadataStatusHeight: number;
outputStatusHeight: number;
fontInfo: FontInfo | undefined;
}
) {
super();
super(mainDocumentTextModel, editorEventDispatcher, initData);
const editorHeight = this._estimateEditorHeight(initData.fontInfo);
const cellStatusHeight = 25;
this._layoutInfo = {
Expand All @@ -154,9 +219,7 @@ export abstract class DiffElementViewModelBase extends Disposable {
this.metadataFoldingState = PropertyFoldingState.Collapsed;
this.outputFoldingState = PropertyFoldingState.Collapsed;

this._register(this.editorEventDispatcher.onDidChangeLayout(e => {
this._layoutInfoEmitter.fire({ outerWidth: true });
}));
this._register(this.editorEventDispatcher.onDidChangeLayout(e => this._layoutInfoEmitter.fire({ outerWidth: true })));
}

layoutChange() {
Expand Down Expand Up @@ -385,7 +448,7 @@ export abstract class DiffElementViewModelBase extends Disposable {
}
}

export class SideBySideDiffElementViewModel extends DiffElementViewModelBase {
export class SideBySideDiffElementViewModel extends DiffElementCellViewModelBase {
get originalDocument() {
return this.otherDocumentTextModel;
}
Expand Down Expand Up @@ -543,7 +606,7 @@ export class SideBySideDiffElementViewModel extends DiffElementViewModelBase {
}
}

export class SingleSideDiffElementViewModel extends DiffElementViewModelBase {
export class SingleSideDiffElementViewModel extends DiffElementCellViewModelBase {
get cellViewModel() {
return this.type === 'insert' ? this.modified! : this.original!;
}
Expand Down
Loading

0 comments on commit 6fb8d2a

Please sign in to comment.