Show the containing directory instead of the full path in the recent repos menu

The third column of the recent repos menu spells out the full path of
each repo. That repeats the directory name which the first column
already shows, and it writes out the home directory in full. Both are
wasted width in a menu that is limited to 90 columns; the path column is
the first thing to run off the right edge, and users who don't know that
'L' scrolls the menu horizontally never see it at all.

Show the directory that contains the repo instead, with the home
directory abbreviated to '~'. For a list of 106 recent repos this takes
the column from 111 characters down to 97 at its longest, and from 47
down to 28 in the median.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Haller 2026-09-07 18:29:28 +02:00
parent 1e1d8a8fcd
commit bae4d4c035
3 changed files with 49 additions and 1 deletions

View file

@ -135,7 +135,10 @@ func (self *ReposHelper) CreateRecentReposMenu() error {
LabelColumns: []string{
filepath.Base(path),
style.FgCyan.Sprint(branchName),
style.FgMagenta.Sprint(path),
// The last segment of the path is already in the first column,
// so showing the directory that contains the repo is enough to
// tell repos with the same name apart.
style.FgMagenta.Sprint(utils.ContractTilde(filepath.Dir(path))),
},
OnPress: func() error {
// Check before clearing the stack, so a refused switch doesn't

View file

@ -120,3 +120,24 @@ func ExpandTilde(path string) string {
}
return filepath.Join(home, path[2:])
}
// ContractTilde is the inverse of ExpandTilde: it replaces the current user's
// home directory at the start of a path with "~", so that paths can be shown
// in a shorter form. Paths outside the home directory are left untouched, as
// is the path if the home directory can't be determined.
func ContractTilde(path string) string {
home, err := os.UserHomeDir()
if err != nil {
return path
}
if path == home {
return "~"
}
if rest, found := strings.CutPrefix(path, home+string(filepath.Separator)); found {
return "~" + string(filepath.Separator) + rest
}
return path
}

View file

@ -125,3 +125,27 @@ func TestExpandTilde(t *testing.T) {
})
}
}
func TestContractTilde(t *testing.T) {
home, err := os.UserHomeDir()
assert.NoError(t, err)
scenarios := []struct {
name string
path string
expected string
}{
{"home directory", home, "~"},
{"path inside the home directory", filepath.Join(home, "worktrees"), filepath.Join("~", "worktrees")},
{"path outside the home directory is untouched", filepath.Join("/absolute", "path"), filepath.Join("/absolute", "path")},
{"path merely starting with the home directory's name is untouched", home + "-backup", home + "-backup"},
{"relative path is untouched", filepath.Join("relative", "path"), filepath.Join("relative", "path")},
{"empty string is untouched", "", ""},
}
for _, s := range scenarios {
t.Run(s.name, func(t *testing.T) {
assert.Equal(t, s.expected, ContractTilde(s.path))
})
}
}