Archived
Make the superproject selectable via the header
The header stands for the root repository: it is selected on startup, shows the root's own state word, and the detail pane shows its state like a submodule's (HEAD vs. upstream, changes, unpushed, leftover submodule clones as untracked repositories). Submodules are ignored in the root's changes; their rows show them. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
+2
-1
@@ -1,7 +1,8 @@
|
||||
# submarine — documentation
|
||||
|
||||
submarine is a terminal UI for git repositories with many (recursively nested)
|
||||
submodules. It shows **only the submodules**, as a collapsible tree, and
|
||||
submodules. It shows **the submodules**, as a collapsible tree (plus the state
|
||||
of the superproject itself in the header), and
|
||||
describes each pin as a **branch plus distance** (`origin/main ↓1`) instead of a
|
||||
bare commit hash.
|
||||
|
||||
|
||||
@@ -258,3 +258,27 @@ one word, D3). It is not counted in `+n`, because `+n` and the header count
|
||||
issues and a staged pin stays quiet (D4). A collapsed row shows `●` if a
|
||||
staged pin is hidden below it (`Hidden.Staged`), placed before the `·k`
|
||||
counts so truncation of the 16-column cell cuts the counts first.
|
||||
|
||||
## Superproject is selectable in the header
|
||||
|
||||
The state of the root repository was invisible: a submodule the current
|
||||
branch no longer has stays on disk as an untracked repository, root files
|
||||
can be modified, HEAD can be unpushed. The root becomes a node with an
|
||||
empty path (the convention `Fetcher`/`Change` already use), selected on
|
||||
startup, and the **header** is its row: it already holds the root's path,
|
||||
branch and ahead/behind, and a tree row would cost a line and an indent
|
||||
level for an item that is not part of the tree. Selecting the header shows
|
||||
the usual detail pane; the header also shows the root's state word, so a
|
||||
problem is visible while a submodule is selected.
|
||||
|
||||
- *Changes ignore submodules* (`--ignore-submodules=all`): off-pin and staged
|
||||
pins already have their rows; counting them again would make the root
|
||||
`changed` in most real repositories.
|
||||
- *Unpushed stays Danger*: same issue kind and level as a submodule, one
|
||||
rule for "work that exists only here" (D4).
|
||||
- *The ref is the upstream*, not the closest branch: the header shows
|
||||
ahead/behind of the upstream, and "up to date" means relative to the
|
||||
tracked branch. A nearer feature branch would make the two disagree.
|
||||
Without an upstream the usual resolution applies.
|
||||
- The root is not in `Walk`, so counts, fetch and loading logic stay
|
||||
submodule-only; the app tracks it by the path `""`.
|
||||
|
||||
+14
-4
@@ -11,7 +11,8 @@ commit hashes. It doesn't answer the questions users actually have:
|
||||
|
||||
## Goals
|
||||
|
||||
- Show **only submodules** (not files), recursively nested, as a tree.
|
||||
- Show **only submodules** (not files), recursively nested, as a tree; the
|
||||
superproject itself is shown by the header, which is selectable.
|
||||
- Describe pins as **ref + distance** instead of a commit hash.
|
||||
- Let **problems stand out** and keep healthy submodules quiet.
|
||||
- Work comfortably with **dozens to hundreds** of submodules.
|
||||
@@ -56,7 +57,7 @@ commit hashes. It doesn't answer the questions users actually have:
|
||||
|
||||
### Detail pane
|
||||
|
||||
- **F20** Shows the selected submodule: full path, name, all issues in
|
||||
- **F20** Shows the selected submodule (or the superproject): full path, name, all issues in
|
||||
words, staged-pin and detached-HEAD notes.
|
||||
- **F21** Shows the resolved ref, how it was resolved, and three commits:
|
||||
**Pinned**, **Checkout** and **Tip** (SHA + subject). A checkout that
|
||||
@@ -72,10 +73,19 @@ commit hashes. It doesn't answer the questions users actually have:
|
||||
shown; the rest is summarized as "n more" with their kinds. Staged and
|
||||
unstaged changes are combined.
|
||||
|
||||
- **F25** The superproject is selectable (the header; selected on startup)
|
||||
and has a state of its own, so a stale checkout shows up: files changed
|
||||
or untracked, untracked repositories (e.g. a submodule clone the current
|
||||
branch no longer has), conflicts, and HEAD not pushed. Its HEAD is compared
|
||||
with the upstream of the branch. Submodules do not count for it, their rows
|
||||
show them. The detail pane shows it like a submodule (HEAD and Tip instead
|
||||
of Pinned and Checkout, a summary of all submodules instead of Children).
|
||||
See [state-model.md](state-model.md#superproject).
|
||||
|
||||
### Header and footer
|
||||
|
||||
- **F30** The header shows the superproject path, its branch and
|
||||
ahead/behind, the number of submodules, a count per issue kind (most
|
||||
ahead/behind, its own state word (**F25**), the number of submodules, a count per issue kind (most
|
||||
severe first), staged pins, how many are still loading, and the time since
|
||||
the last fetch.
|
||||
- **F31** The footer shows key hints; `?` toggles the full help. It
|
||||
@@ -108,7 +118,7 @@ commit hashes. It doesn't answer the questions users actually have:
|
||||
A text input above the footer takes the term; `esc` closes it and removes
|
||||
the filter. A selection that is filtered out moves to the next visible
|
||||
submodule (none if nothing matches); closing the filter keeps the
|
||||
selection. See [Filter](ux-guide.md#filter).
|
||||
selection (the superproject if none is left). See [Filter](ux-guide.md#filter).
|
||||
|
||||
### Actions (planned, not implemented)
|
||||
|
||||
|
||||
@@ -103,6 +103,24 @@ per level, red first, then yellow, so a danger can never hide inside a
|
||||
collapsed subtree and a warning is never mistaken for one.
|
||||
A descendant whose load failed (`error`) counts as one danger.
|
||||
|
||||
## Superproject
|
||||
|
||||
The superproject is a node with an empty `Path` (`Repo.Root`, no children;
|
||||
`Submodule.IsRoot()`) and a `Status` with `Root` set. It reuses the pin
|
||||
fields with **pin = HEAD**: `Pinned` and `CheckedOut` are HEAD, `Checkout`
|
||||
is never `CheckoutDiffers` (`CheckoutDetached` for a detached HEAD),
|
||||
`PinStaged` is false. `Issues()` is the same code; only `unpushed` says
|
||||
"HEAD not pushed to any remote" (Danger, like a submodule's pin).
|
||||
|
||||
- **Ref** is the upstream of the current branch (`RefFromCurrentBranch`), so
|
||||
ahead/behind agrees with the header. Closest-branch resolution is only the
|
||||
fallback without an upstream (detached, or no upstream configured).
|
||||
- **Changes** ignore submodules (`status --ignore-submodules=all`): an off-pin
|
||||
or staged submodule is shown by its own row, not twice. A leftover
|
||||
directory of a submodule the branch no longer has is an untracked
|
||||
repository.
|
||||
- `Walk` and the header counts do not include the root.
|
||||
|
||||
## Resolving a pin to a ref
|
||||
|
||||
The pin is displayed as a ref, not a hash. A commit can be on several
|
||||
|
||||
+19
-7
@@ -75,6 +75,11 @@ indent ▸ name [n] status ref delta
|
||||
|
||||
### Detail pane
|
||||
|
||||
For the superproject (header selected), `Pinned` / `Checkout` become one
|
||||
`HEAD` line, the commit list says "HEAD is n commits behind …", and
|
||||
`Children` becomes `Modules` (count and issues of all submodules). See
|
||||
[Superproject](state-model.md#superproject).
|
||||
|
||||
1. Directory (muted) and name (bold)
|
||||
2. One line per issue: word (colored, 10 columns) + explanation;
|
||||
`in sync nothing to do` if there are none and no pin is staged;
|
||||
@@ -136,7 +141,13 @@ Changes 5 files · 2M 1A 1D 1R · +37 −12
|
||||
- Untracked directories are shown as one entry (`tmp/`).
|
||||
### Header
|
||||
|
||||
`path branch ↑↓ · n submodules · n error · <count> <issue>… · n pin staged · n loading · <fetch>`
|
||||
The header is the superproject's row: it is selected on startup and drawn
|
||||
with the selected background (bold) while selected. After the branch it
|
||||
shows the superproject's own state word like a tree row (`in sync`,
|
||||
`changed`, `unpushed +1`, spinner, `error`). The counts that follow are
|
||||
about submodules only.
|
||||
|
||||
`path branch ↑↓ state · n submodules · n error · <count> <issue>… · n pin staged · n loading · <fetch>`
|
||||
|
||||
Issue counts are ordered by severity (unpushed, conflict, missing, off pin,
|
||||
changed), each in its level color. Zero counts are omitted. `n loading`
|
||||
@@ -195,13 +206,13 @@ colors in components.
|
||||
|
||||
| Key | Behavior |
|
||||
|---|---|
|
||||
| `↑` / `k`, `↓` / `j` | Previous / next submodule; directory headers are skipped |
|
||||
| `↑` / `k`, `↓` / `j` | Previous / next submodule; directory headers are skipped. `↑` from the first submodule selects the header (superproject) |
|
||||
| `space` | Toggle expand/collapse of the selected submodule |
|
||||
| `→` / `l` | Collapsed with children: expand and select the first child. Expanded: select the first child. Leaf: nothing |
|
||||
| `←` / `h` | Expanded: collapse it (stays selected). Otherwise: collapse the parent and select it. Top level: nothing |
|
||||
| `→` / `l` | Header selected: first submodule. Collapsed with children: expand and select the first child. Expanded: select the first child. Leaf: nothing |
|
||||
| `←` / `h` | Expanded: collapse it (stays selected). Otherwise: collapse the parent and select it. Top level: select the header (superproject) |
|
||||
| `L` / `shift+→` / `ctrl+→` | Expand all; then follow the first child from the selection down to a submodule without children |
|
||||
| `H` / `shift+←` / `ctrl+←` | Collapse all (resets remembered expansion); select the top-level ancestor |
|
||||
| `home` / `g`, `end` / `G` | First / last submodule |
|
||||
| `home` / `g`, `end` / `G` | Header (superproject) / last submodule |
|
||||
| `pgup`, `pgdn` | Move by one screen |
|
||||
| `?` | Toggle full help |
|
||||
| `q`, `ctrl+c` | Quit |
|
||||
@@ -235,6 +246,7 @@ match vanish. If nothing matches the tree says `no submodule matches`.
|
||||
`/` edits the term again.
|
||||
- **`esc`** closes the input and removes the filter, in both modes. The
|
||||
selection stays; its ancestors are expanded so it is still visible.
|
||||
- The superproject is never filtered out; if nothing matches it is selected.
|
||||
- The filter line shows the keys that apply on its right.
|
||||
- The header counts are not filtered.
|
||||
|
||||
@@ -252,7 +264,7 @@ where the palette can't be shown, see [Key bar and palette](#key-bar-and-palette
|
||||
| `←` / `h`, `→` / `l` | Fold / unfold, parent / first child | Navigation | Bar, Help | yes |
|
||||
| `H` / `⇧←`, `L` / `⇧→` | Collapse / expand all | Navigation | Bar, Help | yes |
|
||||
| `space` | Toggle expand/collapse | Navigation | Bar, Help | yes |
|
||||
| `home` / `g`, `end` / `G` | First / last submodule | Navigation | Help | yes |
|
||||
| `home` / `g`, `end` / `G` | Header / last submodule | Navigation | Help | yes |
|
||||
| `pgup`, `pgdn` | Move by one screen | Navigation | Help | yes |
|
||||
| `c` | Copy path | Submodule | Palette, Help | yes |
|
||||
| `u` | Checkout pin | Submodule | Help | no (flashes "not implemented") |
|
||||
@@ -266,7 +278,7 @@ where the palette can't be shown, see [Key bar and palette](#key-bar-and-palette
|
||||
|
||||
### Mouse
|
||||
|
||||
- Click a row: select it.
|
||||
- Click a row: select it. Click the header: select the superproject.
|
||||
- Click `▸` / `▾`: select and toggle.
|
||||
- Scroll wheel: move the selection.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user