Вступление к Bubble Tea в Go
Создавайте привлекательные приложения командной строки с помощью Bubble Tea (серия из 2 частей):
- Вступление к Bubble Tea в Go
- Обработка пользовательского ввода в Bubble Tea с помощью компонента меню
Делать что-то в командной строке - это круто, и вы можете почувствовать себя героем хакерского фильма. Но он также может казаться старомодным с монохромными лавинами текста или пугающими со всеми флагами командной строки, префиксами в виде знака доллара и различными способами прерывания работы без предупреждения.
Но командная строка не единственный способ использования вашего терминала, есть также TUI, пользовательские интерфейсы терминала, которые придают вашей программе более удобный вид. Мне это очень нравится, потому что они кажутся одновременно и новыми, и старыми. А в Go в последнее время больше внимания уделяется библиотеке Bubble Tea и всем другим инструментам Charm Bracelet, поскольку они упрощают создание TUI.
Преимущества Bubble Tea, которые сразу бросаются в глаза:
- Использует архитектуру Elm, которая используется совместно с платформами пользовательского интерфейса браузера, поэтому если вы уже работали с React, Vue или Elm, она будет вам знакома.
- Архитектура Elm не просто знакома современным разработчикам внешнего интерфейса, это отличный способ организовать код пользовательского интерфейса, поэтому он способствует созданию простого запуска вашего приложения и расширению его логики управляемым способом.
- Поскольку он находится в Go, последовательный синтаксис языка способствует обучению, читая код других людей.
В этой серии создадим базовое приложение TUI с нуля для регистрации того, что вы изучаете в коде каждый день, если используете программу типа #100Devs или одну из программ семейства #100DaysOfCode. На момент написания этой статьи она еще не закончена, поэтому каждое руководство будет посвящено рассмотрению конкретных концепций. Приблизительный маршрут будет выглядеть следующим образом:
- 🐣 Написание простого приложения hello world и просмотр того, как работает его архитектура;
- 📝 Создание нашего первого настоящего компонента Bubble Tea, меню;
- ✨ Придаем нашему меню классный вид с помощью стилей, используя CSS-like Lipgloss библиотеку;
- 🚇 Добавление маршрутизации в наше приложение для отображения разных страниц;
- 🫧 Использование компонентов Bubble Tea, созданных другими людьми с использованием библиотеки Bubbles;
- 📝 Сохранение наших чекинов в файле JSON.
Давайте прготовим свой терминал и углубимся в Bubble Tea.
🚧 Написание нашего первого базового приложения
В качестве первого шага мы собираемся создать приложение «hello world» в Bubble Tea, выход из которого осуществляется нажатием Ctrl+C, что также познакомит нас с каждой частью приложения Bubble Tea.
Сначала в новом каталоге под названием «code-journal» запустите:
go mod init
go get github.com/charmbracelet/bubbletea
Затем задайте файл с именем app.go
и добавьте следующий код:
package main
import (
tea "github.com/charmbracelet/bubbletea"
)
func main() {
p := tea.NewProgram(
newSimplePage("This app is under construction"),
)
if err := p.Start(); err != nil {
panic(err)
}
}
Затем давайте создадим другой файл с именем simple_page.go
, который содержит наш первый пользовательский интерфейс, простую страницу, которая просто отображает некоторый текст:
package main
import (
"fmt"
"strings"
tea "github.com/charmbracelet/bubbletea"
)
// MODEL DATA
type simplePage struct { text string }
func newSimplePage(text string) simplePage {
return simplePage{text: text}
}
func (s simplePage) Init() tea.Cmd { return nil }
// VIEW
func (s simplePage) View() string {
textLen := len(s.text)
topAndBottomBar := strings.Repeat("*", textLen + 4)
return fmt.Sprintf(
"%s\n* %s *\n%s\n\nPress Ctrl+C to exit",
topAndBottomBar, s.text, topAndBottomBar,
)
}
// UPDATE
func (s simplePage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg.(type) {
case tea.KeyMsg:
switch msg.(tea.KeyMsg).String() {
case "ctrl+c":
return s, tea.Quit
}
}
return s, nil
}
Прежде чем разберем код, давайте запустим его и посмотрим, что он делает. В вашем терминале запустите:
go build
./code-journal
и вы должны увидеть что-то вроде этого:
Вы запустили ваше первое приложение в Bubble Tea. Теперь давайте подробнее рассмотрим код.
🧋 Модель является основным интерфейсом Bubble Tea
Функция main запускает программу путем создания новой программы с моделью simplePage
.
func main() {
p := tea.NewProgram(
newSimplePage("This app is under construction"),
)
if err := p.Start(); err != nil {
panic(err)
}
}
Мы вызываем tea.NewProgram
, сигнатура которого:
func NewProgram(initialModel Model) *Program
а затем вызов метода Start этой программы запускает наше приложение. Но что такое initialModel
?
Model
является основным интерфейсом Bubble Tea. Он имеет три метода:
type Model interface {
Init() Cmd
Update(msg Msg) (Model, Cmd)
View() string
}
Метод Init взывается при запуске приложения, возвращая tea.Cmd
. Cmd
- более или менее «вещи происходящие за кулисами», такие как загрузка данных или течение времени. Но для текущего урока у нас нет никаких фоновых данных, поэтому наш метод init
просто возвращает nil
.
func (s simplePage) Init() tea.Cmd { return nil }
Далее у нас есть метод View
. Одна из крутых абстракций Bubble Tea заключается в том, что весь дисплей вашего пользовательского интерфейса представляет собой строку. А View
- это место, где вы создаете эту строку.
func (s simplePage) View() string {
textLen := len(s.text)
topAndBottomBar := strings.Repeat("*", textLen + 4)
return fmt.Sprintf(
"%s\n* %s *\n%s\n\nPress Ctrl+C to exit",
topAndBottomBar, s.text, topAndBottomBar,
)
}
Итак, мы поместили текст нашей simplePage
в поле, состоящее из звездочек, с сообщением внизу: «Нажмите Ctrl+C для выхода».
Но мы не можем выйти из нашего приложения, если оно не обрабатывает пользовательский ввод, так что здесь на помощь приходит наш. метод Update
.
func (s simplePage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg.(type) {
case tea.KeyMsg:
switch msg.(tea.KeyMsg).String() {
case "ctrl+c":
return s, tea.Quit
}
}
return s, nil
}
Метод Update
использует tea.Msg
и возвращает новый tea.Model
, а иногда и tea.Cmd
(например, если действие приводит к извлечению некоторых данных или срабатыванию таймера).
Сигнатура типа tea.Msg
type Msg interface {}
Таким образом, он может быть любого типа и содержать столько или так мало данных, сколько вам нужно. Это что-то вроде события браузера в JavaScript, если вы сделали там интерфейс; событие таймера не несет никаких данных, событие щелчка сообщает вам, на что нажали, и т.д.
Тип сообщения, которое мы обрабатываем, — tea.KeyMsg
, который представляет ввод с клавиатуры. Мы проверяем, нажал ли пользователь Ctrl+C, и если это так, мы возвращаем команду tea.Quit
, которая имеет тип tea.Cmd
и указывает Bubble Tea выйти из приложения.
Однако для любого другого вида ввода мы ничего не делаем. Мы просто возвращаем модель как есть. Если бы мы делали что-то вроде навигации по пользовательскому интерфейсу, мы бы изменили некоторые поля в модели, а затем вернули бы ее, что привело бы к обновлению пользовательского интерфейса. И это то, что мы увидим в следующем уроке, где мы создадим компонент меню!
Создавайте привлекательные приложения командной строки с помощью Bubble Tea (серия из 2 частей):