feat: status-bar indicator when the graph is unsynced #19

Merged
fiatcode merged 2 commits from feat/sync-status-indicator into main 2026-06-17 18:48:54 +07:00
Owner

The natural companion to in-app sync (#17): instead of having to remember to press S, weft now shows you when there's something to sync.

What it does

A single attention dot (, yellow) appears on the right of the status bar whenever the graph work tree is dirty (uncommitted changes) or ahead of its upstream (committed but unpushed). It's hidden when the graph is clean and in-sync, when the dir isn't a git repo, and while a transient hint (e.g. ✓ synced) occupies the right side.

Design

  • internal/sync.Status(repoDir) — a read-only sibling of Run: git status --porcelain (dirty) + rev-list --count @{u}..HEAD (ahead). Returns an error only for a non-repo (callers treat that as "no indicator"). No network fetch — ahead is measured against the local upstream ref only, so "behind remote" is deliberately out of scope.
  • Event-driven, never polled. The probe runs as a tea.Cmd at the moments git state can actually change: boot, every reindex (R / $EDITOR / editor-exit-saved), in-app save, journal creation, linkify, and after a sync (success and failure). No timer, no per-keystroke cost.
  • Injectable. App.statusProbe defaults to sync.Status but is stubbed in view tests, so no view test shells out to git.

Tests

  • internal/sync: Status against throwaway repos (clean/dirty/ahead/non-repo), CI-safe (local git identity).
  • internal/views: stubbed-probe round-trip for dirty/ahead/clean/error states, dot-hidden-under-hint, and the $EDITOR-exit-refreshes-even-when-unchanged path (catches a journal stub created for E).

go vet ./... && go test ./... green (7 packages). A pre-PR review caught two gaps in the $EDITOR path (stale dot after a journal stub; a dropped cmd in save+exit) — both fixed and covered.

Notes

  • Refreshes only on those discrete events, so an external edit while weft sits idle won't light the dot until the next save/sync/reindex (R doubles as a manual re-check). That's the intended trade — no background polling.
  • Not documented in the help overlay (it's an indicator, not a keybind); say the word if you'd like a legend line added.
The natural companion to in-app sync (#17): instead of having to *remember* to press `S`, weft now *shows* you when there's something to sync. ## What it does A single attention dot (`●`, yellow) appears on the right of the status bar whenever the graph work tree is **dirty** (uncommitted changes) or **ahead** of its upstream (committed but unpushed). It's hidden when the graph is clean and in-sync, when the dir isn't a git repo, and while a transient hint (e.g. `✓ synced`) occupies the right side. ## Design - **`internal/sync.Status(repoDir)`** — a read-only sibling of `Run`: `git status --porcelain` (dirty) + `rev-list --count @{u}..HEAD` (ahead). Returns an error only for a non-repo (callers treat that as "no indicator"). **No network fetch** — ahead is measured against the *local* upstream ref only, so "behind remote" is deliberately out of scope. - **Event-driven, never polled.** The probe runs as a `tea.Cmd` at the moments git state can actually change: boot, every reindex (`R` / `$EDITOR` / editor-exit-saved), in-app save, journal creation, linkify, and after a sync (success *and* failure). No timer, no per-keystroke cost. - **Injectable.** `App.statusProbe` defaults to `sync.Status` but is stubbed in view tests, so no view test shells out to git. ## Tests - `internal/sync`: `Status` against throwaway repos (clean/dirty/ahead/non-repo), CI-safe (local git identity). - `internal/views`: stubbed-probe round-trip for dirty/ahead/clean/error states, dot-hidden-under-hint, and the `$EDITOR`-exit-refreshes-even-when-unchanged path (catches a journal stub created for `E`). `go vet ./... && go test ./...` green (7 packages). A pre-PR review caught two gaps in the `$EDITOR` path (stale dot after a journal stub; a dropped cmd in save+exit) — both fixed and covered. ## Notes - Refreshes only on those discrete events, so an *external* edit while weft sits idle won't light the dot until the next save/sync/reindex (`R` doubles as a manual re-check). That's the intended trade — no background polling. - Not documented in the help overlay (it's an indicator, not a keybind); say the word if you'd like a legend line added.
feat: status-bar indicator when the graph is unsynced
All checks were successful
CI / vet-and-test (pull_request) Successful in 36s
7dc671e5b1
Add a read-only sync.Status probe (the sibling of sync.Run) reporting whether
the graph work tree is dirty or ahead of upstream, and surface it as a single
attention dot (●) on the right of the status bar. The dot shows whenever there
are uncommitted changes or unpushed commits, and is hidden when clean,
in-sync, not a git repo, or while a transient hint occupies the right side.

The probe runs as a tea.Cmd at the moments git state can change — boot, every
reindex (R / $EDITOR / editor-exit), in-app save, journal creation, linkify,
and after a sync — never on a timer or per-keystroke, and never fetches from
the remote. The probe is injected on App so view tests stub it instead of
shelling out to git; sync.Status is tested against throwaway repos.
test: structure sync-indicator tests as arrange/act/assert
All checks were successful
CI / vet-and-test (pull_request) Successful in 25s
c043379ac1
Reorganize the tests added in this PR around explicit // Arrange, // Act,
// Assert sections and tidy them for readability:
- status_test.go: add a writeFile helper to drop the os.WriteFile+err noise.
- app_status_test.go: rename runProbe→stubProbe (clearer intent), AAA layout.
- edit_test.go: AAA layout for the two editor-exit tests touched here.
No behavior change.
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
fiatcode/weft!19
No description provided.