Skip to content

refactor(widgets): share one base class across the Git status indicator widgets - #651

Merged
sirmalloc merged 5 commits into
sirmalloc:mainfrom
eric-engberg:refactor/git-status-widget-duplication
Oct 6, 2026
Merged

sirmalloc merged 5 commits into
sirmalloc:mainfrom
eric-engberg:refactor/git-status-widget-duplication

Conversation

@eric-engberg

@eric-engberg eric-engberg commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

#499 and #594 also touch these files; happy to rebase either way. A sibling PR, #654, does the same for the Git count widgets; the two touch different files, so either can go first.

Demo

After the refactor: in the line editor, g sets Git Staged's glyph and r switches it to its raw value, r switches Git Clean Status to clean, g changes Git Status's staged glyph, and h hides Git SHA outside a repository. Every case also renders byte-for-byte the same as before; see Testing.

Powerline

Editing glyphs, raw values and the hide state of the Git status widgets in Powerline mode

Plain

Editing glyphs, raw values and the hide state of the Git status widgets in plain mode

The same six widgets piped from a real repository with staged, unstaged and untracked changes, a clean one, and a directory outside any repository:

Powerline

The Git status widgets reading a dirty repository, a clean one and a non-repository in Powerline mode

Plain

The Git status widgets reading a dirty repository, a clean one and a non-repository in plain mode

Summary

Git Staged, Unstaged, Untracked, Clean Status, Status and SHA each carried their own copy of:

  • the editor label and the "when not in a git repo" hide state;
  • the start of render: the preview sample, then (no git) outside a work tree, or nothing when that state is hidden.

Git Staged, Unstaged and Untracked were also one class written three times. They differed only in the change they watch for, their glyph, name and color.

GitStatusWidgetBase (widgets/shared/git-status-widget.ts) now holds the shared part. Each widget says what it shows in the preview and inside a work tree, and keeps its own git query. GitStatusFlagWidget adds the single-glyph rendering, the raw true, the glyph editor and the numeric value on top, so Git Staged, Unstaged and Untracked only name their change and glyph. A change to how these widgets behave outside a repository is now made once instead of six times.

7 source files, 129 lines added and 314 removed, plus a test file. No visual change.

Testing

  • Git Staged, Unstaged, Untracked and SHA had no tests of their own, and Git Status only had preview tests. The first commit adds widgets/__tests__/GitStatusWidgets.test.ts (75 tests) and checks it against the current code before the refactor. It covers:

    • what each widget shows in the preview and in repositories with staged, unstaged, untracked and conflicted changes, a clean one and one with no commits yet, raw and labeled;
    • the (no git) placeholder and the hide state that drops it, and Git SHA's (no commit);
    • glyph overrides and the glyph editor's rows;
    • the editor label, hide state and keys, and the numeric value of Git Staged, Unstaged and Untracked.

    It passes at both commits under Bun and under Node. Breaking Git SHA's placeholder, Git Staged's editor default, Git Untracked's numeric value, Git Status's hide state or Git Clean Status's dirty glyph each makes it fail.

  • bun run lint and bun test (2,433 pass).

  • Before/after render check: all six widgets rendered on main and on this branch, in every state their own keys reach, raw and labeled, at all three color levels. It ran in the TUI preview and against seven real repositories: staged, unstaged and untracked changes; only staged; only untracked; a merge conflict; clean; no commits yet; and a directory outside any repository. All 462 cases (66 per repository) are byte-identical, as are each widget's editor label and keys. A wider sweep over the same repositories also varied the hide states, glyph overrides (set and emptied) and raw value (on, off, unset): all 4,320 renders are identical, as are each widget's numeric value, hide states, keys and glyph-editor rows.

  • Built dist/ and piped a status line with all six widgets through it, from the dirty and the clean repository, in plain and Powerline mode under Bun and Node 16, 18, 20, 22, 24 and 26: every runtime agrees, and the output matches main. The TUI opens and exits cleanly on each.

  • Under Node with Vitest, the full suite fails in the same 17 files as main (all from spying on Node built-ins), and the new tests pass.

Git Staged, Unstaged, Untracked and SHA had no tests of their own, and Git
Status only had preview tests. Cover what each of the six shows in the
preview and in repositories with staged, unstaged, untracked and conflicted
changes, a clean one and one with no commits yet, raw and labeled; the
"(no git)" placeholder and the hide state that drops it; Git SHA's
"(no commit)"; glyph overrides and the glyph editor's rows; the editor label,
hide state and keys; and the numeric value of the three single-flag widgets.
Git is answered by a mocked execFileSync, like the other Git widget tests.
…or widgets

Git Staged, Unstaged, Untracked, Clean Status, Status and SHA each carried the
same editor label, "no git" hide state and render prologue: the preview
sample, then "(no git)" outside a work tree, or nothing when that state is
hidden. Git Staged, Unstaged and Untracked were also the same class apart from
the change they watch for, their glyph, name and color.

GitStatusWidgetBase now holds the shared part; each widget says what it shows
in the preview and inside a work tree. GitStatusFlagWidget adds the
single-glyph rendering, raw "true", glyph editor and numeric value on top, so
those three widgets only name their change and glyph.

Behavior is unchanged.
@sirmalloc
sirmalloc merged commit e99c9e0 into sirmalloc:main Oct 6, 2026
3 checks passed
@eric-engberg
eric-engberg deleted the refactor/git-status-widget-duplication branch October 9, 2026 21:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants