Files
u-tabs/docs/02-技术文档/架构设计.md
绝尘 a027fe1703 新增: u-tabs 初始版本
Go TUI 项目启动器,基于 bubbletea v2 + lipgloss v2。
支持分组 Tab、多选启动、编号跳转、Windows Terminal 集成。
2026-05-16 21:01:03 +08:00

223 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# u-tabs 架构设计
> 最后更新2026-05-15 | 基于 u-tabs v0.3.0
## 1. 项目概述
u-tabs 是一个 TUI 工作空间启动器,用 Bubble Tea v2 实现。管理多个工作空间YAML 配置驱动),通过 Windows Terminal + Claude Code 标签页启动。
**技术栈**: Go 1.26 / BubbleTea v2 / LipGloss v2
## 2. 架构
```
main.go → Model (app.go)
├── 分组 Tab 栏
├── 左侧项目列表
├── 右侧详情面板
└── Enter → wt.exe → claude
```
## 3. 配置系统
### 3.1 加载优先级
```
~/.u-tabs/config.yaml → exe同目录/config.yaml → 内置默认值 (workspace.go)
```
### 3.2 YAML 结构
```yaml
groups:
- label: CORE # 分组标签,决定编号基数
desc: 核心业务
items:
- title: flux # 短名
prompt: 描述 # AI prompt
tech: 技术栈 # 精确到版本
deploy: 部署 # 服务器/端口/域名
dir: 目录路径 # 启动目录
```
### 3.3 编号规则
`GroupConfig.Base` 字段决定,若未设置默认从 0 开始。
### 3.4 数据转换
`Config.ToInternal()` 将 YAML 配置转为运行时结构,自动生成:
- `Index`: 全局索引 (0, 1, 2...)
- `N`: 编号 (base + item索引)
- `Group`: 继承父级 label
- `Dir`: `~` 展开为用户主目录
## 4. 数据模型
### 4.1 Workspace
```go
type Workspace struct {
Index int // 全局索引
N int // 编号
Title string // 短名
Prompt string // 描述
Tech string // 技术栈
Deploy string // 部署情况
Dir string // 目录路径
Group string // 分组标签
}
```
### 4.2 Group
```go
type Group struct {
Label string
Desc string
}
```
### 4.3 运行时索引
| 变量 | 类型 | 用途 |
|------|------|------|
| `Groups` | `[]Group` | 分组定义 |
| `AllWorkspaces` | `[]Workspace` | 全部工作空间 |
| `wsByNum` | `map[int]*Workspace` | 编号→Workspace O(1) 索引 |
## 5. 主模型 (app.go)
### 5.1 Model
```go
type Model struct {
activeGroup int // 当前分组索引
cursor int // 分组内光标
selected map[int]bool // 多选标记
inputBuf string // 数字快捷输入缓冲
width, height int
launched string // 启动提示
}
```
### 5.2 Update 消息路由
```
KeyPressMsg
├── q, ctrl+c → tea.Quit
├── tab, right, l → activeGroup++ → cursor=0
├── shift+tab, left, h → activeGroup--
├── 1, 2, 3, 4 → 跳转分组
├── up, k → cursor--
├── down, j → cursor++
├── Space → toggleMultiSelect
├── enter → inputBuf非空? launchByInput() : launchSelected()
├── c → copyCommand()
└── [0-9] → 追加到 inputBuf
```
### 5.3 View 渲染
```
View()
└── 启动器模式:
├─ 第1行: "u-tabs"标题 + 分组 Tab 栏
├─ 分隔线
├─ 左右布局 (JoinHorizontal):
│ ├── 左侧列表: 编号 + 标题 + 描述 (CJK安全截断)
│ └── 右侧详情: 目录/编号/描述/技术/部署/命令预览
├─ 输入缓冲提示
├─ 启动成功提示
└─ 帮助栏 (快捷键高亮)
```
### 5.4 CJK 安全截断
`truncateByWidth()` 按 rune 显示宽度截断,中文=2宽英文=1宽不会切断多字节字符
```go
func truncateByWidth(s string, maxW int) string {
w := 0
for i := 0; i < len(s); {
_, size := utf8.DecodeRuneInString(s[i:])
rw := runeWidth(rune(s[i]))
if w+rw > maxW { return s[:i] }
w += rw
i += size
}
return s
}
```
## 6. 启动逻辑
### 6.1 流程
```
用户按 Enter
buildLaunchScript(ws) → PS 脚本
encodePSCommand(script) → UTF-16LE → Base64
exec.Command("wt.exe", "-w", "0",
"-d", ws.Dir,
"--tabColor", randomColor,
"pwsh", "-NoExit", "-EncodedCommand", encoded).Start()
Windows Terminal 新标签页 → claude 交互模式
```
### 6.2 PS 脚本模板
```powershell
$Host.UI.RawUI.WindowTitle = "{Title}"
Write-Host "=== {Title} ===" -ForegroundColor Cyan
Write-Host "Prompt: {Prompt}" -ForegroundColor Yellow
cd "{Dir}"
claude --name "{Title}" --permission-mode bypassPermissions
```
### 6.3 UTF-16LE 编码
```go
func encodePSCommand(script string) string {
u16 := utf16.Encode([]rune(script))
b := make([]byte, len(u16)*2)
for i, r := range u16 {
b[i*2] = byte(r)
b[i*2+1] = byte(r >> 8)
}
return base64.StdEncoding.EncodeToString(b)
}
```
## 7. 样式系统 (Tokyo Night 主题)
### 7.1 色板
| 常量 | Hex | 用途 |
|------|-----|------|
| BgDark | #1a1b26 | 深底色 |
| BgPanel | #292e42 | 面板/边框/分隔线 |
| Dim | #565f89 | 次要文字 |
| Fg | #a9b1d6 | 正文 |
| Bright | #c0caf5 | 高亮文字 |
| Accent | #7aa2f7 | 主强调 (蓝色) |
| Success | #9ece6a | 绿色 (部署/标记) |
| Warning | #e0af68 | 黄色 (输入提示) |
| Cyan | #7dcfff | 青色 (编号/详情) |
| Purple | #bb9af7 | 紫色 (选中行) |
| Red | #f7768e | 红色 (CORE分组) |
### 7.2 分组颜色
| 分组 | Hex |
|------|-----|
| CORE | #f7768e |
| LAB | #9ece6a |
| TOOLS | #e0af68 |
| ME | #bb9af7 |
| TEMP | #7dcfff |