Path: blob/main/src/vs/workbench/contrib/notebook/test/browser/notebookFolding.test.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import assert from 'assert';6import { CellKind } from '../../common/notebookCommon.js';7import { setupInstantiationService, withTestNotebook } from './testNotebookEditor.js';8import { IUndoRedoService } from '../../../../../platform/undoRedo/common/undoRedo.js';9import { FoldingModel, updateFoldingStateAtIndex } from '../../browser/viewModel/foldingModel.js';10import { DisposableStore } from '../../../../../base/common/lifecycle.js';11import { TestInstantiationService } from '../../../../../platform/instantiation/test/common/instantiationServiceMock.js';12import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';1314suite('Notebook Folding', () => {15let disposables: DisposableStore;16let instantiationService: TestInstantiationService;1718teardown(() => disposables.dispose());1920ensureNoDisposablesAreLeakedInTestSuite();2122setup(() => {23disposables = new DisposableStore();24instantiationService = setupInstantiationService(disposables);25instantiationService.spy(IUndoRedoService, 'pushElement');26});272829test('Folding based on markdown cells', async function () {30await withTestNotebook(31[32['# header 1', 'markdown', CellKind.Markup, [], {}],33['body', 'markdown', CellKind.Markup, [], {}],34['## header 2.1', 'markdown', CellKind.Markup, [], {}],35['body 2', 'markdown', CellKind.Markup, [], {}],36['body 3', 'markdown', CellKind.Markup, [], {}],37['## header 2.2', 'markdown', CellKind.Markup, [], {}],38['var e = 7;', 'markdown', CellKind.Markup, [], {}],39],40(editor, viewModel, ds) => {41const foldingController = ds.add(new FoldingModel());42foldingController.attachViewModel(viewModel);4344assert.strictEqual(foldingController.regions.findRange(1), 0);45assert.strictEqual(foldingController.regions.findRange(2), 0);46assert.strictEqual(foldingController.regions.findRange(3), 1);47assert.strictEqual(foldingController.regions.findRange(4), 1);48assert.strictEqual(foldingController.regions.findRange(5), 1);49assert.strictEqual(foldingController.regions.findRange(6), 2);50assert.strictEqual(foldingController.regions.findRange(7), 2);51}52);53});5455test('Folding not based on code cells', async function () {56await withTestNotebook(57[58['# header 1', 'markdown', CellKind.Markup, [], {}],59['body', 'markdown', CellKind.Markup, [], {}],60['# comment 1', 'python', CellKind.Code, [], {}],61['body 2', 'markdown', CellKind.Markup, [], {}],62['body 3\n```\n## comment 2\n```', 'markdown', CellKind.Markup, [], {}],63['body 4', 'markdown', CellKind.Markup, [], {}],64['## header 2.1', 'markdown', CellKind.Markup, [], {}],65['var e = 7;', 'python', CellKind.Code, [], {}],66],67(editor, viewModel, ds) => {68const foldingController = ds.add(new FoldingModel());69foldingController.attachViewModel(viewModel);7071assert.strictEqual(foldingController.regions.findRange(1), 0);72assert.strictEqual(foldingController.regions.findRange(2), 0);73assert.strictEqual(foldingController.regions.findRange(3), 0);74assert.strictEqual(foldingController.regions.findRange(4), 0);75assert.strictEqual(foldingController.regions.findRange(5), 0);76assert.strictEqual(foldingController.regions.findRange(6), 0);77assert.strictEqual(foldingController.regions.findRange(7), 1);78assert.strictEqual(foldingController.regions.findRange(8), 1);79}80);81});8283test('Top level header in a cell wins', async function () {84await withTestNotebook(85[86['# header 1', 'markdown', CellKind.Markup, [], {}],87['body', 'markdown', CellKind.Markup, [], {}],88['## header 2.1\n# header3', 'markdown', CellKind.Markup, [], {}],89['body 2', 'markdown', CellKind.Markup, [], {}],90['body 3', 'markdown', CellKind.Markup, [], {}],91['## header 2.2', 'markdown', CellKind.Markup, [], {}],92['var e = 7;', 'markdown', CellKind.Markup, [], {}],93],94(editor, viewModel, ds) => {95const foldingController = ds.add(new FoldingModel());96foldingController.attachViewModel(viewModel);9798assert.strictEqual(foldingController.regions.findRange(1), 0);99assert.strictEqual(foldingController.regions.findRange(2), 0);100assert.strictEqual(foldingController.regions.getEndLineNumber(0), 2);101102assert.strictEqual(foldingController.regions.findRange(3), 1);103assert.strictEqual(foldingController.regions.findRange(4), 1);104assert.strictEqual(foldingController.regions.findRange(5), 1);105assert.strictEqual(foldingController.regions.getEndLineNumber(1), 7);106107assert.strictEqual(foldingController.regions.findRange(6), 2);108assert.strictEqual(foldingController.regions.findRange(7), 2);109assert.strictEqual(foldingController.regions.getEndLineNumber(2), 7);110}111);112});113114test('Folding', async function () {115await withTestNotebook(116[117['# header 1', 'markdown', CellKind.Markup, [], {}],118['body', 'markdown', CellKind.Markup, [], {}],119['## header 2.1', 'markdown', CellKind.Markup, [], {}],120['body 2', 'markdown', CellKind.Markup, [], {}],121['body 3', 'markdown', CellKind.Markup, [], {}],122['## header 2.2', 'markdown', CellKind.Markup, [], {}],123['var e = 7;', 'markdown', CellKind.Markup, [], {}],124],125(editor, viewModel, ds) => {126const foldingModel = ds.add(new FoldingModel());127foldingModel.attachViewModel(viewModel);128updateFoldingStateAtIndex(foldingModel, 0, true);129viewModel.updateFoldingRanges(foldingModel.regions);130assert.deepStrictEqual(viewModel.getHiddenRanges(), [131{ start: 1, end: 6 }132]);133}134);135136await withTestNotebook(137[138['# header 1', 'markdown', CellKind.Markup, [], {}],139['body', 'markdown', CellKind.Markup, [], {}],140['## header 2.1\n', 'markdown', CellKind.Markup, [], {}],141['body 2', 'markdown', CellKind.Markup, [], {}],142['body 3', 'markdown', CellKind.Markup, [], {}],143['## header 2.2', 'markdown', CellKind.Markup, [], {}],144['var e = 7;', 'markdown', CellKind.Markup, [], {}],145],146(editor, viewModel, ds) => {147const foldingModel = ds.add(new FoldingModel());148foldingModel.attachViewModel(viewModel);149updateFoldingStateAtIndex(foldingModel, 2, true);150viewModel.updateFoldingRanges(foldingModel.regions);151152assert.deepStrictEqual(viewModel.getHiddenRanges(), [153{ start: 3, end: 4 }154]);155}156);157158await withTestNotebook(159[160['# header 1', 'markdown', CellKind.Markup, [], {}],161['body', 'markdown', CellKind.Markup, [], {}],162['# header 2.1\n', 'markdown', CellKind.Markup, [], {}],163['body 2', 'markdown', CellKind.Markup, [], {}],164['body 3', 'markdown', CellKind.Markup, [], {}],165['## header 2.2', 'markdown', CellKind.Markup, [], {}],166['var e = 7;', 'markdown', CellKind.Markup, [], {}],167],168(editor, viewModel, ds) => {169const foldingModel = ds.add(new FoldingModel());170foldingModel.attachViewModel(viewModel);171updateFoldingStateAtIndex(foldingModel, 2, true);172viewModel.updateFoldingRanges(foldingModel.regions);173174assert.deepStrictEqual(viewModel.getHiddenRanges(), [175{ start: 3, end: 6 }176]);177}178);179});180181test('Nested Folding', async function () {182await withTestNotebook(183[184['# header 1', 'markdown', CellKind.Markup, [], {}],185['body', 'markdown', CellKind.Markup, [], {}],186['# header 2.1\n', 'markdown', CellKind.Markup, [], {}],187['body 2', 'markdown', CellKind.Markup, [], {}],188['body 3', 'markdown', CellKind.Markup, [], {}],189['## header 2.2', 'markdown', CellKind.Markup, [], {}],190['var e = 7;', 'markdown', CellKind.Markup, [], {}],191],192(editor, viewModel, ds) => {193const foldingModel = ds.add(new FoldingModel());194foldingModel.attachViewModel(viewModel);195updateFoldingStateAtIndex(foldingModel, 0, true);196viewModel.updateFoldingRanges(foldingModel.regions);197198assert.deepStrictEqual(viewModel.getHiddenRanges(), [199{ start: 1, end: 1 }200]);201202updateFoldingStateAtIndex(foldingModel, 5, true);203updateFoldingStateAtIndex(foldingModel, 2, true);204viewModel.updateFoldingRanges(foldingModel.regions);205206assert.deepStrictEqual(viewModel.getHiddenRanges(), [207{ start: 1, end: 1 },208{ start: 3, end: 6 }209]);210211updateFoldingStateAtIndex(foldingModel, 2, false);212viewModel.updateFoldingRanges(foldingModel.regions);213assert.deepStrictEqual(viewModel.getHiddenRanges(), [214{ start: 1, end: 1 },215{ start: 6, end: 6 }216]);217218// viewModel.insertCell(7, new TestCell(viewModel.viewType, 7, ['var c = 8;'], 'markdown', CellKind.Code, []), true);219220// assert.deepStrictEqual(viewModel.getHiddenRanges(), [221// { start: 1, end: 1 },222// { start: 6, end: 7 }223// ]);224225// viewModel.insertCell(1, new TestCell(viewModel.viewType, 8, ['var c = 9;'], 'markdown', CellKind.Code, []), true);226// assert.deepStrictEqual(viewModel.getHiddenRanges(), [227// // the first collapsed range is now expanded as we insert content into it.228// // { start: 1,},229// { start: 7, end: 8 }230// ]);231}232);233});234235test('Folding Memento', async function () {236await withTestNotebook(237[238['# header 1', 'markdown', CellKind.Markup, [], {}],239['body', 'markdown', CellKind.Markup, [], {}],240['# header 2.1\n', 'markdown', CellKind.Markup, [], {}],241['body 2', 'markdown', CellKind.Markup, [], {}],242['body 3', 'markdown', CellKind.Markup, [], {}],243['## header 2.2', 'markdown', CellKind.Markup, [], {}],244['var e = 7;', 'markdown', CellKind.Markup, [], {}],245['# header 2.1\n', 'markdown', CellKind.Markup, [], {}],246['body 2', 'markdown', CellKind.Markup, [], {}],247['body 3', 'markdown', CellKind.Markup, [], {}],248['## header 2.2', 'markdown', CellKind.Markup, [], {}],249['var e = 7;', 'markdown', CellKind.Markup, [], {}],250],251(editor, viewModel, ds) => {252const foldingModel = ds.add(new FoldingModel());253foldingModel.attachViewModel(viewModel);254foldingModel.applyMemento([{ start: 2, end: 6 }]);255viewModel.updateFoldingRanges(foldingModel.regions);256257// Note that hidden ranges !== folding ranges258assert.deepStrictEqual(viewModel.getHiddenRanges(), [259{ start: 3, end: 6 }260]);261}262);263264await withTestNotebook(265[266['# header 1', 'markdown', CellKind.Markup, [], {}],267['body', 'markdown', CellKind.Markup, [], {}],268['# header 2.1\n', 'markdown', CellKind.Markup, [], {}],269['body 2', 'markdown', CellKind.Markup, [], {}],270['body 3', 'markdown', CellKind.Markup, [], {}],271['## header 2.2', 'markdown', CellKind.Markup, [], {}],272['var e = 7;', 'markdown', CellKind.Markup, [], {}],273['# header 2.1\n', 'markdown', CellKind.Markup, [], {}],274['body 2', 'markdown', CellKind.Markup, [], {}],275['body 3', 'markdown', CellKind.Markup, [], {}],276['## header 2.2', 'markdown', CellKind.Markup, [], {}],277['var e = 7;', 'markdown', CellKind.Markup, [], {}],278],279(editor, viewModel, ds) => {280const foldingModel = ds.add(new FoldingModel());281foldingModel.attachViewModel(viewModel);282foldingModel.applyMemento([283{ start: 5, end: 6 },284{ start: 10, end: 11 },285]);286viewModel.updateFoldingRanges(foldingModel.regions);287288// Note that hidden ranges !== folding ranges289assert.deepStrictEqual(viewModel.getHiddenRanges(), [290{ start: 6, end: 6 },291{ start: 11, end: 11 }292]);293}294);295296await withTestNotebook(297[298['# header 1', 'markdown', CellKind.Markup, [], {}],299['body', 'markdown', CellKind.Markup, [], {}],300['# header 2.1\n', 'markdown', CellKind.Markup, [], {}],301['body 2', 'markdown', CellKind.Markup, [], {}],302['body 3', 'markdown', CellKind.Markup, [], {}],303['## header 2.2', 'markdown', CellKind.Markup, [], {}],304['var e = 7;', 'markdown', CellKind.Markup, [], {}],305['# header 2.1\n', 'markdown', CellKind.Markup, [], {}],306['body 2', 'markdown', CellKind.Markup, [], {}],307['body 3', 'markdown', CellKind.Markup, [], {}],308['## header 2.2', 'markdown', CellKind.Markup, [], {}],309['var e = 7;', 'markdown', CellKind.Markup, [], {}],310],311(editor, viewModel, ds) => {312const foldingModel = ds.add(new FoldingModel());313foldingModel.attachViewModel(viewModel);314foldingModel.applyMemento([315{ start: 5, end: 6 },316{ start: 7, end: 11 },317]);318viewModel.updateFoldingRanges(foldingModel.regions);319320// Note that hidden ranges !== folding ranges321assert.deepStrictEqual(viewModel.getHiddenRanges(), [322{ start: 6, end: 6 },323{ start: 8, end: 11 }324]);325}326);327});328329test('View Index', async function () {330await withTestNotebook(331[332['# header 1', 'markdown', CellKind.Markup, [], {}],333['body', 'markdown', CellKind.Markup, [], {}],334['# header 2.1\n', 'markdown', CellKind.Markup, [], {}],335['body 2', 'markdown', CellKind.Markup, [], {}],336['body 3', 'markdown', CellKind.Markup, [], {}],337['## header 2.2', 'markdown', CellKind.Markup, [], {}],338['var e = 7;', 'markdown', CellKind.Markup, [], {}],339['# header 2.1\n', 'markdown', CellKind.Markup, [], {}],340['body 2', 'markdown', CellKind.Markup, [], {}],341['body 3', 'markdown', CellKind.Markup, [], {}],342['## header 2.2', 'markdown', CellKind.Markup, [], {}],343['var e = 7;', 'markdown', CellKind.Markup, [], {}],344],345(editor, viewModel, ds) => {346const foldingModel = ds.add(new FoldingModel());347foldingModel.attachViewModel(viewModel);348foldingModel.applyMemento([{ start: 2, end: 6 }]);349viewModel.updateFoldingRanges(foldingModel.regions);350351// Note that hidden ranges !== folding ranges352assert.deepStrictEqual(viewModel.getHiddenRanges(), [353{ start: 3, end: 6 }354]);355356assert.strictEqual(viewModel.getNextVisibleCellIndex(1), 2);357assert.strictEqual(viewModel.getNextVisibleCellIndex(2), 7);358assert.strictEqual(viewModel.getNextVisibleCellIndex(3), 7);359assert.strictEqual(viewModel.getNextVisibleCellIndex(4), 7);360assert.strictEqual(viewModel.getNextVisibleCellIndex(5), 7);361assert.strictEqual(viewModel.getNextVisibleCellIndex(6), 7);362assert.strictEqual(viewModel.getNextVisibleCellIndex(7), 8);363}364);365366await withTestNotebook(367[368['# header 1', 'markdown', CellKind.Markup, [], {}],369['body', 'markdown', CellKind.Markup, [], {}],370['# header 2.1\n', 'markdown', CellKind.Markup, [], {}],371['body 2', 'markdown', CellKind.Markup, [], {}],372['body 3', 'markdown', CellKind.Markup, [], {}],373['## header 2.2', 'markdown', CellKind.Markup, [], {}],374['var e = 7;', 'markdown', CellKind.Markup, [], {}],375['# header 2.1\n', 'markdown', CellKind.Markup, [], {}],376['body 2', 'markdown', CellKind.Markup, [], {}],377['body 3', 'markdown', CellKind.Markup, [], {}],378['## header 2.2', 'markdown', CellKind.Markup, [], {}],379['var e = 7;', 'markdown', CellKind.Markup, [], {}],380],381(editor, viewModel, ds) => {382const foldingModel = ds.add(new FoldingModel());383foldingModel.attachViewModel(viewModel);384foldingModel.applyMemento([385{ start: 5, end: 6 },386{ start: 10, end: 11 },387]);388389viewModel.updateFoldingRanges(foldingModel.regions);390391// Note that hidden ranges !== folding ranges392assert.deepStrictEqual(viewModel.getHiddenRanges(), [393{ start: 6, end: 6 },394{ start: 11, end: 11 }395]);396397// folding ranges398// [5, 6]399// [10, 11]400assert.strictEqual(viewModel.getNextVisibleCellIndex(4), 5);401assert.strictEqual(viewModel.getNextVisibleCellIndex(5), 7);402assert.strictEqual(viewModel.getNextVisibleCellIndex(6), 7);403404assert.strictEqual(viewModel.getNextVisibleCellIndex(9), 10);405assert.strictEqual(viewModel.getNextVisibleCellIndex(10), 12);406assert.strictEqual(viewModel.getNextVisibleCellIndex(11), 12);407}408);409});410});411412413