ui.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/gdamore/tcell/v2"
  6. "github.com/oklog/run"
  7. "github.com/rivo/tview"
  8. "io"
  9. )
  10. type UI struct {
  11. app *tview.Application
  12. flex *tview.Flex
  13. logbox *tview.TextView
  14. menu *tview.List
  15. running bool
  16. grp *run.Group
  17. pctx context.Context
  18. cncl context.CancelFunc
  19. tasks []*Task
  20. logwr io.Writer
  21. }
  22. func NewUI() *UI {
  23. ui := &UI{
  24. app: tview.NewApplication(),
  25. flex: tview.NewFlex(),
  26. logbox: tview.NewTextView(),
  27. menu: tview.NewList(),
  28. }
  29. ui.flex.AddItem(ui.menu, 32, 0, true)
  30. ui.flex.AddItem(ui.logbox, 0, 1, false)
  31. ui.flex.SetDirection(tview.FlexColumn)
  32. ui.logbox.SetScrollable(true)
  33. ui.logbox.SetBackgroundColor(tcell.ColorNavy)
  34. ui.logwr = tview.ANSIWriter(ui.logbox)
  35. ui.menu.AddItem("start", "", 0, ui.startTasks)
  36. ui.menu.AddItem("cancel parent", "", 0, ui.killParent)
  37. ui.menu.AddItem("cancel Task1", "", 0, func() {
  38. ui.killTask(0)
  39. })
  40. ui.menu.AddItem("cancel Task2", "", 0, func() {
  41. ui.killTask(1)
  42. })
  43. ui.menu.AddItem("cancel Task3", "", 0, func() {
  44. ui.killTask(2)
  45. })
  46. ui.app.SetRoot(ui.flex, true)
  47. ui.app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
  48. switch event.Key() {
  49. case tcell.KeyF1:
  50. {
  51. ui.app.SetFocus(ui.menu)
  52. break
  53. }
  54. case tcell.KeyF2:
  55. {
  56. ui.app.SetFocus(ui.logbox)
  57. break
  58. }
  59. default:
  60. {
  61. return event
  62. }
  63. }
  64. return nil
  65. })
  66. return ui
  67. }
  68. func (u *UI) killParent() {
  69. if u.running {
  70. _, _ = fmt.Fprintln(u, "[UI] cancel parent")
  71. u.cncl()
  72. } else {
  73. _, _ = fmt.Fprintln(u, "[UI] tasks not running")
  74. }
  75. }
  76. func (u *UI) startTasks() {
  77. if !u.running {
  78. u.grp = &run.Group{}
  79. ctx, cncl := context.WithCancel(context.Background())
  80. u.pctx = ctx
  81. u.cncl = cncl
  82. u.tasks = make([]*Task, 3)
  83. for i := 0; i < 3; i++ {
  84. t := NewTask(i+1, u.pctx, u)
  85. u.tasks[i] = t
  86. u.grp.Add(t.Task, t.Cancel)
  87. }
  88. go func() {
  89. _, _ = fmt.Fprintln(u, "[UI] run tasks.")
  90. u.running = true
  91. err := u.grp.Run()
  92. if err != nil {
  93. _, _ = fmt.Fprintln(u, "[UI] all tasks end, with error:", err)
  94. } else {
  95. _, _ = fmt.Fprintln(u, "[UI] all tasks end, with no error")
  96. }
  97. u.running = false
  98. }()
  99. } else {
  100. _, _ = fmt.Fprintln(u, "[UI] tasks already running")
  101. }
  102. }
  103. func (u *UI) killTask(id int) {
  104. if !u.running {
  105. _, _ = fmt.Fprintln(u, "[UI] tasks not running")
  106. return
  107. }
  108. v := u.tasks[id]
  109. if v != nil {
  110. _, _ = fmt.Fprintf(u, "[UI] cancel task %d\n", id+1)
  111. v.Cancel(nil)
  112. }
  113. }
  114. func (u *UI) Write(p []byte) (n int, err error) {
  115. return u.logwr.Write(p)
  116. }
  117. func (u *UI) Run() error {
  118. return u.app.Run()
  119. }