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

Hide cell output in webview when fold #95732

Merged
merged 6 commits into from
Apr 21, 2020
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
3 changes: 3 additions & 0 deletions src/vs/workbench/api/common/extHost.api.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -903,12 +903,15 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
// namespace: notebook
const notebook: typeof vscode.notebook = {
registerNotebookProvider: (viewType: string, provider: vscode.NotebookProvider) => {
checkProposedApiEnabled(extension);
return extHostNotebook.registerNotebookProvider(extension, viewType, provider);
},
registerNotebookOutputRenderer: (type: string, outputFilter: vscode.NotebookOutputSelector, renderer: vscode.NotebookOutputRenderer) => {
checkProposedApiEnabled(extension);
return extHostNotebook.registerNotebookOutputRenderer(type, extension, outputFilter, renderer);
},
get activeNotebookDocument(): vscode.NotebookDocument | undefined {
checkProposedApiEnabled(extension);
return extHostNotebook.activeNotebookDocument;
}
};
Expand Down
36 changes: 33 additions & 3 deletions src/vs/workbench/contrib/notebook/browser/contrib/fold/folding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
*--------------------------------------------------------------------------------------------*/

import { Disposable } from 'vs/base/common/lifecycle';
import { INotebookEditor, INotebookEditorMouseEvent } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookEditor, INotebookEditorMouseEvent, ICellRange } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import * as DOM from 'vs/base/browser/dom';
import { CellFoldingState } from 'vs/workbench/contrib/notebook/browser/viewModel/foldingModel';
import { CellFoldingState, FoldingModel } from 'vs/workbench/contrib/notebook/browser/contrib/fold/foldingModel';

export class FoldingController extends Disposable {
private _foldingModel: FoldingModel;
constructor(
private readonly _notebookEditor: INotebookEditor

Expand All @@ -20,6 +21,35 @@ export class FoldingController extends Disposable {
const hiddenRanges = this._notebookEditor.viewModel!.getHiddenRanges();
this._notebookEditor.setHiddenAreas(hiddenRanges);
}));

this._foldingModel = new FoldingModel();
this._foldingModel.attachViewModel(this._notebookEditor.viewModel!);

this._register(this._foldingModel.onDidFoldingRegionChanged(() => {
this._notebookEditor.viewModel!.updateFoldingRanges(this._foldingModel.regions);
}));
}

applyMemento(state: ICellRange[]) {
this._foldingModel.applyMemento(state);
this._notebookEditor.viewModel!.updateFoldingRanges(this._foldingModel.regions);
}

getMemento(): ICellRange[] {
return this._foldingModel.getMemento();
}

setFoldingState(index: number, state: CellFoldingState) {
const range = this._foldingModel.regions.findRange(index + 1);
const startIndex = this._foldingModel.regions.getStartLineNumber(range) - 1;

if (startIndex !== index) {
return;
}

this._foldingModel.setCollapsed(range, state === CellFoldingState.Collapsed);
this._notebookEditor.viewModel!.updateFoldingRanges(this._foldingModel.regions);

}

onMouseUp(e: INotebookEditorMouseEvent) {
Expand Down Expand Up @@ -52,7 +82,7 @@ export class FoldingController extends Disposable {
return;
}

viewModel.setFoldingState(modelIndex, state === CellFoldingState.Collapsed ? CellFoldingState.Expanded : CellFoldingState.Collapsed);
this.setFoldingState(modelIndex, state === CellFoldingState.Collapsed ? CellFoldingState.Expanded : CellFoldingState.Collapsed);
}

return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,54 @@ export class FoldingModel extends Disposable {
this._regions = newRegions;
this._onDidFoldingRegionChanges.fire();
}

getMemento(): ICellRange[] {
const collapsedRanges: ICellRange[] = [];
let i = 0;
while (i < this._regions.length) {
let isCollapsed = this._regions.isCollapsed(i);

if (isCollapsed) {
const region = this._regions.toRegion(i);
collapsedRanges.push({ start: region.startLineNumber - 1, end: region.endLineNumber - 1 });
}

i++;
}

return collapsedRanges;
}

public applyMemento(state: ICellRange[]): boolean {
let i = 0;
let k = 0;

while (k < state.length && i < this._regions.length) {
// get the latest range
let decRange = this._viewModel!.getTrackedRange(this._foldingRangeDecorationIds[i]);
if (decRange) {
let collasedStartIndex = state[k].start;

while (i < this._regions.length) {
let startIndex = this._regions.getStartLineNumber(i) - 1;
if (collasedStartIndex >= startIndex) {
this._regions.setCollapsed(i, collasedStartIndex === startIndex);
i++;
} else {
break;
}
}
}
k++;
}

while (i < this._regions.length) {
this._regions.setCollapsed(i, false);
i++;
}

return true;
}
}

export enum CellFoldingState {
Expand Down
4 changes: 3 additions & 1 deletion src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,11 +312,13 @@ export interface INotebookCellList {
length: number;
rowsContainer: HTMLElement;
readonly onDidRemoveOutput: Event<IOutput>;
readonly onDidHideOutput: Event<IOutput>;
readonly onMouseUp: Event<IListMouseEvent<CellViewModel>>;
readonly onMouseDown: Event<IListMouseEvent<CellViewModel>>;
detachViewModel(): void;
attachViewModel(viewModel: NotebookViewModel): void;
clear(): void;
getViewIndex(cell: ICellViewModel): number | undefined;
focusElement(element: ICellViewModel): void;
selectElement(element: ICellViewModel): void;
getFocusedElements(): ICellViewModel[];
Expand All @@ -329,7 +331,7 @@ export interface INotebookCellList {
revealElementRangeInView(element: ICellViewModel, range: Range): void;
revealElementRangeInCenter(element: ICellViewModel, range: Range): void;
revealElementRangeInCenterIfOutsideViewport(element: ICellViewModel, range: Range): void;
setHiddenAreas(_ranges: ICellRange[]): boolean;
setHiddenAreas(_ranges: ICellRange[], triggerViewUpdate: boolean): boolean;
domElementOfElement(element: ICellViewModel): HTMLElement | null;
focusView(): void;
getAbsoluteTopOfElement(element: ICellViewModel): number;
Expand Down
103 changes: 73 additions & 30 deletions src/vs/workbench/contrib/notebook/browser/notebookEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
private editorExecutingNotebook: IContextKey<boolean> | null = null;
private outputRenderer: OutputRenderer;
private findWidget: NotebookFindWidget;
private folding: FoldingController | null = null;

constructor(
@ITelemetryService telemetryService: ITelemetryService,
Expand Down Expand Up @@ -282,7 +283,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {

onWillHide() {
if (this.input && this.input instanceof NotebookEditorInput && !this.input.isDisposed()) {
this.saveTextEditorViewState(this.input);
this.saveEditorViewState(this.input);
}

this.editorFocus?.set(false);
Expand All @@ -309,7 +310,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
}

if (editor === this.input) {
this.saveTextEditorViewState(editor);
this.saveEditorViewState(editor);
}
}

Expand All @@ -321,7 +322,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {

async setInput(input: NotebookEditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
if (this.input instanceof NotebookEditorInput) {
this.saveTextEditorViewState(this.input);
this.saveEditorViewState(this.input);
}

await super.setInput(input, options, token);
Expand Down Expand Up @@ -384,14 +385,24 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
this.notebookViewModel = this.instantiationService.createInstance(NotebookViewModel, input.viewType!, model, this.eventDispatcher, this.getLayoutInfo());
this.editorEditable?.set(!!this.notebookViewModel.metadata?.editable);
this.eventDispatcher.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]);
const viewState = this.loadTextEditorViewState(input);
this.notebookViewModel.restoreEditorViewState(viewState);

this.localStore.add(this.eventDispatcher.onDidChangeMetadata((e) => {
this.editorEditable?.set(e.source.editable);
}));

this.localStore.add(this.instantiationService.createInstance(FoldingController, this));
// load contributions
this.folding = this.localStore.add(this.instantiationService.createInstance(FoldingController, this));

// restore view states, including contributions
const viewState = this.loadTextEditorViewState(input);

{
// restore view state
this.notebookViewModel.restoreEditorViewState(viewState);

// contribution state restore
this.folding?.applyMemento(viewState?.hiddenFoldingRanges || []);
}

this.webview?.updateRendererPreloads(this.notebookViewModel.renderers);

Expand All @@ -401,37 +412,49 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
}));

this.localStore.add(this.list!.onDidChangeContentHeight(() => {
const scrollTop = this.list?.scrollTop || 0;
const scrollHeight = this.list?.scrollHeight || 0;
this.webview!.element.style.height = `${scrollHeight}px`;
let updateItems: { cell: CodeCellViewModel, output: IOutput, cellTop: number }[] = [];

if (this.webview?.insetMapping) {
this.webview?.insetMapping.forEach((value, key) => {
const cell = value.cell;
const cellTop = this.list?.getAbsoluteTopOfElement(cell) || 0;
if (this.webview!.shouldUpdateInset(cell, key, cellTop)) {
updateItems.push({
cell: cell,
output: key,
cellTop: cellTop
});
DOM.scheduleAtNextAnimationFrame(() => {
const scrollTop = this.list?.scrollTop || 0;
const scrollHeight = this.list?.scrollHeight || 0;
this.webview!.element.style.height = `${scrollHeight}px`;
let updateItems: { cell: CodeCellViewModel, output: IOutput, cellTop: number }[] = [];

if (this.webview?.insetMapping) {
this.webview?.insetMapping.forEach((value, key) => {
const cell = value.cell;
const viewIndex = this.list?.getViewIndex(cell);

if (viewIndex === undefined) {
return;
}

const cellTop = this.list?.getAbsoluteTopOfElement(cell) || 0;
if (this.webview!.shouldUpdateInset(cell, key, cellTop)) {
updateItems.push({
cell: cell,
output: key,
cellTop: cellTop
});
}
});

if (updateItems.length) {
this.webview?.updateViewScrollTop(-scrollTop, updateItems);
}
});

if (updateItems.length) {
this.webview?.updateViewScrollTop(-scrollTop, updateItems);
}
}
});
}));

this.list!.attachViewModel(this.notebookViewModel);
this.localStore.add(this.list!.onDidRemoveOutput(output => {
this.removeInset(output);
}));
this.localStore.add(this.list!.onDidHideOutput(output => {
this.hideInset(output);
}));

this.list!.layout();

// restore list state at last, it must be after list layout
this.restoreTextEditorViewState(viewState);
}

Expand All @@ -457,9 +480,9 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
}
}

private saveTextEditorViewState(input: NotebookEditorInput): void {
private saveEditorViewState(input: NotebookEditorInput): void {
if (this.group && this.notebookViewModel) {
const state = this.notebookViewModel.saveEditorViewState();
const state = this.notebookViewModel.geteEditorViewState();
if (this.list) {
state.scrollPosition = { left: this.list.scrollLeft, top: this.list.scrollTop };
let cellHeights: { [key: number]: number } = {};
Expand Down Expand Up @@ -488,6 +511,12 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
}
}

// Save contribution view states
if (this.folding) {
const foldingState = this.folding.getMemento();
state.hiddenFoldingRanges = foldingState;
}

this.editorMemento.saveEditorState(this.group, input.resource, state);
}
}
Expand Down Expand Up @@ -518,7 +547,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {

protected saveState(): void {
if (this.input instanceof NotebookEditorInput) {
this.saveTextEditorViewState(this.input);
this.saveEditorViewState(this.input);
}

super.saveState();
Expand Down Expand Up @@ -577,7 +606,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
}

setHiddenAreas(_ranges: ICellRange[]): boolean {
return this.list!.setHiddenAreas(_ranges);
return this.list!.setHiddenAreas(_ranges, true);
}

//#endregion
Expand Down Expand Up @@ -606,6 +635,12 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {

//#region Cell operations
async layoutNotebookCell(cell: ICellViewModel, height: number): Promise<void> {
const viewIndex = this.list!.getViewIndex(cell);
if (viewIndex === undefined) {
// the cell is hidden
return;
}

let relayout = (cell: ICellViewModel, height: number) => {
this.list?.updateElementHeight2(cell, height);
};
Expand Down Expand Up @@ -857,6 +892,14 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
this.webview!.removeInset(output);
}

hideInset(output: IOutput) {
if (!this.webview) {
return;
}

this.webview!.hideInset(output);
}

getOutputRenderer(): OutputRenderer {
return this.outputRenderer;
}
Expand Down
Loading