commands.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. package tea
  2. import (
  3. "time"
  4. )
  5. // Batch performs a bunch of commands concurrently with no ordering guarantees
  6. // about the results. Use a Batch to return several commands.
  7. //
  8. // Example:
  9. //
  10. // func (m model) Init() Cmd {
  11. // return tea.Batch(someCommand, someOtherCommand)
  12. // }
  13. func Batch(cmds ...Cmd) Cmd {
  14. var validCmds []Cmd
  15. for _, c := range cmds {
  16. if c == nil {
  17. continue
  18. }
  19. validCmds = append(validCmds, c)
  20. }
  21. if len(validCmds) == 0 {
  22. return nil
  23. }
  24. return func() Msg {
  25. return BatchMsg(validCmds)
  26. }
  27. }
  28. // BatchMsg is a message used to perform a bunch of commands concurrently with
  29. // no ordering guarantees. You can send a BatchMsg with Batch.
  30. type BatchMsg []Cmd
  31. // Sequence runs the given commands one at a time, in order. Contrast this with
  32. // Batch, which runs commands concurrently.
  33. func Sequence(cmds ...Cmd) Cmd {
  34. return func() Msg {
  35. return sequenceMsg(cmds)
  36. }
  37. }
  38. // sequenceMsg is used internally to run the given commands in order.
  39. type sequenceMsg []Cmd
  40. // Every is a command that ticks in sync with the system clock. So, if you
  41. // wanted to tick with the system clock every second, minute or hour you
  42. // could use this. It's also handy for having different things tick in sync.
  43. //
  44. // Because we're ticking with the system clock the tick will likely not run for
  45. // the entire specified duration. For example, if we're ticking for one minute
  46. // and the clock is at 12:34:20 then the next tick will happen at 12:35:00, 40
  47. // seconds later.
  48. //
  49. // To produce the command, pass a duration and a function which returns
  50. // a message containing the time at which the tick occurred.
  51. //
  52. // type TickMsg time.Time
  53. //
  54. // cmd := Every(time.Second, func(t time.Time) Msg {
  55. // return TickMsg(t)
  56. // })
  57. //
  58. // Beginners' note: Every sends a single message and won't automatically
  59. // dispatch messages at an interval. To do that, you'll want to return another
  60. // Every command after receiving your tick message. For example:
  61. //
  62. // type TickMsg time.Time
  63. //
  64. // // Send a message every second.
  65. // func tickEvery() Cmd {
  66. // return Every(time.Second, func(t time.Time) Msg {
  67. // return TickMsg(t)
  68. // })
  69. // }
  70. //
  71. // func (m model) Init() Cmd {
  72. // // Start ticking.
  73. // return tickEvery()
  74. // }
  75. //
  76. // func (m model) Update(msg Msg) (Model, Cmd) {
  77. // switch msg.(type) {
  78. // case TickMsg:
  79. // // Return your Every command again to loop.
  80. // return m, tickEvery()
  81. // }
  82. // return m, nil
  83. // }
  84. //
  85. // Every is analogous to Tick in the Elm Architecture.
  86. func Every(duration time.Duration, fn func(time.Time) Msg) Cmd {
  87. return func() Msg {
  88. n := time.Now()
  89. d := n.Truncate(duration).Add(duration).Sub(n)
  90. t := time.NewTimer(d)
  91. return fn(<-t.C)
  92. }
  93. }
  94. // Tick produces a command at an interval independent of the system clock at
  95. // the given duration. That is, the timer begins precisely when invoked,
  96. // and runs for its entire duration.
  97. //
  98. // To produce the command, pass a duration and a function which returns
  99. // a message containing the time at which the tick occurred.
  100. //
  101. // type TickMsg time.Time
  102. //
  103. // cmd := Tick(time.Second, func(t time.Time) Msg {
  104. // return TickMsg(t)
  105. // })
  106. //
  107. // Beginners' note: Tick sends a single message and won't automatically
  108. // dispatch messages at an interval. To do that, you'll want to return another
  109. // Tick command after receiving your tick message. For example:
  110. //
  111. // type TickMsg time.Time
  112. //
  113. // func doTick() Cmd {
  114. // return Tick(time.Second, func(t time.Time) Msg {
  115. // return TickMsg(t)
  116. // })
  117. // }
  118. //
  119. // func (m model) Init() Cmd {
  120. // // Start ticking.
  121. // return doTick()
  122. // }
  123. //
  124. // func (m model) Update(msg Msg) (Model, Cmd) {
  125. // switch msg.(type) {
  126. // case TickMsg:
  127. // // Return your Tick command again to loop.
  128. // return m, doTick()
  129. // }
  130. // return m, nil
  131. // }
  132. func Tick(d time.Duration, fn func(time.Time) Msg) Cmd {
  133. return func() Msg {
  134. t := time.NewTimer(d)
  135. return fn(<-t.C)
  136. }
  137. }
  138. // Sequentially produces a command that sequentially executes the given
  139. // commands.
  140. // The Msg returned is the first non-nil message returned by a Cmd.
  141. //
  142. // func saveStateCmd() Msg {
  143. // if err := save(); err != nil {
  144. // return errMsg{err}
  145. // }
  146. // return nil
  147. // }
  148. //
  149. // cmd := Sequentially(saveStateCmd, Quit)
  150. //
  151. // Deprecated: use Sequence instead.
  152. func Sequentially(cmds ...Cmd) Cmd {
  153. return func() Msg {
  154. for _, cmd := range cmds {
  155. if cmd == nil {
  156. continue
  157. }
  158. if msg := cmd(); msg != nil {
  159. return msg
  160. }
  161. }
  162. return nil
  163. }
  164. }