summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pkg/app/app.go3
-rw-r--r--pkg/commands/branch.go15
-rw-r--r--pkg/commands/git.go35
-rw-r--r--pkg/commands/git_test.go6
-rw-r--r--pkg/gui/branches_panel.go70
-rw-r--r--pkg/gui/commit_message_panel.go8
-rw-r--r--pkg/gui/commits_panel.go3
-rw-r--r--pkg/gui/confirmation_panel.go11
-rw-r--r--pkg/gui/files_panel.go4
-rw-r--r--pkg/gui/gui.go29
-rw-r--r--pkg/gui/keybindings.go60
-rw-r--r--pkg/gui/menu_panel.go12
-rw-r--r--pkg/gui/merge_panel.go7
-rw-r--r--pkg/gui/stash_panel.go2
-rw-r--r--pkg/gui/status_panel.go6
-rw-r--r--pkg/gui/view_helpers.go66
-rw-r--r--pkg/i18n/english.go6
-rw-r--r--pkg/utils/utils_test.go11
18 files changed, 223 insertions, 131 deletions
diff --git a/pkg/app/app.go b/pkg/app/app.go
index b43f9568c..74152b08b 100644
--- a/pkg/app/app.go
+++ b/pkg/app/app.go
@@ -52,6 +52,9 @@ func newLogger(config config.AppConfigurer) *logrus.Entry {
} else {
log = newProductionLogger(config)
}
+
+ // highly recommended: tail -f development.log | humanlog
+ // https://github.com/aybabtme/humanlog
log.Formatter = &logrus.JSONFormatter{}
if config.GetUserConfig().GetString("reporting") == "on" {
diff --git a/pkg/commands/branch.go b/pkg/commands/branch.go
index 19553a26b..49655c41a 100644
--- a/pkg/commands/branch.go
+++ b/pkg/commands/branch.go
@@ -1,6 +1,7 @@
package commands
import (
+ "fmt"
"strings"
"github.com/fatih/color"
@@ -10,13 +11,21 @@ import (
// Branch : A git branch
// duplicating this for now
type Branch struct {
- Name string
- Recency string
+ Name string
+ Recency string
+ Pushables string
+ Pullables string
+ Selected bool
}
// GetDisplayStrings returns the dispaly string of branch
func (b *Branch) GetDisplayStrings() []string {
- return []string{b.Recency, utils.ColoredString(b.Name, b.GetColor())}
+ displayName := utils.ColoredString(b.Name, b.GetColor())
+ if b.Selected && b.Pushables != "" && b.Pullables != "" {
+ displayName = fmt.Sprintf("↑%s↓%s %s", b.Pushables, b.Pullables, displayName)
+ }
+
+ return []string{b.Recency, displayName}
}
// GetColor branch color
diff --git a/pkg/commands/git.go b/pkg/commands/git.go
index e185b0fbd..b78db1fa6 100644
--- a/pkg/commands/git.go
+++ b/pkg/commands/git.go
@@ -130,17 +130,6 @@ func (c *GitCommand) GetStashEntryDiff(index int) (string, error) {
// GetStatusFiles git status files
func (c *GitCommand) GetStatusFiles() []*File {
-
- // files := []*File{}
- // for i := 0; i < 100; i++ {
- // files = append(files, &File{
- // Name: strconv.Itoa(i),
- // DisplayString: strconv.Itoa(i),
- // Type: "file",
- // })
- // }
- // return files
-
statusOutput, _ := c.GitStatus()
statusStrings := utils.SplitLines(statusOutput)
files := []*File{}
@@ -165,7 +154,6 @@ func (c *GitCommand) GetStatusFiles() []*File {
}
files = append(files, file)
}
- c.Log.Info(files) // TODO: use a dumper-esque log here
return files
}
@@ -228,14 +216,24 @@ func (c *GitCommand) ResetAndClean() error {
return c.OSCommand.RunCommand("git clean -fd")
}
-// UpstreamDifferenceCount checks how many pushables/pullables there are for the
+func (c *GitCommand) GetCurrentBranchUpstreamDifferenceCount() (string, string) {
+ return c.GetCommitDifferences("HEAD", "@{u}")
+}
+
+func (c *GitCommand) GetBranchUpstreamDifferenceCount(branchName string) (string, string) {
+ upstream := "origin" // hardcoded for now
+ return c.GetCommitDifferences(branchName, fmt.Sprintf("%s/%s", upstream, branchName))
+}
+
+// GetCommitDifferences checks how many pushables/pullables there are for the
// current branch
-func (c *GitCommand) UpstreamDifferenceCount() (string, string) {
- pushableCount, err := c.OSCommand.RunCommandWithOutput("git rev-list @{u}..HEAD --count")
+func (c *GitCommand) GetCommitDifferences(from, to string) (string, string) {
+ command := "git rev-list %s..%s --count"
+ pushableCount, err := c.OSCommand.RunCommandWithOutput(fmt.Sprintf(command, to, from))
if err != nil {
return "?", "?"
}
- pullableCount, err := c.OSCommand.RunCommandWithOutput("git rev-list HEAD..@{u} --count")
+ pullableCount, err := c.OSCommand.RunCommandWithOutput(fmt.Sprintf(command, from, to))
if err != nil {
return "?", "?"
}
@@ -618,3 +616,8 @@ func (c *GitCommand) ApplyPatch(patch string) (string, error) {
return c.OSCommand.RunCommandWithOutput(fmt.Sprintf("git apply --cached %s", filename))
}
+
+func (c *GitCommand) FastForward(branchName string) error {
+ upstream := "origin" // hardcoding for now
+ return c.OSCommand.RunCommand(fmt.Sprintf("git fetch %s %s:%s", upstream, branchName, branchName))
+}
diff --git a/pkg/commands/git_test.go b/pkg/commands/git_test.go
index 206696b22..997054bca 100644
--- a/pkg/commands/git_test.go
+++ b/pkg/commands/git_test.go
@@ -557,8 +557,8 @@ func TestGitCommandMergeStatusFiles(t *testing.T) {
}
}
-// TestGitCommandUpstreamDifferentCount is a function.
-func TestGitCommandUpstreamDifferentCount(t *testing.T) {
+// TestGitCommandGetCommitDifferences is a function.
+func TestGitCommandGetCommitDifferences(t *testing.T) {
type scenario struct {
testName string
command func(string, ...string) *exec.Cmd
@@ -610,7 +610,7 @@ func TestGitCommandUpstreamDifferentCount(t *testing.T) {
t.Run(s.testName, func(t *testing.T) {
gitCmd := newDummyGitCommand()
gitCmd.OSCommand.command = s.command
- s.test(gitCmd.UpstreamDifferenceCount())
+ s.test(gitCmd.GetCommitDifferences("HEAD", "@{u}"))
})
}
}
diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go
index 809deaa7d..a0e3448f6 100644
--- a/pkg/gui/branches_panel.go
+++ b/pkg/gui/branches_panel.go
@@ -7,7 +7,6 @@ import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/git"
- "github.com/jesseduffield/lazygit/pkg/utils"
)
// list panel functions
@@ -32,6 +31,9 @@ func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error {
return err
}
go func() {
+ _ = gui.RenderSelectedBranchUpstreamDifferences()
+ }()
+ go func() {
graph, err := gui.GitCommand.GetBranchGraph(branch.Name)
if err != nil && strings.HasPrefix(graph, "fatal: ambiguous argument") {
graph = gui.Tr.SLocalize("NoTrackingThisBranch")
@@ -41,14 +43,23 @@ func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error {
return nil
}
+func (gui *Gui) RenderSelectedBranchUpstreamDifferences() error {
+ // here we tell the selected branch that it is selected.
+ // this is necessary for showing stats on a branch that is selected, because
+ // the displaystring function doesn't have access to gui state to tell if it's selected
+ for i, branch := range gui.State.Branches {
+ branch.Selected = i == gui.State.Panels.Branches.SelectedLine
+ }
+
+ branch := gui.getSelectedBranch()
+ branch.Pushables, branch.Pullables = gui.GitCommand.GetBranchUpstreamDifferenceCount(branch.Name)
+ return gui.renderListPanel(gui.getBranchesView(gui.g), gui.State.Branches)
+}
+
// gui.refreshStatus is called at the end of this because that's when we can
// be sure there is a state.Branches array to pick the current branch from
func (gui *Gui) refreshBranches(g *gocui.Gui) error {
g.Update(func(g *gocui.Gui) error {
- v, err := g.View("branches")
- if err != nil {
- panic(err)
- }
builder, err := git.NewBranchListBuilder(gui.Log, gui.GitCommand)
if err != nil {
return err
@@ -56,16 +67,13 @@ func (gui *Gui) refreshBranches(g *gocui.Gui) error {
gui.State.Branches = builder.Build()
gui.refreshSelectedLine(&gui.State.Panels.Branches.SelectedLine, len(gui.State.Branches))
-
- v.Clear()
- list, err := utils.RenderList(gui.State.Branches)
- if err != nil {
+ if err := gui.resetOrigin(gui.getBranchesView(gui.g)); err != nil {
+ return err
+ }
+ if err := gui.RenderSelectedBranchUpstreamDifferences(); err != nil {
return err
}
- fmt.Fprint(v, list)
-
- gui.resetOrigin(v)
return gui.refreshStatus(g)
})
return nil
@@ -74,7 +82,6 @@ func (gui *Gui) refreshBranches(g *gocui.Gui) error {
func (gui *Gui) handleBranchesNextLine(g *gocui.Gui, v *gocui.View) error {
panelState := gui.State.Panels.Branches
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Branches), false)
-
return gui.handleBranchSelect(gui.g, v)
}
@@ -99,7 +106,10 @@ func (gui *Gui) handleBranchPress(g *gocui.Gui, v *gocui.View) error {
if err := gui.createErrorPanel(g, err.Error()); err != nil {
return err
}
+ } else {
+ gui.State.Panels.Branches.SelectedLine = 0
}
+
return gui.refreshSidePanels(g)
}
@@ -213,3 +223,37 @@ func (gui *Gui) handleMerge(g *gocui.Gui, v *gocui.View) error {
}
return nil
}
+
+func (gui *Gui) handleFastForward(g *gocui.Gui, v *gocui.View) error {
+ branch := gui.getSelectedBranch()
+ if branch == nil {
+ return nil
+ }
+ if branch.Pushables == "" {
+ return nil
+ }
+ if branch.Pushables == "?" {
+ return gui.createErrorPanel(gui.g, "Cannot fast-forward a branch with no upstream")
+ }
+ if branch.Pushables != "0" {
+ return gui.createErrorPanel(gui.g, "Cannot fast-forward a branch with commits to push")
+ }
+ upstream := "origin" // hardcoding for now
+ message := gui.Tr.TemplateLocalize(
+ "Fetching",
+ Teml{
+ "from": fmt.Sprintf("%s/%s", upstream, branch.Name),
+ "to": branch.Name,
+ },
+ )
+ go func() {
+ _ = gui.createMessagePanel(gui.g, v, "", message)
+ if err := gui.GitCommand.FastForward(branch.Name); err != nil {
+ _ = gui.createErrorPanel(gui.g, err.Error())
+ } else {
+ _ = gui.closeConfirmationPrompt(gui.g)
+ _ = gui.RenderSelectedBranchUpstreamDifferences()
+ }
+ }()
+ return nil
+}
diff --git a/pkg/gui/commit_message_panel.go b/pkg/gui/commit_message_panel.go
index 60058d48c..33eb5b218 100644
--- a/pkg/gui/commit_message_panel.go
+++ b/pkg/gui/commit_message_panel.go
@@ -24,10 +24,10 @@ func (gui *Gui) handleCommitConfirm(g *gocui.Gui, v *gocui.View) error {
return gui.Errors.ErrSubProcess
}
v.Clear()
- v.SetCursor(0, 0)
- v.SetOrigin(0, 0)
- g.SetViewOnBottom("commitMessage")
- gui.switchFocus(g, v, gui.getFilesView(g))
+ _ = v.SetCursor(0, 0)
+ _ = v.SetOrigin(0, 0)
+ _, _ = g.SetViewOnBottom("commitMessage")
+ _ = gui.switchFocus(g, v, gui.getFilesView(g))
return gui.refreshSidePanels(g)
}
diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go
index 2591fa240..4ff79960d 100644
--- a/pkg/gui/commits_panel.go
+++ b/pkg/gui/commits_panel.go
@@ -96,7 +96,8 @@ func (gui *Gui) handleResetToCommit(g *gocui.Gui, commitView *gocui.View) error
panic(err)
}
gui.resetOrigin(commitView)
- return gui.handleCommitSelect(g, nil)
+ gui.State.Panels.Commits.SelectedLine = 0
+ return gui.handleCommitSelect(g, commitView)
}, nil)
}
diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go
index afe53ca2c..30d5e0661 100644
--- a/pkg/gui/confirmation_panel.go
+++ b/pkg/gui/confirmation_panel.go
@@ -28,7 +28,7 @@ func (gui *Gui) wrappedConfirmationFunction(function func(*gocui.Gui, *gocui.Vie
func (gui *Gui) closeConfirmationPrompt(g *gocui.Gui) error {
view, err := g.View("confirmation")
if err != nil {
- panic(err)
+ return nil // if it's already been closed we can just return
}
if err := gui.returnFocus(g, view); err != nil {
panic(err)
@@ -77,11 +77,10 @@ func (gui *Gui) prepareConfirmationPanel(currentView *gocui.View, title, prompt
confirmationView.Wrap = true
confirmationView.FgColor = gocui.ColorWhite
}
- confirmationView.Clear()
-
- if err := gui.switchFocus(gui.g, currentView, confirmationView); err != nil {
- return nil, err
- }
+ gui.g.Update(func(g *gocui.Gui) error {
+ confirmationView.Clear()
+ return gui.switchFocus(gui.g, currentView, confirmationView)
+ })
return confirmationView, nil
}
diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go
index 231e5d488..95b4f80a4 100644
--- a/pkg/gui/files_panel.go
+++ b/pkg/gui/files_panel.go
@@ -64,7 +64,7 @@ func (gui *Gui) refreshFiles(g *gocui.Gui) error {
fmt.Fprint(filesView, list)
if filesView == g.CurrentView() {
- gui.handleFileSelect(g, filesView)
+ return gui.handleFileSelect(g, filesView)
}
return nil
})
@@ -411,7 +411,7 @@ func (gui *Gui) pushWithForceFlag(currentView *gocui.View, force bool) error {
func (gui *Gui) pushFiles(g *gocui.Gui, v *gocui.View) error {
// if we have pullables we'll ask if the user wants to force push
- _, pullables := gui.GitCommand.UpstreamDifferenceCount()
+ _, pullables := gui.GitCommand.GetCurrentBranchUpstreamDifferenceCount()
if pullables == "?" || pullables == "0" {
return gui.pushWithForceFlag(v, false)
}
diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go
index 6a7eaaf98..26ebd5f2b 100644
--- a/pkg/gui/gui.go
+++ b/pkg/gui/gui.go
@@ -72,6 +72,9 @@ type Gui struct {
statusManager *statusManager
}
+// for now the staging panel state, unlike the other panel states, is going to be
+// non-mutative, so that we don't accidentally end up
+// with mismatches of data. We might change this in the future
type stagingPanelState struct {
SelectedLine int
StageableLines []int
@@ -233,7 +236,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
}
return nil
} else {
- g.SetViewOnBottom("limit")
+ _, _ = g.SetViewOnBottom("limit")
}
g.DeleteView("limit")
@@ -364,14 +367,14 @@ func (gui *Gui) layout(g *gocui.Gui) error {
return err
}
- gui.g.SetCurrentView(filesView.Name())
+ if _, err := gui.g.SetCurrentView(filesView.Name()); err != nil {
+ return err
+ }
- gui.refreshSidePanels(gui.g)
- if gui.g.CurrentView().Name() != "menu" {
- if err := gui.renderGlobalOptions(g); err != nil {
- return err
- }
+ if err := gui.refreshSidePanels(gui.g); err != nil {
+ return err
}
+
if err := gui.switchFocus(g, nil, filesView); err != nil {
return err
}
@@ -394,8 +397,10 @@ func (gui *Gui) layout(g *gocui.Gui) error {
}
}
- // TODO: comment-out
- gui.Log.Info(utils.AsJson(gui.State))
+ // here is a good place log some stuff
+ // if you download humanlog and do tail -f development.log | humanlog
+ // this will let you see these branches as prettified json
+ // gui.Log.Info(utils.AsJson(gui.State.Branches[0:4]))
return gui.resizeCurrentPopupPanel(g)
}
@@ -435,8 +440,8 @@ func (gui *Gui) renderAppStatus(g *gocui.Gui) error {
return nil
}
-func (gui *Gui) renderGlobalOptions(g *gocui.Gui) error {
- return gui.renderOptionsMap(g, map[string]string{
+func (gui *Gui) renderGlobalOptions() error {
+ return gui.renderOptionsMap(map[string]string{
"PgUp/PgDn": gui.Tr.SLocalize("scroll"),
"← → ↑ ↓": gui.Tr.SLocalize("navigate"),
"esc/q": gui.Tr.SLocalize("close"),
@@ -467,7 +472,7 @@ func (gui *Gui) Run() error {
}
gui.goEvery(g, time.Second*60, gui.fetch)
- // gui.goEvery(g, time.Second*2, gui.refreshFiles) // TODO: comment back in
+ gui.goEvery(g, time.Second*2, gui.refreshFiles)
gui.goEvery(g, time.Millisecond*50, gui.updateLoader)
gui.goEvery(g, time.Millisecond*50, gui.renderAppStatus)
diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go
index c02074d6f..b0c141d73 100644
--- a/pkg/gui/keybindings.go
+++ b/pkg/gui/keybindings.go
@@ -219,12 +219,7 @@ func (gui *Gui) GetKeybindings() []*Binding {
Handler: gui.handleSwitchToStagingPanel,
Description: gui.Tr.SLocalize("StageLines"),
KeyReadable: "enter",
- },
- {ViewName: "files", Key: 'k', Modifier: gocui.ModNone, Handler: gui.handleFilesPrevLine},
- {ViewName: "files", Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: gui.handleFilesPrevLine},
- {ViewName: "files", Key: 'j', Modifier: gocui.ModNone, Handler: gui.handleFilesNextLine},
- {ViewName: "files", Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: gui.handleFilesNextLine},
- {
+ }, {
ViewName: "main",
Key: gocui.KeyEsc,
Modifier: gocui.ModNone,
@@ -327,12 +322,13 @@ func (gui *Gui) GetKeybindings() []*Binding {
Modifier: gocui.ModNone,
Handler: gui.handleMerge,
Description: gui.Tr.SLocalize("mergeIntoCurrentBranch"),
- },
- {ViewName: "branches", Key: 'k', Modifier: gocui.ModNone, Handler: gui.handleBranchesPrevLine},
- {ViewName: "branches", Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: gui.handleBranchesPrevLine},
- {ViewName: "branches", Key: 'j', Modifier: gocui.ModNone, Handler: gui.handleBranchesNextLine},
- {ViewName: "branches", Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: gui.handleBranchesNextLine},
- {
+ }, {
+ ViewName: "branches",
+ Key: 'f',
+ Modifier: gocui.ModNone,
+ Handler: gui.handleFastForward,
+ Description: gui.Tr.SLocalize("FastForward"),
+ }, {
ViewName: "commits",
Key: 's',
Modifier: gocui.ModNone,
@@ -362,12 +358,7 @@ func (gui *Gui) GetKeybindings() []*Binding {
Modifier: gocui.ModNone,
Handler: gui.handleCommitFixup,
Description: gui.Tr.SLocalize("fixupCommit"),
- },
- {ViewName: "commits", Key: 'k', Modifier: gocui.ModNone, Handler: gui.handleCommitsPrevLine},
- {ViewName: "commits", Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: gui.handleCommitsPrevLine},
- {ViewName: "commits", Key: 'j', Modifier: gocui.ModNone, Handler: gui.handleCommitsNextLine},
- {ViewName: "commits", Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: gui.handleCommitsNextLine},
- {
+ }, {
ViewName: "stash",
Key: gocui.KeySpace,
Modifier: gocui.ModNone,
@@ -386,12 +377,7 @@ func (gui *Gui) GetKeybindings() []*Binding {
Modifier: gocui.ModNone,
Handler: gui.handleStashDrop,
Description: gui.Tr.SLocalize("drop"),
- },
- {ViewName: "stash", Key: 'k', Modifier: gocui.ModNone, Handler: gui.handleStashPrevLine},
- {ViewName: "stash", Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: gui.handleStashPrevLine},
- {ViewName: "stash", Key: 'j', Modifier: gocui.ModNone, Handler: gui.handleStashNextLine},
- {ViewName: "stash", Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: gui.handleStashNextLine},
- {
+ }, {
ViewName: "commitMessage",
Key: gocui.KeyEnter,
Modifier: gocui.ModNone,
@@ -411,11 +397,7 @@ func (gui *Gui) GetKeybindings() []*Binding {
Key: 'q',
Modifier: gocui.ModNone,
Handler: gui.handleMenuClose,
- },
- {ViewName: "menu", Key: 'k', Modifier: gocui.ModNone, Handler: gui.handleMenuPrevLine},
- {ViewName: "menu", Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: gui.handleMenuPrevLine},
- {ViewName: "menu", Key: 'j', Modifier: gocui.ModNone, Handler: gui.handleMenuNextLine},
- {ViewName: "menu", Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: gui.handleMenuNextLine}, {
+ }, {
ViewName: "staging",
Key: gocui.KeyEsc,
Modifier: gocui.ModNone,
@@ -487,6 +469,26 @@ func (gui *Gui) GetKeybindings() []*Binding {
}...)
}
+ listPanelMap := map[string]struct {
+ prevLine func(*gocui.Gui, *gocui.View) error
+ nextLine func(*gocui.Gui, *gocui.View) error
+ }{
+ "menu": {prevLine: gui.handleMenuPrevLine, nextLine: gui.handleMenuNextLine},
+ "files": {prevLine: gui.handleFilesPrevLine, nextLine: gui.handleFilesNextLine},
+ "branches": {prevLine: gui.handleBranchesPrevLine, nextLine: gui.handleBranchesNextLine},
+ "commits": {prevLine: gui.handleCommitsPrevLine, nextLine: gui.handleCommitsNextLine},
+ "stash": {prevLine: gui.handleStashPrevLine, nextLine: gui.handleStashNextLine},
+ }
+
+ for viewName, functions := range listPanelMap {
+ bindings = append(bindings, []*Binding{
+ {ViewName: viewName, Key: 'k', Modifier: gocui.ModNone, Handler: functions.prevLine},
+ {ViewName: viewName, Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: functions.prevLine},
+ {ViewName: viewName, Key: 'j', Modifier: gocui.ModNone, Handler: functions.nextLine},
+ {ViewName: viewName, Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: functions.nextLine},
+ }...)
+ }
+
return bindings
}
diff --git a/pkg/gui/menu_panel.go b/pkg/gui/menu_panel.go
index 0d3d8cf2b..8ce60f6be 100644
--- a/pkg/gui/menu_panel.go
+++ b/pkg/gui/menu_panel.go
@@ -25,22 +25,18 @@ func (gui *Gui) handleMenuPrevLine(g *gocui.Gui, v *gocui.View) error {
panelState := gui.State.Panels.Menu
gui.changeSelectedLine(&panelState.SelectedLine, v.LinesHeight(), true)
- if err := gui.focusPoint(0, gui.State.Panels.Commits.SelectedLine, v); err != nil {
- return err
- }
-
return gui.handleMenuSelect(g, v)
}
// specific functions
-func (gui *Gui) renderMenuOptions(g *gocui.Gui) error {
+func (gui *Gui) renderMenuOptions() error {
optionsMap := map[string]string{
"esc/q": gui.Tr.SLocalize("close"),
"↑ ↓": gui.Tr.SLocalize("navigate"),
"space": gui.Tr.SLocalize("execute"),
}
- return gui.renderOptionsMap(g, optionsMap)
+ return gui.renderOptionsMap(optionsMap)
}
func (gui *Gui) handleMenuClose(g *gocui.Gui, v *gocui.View) error {
@@ -68,10 +64,6 @@ func (gui *Gui) createMenu(items interface{}, handlePress func(int) error) error
fmt.Fprint(menuView, list)
gui.State.Panels.Menu.SelectedLine = 0
- if err := gui.renderMenuOptions(gui.g); err != nil {
- return err
- }
-
wrappedHandlePress := func(g *gocui.Gui, v *gocui.View) error {
selectedLine := gui.State.Panels.Menu.SelectedLine
return handlePress(selectedLine)
diff --git a/pkg/gui/merge_panel.go b/pkg/gui/merge_panel.go
index e3da82f3c..2592275bf 100644
--- a/pkg/gui/merge_panel.go
+++ b/pkg/gui/merge_panel.go
@@ -194,9 +194,6 @@ func (gui *Gui) refreshMergePanel(g *gocui.Gui) error {
gui.State.ConflictIndex = len(gui.State.Conflicts) - 1
}
hasFocus := gui.currentViewName(g) == "main"
- if hasFocus {
- gui.renderMergeOptions(g)
- }
content, err := gui.coloredConflictFile(cat, gui.State.Conflicts, gui.State.ConflictIndex, gui.State.ConflictTop, hasFocus)
if err != nil {
return err
@@ -233,8 +230,8 @@ func (gui *Gui) switchToMerging(g *gocui.Gui) error {
return gui.refreshMergePanel(g)
}
-func (gui *Gui) renderMergeOptions(g *gocui.Gui) error {
- return gui.renderOptionsMap(g, map[string]string{
+func (gui *Gui) renderMergeOptions() error {
+ return gui.renderOptionsMap(map[string]string{
"↑ ↓": gui.Tr.SLocalize("selectHunk"),
"← →": gui.Tr.SLocalize("navigateConflicts"),
"space": gui.Tr.SLocalize("pickHunk"),
diff --git a/pkg/gui/stash_panel.go b/pkg/gui/stash_panel.go
index ef54ef997..306d61771 100644
--- a/pkg/gui/stash_panel.go
+++ b/pkg/gui/stash_panel.go
@@ -30,7 +30,7 @@ func (gui *Gui) handleStashEntrySelect(g *gocui.Gui, v *gocui.View) error {
go func() {
// doing this asynchronously cos it can take time
diff, _ := gui.GitCommand.GetStashEntryDiff(stashEntry.Index)
- gui.renderString(g, "main", diff)
+ _ = gui.renderString(g, "main", diff)
}()
return nil
}
diff --git a/pkg/gui/status_panel.go b/pkg/gui/status_panel.go
index 15f3f27d1..8d3b34dfe 100644
--- a/pkg/gui/status_panel.go
+++ b/pkg/gui/status_panel.go
@@ -19,7 +19,7 @@ func (gui *Gui) refreshStatus(g *gocui.Gui) error {
// contents end up cleared
g.Update(func(*gocui.Gui) error {
v.Clear()
- pushables, pullables := gui.GitCommand.UpstreamDifferenceCount()
+ pushables, pullables := gui.GitCommand.GetCurrentBranchUpstreamDifferenceCount()
fmt.Fprint(v, "↑"+pushables+"↓"+pullables)
branches := gui.State.Branches
if err := gui.updateHasMergeConflictStatus(); err != nil {
@@ -48,6 +48,8 @@ func (gui *Gui) handleCheckForUpdate(g *gocui.Gui, v *gocui.View) error {
}
func (gui *Gui) handleStatusSelect(g *gocui.Gui, v *gocui.View) error {
+ blue := color.New(color.FgBlue)
+
dashboardString := strings.Join(
[]string{
lazygitTitle(),
@@ -56,7 +58,7 @@ func (gui *Gui) handleStatusSelect(g *gocui.Gui, v *gocui.View) error {
"Config Options: https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md",
"Tutorial: https://youtu.be/VDXvbHZYeKY",
"Raise an Issue: https://github.com/jesseduffield/lazygit/issues",
- "Buy Jesse a coffee: https://donorbox.org/lazygit",
+ blue.Sprint("Buy Jesse a coffee: https://donorbox.org/lazygit"), // caffeine ain't free
}, "\n\n")
return gui.renderString(g, "main", dashboardString)
diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go
index 5b02b1ae9..1508daa1b 100644
--- a/pkg/gui/view_helpers.go
+++ b/pkg/gui/view_helpers.go
@@ -13,11 +13,16 @@ import (
var cyclableViews = []string{"status", "files", "branches", "commits", "stash"}
func (gui *Gui) refreshSidePanels(g *gocui.Gui) error {
- gui.refreshBranches(g)
- gui.refreshFiles(g)
- gui.refreshCommits(g)
- gui.refreshStashEntries(g)
- return nil
+ if err := gui.refreshBranches(g); err != nil {
+ return err
+ }
+ if err := gui.refreshFiles(g); err != nil {
+ return err
+ }
+ if err := gui.refreshCommits(g); err != nil {
+ return err
+ }
+ return gui.refreshStashEntries(g)
}
func (gui *Gui) nextView(g *gocui.Gui, v *gocui.View) error {
@@ -81,7 +86,7 @@ func (gui *Gui) previousView(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) newLineFocused(g *gocui.Gui, v *gocui.View) error {
switch v.Name() {
case "menu":
- return nil
+ return gui.handleMenuSelect(g, v)
case "status":
return gui.handleStatusSelect(g, v)
case "files":
@@ -160,6 +165,10 @@ func (gui *Gui) switchFocus(g *gocui.Gui, oldView, newView *gocui.View) error {
g.Cursor = newView.Editable
+ if err := gui.renderPanelOptions(); err != nil {
+ return err
+ }
+
return gui.newLineFocused(g, newView)
}
@@ -240,8 +249,8 @@ func (gui *Gui) optionsMapToString(optionsMap map[string]string) string {
return strings.Join(optionsArray, ", ")
}
-func (gui *Gui) renderOptionsMap(g *gocui.Gui, optionsMap map[string]string) error {
- return gui.renderString(g, "options", gui.optionsMapToString(optionsMap))
+func (gui *Gui) renderOptionsMap(optionsMap map[string]string) error {
+ return gui.renderString(gui.g, "options", gui.optionsMapToString(optionsMap))
}
// TODO: refactor properly
@@ -312,22 +321,6 @@ func (gui *Gui) resizePopupPanel(g *gocui.Gui, v *gocui.View) error {
return err
}
-// focusLine focuses and selects the given line
-func (gui *Gui) focusLine(lineNumber int, v *gocui.View) error {
- _, height := v.Size()
- overScroll := lineNumber - height + 1
- if overScroll < 0 {
- overScroll = 0
- }
- if err := v.SetOrigin(0, overScroll); err != nil {
- return err
- }
- if err := v.SetCursor(0, lineNumber-overScroll); err != nil {
- return err
- }
- return nil
-}
-
// generalFocusLine takes a lineNumber to focus, and a bottomLine to ensure we can see
func (gui *Gui) generalFocusLine(lineNumber int, bottomLine int, v *gocui.View) error {
_, height := v.Size()
@@ -367,3 +360,28 @@ func (gui *Gui) refreshSelectedLine(line *int, total int) {
*line = total - 1
}
}
+
+func (gui *Gui) renderListPanel(v *gocui.View, items interface{}) error {
+ gui.g.Update(func(g *gocui.Gui) error {
+ list, err := utils.RenderList(items)
+ if err != nil {
+ return gui.createErrorPanel(gui.g, err.Error())
+ }
+ v.Clear()
+ fmt.Fprint(v, list)
+ return nil
+ })
+ return nil
+}
+
+func (gui *Gui) renderPanelOptions() error {
+ currentView := gui.g.CurrentView()
+ switch currentView.Name() {
+ case "menu":
+ return gui.renderMenuOptions()
+ case "main":
+ return gui.renderMergeOptions()
+ default:
+ return gui.renderGlobalOptions()
+ }
+}
diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go
index 97b6addf6..9ff671476 100644
--- a/pkg/i18n/english.go
+++ b/pkg/i18n/english.go
@@ -435,6 +435,12 @@ func addEnglish(i18nObject *i18n.Bundle) error {
}, &i18n.Message{
ID: "CantFindHunk",
Other: `Could not find hunk`,
+ }, &i18n.Message{
+ ID: "FastForward",
+ Other: `fast-forward this branch from its upstream`,
+ }, &i18n.Message{
+ ID: "Fetching",
+ Other: "fetching and fast-forwarding {{.from}} -> {{.to}} ...",
},
)
}
diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go
index f03bc087a..f7545f5e9 100644
--- a/pkg/utils/utils_test.go
+++ b/pkg/utils/utils_test.go
@@ -517,3 +517,14 @@ func TestPrevIndex(t *testing.T) {
})
}
}
+
+func TestAsJson(t *testing.T) {
+ type myStruct struct {
+ a string
+ }
+
+ output := AsJson(&myStruct{a: "foo"})
+
+ // no idea why this is returning empty hashes but it's works in the app ¯\_(ツ)_/¯
+ assert.EqualValues(t, "{}", output)
+}