summaryrefslogtreecommitdiffstats
path: root/pkg/gui/panels/branches_panel.go
blob: 63e3ad7e8ddeb372ef1248250c7b2f6933c7c092 (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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package panels

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 handleDeleteBranch(g *gocui.Gui, v *gocui.View) error {
	checkedOutBranch := state.Branches[0]
	selectedBranch := getSelectedBranch(v)
	if checkedOutBranch.Name == selectedBranch.Name {
		return createErrorPanel(g, "You cannot delete the checked out branch!")
	}
	return createConfirmationPanel(g, v, "Delete Branch", "Are you sure you want delete the branch "+selectedBranch.Name+" ?", func(g *gocui.Gui, v *gocui.View) error {
		if output, err := gitDeleteBranch(selectedBranch.Name); err != nil {
			return createErrorPanel(g, output)
		}
		return refreshSidePanels(g)
	}, 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",
		"d":       "delete 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)
		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)
		}
		builder := git.newBranchListBuilder() // TODO: add constructor params
		state.Branches = builder.build()
		v.Clear()
		for _, branch := range state.Branches {
			fmt.Fprintln(v, branch.getDisplayString())
		}
		resetOrigin(v)
		return refreshStatus(g)
	})
	return nil
}