Upgrade to Pro — share decks privately, control downloads, hide ads and more …

入門 Bubble Tea

Avatar for motemen motemen
June 11, 2022

入門 Bubble Tea

Avatar for motemen

motemen

June 11, 2022
Tweet

More Decks by motemen

Other Decks in Technology

Transcript

  1. charmbracelet/ bubbletea Go TUI The fun, functional and stateful way

    to build terminal apps. A Go framework based on The Elm Architecture.
  2. The Elm Architecture • Model: ΞϓϦέʔγϣϯͷεςʔτ • View: Model ͔Β

    HTML Λੜ੒ • Update: Msg ʹج͖ͮ Model Λߋ৽ • Msg ͸ϢʔβೖྗͳͲϞσϧͷ֎෦ View() Update(msg) Model Msg
  3. interface tea.Model // Model contains the program's state as well

    as its core functions. type Model interface { // Init is the first function that will be called. It returns an optional // initial command. To not perform an initial command return nil. Init() Cmd // Update is called when a message is received. Use it to inspect messages // and, in response, update the model and/or send a command. Update(Msg) (Model, Cmd) // View renders the program's UI, which is just a string. The view is // rendered after every Update. View() string }
  4. model, View() string type model struct { count int }

    func (model) Init() tea.Cmd { return nil } func (m model) View() string { return fmt.Sprintf("count: %v", m.count) }
  5. Update(tea.Msg) (tea.Model, tea.Cmd) func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd)

    { switch msg := msg.(type) { case tea.KeyMsg: switch msg.String() { case " ": m.count = m.count + 1 return m, nil } } return m, nil } ߋ৽͞ΕͨϞσϧΛฦ͢ View() ͕ը໘ʹඳը͞ΕΔ
  6. Msg ͸Ϣʔβʗ֎ք͔Βͷೖྗ Msg contain data from the result of a

    IO operation. Msgs trigger the update function and, henceforth, the UI. tea.KeyMsg tea.MouseMsg tea.WindowMsg Msg type Msg interface{}
  7. bubbletea ʹ৐ͤΔ 🚀 func main() { prog := tea.NewProgram(model{count: 0})

    err := prog.Start() if err != nil { log.Fatal(err) } }
  8. ऴྃͰ͖ΔΑ͏ʹ͢Δ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch

    msg := msg.(type) { case tea.KeyMsg: switch msg.String() { case "q", "ctrl+c": return m, tea.Quit case " ": m.count = m.count + 1 return m, nil } } return m, nil } CmdΛฦ͢
  9. tea.Cmd • “Cmd is an IO operation that returns a

    message when it's complete” • ֎ք΁ͷ໋ྩ • ऴΘͬͨΒ Msg Λ໭ؔ͢਺ • goroutine Ͱ࣮ߦ͞ΕΔ View() Cmd Update(msg) Model Msg
  10. HTTP ௨৴Λ൐͏ྫ type countLoadedMsg struct { count int } func

    (m model) hitCounter() tea.Msg { count, err := m.api.Hit() if err != nil { panic(err) } return countLoadedMsg{count: count} } var _ tea.Cmd = model{}.hitCounter ͜ͷϝιουͷܕ͕ tea.Cmd IO͕ऴΘͬͨΒMsgΛฦ͢
  11. ΦϦδφϧͷ Msg Λड͚औΔ func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd)

    { switch msg := msg.(type) { case tea.KeyMsg: switch msg.String() { case " ": m.loading = true return m, m.hitCounter } case countLoadedMsg: m.count = msg.count m.loading = false return m, nil } return m, nil } CmdΛฦ͢ MsgΛड͚औͬͨΒϞσϧߋ৽
  12. Init(), View() func (m model) Init() tea.Cmd { return m.hitCounter

    } func (m model) View() string { if m.loading { return "..." } else { return fmt.Sprintf("count: %v", m.count) } } ϓϩάϥϜ։࢝࣌ʹൃߦ͍ͨ͠Cmd
  13. bubbles ࢖ͬͨྫ type model struct { ... spinner spinner.Model }

    func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmd tea.Cmd m.spinner, cmd = m.spinner.Update(msg) ... } func (m model) View() string { if m.loading { return m.spinner.View() } ... } func (m model) Init() tea.Cmd { return tea.Batch( m.hitCounter, m.spinner.Tick, ) } • charmbracelet/bubbles • bubbletea ༻ͷ TUI ίϯ ϙʔωϯτू ModelΛೖΕࢠʹ ࢠڙʹ΋MsgΛ౉͢ Ξχϝʔγϣϯ༻Cmd