import { escapeHTML } from "bun" import { readdirSync } from "fs" import { join, extname } from "path" import type { CommandOutput } from "@/shared/types" import { NOSE_WWW } from "@/config" import { getState } from "@/state" import { appPath } from "@/webapp" import { isBinaryFile } from "@/utils" import { highlight } from "../lib/highlight" export default async function (path: string) { const state = getState() if (!state) return { error: "no state" } const project = state.project if (!project) return { error: "no project loaded" } const root = appPath(project) if (!root) return { error: "error loading project" } let files: string[] = [] for (const file of readdirSync(root, { withFileTypes: true })) { files.push(file.name) } if (root === NOSE_WWW) { files = files.filter(file => file.endsWith(`${project}.ts`) || file.endsWith(`${project}.tsx`)) } if (!files.includes(path)) return { error: `file not found: ${path}` } return await readFile(join(root, path)) } async function readFile(path: string): Promise { const ext = extname(path).slice(1) const file = Bun.file(path) switch (ext) { case "jpeg": case "jpg": case "png": case "gif": case "webp": const img = await file.arrayBuffer() return { html: `` } case "mp3": case "wav": case "mp4": case "mov": case "avi": case "mkv": case "webm": return "Not implemented" case "js": case "ts": case "tsx": case "json": return { html: `
${highlight(convertIndent(await file.text()))}
` } default: if (await isBinaryFile(path)) throw "Cannot display binary file" return { html: `
${escapeHTML(await file.text())}
` } } } // cut down 4space and 2space indents into 1space, for readability on a small screen function convertIndent(str: string) { const lines = str.split("\n") // find the smallest non-zero indent const minIndent = Math.min( ...lines .map(l => (l.match(/^ +/) || [""])[0].length) .filter(len => len > 0) ) return lines .map(line => line.replace(/^( +)/, (_, spaces) => " ".repeat(spaces.length / minIndent)) ) .join("\n") }