package main import ( "fmt" "strings" "github.com/jesseduffield/gocui" ) func handleBranchPress(g *gocui.Gui, v *gocui.View) error { index := getItemPosition(v) if index == 0 { return createErrorPanel(g, "You have already checked out this branch") } branch := getSelectedBranch(v) if output, err := gitCheckout(branch.Name, false); err != nil { createErrorPanel(g, output) } return refreshSidePanels(g) } func handleForceCheckout(g *gocui.Gui, v *gocui.View) error { branch := getSelectedBranch(v) return 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 { if output, err := gitCheckout(branch.Name, true); err != nil { createErrorPanel(g, output) } return refreshSidePanels(g) }, nil) } func handleCheckoutByName(g *gocui.Gui, v *gocui.View) error { createPromptPanel(g, v, "Branch Name:", func(g *gocui.Gui, v *gocui.View) error { if output, err := gitCheckout(trimmedContent(v), false); err != nil { return createErrorPanel(g, output) } return refreshSidePanels(g) }) return nil } func handleNewBranch(g *gocui.Gui, v *gocui.View) error { branch := state.Branches[0] createPromptPanel(g, v, "New Branch Name (Branch is off of "+branch.Name+")", func(g *gocui.Gui, v *gocui.View) error { if output, err := gitNewBranch(trimmedContent(v)); err != nil { return createErrorPanel(g, output) } refreshSidePanels(g) return handleBranchSelect(g, v) }) return nil } func handleMerge(g *gocui.Gui, v *gocui.View) error { checkedOutBranch := state.Branches[0] selectedBranch := getSelectedBranch(v) defer refreshSidePanels(g) if checkedOutBranch.Name == selectedBranch.Name { return createErrorPanel(g, "You cannot merge a branch into itself") } if output, err := gitMerge(selectedBranch.Name); err != nil { return createErrorPanel(g, output) } return nil } func getSelectedBranch(v *gocui.View) Branch { lineNumber := getItemPosition(v) return state.Branches[lineNumber] } func renderBranchesOptions(g *gocui.Gui) error { return renderOptionsMap(g, map[string]string{ "space": "checkout", "f": "force checkout", "m": "merge", "c": "checkout by name", "n": "new branch", "← → ↑ ↓": "navigate", }) } // may want to standardise how these select methods work func handleBranchSelect(g *gocui.Gui, v *gocui.View) error { if err := renderBranchesOptions(g); err != nil { return err } // This really shouldn't happen: there should always be a master branch if len(state.Branches) == 0 { return renderString(g, "main", "No branches for this repo") } go func() { branch := getSelectedBranch(v) diff, err := getBranchGraph(branch.Name, branch.BaseBranch) if err != nil && strings.HasPrefix(diff, "fatal: ambiguous argument") { diff = "There is no tracking for this branch" } renderString(g, "main", diff) }() return nil } // 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 refreshBranches(g *gocui.Gui) error { g.Update(func(g *gocui.Gui) error { v, err := g.View("branches") if err != nil { panic(err) } state.Branches = getGitBranches() v.Clear() for _, branch := range state.Branches { fmt.Fprintln(v, branch.DisplayString) } resetOrigin(v) return refreshStatus(g) }) return nil }