Archived
Preview uncommitted changes in the detail pane
For a dirty submodule, list the changed files so the user can remember
what they were doing there:
Changes 5 files · 2M 1A 1D 1R · +37 −12
──────────────────────────────────
M render.go src/render/ +20 −4 3d ago
? scratch.txt 5m ago
- Status.Changes: files changed against HEAD (staged and unstaged
combined) with kind, line counts and modification time; sorted by kind,
then by size; capped at 200 with totals over all files.
- Git provider: parse `status --porcelain=v2 -z` and one
`diff HEAD --numstat -z -M`, only for dirty submodules.
- Detail pane: flat list with a colored status letter per file, like IDE
source-control views; counts and age in compact columns; up to 10 files,
every kind keeps a line, the rest is summarized as "n more".
- Fixture gains libs/work with every kind of change; mock data extended.
- Docs: F24, change preview in the UX guide, D17.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
64fe34b5b0
commit
19c6f17eb2
@@ -0,0 +1,65 @@
|
||||
package detail
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"submarine/internal/submodule"
|
||||
)
|
||||
|
||||
func files(kind submodule.ChangeKind, n int) []submodule.FileChange {
|
||||
var fs []submodule.FileChange
|
||||
for i := range n {
|
||||
fs = append(fs, submodule.FileChange{Path: fmt.Sprintf("%d-%d", kind, i), Kind: kind})
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
func TestPickPreview(t *testing.T) {
|
||||
t.Run("fits", func(t *testing.T) {
|
||||
all := append(files(submodule.ChangeModified, 2), files(submodule.ChangeUntracked, 1)...)
|
||||
shown, hidden := pickPreview(all, 5)
|
||||
if len(shown) != 3 || len(hidden) != 0 {
|
||||
t.Errorf("shown %d, hidden %d; want 3, 0", len(shown), len(hidden))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("one over the budget shows all", func(t *testing.T) {
|
||||
shown, hidden := pickPreview(files(submodule.ChangeModified, 6), 5)
|
||||
if len(shown) != 6 || len(hidden) != 0 {
|
||||
t.Errorf("shown %d, hidden %d; want 6, 0", len(shown), len(hidden))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("every kind keeps a line", func(t *testing.T) {
|
||||
all := files(submodule.ChangeModified, 8)
|
||||
all = append(all, files(submodule.ChangeRemoved, 1)...)
|
||||
all = append(all, files(submodule.ChangeUntracked, 3)...)
|
||||
shown, hidden := pickPreview(all, 4)
|
||||
if len(shown) != 4 || len(hidden) != 8 {
|
||||
t.Fatalf("shown %d, hidden %d; want 4, 8", len(shown), len(hidden))
|
||||
}
|
||||
want := []string{"1-0", "1-1", "3-0", "5-0"} // sort order is kept
|
||||
for i, f := range shown {
|
||||
if f.Path != want[i] {
|
||||
t.Errorf("shown[%d] = %q, want %q (all: %+v)", i, f.Path, want[i], shown)
|
||||
}
|
||||
}
|
||||
if n := (&submodule.Changes{}).Counts(hidden); n[submodule.ChangeModified] != 6 || n[submodule.ChangeUntracked] != 2 {
|
||||
t.Errorf("hidden counts = %v", n)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSplitPath(t *testing.T) {
|
||||
for _, tt := range []struct{ in, name, dir string }{
|
||||
{"README.md", "README.md", ""},
|
||||
{"src/a/b.go", "b.go", "src/a/"},
|
||||
{"tmp/", "tmp/", ""},
|
||||
{"src/tmp/", "tmp/", "src/"},
|
||||
} {
|
||||
if name, dir := splitPath(tt.in); name != tt.name || dir != tt.dir {
|
||||
t.Errorf("splitPath(%q) = %q, %q; want %q, %q", tt.in, name, dir, tt.name, tt.dir)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user