feat(nvim-tree): fully working navigation

This commit is contained in:
Pihkaal
2024-01-27 15:39:26 +01:00
parent e9fe8c95d2
commit 73297d046a
6 changed files with 217 additions and 41 deletions

View File

@@ -1,5 +1,6 @@
import { useState, useEffect } from "react";
import { useTerminal } from "~/context/TerminalContext";
import { api } from "~/utils/api";
import { type Cell } from "~/utils/terminal/cell";
import { TerminalRenderer } from "~/utils/terminal/renderer";
import { theme } from "~/utils/terminal/theme";
@@ -45,7 +46,12 @@ type File = {
);
const FILES_SRC: Array<File> = [
{ name: "projects", type: "directory", children: [], folded: true },
{
name: "projects",
type: "directory",
children: [{ name: "README.md", type: "md" }],
folded: true,
},
{ name: "README.md", type: "md" },
{ name: "LICENSE.md", type: "md" },
{ name: "prout", type: "directory", children: [], folded: true },
@@ -54,16 +60,10 @@ const FILES_SRC: Array<File> = [
];
export const NvimTree = () => {
const { data: repos } = api.github.getRepos.useQuery();
const [selected, setSelected] = useState(0);
const [files, setFiles] = useState(
FILES_SRC.sort((a, b) => a.name.localeCompare(b.name)).sort((a, b) =>
a.type === "directory" && b.type !== "directory"
? -1
: a.type !== "directory" && b.type === "directory"
? 1
: 0,
),
);
const [files, setFiles] = useState(FILES_SRC);
const { cols: width, rows: height } = useTerminal();
const canvas = new TerminalRenderer(width * 0.2, height - 2, {
@@ -71,6 +71,39 @@ export const NvimTree = () => {
});
const tree = new TerminalRenderer(canvas.width - 3, height - 1);
tree.write(0, selected, " ".repeat(tree.width), { background: "#504651" });
let y = 0;
let indent = 0;
const renderTree = (files: Array<File>) => {
files.forEach(file => {
tree.apply(2 + indent * 2, y, FILE_STYLES[file.type]);
if (file.type === "directory") {
tree.apply(indent * 2, y, file.folded ? PATH_FOLDED : PATH_UNFOLDED);
tree.write(4 + indent * 2, y, file.name, {
foreground: FILE_STYLES.directory.foreground,
});
y++;
if (!file.folded) {
indent++;
renderTree(file.children);
indent--;
}
} else {
if (file.name === "README.md") {
tree.write(4 + indent * 2, y, file.name, {
foreground: theme.yellow,
fontWeight: 800,
});
} else {
tree.write(4 + indent * 2, y, file.name);
}
y++;
}
});
};
useEffect(() => {
const onScroll = (event: KeyboardEvent) => {
@@ -80,18 +113,36 @@ export const NvimTree = () => {
break;
case "ArrowDown":
setSelected(x => Math.min(files.length - 1, x + 1));
setSelected(x => Math.min(y - 1, x + 1));
break;
case "Enter":
const newFiles = [...files];
let y = 0;
const findFile = (files: Array<File>): File | null => {
for (const f of files) {
if (y === selected) {
return f;
}
y++;
if (f.type === "directory" && !f.folded) {
const found = findFile(f.children);
if (found) return found;
}
}
const file = newFiles[selected];
if (file?.type === "directory") {
file.folded = !file.folded;
return null;
};
const current = findFile(files);
if (!current) {
setSelected(0);
return;
}
setFiles(newFiles);
if (current.type === "directory") {
current.folded = !current.folded;
setFiles([...files]);
}
break;
}
};
@@ -103,30 +154,19 @@ export const NvimTree = () => {
};
});
tree.write(0, selected, " ".repeat(tree.width), { background: "#504651" });
files.forEach((file, y) => {
tree.apply(2, y, FILE_STYLES[file.type]);
if (file.type === "directory") {
tree.apply(0, y, file.folded ? PATH_FOLDED : PATH_UNFOLDED);
tree.write(4, y, file.name, {
foreground: FILE_STYLES.directory.foreground,
});
} else {
if (file.name === "README.md") {
tree.write(4, y, file.name, {
foreground: theme.yellow,
fontWeight: 800,
});
} else {
tree.write(4, y, file.name);
}
}
});
renderTree(files);
canvas.writeElement(tree, 2, 1);
return <p>{canvas.render()}</p>;
};
/*
.sort((a, b) => a.name.localeCompare(b.name)).sort((a, b) =>
a.type === "directory" && b.type !== "directory"
? -1
: a.type !== "directory" && b.type === "directory"
? 1
: 0,
),
*/