Shared workspace inspection, backed by the native git binary.
UI surfaces and extensions depend on this namespace instead of embedding
their own git calls. It reports small, renderable facts about the current
repository (branch, dirty buckets, ahead/behind, porcelain entries) by
shelling out to git status --porcelain=v2 and git rev-parse, parsed
into stable Clojure maps. No JGit — the only git implementation is the one
already on the user's PATH, so behaviour matches their shell exactly.
Workspace lifecycle mutations stay in
com.blockether.vis.internal.workspace.
Shared workspace inspection, backed by the native `git` binary. UI surfaces and extensions depend on this namespace instead of embedding their own git calls. It reports small, renderable facts about the current repository (branch, dirty buckets, ahead/behind, porcelain entries) by shelling out to `git status --porcelain=v2` and `git rev-parse`, parsed into stable Clojure maps. No JGit — the only git implementation is the one already on the user's PATH, so behaviour matches their shell exactly. Workspace lifecycle mutations stay in `com.blockether.vis.internal.workspace`.
(cached-working-tree-status)(cached-working-tree-status start)(cached-working-tree-status now-ms ttl-ms)(cached-working-tree-status start now-ms ttl-ms)Cached working-tree-status for hot render paths.
Stale-while-revalidate: the TUI footer repaints often, so this NEVER shells out to git on the caller's (render) thread. It returns the last resolved value instantly and refreshes in the background when the 15s TTL lapses, so a footer repaint costs a cache read, not a git walk. Keyed by cwd so every UI namespace shares one resolved view.
Cached `working-tree-status` for hot render paths. Stale-while-revalidate: the TUI footer repaints often, so this NEVER shells out to git on the caller's (render) thread. It returns the last resolved value instantly and refreshes in the background when the 15s TTL lapses, so a footer repaint costs a cache read, not a git walk. Keyed by cwd so every UI namespace shares one resolved view.
(cwd-file)Canonical current working directory as a File. Indirected for tests.
Canonical current working directory as a File. Indirected for tests.
(file-dirty? f)True when f is a TRACKED file carrying UNCOMMITTED changes — modified in
the worktree, staged, deleted/missing, or conflicting. An UNTRACKED
(brand-new) file is NOT dirty (write is how you create one) and a clean
tracked file is fine. Repo-less / nil-safe → false.
True when `f` is a TRACKED file carrying UNCOMMITTED changes — modified in the worktree, staged, deleted/missing, or conflicting. An UNTRACKED (brand-new) file is NOT dirty (write is how you create one) and a clean tracked file is fine. Repo-less / nil-safe → false.
(git-status-snapshot top)One-shot status + ignore snapshot for the repo containing top (a
work-tree File). Returns a map the file picker indexes into:
{:repo-root <File> :path-status {<repo-rel-path> <kw ∈ #{:conflict :deleted :modified :added :untracked}>} :ignored-exact #{<repo-rel-path> …} :ignored-prefixes ["dir/" …]}
One-shot status + ignore snapshot for the repo containing `top` (a
work-tree File). Returns a map the file picker indexes into:
{:repo-root <File>
:path-status {<repo-rel-path> <kw ∈ #{:conflict :deleted :modified
:added :untracked}>}
:ignored-exact #{<repo-rel-path> …}
:ignored-prefixes ["dir/" …]}(in-repository? start)True when start is inside a git repository.
True when `start` is inside a git repository.
(porcelain-tokens dir {:keys [ignored? untracked-all?]})Structured status of the repo containing dir, or nil when dir is outside
a repo / git is unavailable. Options: :ignored? adds ! entries,
:untracked-all? recurses untracked dirs into individual files.
Returns {:branch <str> :head <sha|nil> :detached? bool :upstream? bool :ahead <int> :behind <int> :entries [{:x :y :type :path :dir?}]}.
Structured status of the repo containing `dir`, or nil when `dir` is outside
a repo / git is unavailable. Options: `:ignored?` adds `!` entries,
`:untracked-all?` recurses untracked dirs into individual files.
Returns {:branch <str> :head <sha|nil> :detached? bool :upstream? bool
:ahead <int> :behind <int> :entries [{:x :y :type :path :dir?}]}.(repo-name start)Human label for the repository containing start — its top-level dir name.
Human label for the repository containing `start` — its top-level dir name.
(repo-work-tree start)Canonical work-tree directory (top level) of the repository containing
start, or nil when start is outside any git repo.
Canonical work-tree directory (top level) of the repository containing `start`, or nil when `start` is outside any git repo.
(run-git dir args)(run-git dir args {:keys [timeout-secs]})Run git <args> in dir (a File). args is a seq of stringable tokens.
Returns {:exit <int|nil> :out <stdout> :err <stderr> :duration-ms <long>};
:exit is nil when the process could not be spawned or timed out. Never
throws — repo-less and git-less environments degrade to {:exit nil …}.
The 3-arity opts map takes :timeout-secs (default 10).
Run `git <args>` in `dir` (a File). `args` is a seq of stringable tokens.
Returns `{:exit <int|nil> :out <stdout> :err <stderr> :duration-ms <long>}`;
`:exit` is nil when the process could not be spawned or timed out. Never
throws — repo-less and git-less environments degrade to `{:exit nil …}`.
The 3-arity opts map takes `:timeout-secs` (default 10).(seed-working-tree-status! start)Synchronously resolve and publish the working-tree status for start into
the shared cache, so the FIRST render after a root switch shows the NEW
repo instead of a blank/"No git" frame.
cached-working-tree-status is stale-while-revalidate: on a cache MISS
(a cwd it hasn't seen) it returns nil immediately and refreshes in the
background — correct for the hot repaint path, but it means a /root
switch paints the wrong repo (or "No git") for one refresh cycle. A root
switch is a rare, user-initiated event (not per-frame), so paying one
synchronous ~2ms git walk HERE — on the dispatch thread, never the render
thread — is the right trade: the next footer paint is already warm.
No-op outside a git repo (publishes {:workspace? false}). Never throws.
Synchronously resolve and publish the working-tree status for `start` into
the shared cache, so the FIRST render after a root switch shows the NEW
repo instead of a blank/"No git" frame.
`cached-working-tree-status` is stale-while-revalidate: on a cache MISS
(a cwd it hasn't seen) it returns nil immediately and refreshes in the
background — correct for the hot repaint path, but it means a `/root`
switch paints the wrong repo (or "No git") for one refresh cycle. A root
switch is a rare, user-initiated event (not per-frame), so paying one
synchronous ~2ms git walk HERE — on the dispatch thread, never the render
thread — is the right trade: the next footer paint is already warm.
No-op outside a git repo (publishes `{:workspace? false}`). Never throws.(status-counts porcelain)Detailed, environment-facing counters from a parsed porcelain map (as returned by the private status reader). Mirrors the historical JGit shape.
Detailed, environment-facing counters from a parsed porcelain map (as returned by the private status reader). Mirrors the historical JGit shape.
(status-snapshot start)Read branch, head and porcelain-like entries for start via git.
Read branch, head and porcelain-like entries for `start` via git.
(vcs-kind root)The :vcs/kind for a workspace root: :git when the root sits inside a
git repository, else :none. Single source of truth so the model-facing
CTX, the env, and channels all agree — staying inside the ctx-spec set
#{:git :hg :jj :fossil :none}. NOTE: :rift (the CoW-clone sandbox
mechanism) is NOT a VCS and must never appear here; sandbox-ness lives on
:workspace/sandbox?.
The `:vcs/kind` for a workspace `root`: `:git` when the root sits inside a
git repository, else `:none`. Single source of truth so the model-facing
CTX, the env, and channels all agree — staying inside the ctx-spec set
#{:git :hg :jj :fossil :none}. NOTE: `:rift` (the CoW-clone sandbox
mechanism) is NOT a VCS and must never appear here; sandbox-ness lives on
`:workspace/sandbox?`.(working-tree-status)(working-tree-status start)Return git facts for start (default cwd).
Outside git, returns {:workspace? false} so callers can explicitly render
the absence of a workspace. Inside git, returns:
{:workspace? true :repo <repo-name> :branch <branch-name> :modified 2 :created 1 :deleted 0 :upstream? true :ahead 4 :behind 0}
Return git facts for `start` (default cwd).
Outside git, returns `{:workspace? false}` so callers can explicitly render
the absence of a workspace. Inside git, returns:
{:workspace? true
:repo <repo-name>
:branch <branch-name>
:modified 2 :created 1 :deleted 0
:upstream? true :ahead 4 :behind 0}cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |