diff --git a/frontend/src/reports/editor/EditorMenu.svelte b/frontend/src/reports/editor/EditorMenu.svelte index e53099f48..0c9370af1 100644 --- a/frontend/src/reports/editor/EditorMenu.svelte +++ b/frontend/src/reports/editor/EditorMenu.svelte @@ -14,7 +14,10 @@ import AppMenu from "./AppMenu.svelte"; import AppMenuItem from "./AppMenuItem.svelte"; import AppMenuSubItem from "./AppMenuSubItem.svelte"; + import File from "./File.svelte"; + import Folder from "./Folder.svelte"; import Key from "./Key.svelte"; + import { source_tree } from "./treeview"; export let file_path: string; export let editor: EditorView; @@ -33,18 +36,17 @@ editor.focus(); } } + $: [filenodes, foldernodes] = source_tree(sources, goToFileAndLine);
- {#each sources as source} - goToFileAndLine(source)} - selected={source === file_path} - > - {source} - + {#each filenodes as file} + + {/each} + {#each foldernodes as folder} + {/each} diff --git a/frontend/src/reports/editor/File.svelte b/frontend/src/reports/editor/File.svelte new file mode 100644 index 000000000..6aeb499c1 --- /dev/null +++ b/frontend/src/reports/editor/File.svelte @@ -0,0 +1,28 @@ + + + + + + + diff --git a/frontend/src/reports/editor/Folder.svelte b/frontend/src/reports/editor/Folder.svelte new file mode 100644 index 000000000..735c00787 --- /dev/null +++ b/frontend/src/reports/editor/Folder.svelte @@ -0,0 +1,67 @@ + + +
+ {folder.name} + +
    + {#each folder.subfiles as file} +
  • + +
  • + {/each} + {#each folder.subfolders as subfolder} +
  • + +
  • + {/each} +
+
+ + diff --git a/frontend/src/reports/editor/treeview.ts b/frontend/src/reports/editor/treeview.ts new file mode 100644 index 000000000..c222c054f --- /dev/null +++ b/frontend/src/reports/editor/treeview.ts @@ -0,0 +1,90 @@ +export interface FileNode { + name: string; + path: string; + action: () => void; +} +export interface FolderNode { + name: string; + subfolders: FolderNode[]; + subfiles: FileNode[]; +} + +const zip: (a: A[], b: B[]) => [A, B][] = (a: A[], b: B[]) => + a.reduce((l: [A, B][], k: A, i) => { + const n = b[i]; + if (n !== undefined) { + l.push([k, n]); + } + return l; + }, []); + +function shorten_folder(folder: FolderNode): FolderNode { + if (folder.subfiles.length === 0) { + const subfolder = folder.subfolders[0]; + if (subfolder !== undefined) { + const new_name = `${folder.name}/${subfolder.name}`; + return shorten_folder({ + name: new_name, + subfolders: subfolder.subfolders, + subfiles: subfolder.subfiles, + }); + } + } + return { + name: folder.name, + subfolders: folder.subfolders.map(shorten_folder), + subfiles: folder.subfiles, + }; +} +function _source_tree( + paths: string[][], + filenodes: FileNode[] +): [FileNode[], FolderNode[]] { + const groupBy = (arr: T[], key: (i: T) => string) => + arr.reduce>((groups, item) => { + (groups[key(item)] ||= []).push(item); + return groups; + }, {}); + + const r1 = zip(filenodes, paths) + .filter((a) => a[1].length === 0) + .map((a) => a[0]); + const r2 = Object.entries( + groupBy( + zip(filenodes, paths).reduce( + (acc: [FileNode, string[], string][], [file, path]) => { + const root = path[0]; + if (root !== undefined) { + acc.push([file, path.slice(1), root]); + } + return acc; + }, + [] + ), + (a: [FileNode, string[], string]) => a[2] + ) + ).map(([dir, group]: [string, [FileNode, string[], string][]]) => { + const [subfiles, subfolders] = _source_tree( + group.map((a: [FileNode, string[], string]) => a[1]), + group.map((a: [FileNode, string[], string]) => a[0]) + ); + return { name: dir, subfolders, subfiles }; + }); + return [r1, r2]; +} +export function source_tree( + files: string[], + goToFileAndLine: (filename: string, line?: number) => void +): [FileNode[], FolderNode[]] { + files.sort(); + const paths = files.map((file) => file.split("/")); + const raw_filenodes = zip(files, paths).map( + ([file, path]: [string, string[]]) => ({ + name: path.pop() ?? file, + path: file, + action: () => goToFileAndLine(file), + }) + ); + const [filenodes, foldernodes] = _source_tree(paths, raw_filenodes); + return [filenodes, foldernodes.map(shorten_folder)]; +}