Archived
Show staged pins in the tree
A staged pin was only visible in the detail pane, so the header's "n pin staged" could not be traced to a row. The status column now shows a blue "staged" instead of "in sync", a blue marker after an issue word, and the marker on collapsed rows with a staged pin below. It is still not an issue and not counted in +n. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -60,13 +60,14 @@ func (s *Status) Issues() []Issue {
|
||||
return out
|
||||
}
|
||||
|
||||
// Hidden counts issues below a submodule per level.
|
||||
type Hidden struct{ Warn, Danger int }
|
||||
// Hidden counts issues below a submodule per level, plus staged pins (which
|
||||
// are not issues).
|
||||
type Hidden struct{ Warn, Danger, Staged int }
|
||||
|
||||
// Total is the number of issues of all levels.
|
||||
// Total is the number of issues of all levels; staged pins are not counted.
|
||||
func (h Hidden) Total() int { return h.Warn + h.Danger }
|
||||
|
||||
// HiddenIssues counts the issues of all loaded descendants per level. A
|
||||
// HiddenIssues counts the issues and staged pins of all loaded descendants. A
|
||||
// descendant whose load failed counts as one danger, since its state is
|
||||
// unknown.
|
||||
func (m *Submodule) HiddenIssues() Hidden {
|
||||
@@ -75,6 +76,9 @@ func (m *Submodule) HiddenIssues() Hidden {
|
||||
if c.Status == nil && c.Err != nil {
|
||||
h.Danger++
|
||||
}
|
||||
if c.Status != nil && c.Status.PinStaged {
|
||||
h.Staged++
|
||||
}
|
||||
for _, is := range c.Status.Issues() {
|
||||
switch is.Level {
|
||||
case LevelDanger:
|
||||
|
||||
@@ -39,15 +39,15 @@ func TestIssues(t *testing.T) {
|
||||
|
||||
func TestHiddenIssues(t *testing.T) {
|
||||
ok := &Status{Pin: PinInfo{Pushed: true}}
|
||||
dirty := &Status{Worktree: WorktreeModified, Pin: PinInfo{Pushed: true}}
|
||||
dirty := &Status{Worktree: WorktreeModified, Pin: PinInfo{Pushed: true}, PinStaged: true}
|
||||
unpushed := &Status{}
|
||||
grandchild := &Submodule{Status: unpushed}
|
||||
child := &Submodule{Status: dirty, Children: []*Submodule{grandchild}}
|
||||
loading := &Submodule{}
|
||||
root := &Submodule{Status: ok, Children: []*Submodule{child, {Status: ok}, loading}}
|
||||
|
||||
if got := root.HiddenIssues(); got != (Hidden{Warn: 1, Danger: 1}) {
|
||||
t.Errorf("HiddenIssues() = %+v; want 1 warn, 1 danger", got)
|
||||
if got := root.HiddenIssues(); got != (Hidden{Warn: 1, Danger: 1, Staged: 1}) {
|
||||
t.Errorf("HiddenIssues() = %+v; want 1 warn, 1 danger, 1 staged", got)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -97,11 +97,11 @@ func (m Model) lines(s *submodule.Submodule) []string {
|
||||
for _, is := range issues {
|
||||
out = append(out, t.LevelStyle(is.Level, lipgloss.NewStyle()).Width(labelWidth).Render(theme.IssueWord(is.Kind))+text.Render(is.Detail))
|
||||
}
|
||||
if len(issues) == 0 {
|
||||
if len(issues) == 0 && !st.PinStaged {
|
||||
out = append(out, label(theme.InSync)+muted.Render("nothing to do"))
|
||||
}
|
||||
if st.PinStaged {
|
||||
out = append(out, theme.Fg(t.Info).Width(labelWidth).Render("staged")+text.Render("pin change staged, not committed"))
|
||||
out = append(out, theme.Fg(t.Info).Width(labelWidth).Render(theme.Staged)+text.Render("pin change staged, not committed"))
|
||||
}
|
||||
if st.Checkout == submodule.CheckoutDetached {
|
||||
out = append(out, label("")+muted.Render("detached HEAD on pin"))
|
||||
@@ -170,6 +170,9 @@ func (m Model) lines(s *submodule.Submodule) []string {
|
||||
if h.Warn > 0 {
|
||||
parts = append(parts, t.LevelStyle(submodule.LevelWarn, lipgloss.NewStyle()).Render(fmt.Sprintf("%d warning(s)", h.Warn)))
|
||||
}
|
||||
if h.Staged > 0 {
|
||||
parts = append(parts, theme.Fg(t.Info).Render(fmt.Sprintf("%d %s", h.Staged, theme.Staged)))
|
||||
}
|
||||
if len(parts) > 0 {
|
||||
children += muted.Render(" · ") + strings.Join(parts, muted.Render(", ")) + muted.Render(" below")
|
||||
}
|
||||
|
||||
@@ -12,6 +12,10 @@ import (
|
||||
// InSync is the word for a submodule without issues.
|
||||
const InSync = "in sync"
|
||||
|
||||
// Staged is the word for a pin change staged in the superproject. It is not
|
||||
// an issue: it replaces InSync, or follows an issue word as a marker.
|
||||
const Staged = "staged"
|
||||
|
||||
// IssueWord is the short label for an issue kind shown in the tree.
|
||||
func IssueWord(k submodule.IssueKind) string {
|
||||
switch k {
|
||||
|
||||
@@ -410,7 +410,12 @@ func (m Model) nodeLine(r row, nameColW, refW int) string {
|
||||
nameCell := seg(textColor, name) + seg(t.Muted, count) + pad(nameW-lipgloss.Width(name+count))
|
||||
|
||||
// status: the most severe issue as a word, "+n" for further issues;
|
||||
// a muted "in sync" without issues, so an empty cell never looks broken
|
||||
// a muted "in sync" without issues, so an empty cell never looks broken.
|
||||
// A staged pin is no issue: it replaces "in sync", or follows the issue
|
||||
// as a blue marker (also for staged pins below a collapsed row).
|
||||
staged := s.Status != nil && s.Status.PinStaged
|
||||
h := s.HiddenIssues()
|
||||
stagedMark := staged && len(issues) > 0
|
||||
var status string
|
||||
switch {
|
||||
case s.Err != nil:
|
||||
@@ -422,10 +427,15 @@ func (m Model) nodeLine(r row, nameColW, refW int) string {
|
||||
if len(issues) > 1 {
|
||||
status += seg(t.Muted, fmt.Sprintf(" +%d", len(issues)-1))
|
||||
}
|
||||
case staged:
|
||||
status = seg(t.Info, theme.Staged)
|
||||
default:
|
||||
status = seg(t.Muted, theme.InSync)
|
||||
}
|
||||
if h := s.HiddenIssues(); collapsed && h.Total() > 0 {
|
||||
if stagedMark || collapsed && h.Staged > 0 {
|
||||
status += pad(1) + seg(t.Info, t.Glyphs.Staged)
|
||||
}
|
||||
if collapsed && h.Total() > 0 {
|
||||
for _, c := range []struct {
|
||||
level submodule.Level
|
||||
n int
|
||||
|
||||
Reference in New Issue
Block a user