-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcmd.go
More file actions
138 lines (127 loc) · 3.3 KB
/
Copy pathcmd.go
File metadata and controls
138 lines (127 loc) · 3.3 KB
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
package wui
import "time"
// QuitMsg asks the runtime to shut the program down. Return it from a
// Cmd (or use Quit) rather than calling os.Exit, so the terminal is
// restored properly. In WASM builds it stops the event loop; the page
// itself stays open.
type QuitMsg struct{}
// BatchMsg carries several Msgs produced by Batch. The runtime unpacks
// it and feeds each Msg through Update in order.
type BatchMsg struct {
Msgs []Msg
}
// Quit returns a Cmd that ends the program.
func Quit() Cmd {
return func() Msg { return QuitMsg{} }
}
// Send wraps a value as a Cmd that delivers it immediately. It is the
// bridge from "I have a Msg" to "Update wants a Cmd":
//
// return m, wui.Send(savedMsg{})
func Send(msg Msg) Cmd {
return func() Msg { return msg }
}
// Batch runs cmds concurrently and delivers every resulting Msg. nil
// cmds are skipped; Batch returns nil when nothing is left to run.
func Batch(cmds ...Cmd) Cmd {
active := make([]Cmd, 0, len(cmds))
for _, c := range cmds {
if c != nil {
active = append(active, c)
}
}
switch len(active) {
case 0:
return nil
case 1:
return active[0]
}
return func() Msg {
msgs := make([]Msg, len(active))
done := make(chan struct{}, len(active))
for i, c := range active {
go func(i int, c Cmd) {
msgs[i] = c()
done <- struct{}{}
}(i, c)
}
for range active {
<-done
}
return BatchMsg{Msgs: msgs}
}
}
// Sequence runs cmds one after another, delivering their Msgs in order.
// Use it when a later command depends on an earlier one having run.
func Sequence(cmds ...Cmd) Cmd {
active := make([]Cmd, 0, len(cmds))
for _, c := range cmds {
if c != nil {
active = append(active, c)
}
}
if len(active) == 0 {
return nil
}
return func() Msg {
msgs := make([]Msg, 0, len(active))
for _, c := range active {
msgs = append(msgs, c())
}
return BatchMsg{Msgs: msgs}
}
}
// Tick delivers the Msg from build once, after d elapses. Reschedule
// from Update for a repeating timer:
//
// case tickMsg:
// m.elapsed++
// return m, wui.Tick(time.Second, func() wui.Msg { return tickMsg{} })
func Tick(d time.Duration, build func() Msg) Cmd {
return func() Msg {
time.Sleep(d)
if build == nil {
return nil
}
return build()
}
}
// Every delivers the Msg from build once, after the wall clock reaches
// the next multiple of d. Unlike Tick, successive ticks stay aligned to
// the clock rather than drifting by the time Update takes — use it for
// anything displaying a real time.
func Every(d time.Duration, build func(time.Time) Msg) Cmd {
return func() Msg {
if d <= 0 {
if build == nil {
return nil
}
return build(time.Now())
}
now := time.Now()
time.Sleep(now.Truncate(d).Add(d).Sub(now))
if build == nil {
return nil
}
return build(time.Now())
}
}
// Do runs f in the background and delivers the Msg it returns. It is
// the plain-function form of a Cmd, for readability at call sites.
func Do(f func() Msg) Cmd { return f }
// unpackBatch flattens nested BatchMsgs into a flat list of Msgs,
// dropping nils. Both runtimes use it so Batch composes with itself.
func unpackBatch(msg Msg) []Msg {
b, ok := msg.(BatchMsg)
if !ok {
if msg == nil {
return nil
}
return []Msg{msg}
}
var out []Msg
for _, m := range b.Msgs {
out = append(out, unpackBatch(m)...)
}
return out
}