Share
Embed
Transcript
21 slides
-
ೖ Bubble Tea 2022 - 0 6 - 1 1
motemen Kyoto.go LT -
charmbracelet/ bubbletea Go TUI The fun, functional and stateful way
to build terminal apps. A Go framework based on The Elm Architecture. -
The Elm Architecture • Model: ΞϓϦέʔγϣϯͷεςʔτ • View: Model ͔Β
HTML Λੜ • Update: Msg ʹج͖ͮ Model Λߋ৽ • Msg ϢʔβೖྗͳͲϞσϧͷ֎෦ View() Update(msg) Model Msg -
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 } -
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) } -
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() ͕ը໘ʹඳը͞ΕΔ -
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{} -
bubbletea ʹͤΔ 🚀 func main() { prog := tea.NewProgram(model{count: 0})
err := prog.Start() if err != nil { log.Fatal(err) } } -
ऴྃͰ͖ΔΑ͏ʹ͢Δ 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Λฦ͢ -
tea.Cmd • “Cmd is an IO operation that returns a
message when it's complete” • ֎քͷ໋ྩ • ऴΘͬͨΒ Msg Λؔ͢ • goroutine Ͱ࣮ߦ͞ΕΔ View() Cmd Update(msg) Model Msg -
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Λฦ͢ -
ΦϦδφϧͷ 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Λड͚औͬͨΒϞσϧߋ৽ -
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 -
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