From 320d33a8ef1b7cd0eaf167d577e2b9bfcc733977 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Thu, 30 Jul 2026 12:21:47 +0200 Subject: [PATCH] Centralize pull-request header presentation The branch controller should decide which pull request to show, not how its header is styled and linked. Move the existing formatter and state badge next to the branch presentation helpers so subsequent header changes stay in one layer. --- pkg/gui/controllers/branches_controller.go | 42 +--------------------- pkg/gui/presentation/branches.go | 41 +++++++++++++++++++++ pkg/gui/presentation/branches_test.go | 20 +++++++++++ 3 files changed, 62 insertions(+), 41 deletions(-) diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go index a73ee3bc2..47f95aa91 100644 --- a/pkg/gui/controllers/branches_controller.go +++ b/pkg/gui/controllers/branches_controller.go @@ -5,15 +5,12 @@ import ( "fmt" "strings" - "github.com/gookit/color" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gocui" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers" "github.com/jesseduffield/lazygit/pkg/gui/presentation" - "github.com/jesseduffield/lazygit/pkg/gui/presentation/icons" - "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" "github.com/samber/lo" @@ -214,13 +211,7 @@ func (self *BranchesController) GetOnRenderToMain() func() { pr, ok := self.c.Model().PullRequestsMap[branch.Name] if ok && presentation.ShouldShowPrForBranch(pr, branch.Name, self.c.UserConfig()) { - icon := lo.Ternary(icons.IsIconEnabled(), icons.IconForRemoteUrl(pr.Url)+" ", "") - ptyTask.Prefix = style.PrintHyperlink(fmt.Sprintf("%s%s %s %s\n", - icon, - coloredStateText(pr.State), - pr.Title, - style.FgCyan.Sprintf("#%d", pr.Number)), - pr.Url) + ptyTask.Prefix = presentation.FormatPullRequestHeader(pr) ptyTask.Prefix += strings.Repeat("─", self.c.Contexts().Normal.GetView().InnerWidth()) + "\n" } } @@ -236,37 +227,6 @@ func (self *BranchesController) GetOnRenderToMain() func() { } } -func stateText(state string) string { - var icon, label string - switch state { - case "OPEN": - icon, label = " ", "Open" - case "CLOSED": - icon, label = " ", "Closed" - case "MERGED": - icon, label = " ", "Merged" - case "DRAFT": - icon, label = " ", "Draft" - default: - return "" - } - if icons.IsIconEnabled() { - return icon + label - } - return label -} - -func coloredStateText(state string) string { - if icons.IsIconEnabled() { - return fmt.Sprintf("%s%s%s", - presentation.WithPrColor(state, "", false), - presentation.WithPrColor(state, color.RGB(0xFF, 0xFF, 0xFF, false).Sprint(stateText(state)), true), - presentation.WithPrColor(state, "", false)) - } - - return presentation.WithPrColor(state, stateText(state), false) -} - func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branch) error { upstream := lo.Ternary(selectedBranch.RemoteBranchStoredLocally(), selectedBranch.ShortUpstreamRefName(), diff --git a/pkg/gui/presentation/branches.go b/pkg/gui/presentation/branches.go index 2e8ab0106..b705b4b2f 100644 --- a/pkg/gui/presentation/branches.go +++ b/pkg/gui/presentation/branches.go @@ -287,6 +287,47 @@ func WithPrColor(state string, text string, isBg bool) string { } } +func FormatPullRequestHeader(pr *models.GithubPullRequest) string { + icon := lo.Ternary(icons.IsIconEnabled(), icons.IconForRemoteUrl(pr.Url)+" ", "") + return style.PrintHyperlink(fmt.Sprintf("%s%s %s %s\n", + icon, + coloredPullRequestStateText(pr.State), + pr.Title, + style.FgCyan.Sprintf("#%d", pr.Number)), + pr.Url) +} + +func pullRequestStateText(state string) string { + var icon, label string + switch state { + case "OPEN": + icon, label = " ", "Open" + case "CLOSED": + icon, label = " ", "Closed" + case "MERGED": + icon, label = " ", "Merged" + case "DRAFT": + icon, label = " ", "Draft" + default: + return "" + } + if icons.IsIconEnabled() { + return icon + label + } + return label +} + +func coloredPullRequestStateText(state string) string { + if icons.IsIconEnabled() { + return fmt.Sprintf("%s%s%s", + WithPrColor(state, "", false), + WithPrColor(state, color.RGB(0xFF, 0xFF, 0xFF, false).Sprint(pullRequestStateText(state)), true), + WithPrColor(state, "", false)) + } + + return WithPrColor(state, pullRequestStateText(state), false) +} + func ShouldShowPrForBranch(pr *models.GithubPullRequest, branchName string, userConfig *config.UserConfig) bool { if !lo.Contains(userConfig.Git.MainBranches, branchName) { return true diff --git a/pkg/gui/presentation/branches_test.go b/pkg/gui/presentation/branches_test.go index 339f57cc3..178ddec69 100644 --- a/pkg/gui/presentation/branches_test.go +++ b/pkg/gui/presentation/branches_test.go @@ -10,6 +10,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/common" "github.com/jesseduffield/lazygit/pkg/gui/presentation/icons" + "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/samber/lo" "github.com/stretchr/testify/assert" @@ -22,6 +23,25 @@ func makeAtomic(v int32) *atomic.Int32 { return &result } +func TestFormatPullRequestHeader(t *testing.T) { + oldColorLevel := color.ForceSetColorLevel(terminfo.ColorLevelNone) + defer color.ForceSetColorLevel(oldColorLevel) + icons.SetNerdFontsVersion("") + + pr := &models.GithubPullRequest{ + Title: "Improve checks", + Number: 5871, + State: "OPEN", + Url: "https://github.com/jesseduffield/lazygit/pull/5871", + } + numberText := style.FgCyan.Sprint("#5871") + + actual := FormatPullRequestHeader(pr) + + expected := style.PrintHyperlink("Open Improve checks "+numberText+"\n", pr.Url) + assert.Equal(t, expected, actual) +} + func Test_getBranchDisplayStrings(t *testing.T) { scenarios := []struct { branch *models.Branch