-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathtea_taskmodel.go
145 lines (123 loc) · 2.99 KB
/
tea_taskmodel.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
136
137
138
139
140
141
142
143
144
145
package cmd
import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
"github.com/charmbracelet/bubbles/spinner"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
// waitForCancellation returns a tea.Cmd that will wait for SIGINT and SIGTERM and run the provided cancel on receipt.
func waitForCancellation(ctx context.Context, cancel context.CancelFunc) tea.Cmd {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
return func() tea.Msg {
select {
case <-sigs:
cancel()
case <-ctx.Done():
}
return tea.Quit
}
}
type taskStatus int
const (
taskStatusPending taskStatus = 0
taskStatusRunning taskStatus = 1
taskStatusDone taskStatus = 2
taskStatusError taskStatus = 3
taskStatusSkipped taskStatus = 4
)
type taskModel struct {
status taskStatus
title string
spinner spinner.Model
width int
indent int
}
type WithTaskModel interface {
TaskModel() taskModel
}
// assert that taskModel implements WithTaskModel
var _ WithTaskModel = (*taskModel)(nil)
type updateTaskTitleMsg struct {
id int
title string
}
type updateTaskStatusMsg struct {
id int
status taskStatus
}
func NewTaskModel(title string, width int) taskModel {
return taskModel{
status: taskStatusPending,
title: title,
spinner: spinner.New(
spinner.WithSpinner(DotsSpinner),
spinner.WithStyle(lipgloss.NewStyle().Foreground(ColorPalette.BgMain)),
),
width: width,
indent: 2,
}
}
func (m taskModel) Init() tea.Cmd {
if m.status == taskStatusRunning {
return m.spinner.Tick
}
return nil
}
func (m taskModel) TaskModel() taskModel {
return m
}
func (m taskModel) Update(msg tea.Msg) (taskModel, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.width = min(MAX_TERMINAL_WIDTH, msg.Width)
return m, nil
case updateTaskTitleMsg:
if m.spinner.ID() == msg.id {
m.title = msg.title
}
case updateTaskStatusMsg:
if m.spinner.ID() == msg.id {
m.status = msg.status
}
default:
var cmd tea.Cmd
m.spinner, cmd = m.spinner.Update(msg)
return m, cmd
}
return m, nil
}
func (m taskModel) View() string {
label := ""
switch m.status {
case taskStatusPending:
label = lipgloss.NewStyle().Foreground(ColorPalette.LabelFaint).Render("+")
case taskStatusRunning:
label = m.spinner.View()
case taskStatusDone:
label = lipgloss.NewStyle().Foreground(ColorPalette.BgSuccess).Render("✔︎")
case taskStatusError:
label = lipgloss.NewStyle().Foreground(ColorPalette.BgDanger).Render("✗")
case taskStatusSkipped:
label = lipgloss.NewStyle().Foreground(ColorPalette.LabelFaint).Render("-")
default:
label = lipgloss.NewStyle().Render("?")
}
return wrap(fmt.Sprintf("%v %v", label, m.title), m.width, m.indent)
}
func (m taskModel) UpdateTitleMsg(newTitle string) tea.Msg {
return updateTaskTitleMsg{
id: m.spinner.ID(),
title: newTitle,
}
}
func (m taskModel) UpdateStatusMsg(newStatus taskStatus) tea.Msg {
return updateTaskStatusMsg{
id: m.spinner.ID(),
status: newStatus,
}
}