mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-08-28 02:24:49 -05:00
fix conflict
This commit is contained in:
@@ -41,75 +41,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
||||
<kbd>[</kbd>: previous tab
|
||||
</pre>
|
||||
|
||||
## Branches Panel (Branches Tab)
|
||||
|
||||
<pre>
|
||||
<kbd>space</kbd>: checkout
|
||||
<kbd>o</kbd>: create pull request
|
||||
<kbd>O</kbd>: create pull request options
|
||||
<kbd>ctrl+y</kbd>: copy pull request URL to clipboard
|
||||
<kbd>c</kbd>: checkout by name
|
||||
<kbd>F</kbd>: force checkout
|
||||
<kbd>n</kbd>: new branch
|
||||
<kbd>d</kbd>: delete branch
|
||||
<kbd>r</kbd>: rebase checked-out branch onto this branch
|
||||
<kbd>M</kbd>: merge into currently checked out branch
|
||||
<kbd>i</kbd>: show git-flow options
|
||||
<kbd>f</kbd>: fast-forward this branch from its upstream
|
||||
<kbd>g</kbd>: view reset options
|
||||
<kbd>R</kbd>: rename branch
|
||||
<kbd>ctrl+o</kbd>: copy branch name to clipboard
|
||||
<kbd>enter</kbd>: view commits
|
||||
</pre>
|
||||
|
||||
## Branches Panel (Remote Branches (in Remotes tab))
|
||||
|
||||
<pre>
|
||||
<kbd>esc</kbd>: Return to remotes list
|
||||
<kbd>g</kbd>: view reset options
|
||||
<kbd>enter</kbd>: view commits
|
||||
<kbd>space</kbd>: checkout
|
||||
<kbd>n</kbd>: new branch
|
||||
<kbd>M</kbd>: merge into currently checked out branch
|
||||
<kbd>d</kbd>: delete branch
|
||||
<kbd>r</kbd>: rebase checked-out branch onto this branch
|
||||
<kbd>u</kbd>: set as upstream of checked-out branch
|
||||
</pre>
|
||||
|
||||
## Branches Panel (Remotes Tab)
|
||||
|
||||
<pre>
|
||||
<kbd>f</kbd>: fetch remote
|
||||
<kbd>n</kbd>: add new remote
|
||||
<kbd>d</kbd>: remove remote
|
||||
<kbd>e</kbd>: edit remote
|
||||
</pre>
|
||||
|
||||
## Branches Panel (Sub-commits)
|
||||
|
||||
<pre>
|
||||
<kbd>enter</kbd>: view commit's files
|
||||
<kbd>space</kbd>: checkout commit
|
||||
<kbd>g</kbd>: view reset options
|
||||
<kbd>n</kbd>: new branch
|
||||
<kbd>c</kbd>: copy commit (cherry-pick)
|
||||
<kbd>C</kbd>: copy commit range (cherry-pick)
|
||||
<kbd>ctrl+r</kbd>: reset cherry-picked (copied) commits selection
|
||||
<kbd>ctrl+o</kbd>: copy commit SHA to clipboard
|
||||
</pre>
|
||||
|
||||
## Branches Panel (Tags Tab)
|
||||
|
||||
<pre>
|
||||
<kbd>space</kbd>: checkout
|
||||
<kbd>d</kbd>: delete tag
|
||||
<kbd>P</kbd>: push tag
|
||||
<kbd>n</kbd>: create tag
|
||||
<kbd>g</kbd>: view reset options
|
||||
<kbd>enter</kbd>: view commits
|
||||
</pre>
|
||||
|
||||
## Commit Files Panel
|
||||
## Commit Files
|
||||
|
||||
<pre>
|
||||
<kbd>ctrl+o</kbd>: copy the committed file name to the clipboard
|
||||
|
||||
@@ -64,7 +64,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
||||
<kbd>space</kbd>: 检出
|
||||
<kbd>n</kbd>: 新分支
|
||||
<kbd>o</kbd>: 创建抓取请求
|
||||
<kbd>O</kbd>: 创建抓取请求
|
||||
<kbd>O</kbd>: 创建抓取请求选项
|
||||
<kbd>ctrl+y</kbd>: 将抓取请求 URL 复制到剪贴板
|
||||
<kbd>c</kbd>: 按名称检出
|
||||
<kbd>F</kbd>: 强制检出
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
+26
-26
@@ -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: "<c-b>",
|
||||
},
|
||||
Branches: KeybindingBranchesConfig{
|
||||
CopyPullRequestURL: "<c-y>",
|
||||
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: "<c-y>",
|
||||
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",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
+13
-4
@@ -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
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+3
-1
@@ -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: "切换 显示/隐藏 命令日志",
|
||||
|
||||
+1
-1
@@ -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`,
|
||||
|
||||
+8
-17
@@ -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",
|
||||
|
||||
+1
-3
@@ -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}}?",
|
||||
|
||||
Reference in New Issue
Block a user