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
@@ -2,7 +2,12 @@
|
||||
// (recursively nested) git submodules. It has no UI dependencies.
|
||||
package submodule
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"cmp"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Repo is the superproject.
|
||||
type Repo struct {
|
||||
@@ -100,6 +105,68 @@ type Commit struct {
|
||||
When time.Time
|
||||
}
|
||||
|
||||
// ChangeKind classifies one changed file. The order is the display order.
|
||||
type ChangeKind int
|
||||
|
||||
const (
|
||||
ChangeConflicted ChangeKind = iota
|
||||
ChangeModified
|
||||
ChangeAdded
|
||||
ChangeRemoved
|
||||
ChangeRenamed
|
||||
ChangeUntracked
|
||||
NumChangeKinds
|
||||
)
|
||||
|
||||
// MaxChangeFiles limits Changes.Files; Changes.Total keeps the real count.
|
||||
const MaxChangeFiles = 200
|
||||
|
||||
// FileChange is one changed file, relative to HEAD of the submodule
|
||||
// (staged and unstaged changes are combined).
|
||||
type FileChange struct {
|
||||
Path string
|
||||
OrigPath string // old path, only for renames
|
||||
Kind ChangeKind
|
||||
Added int // added lines; 0 for untracked, binary and nested submodules
|
||||
Removed int // removed lines
|
||||
Binary bool // line counts are unknown
|
||||
Submodule bool // a nested submodule pointer changed
|
||||
Modified time.Time // modification time of the file; zero if it doesn't exist
|
||||
}
|
||||
|
||||
// Changes describes what differs in the worktree of a submodule.
|
||||
type Changes struct {
|
||||
Files []FileChange // at most MaxChangeFiles, sorted by kind, then by changed lines
|
||||
Total int // all changed files; may exceed len(Files)
|
||||
Added int // added lines in all files
|
||||
Removed int // removed lines in all files
|
||||
}
|
||||
|
||||
// Counts returns the number of files per kind among files (all of
|
||||
// c.Files if files is nil).
|
||||
func (c *Changes) Counts(files []FileChange) [NumChangeKinds]int {
|
||||
if files == nil && c != nil {
|
||||
files = c.Files
|
||||
}
|
||||
var n [NumChangeKinds]int
|
||||
for _, f := range files {
|
||||
n[f.Kind]++
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Sort orders Files by kind, then by changed lines (largest first), then by
|
||||
// path.
|
||||
func (c *Changes) Sort() {
|
||||
slices.SortStableFunc(c.Files, func(a, b FileChange) int {
|
||||
return cmp.Or(
|
||||
cmp.Compare(a.Kind, b.Kind),
|
||||
cmp.Compare(b.Added+b.Removed, a.Added+a.Removed),
|
||||
strings.Compare(a.Path, b.Path),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// Status is the full state of one submodule.
|
||||
type Status struct {
|
||||
Presence Presence
|
||||
@@ -111,4 +178,5 @@ type Status struct {
|
||||
CheckedOut *Commit
|
||||
Tip *Commit
|
||||
Between []Commit // commits that make up the pin <-> tip difference
|
||||
Changes *Changes // nil if the worktree is clean or the details are unknown
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user