TUI #
TUI和CLI的定义和区别 #
- **TUI(Text-based User Interface)**:TUI是通过文本实现交互窗口展示内容,用户通过键盘输入命令进行操作。它提供字符图形界面,使得任务执行更加友好。
- **CLI(Command Line Interface)**:CLI是一种通过命令行解释器与计算机进行交互的用户界面。用户通过输入命令和参数来执行系统提供的各种功能。CLI通常通过终端或控制台访问,具有高度灵活性和资源效率。
TUI和CLI的关系 #
- 互补关系:TUI和CLI在Linux系统中相互补充,共同提供不同的交互方式。TUI通过字符图形界面简化操作,而CLI则通过命令行提供更高的灵活性和控制能力。
- 应用场景:TUI适用于需要字符图形界面的任务,如文件管理、简单的系统监控等;而CLI则适用于系统管理和配置、自动化脚本编写等需要高度控制和灵活性的任务。
bubbletea #
bubbletea是一个简单、小巧、可以非常方便地用来编写 TUI(terminal User Interface,控制台界面程序)程序的框架。内置简单的事件处理机制,可以对外部事件做出响应,如键盘按键。
快速使用 #
创建 Go 项目,并初始化
mkdir tui-demo && cd tui-demo
go mod init ygang.top/tui-demo
安装bubbletea库:
go get -u github.com/charmbracelet/bubbletea
bubbletea程序都需要有一个实现bubbletea.Model接口的类型:
type Model interface {
Init() Cmd
Update(Msg) (Model, Cmd)
View() string
}
Init()方法在程序启动时会立刻调用,它会做一些初始化工作,并返回一个Cmd告诉bubbletea要执行什么命令;Update()方法用来响应外部事件,返回一个修改后的模型,和想要bubbletea执行的命令;View()方法用于返回在控制台上显示的文本字符串。
package main
import (
"fmt"
tea "github.com/charmbracelet/bubbletea"
"os"
)
type Todo struct {
// 所有待完成事项
todos []string
// 界面上光标位置
cursor int
// 已完成标识
selected map[int]struct{}
}
var initTodo = &Todo{
todos: []string{"clean house", "wash clothes", "write a blog"},
selected: make(map[int]struct{}),
}
func (t *Todo) Init() tea.Cmd {
// 不需要初始化操作,所以返回 nil
return nil
}
/*
Update
ctrl+c或q:退出程序;
up或k:向上移动光标;
down或j:向下移动光标;
enter或:切换光标处事项的完成状态。
*/
func (t *Todo) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch model := msg.(type) {
case tea.KeyMsg:
switch model.String() {
case "ctrl+c", "q":
return t, tea.Quit
case "up", "k":
if t.cursor > 0 {
t.cursor--
}
case "down", "j":
if t.cursor < len(t.todos)-1 {
t.cursor++
}
case "enter":
_, ok := t.selected[t.cursor]
if ok {
delete(t.selected, t.cursor)
} else {
t.selected[t.cursor] = struct{}{}
}
}
}
return t, nil
}
/*
View 这个方法返回的字符串就是最终显示在控制台上的文本。
我们可以按照自己想要的形式,根据模型数据拼装
*/
func (t *Todo) View() string {
s := "Todo List:\n\n"
for i, choice := range t.todos {
cursor := ""
if t.cursor == i {
cursor = ">"
}
checked := ""
if _, ok := t.selected[i]; ok {
checked = "x"
}
s += fmt.Sprintf("%s [%s] %s\n", cursor, checked, choice)
}
s += "\nPress q to quit.\n"
return s
}
func main() {
program := tea.NewProgram(initTodo)
if _, err := program.Run(); err != nil {
fmt.Println("start failed:", err)
os.Exit(1)
}
}