summaryrefslogtreecommitdiffstats
path: root/branches_panel.go
blob: 0b8508a3d7d71b7404e384d0f64b96ac6d3e42e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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
}