diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2018-08-13 21:16:21 +1000 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2018-08-13 21:16:21 +1000 |
commit | 9e725ae24e8fcecefec35a65b50476d371653ffb (patch) | |
tree | 840df3748f981967a3b9f7c276602832dab360d3 /pkg | |
parent | 97cff656121270e9c790432e28622d92ab7b0f1a (diff) |
got this bad boy compiling again
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/app/app.go | 22 | ||||
-rw-r--r-- | pkg/commands/git_structs.go | 6 | ||||
-rw-r--r-- | pkg/commands/os.go | 28 | ||||
-rw-r--r-- | pkg/gui/branches_panel.go | 4 | ||||
-rw-r--r-- | pkg/gui/commits_panel.go | 6 | ||||
-rw-r--r-- | pkg/gui/files_panel.go | 68 | ||||
-rw-r--r-- | pkg/gui/gui.go | 84 | ||||
-rw-r--r-- | pkg/gui/keybindings.go | 18 | ||||
-rw-r--r-- | pkg/gui/merge_panel.go | 165 | ||||
-rw-r--r-- | pkg/gui/stash_panel.go | 49 | ||||
-rw-r--r-- | pkg/gui/status_panel.go | 17 | ||||
-rw-r--r-- | pkg/gui/view_helpers.go | 37 | ||||
-rw-r--r-- | pkg/utils/utils.go | 4 |
13 files changed, 267 insertions, 241 deletions
diff --git a/pkg/app/app.go b/pkg/app/app.go index b6318b745..011375737 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -2,9 +2,9 @@ package app import ( "io" + "os" "github.com/Sirupsen/logrus" - "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui" @@ -18,7 +18,21 @@ type App struct { Log *logrus.Logger OSCommand *commands.OSCommand GitCommand *commands.GitCommand - Gui *gocui.Gui + Gui *gui.Gui +} + +func newLogger(config config.AppConfigurer) *logrus.Logger { + log := logrus.New() + if !config.GetDebug() { + log.Out = nil + return log + } + file, err := os.OpenFile("development.log", os.O_CREATE|os.O_WRONLY, 0666) + if err != nil { + panic("unable to log to file") // TODO: don't panic (also, remove this call to the `panic` function) + } + log.Out = file + return log } // NewApp retruns a new applications @@ -28,7 +42,7 @@ func NewApp(config config.AppConfigurer) (*App, error) { Config: config, } var err error - app.Log = logrus.New() + app.Log = newLogger(config) app.OSCommand, err = commands.NewOSCommand(app.Log) if err != nil { return nil, err @@ -37,7 +51,7 @@ func NewApp(config config.AppConfigurer) (*App, error) { if err != nil { return nil, err } - app.Gui, err = gui.NewGui(app.Log, app.GitCommand, config.GetVersion()) + app.Gui, err = gui.NewGui(app.Log, app.GitCommand, app.OSCommand, config.GetVersion()) if err != nil { return nil, err } diff --git a/pkg/commands/git_structs.go b/pkg/commands/git_structs.go index 2f7255be1..6b10b18bb 100644 --- a/pkg/commands/git_structs.go +++ b/pkg/commands/git_structs.go @@ -30,7 +30,7 @@ type StashEntry struct { // Conflict : A git conflict with a start middle and end corresponding to line // numbers in the file where the conflict bars appear type Conflict struct { - start int - middle int - end int + Start int + Middle int + End int } diff --git a/pkg/commands/os.go b/pkg/commands/os.go index 2313b5550..3be1e1288 100644 --- a/pkg/commands/os.go +++ b/pkg/commands/os.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/Sirupsen/logrus" - "github.com/jesseduffield/gocui" gitconfig "github.com/tcnksm/go-gitconfig" ) @@ -105,28 +104,34 @@ func (c *OSCommand) GetOpenCommand() (string, string, error) { // VsCodeOpenFile opens the file in code, with the -r flag to open in the // current window -func (c *OSCommand) VsCodeOpenFile(g *gocui.Gui, filename string) (string, error) { - return c.RunCommand("code -r " + filename) +// each of these open files needs to have the same function signature because +// they're being passed as arguments into another function, +// but only editFile actually returns a *exec.Cmd +func (c *OSCommand) VsCodeOpenFile(filename string) (*exec.Cmd, error) { + _, err := c.RunCommand("code -r " + filename) + return nil, err } // SublimeOpenFile opens the filein sublime // may be deprecated in the future -func (c *OSCommand) SublimeOpenFile(g *gocui.Gui, filename string) (string, error) { - return c.RunCommand("subl " + filename) +func (c *OSCommand) SublimeOpenFile(filename string) (*exec.Cmd, error) { + _, err := c.RunCommand("subl " + filename) + return nil, err } // OpenFile opens a file with the given -func (c *OSCommand) OpenFile(g *gocui.Gui, filename string) (string, error) { +func (c *OSCommand) OpenFile(filename string) (*exec.Cmd, error) { cmdName, cmdTrail, err := c.GetOpenCommand() if err != nil { - return "", err + return nil, err } - return c.RunCommand(cmdName + " " + filename + cmdTrail) + _, err = c.RunCommand(cmdName + " " + filename + cmdTrail) + return nil, err } // EditFile opens a file in a subprocess using whatever editor is available, // falling back to core.editor, VISUAL, EDITOR, then vi -func (c *OSCommand) editFile(g *gocui.Gui, filename string) (string, error) { +func (c *OSCommand) EditFile(filename string) (*exec.Cmd, error) { editor, _ := gitconfig.Global("core.editor") if editor == "" { editor = os.Getenv("VISUAL") @@ -140,10 +145,9 @@ func (c *OSCommand) editFile(g *gocui.Gui, filename string) (string, error) { } } if editor == "" { - return "", ErrNoEditorDefined + return nil, ErrNoEditorDefined } - c.PrepareSubProcess(editor, filename) - return "", nil + return c.PrepareSubProcess(editor, filename) } // PrepareSubProcess iniPrepareSubProcessrocess then tells the Gui to switch to it diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go index 53b8465cb..2820b7b9e 100644 --- a/pkg/gui/branches_panel.go +++ b/pkg/gui/branches_panel.go @@ -117,7 +117,7 @@ func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error { return nil } -// refreshStatus is called at the end of this because that's when we can +// 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 { @@ -135,7 +135,7 @@ func (gui *Gui) refreshBranches(g *gocui.Gui) error { fmt.Fprintln(v, branch.GetDisplayString()) } gui.resetOrigin(v) - return refreshStatus(g) + return gui.refreshStatus(g) }) return nil } diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go index 45134e44a..faff6ad32 100644 --- a/pkg/gui/commits_panel.go +++ b/pkg/gui/commits_panel.go @@ -34,7 +34,7 @@ func (gui *Gui) refreshCommits(g *gocui.Gui) error { shaColor.Fprint(v, commit.Sha+" ") white.Fprintln(v, commit.Name) } - refreshStatus(g) + gui.refreshStatus(g) if g.CurrentView().Name() == "commits" { gui.handleCommitSelect(g, v) } @@ -105,7 +105,7 @@ func (gui *Gui) handleCommitSquashDown(g *gocui.Gui, v *gocui.View) error { if err := gui.refreshCommits(g); err != nil { panic(err) } - refreshStatus(g) + gui.refreshStatus(g) return gui.handleCommitSelect(g, v) } @@ -138,7 +138,7 @@ func (gui *Gui) handleCommitFixup(g *gocui.Gui, v *gocui.View) error { if err := gui.refreshCommits(g); err != nil { panic(err) } - return refreshStatus(g) + return gui.refreshStatus(g) }, nil) return nil } diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go index 9ffcafa44..8c60fcbf4 100644 --- a/pkg/gui/files_panel.go +++ b/pkg/gui/files_panel.go @@ -8,6 +8,7 @@ import ( // "strings" "errors" + "os/exec" "strings" "github.com/fatih/color" @@ -171,7 +172,7 @@ func (gui *Gui) handleFileSelect(g *gocui.Gui, v *gocui.View) error { gui.renderfilesOptions(g, &file) var content string if file.HasMergeConflicts { - return refreshMergePanel(g) + return gui.refreshMergePanel(g) } content = gui.GitCommand.Diff(file) @@ -191,9 +192,9 @@ func (gui *Gui) handleCommitPress(g *gocui.Gui, filesView *gocui.View) error { return nil } -// HandleCommitEditorPress - handle when the user wants to commit changes via +// handleCommitEditorPress - handle when the user wants to commit changes via // their editor rather than via the popup panel -func (gui *Gui) HandleCommitEditorPress(g *gocui.Gui, filesView *gocui.View) error { +func (gui *Gui) handleCommitEditorPress(g *gocui.Gui, filesView *gocui.View) error { if len(gui.stagedFiles(gui.State.Files)) == 0 && !gui.State.HasMergeConflicts { return gui.createErrorPanel(g, "There are no staged files to commit") } @@ -214,7 +215,7 @@ func (gui *Gui) PrepareSubProcess(g *gocui.Gui, commands ...string) error { return nil } -func (gui *Gui) genericFileOpen(g *gocui.Gui, v *gocui.View, open func(*gocui.Gui, string) (string, error)) 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 { @@ -222,26 +223,31 @@ func (gui *Gui) genericFileOpen(g *gocui.Gui, v *gocui.View, open func(*gocui.Gu } return nil } - if _, err := open(g, file.Name); err != nil { + sub, err := open(file.Name) + if err != nil { return gui.createErrorPanel(g, err.Error()) } + if sub != nil { + gui.SubProcess = sub + return ErrSubProcess + } return nil } func (gui *Gui) handleFileEdit(g *gocui.Gui, v *gocui.View) error { - return gui.genericFileOpen(g, v, gui.editFile) + return gui.genericFileOpen(g, v, gui.OSCommand.EditFile) } func (gui *Gui) handleFileOpen(g *gocui.Gui, v *gocui.View) error { - return gui.genericFileOpen(g, v, gui.openFile) + return gui.genericFileOpen(g, v, gui.OSCommand.OpenFile) } func (gui *Gui) handleSublimeFileOpen(g *gocui.Gui, v *gocui.View) error { - return gui.genericFileOpen(g, v, gui.sublimeOpenFile) + return gui.genericFileOpen(g, v, gui.OSCommand.SublimeOpenFile) } func (gui *Gui) handleVsCodeFileOpen(g *gocui.Gui, v *gocui.View) error { - return gui.genericFileOpen(g, v, gui.vsCodeOpenFile) + return gui.genericFileOpen(g, v, gui.OSCommand.VsCodeOpenFile) } func (gui *Gui) handleRefreshFiles(g *gocui.Gui, v *gocui.View) error { @@ -250,13 +256,13 @@ func (gui *Gui) handleRefreshFiles(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) refreshStateFiles() { // get files to stage - files := getGitStatusFiles() - gui.State.Files = mergeGitStatusFiles(gui.State.Files, files) - updateHasMergeConflictStatus() + files := gui.GitCommand.GetStatusFiles() + gui.State.Files = gui.GitCommand.MergeStatusFiles(gui.State.Files, files) + gui.updateHasMergeConflictStatus() } func (gui *Gui) updateHasMergeConflictStatus() error { - merging, err := isInMergeState() + merging, err := gui.GitCommand.IsInMergeState() if err != nil { return err } @@ -290,7 +296,7 @@ func (gui *Gui) catSelectedFile(g *gocui.Gui) (string, error) { } return "", gui.renderString(g, "main", "No file to display") } - cat, err := catFile(item.Name) + cat, err := gui.GitCommand.CatFile(item.Name) if err != nil { panic(err) } @@ -302,12 +308,12 @@ func (gui *Gui) refreshFiles(g *gocui.Gui) error { if err != nil { return err } - refreshStateFiles() + gui.refreshStateFiles() filesView.Clear() for _, file := range gui.State.Files { - renderFile(file, filesView) + gui.renderFile(file, filesView) } - correctCursor(filesView) + gui.correctCursor(filesView) if filesView == g.CurrentView() { gui.handleFileSelect(g, filesView) } @@ -315,14 +321,14 @@ func (gui *Gui) refreshFiles(g *gocui.Gui) error { } func (gui *Gui) pullFiles(g *gocui.Gui, v *gocui.View) error { - createMessagePanel(g, v, "", "Pulling...") + gui.createMessagePanel(g, v, "", "Pulling...") go func() { - if output, err := gitPull(); err != nil { + if output, err := gui.GitCommand.Pull(); err != nil { gui.createErrorPanel(g, output) } else { gui.closeConfirmationPrompt(g) - refreshCommits(g) - refreshStatus(g) + gui.refreshCommits(g) + gui.refreshStatus(g) } gui.refreshFiles(g) }() @@ -330,15 +336,15 @@ func (gui *Gui) pullFiles(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) pushFiles(g *gocui.Gui, v *gocui.View) error { - createMessagePanel(g, v, "", "Pushing...") + gui.createMessagePanel(g, v, "", "Pushing...") go func() { - branchName = gui.State.Branches[0].Name - if output, err := commands.Push(branchName); err != nil { + branchName := gui.State.Branches[0].Name + if output, err := gui.GitCommand.Push(branchName); err != nil { gui.createErrorPanel(g, output) } else { gui.closeConfirmationPrompt(g) - refreshCommits(g) - refreshStatus(g) + gui.refreshCommits(g) + gui.refreshStatus(g) } }() return nil @@ -360,22 +366,22 @@ func (gui *Gui) handleSwitchToMerge(g *gocui.Gui, v *gocui.View) error { return gui.createErrorPanel(g, "This file has no merge conflicts") } gui.switchFocus(g, v, mergeView) - return refreshMergePanel(g) + return gui.refreshMergePanel(g) } func (gui *Gui) handleAbortMerge(g *gocui.Gui, v *gocui.View) error { - output, err := gitAbortMerge() + output, err := gui.GitCommand.AbortMerge() if err != nil { return gui.createErrorPanel(g, output) } - createMessagePanel(g, v, "", "Merge aborted") - refreshStatus(g) + gui.createMessagePanel(g, v, "", "Merge aborted") + gui.refreshStatus(g) return gui.refreshFiles(g) } func (gui *Gui) handleResetHard(g *gocui.Gui, v *gocui.View) error { return gui.createConfirmationPanel(g, v, "Clear file panel", "Are you sure you want `reset --hard HEAD`? You may lose changes", func(g *gocui.Gui, v *gocui.View) error { - if err := commands.ResetHard(); err != nil { + if err := gui.GitCommand.ResetHard(); err != nil { gui.createErrorPanel(g, err.Error()) } return gui.refreshFiles(g) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 402b4ff32..aa524ce0d 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -37,12 +37,27 @@ type Gui struct { OSCommand *commands.OSCommand Version string SubProcess *exec.Cmd - State StateType + State guiState +} + +type guiState struct { + Files []commands.File + Branches []commands.Branch + Commits []commands.Commit + StashEntries []commands.StashEntry + PreviousView string + HasMergeConflicts bool + ConflictIndex int + ConflictTop bool + Conflicts []commands.Conflict + EditHistory *stack.Stack + Platform platform + Version string } // NewGui builds a new gui handler func NewGui(log *logrus.Logger, gitCommand *commands.GitCommand, oSCommand *commands.OSCommand, version string) (*Gui, error) { - initialState := StateType{ + initialState := guiState{ Files: make([]commands.File, 0), PreviousView: "files", Commits: make([]commands.Commit, 0), @@ -64,21 +79,6 @@ func NewGui(log *logrus.Logger, gitCommand *commands.GitCommand, oSCommand *comm }, nil } -type StateType struct { - Files []commands.File - Branches []commands.Branch - Commits []commands.Commit - StashEntries []commands.StashEntry - PreviousView string - HasMergeConflicts bool - ConflictIndex int - ConflictTop bool - Conflicts []commands.Conflict - EditHistory *stack.Stack - Platform platform - Version string -} - type platform struct { os string shell string @@ -105,7 +105,7 @@ func getPlatform() platform { } } -func scrollUpMain(g *gocui.Gui, v *gocui.View) error { +func (gui *Gui) scrollUpMain(g *gocui.Gui, v *gocui.View) error { mainView, _ := g.View("main") ox, oy := mainView.Origin() if oy >= 1 { @@ -114,7 +114,7 @@ func scrollUpMain(g *gocui.Gui, v *gocui.View) error { return nil } -func scrollDownMain(g *gocui.Gui, v *gocui.View) error { +func (gui *Gui) scrollDownMain(g *gocui.Gui, v *gocui.View) error { mainView, _ := g.View("main") ox, oy := mainView.Origin() if oy < len(mainView.BufferLines()) { @@ -123,8 +123,8 @@ func scrollDownMain(g *gocui.Gui, v *gocui.View) error { return nil } -func handleRefresh(g *gocui.Gui, v *gocui.View) error { - return refreshSidePanels(g) +func (gui *Gui) handleRefresh(g *gocui.Gui, v *gocui.View) error { + return gui.refreshSidePanels(g) } func max(a, b int) int { @@ -257,35 +257,35 @@ func (gui *Gui) layout(g *gocui.Gui) error { // these are only called once gui.handleFileSelect(g, filesView) gui.refreshFiles(g) - refreshBranches(g) - refreshCommits(g) - refreshStashEntries(g) - nextView(g, nil) + gui.refreshBranches(g) + gui.refreshCommits(g) + gui.refreshStashEntries(g) + gui.nextView(g, nil) } - resizePopupPanels(g) + gui.resizePopupPanels(g) return nil } -func fetch(g *gocui.Gui) error { - gitFetch() - refreshStatus(g) +func (gui *Gui) fetch(g *gocui.Gui) error { + gui.GitCommand.Fetch() + gui.refreshStatus(g) return nil } -func updateLoader(g *gocui.Gui) error { +func (gui *Gui) updateLoader(g *gocui.Gui) error { if confirmationView, _ := g.View("confirmation"); confirmationView != nil { content := gui.trimmedContent(confirmationView) if strings.Contains(content, "...") { staticContent := strings.Split(content, "...")[0] + "..." - gui.renderString(g, "confirmation", staticContent+" "+loader()) + gui.renderString(g, "confirmation", staticContent+" "+gui.loader()) } } return nil } -func goEvery(g *gocui.Gui, interval time.Duration, function func(*gocui.Gui) error) { +func (gui *Gui) goEvery(g *gocui.Gui, interval time.Duration, function func(*gocui.Gui) error) { go func() { for range time.Tick(interval) { function(g) @@ -293,36 +293,36 @@ func goEvery(g *gocui.Gui, interval time.Duration, function func(*gocui.Gui) err }() } -func resizePopupPanels(g *gocui.Gui) error { +func (gui *Gui) resizePopupPanels(g *gocui.Gui) error { v := g.CurrentView() if v.Name() == "commitMessage" || v.Name() == "confirmation" { - return resizePopupPanel(g, v) + return gui.resizePopupPanel(g, v) } return nil } // Run setup the gui with keybindings and start the mainloop -func (gui *Gui) Run() (*exec.Cmd, error) { +func (gui *Gui) Run() error { g, err := gocui.NewGui(gocui.OutputNormal, OverlappingEdges) if err != nil { - return nil, err + return err } defer g.Close() g.FgColor = gocui.ColorDefault - goEvery(g, time.Second*60, fetch) - goEvery(g, time.Second*10, gui.refreshFiles) - goEvery(g, time.Millisecond*10, updateLoader) + gui.goEvery(g, time.Second*60, gui.fetch) + gui.goEvery(g, time.Second*10, gui.refreshFiles) + gui.goEvery(g, time.Millisecond*10, gui.updateLoader) g.SetManagerFunc(gui.layout) if err = gui.keybindings(g); err != nil { - return nil, err + return err } err = g.MainLoop() - return nil, err + return err } // RunWithSubprocesses loops, instantiating a new gocui.Gui with each iteration @@ -342,6 +342,6 @@ func (gui *Gui) RunWithSubprocesses() { } } -func quit(g *gocui.Gui, v *gocui.View) error { +func (gui *Gui) quit(g *gocui.Gui, v *gocui.View) error { return gocui.ErrQuit } diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 194746d28..6a8a645f5 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -70,15 +70,15 @@ func (gui *Gui) keybindings(g *gocui.Gui) error { // input in the confirmation panel for _, viewName := range []string{"files", "branches", "commits", "stash"} { bindings = append(bindings, []Binding{ - {ViewName: viewName, Key: gocui.KeyTab, Modifier: gocui.ModNone, Handler: nextView}, - {ViewName: viewName, Key: gocui.KeyArrowLeft, Modifier: gocui.ModNone, Handler: previousView}, - {ViewName: viewName, Key: gocui.KeyArrowRight, Modifier: gocui.ModNone, Handler: nextView}, - {ViewName: viewName, Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: cursorUp}, - {ViewName: viewName, Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: cursorDown}, - {ViewName: viewName, Key: 'h', Modifier: gocui.ModNone, Handler: previousView}, - {ViewName: viewName, Key: 'l', Modifier: gocui.ModNone, Handler: nextView}, - {ViewName: viewName, Key: 'k', Modifier: gocui.ModNone, Handler: cursorUp}, - {ViewName: viewName, Key: 'j', Modifier: gocui.ModNone, Handler: cursorDown}, + {ViewName: viewName, Key: gocui.KeyTab, Modifier: gocui.ModNone, Handler: gui.nextView}, + {ViewName: viewName, Key: gocui.KeyArrowLeft, Modifier: gocui.ModNone, Handler: gui.previousView}, + {ViewName: viewName, Key: gocui.KeyArrowRight, Modifier: gocui.ModNone, Handler: gui.nextView}, + {ViewName: viewName, Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: gui.cursorUp}, + {ViewName: viewName, Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: gui.cursorDown}, + {ViewName: viewName, Key: 'h', Modifier: gocui.ModNone, Handler: gui.previousView}, + {ViewName: viewName, Key: 'l', Modifier: gocui.ModNone, Handler: gui.nextView}, + {ViewName: viewName, Key: 'k', Modifier: gocui.ModNone, Handler: gui.cursorUp}, + {ViewName: viewName, Key: 'j', Modifier: gocui.ModNone, Handler: gui.cursorDown}, }...) } diff --git a/pkg/gui/merge_panel.go b/pkg/gui/merge_panel.go index 7e0a3a873..81e37f593 100644 --- a/pkg/gui/merge_panel.go +++ b/pkg/gui/merge_panel.go @@ -16,89 +16,89 @@ import ( "github.com/jesseduffield/lazygit/pkg/utils" ) -func findConflicts(content string) ([]commands.Conflict, error) { +func (gui *Gui) findConflicts(content string) ([]commands.Conflict, error) { conflicts := make([]commands.Conflict, 0) - var newConflict conflict + var newConflict commands.Conflict for i, line := range utils.SplitLines(content) { if line == "<<<<<<< HEAD" || line == "<<<<<<< MERGE_HEAD" || line == "<<<<<<< Updated upstream" { - newConflict = conflict{start: i} + newConflict = commands.Conflict{Start: i} } else if line == "=======" { - newConflict.middle = i + newConflict.Middle = i } else if strings.HasPrefix(line, ">>>>>>> ") { - newConflict.end = i + newConflict.End = i conflicts = append(conflicts, newConflict) } } return conflicts, nil } -func shiftConflict(conflicts []commands.Conflict) (commands.Conflict, []commands.Conflict) { +func (gui *Gui) shiftConflict(conflicts []commands.Conflict) (commands.Conflict, []commands.Conflict) { return conflicts[0], conflicts[1:] } -func shouldHighlightLine(index int, conflict commands.Conflict, top bool) bool { - return (index >= conflict.start && index <= conflict.middle && top) || (index >= conflict.middle && index <= conflict.end && !top) +func (gui *Gui) shouldHighlightLine(index int, conflict commands.Conflict, top bool) bool { + return (index >= conflict.Start && index <= conflict.Middle && top) || (index >= conflict.Middle && index <= conflict.End && !top) } -func coloredConflictFile(content string, conflicts []commands.Conflict, conflictIndex int, conflictTop, hasFocus bool) (string, error) { +func (gui *Gui) coloredConflictFile(content string, conflicts []commands.Conflict, conflictIndex int, conflictTop, hasFocus bool) (string, error) { if len(conflicts) == 0 { return content, nil } - conflict, remainingConflicts := shiftConflict(conflicts) + conflict, remainingConflicts := gui.shiftConflict(conflicts) var outputBuffer bytes.Buffer - for i, line := range splitLines(content) { + for i, line := range utils.SplitLines(content) { colourAttr := color.FgWhite - if i == conflict.start || i == conflict.middle || i == conflict.end { + if i == conflict.Start || i == conflict.Middle || i == conflict.End { colourAttr = color.FgRed } colour := color.New(colourAttr) - if hasFocus && conflictIndex < len(conflicts) && conflicts[conflictIndex] == conflict && shouldHighlightLine(i, conflict, conflictTop) { + if hasFocus && conflictIndex < len(conflicts) && conflicts[conflictIndex] == conflict && gui.shouldHighlightLine(i, conflict, conflictTop) { colour.Add(color.Bold) } - if i == conflict.end && len(remainingConflicts) > 0 { - conflict, remainingConflicts = shiftConflict(remainingConflicts) + if i == conflict.End && len(remainingConflicts) > 0 { + conflict, remainingConflicts = gui.shiftConflict(remainingConflicts) } - outputBuffer.WriteString(coloredStringDirect(line, colour) + "\n") + outputBuffer.WriteString(utils.ColoredStringDirect(line, colour) + "\n") } return outputBuffer.String(), nil } -func handleSelectTop(g *gocui.Gui, v *gocui.View) error { - state.ConflictTop = true - return refreshMergePanel(g) +func (gui *Gui) handleSelectTop(g *gocui.Gui, v *gocui.View) error { + gui.State.ConflictTop = true + return gui.refreshMergePanel(g) } -func handleSelectBottom(g *gocui.Gui, v *gocui.View) error { - state.ConflictTop = false - return refreshMergePanel(g) +func (gui *Gui) handleSelectBottom(g *gocui.Gui, v *gocui.View) error { + gui.State.ConflictTop = false + return gui.refreshMergePanel(g) } -func handleSelectNextConflict(g *gocui.Gui, v *gocui.View) error { - if state.ConflictIndex >= len(state.Conflicts)-1 { +func (gui *Gui) handleSelectNextConflict(g *gocui.Gui, v *gocui.View) error { + if gui.State.ConflictIndex >= len(gui.State.Conflicts)-1 { return nil } - state.ConflictIndex++ - return refreshMergePanel(g) + gui.State.ConflictIndex++ + return gui.refreshMergePanel(g) } -func handleSelectPrevConflict(g *gocui.Gui, v *gocui.View) error { - if state.ConflictIndex <= 0 { +func (gui *Gui) handleSelectPrevConflict(g *gocui.Gui, v *gocui.View) error { + if gui.State.ConflictIndex <= 0 { return nil } - state.ConflictIndex-- - return refreshMergePanel(g) + gui.State.ConflictIndex-- + return gui.refreshMergePanel(g) } -func isIndexToDelete(i int, conflict commands.Conflict, pick string) bool { - return i == conflict.middle || - i == conflict.start || - i == conflict.end || +func (gui *Gui) isIndexToDelete(i int, conflict commands.Conflict, pick string) bool { + return i == conflict.Middle || + i == conflict.Start || + i == conflict.End || pick != "both" && - (pick == "bottom" && i > conflict.start && i < conflict.middle) || - (pick == "top" && i > conflict.middle && i < conflict.end) + (pick == "bottom" && i > conflict.Start && i < conflict.Middle) || + (pick == "top" && i > conflict.Middle && i < conflict.End) } -func resolveConflict(g *gocui.Gui, conflict commands.Conflict, pick string) error { +func (gui *Gui) resolveConflict(g *gocui.Gui, conflict commands.Conflict, pick string) error { gitFile, err := gui.getSelectedFile(g) if err != nil { return err @@ -116,126 +116,121 @@ func resolveConflict(g *gocui.Gui, conflict commands.Conflict, pick string) erro if err != nil { break } - if !isIndexToDelete(i, conflict, pick) { + if !gui.isIndexToDelete(i, conflict, pick) { output += line } } - devLog(output) + gui.Log.Info(output) return ioutil.WriteFile(gitFile.Name, []byte(output), 0644) } -func pushFileSnapshot(g *gocui.Gui) error { +func (gui *Gui) pushFileSnapshot(g *gocui.Gui) error { gitFile, err := gui.getSelectedFile(g) if err != nil { return err } - content, err := catFile(gitFile.Name) + content, err := gui.GitCommand.CatFile(gitFile.Name) if err != nil { return err } - state.EditHistory.Push(content) + gui.State.EditHistory.Push(content) return nil } -func handlePopFileSnapshot(g *gocui.Gui, v *gocui.View) error { - if state.EditHistory.Len() == 0 { +func (gui *Gui) handlePopFileSnapshot(g *gocui.Gui, v *gocui.View) error { + if gui.State.EditHistory.Len() == 0 { return nil } - prevContent := state.EditHistory.Pop().(string) + prevContent := gui.State.EditHistory.Pop().(string) gitFile, err := gui.getSelectedFile(g) if err != nil { return err } ioutil.WriteFile(gitFile.Name, []byte(prevContent), 0644) - return refreshMergePanel(g) + return gui.refreshMergePanel(g) } -func handlePickHunk(g *gocui.Gui, v *gocui.View) error { - conflict := state.Conflicts[state.ConflictIndex] - pushFileSnapshot(g) +func (gui *Gui) handlePickHunk(g *gocui.Gui, v *gocui.View) error { + conflict := gui.State.Conflicts[gui.State.ConflictIndex] + gui.pushFileSnapshot(g) pick := "bottom" - if state.ConflictTop { + if gui.State.ConflictTop { pick = "top" } - err := resolveConflict(g, conflict, pick) + err := gui.resolveConflict(g, conflict, pick) if err != nil { panic(err) } - refreshMergePanel(g) + gui.refreshMergePanel(g) return nil } -func handlePickBothHunks(g *gocui.Gui, v *gocui.View) error { - conflict := state.Conflicts[state.ConflictIndex] - pushFileSnapshot(g) - err := resolveConflict(g, conflict, "both") +func (gui *Gui) handlePickBothHunks(g *gocui.Gui, v *gocui.View) error { + conflict := gui.State.Conflicts[gui.State.ConflictIndex] + gui.pushFileSnapshot(g) + err := gui.resolveConflict(g, conflict, "both") if err != nil { panic(err) } - return refreshMergePanel(g) -} - -func currentViewName(g *gocui.Gui) string { - currentView := g.CurrentView() - return currentView.Name() + return gui.refreshMergePanel(g) } -func refreshMergePanel(g *gocui.Gui) error { - cat, err := catSelectedFile(g) +func (gui *Gui) refreshMergePanel(g *gocui.Gui) error { + cat, err := gui.catSelectedFile(g) if err != nil { return err } - state.Conflicts, err = findConflicts(cat) + gui.State.Conflicts, err = gui.findConflicts(cat) if err != nil { return err } - if len(state.Conflicts) == 0 { - return handleCompleteMerge(g) - } else if state.ConflictIndex > len(state.Conflicts)-1 { - state.ConflictIndex = len(state.Conflicts) - 1 + if len(gui.State.Co |