From 59f9c6de1818714c762cb3e6817287ab2f226cfd Mon Sep 17 00:00:00 2001 From: titor Date: Mon, 6 Apr 2026 05:18:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E6=A8=A1=E5=9D=976?= =?UTF-8?q?=20-=20TUI=E9=9B=86=E6=88=90=E7=BF=BB=E8=AF=91=20(Enter?= =?UTF-8?q?=E7=BF=BB=E8=AF=91/=E5=BC=82=E6=AD=A5=E6=89=A7=E8=A1=8C/?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E7=8A=B6=E6=80=81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- changelog.md | 15 ++++++----- internal/tui/app.go | 66 ++++++++++++++++++++++++++++++++++++++++++--- memory.md | 53 ++++++++++++++++++++++++++++++++++++ taolun.md | 39 +++++++++++++++++++++++++++ 4 files changed, 164 insertions(+), 9 deletions(-) diff --git a/changelog.md b/changelog.md index 9819dbe..af10564 100644 --- a/changelog.md +++ b/changelog.md @@ -30,8 +30,9 @@ - [x] 模块3: 翻译显示区 ✅ 已完成 - [x] 模块4: 状态栏/主题 ✅ 已完成 - [x] 模块5: 快捷键系统 ✅ 已完成 +- [x] 模块6: 集成翻译 ✅ 已完成 -## TUI界面实现计划 (v0.6.0) +## TUI界面实现计划 (v0.6.0) - 全部完成! | 步骤 | 模块 | 内容 | 状态 | |------|------|------|------| | 1 | TUI框架搭建 | bubbletea基础App结构、运行循环 | ✅ 已完成 | @@ -39,16 +40,16 @@ | 3 | 翻译显示区 | 结果展示、格式化、滚动 | ✅ 已完成 | | 4 | 状态栏/主题 | 底部状态栏、语言选择、主题配色 | ✅ 已完成 | | 5 | 快捷键系统 | 退出、清空、切换语言等 | ✅ 已完成 | -| 6 | 集成翻译 | 对接现有Translator、加载动画 | ⏳ 待实现 | +| 6 | 集成翻译 | 对接现有Translator、加载动画 | ✅ 已完成 | ## 待修复BUG - 无 ## 版本历史 -### 0.6.0 (2026-04-06) - TUI交互界面 (开发中) +### 0.6.0 (2026-04-06) - TUI交互界面 **类型**: 功能版本 -**状态**: 开发中 +**状态**: 已完成 **变更内容**: - ✅ 模块1: TUI框架搭建 - 添加bubbletea依赖,实现基础App结构 @@ -56,7 +57,7 @@ - ✅ 模块3: 翻译显示区 - 结果显示区域、样式定义 - ✅ 模块4: 状态栏/主题 - 底部状态栏、语言显示、配色完善 - ✅ 模块5: 快捷键系统 - Ctrl+L清空、Ctrl+T切换语言 -- ⏳ 模块6: 集成翻译 - 待实现 +- ✅ 模块6: 集成翻译 - Enter触发翻译、异步执行、加载状态、错误处理 **技术实现**: - 使用 `github.com/charmbracelet/bubbletea` v1.3.10 @@ -68,7 +69,9 @@ - [TUI界面模块拆分计划](taolun.md#2026-04-06-1000-版本-060---tui界面模块拆分计划) **下一步**: -- 实现模块6: 集成翻译 +- 测试TUI交互界面 +- 优化用户体验 +- 添加更多功能(如复制翻译结果) --- diff --git a/internal/tui/app.go b/internal/tui/app.go index 1404d9e..d22a91e 100644 --- a/internal/tui/app.go +++ b/internal/tui/app.go @@ -1,6 +1,8 @@ package tui import ( + "context" + "github.com/charmbracelet/bubbles/textinput" "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" @@ -13,8 +15,15 @@ type model struct { translator *translator.Translator textInput textinput.Model result string + errMsg string targetLang string langIndex int + loading bool +} + +type translateMsg struct { + result string + err error } var ( @@ -29,6 +38,9 @@ var ( resultStyle = lipgloss.NewStyle(). Foreground(lipgloss.Color("#98FB98")). Background(lipgloss.Color("#0D1B2A")) + errorStyle = lipgloss.NewStyle(). + Foreground(lipgloss.Color("#FF6B6B")). + Background(lipgloss.Color("#1A1A2E")) helpStyle = lipgloss.NewStyle(). Foreground(lipgloss.Color("#888888")) statusBarStyle = lipgloss.NewStyle(). @@ -40,6 +52,8 @@ var ( Bold(true) keyStyle = lipgloss.NewStyle(). Foreground(lipgloss.Color("#60A5FA")) + loadingStyle = lipgloss.NewStyle(). + Foreground(lipgloss.Color("#60A5FA")) ) var supportedLangs = []string{"zh-CN", "en-US", "ja", "ko", "zh-TW", "es", "fr", "de"} @@ -72,22 +86,45 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmd tea.Cmd switch msg := msg.(type) { + case translateMsg: + m.loading = false + if msg.err != nil { + m.errMsg = msg.err.Error() + m.result = "" + } else { + m.result = msg.result + m.errMsg = "" + } + return m, nil + case tea.KeyMsg: switch msg.Type { case tea.KeyEnter: - // 回车键处理,后续模块会添加翻译逻辑 + if m.loading { + return m, nil + } + text := m.textInput.Value() + if text == "" { + return m, nil + } + m.loading = true + m.errMsg = "" + return m, m.doTranslate(text, m.targetLang) + case tea.KeyCtrlC: return m, tea.Quit + case tea.KeyCtrlL: - // Ctrl+L: 清空输入和结果 m.textInput.SetValue("") m.result = "" + m.errMsg = "" return m, nil + case tea.KeyCtrlT: - // Ctrl+T: 切换语言 m.langIndex = (m.langIndex + 1) % len(supportedLangs) m.targetLang = supportedLangs[m.langIndex] return m, nil + case tea.KeyEsc: return m, tea.Quit } @@ -97,6 +134,23 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, cmd } +func (m model) doTranslate(text, toLang string) tea.Cmd { + return func() tea.Msg { + result, err := m.translator.Translate( + context.Background(), + text, + &translator.TranslateOptions{ + ToLang: toLang, + PromptName: "simple", + }, + ) + if err != nil { + return translateMsg{err: err} + } + return translateMsg{result: result.Translated} + } +} + func (m model) View() string { resultBox := m.renderResult() helpText := helpStyle.Render("\n " + @@ -116,6 +170,12 @@ func (m model) View() string { } func (m model) renderResult() string { + if m.loading { + return " " + loadingStyle.Render("正在翻译...") + "\n" + } + if m.errMsg != "" { + return " " + errorStyle.Render("错误: "+m.errMsg) + "\n" + } if m.result == "" { return " " + helpStyle.Render("翻译结果将显示在这里...") + "\n" } diff --git a/memory.md b/memory.md index 01fdf20..1f52116 100644 --- a/memory.md +++ b/memory.md @@ -643,4 +643,57 @@ func (m model) renderResult() string { } return " " + resultStyle.Render(m.result) + "\n" } + +### 异步命令和消息模式 +```go +// 定义自定义消息类型 +type translateMsg struct { + result string + err error +} + +// 异步执行函数 +func (m model) doTranslate(text string) tea.Cmd { + return func() tea.Msg { + result, err := translate(text) + if err != nil { + return translateMsg{err: err} + } + return translateMsg{result: result} + } +} + +// Update中处理消息 +func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case translateMsg: + if msg.err != nil { + m.errMsg = msg.err.Error() + } else { + m.result = msg.result + } + return m, nil + } + return m, nil +} +``` + +### 加载状态处理 +```go +type model struct { + loading bool + errMsg string +} + +// View中显示loading +func (m model) View() string { + if m.loading { + return "正在翻译..." + } + if m.errMsg != "" { + return "错误: " + m.errMsg + } + return m.result +} +``` ``` \ No newline at end of file diff --git a/taolun.md b/taolun.md index 86df6f6..332d5ac 100644 --- a/taolun.md +++ b/taolun.md @@ -543,5 +543,44 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { **下一步**: 实现模块6: 集成翻译 +**关联文档**: +- [changelog.md#0.6.0](changelog.md#060) + +--- + +### [2026-04-06 13:00] 版本 0.6.0 - 模块6: 集成翻译 (已完成) +**原因**: 将Translator集成到TUI,实现真正的翻译功能 +**分析**: +- 需要在Enter键时调用翻译API +- 需要异步执行避免阻塞UI +- 需要显示loading状态和错误处理 + +**解决方案**: +1. 添加translateMsg消息类型处理异步结果 +2. 添加loading和errMsg字段 +3. 实现doTranslate()函数执行异步翻译 +4. Update中处理translateMsg消息 +5. View中显示loading状态或错误信息 + +**技术实现**: +```go +type translateMsg struct { + result string + err error +} + +func (m model) doTranslate(text, toLang string) tea.Cmd { + return func() tea.Msg { + result, err := m.translator.Translate(...) + if err != nil { + return translateMsg{err: err} + } + return translateMsg{result: result.Translated} + } +} +``` + +**下一步**: 测试TUI界面、优化体验 + **关联文档**: - [changelog.md#0.6.0](changelog.md#060) \ No newline at end of file