AI书签管理工具开发全记录(十三):TUI基本框架搭建

文章目录

  • AI书签管理工具开发全记录(十三):TUI基本框架搭建
    • [前言 📝](#前言 📝)
    • [1.TUI介绍 🔍](#1.TUI介绍 🔍)
    • [2. 框架选择 ⚙️](#2. 框架选择 ⚙️)
    • [3. 功能梳理 🎯](#3. 功能梳理 🎯)
    • [4. 基础框架搭建⚙️](#4. 基础框架搭建⚙️)
      • [4.1 安装](#4.1 安装)
      • [4.2 参数设计](#4.2 参数设计)
      • [4.3 绘制ui](#4.3 绘制ui)
        • [4.3.1 设计结构体](#4.3.1 设计结构体)
        • [4.3.2 创建头部](#4.3.2 创建头部)
        • [4.3.3 创建主体](#4.3.3 创建主体)
        • [4.3.4 创建日志栏](#4.3.4 创建日志栏)
        • [4.3.5 创建整体布局](#4.3.5 创建整体布局)
        • [4.3.6 创建启动函数](#4.3.6 创建启动函数)
        • [4.3.6 对接cobra命令行](#4.3.6 对接cobra命令行)
    • [5.效果测试 ✅](#5.效果测试 ✅)

AI书签管理工具开发全记录(十三):TUI基本框架搭建

前言 📝

在上一篇文章中,我们实现了MCP查询集成,集成了常用的查询场景,在支持MCP的客户端如cherry studio中可以查询书签数据了。但有时候,我们需要快速的浏览书签书签,没有比命令行的方式更快速的了,但是命令行操作太繁琐,所以我们本篇文章采用更进一步的TUI。

1.TUI介绍 🔍

TUI(Terminal User Interface) 是命令行工具与图形界面的完美融合体。不同于传统CLI需要记忆复杂指令的操作方式,TUI通过直观的文本界面组件(如菜单、列表、状态栏)实现可视化交互;相较于GUI应用,它又保留了终端操作的高效性与轻量级优势。经典的Linux工具如htopncduvim都证明了TUI在提升生产力方面的价值------无需离开终端窗口,即可实现键盘驱动的快速导航与操作。

在书签管理场景中,TUI能让我们通过方向键即时浏览收藏链接,用快捷键执行搜索/跳转/删除等操作,避免图形界面加载的延迟和命令行输入的低效。

2. 框架选择 ⚙️

在Go语言的TUI框架生态中,rivo/tview 以其组件化的设计强大的布局能力卓越的性能 脱颖而出,成为我们构建书签管理TUI的首选。它提供了一套丰富且高度可定制的基础组件 (如列表 List、表格 Table、文本框 TextView、表单 Form、模态框 Modal 等)和灵活的布局管理器 (如 Flex, Grid, Pages),极大地简化了复杂终端界面的构建过程。其核心优势在于:

  1. 声明式布局:通过组合嵌套布局和组件,可以直观地构建出结构清晰、响应式的界面,适应不同终端尺寸。
  2. 高效渲染与键盘导航tview 采用智能渲染机制,确保界面更新流畅。它内置了强大且可自定义的键盘事件处理系统,让我们能够轻松为书签的浏览、选择、搜索、操作(打开、删除、编辑)定义直观的快捷键,实现真正的"键盘驱动"体验。
  3. 丰富的样式与主题:支持设置文本颜色、背景色、边框样式、标题等,允许我们为书签的不同状态(如已读/未读、分类)设计清晰的视觉区分。
  4. 活跃的社区与成熟度 :作为Go领域最受欢迎的TUI库之一,tview 拥有良好的文档、活跃的社区支持和经过大量项目验证的稳定性。

选择 tview,意味着我们能高效地 实现一个性能出色交互流畅视觉清晰 的书签管理终端应用,完美契合我们追求快速浏览与操作的核心目标。接下来,我们将开始搭建基于 tview 的应用基础框架。

3. 功能梳理 🎯

在开始搭建基础框架前,我们先规划一下tui应用需求和布局

功能列表:

  • 需要搜索功能,可以快速搜索书签
  • 可以快速浏览器分类、书签

ui设计:

  • 最顶层是搜索框,可以输入关键词进行搜索
  • 中间是三栏数据,第一栏分类、第二栏书签、第三栏书签描述
  • 最下层是日志框,可以隐藏

4. 基础框架搭建⚙️

4.1 安装

bash 复制代码
go get -u github.com/rivo/tview

4.2 参数设计

需求:

  1. 启动时可以输入关键词,查询书签
  2. 可以关闭日志栏
go 复制代码
// cmd/root.go:Execute
rootCmd.Flags().StringP("search", "s", "", "Search for a command")
rootCmd.Flags().BoolP("showlog", "l", false, "Show log panel")

4.3 绘制ui

4.3.1 设计结构体
go 复制代码
// internal/tui/app.go

type TuiView struct {
	app             *tview.Application
	searchBox       *tview.InputField
	categoryList    *tview.List
	bookmarkList    *tview.List
	descriptionView *tview.TextView
	logView         *tview.TextView
	main            *tview.Flex
	modal           *tview.Flex
	pages           *tview.Pages
	focusable       []tview.Primitive
	showLog         bool
	focusIndex      int
}
4.3.2 创建头部
go 复制代码
// internal/tui/ui.go

func (t *TuiView) CreateHeader() *tview.TextView {
	return tview.NewTextView().
		SetDynamicColors(true).
		SetTextAlign(tview.AlignCenter).
		SetText("[::b]AiBookMark[::-] [darkcyan] ← →:切换 ↑↓:导航 CTRL+F:搜索 /CTRL+R:重置 Q:退出")
}
4.3.3 创建主体
go 复制代码
// internal/tui/ui.go

func (t *TuiView) CreateCategoryList() *tview.List {
	t.categoryList = tview.NewList().ShowSecondaryText(true)
	t.categoryList.SetBorder(true).SetTitle(" 分类 ")
	t.categoryList.SetBorderColor(tcell.ColorWhite) // 添加默认边框颜色
	return t.categoryList
}

func (t *TuiView) CreateBookmarkList() *tview.List {
	t.bookmarkList = tview.NewList().ShowSecondaryText(true)
	t.bookmarkList.SetBorder(true).SetTitle(" 书签 ")
	t.bookmarkList.SetBorderColor(tcell.ColorWhite) // 添加默认边框颜色
	return t.bookmarkList
}

func (t *TuiView) CreateDescriptionView() *tview.TextView {
	t.descriptionView = tview.NewTextView().
		SetDynamicColors(true).
		SetScrollable(true).
		SetWrap(true)
	t.descriptionView.SetBorder(true).SetTitle(" 描述 ")
	t.descriptionView.SetBorderColor(tcell.ColorWhite) // 添加默认边框颜色
	return t.descriptionView
}


func (t *TuiView) CreateMain() *tview.Flex {
	// 菜单列表
	t.CreateCategoryList()
	// 书签列表
	t.CreateBookmarkList()
	// 书签描述
	t.CreateDescriptionView()

	// 创建布局
	mainFlex := tview.NewFlex()
	mainFlex.AddItem(t.categoryList, 35, 0, true)
	mainFlex.AddItem(tview.NewFlex().
		AddItem(t.bookmarkList, 0, 1, true).
		AddItem(t.descriptionView, 0, 2, false), 0, 1, false)
	return mainFlex
}
4.3.4 创建日志栏
go 复制代码
// internal/tui/ui.go

func (t *TuiView) CreateLogs() *tview.TextView {
	t.logView = tview.NewTextView().
		SetDynamicColors(true).
		SetScrollable(true).
		SetWrap(false)
	t.logView.SetBorder(true).SetTitle(" 日志 ")
	return t.logView
}
4.3.5 创建整体布局
go 复制代码
// internal/tui/ui.go

func (t *TuiView) CreateMainFlex() *tview.Flex {
	mainFlex := tview.NewFlex()
	mainFlex.SetDirection(tview.FlexRow)
	// Header
	mainFlex.AddItem(t.CreateHeader(), 3, 0, false)
	// 搜索框
	mainFlex.AddItem(t.CreateSearchBox(), 3, 0, false)
	// CategoryList
	mainFlex.AddItem(t.CreateMain(), 0, 1, false)
	if t.showLog {
		mainFlex.AddItem(t.CreateLogs(), 8, 10, false)
	}
	return mainFlex
}
4.3.6 创建启动函数
go 复制代码
// internal/tui/app.go
func (t *TuiView) Run(searchKeyWord string, showLog bool) {
	t.showLog = showLog
	// 初始化应用程序
	t.app = tview.NewApplication()
	// enable鼠标
	t.app.EnableMouse(false)
	// 创建mainFlex
	t.main = t.CreateMainFlex()
	// 初始化可聚焦组件列表
	t.focusable = []tview.Primitive{t.categoryList, t.bookmarkList, t.descriptionView}
	t.focusIndex = 0
	// 设置根节点
	t.app.SetRoot(t.main, true)
	// 设置焦点
	t.Focus(t.focusable[t.focusIndex])
	// 设置初始焦点组件的边框颜色
	if focusable, ok := t.focusable[t.focusIndex].(interface{ SetBorderColor(tcell.Color) }); ok {
		focusable.SetBorderColor(tcell.ColorSkyblue)
	}
	if err := t.app.Run(); err != nil {
		fmt.Println("TUI启动失败: " + err.Error())
	}
}
4.3.6 对接cobra命令行
go 复制代码
// internal/tui/app.go

// 获取搜索关键字
searchKeyword, _ := cmd.Flags().GetString("search")
// 是否显示日志
show, _ := cmd.Flags().GetBool("showlog")
tui := tui.TuiView{}
tui.Run(searchKeyword, show)

5.效果测试 ✅

运行

bash 复制代码
go run main.go

带日志启动

基本框架搭建完毕,后续就是从数据库中获取数据,渲染到终端上。


往期系列

相关推荐
I'm Jie20 小时前
Swagger UI 本地化部署,解决 FastAPI Swagger UI 依赖外部 CDN 加载失败问题
python·ui·fastapi·swagger·swagger ui
爱学习的程序媛21 小时前
【Web前端】优化Core Web Vitals提升用户体验
前端·ui·web·ux·用户体验
爱学习的程序媛21 小时前
【Web前端】前端用户体验优化全攻略
前端·ui·交互·web·ux·用户体验
紫丁香1 天前
Selenium自动化测试详解1
python·selenium·测试工具·ui
GISer_Jing1 天前
前端组件库——shadcn/ui:轻量、自由、可拥有,解锁前端组件库的AI时代未来
前端·人工智能·ui
一条GO1 天前
简单的 defer 也有可能写出BUG
go
用户580559502101 天前
深入理解 Go defer(下):编译器与runtime视角的实现原理
后端·go
tyung1 天前
用 zhenyi-base 做一个带网页的群聊 Demo
websocket·go
rjc_lihui1 天前
IntelliSense: 无法打开 源 文件 “ui_mainwindow.h“ demo\qtdemosrc\mainwindow
ui
AntBlack1 天前
Ant-Browser : 发布一个开源免费的指纹浏览器 ,欢迎体验
后端·架构·go