From 6b7aaeca45847ebc41aa0fd9b773362d4a79f1ab Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 17 Nov 2019 12:02:39 +1100 Subject: [PATCH] support adding/removing remotes --- pkg/commands/git.go | 8 +++++ pkg/commands/remote.go | 11 ++++++- pkg/gui/branches_panel.go | 44 ++++++++++++++-------------- pkg/gui/confirmation_panel.go | 8 ++++- pkg/gui/keybindings.go | 16 ++++++++++ pkg/gui/remote_branches_panel.go | 14 +++++++++ pkg/gui/remotes_panel.go | 50 +++++++++++++++++++++++++++++--- pkg/i18n/english.go | 15 ++++++++++ 8 files changed, 139 insertions(+), 27 deletions(-) diff --git a/pkg/commands/git.go b/pkg/commands/git.go index ad275d10f..26f8aae32 100644 --- a/pkg/commands/git.go +++ b/pkg/commands/git.go @@ -1061,3 +1061,11 @@ func (c *GitCommand) BeginInteractiveRebaseForCommit(commits []*Commit, commitIn func (c *GitCommand) SetUpstreamBranch(upstream string) error { return c.OSCommand.RunCommand(fmt.Sprintf("git branch -u %s", upstream)) } + +func (c *GitCommand) AddRemote(name string, url string) error { + return c.OSCommand.RunCommand(fmt.Sprintf("git remote add %s %s", name, url)) +} + +func (c *GitCommand) RemoveRemote(name string) error { + return c.OSCommand.RunCommand(fmt.Sprintf("git remote remove %s", name)) +} diff --git a/pkg/commands/remote.go b/pkg/commands/remote.go index d61f81a53..b3c144b65 100644 --- a/pkg/commands/remote.go +++ b/pkg/commands/remote.go @@ -1,5 +1,12 @@ package commands +import ( + "fmt" + + "github.com/fatih/color" + "github.com/jesseduffield/lazygit/pkg/utils" +) + // Remote : A git remote type Remote struct { Name string @@ -11,5 +18,7 @@ type Remote struct { // GetDisplayStrings returns the display string of a remote func (r *Remote) GetDisplayStrings(isFocused bool) []string { - return []string{r.Name} + branchCount := len(r.Branches) + + return []string{r.Name, utils.ColoredString(fmt.Sprintf("%d branches", branchCount), color.FgBlue)} } diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go index 54a9301e2..c47138bd1 100644 --- a/pkg/gui/branches_panel.go +++ b/pkg/gui/branches_panel.go @@ -95,9 +95,12 @@ func (gui *Gui) refreshBranches(g *gocui.Gui) error { } gui.State.Branches = builder.Build() - gui.refreshSelectedLine(&gui.State.Panels.Branches.SelectedLine, len(gui.State.Branches)) - if err := gui.RenderSelectedBranchUpstreamDifferences(); err != nil { - return err + // TODO: if we're in the remotes view and we've just deleted a remote we need to refresh accordingly + if gui.getBranchesView().Context == "local-branches" { + gui.refreshSelectedLine(&gui.State.Panels.Branches.SelectedLine, len(gui.State.Branches)) + if err := gui.RenderSelectedBranchUpstreamDifferences(); err != nil { + return err + } } return gui.refreshStatus(g) @@ -105,6 +108,20 @@ func (gui *Gui) refreshBranches(g *gocui.Gui) error { return nil } +func (gui *Gui) renderLocalBranchesWithSelection() error { + branchesView := gui.getBranchesView() + + gui.refreshSelectedLine(&gui.State.Panels.Branches.SelectedLine, len(gui.State.Branches)) + if err := gui.renderListPanel(branchesView, gui.State.Branches); err != nil { + return err + } + if err := gui.handleBranchSelect(gui.g, branchesView); err != nil { + return err + } + + return nil +} + // specific functions func (gui *Gui) handleBranchPress(g *gocui.Gui, v *gocui.View) error { @@ -350,26 +367,11 @@ func (gui *Gui) switchBranchesPanelContext(context string) error { switch context { case "local-branches": - if err := gui.renderListPanel(branchesView, gui.State.Branches); err != nil { - return err - } - if err := gui.handleBranchSelect(gui.g, gui.getBranchesView()); err != nil { - return err - } + return gui.renderLocalBranchesWithSelection() case "remotes": - if err := gui.renderListPanel(branchesView, gui.State.Remotes); err != nil { - return err - } - if err := gui.handleRemoteSelect(gui.g, gui.getBranchesView()); err != nil { - return err - } + return gui.renderRemotesWithSelection() case "remote-branches": - if err := gui.renderListPanel(branchesView, gui.State.RemoteBranches); err != nil { - return err - } - if err := gui.handleRemoteBranchSelect(gui.g, gui.getBranchesView()); err != nil { - return err - } + return gui.renderRemoteBranchesWithSelection() } return nil diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go index db0bf7bdc..0638f6fba 100644 --- a/pkg/gui/confirmation_panel.go +++ b/pkg/gui/confirmation_panel.go @@ -17,12 +17,18 @@ import ( func (gui *Gui) wrappedConfirmationFunction(function func(*gocui.Gui, *gocui.View) error, returnFocusOnClose bool) func(*gocui.Gui, *gocui.View) error { return func(g *gocui.Gui, v *gocui.View) error { + + if err := gui.closeConfirmationPrompt(g, returnFocusOnClose); err != nil { + return err + } + if function != nil { if err := function(g, v); err != nil { return err } } - return gui.closeConfirmationPrompt(g, returnFocusOnClose) + + return nil } } diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index a67894999..eb817e76d 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -1041,6 +1041,22 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { Modifier: gocui.ModNone, Handler: gui.handleRemoteEnter, }, + { + ViewName: "branches", + Contexts: []string{"remotes"}, + Key: 'n', + Modifier: gocui.ModNone, + Handler: gui.handleAddRemote, + Description: gui.Tr.SLocalize("addNewRemote"), + }, + { + ViewName: "branches", + Contexts: []string{"remotes"}, + Key: 'd', + Modifier: gocui.ModNone, + Handler: gui.handleRemoveRemote, + Description: gui.Tr.SLocalize("removeRemote"), + }, { ViewName: "commits", Key: gocui.MouseLeft, diff --git a/pkg/gui/remote_branches_panel.go b/pkg/gui/remote_branches_panel.go index 544e8bf81..f47ea9f63 100644 --- a/pkg/gui/remote_branches_panel.go +++ b/pkg/gui/remote_branches_panel.go @@ -67,3 +67,17 @@ func (gui *Gui) handleRemoteBranchSelect(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleRemoteBranchesEscape(g *gocui.Gui, v *gocui.View) error { return gui.switchBranchesPanelContext("remotes") } + +func (gui *Gui) renderRemoteBranchesWithSelection() error { + branchesView := gui.getBranchesView() + + gui.refreshSelectedLine(&gui.State.Panels.RemoteBranches.SelectedLine, len(gui.State.RemoteBranches)) + if err := gui.renderListPanel(branchesView, gui.State.RemoteBranches); err != nil { + return err + } + if err := gui.handleRemoteBranchSelect(gui.g, branchesView); err != nil { + return err + } + + return nil +} diff --git a/pkg/gui/remotes_panel.go b/pkg/gui/remotes_panel.go index c63b2f07d..1402cfd0f 100644 --- a/pkg/gui/remotes_panel.go +++ b/pkg/gui/remotes_panel.go @@ -60,10 +60,23 @@ func (gui *Gui) refreshRemotes() error { gui.State.Remotes = remotes - gui.g.Update(func(g *gocui.Gui) error { - gui.refreshSelectedLine(&gui.State.Panels.Remotes.SelectedLine, len(gui.State.Remotes)) - return nil - }) + if gui.getBranchesView().Context == "remotes" { + return gui.renderRemotesWithSelection() + } + + return nil +} + +func (gui *Gui) renderRemotesWithSelection() error { + branchesView := gui.getBranchesView() + + gui.refreshSelectedLine(&gui.State.Panels.Remotes.SelectedLine, len(gui.State.Remotes)) + if err := gui.renderListPanel(branchesView, gui.State.Remotes); err != nil { + return err + } + if err := gui.handleRemoteSelect(gui.g, branchesView); err != nil { + return err + } return nil } @@ -82,3 +95,32 @@ func (gui *Gui) handleRemoteEnter(g *gocui.Gui, v *gocui.View) error { return gui.switchBranchesPanelContext("remote-branches") } + +func (gui *Gui) handleAddRemote(g *gocui.Gui, v *gocui.View) error { + branchesView := gui.getBranchesView() + return gui.createPromptPanel(g, branchesView, gui.Tr.SLocalize("newRemoteName"), "", func(g *gocui.Gui, v *gocui.View) error { + remoteName := gui.trimmedContent(v) + return gui.createPromptPanel(g, branchesView, gui.Tr.SLocalize("newRemoteUrl"), "", func(g *gocui.Gui, v *gocui.View) error { + remoteUrl := gui.trimmedContent(v) + if err := gui.GitCommand.AddRemote(remoteName, remoteUrl); err != nil { + return err + } + return gui.refreshRemotes() + }) + }) +} + +func (gui *Gui) handleRemoveRemote(g *gocui.Gui, v *gocui.View) error { + remote := gui.getSelectedRemote() + if remote == nil { + return nil + } + return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("removeRemote"), gui.Tr.SLocalize("removeRemotePrompt")+" '"+remote.Name+"'?", func(*gocui.Gui, *gocui.View) error { + if err := gui.GitCommand.RemoveRemote(remote.Name); err != nil { + return err + } + + return gui.refreshRemotes() + + }, nil) +} diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 62c762fdd..135c52bda 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -849,6 +849,21 @@ func addEnglish(i18nObject *i18n.Bundle) error { }, &i18n.Message{ ID: "ReturnToRemotesList", Other: `return to remotes list`, + }, &i18n.Message{ + ID: "addNewRemote", + Other: `add new remote`, + }, &i18n.Message{ + ID: "newRemoteName", + Other: `New remote name:`, + }, &i18n.Message{ + ID: "newRemoteUrl", + Other: `New remote url:`, + }, &i18n.Message{ + ID: "removeRemote", + Other: `remove remote`, + }, &i18n.Message{ + ID: "removeRemotePrompt", + Other: "Are you sure you want to remove remote", }, ) }