ignore: add file status command

This commit is contained in:
Dax Raad 2025-07-01 20:39:43 -04:00
parent c68aeed8d9
commit 7e5941e14b
3 changed files with 122 additions and 28 deletions

View file

@ -2,12 +2,6 @@ import { File } from "../../../file"
import { bootstrap } from "../../bootstrap"
import { cmd } from "../cmd"
export const FileCommand = cmd({
command: "file",
builder: (yargs) => yargs.command(FileReadCommand).demandCommand(),
async handler() {},
})
const FileReadCommand = cmd({
command: "read <path>",
builder: (yargs) =>
@ -23,3 +17,21 @@ const FileReadCommand = cmd({
})
},
})
const FileStatusCommand = cmd({
command: "status",
builder: (yargs) => yargs,
async handler() {
await bootstrap({ cwd: process.cwd() }, async () => {
const status = await File.status()
console.log(JSON.stringify(status, null, 2))
})
},
})
export const FileCommand = cmd({
command: "file",
builder: (yargs) =>
yargs.command(FileReadCommand).command(FileStatusCommand).demandCommand(),
async handler() {},
})

View file

@ -3,13 +3,13 @@ import { Bus } from "../bus"
import { $ } from "bun"
import { createPatch } from "diff"
import path from "path"
import { status } from "isomorphic-git"
import * as git from "isomorphic-git"
import { App } from "../app/app"
import fs from "fs"
import { Log } from "../util/log"
export namespace File {
const log = Log.create({ service: "files" })
const log = Log.create({ service: "file" })
export const Event = {
Edited: Bus.event(
@ -20,6 +20,84 @@ export namespace File {
),
}
export async function status() {
const app = App.info()
if (!app.git) return []
// Get all changed files with line counts in one command
const diffOutput = await $`git diff --numstat HEAD`
.cwd(app.path.root)
.quiet()
.nothrow()
.text()
const changedFiles = []
if (diffOutput.trim()) {
const lines = diffOutput.trim().split("\n")
for (const line of lines) {
const [added, removed, filepath] = line.split("\t")
changedFiles.push({
file: filepath,
added: added === "-" ? 0 : parseInt(added, 10),
removed: removed === "-" ? 0 : parseInt(removed, 10),
status: "modified",
})
}
}
// Get untracked files
const untrackedOutput = await $`git ls-files --others --exclude-standard`
.cwd(app.path.root)
.quiet()
.nothrow()
.text()
if (untrackedOutput.trim()) {
const untrackedFiles = untrackedOutput.trim().split("\n")
for (const filepath of untrackedFiles) {
try {
const content = await Bun.file(
path.join(app.path.root, filepath),
).text()
const lines = content.split("\n").length
changedFiles.push({
file: filepath,
added: lines,
removed: 0,
status: "added",
})
} catch {
continue
}
}
}
// Get deleted files
const deletedOutput = await $`git diff --name-only --diff-filter=D HEAD`
.cwd(app.path.root)
.quiet()
.nothrow()
.text()
if (deletedOutput.trim()) {
const deletedFiles = deletedOutput.trim().split("\n")
for (const filepath of deletedFiles) {
changedFiles.push({
file: filepath,
added: 0,
removed: 0, // Could get original line count but would require another git command
status: "deleted",
})
}
}
return changedFiles.map((x) => ({
...x,
file: path.relative(app.path.cwd, path.join(app.path.root, x.file)),
}))
}
export async function read(file: string) {
using _ = log.time("read", { file })
const app = App.info()
@ -27,7 +105,7 @@ export namespace File {
const content = await Bun.file(full).text()
if (app.git) {
const rel = path.relative(app.path.root, full)
const diff = await status({
const diff = await git.status({
fs,
dir: app.path.root,
filepath: rel,
@ -38,7 +116,9 @@ export namespace File {
.quiet()
.nothrow()
.text()
const patch = createPatch(file, original, content)
const patch = createPatch(file, original, content, "old", "new", {
context: Infinity,
})
return patch
}
}

View file

@ -22,28 +22,30 @@ export namespace FileWatcher {
"file.watcher",
() => {
const app = App.use()
const watcher = fs.watch(
app.info.path.cwd,
{ recursive: true },
(event, file) => {
log.info("change", { file, event })
if (!file) return
// for some reason async local storage is lost here
// https://github.com/oven-sh/bun/issues/20754
App.provideExisting(app, async () => {
Bus.publish(Event.Updated, {
file,
event,
try {
const watcher = fs.watch(
app.info.path.cwd,
{ recursive: true },
(event, file) => {
log.info("change", { file, event })
if (!file) return
// for some reason async local storage is lost here
// https://github.com/oven-sh/bun/issues/20754
App.provideExisting(app, async () => {
Bus.publish(Event.Updated, {
file,
event,
})
})
})
},
)
return {
watcher,
},
)
return { watcher }
} finally {
return {}
}
},
async (state) => {
state.watcher.close()
state.watcher?.close()
},
)()
}