From ba2b6fbf1fa13ca5a72c18fba996bdd561d4899c Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Tue, 14 Aug 2018 23:47:14 +1000 Subject: pull errors out of package scope and store sentinel errors on the gui struct --- pkg/commands/os.go | 11 ++--------- pkg/gui/commit_message_panel.go | 4 ++-- pkg/gui/commits_panel.go | 9 ++------- pkg/gui/files_panel.go | 28 +++++++++++----------------- pkg/gui/gui.go | 41 ++++++++++++++++++++++++++++++++--------- 5 files changed, 49 insertions(+), 44 deletions(-) (limited to 'pkg') diff --git a/pkg/commands/os.go b/pkg/commands/os.go index 9f9819a5a..d4ea75e74 100644 --- a/pkg/commands/os.go +++ b/pkg/commands/os.go @@ -14,13 +14,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 +106,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 +150,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) } diff --git a/pkg/gui/commit_message_panel.go b/pkg/gui/commit_message_panel.go index 854732817..599c80186 100644 --- a/pkg/gui/commit_message_panel.go +++ b/pkg/gui/commit_message_panel.go @@ -12,13 +12,13 @@ func (gui *Gui) handleCommitConfirm(g *gocui.Gui, v *gocui.View) error { 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() diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go index 60ae1c315..4f5ae2afc 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() @@ -79,7 +74,7 @@ func (gui *Gui) handleCommitSelect(g *gocui.Gui, v *gocui.View) error { } commit, err := gui.getSelectedCommit(g) if err != nil { - if err != ErrNoCommits { + if err != errors.New("No commits for this branch") { return err } return gui.renderString(g, "main", "No commits for this branch") @@ -165,7 +160,7 @@ func (gui *Gui) getSelectedCommit(g *gocui.Gui) (commands.Commit, error) { panic(err) } if len(gui.State.Commits) == 0 { - return commands.Commit{}, ErrNoCommits + return commands.Commit{}, errors.New("No commits for this branch") } lineNumber := gui.getItemPosition(v) if lineNumber > len(gui.State.Commits)-1 { diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go index 8c4c5cb6f..312c06554 100644 --- a/pkg/gui/files_panel.go +++ b/pkg/gui/files_panel.go @@ -7,7 +7,6 @@ import ( // "strings" - "errors" "os/exec" "strings" @@ -16,11 +15,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands" ) -var ( - errNoFiles = errors.New(lang.SLocalize("NoChangedFiles", "No changed files")) - errNoUsername = errors.New(lang.SLocalize("NoUsernameSetErr", `No username set. Please do: git config --global user.name "Your Name"`)) -) - func (gui *Gui) stagedFiles() []commands.File { files := gui.State.Files result := make([]commands.File, 0) @@ -54,7 +48,7 @@ func (gui *Gui) stageSelectedFile(g *gocui.Gui) error { func (gui *Gui) handleFilePress(g *gocui.Gui, v *gocui.View) error { file, err := gui.getSelectedFile(g) if err != nil { - if err == errNoFiles { + if err == gui.Errors.ErrNoFiles { return nil } return err @@ -80,16 +74,16 @@ func (gui *Gui) handleFilePress(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleAddPatch(g *gocui.Gui, v *gocui.View) error { file, err := gui.getSelectedFile(g) if err != nil { - if err == errNoFiles { + if err == gui.Errors.ErrNoFiles { return nil } return err } if !file.HasUnstagedChanges { - return gui.createErrorPanel(g, lang.SLocalize("FileHasNoUnstagedChanges", "File has no unstaged changes to add")) + return gui.createErrorPanel(g, gui.Tr.SLocalize("FileHasNoUnstagedChanges", "File has no unstaged changes to add")) } if !file.Tracked { - return gui.createErrorPanel(g, lang.SLocalize("CannotGitAdd", "Cannot git add --patch untracked files")) + return gui.createErrorPanel(g, gui.Tr.SLocalize("CannotGitAdd", "Cannot git add --patch untracked files")) } sub, err := gui.GitCommand.AddPatch(file.Name) if err != nil { @@ -101,7 +95,7 @@ func (gui *Gui) handleAddPatch(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) getSelectedFile(g *gocui.Gui) (commands.File, error) { if len(gui.State.Files) == 0 { - return commands.File{}, errNoFiles + return commands.File{}, gui.Errors.ErrNoFiles } filesView, err := g.View("files") if err != nil { @@ -114,7 +108,7 @@ func (gui *Gui) getSelectedFile(g *gocui.Gui) (commands.File, error) { func (gui *Gui) handleFileRemove(g *gocui.Gui, v *gocui.View) error { file, err := gui.getSelectedFile(g) if err != nil { - if err == errNoFiles { + if err == gui.Errors.ErrNoFiles { return nil } return err @@ -139,7 +133,7 @@ func (gui *Gui) handleIgnoreFile(g *gocui.Gui, v *gocui.View) error { return gui.createErrorPanel(g, err.Error()) } if file.Tracked { - return gui.createErrorPanel(g, lang.SLocalize("CantIgnoreTrackFiles", "Cannot ignore tracked files")) + return gui.createErrorPanel(g, gui.Tr.SLocalize("CantIgnoreTrackFiles", "Cannot ignore tracked files")) } gui.GitCommand.Ignore(file.Name) return gui.refreshFiles(g) @@ -175,7 +169,7 @@ func (gui *Gui) renderfilesOptions(g *gocui.Gui, file *commands.File) error { func (gui *Gui) handleFileSelect(g *gocui.Gui, v *gocui.View) error { file, err := gui.getSelectedFile(g) if err != nil { - if err != errNoFiles { + if err != gui.Errors.ErrNoFiles { return err } gui.renderString(g, "main", "No changed files") @@ -230,7 +224,7 @@ func (gui *Gui) PrepareSubProcess(g *gocui.Gui, commands ...string) error { func (gui *Gui) genericFileOpen(g *gocui.Gui, v *gocui.View, open func(string) (*exec.Cmd, error)) error { file, err := gui.getSelectedFile(g) if err != nil { - if err != errNoFiles { + if err != gui.Errors.ErrNoFiles { return err } return nil @@ -303,7 +297,7 @@ func (gui *Gui) renderFile(file commands.File, filesView *gocui.View) { func (gui *Gui) catSelectedFile(g *gocui.Gui) (string, error) { item, err := gui.getSelectedFile(g) if err != nil { - if err != errNoFiles { + if err != gui.Errors.ErrNoFiles { return "", err } return "", gui.renderString(g, "main", "No file to display") @@ -369,7 +363,7 @@ func (gui *Gui) handleSwitchToMerge(g *gocui.Gui, v *gocui.View) error { } file, err := gui.getSelectedFile(g) if err != nil { - if err != errNoFiles { + if err != gui.Errors.ErrNoFiles { return err } return nil diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index bf8360f72..4e8382eae 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -25,11 +25,29 @@ import ( // OverlappingEdges determines if panel edges overlap var OverlappingEdges = false -// ErrSubProcess tells us we're switching to a subprocess so we need to -// close the Gui until it is finished -var ( - ErrSubProcess = errors.New("running subprocess") -) +// SentinelErrors are the errors that have special meaning and need to be checked +// by calling functions. The less of these, the better +type SentinelErrors struct { + ErrSubProcess error + ErrNoFiles error +} + +// GenerateSentinelErrors makes the sentinel errors for the gui. We're defining it here +// because we can't do package-scoped errors with localization, and also because +// it seems like package-scoped variables are bad in general +// https://dave.cheney.net/2017/06/11/go-without-package-scoped-variables +// In the future it would be good to implement some of the recommendations of +// that article. For now, if we don't need an error to be a sentinel, we will just +// define it inline. This has implications for error messages that pop up everywhere +// in that we'll be duplicating the default values. We may need to look at +// having a default localisation bundle defined, and just using keys-only when +// localising things in the code. +func (gui *Gui) GenerateSentinelErrors() { + gui.Errors = SentinelErrors{ + ErrSubProcess: errors.New("running subprocess"), + ErrNoFiles: errors.New(gui.Tr.SLocalize("NoChangedFiles", "No changed files")), + } +} // Gui wraps the gocui Gui object which handles rendering and events type Gui struct { @@ -41,6 +59,7 @@ type Gui struct { SubProcess *exec.Cmd State guiState Tr *i18n.Localizer + Errors SentinelErrors } type guiState struct { @@ -70,17 +89,21 @@ func NewGui(log *logrus.Logger, gitCommand *commands.GitCommand, oSCommand *comm Conflicts: make([]commands.Conflict, 0), EditHistory: stack.New(), Platform: *oSCommand.Platform, - Version: "test version", // TODO: send version in + Version: version, } - return &Gui{ + gui := &Gui{ Log: log, GitCommand: gitCommand, OSCommand: oSCommand, Version: version, State: initialState, Tr: tr, - }, nil + } + + gui.GenerateSentinelErrors() + + return gui, nil } func (gui *Gui) scrollUpMain(g *gocui.Gui, v *gocui.View) error { @@ -313,7 +336,7 @@ func (gui *Gui) RunWithSubprocesses() { if err := gui.Run(); err != nil { if err == gocui.ErrQuit { break - } else if err == ErrSubProcess { + } else if err == gui.Errors.ErrSubProcess { gui.SubProcess.Stdin = os.Stdin gui.SubProcess.Stdout = os.Stdout gui.SubProcess.Stderr = os.Stderr -- cgit v1.2.3