Sources
What the shell's asking about, read lazily: completing a command name shouldn't open the codebase.
import type { Complete } from "#codebase/tcmts/cli/complete"; import { Store } from "#codebase/tcmts/store"; import fs from "node:fs"; import path from "node:path"; import { DatabaseSync } from "node:sqlite"; export class Sources { private store: Store | undefined | null = null; private cwd: string; constructor(cwd: string) { this.cwd = cwd; } private root(): string | undefined { for (let dir = this.cwd; ; dir = path.dirname(dir)) { if (fs.existsSync(path.join(dir, ".tcm", "codebase.sqlite"))) return dir; if (path.dirname(dir) === dir) return undefined; } } private db(): Store | undefined { if (this.store === null) { const r = this.root(); this.store = r ? new Store(path.join(r, ".tcm", "codebase.sqlite")) : undefined; } return this.store; } definitions(complete: Complete, kind?: "value") { for (const n of this.db()?.names(undefined, true) ?? []) if (!kind || n.kind !== "type") complete(n.path, n.kind); } namespaces(complete: Complete) { const seen = new Set<string>(); for (const n of this.db()?.names(undefined, true) ?? []) { const parts = n.path.split("."); for (let i = 1; i < parts.length; i++) seen.add(parts.slice(0, i).join(".")); } for (const ns of [...seen].sort()) complete(ns, "namespace"); } branches(complete: Complete) { const db = this.db(); for (const b of db?.branches() ?? []) complete(b, b === db!.branch().name ? "current branch" : "branch"); } remotes(complete: Complete) { for (const [key, value] of this.db()?.settings("remote.") ?? []) complete(key.slice("remote.".length), (JSON.parse(value) as { url?: string }).url ?? ""); } packages(complete: Complete) { const seen = new Set<string>(); for (const p of this.db()?.lockedPackages() ?? []) if (!p.name.startsWith("@types/") && !seen.has(p.name)) { seen.add(p.name); complete(p.name, p.version); } } tables(complete: Complete) { const r = this.root(); const file = r && path.join(r, ".tcm", "data", "store.sqlite"); if (!file || !fs.existsSync(file)) return; const db = new DatabaseSync(file, { readOnly: true }); try { for (const t of db .prepare("SELECT tbl, count(*) AS n FROM rows GROUP BY tbl ORDER BY tbl") .all() as { tbl: string; n: number }[]) complete(t.tbl, `${t.n} row(s)`); } finally { db.close(); } } /** Directories under this one (tab can't hand a word back to the shell's own path completion). */ directories(complete: Complete) { const walk = (dir: string, depth: number) => { for (const e of fs.readdirSync(path.join(this.cwd, dir), { withFileTypes: true })) { if (!e.isDirectory() || e.name.startsWith(".") || e.name === "node_modules") continue; const rel = dir ? `${dir}/${e.name}` : e.name; complete(rel, "directory"); if (depth < 2) walk(rel, depth + 1); } }; walk("", 1); } scratchFiles(complete: Complete) { const r = this.root() ?? this.cwd; for (const f of fs.readdirSync(r)) if (/\.tsx?$/.test(f) && !f.endsWith(".d.ts")) complete(f, "scratch file"); } }