diff --git a/packages/app/src/components/file-tree.tsx b/packages/app/src/components/file-tree.tsx index b7f8316d0..64988af53 100644 --- a/packages/app/src/components/file-tree.tsx +++ b/packages/app/src/components/file-tree.tsx @@ -17,6 +17,11 @@ import { import { Dynamic } from "solid-js/web" import type { FileNode } from "@opencode-ai/sdk/v2" +type Filter = { + files: Set + dirs: Set +} + export default function FileTree(props: { path: string class?: string @@ -27,26 +32,19 @@ export default function FileTree(props: { draggable?: boolean tooltip?: boolean onFileClick?: (file: FileNode) => void + + _filter?: Filter + _marks?: Set + _deeps?: Map }) { const file = useFile() const level = props.level ?? 0 const draggable = () => props.draggable ?? true const tooltip = () => props.tooltip ?? true - const maxOpen = (dir: string, lvl: number): number => { - const expanded = file.tree.state(dir)?.expanded ?? false - if (!expanded) return -1 - - const nodes = file.tree.children(dir) - const child = nodes.reduce((max, node) => { - if (node.type !== "directory") return max - return Math.max(max, maxOpen(node.path, lvl + 1)) - }, -1) - - return Math.max(lvl, child) - } - const filter = createMemo(() => { + if (props._filter) return props._filter + const allowed = props.allowed if (!allowed) return @@ -66,11 +64,38 @@ export default function FileTree(props: { }) const marks = createMemo(() => { + if (props._marks) return props._marks + const modified = props.modified if (!modified || modified.length === 0) return return new Set(modified) }) + const deeps = createMemo(() => { + if (props._deeps) return props._deeps + + const out = new Map() + + const visit = (dir: string, lvl: number): number => { + const expanded = file.tree.state(dir)?.expanded ?? false + if (!expanded) return -1 + + const nodes = file.tree.children(dir) + const max = nodes.reduce((max, node) => { + if (node.type !== "directory") return max + const open = file.tree.state(node.path)?.expanded ?? false + if (!open) return max + return Math.max(max, visit(node.path, lvl + 1)) + }, lvl) + + out.set(dir, max) + return max + } + + visit(props.path, level - 1) + return out + }) + createEffect(() => { const current = filter() if (!current) return @@ -84,7 +109,8 @@ export default function FileTree(props: { }) createEffect(() => { - void file.tree.list(props.path) + const path = props.path + untrack(() => void file.tree.list(path)) }) const nodes = createMemo(() => { @@ -165,7 +191,7 @@ export default function FileTree(props: { {(node) => { const expanded = () => file.tree.state(node.path)?.expanded ?? false - const deep = createMemo(() => (node.type === "directory" ? maxOpen(node.path, level) : -1)) + const deep = () => deeps().get(node.path) ?? -1 const Wrapper = (p: ParentProps) => { if (!tooltip()) return p.children return ( @@ -212,6 +238,9 @@ export default function FileTree(props: { draggable={props.draggable} tooltip={props.tooltip} onFileClick={props.onFileClick} + _filter={filter()} + _marks={marks()} + _deeps={deeps()} />