diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2018-08-18 12:08:21 +1000 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2018-08-18 12:08:21 +1000 |
commit | 4dc6d40b5a2d7b7ba882c92f3c62b7122fcd849d (patch) | |
tree | 11da254d4335b16f55d0177b4f2cf0a75d1cc28b | |
parent | df7d1df4cbad9065c29fef08d3e8d143d8836b3f (diff) | |
parent | 99d40c2f8ecdecd39df80b199f9ff1cc9eb90434 (diff) |
merge master
56 files changed, 12961 insertions, 146 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 000000000..c5f520b70 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,26 @@ +# Golang CircleCI 2.0 configuration file +# +# Check https://circleci.com/docs/2.0/language-go/ for more details +version: 2 +jobs: + build: + docker: + # specify the version + - image: circleci/golang:1.9 + + # Specify service dependencies here if necessary + # CircleCI maintains a library of pre-built images + # documented at https://circleci.com/docs/2.0/circleci-images/ + # - image: circleci/postgres:9.4 + + #### TEMPLATE_NOTE: go expects specific checkout path representing url + #### expecting it in the form of + #### /go/src/github.com/circleci/go-tool + #### /go/src/bitbucket.org/circleci/go-tool + working_directory: /go/src/github.com/jesseduffield/lazygit + steps: + - checkout + + # specify any bash command here prefixed with `run: ` + - run: go test -v ./... + - run: bash <(curl -s https://codecov.io/bash) diff --git a/Gopkg.lock b/Gopkg.lock index 8cf5c89e4..b8bb00dba 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -10,6 +10,14 @@ version = "v1.0.6" [[projects]] + branch = "master" + digest = "1:cd7ba2b29e93e2a8384e813dfc80ebb0f85d9214762e6ca89bb55a58092eab87" + name = "github.com/cloudfoundry/jibber_jabber" + packages = ["."] + pruneopts = "NUT" + revision = "bcc4c8345a21301bf47c032ff42dd1aae2fe3027" + +[[projects]] digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39" name = "github.com/davecgh/go-spew" packages = ["spew"] @@ -148,6 +156,18 @@ revision = "58046073cbffe2f25d425fe1331102f55cf719de" [[projects]] + digest = "1:2c34c77bf3ec848da26e48af58fc511ed52750961fa848399d122882b8890928" + name = "github.com/nicksnyder/go-i18n" + packages = [ + "v2/i18n", + "v2/internal", + "v2/internal/plural", + ] + pruneopts = "NUT" + revision = "a16b91a3ba80db3a2301c70d1d302d42251c9079" + version = "v2.0.0-beta.5" + +[[projects]] branch = "master" digest = "1:5fe20cfe4ef484c237cec9f947b2a6fa90bad4b8610fd014f0e4211e13d82d5d" name = "github.com/mitchellh/mapstructure" @@ -313,12 +333,14 @@ revision = "98c5dad5d1a0e8a73845ecc8897d0bd56586511d" [[projects]] - digest = "1:8029e9743749d4be5bc9f7d42ea1659471767860f0cdc34d37c3111bd308a295" + digest = "1:a95288ef1ef4dfad6cba7fe30843e1683f71bc28c912ca1ba3f6a539d44db739" name = "golang.org/x/text" packages = [ "internal/gen", + "internal/tag", "internal/triegen", "internal/ucd", + "language", "transform", "unicode/cldr", "unicode/norm", @@ -410,6 +432,7 @@ analyzer-version = 1 input-imports = [ "github.com/Sirupsen/logrus", + "github.com/cloudfoundry/jibber_jabber", "github.com/davecgh/go-spew/spew", "github.com/fatih/color", "github.com/golang-collections/collections/stack", @@ -417,7 +440,9 @@ "github.com/mgutz/str", "github.com/shibukawa/configdir", "github.com/spf13/viper", + "github.com/nicksnyder/go-i18n/v2/i18n", "github.com/tcnksm/go-gitconfig", + "golang.org/x/text/language", "gopkg.in/src-d/go-git.v4", "gopkg.in/src-d/go-git.v4/plumbing", ] @@ -28,7 +28,19 @@ brew install lazygit ### Ubuntu Packages for Ubuntu 16.04, 18.04 and 18.10 are available via [Launchpad PPA](https://launchpad.net/~lazygit-team). -They are built daily, straight from master branch. +**Release builds** + +Built from git tags. Supposed to be more stable. + +```sh +sudo add-apt-repository ppa:lazygit-team/release +sudo apt-get update +sudo apt-get install lazygit +``` + +**Daily builds** + +Built from master branch once in 24 hours (or more sometimes). ```sh sudo add-apt-repository ppa:lazygit-team/daily @@ -105,6 +117,9 @@ whichever rc file you're using). ## Contributing We love your input! Please check out the [contributing guide](CONTRIBUTING.md). +For contributor discussion about things not better discussed here in the repo, join the slack channel + +[![Slack](/files/slack_rgb.png)](https://join.slack.com/t/lazygit/shared_invite/enQtNDE3MjIwNTYyMDA0LTM3Yjk3NzdiYzhhNTA1YjM4Y2M4MWNmNDBkOTI0YTE4YjQ1ZmI2YWRhZTgwNjg2YzhhYjg3NDBlMmQyMTI5N2M) ## Work in progress This is still a work in progress so there's still bugs to iron out and as this @@ -1 +1 @@ -v0.1.61
\ No newline at end of file +v0.1.64
\ No newline at end of file diff --git a/files/slack_rgb.png b/files/slack_rgb.png Binary files differnew file mode 100644 index 000000000..e400779c0 --- /dev/null +++ b/files/slack_rgb.png diff --git a/pkg/app/app.go b/pkg/app/app.go index 0eb9c8d25..e18a98dc4 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -9,6 +9,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui" + "github.com/jesseduffield/lazygit/pkg/i18n" ) // App struct @@ -20,6 +21,7 @@ type App struct { OSCommand *commands.OSCommand GitCommand *commands.GitCommand Gui *gui.Gui + Tr *i18n.Localizer } func newLogger(config config.AppConfigurer) *logrus.Logger { @@ -48,11 +50,17 @@ func NewApp(config config.AppConfigurer) (*App, error) { if err != nil { return nil, err } + + app.Tr, err = i18n.NewLocalizer(app.Log) + if err != nil { + return nil, err + } + app.GitCommand, err = commands.NewGitCommand(app.Log, app.OSCommand) if err != nil { return nil, err } - app.Gui, err = gui.NewGui(app.Log, app.GitCommand, app.OSCommand, config.GetVersion(), config.GetUserConfig()) + app.Gui, err = gui.NewGui(app.Log, app.GitCommand, app.OSCommand, app.Tr, config.GetUserConfig(), config.GetVersion()) if err != nil { return nil, err } diff --git a/pkg/commands/git.go b/pkg/commands/git.go index 44fd57f1c..3349e4860 100644 --- a/pkg/commands/git.go +++ b/pkg/commands/git.go @@ -359,7 +359,7 @@ func (c *GitCommand) IsInMergeState() (bool, error) { func (c *GitCommand) RemoveFile(file File) error { // if the file isn't tracked, we assume you want to delete it if !file.Tracked { - return c.OSCommand.RunCommand("rm -rf ./" + file.Name) + return os.RemoveAll(file.Name) } // if the file is tracked, we assume you want to just check it out return c.OSCommand.RunCommand("git checkout " + file.Name) diff --git a/pkg/commands/os.go b/pkg/commands/os.go index 9f9819a5a..f5efbac63 100644 --- a/pkg/commands/os.go +++ b/pkg/commands/os.go @@ -5,6 +5,7 @@ import ( "os" "os/exec" "runtime" + "strings" "github.com/davecgh/go-spew/spew" @@ -14,13 +15,6 @@ import ( gitconfig "github.com/tcnksm/go-gitconfig" ) -var ( - // ErrNoOpenCommand : When we don't know which command to use to open a file - ErrNoOpenCommand = errors.New("Unsure what command to use to open this file") - // ErrNoEditorDefined : When we can't find an editor to edit a file - ErrNoEditorDefined = errors.New("No editor defined in $VISUAL, $EDITOR, or git config") -) - // Platform stores the os state type Platform struct { os string @@ -113,7 +107,7 @@ func (c *OSCommand) GetOpenCommand() (string, string, error) { return name, trail, nil } } - return "", "", ErrNoOpenCommand + return "", "", errors.New("Unsure what command to use to open this file") } // VsCodeOpenFile opens the file in code, with the -r flag to open in the @@ -157,7 +151,7 @@ func (c *OSCommand) EditFile(filename string) (*exec.Cmd, error) { } } if editor == "" { - return nil, ErrNoEditorDefined + return nil, errors.New("No editor defined in $VISUAL, $EDITOR, or git config") } return c.PrepareSubProcess(editor, filename) } @@ -170,5 +164,6 @@ func (c *OSCommand) PrepareSubProcess(cmdName string, commandArgs ...string) (*e // Quote wraps a message in platform-specific quotation marks func (c *OSCommand) Quote(message string) string { + message = strings.Replace(message, "`", "\\`", -1) return c.Platform.escapedQuote + message + c.Platform.escapedQuote } diff --git a/pkg/commands/os_test.go b/pkg/commands/os_test.go new file mode 100644 index 000000000..29540aff6 --- /dev/null +++ b/pkg/commands/os_test.go @@ -0,0 +1,16 @@ +package commands + +import "testing" + +func TestQuote(t *testing.T) { + osCommand := &OSCommand{ + Log: nil, + Platform: getPlatform(), + } + test := "hello `test`" + expected := osCommand.Platform.escapedQuote + "hello \\`test\\`" + osCommand.Platform.escapedQuote + test = osCommand.Quote(test) + if test != expected { + t.Error("Expected " + expected + ", got " + test) + } +} diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go index c4786d39f..67e0ceb07 100644 --- a/pkg/gui/branches_panel.go +++ b/pkg/gui/branches_panel.go @@ -12,7 +12,7 @@ import ( func (gui *Gui) handleBranchPress(g *gocui.Gui, v *gocui.View) error { index := gui.getItemPosition(v) if index == 0 { - return gui.createErrorPanel(g, "You have already checked out this branch") + return gui.createErrorPanel(g, gui.Tr.SLocalize("AlreadyCheckedOutBranch")) } branch := gui.getSelectedBranch(v) if err := gui.GitCommand.Checkout(branch.Name, false); err != nil { @@ -23,7 +23,9 @@ func (gui *Gui) handleBranchPress(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleForceCheckout(g *gocui.Gui, v *gocui.View) error { branch := gui.getSelectedBranch(v) - return gui.createConfirmationPanel(g, v, "Force Checkout Branch", "Are you sure you want force checkout? You will lose all local changes", func(g *gocui.Gui, v *gocui.View) error { + message := gui.Tr.SLocalize("SureForceCheckout") + title := gui.Tr.SLocalize("ForceCheckoutBranch") + return gui.createConfirmationPanel(g, v, title, message, func(g *gocui.Gui, v *gocui.View) error { if err := gui.GitCommand.Checkout(branch.Name, true); err != nil { gui.createErrorPanel(g, err.Error()) } @@ -32,7 +34,7 @@ func (gui *Gui) handleForceCheckout(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleCheckoutByName(g *gocui.Gui, v *gocui.View) error { - gui.createPromptPanel(g, v, "Branch Name:", func(g *gocui.Gui, v *gocui.View) error { + gui.createPromptPanel(g, v, gui.Tr.SLocalize("BranchName")+":", func(g *gocui.Gui, v *gocui.View) error { if err := gui.GitCommand.Checkout(gui.trimmedContent(v), false); err != nil { return gui.createErrorPanel(g, err.Error()) } @@ -43,7 +45,13 @@ func (gui *Gui) handleCheckoutByName(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleNewBranch(g *gocui.Gui, v *gocui.View) error { branch := gui.State.Branches[0] - gui.createPromptPanel(g, v, "New Branch Name (Branch is off of "+branch.Name+")", func(g *gocui.Gui, v *gocui.View) error { + message := gui.Tr.TemplateLocalize( + "NewBranchNameBranchOff", + Teml{ + "branchName": branch.Name, + }, + ) + gui.createPromptPanel(g, v, message, func(g *gocui.Gui, v *gocui.View) error { if err := gui.GitCommand.NewBranch(gui.trimmedContent(v)); err != nil { return gui.createErrorPanel(g, err.Error()) } @@ -57,9 +65,16 @@ func (gui *Gui) handleDeleteBranch(g *gocui.Gui, v *gocui.View) error { checkedOutBranch := gui.State.Branches[0] selectedBranch := gui.getSelectedBranch(v) if checkedOutBranch.Name == selectedBranch.Name { - return gui.createErrorPanel(g, "You cannot delete the checked out branch!") + return gui.createErrorPanel(g, gui.Tr.SLocalize("CantDeleteCheckOutBranch")) } - return gui.createConfirmationPanel(g, v, "Delete Branch", "Are you sure you want delete the branch "+selectedBranch.Name+" ?", func(g *gocui.Gui, v *gocui.View) error { + message := gui.Tr.TemplateLocalize( + "DeleteBranchMessage", + Teml{ + "selectedBranchName": selectedBranch.Name, + }, + ) + title := gui.Tr.SLocalize("DeleteBranch") + return gui.createConfirmationPanel(g, v, title, message, func(g *gocui.Gui, v *gocui.View) error { if err := gui.GitCommand.DeleteBranch(selectedBranch.Name); err != nil { return gui.createErrorPanel(g, err.Error()) } @@ -72,7 +87,7 @@ func (gui *Gui) handleMerge(g *gocui.Gui, v *gocui.View) error { selectedBranch := gui.getSelectedBranch(v) defer gui.refreshSidePanels(g) if checkedOutBranch.Name == selectedBranch.Name { - return gui.createErrorPanel(g, "You cannot merge a branch into itself") + return gui.createErrorPanel(g, gui.Tr.SLocalize("CantMergeBranchIntoItself")) } if err := gui.GitCommand.Merge(selectedBranch.Name); err != nil { return gui.createErrorPanel(g, err.Error()) @@ -87,13 +102,13 @@ func (gui *Gui) getSelectedBranch(v *gocui.View) commands.Branch { func (gui *Gui) renderBranchesOptions(g *gocui.Gui) error { return gui.renderOptionsMap(g, map[string]string{ - "space": "checkout", - "f": "force checkout", - "m": "merge", - "c": "checkout by name", - "n": "new branch", - "d": "delete branch", - "← → ↑ ↓": "navigate", + "space": gui.Tr.SLocalize("checkout"), + "f": gui.Tr.SLocalize("forceCheckout"), + "m": gui.Tr.SLocalize("merge"), + "c": gui.Tr.SLocalize("checkoutByName"), + "n": gui.Tr.SLocalize("newBranch"), + "d": gui.Tr.SLocalize("deleteBranch"), + "← → ↑ ↓": gui.Tr.SLocalize("navigate"), }) } @@ -104,13 +119,13 @@ func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error { } // This really shouldn't happen: there should always be a master branch if len(gui.State.Branches) == 0 { - return gui.renderString(g, "main", "No branches for this repo") + return gui.renderString(g, "main", gui.Tr.SLocalize("NoBranchesThisRepo")) } go func() { branch := gui.getSelectedBranch(v) diff, err := gui.GitCommand.GetBranchGraph(branch.Name) if err != nil && strings.HasPrefix(diff, "fatal: ambiguous argument") { - diff = "There is no tracking for this branch" + diff = gui.Tr.SLocalize("NoTrackingThisBranch") } gui.renderString(g, "main", diff) }() diff --git a/pkg/gui/commit_message_panel.go b/pkg/gui/commit_message_panel.go index f765ab308..26db703f0 100644 --- a/pkg/gui/commit_message_panel.go +++ b/pkg/gui/commit_message_panel.go @@ -1,22 +1,24 @@ package gui -import "github.com/jesseduffield/gocui" +import ( + "github.com/jesseduffield/gocui" +) func (gui *Gui) handleCommitConfirm(g *gocui.Gui, v *gocui.View) error { message := gui.trimmedContent(v) if message == "" { - return gui.createErrorPanel(g, "You cannot commit without a commit message") + return gui.createErrorPanel(g, gui.Tr.SLocalize("CommitWithoutMessageErr")) } sub, err := gui.GitCommand.Commit(g, message) if err != nil { // TODO need to find a way to send through this error - if err != ErrSubProcess { + if err != gui.Errors.ErrSubProcess { return gui.createErrorPanel(g, err.Error()) } } if sub != nil { gui.SubProcess = sub - return ErrSubProcess + return gui.Errors.ErrSubProcess } gui.refreshFiles(g) v.Clear() @@ -46,5 +48,12 @@ func (gui *Gui) handleNewlineCommitMessage(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleCommitFocused(g *gocui.Gui, v *gocui.View) error { - return gui.renderString(g, "options", "esc: close, enter: confirm") + message := gui.Tr.TemplateLocalize( + "CloseConfirm", + Teml{ + "keyBindClose": "esc", + "keyBindConfirm": "enter", + }, + ) + return gui.renderString(g, "options", message) } diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go index 60ae1c315..417b947a2 100644 --- a/pkg/gui/commits_panel.go +++ b/pkg/gui/commits_panel.go @@ -8,11 +8,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands" ) -var ( - // ErrNoCommits : When no commits are found for the branch - ErrNoCommits = errors.New("No commits for this branch") -) - func (gui *Gui) refreshCommits(g *gocui.Gui) error { g.Update(func(*gocui.Gui) error { gui.State.Commits = gui.GitCommand.GetCommits() @@ -44,7 +39,7 @@ func (gui *Gui) refreshCommits(g *gocui.Gui) error { } func (gui *Gui) handleResetToCommit(g *gocui.Gui, commitView *gocui.View) error { - return gui.createConfirmationPanel(g, commitView, "Reset To Commit", "Are you sure you want to reset to this commit?", func(g *gocui.Gui, v *gocui.View) error { + |