diff --git a/packages/example-app/src/ProjectView/ProjectView.state.ts b/packages/example-app/src/ProjectView/ProjectView.state.ts index 2a8b30c0..4f230965 100644 --- a/packages/example-app/src/ProjectView/ProjectView.state.ts +++ b/packages/example-app/src/ProjectView/ProjectView.state.ts @@ -12,7 +12,6 @@ import { currentProjectState, Project } from "../Project/project.state"; import { dirContentState, FsItem } from "../fs/fs.state"; import { filterPath } from "../Project/project-utils"; import { getParentPaths } from "../file-utils"; -import * as path from "path"; import { vcsRootsState } from "../VersionControl/file-status.state"; import { notNull } from "@intellij-platform/core/utils/array-utils"; @@ -73,6 +72,32 @@ export const currentProjectTreeState = selector({ }, }); +type FilesTreeSort = "name"; // more to be added + +// TODO: add more sort options and add "Tree Appearance" option in Project tool window settings menu. +export const projectTreeSortState = atom({ + key: "project.tree.sort", + default: "name", +}); + +/** + * NOTE: using in-place native sort for performance. + * See more https://www.measurethat.net/Benchmarks/Show/6698/0/ramda-sort-vs-js-native-sort + */ +function sortProjectTreeNodes(items: FileTreeNode[]): void { + // TODO: add sortBy: FileTreeSort parameter + // TODO: add directoriesOnTop: boolean parameter + items.sort((item1, item2) => { + if (item1.name < item2.name) { + return -1; + } + if (item1.name > item2.name) { + return 1; + } + return 0; + }); +} + // NOTE: this function could be sync, and those `await`s before `get` are unnecessary. They are there simply because // I didn't realize `get` returns the value, not Promise. But interestingly, when this function is made sync, // performance drastically drops for some reason. That needs to be investigated. @@ -84,10 +109,8 @@ async function createProjectTree( const mapItem = (parent: FileTreeDirNode | null) => async (item: FsItem): Promise => { - const name = path.basename(item.path); const node = { ...item, - name, parent, }; const dirNode: FileTreeDirNode = { ...node, children: [] }; @@ -100,6 +123,7 @@ async function createProjectTree( ) ) ).filter(notNull); + sortProjectTreeNodes(dirNode.children); return dirNode; } return null; @@ -107,14 +131,16 @@ async function createProjectTree( return node; }; + const children = ( + await Promise.all((rootItems || []).map(mapItem(null))) + ).filter(notNull); + sortProjectTreeNodes(children); return { type: "project", path: project.path, name: project.name, parent: null, - children: (await Promise.all((rootItems || []).map(mapItem(null)))).filter( - notNull - ), + children, }; } diff --git a/packages/example-app/src/SearchEverywhere/contributors/file/FileItem.tsx b/packages/example-app/src/SearchEverywhere/contributors/file/FileItem.tsx index 95670e2a..a7810895 100644 --- a/packages/example-app/src/SearchEverywhere/contributors/file/FileItem.tsx +++ b/packages/example-app/src/SearchEverywhere/contributors/file/FileItem.tsx @@ -31,7 +31,7 @@ export function FileItem({ matches: null | TextRange[]; }) { const { isSelected } = useContext(ItemStateContext) || {}; - const title = path.basename(file.relativePath); + const title = file.name; const dir = path.dirname(file.relativePath); const [dirMatches, filenameMatches] = splitWhen( diff --git a/packages/example-app/src/fs/fs.state.ts b/packages/example-app/src/fs/fs.state.ts index 4ad4d7b1..3e6ca9b1 100644 --- a/packages/example-app/src/fs/fs.state.ts +++ b/packages/example-app/src/fs/fs.state.ts @@ -6,10 +6,13 @@ import { } from "recoil"; import { fs } from "./fs"; import { Stats } from "@isomorphic-git/lightning-fs"; +import { basename } from "path"; export interface FsItem { type: "dir" | "file"; + name: string; path: string; + lastModification: number; size: number; } @@ -40,7 +43,9 @@ export const dirContentState = selectorFamily({ ); return stats.map((stat) => ({ type: stat.type, + name: basename(stat.filePath), path: stat.filePath, + lastModification: stat.mtimeMs, size: stat.size, })); },