diff --git a/pkg/gui/controllers/helpers/repos_helper.go b/pkg/gui/controllers/helpers/repos_helper.go index 19bdec135..463443137 100644 --- a/pkg/gui/controllers/helpers/repos_helper.go +++ b/pkg/gui/controllers/helpers/repos_helper.go @@ -103,29 +103,48 @@ func (self *ReposHelper) getCurrentBranch(path string) string { return self.c.Tr.BranchUnknown } -// The maximum width of the repo name and branch name columns of the recent -// repos menu. Without a limit, one long name pushes the path column off the -// right edge of the menu for every entry, because each column is padded to the -// width of its widest entry. -const recentReposColumnMaxWidth = 30 +// The maximum widths of the three columns of the recent repos menu. Each +// column is padded to the width of its widest entry, so without a limit one +// long entry pushes the columns after it off the right edge of the menu for +// every entry. The three widths plus the two spaces between the columns add up +// to the content width of a menu that is as wide as it gets, so that a whole +// row fits into it. +const ( + recentReposNameMaxWidth = 30 + recentReposBranchMaxWidth = 30 + // The menu's frame takes up two columns, and two more separate the three + // columns from each other. + recentReposPathMaxWidth = menuMaxWidth - 2 - 2 - recentReposNameMaxWidth - recentReposBranchMaxWidth +) func (self *ReposHelper) recentRepoMenuItem(path string, branchName string) *types.MenuItem { repoName := filepath.Base(path) - displayedRepoName := utils.TruncateWithEllipsis(repoName, recentReposColumnMaxWidth) + displayedRepoName := utils.TruncateWithEllipsis(repoName, recentReposNameMaxWidth) // The icon is part of the column, so it counts towards the maximum width. branchColumn := branchName if icons.IsIconEnabled() { branchColumn = icons.BRANCH_ICON + " " + branchName } - displayedBranchColumn := utils.TruncateWithEllipsis(branchColumn, recentReposColumnMaxWidth) + displayedBranchColumn := utils.TruncateWithEllipsis(branchColumn, recentReposBranchMaxWidth) + + // 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. Its beginning and its end are both worth seeing, so it + // loses its middle rather than its end when it doesn't fit. + dir := utils.ContractTilde(filepath.Dir(path)) + displayedDir := utils.TruncateWithEllipsisInMiddle(dir, recentReposPathMaxWidth) // Spell out whatever the columns show in truncated form. The labels are // padded to the same width no matter which of them appear, so that the // tooltip doesn't shift around as the selection moves. tooltipLines := []string{} labelWidth := utils.MaxFn( - []string{self.c.Tr.RecentReposRepoLabel, self.c.Tr.RecentReposBranchLabel}, + []string{ + self.c.Tr.RecentReposRepoLabel, + self.c.Tr.RecentReposBranchLabel, + self.c.Tr.RecentReposPathLabel, + }, utils.StringWidth) addTooltipLine := func(label string, value string) { tooltipLines = append(tooltipLines, @@ -138,15 +157,15 @@ func (self *ReposHelper) recentRepoMenuItem(path string, branchName string) *typ if displayedBranchColumn != branchColumn { addTooltipLine(self.c.Tr.RecentReposBranchLabel, branchName) } + if displayedDir != dir { + addTooltipLine(self.c.Tr.RecentReposPathLabel, utils.ContractTilde(path)) + } return &types.MenuItem{ LabelColumns: []string{ displayedRepoName, style.FgCyan.Sprint(displayedBranchColumn), - // 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))), + style.FgMagenta.Sprint(displayedDir), }, // Filtering matches the full text, including the parts that the columns // above truncate or leave out. diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 918247902..0f33d9bc0 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -334,6 +334,7 @@ type TranslationSet struct { RecentRepos string RecentReposRepoLabel string RecentReposBranchLabel string + RecentReposPathLabel string MergeOptionsTitle string RebaseOptionsTitle string CherryPickOptionsTitle string @@ -1494,6 +1495,7 @@ func EnglishTranslationSet() *TranslationSet { RecentRepos: "Recent repositories", RecentReposRepoLabel: "Repo:", RecentReposBranchLabel: "Branch:", + RecentReposPathLabel: "Path:", MergeOptionsTitle: "Merge options", RebaseOptionsTitle: "Rebase options", CherryPickOptionsTitle: "Cherry-pick options", diff --git a/pkg/integration/tests/misc/recent_repos_with_long_names.go b/pkg/integration/tests/misc/recent_repos_with_long_names.go index 7396faff3..7369dd367 100644 --- a/pkg/integration/tests/misc/recent_repos_with_long_names.go +++ b/pkg/integration/tests/misc/recent_repos_with_long_names.go @@ -29,10 +29,14 @@ var RecentReposWithLongNames = NewIntegrationTest(NewIntegrationTestArgs{ t.ExpectPopup().Menu(). Title(Equals("Recent repositories")). Lines( - Contains("repo-with-a-name-that-is-far-… branch-with-a-name-that-is-to…").IsSelected(), + // The repo lives in the test's own directory, so its path is + // long enough to lose its middle + Contains("repo-with-a-name-that-is-far-… branch-with-a-name-that-is-to… ~/_results/mi…names/actual").IsSelected(), Contains("Cancel"), ). - Tooltip(Equals("Repo: repo-with-a-name-that-is-far-too-long\nBranch: branch-with-a-name-that-is-too-long")). + Tooltip(Contains("Repo: repo-with-a-name-that-is-far-too-long\n" + + "Branch: branch-with-a-name-that-is-too-long\n" + + "Path: ~/")). // Filtering matches the full names, including the part that the // menu truncates Filter("too-long").