|
|
@@ -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
|
|
|
}
|
|
|
}
|