| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- import { $ } from "bun"
- import path from "path"
- import z from "zod"
- import { Log } from "@/util/log"
- import { Bus } from "@/bus"
- import { Instance } from "./instance"
- import { FileWatcher } from "@/file/watcher"
- const log = Log.create({ service: "vcs" })
- export namespace Vcs {
- export const Event = {
- BranchUpdated: Bus.event(
- "vcs.branch.updated",
- z.object({
- branch: z.string().optional(),
- }),
- ),
- }
- export const Info = z
- .object({
- branch: z.string(),
- })
- .meta({
- ref: "VcsInfo",
- })
- export type Info = z.infer<typeof Info>
- async function currentBranch() {
- return $`git rev-parse --abbrev-ref HEAD`
- .quiet()
- .nothrow()
- .cwd(Instance.worktree)
- .text()
- .then((x) => x.trim())
- .catch(() => undefined)
- }
- const state = Instance.state(
- async () => {
- const vcsDir = Instance.project.vcsDir
- if (Instance.project.vcs !== "git" || !vcsDir) {
- return { branch: async () => undefined, unsubscribe: undefined }
- }
- let current = await currentBranch()
- log.info("initialized", { branch: current })
- const head = path.join(vcsDir, "HEAD")
- const unsubscribe = Bus.subscribe(FileWatcher.Event.Updated, async (evt) => {
- if (evt.properties.file !== head) return
- const next = await currentBranch()
- if (next !== current) {
- log.info("branch changed", { from: current, to: next })
- current = next
- Bus.publish(Event.BranchUpdated, { branch: next })
- }
- })
- return {
- branch: async () => current,
- unsubscribe,
- }
- },
- async (state) => {
- state.unsubscribe?.()
- },
- )
- export async function init() {
- return state()
- }
- export async function branch() {
- return await state().then((s) => s.branch())
- }
- }
|