diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md index d9884256b..af5787dab 100644 --- a/docs/keybindings/Keybindings_en.md +++ b/docs/keybindings/Keybindings_en.md @@ -41,75 +41,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct [: previous tab -## Branches Panel (Branches Tab) - -
- space: checkout - o: create pull request - O: create pull request options - ctrl+y: copy pull request URL to clipboard - c: checkout by name - F: force checkout - n: new branch - d: delete branch - r: rebase checked-out branch onto this branch - M: merge into currently checked out branch - i: show git-flow options - f: fast-forward this branch from its upstream - g: view reset options - R: rename branch - ctrl+o: copy branch name to clipboard - enter: view commits -- -## Branches Panel (Remote Branches (in Remotes tab)) - -
- esc: Return to remotes list - g: view reset options - enter: view commits - space: checkout - n: new branch - M: merge into currently checked out branch - d: delete branch - r: rebase checked-out branch onto this branch - u: set as upstream of checked-out branch -- -## Branches Panel (Remotes Tab) - -
- f: fetch remote - n: add new remote - d: remove remote - e: edit remote -- -## Branches Panel (Sub-commits) - -
- enter: view commit's files - space: checkout commit - g: view reset options - n: new branch - c: copy commit (cherry-pick) - C: copy commit range (cherry-pick) - ctrl+r: reset cherry-picked (copied) commits selection - ctrl+o: copy commit SHA to clipboard -- -## Branches Panel (Tags Tab) - -
- space: checkout - d: delete tag - P: push tag - n: create tag - g: view reset options - enter: view commits -- -## Commit Files Panel +## Commit Files
ctrl+o: copy the committed file name to the clipboard
diff --git a/docs/keybindings/Keybindings_zh.md b/docs/keybindings/Keybindings_zh.md
index 7ffaf2292..df1db2e55 100644
--- a/docs/keybindings/Keybindings_zh.md
+++ b/docs/keybindings/Keybindings_zh.md
@@ -64,7 +64,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
space: 检出
n: 新分支
o: 创建抓取请求
- O: 创建抓取请求
+ O: 创建抓取请求选项
ctrl+y: 将抓取请求 URL 复制到剪贴板
c: 按名称检出
F: 强制检出
diff --git a/pkg/app/app.go b/pkg/app/app.go
index a1b53d96c..88af18486 100644
--- a/pkg/app/app.go
+++ b/pkg/app/app.go
@@ -136,6 +136,29 @@ func (app *App) validateGhVersion() error {
return minVersionError
}
+func isGhVersionValid(versionStr string) bool {
+ // output should be something like:
+ // gh version 2.0.0 (2021-08-23)
+ // https://github.com/cli/cli/releases/tag/v2.0.0
+ re := regexp.MustCompile(`[^\d]+([\d\.]+)`)
+ matches := re.FindStringSubmatch(versionStr)
+
+ if len(matches) == 0 {
+ return false
+ }
+
+ ghVersion := matches[1]
+ majorVersion, err := strconv.Atoi(ghVersion[0:1])
+ if err != nil {
+ return false
+ }
+ if majorVersion < 2 {
+ return false
+ }
+
+ return true
+}
+
func (app *App) validateGitVersion() error {
output, err := app.OSCommand.Cmd.New("git --version").RunWithOutput()
// if we get an error anywhere here we'll show the same status
diff --git a/pkg/commands/git_commands/gh.go b/pkg/commands/git_commands/gh.go
index 30d580aa4..2edd36a73 100644
--- a/pkg/commands/git_commands/gh.go
+++ b/pkg/commands/git_commands/gh.go
@@ -5,7 +5,6 @@ import (
"fmt"
"strings"
- "github.com/jesseduffield/lazygit/pkg/commands/hosting_service"
"github.com/jesseduffield/lazygit/pkg/commands/models"
)
@@ -21,17 +20,16 @@ func NewGhCommand(gitCommon *GitCommon) *GhCommands {
// https://github.com/cli/cli/issues/2300
func (self *GhCommands) BaseRepo() error {
- return self.cmd.New("git config --local --get-regexp .gh-resolved").StreamOutput().Run()
-
+ return self.cmd.New("git config --local --get-regexp .gh-resolved").Run()
}
// Ex: git config --local --add "remote.origin.gh-resolved" "jesseduffield/lazygit"
func (self *GhCommands) SetBaseRepo(repository string) (string, error) {
- return self.cmd.NewShell(fmt.Sprintf("git config --local --add \"remote.origin.gh-resolved\" \"%s\"", repository)).RunWithOutput()
+ return self.cmd.New(fmt.Sprintf("git config --local --add \"remote.origin.gh-resolved\" \"%s\"", repository)).RunWithOutput()
}
func (self *GhCommands) prList() (string, error) {
- return self.cmd.NewShell("gh pr list --limit 100 --state all --json state,url,number,headRefName,headRepositoryOwner").RunWithOutput()
+ return self.cmd.New("gh pr list --limit 500 --state all --json state,url,number,headRefName,headRepositoryOwner").RunWithOutput()
}
func (self *GhCommands) GithubMostRecentPRs() ([]*models.GithubPullRequest, error) {
@@ -49,17 +47,17 @@ func (self *GhCommands) GithubMostRecentPRs() ([]*models.GithubPullRequest, erro
return prs, nil
}
-func GenerateGithubPullRequestMap(prs []*models.GithubPullRequest, branches []*models.Branch, remotes []*models.Remote) (map[*models.Branch]*models.GithubPullRequest, error) {
+func GenerateGithubPullRequestMap(prs []*models.GithubPullRequest, branches []*models.Branch, remotes []*models.Remote) map[*models.Branch]*models.GithubPullRequest {
res := map[*models.Branch]*models.GithubPullRequest{}
if len(prs) == 0 {
- return res, nil
+ return res
}
- remotesToOwnersMap, err := getRemotesToOwnersMap(remotes)
+ remotesToOwnersMap := getRemotesToOwnersMap(remotes)
if len(remotesToOwnersMap) == 0 {
- return res, err
+ return res
}
prWithStringKey := map[string]models.GithubPullRequest{}
@@ -87,10 +85,10 @@ func GenerateGithubPullRequestMap(prs []*models.GithubPullRequest, branches []*m
res[branch] = &pr
}
- return res, nil
+ return res
}
-func GetRepoInfoFromURL(url string) hosting_service.RepoInformation {
+func GetRepoInfoFromURL(url string) RepoInformation {
isHTTP := strings.HasPrefix(url, "http")
if isHTTP {
@@ -98,7 +96,7 @@ func GetRepoInfoFromURL(url string) hosting_service.RepoInformation {
owner := strings.Join(splits[3:len(splits)-1], "/")
repo := strings.TrimSuffix(splits[len(splits)-1], ".git")
- return hosting_service.RepoInformation{
+ return RepoInformation{
Owner: owner,
Repository: repo,
}
@@ -109,13 +107,13 @@ func GetRepoInfoFromURL(url string) hosting_service.RepoInformation {
owner := strings.Join(splits[0:len(splits)-1], "/")
repo := strings.TrimSuffix(splits[len(splits)-1], ".git")
- return hosting_service.RepoInformation{
+ return RepoInformation{
Owner: owner,
Repository: repo,
}
}
-func getRemotesToOwnersMap(remotes []*models.Remote) (map[string]string, error) {
+func getRemotesToOwnersMap(remotes []*models.Remote) map[string]string {
res := map[string]string{}
for _, remote := range remotes {
if len(remote.Urls) == 0 {
@@ -124,5 +122,10 @@ func getRemotesToOwnersMap(remotes []*models.Remote) (map[string]string, error)
res[remote.Name] = GetRepoInfoFromURL(remote.Urls[0]).Owner
}
- return res, nil
+ return res
+}
+
+type RepoInformation struct {
+ Owner string
+ Repository string
}
diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go
index 05020a3fa..f6f9621d1 100644
--- a/pkg/config/user_config.go
+++ b/pkg/config/user_config.go
@@ -224,19 +224,19 @@ type KeybindingFilesConfig struct {
}
type KeybindingBranchesConfig struct {
- CreateOrShowPullRequest string `yaml:"createPullRequest"`
- ViewPullRequestOptions string `yaml:"viewPullRequestOptions"`
- CopyPullRequestURL string `yaml:"copyPullRequestURL"`
- CheckoutBranchByName string `yaml:"checkoutBranchByName"`
- ForceCheckoutBranch string `yaml:"forceCheckoutBranch"`
- RebaseBranch string `yaml:"rebaseBranch"`
- RenameBranch string `yaml:"renameBranch"`
- MergeIntoCurrentBranch string `yaml:"mergeIntoCurrentBranch"`
- ViewGitFlowOptions string `yaml:"viewGitFlowOptions"`
- FastForward string `yaml:"fastForward"`
- PushTag string `yaml:"pushTag"`
- SetUpstream string `yaml:"setUpstream"`
- FetchRemote string `yaml:"fetchRemote"`
+ CreatePullRequest string `yaml:"createPullRequest"`
+ ViewPullRequestOptions string `yaml:"viewPullRequestOptions"`
+ CopyPullRequestURL string `yaml:"copyPullRequestURL"`
+ CheckoutBranchByName string `yaml:"checkoutBranchByName"`
+ ForceCheckoutBranch string `yaml:"forceCheckoutBranch"`
+ RebaseBranch string `yaml:"rebaseBranch"`
+ RenameBranch string `yaml:"renameBranch"`
+ MergeIntoCurrentBranch string `yaml:"mergeIntoCurrentBranch"`
+ ViewGitFlowOptions string `yaml:"viewGitFlowOptions"`
+ FastForward string `yaml:"fastForward"`
+ PushTag string `yaml:"pushTag"`
+ SetUpstream string `yaml:"setUpstream"`
+ FetchRemote string `yaml:"fetchRemote"`
}
type KeybindingCommitsConfig struct {
@@ -505,19 +505,19 @@ func GetDefaultConfig() *UserConfig {
OpenStatusFilter: "",
},
Branches: KeybindingBranchesConfig{
- CopyPullRequestURL: "",
- CreateOrShowPullRequest: "o",
- ViewPullRequestOptions: "O",
- CheckoutBranchByName: "c",
- ForceCheckoutBranch: "F",
- RebaseBranch: "r",
- RenameBranch: "R",
- MergeIntoCurrentBranch: "M",
- ViewGitFlowOptions: "i",
- FastForward: "f",
- PushTag: "P",
- SetUpstream: "u",
- FetchRemote: "f",
+ CopyPullRequestURL: "",
+ CreatePullRequest: "o",
+ ViewPullRequestOptions: "O",
+ CheckoutBranchByName: "c",
+ ForceCheckoutBranch: "F",
+ RebaseBranch: "r",
+ RenameBranch: "R",
+ MergeIntoCurrentBranch: "M",
+ ViewGitFlowOptions: "i",
+ FastForward: "f",
+ PushTag: "P",
+ SetUpstream: "u",
+ FetchRemote: "f",
},
Commits: KeybindingCommitsConfig{
SquashDown: "s",
diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go
index b9a25ea67..ad3fc1947 100644
--- a/pkg/gui/branches_panel.go
+++ b/pkg/gui/branches_panel.go
@@ -1,6 +1,8 @@
package gui
-import "github.com/jesseduffield/lazygit/pkg/gui/types"
+import (
+ "github.com/jesseduffield/lazygit/pkg/gui/types"
+)
func (gui *Gui) branchesRenderToMain() error {
var task types.UpdateTask
@@ -21,3 +23,44 @@ func (gui *Gui) branchesRenderToMain() error {
},
})
}
+
+func (gui *Gui) refreshGithubPullRequests() {
+ if err := gui.git.Gh.BaseRepo(); err == nil {
+ _ = gui.setGithubPullRequests()
+ return
+ }
+
+ // when config not exits
+ _ = gui.refreshRemotes()
+
+ _ = gui.c.Prompt(types.PromptOpts{
+ Title: gui.c.Tr.SelectRemoteRepository,
+ InitialContent: "",
+ FindSuggestionsFunc: gui.helpers.Suggestions.GetRemoteRepoSuggestionsFunc(),
+ HandleConfirm: func(repository string) error {
+ return gui.c.WithWaitingStatus(gui.c.Tr.LcSelectingRemote, func() error {
+ _, err := gui.git.Gh.SetBaseRepo(repository)
+ if err != nil {
+ return err
+ }
+
+ err = gui.setGithubPullRequests()
+ if err != nil {
+ return err
+ }
+ _ = gui.postRefreshUpdate(gui.State.Contexts.Branches)
+ return nil
+ })
+ },
+ })
+}
+
+func (gui *Gui) setGithubPullRequests() error {
+ prs, err := gui.git.Gh.GithubMostRecentPRs()
+ if err != nil {
+ return gui.c.Error(err)
+ }
+
+ gui.State.Model.PullRequests = prs
+ return nil
+}
diff --git a/pkg/gui/controllers/helpers/suggestions_helper.go b/pkg/gui/controllers/helpers/suggestions_helper.go
index 0cc4a642b..68816ce9f 100644
--- a/pkg/gui/controllers/helpers/suggestions_helper.go
+++ b/pkg/gui/controllers/helpers/suggestions_helper.go
@@ -5,6 +5,7 @@ import (
"os"
"github.com/jesseduffield/generics/slices"
+ "github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
"github.com/jesseduffield/lazygit/pkg/gui/types"
@@ -80,6 +81,26 @@ func (self *SuggestionsHelper) getBranchNames() []string {
})
}
+func (self *SuggestionsHelper) GetRemoteRepoSuggestionsFunc() func(string) []*types.Suggestion {
+ remotesNames := self.getRemoteRepoNames()
+
+ return FuzzySearchFunc(remotesNames)
+}
+
+func (self *SuggestionsHelper) getRemoteRepoNames() []string {
+ remotes := self.model.Remotes
+ result := make([]string, 0, len(remotes))
+ for _, remote := range remotes {
+ if len(remote.Urls) == 0 {
+ continue
+ }
+ info := git_commands.GetRepoInfoFromURL(remote.Urls[0])
+ result = append(result, fmt.Sprintf("%s/%s", info.Owner, info.Repository))
+ }
+
+ return result
+}
+
func (self *SuggestionsHelper) GetBranchNameSuggestionsFunc() func(string) []*types.Suggestion {
branchNames := self.getBranchNames()
diff --git a/pkg/gui/find_suggestions.go b/pkg/gui/find_suggestions.go
deleted file mode 100644
index 56a27ee94..000000000
--- a/pkg/gui/find_suggestions.go
+++ /dev/null
@@ -1,211 +0,0 @@
-package gui
-
-import (
- "fmt"
- "os"
-
- "github.com/jesseduffield/lazygit/pkg/commands/git_commands"
- "github.com/jesseduffield/lazygit/pkg/gui/presentation"
- "github.com/jesseduffield/lazygit/pkg/gui/types"
- "github.com/jesseduffield/lazygit/pkg/utils"
- "github.com/jesseduffield/minimal/gitignore"
- "gopkg.in/ozeidan/fuzzy-patricia.v3/patricia"
-)
-
-// Thinking out loud: I'm typically a staunch advocate of organising code by feature rather than type,
-// because colocating code that relates to the same feature means far less effort
-// to get all the context you need to work on any particular feature. But the one
-// major benefit of grouping by type is that it makes it makes it less likely that
-// somebody will re-implement the same logic twice, because they can quickly see
-// if a certain method has been used for some use case, given that as a starting point
-// they know about the type. In that vein, I'm including all our functions for
-// finding suggestions in this file, so that it's easy to see if a function already
-// exists for fetching a particular model.
-
-func (gui *Gui) getRemoteNames() []string {
- result := make([]string, len(gui.State.Remotes))
- for i, remote := range gui.State.Remotes {
- result[i] = remote.Name
- }
- return result
-}
-
-func matchesToSuggestions(matches []string) []*types.Suggestion {
- suggestions := make([]*types.Suggestion, len(matches))
- for i, match := range matches {
- suggestions[i] = &types.Suggestion{
- Value: match,
- Label: match,
- }
- }
- return suggestions
-}
-
-func (gui *Gui) getRemoteSuggestionsFunc() func(string) []*types.Suggestion {
- remoteNames := gui.getRemoteNames()
-
- return fuzzySearchFunc(remoteNames)
-}
-
-func (gui *Gui) getRemoteRepoSuggestionsFunc() func(string) []*types.Suggestion {
- remotesNames := gui.getRemoteRepoNames()
-
- return fuzzySearchFunc(remotesNames)
-}
-
-func (gui *Gui) getRemoteRepoNames() []string {
- remotes := gui.State.Remotes
- result := make([]string, 0, len(remotes))
- for _, remote := range remotes {
- if len(remote.Urls) == 0 {
- continue
- }
- info := git_commands.GetRepoInfoFromURL(remote.Urls[0])
- result = append(result, fmt.Sprintf("%s/%s", info.Owner, info.Repository))
- }
-
- return result
-}
-
-func (gui *Gui) getBranchNames() []string {
- result := make([]string, len(gui.State.Branches))
- for i, branch := range gui.State.Branches {
- result[i] = branch.Name
- }
- return result
-}
-
-func (gui *Gui) getBranchNameSuggestionsFunc() func(string) []*types.Suggestion {
- branchNames := gui.getBranchNames()
-
- return func(input string) []*types.Suggestion {
- var matchingBranchNames []string
- if input == "" {
- matchingBranchNames = branchNames
- } else {
- matchingBranchNames = utils.FuzzySearch(input, branchNames)
- }
-
- suggestions := make([]*types.Suggestion, len(matchingBranchNames))
- for i, branchName := range matchingBranchNames {
- suggestions[i] = &types.Suggestion{
- Value: branchName,
- Label: presentation.GetBranchTextStyle(branchName).Sprint(branchName),
- }
- }
-
- return suggestions
- }
-}
-
-// here we asynchronously fetch the latest set of paths in the repo and store in
-// gui.State.FilesTrie. On the main thread we'll be doing a fuzzy search via
-// gui.State.FilesTrie. So if we've looked for a file previously, we'll start with
-// the old trie and eventually it'll be swapped out for the new one.
-// Notably, unlike other suggestion functions we're not showing all the options
-// if nothing has been typed because there'll be too much to display efficiently
-func (gui *Gui) getFilePathSuggestionsFunc() func(string) []*types.Suggestion {
- _ = gui.WithWaitingStatus(gui.Tr.LcLoadingFileSuggestions, func() error {
- trie := patricia.NewTrie()
- // load every non-gitignored file in the repo
- ignore, err := gitignore.FromGit()
- if err != nil {
- return err
- }
-
- err = ignore.Walk(".",
- func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- trie.Insert(patricia.Prefix(path), path)
- return nil
- })
- // cache the trie for future use
- gui.State.FilesTrie = trie
-
- // refresh the selections view
- gui.suggestionsAsyncHandler.Do(func() func() {
- // assuming here that the confirmation view is what we're typing into.
- // This assumption may prove false over time
- suggestions := gui.findSuggestions(gui.Views.Confirmation.TextArea.GetContent())
- return func() { gui.setSuggestions(suggestions) }
- })
-
- return err
- })
-
- return func(input string) []*types.Suggestion {
- matchingNames := []string{}
- _ = gui.State.FilesTrie.VisitFuzzy(patricia.Prefix(input), true, func(prefix patricia.Prefix, item patricia.Item, skipped int) error {
- matchingNames = append(matchingNames, item.(string))
- return nil
- })
-
- // doing another fuzzy search for good measure
- matchingNames = utils.FuzzySearch(input, matchingNames)
-
- suggestions := make([]*types.Suggestion, len(matchingNames))
- for i, name := range matchingNames {
- suggestions[i] = &types.Suggestion{
- Value: name,
- Label: name,
- }
- }
-
- return suggestions
- }
-}
-
-func (gui *Gui) getRemoteBranchNames(separator string) []string {
- result := []string{}
- for _, remote := range gui.State.Remotes {
- for _, branch := range remote.Branches {
- result = append(result, fmt.Sprintf("%s%s%s", remote.Name, separator, branch.Name))
- }
- }
- return result
-}
-
-func (gui *Gui) getRemoteBranchesSuggestionsFunc(separator string) func(string) []*types.Suggestion {
- return fuzzySearchFunc(gui.getRemoteBranchNames(separator))
-}
-
-func (gui *Gui) getTagNames() []string {
- result := make([]string, len(gui.State.Tags))
- for i, tag := range gui.State.Tags {
- result[i] = tag.Name
- }
- return result
-}
-
-func (gui *Gui) getRefsSuggestionsFunc() func(string) []*types.Suggestion {
- remoteBranchNames := gui.getRemoteBranchNames("/")
- localBranchNames := gui.getBranchNames()
- tagNames := gui.getTagNames()
- additionalRefNames := []string{"HEAD", "FETCH_HEAD", "MERGE_HEAD", "ORIG_HEAD"}
-
- refNames := append(append(append(remoteBranchNames, localBranchNames...), tagNames...), additionalRefNames...)
-
- return fuzzySearchFunc(refNames)
-}
-
-func (gui *Gui) getCustomCommandsHistorySuggestionsFunc() func(string) []*types.Suggestion {
- // reversing so that we display the latest command first
- history := utils.Reverse(gui.Config.GetAppState().CustomCommandsHistory)
-
- return fuzzySearchFunc(history)
-}
-
-func fuzzySearchFunc(options []string) func(string) []*types.Suggestion {
- return func(input string) []*types.Suggestion {
- var matches []string
- if input == "" {
- matches = options
- } else {
- matches = utils.FuzzySearch(input, options)
- }
-
- return matchesToSuggestions(matches)
- }
-}
diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go
index d7103914d..2643cac2c 100644
--- a/pkg/gui/gui.go
+++ b/pkg/gui/gui.go
@@ -238,10 +238,6 @@ func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, reuseState bool) error {
return nil
}
-type GithubState struct {
- RecentPRs []*models.GithubPullRequest
-}
-
// reuseState determines if we pull the repo state from our repo state map or
// just re-initialize it. For now we're only re-using state when we're going
// in and out of submodules, for the sake of having the cursor back on the submodule
@@ -290,6 +286,7 @@ func (gui *Gui) resetState(startArgs appTypes.StartArgs, reuseState bool) {
ReflogCommits: make([]*models.Commit, 0),
BisectInfo: git_commands.NewNullBisectInfo(),
FilesTrie: patricia.NewTrie(),
+ PullRequests: make([]*models.GithubPullRequest, 0),
},
Modes: &types.Modes{
Filtering: filtering.New(startArgs.FilterPath),
@@ -777,3 +774,15 @@ func (gui *Gui) onUIThread(f func() error) {
return f()
})
}
+
+func (gui *Gui) GetPr(branch *models.Branch) (*models.GithubPullRequest, bool, error) {
+ prs := git_commands.GenerateGithubPullRequestMap(
+ gui.State.Model.PullRequests,
+ []*models.Branch{branch},
+ gui.State.Model.Remotes,
+ )
+
+ pr, hasPr := prs[branch]
+
+ return pr, hasPr, nil
+}
diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go
index d463c2ac5..7e73cd1bb 100644
--- a/pkg/gui/list_context_config.go
+++ b/pkg/gui/list_context_config.go
@@ -45,7 +45,8 @@ func (gui *Gui) branchesListContext() *context.BranchesContext {
func() []*models.Branch { return gui.State.Model.Branches },
gui.Views.Branches,
func(startIdx int, length int) [][]string {
- return presentation.GetBranchListDisplayStrings(gui.State.Model.Branches, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Modes.Diffing.Ref, gui.Tr)
+ prs := git_commands.GenerateGithubPullRequestMap(gui.State.Model.PullRequests, gui.State.Model.Branches, gui.State.Model.Remotes)
+ return presentation.GetBranchListDisplayStrings(gui.State.Model.Branches, prs, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Modes.Diffing.Ref, gui.Tr)
},
nil,
gui.withDiffModeCheck(gui.branchesRenderToMain),
diff --git a/pkg/gui/presentation/branches.go b/pkg/gui/presentation/branches.go
index 1b9cc9b12..ed1d6edda 100644
--- a/pkg/gui/presentation/branches.go
+++ b/pkg/gui/presentation/branches.go
@@ -16,15 +16,17 @@ import (
var branchPrefixColorCache = make(map[string]style.TextStyle)
-func GetBranchListDisplayStrings(branches []*models.Branch, fullDescription bool, diffName string, tr *i18n.TranslationSet) [][]string {
+func GetBranchListDisplayStrings(branches []*models.Branch, prs map[*models.Branch]*models.GithubPullRequest, fullDescription bool, diffName string, tr *i18n.TranslationSet) [][]string {
return slices.Map(branches, func(branch *models.Branch) []string {
diffed := branch.Name == diffName
- return getBranchDisplayStrings(branch, fullDescription, diffed, tr)
+ return getBranchDisplayStrings(branch, prs, fullDescription, diffed, tr)
})
}
// getBranchDisplayStrings returns the display string of branch
-func getBranchDisplayStrings(b *models.Branch, fullDescription bool, diffed bool, tr *i18n.TranslationSet) []string {
+func getBranchDisplayStrings(b *models.Branch,
+ prs map[*models.Branch]*models.GithubPullRequest, fullDescription bool, diffed bool, tr *i18n.TranslationSet,
+) []string {
displayName := b.Name
if b.DisplayName != "" {
displayName = b.DisplayName
@@ -49,7 +51,15 @@ func getBranchDisplayStrings(b *models.Branch, fullDescription bool, diffed bool
if icons.IsIconEnabled() {
res = append(res, nameTextStyle.Sprint(icons.IconForBranch(b)))
}
- res = append(res, coloredName)
+
+ pr, hasPr := prs[b]
+
+ if hasPr {
+ res = append(res, coloredPrNumber(pr, hasPr), coloredName)
+ } else {
+ res = append(res, coloredName)
+ }
+
if fullDescription {
res = append(
res,
diff --git a/pkg/gui/pull_request_menu_panel.go b/pkg/gui/pull_request_menu_panel.go
deleted file mode 100644
index 276074072..000000000
--- a/pkg/gui/pull_request_menu_panel.go
+++ /dev/null
@@ -1,94 +0,0 @@
-package gui
-
-import (
- "fmt"
- "strconv"
-
- "github.com/jesseduffield/lazygit/pkg/commands/hosting_service"
- "github.com/jesseduffield/lazygit/pkg/commands/models"
-)
-
-func (gui *Gui) createOrOpenPullRequestMenu(selectedBranch *models.Branch, checkedOutBranch *models.Branch) error {
- menuItems := make([]*menuItem, 0, 4)
-
- fromToDisplayStrings := func(from string, to string) []string {
- return []string{fmt.Sprintf("%s → %s", from, to)}
- }
-
- menuItemsForBranch := func(branch *models.Branch) []*menuItem {
- return []*menuItem{
- {
- displayStrings: fromToDisplayStrings(branch.Name, gui.Tr.LcDefaultBranch),
- onPress: func() error {
- return gui.createPullRequest(branch.Name, "")
- },
- },
- {
- displayStrings: fromToDisplayStrings(branch.Name, gui.Tr.LcSelectBranch),
- onPress: func() error {
- return gui.prompt(promptOpts{
- title: branch.Name + " →",
- findSuggestionsFunc: gui.getBranchNameSuggestionsFunc(),
- handleConfirm: func(targetBranchName string) error {
- return gui.createPullRequest(branch.Name, targetBranchName)
- }},
- )
- },
- },
- }
- }
-
- pr, hasPr, err := gui.GetPr(selectedBranch)
- if err != nil {
- return err
- }
-
- if hasPr {
- menuItems = append(menuItems, &menuItem{
- displayString: gui.Git.Gh.Tr.MustSpecifyOriginError + strconv.Itoa(pr.Number),
- onPress: func() error {
- return gui.OSCommand.OpenLink(pr.Url)
- },
- })
- }
-
- if selectedBranch != checkedOutBranch {
- menuItems = append(menuItems,
- &menuItem{
- displayStrings: fromToDisplayStrings(checkedOutBranch.Name, selectedBranch.Name),
- onPress: func() error {
- return gui.createPullRequest(checkedOutBranch.Name, selectedBranch.Name)
- },
- },
- )
- menuItems = append(menuItems, menuItemsForBranch(checkedOutBranch)...)
- }
-
- menuItems = append(menuItems, menuItemsForBranch(selectedBranch)...)
-
- return gui.createMenu(fmt.Sprintf(gui.Tr.CreateOrOpenPullRequestOptions), menuItems, createMenuOptions{showCancel: true})
-}
-
-func (gui *Gui) createPullRequest(from string, to string) error {
- hostingServiceMgr := gui.getHostingServiceMgr()
- url, err := hostingServiceMgr.GetPullRequestURL(from, to)
- if err != nil {
- return gui.surfaceError(err)
- }
-
- // gui.OnRunCommand(oscommands.NewCmdLogEntry(fmt.Sprintf(gui.Tr.CreatingPullRequestAtUrl, url), gui.Tr.CreateOrShowPullRequest, false))
-
- gui.logAction(gui.Tr.Actions.OpenPullRequest)
-
- if err := gui.OSCommand.OpenLink(url); err != nil {
- return gui.surfaceError(err)
- }
-
- return nil
-}
-
-func (gui *Gui) getHostingServiceMgr() *hosting_service.HostingServiceMgr {
- remoteUrl := gui.Git.Config.GetRemoteURL()
- configServices := gui.UserConfig.Services
- return hosting_service.NewHostingServiceMgr(gui.Log, gui.Tr, remoteUrl, configServices)
-}
diff --git a/pkg/gui/refresh.go b/pkg/gui/refresh.go
index d09583389..23be7d1ac 100644
--- a/pkg/gui/refresh.go
+++ b/pkg/gui/refresh.go
@@ -237,6 +237,10 @@ func (gui *Gui) refreshCommitsWithLimit() error {
}
gui.State.Model.Commits = commits
+ if gui.Config.GetUserConfig().Git.EnableGhCommand {
+ gui.refreshGithubPullRequests()
+ }
+
return gui.c.PostRefreshUpdate(gui.State.Contexts.LocalCommits)
}
diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go
index ab8f6b2b8..ea5164eda 100644
--- a/pkg/gui/types/common.go
+++ b/pkg/gui/types/common.go
@@ -145,6 +145,7 @@ type Model struct {
StashEntries []*models.StashEntry
SubCommits []*models.Commit
Remotes []*models.Remote
+ PullRequests []*models.GithubPullRequest
// FilteredReflogCommits are the ones that appear in the reflog panel.
// when in filtering mode we only include the ones that match the given path
diff --git a/pkg/i18n/chinese.go b/pkg/i18n/chinese.go
index 66e895359..6b9a94a76 100644
--- a/pkg/i18n/chinese.go
+++ b/pkg/i18n/chinese.go
@@ -163,7 +163,7 @@ func chineseTranslationSet() TranslationSet {
SwitchRepo: `切换到最近的仓库`,
LcAllBranchesLogGraph: `显示所有分支的日志`,
UnsupportedGitService: `不支持的 git 服务`,
- LcCreateOrOpenPullRequestOptions: `创建抓取请求`,
+ LcCreatePullRequest: `创建抓取请求`,
LcCopyPullRequestURL: `将抓取请求 URL 复制到剪贴板`,
NoBranchOnRemote: `该分支在远程上不存在. 您需要先将其推送到远程.`,
LcFetch: `抓取`,
@@ -436,6 +436,8 @@ func chineseTranslationSet() TranslationSet {
LcCopiedToClipboard: "复制到剪贴板",
ErrCannotEditDirectory: "无法编辑目录:您只能编辑单个文件",
ErrStageDirWithInlineMergeConflicts: "无法 暂存/取消暂存 包含具有内联合并冲突的文件的目录。请先解决合并冲突",
+ SelectRemoteRepository: "选择存储库",
+ LcSelectingRemote: "选择遥控器",
ErrRepositoryMovedOrDeleted: "找不到仓库。它可能已被移动或删除 ¯\\_(ツ)_/¯",
CommandLog: "命令日志",
ToggleShowCommandLog: "切换 显示/隐藏 命令日志",
diff --git a/pkg/i18n/dutch.go b/pkg/i18n/dutch.go
index 1aaee6952..536793fc6 100644
--- a/pkg/i18n/dutch.go
+++ b/pkg/i18n/dutch.go
@@ -128,7 +128,7 @@ func dutchTranslationSet() TranslationSet {
SwitchRepo: "wissel naar een recente repo",
LcAllBranchesLogGraph: `alle logs van de branch laten zien`,
UnsupportedGitService: `Niet-ondersteunde git-service`,
- LcCreateOrShowPullRequest: `maak of laat een pull-request zien`,
+ LcCreatePullRequest: `maak een pull-request`,
LcCopyPullRequestURL: `kopieer de URL van het pull-verzoek naar het klembord`,
NoBranchOnRemote: `Deze branch bestaat niet op de remote. U moet het eerst naar de remote pushen.`,
LcFetch: `fetch`,
diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go
index d993d70d0..bd9804634 100644
--- a/pkg/i18n/english.go
+++ b/pkg/i18n/english.go
@@ -162,7 +162,7 @@ type TranslationSet struct {
SwitchRepo string
LcAllBranchesLogGraph string
UnsupportedGitService string
- LcCreateOrShowPullRequest string
+ LcCreatePullRequest string
LcCopyPullRequestURL string
NoBranchOnRemote string
LcFetch string
@@ -355,6 +355,8 @@ type TranslationSet struct {
LcNextScreenMode string
LcPrevScreenMode string
LcStartSearch string
+ SelectRemoteRepository string
+ LcSelectingRemote string
Panel string
Keybindings string
LcRenameBranch string
@@ -472,16 +474,12 @@ type TranslationSet struct {
ToggleWhitespaceInDiffView string
IgnoringWhitespaceInDiffView string
ShowingWhitespaceInDiffView string
- CreateOrOpenPullRequestOptions string
- LcCreateOrOpenPullRequestOptions string
- LcDefaultBranch string
- LcSelectBranch string
- CreateOrShowPullRequest string
- CreatingPullRequestAtUrl string
IncreaseContextInDiffView string
DecreaseContextInDiffView string
CreatePullRequestOptions string
LcCreatePullRequestOptions string
+ LcDefaultBranch string
+ LcSelectBranch string
CreatePullRequest string
SelectConfigFile string
NoConfigFileFoundErr string
@@ -490,11 +488,8 @@ type TranslationSet struct {
MustSpecifyOriginError string
GitOutput string
GitCommandFailed string
- OpenPr string
AbortTitle string
AbortPrompt string
- SelectRemoteRepository string
- LcSelectingRemote string
LcOpenLogMenu string
LogMenuTitle string
ToggleShowGitGraphAll string
@@ -808,7 +803,7 @@ func EnglishTranslationSet() TranslationSet {
SwitchRepo: `switch to a recent repo`,
LcAllBranchesLogGraph: `show all branch logs`,
UnsupportedGitService: `Unsupported git service`,
- LcCreateOrShowPullRequest: `create / open pull request`,
+ LcCreatePullRequest: `create pull request`,
LcCopyPullRequestURL: `copy pull request URL to clipboard`,
NoBranchOnRemote: `This branch doesn't exist on remote. You need to push it to remote first.`,
LcFetch: `fetch`,
@@ -1002,6 +997,8 @@ func EnglishTranslationSet() TranslationSet {
LcNextScreenMode: "next screen mode (normal/half/fullscreen)",
LcPrevScreenMode: "prev screen mode",
LcStartSearch: "start search",
+ LcSelectingRemote: "selecting remote",
+ SelectRemoteRepository: "select base remote repository",
Panel: "Panel",
Keybindings: "Keybindings",
LcRenameBranch: "rename branch",
@@ -1100,8 +1097,6 @@ func EnglishTranslationSet() TranslationSet {
SuggestionsTitle: "Suggestions (press %s to focus)",
ExtrasTitle: "Command Log",
PushingTagStatus: "pushing tag",
- SelectRemoteRepository: "select base remote repository",
- LcSelectingRemote: "selecting remote",
PullRequestURLCopiedToClipboard: "Pull request URL copied to clipboard",
CommitDiffCopiedToClipboard: "Commit diff copied to clipboard",
CommitSHACopiedToClipboard: "Commit SHA copied to clipboard",
@@ -1121,9 +1116,6 @@ func EnglishTranslationSet() TranslationSet {
ToggleWhitespaceInDiffView: "Toggle whether or not whitespace changes are shown in the diff view",
IgnoringWhitespaceInDiffView: "Whitespace will be ignored in the diff view",
ShowingWhitespaceInDiffView: "Whitespace will be shown in the diff view",
- CreateOrShowPullRequest: "create / open pull request",
- CreateOrOpenPullRequestOptions: "create / open pull request options",
- LcCreateOrOpenPullRequestOptions: "create / open pull request options",
IncreaseContextInDiffView: "Increase the size of the context shown around changes in the diff view",
DecreaseContextInDiffView: "Decrease the size of the context shown around changes in the diff view",
CreatePullRequest: "Create pull request",
@@ -1138,7 +1130,6 @@ func EnglishTranslationSet() TranslationSet {
MustSpecifyOriginError: "Must specify a remote if specifying a branch",
GitOutput: "Git output:",
GitCommandFailed: "Git command failed. Check command log for details (open with %s)",
- OpenPr: "Open PR #",
AbortTitle: "Abort %s",
AbortPrompt: "Are you sure you want to abort the current %s?",
LcOpenLogMenu: "open log menu",
diff --git a/pkg/i18n/polish.go b/pkg/i18n/polish.go
index 74ea00673..e82ddc2de 100644
--- a/pkg/i18n/polish.go
+++ b/pkg/i18n/polish.go
@@ -102,7 +102,7 @@ func polishTranslationSet() TranslationSet {
ConfirmQuit: "Na pewno chcesz wyjść z programu?",
LcAllBranchesLogGraph: "pokaż wszystkie logi gałęzi",
UnsupportedGitService: "Nieobsługiwana usługa git",
- LcCreateOrShowPullRequest: `maak of laat een pull-request zien`,
+ LcCreatePullRequest: "utwórz żądanie pobrania",
LcCopyPullRequestURL: "skopiuj adres URL żądania pobrania do schowka",
NoBranchOnRemote: "Ta gałąź nie istnieje w zdalnym repo. Najpierw musisz ją wysłać.",
LcFetch: "pobierz",
@@ -225,8 +225,6 @@ func polishTranslationSet() TranslationSet {
PullRequestURLCopiedToClipboard: "URL żądania ściągnięcia skopiowany do schowka",
CommitMessageCopiedToClipboard: "Komunikat commita skopiowany do schowka",
LcCopiedToClipboard: "skopiowany do schowka",
- CreateOrOpenPullRequestOptions: "Utwórz opcje żądania ściągnięcia",
- LcCreateOrOpenPullRequestOptions: "utwórz opcje żądania",
CreatePullRequestOptions: "Utwórz opcje żądania ściągnięcia",
LcCreatePullRequestOptions: "utwórz opcje żądania ściągnięcia",
ConfirmRevertCommit: "Czy na pewno chcesz obrócić {{.selectedCommit}}?",