-
Notifications
You must be signed in to change notification settings - Fork 0
/
tui.go
135 lines (118 loc) · 2.81 KB
/
tui.go
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
package main
import (
"os/exec"
"strings"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/list"
"github.com/charmbracelet/bubbles/spinner"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
var docStyle = lipgloss.NewStyle().Margin(1, 2)
type repoMsg struct {
repo
}
type doneMsg struct{}
type errMsg error
func (r repo) Title() string {
return r.path
}
func (r repo) Description() string {
// NOTE: list renders single line only..
return r.status
}
func (r repo) FilterValue() string {
return r.path
}
type model struct {
list list.Model
path string
sub chan repo
quitting bool
err error
}
func (m model) Init() tea.Cmd {
return tea.Batch(
m.list.StartSpinner(),
startRepoSearch(m.path, m.sub),
waitForRepoStatus(m.sub),
)
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case tea.KeyEnter.String():
return m, openEditor(m.list.SelectedItem().(repo).path)
case "u":
return m, tea.Sequence(m.list.SetItems([]list.Item{}), m.Init())
}
case tea.WindowSizeMsg:
h, v := docStyle.GetFrameSize()
m.list.SetSize(msg.Width-h, msg.Height-v)
case repoMsg:
return m, tea.Sequence(
m.list.InsertItem(len(m.list.Items()), msg.repo),
waitForRepoStatus(m.sub), // wait for next found repo
)
case doneMsg:
m.list.StopSpinner()
return m, nil
case errMsg:
m.err = msg
return m, nil
}
var cmd tea.Cmd
m.list, cmd = m.list.Update(msg)
return m, cmd
}
func (m model) View() string {
if m.err != nil {
return m.err.Error()
}
// Remove duplicate (status has it) + misaligned string coming from:
// https://github.com/charmbracelet/bubbles/blob/178590b4469b2386726cff8da7c479615a746a94/list/list.go#L1220
s := strings.Replace(m.list.View(), "No repositories.", "", 1)
if m.quitting {
s += "\n"
}
return s
}
func initialModel(wd string) tea.Model {
l := list.New([]list.Item{}, list.NewDefaultDelegate(), 0, 0)
l.Title = "Dirty Repositories"
l.SetStatusBarItemName("repository", "repositories")
l.SetSpinner(spinner.MiniDot)
l.ToggleSpinner()
l.AdditionalShortHelpKeys = additionalShortHelpKeys
return model{list: l, path: wd, sub: make(chan repo)}
}
func additionalShortHelpKeys() []key.Binding {
return []key.Binding{
key.NewBinding(
key.WithKeys("u"),
key.WithHelp("u", "update"),
),
}
}
func startRepoSearch(path string, sub chan repo) tea.Cmd {
return func() tea.Msg {
err := collectDirtyRepos(path, sub)
if err != nil {
return err
}
return doneMsg{}
}
}
func waitForRepoStatus(sub chan repo) tea.Cmd {
return func() tea.Msg {
repo := <-sub
return repoMsg{repo: repo}
}
}
func openEditor(path string) tea.Cmd {
c := exec.Command("code", path)
return tea.ExecProcess(c, func(err error) tea.Msg {
return nil
})
}