summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md5
-rw-r--r--commits_panel.go218
-rw-r--r--confirmation_panel.go6
-rw-r--r--files_panel.go5
-rw-r--r--gui.go10
-rw-r--r--status_panel.go68
6 files changed, 153 insertions, 159 deletions
diff --git a/README.md b/README.md
index 61ede7d09..90791b1f9 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
-# lazygit
+# lazygit [![Go Report Card](https://goreportcard.com/badge/github.com/jesseduffield/lazygit)](https://goreportcard.com/report/github.com/jesseduffield/lazygit)
+
A simple terminal UI for git commands, written in Go with the [gocui](https://github.com/jroimartin/gocui "gocui") library.
Are YOU tired of typing every git command directly into the terminal, but you're too stubborn to use Sourcetree because you'll never forgive Atlassian for making Jira? This is the app for you!
@@ -20,7 +21,7 @@ If you want, you can also add an alias for this with `echo "alias lg='lazygit'"
- Adding files easily
- Resolving merge conflicts
- Easily check out recent branches
-- Scroll through logs/diffs of branches/commits/stash
+- Scroll through logs/diffs of branches/commits/stash
- Quick pushing/pulling
- Squash down and rename commits
diff --git a/commits_panel.go b/commits_panel.go
index 767e49bcd..048807ca9 100644
--- a/commits_panel.go
+++ b/commits_panel.go
@@ -1,138 +1,138 @@
package main
import (
- "errors"
+ "errors"
- "github.com/fatih/color"
- "github.com/jesseduffield/gocui"
+ "github.com/fatih/color"
+ "github.com/jesseduffield/gocui"
)
var (
- // ErrNoCommits : When no commits are found for the branch
- ErrNoCommits = errors.New("No commits for this branch")
+ // ErrNoCommits : When no commits are found for the branch
+ ErrNoCommits = errors.New("No commits for this branch")
)
func refreshCommits(g *gocui.Gui) error {
- g.Update(func(*gocui.Gui) error {
- state.Commits = getCommits()
- v, err := g.View("commits")
- if err != nil {
- panic(err)
- }
- v.Clear()
- red := color.New(color.FgRed)
- yellow := color.New(color.FgYellow)
- white := color.New(color.FgWhite)
- shaColor := white
- for _, commit := range state.Commits {
- if commit.Pushed {
- shaColor = red
- } else {
- shaColor = yellow
- }
- shaColor.Fprint(v, commit.Sha+" ")
- white.Fprintln(v, commit.Name)
- }
- refreshStatus(g)
- return nil
- })
- return nil
+ g.Update(func(*gocui.Gui) error {
+ state.Commits = getCommits()
+ v, err := g.View("commits")
+ if err != nil {
+ panic(err)
+ }
+ v.Clear()
+ red := color.New(color.FgRed)
+ yellow := color.New(color.FgYellow)
+ white := color.New(color.FgWhite)
+ shaColor := white
+ for _, commit := range state.Commits {
+ if commit.Pushed {
+ shaColor = red
+ } else {
+ shaColor = yellow
+ }
+ shaColor.Fprint(v, commit.Sha+" ")
+ white.Fprintln(v, commit.Name)
+ }
+ refreshStatus(g)
+ return nil
+ })
+ return nil
}
func handleResetToCommit(g *gocui.Gui, commitView *gocui.View) error {
- return createConfirmationPanel(g, commitView, "Reset To Commit", "Are you sure you want to reset to this commit?", func(g *gocui.Gui, v *gocui.View) error {
- commit, err := getSelectedCommit(g)
- devLog(commit)
- if err != nil {
- panic(err)
- }
- if output, err := gitResetToCommit(commit.Sha); err != nil {
- return createErrorPanel(g, output)
- }
- if err := refreshCommits(g); err != nil {
- panic(err)
- }
- if err := refreshFiles(g); err != nil {
- panic(err)
- }
- resetOrigin(commitView)
- return handleCommitSelect(g, nil)
- }, nil)
+ return createConfirmationPanel(g, commitView, "Reset To Commit", "Are you sure you want to reset to this commit?", func(g *gocui.Gui, v *gocui.View) error {
+ commit, err := getSelectedCommit(g)
+ devLog(commit)
+ if err != nil {
+ panic(err)
+ }
+ if output, err := gitResetToCommit(commit.Sha); err != nil {
+ return createErrorPanel(g, output)
+ }
+ if err := refreshCommits(g); err != nil {
+ panic(err)
+ }
+ if err := refreshFiles(g); err != nil {
+ panic(err)
+ }
+ resetOrigin(commitView)
+ return handleCommitSelect(g, nil)
+ }, nil)
}
func renderCommitsOptions(g *gocui.Gui) error {
- return renderOptionsMap(g, map[string]string{
- "s": "squash down",
- "r": "rename",
- "g": "reset to this commit",
- "← → ↑ ↓": "navigate",
- })
+ return renderOptionsMap(g, map[string]string{
+ "s": "squash down",
+ "r": "rename",
+ "g": "reset to this commit",
+ "← → ↑ ↓": "navigate",
+ })
}
func handleCommitSelect(g *gocui.Gui, v *gocui.View) error {
- if err := renderCommitsOptions(g); err != nil {
- return err
- }
- commit, err := getSelectedCommit(g)
- if err != nil {
- if err != ErrNoCommits {
- return err
- }
- return renderString(g, "main", "No commits for this branch")
- }
- commitText := gitShow(commit.Sha)
- return renderString(g, "main", commitText)
+ if err := renderCommitsOptions(g); err != nil {
+ return err
+ }
+ commit, err := getSelectedCommit(g)
+ if err != nil {
+ if err != ErrNoCommits {
+ return err
+ }
+ return renderString(g, "main", "No commits for this branch")
+ }
+ commitText := gitShow(commit.Sha)
+ return renderString(g, "main", commitText)
}
func handleCommitSquashDown(g *gocui.Gui, v *gocui.View) error {
- if getItemPosition(v) != 0 {
- return createErrorPanel(g, "Can only squash topmost commit")
- }
- if len(state.Commits) == 1 {
- return createErrorPanel(g, "You have no commits to squash with")
- }
- commit, err := getSelectedCommit(g)
- if err != nil {
- return err
- }
- if output, err := gitSquashPreviousTwoCommits(commit.Name); err != nil {
- return createErrorPanel(g, output)
- }
- if err := refreshCommits(g); err != nil {
- panic(err)
- }
- refreshStatus(g)
- return handleCommitSelect(g, v)
+ if getItemPosition(v) != 0 {
+ return createErrorPanel(g, "Can only squash topmost commit")
+ }
+ if len(state.Commits) == 1 {
+ return createErrorPanel(g, "You have no commits to squash with")
+ }
+ commit, err := getSelectedCommit(g)
+ if err != nil {
+ return err
+ }
+ if output, err := gitSquashPreviousTwoCommits(commit.Name); err != nil {
+ return createErrorPanel(g, output)
+ }
+ if err := refreshCommits(g); err != nil {
+ panic(err)
+ }
+ refreshStatus(g)
+ return handleCommitSelect(g, v)
}
func handleRenameCommit(g *gocui.Gui, v *gocui.View) error {
- if getItemPosition(v) != 0 {
- return createErrorPanel(g, "Can only rename topmost commit")
- }
- createPromptPanel(g, v, "Rename Commit", func(g *gocui.Gui, v *gocui.View) error {
- if output, err := gitRenameCommit(v.Buffer()); err != nil {
- return createErrorPanel(g, output)
- }
- if err := refreshCommits(g); err != nil {
- panic(err)
- }
- return handleCommitSelect(g, v)
- })
- return nil
+ if getItemPosition(v) != 0 {
+ return createErrorPanel(g, "Can only rename topmost commit")
+ }
+ createPromptPanel(g, v, "Rename Commit", func(g *gocui.Gui, v *gocui.View) error {
+ if output, err := gitRenameCommit(v.Buffer()); err != nil {
+ return createErrorPanel(g, output)
+ }
+ if err := refreshCommits(g); err != nil {
+ panic(err)
+ }
+ return handleCommitSelect(g, v)
+ })
+ return nil
}
func getSelectedCommit(g *gocui.Gui) (Commit, error) {
- v, err := g.View("commits")
- if err != nil {
- panic(err)
- }
- if len(state.Commits) == 0 {
- return Commit{}, ErrNoCommits
- }
- lineNumber := getItemPosition(v)
- if lineNumber > len(state.Commits)-1 {
- colorLog(color.FgRed, "potential error in getSelected Commit (mismatched ui and state)", state.Commits, lineNumber)
- return state.Commits[len(state.Commits)-1], nil
- }
- return state.Commits[lineNumber], nil
+ v, err := g.View("commits")
+ if err != nil {
+ panic(err)
+ }
+ if len(state.Commits) == 0 {
+ return Commit{}, ErrNoCommits
+ }
+ lineNumber := getItemPosition(v)
+ if lineNumber > len(state.Commits)-1 {
+ colorLog(color.FgRed, "potential error in getSelected Commit (mismatched ui and state)", state.Commits, lineNumber)
+ return state.Commits[len(state.Commits)-1], nil
+ }
+ return state.Commits[lineNumber], nil
}
diff --git a/confirmation_panel.go b/confirmation_panel.go
index a773c0059..2508748f6 100644
--- a/confirmation_panel.go
+++ b/confirmation_panel.go
@@ -103,10 +103,8 @@ func setKeyBindings(g *gocui.Gui, handleYes, handleNo func(*gocui.Gui, *gocui.Vi
if err := g.SetKeybinding("confirmation", gocui.KeyEnter, gocui.ModNone, wrappedConfirmationFunction(handleYes)); err != nil {
return err
}
- if err := g.SetKeybinding("confirmation", gocui.KeyEsc, gocui.ModNone, wrappedConfirmationFunction(handleNo)); err != nil {
- return err
- }
- return nil
+
+ return g.SetKeybinding("confirmation", gocui.KeyEsc, gocui.ModNone, wrappedConfirmationFunction(handleNo))
}
func createMessagePanel(g *gocui.Gui, currentView *gocui.View, title, prompt string) error {
diff --git a/files_panel.go b/files_panel.go
index 52d4137e3..ad4f9e809 100644
--- a/files_panel.go
+++ b/files_panel.go
@@ -59,11 +59,8 @@ func handleFilePress(g *gocui.Gui, v *gocui.View) error {
if err := refreshFiles(g); err != nil {
return err
}
- if err := handleFileSelect(g, v); err != nil {
- return err
- }
- return nil
+ return handleFileSelect(g, v)
}
func getSelectedFile(g *gocui.Gui) (GitFile, error) {
diff --git a/gui.go b/gui.go
index 70f12beca..2e8672528 100644
--- a/gui.go
+++ b/gui.go
@@ -197,10 +197,8 @@ func keybindings(g *gocui.Gui) error {
if err := g.SetKeybinding("stash", 'k', gocui.ModNone, handleStashPop); err != nil {
return err
}
- if err := g.SetKeybinding("stash", 'd', gocui.ModNone, handleStashDrop); err != nil {
- return err
- }
- return nil
+
+ return g.SetKeybinding("stash", 'd', gocui.ModNone, handleStashDrop)
}
func layout(g *gocui.Gui) error {
@@ -230,10 +228,10 @@ func layout(g *gocui.Gui) error {
v.Wrap = true
}
return nil
- } else {
- g.DeleteView("limit")
}
+ g.DeleteView("limit")
+
optionsTop := height - 2
// hiding options if there's not enough space
if height < 30 {
diff --git a/status_panel.go b/status_panel.go
index cbc6956a8..6e3ec35e8 100644
--- a/status_panel.go
+++ b/status_panel.go
@@ -1,43 +1,43 @@
package main
import (
- "fmt"
- "time"
+ "fmt"
+ "time"
- "github.com/fatih/color"
- "github.com/jesseduffield/gocui"
+ "github.com/fatih/color"
+ "github.com/jesseduffield/gocui"
)
func refreshStatus(g *gocui.Gui) error {
- v, err := g.View("status")
- if err != nil {
- panic(err)
- }
- // for some reason if this isn't wrapped in an update the clear seems to
- // be applied after the other things or something like that; the panel's
- // contents end up cleared
- g.Update(func(*gocui.Gui) error {
- v.Clear()
- pushables, pullables := gitUpstreamDifferenceCount()
- fmt.Fprint(v, "↑"+pushables+"↓"+pullables)
- branches := state.Branches
- if err := updateHasMergeConflictStatus(); err != nil {
- return err
- }
- if state.HasMergeConflicts {
- colour := color.New(color.FgYellow)
- fmt.Fprint(v, coloredString(" (merging)", colour))
- }
- if len(branches) == 0 {
- return nil
- }
- branch := branches[0]
- // utilising the fact these all have padding to only grab the name
- // from the display string with the existing coloring applied
- fmt.Fprint(v, " "+branch.DisplayString[4:])
- colorLog(color.FgCyan, time.Now().Sub(startTime))
- return nil
- })
+ v, err := g.View("status")
+ if err != nil {
+ panic(err)
+ }
+ // for some reason if this isn't wrapped in an update the clear seems to
+ // be applied after the other things or something like that; the panel's
+ // contents end up cleared
+ g.Update(func(*gocui.Gui) error {
+ v.Clear()
+ pushables, pullables := gitUpstreamDifferenceCount()
+ fmt.Fprint(v, "↑"+pushables+"↓"+pullables)
+ branches := state.Branches
+ if err := updateHasMergeConflictStatus(); err != nil {
+ return err
+ }
+ if state.HasMergeConflicts {
+ colour := color.New(color.FgYellow)
+ fmt.Fprint(v, coloredString(" (merging)", colour))
+ }
+ if len(branches) == 0 {
+ return nil
+ }
+ branch := branches[0]
+ // utilising the fact these all have padding to only grab the name
+ // from the display string with the existing coloring applied
+ fmt.Fprint(v, " "+branch.DisplayString[4:])
+ colorLog(color.FgCyan, time.Now().Sub(startTime))
+ return nil
+ })
- return nil
+ return nil
}