summaryrefslogtreecommitdiffstats
path: root/pkg/gui/menu_panel.go
blob: 983543c948c8dc76da302b38c8be0afb8decacfb (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
package gui

import (
	"fmt"
	"strings"

	"github.com/jesseduffield/gocui"
	"github.com/jesseduffield/lazygit/pkg/utils"
)

func (gui *Gui) handleMenuPress(g *gocui.Gui, v *gocui.View) error {
	lineNumber := gui.getItemPosition(v)
	if gui.State.Keys[lineNumber].Key == nil {
		return nil
	}
	if len(gui.State.Keys) > lineNumber {
		err := gui.handleMenuClose(g, v)
		if err != nil {
			return err
		}
		return gui.State.Keys[lineNumber].Handler(g, v)
	}
	return nil
}

func (gui *Gui) handleMenuSelect(g *gocui.Gui, v *gocui.View) error {
	// doing nothing for now
	// but it is needed for switch in newLineFocused
	return nil
}

func (gui *Gui) renderMenuOptions(g *gocui.Gui) error {
	optionsMap := map[string]string{
		"esc/q": gui.Tr.SLocalize("close"),
		"↑ ↓":   gui.Tr.SLocalize("navigate"),
		"space": gui.Tr.SLocalize("execute"),
	}
	return gui.renderOptionsMap(g, optionsMap)
}

func (gui *Gui) handleMenuClose(g *gocui.Gui, v *gocui.View) error {
	// better to delete because for example after closing update confirmation panel,
	// the focus isn't set back to any of panels and one is unable to even quit
	//_, err := g.SetViewOnBottom(v.Name())
	err := g.DeleteView("menu")
	if err != nil {
		return err
	}
	return gui.returnFocus(g, v)
}

func (gui *Gui) GetKey(binding Binding) string {
	r, ok := binding.Key.(rune)
	key := ""

	if ok {
		key = string(r)
	} else if binding.KeyReadable != "" {
		key = binding.KeyReadable
	}

	return key
}

func (gui *Gui) GetMaxKeyLength(bindings []Binding) int {
	max := 0
	for _, binding := range bindings {
		keyLength := len(gui.GetKey(binding))
		if keyLength > max {
			max = keyLength
		}
	}
	return max
}

func (gui *Gui) handleMenu(g *gocui.Gui, v *gocui.View) error {
	var (
		contentGlobal, contentPanel   []string
		bindingsGlobal, bindingsPanel []Binding
	)
	// clear keys slice, so we don't have ghost elements
	gui.State.Keys = gui.State.Keys[:0]
	bindings := gui.GetKeybindings()
	padWidth := gui.GetMaxKeyLength(bindings)

	for _, binding := range bindings {
		key := gui.GetKey(binding)
		if key != "" && binding.Description != "" {
			content := fmt.Sprintf("%s  %s", utils.WithPadding(key, padWidth), binding.Description)
			switch binding.ViewName {
			case "":
				contentGlobal = append(contentGlobal, content)
				bindingsGlobal = append(bindingsGlobal, binding)
			case v.Name():
				contentPanel = append(contentPanel, content)
				bindingsPanel = append(bindingsPanel, binding)
			}
		}
	}

	// append dummy element to have a separator between
	// panel and global keybindings
	contentPanel = append(contentPanel, "")
	bindingsPanel = append(bindingsPanel, Binding{})

	content := append(contentPanel, contentGlobal...)
	gui.State.Keys = append(bindingsPanel, bindingsGlobal...)
	contentJoined := strings.Join(content, "\n")

	x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(g, contentJoined)
	menuView, _ := g.SetView("menu", x0, y0, x1, y1, 0)
	menuView.Title = strings.Title(gui.Tr.SLocalize("menu"))
	menuView.FgColor = gocui.ColorWhite

	if err := gui.renderMenuOptions(g); err != nil {
		return err
	}

	fmt.Fprint(menuView, contentJoined)

	g.Update(func(g *gocui.Gui) error {
		_, err := g.SetViewOnTop("menu")
		if err != nil {
			return err
		}
		return gui.switchFocus(g, v, menuView)
	})
	return nil
}