Skip to content

Commit

Permalink
Remove toc-trees-provider
Browse files Browse the repository at this point in the history
TocTreesProvider and TocTreeItem were only used in tests

Move toggleTocTreesFilteringHandler to book-tocs
  • Loading branch information
TylerZeroMaster committed Aug 8, 2024
1 parent a69e864 commit 10ec38a
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 119 deletions.
77 changes: 76 additions & 1 deletion client/specs/book-tocs.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import SinonRoot from 'sinon'
import type vscode from 'vscode'
import { expect } from '@jest/globals'

import { BookRootNode, type BookToc, type ClientTocNode, TocNodeKind } from '../../common/src/toc'
import { TocsTreeProvider } from '../src/book-tocs'
import { type BookOrTocNode, TocsTreeProvider, toggleTocTreesFilteringHandler } from '../src/book-tocs'

const testTocPage: ClientTocNode = {
type: TocNodeKind.Page,
Expand Down Expand Up @@ -69,3 +71,76 @@ describe('Toc Provider', () => {
expect(p.getParentBook(testToc)).toBe(undefined)
})
})

describe('filtering', () => {
const sinon = SinonRoot.createSandbox()
afterEach(() => { sinon.restore() })
it('toggleTocTreesFilteringHandler', async () => {
const revealStub = sinon.stub()
const toggleFilterStub = sinon.stub()
const getChildrenStub = sinon.stub()
const refreshStub = sinon.stub()

const view: vscode.TreeView<BookOrTocNode> = {
reveal: revealStub
} as unknown as vscode.TreeView<BookOrTocNode>
const provider: TocsTreeProvider = {
toggleFilterMode: toggleFilterStub,
getChildren: getChildrenStub,
refresh: refreshStub,
getParent: () => undefined
} as unknown as TocsTreeProvider
const fakeChildren = [
{ type: BookRootNode.Singleton, tocTree: [{ type: TocNodeKind.Subbook, label: 'unit1', children: [{ type: TocNodeKind.Subbook, label: 'subcol1', children: [{ type: TocNodeKind.Page, label: 'm2', children: [] }] }] }] },
{ type: BookRootNode.Singleton, tocTree: [{ label: 'm1', children: [] }] }
]
getChildrenStub.returns(fakeChildren)

const handler = toggleTocTreesFilteringHandler(view, provider)
await handler()
expect(toggleFilterStub.callCount).toBe(1)
expect(getChildrenStub.callCount).toBe(1)
expect(revealStub.callCount).toBe(2)
expect(revealStub.getCalls().map(c => c.args)).toMatchSnapshot()
expect(refreshStub.callCount).toBe(0)
})
it('toggleTocTreesFilteringHandler disables itself while revealing', async () => {
const revealStub = sinon.stub()
const toggleFilterStub = sinon.stub()
const getChildrenStub = sinon.stub()
const fakeChildren = [
{ label: 'col1', children: [{ label: 'm1', children: [] }] }
]
getChildrenStub.returns(fakeChildren)

const view: vscode.TreeView<BookOrTocNode> = {
reveal: revealStub
} as unknown as vscode.TreeView<BookOrTocNode>
const provider: TocsTreeProvider = {
toggleFilterMode: toggleFilterStub,
getChildren: getChildrenStub,
getParent: () => undefined
} as unknown as TocsTreeProvider

const handler = toggleTocTreesFilteringHandler(view, provider)
// Invoke the handler the first time reveal is called to simulate a parallel
// user request without resorting to synthetic delay injection
revealStub.onCall(0).callsFake(handler)
await handler()
expect(toggleFilterStub.callCount).toBe(1)
expect(revealStub.callCount).toBe(1)
expect(getChildrenStub.callCount).toBe(1)
})
it('toggleTocTreesFilteringHandler does not lock itself on errors', async () => {
const toggleFilterStub = sinon.stub().throws()
const view: vscode.TreeView<BookOrTocNode> = {} as unknown as vscode.TreeView<BookOrTocNode>
const provider: TocsTreeProvider = {
toggleFilterMode: toggleFilterStub
} as unknown as TocsTreeProvider

const handler = toggleTocTreesFilteringHandler(view, provider)
try { await handler() } catch { }
try { await handler() } catch { }
expect(toggleFilterStub.callCount).toBe(2)
})
})
58 changes: 56 additions & 2 deletions client/src/book-tocs.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { EventEmitter, type TreeItem, TreeItemCollapsibleState, Uri, type TreeDataProvider } from 'vscode'
import { EventEmitter, type TreeItem, TreeItemCollapsibleState, Uri, type TreeDataProvider, ThemeIcon } from 'vscode'

import { type BookToc, type ClientTocNode, BookRootNode, TocNodeKind, type ClientPageish } from '../../common/src/toc'
import { TocItemIcon } from './toc-trees-provider'
import type vscode from 'vscode'

export type BookOrTocNode = BookToc | ClientTocNode

const toClientTocNode = (n: ClientPageish): ClientTocNode => ({ type: TocNodeKind.Page, value: n })

export const TocItemIcon = {
Page: ThemeIcon.File,
Book: new ThemeIcon('book'),
Subbook: ThemeIcon.Folder
}

export class TocsTreeProvider implements TreeDataProvider<BookOrTocNode> {
private readonly _onDidChangeTreeData = new EventEmitter<void>()
readonly onDidChangeTreeData = this._onDidChangeTreeData.event
Expand Down Expand Up @@ -122,3 +128,51 @@ export class TocsTreeProvider implements TreeDataProvider<BookOrTocNode> {
: this.getBookIndex(parentBook)
}
}

export function toggleTocTreesFilteringHandler(view: vscode.TreeView<BookOrTocNode>, provider: TocsTreeProvider): () => Promise<void> {
let revealing: boolean = false

// We call the view.reveal API for all nodes with children to ensure the tree
// is fully expanded. This approach is used since attempting to simply call
// reveal on root notes with the max expand value of 3 doesn't seem to always
// fully expose leaf nodes for large trees.
function leafFinder(acc: ClientTocNode[], elements: BookOrTocNode[]) {
for (const el of elements) {
if (el.type === BookRootNode.Singleton) {
leafFinder(acc, el.tocTree)
} else if (el.type === TocNodeKind.Subbook) {
leafFinder(acc, el.children)
} else {
acc.push(el)
}
}
}

return async () => {
// Avoid parallel processing of requests by ignoring if we're actively
// revealing
if (revealing) { return }
revealing = true

try {
// Toggle data provider filter mode and reveal all children so the
// tree expands if it hasn't already
provider.toggleFilterMode()
const leaves: ClientTocNode[] = []
leafFinder(leaves, provider.getChildren())
const nodes3Up = new Set<BookOrTocNode>() // VSCode allows expanding up to 3 levels down
leaves.forEach(l => {
const p1 = provider.getParent(l)
const p2 = p1 === undefined ? undefined : /* istanbul ignore next */ provider.getParent(p1)
const p3 = p2 === undefined ? undefined : /* istanbul ignore next */ provider.getParent(p2)
/* istanbul ignore next */
nodes3Up.add(p3 ?? p2 ?? p1 ?? l)
})
for (const node of Array.from(nodes3Up).reverse()) {
await view.reveal(node, { expand: 3 })
}
} finally {
revealing = false
}
}
}
2 changes: 1 addition & 1 deletion client/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { expect, ensureCatch, ensureCatchPromise, launchLanguageServer, populate
import { OpenstaxCommand } from './extension-types'
import { type ExtensionHostContext, type Panel, PanelManager } from './panel'
import { ImageManagerPanel } from './panel-image-manager'
import { toggleTocTreesFilteringHandler } from './toc-trees-provider'
import { toggleTocTreesFilteringHandler } from './book-tocs'
import { type BookOrTocNode, TocsTreeProvider } from './book-tocs'
import { type BooksAndOrphans, EMPTY_BOOKS_AND_ORPHANS, ExtensionServerNotification } from '../../common/src/requests'
import { readmeGenerator } from './generate-readme'
Expand Down
115 changes: 0 additions & 115 deletions client/src/toc-trees-provider.ts

This file was deleted.

0 comments on commit 10ec38a

Please sign in to comment.