Skip to content

重构(编辑器):re editor 库#280

Open
XiaoBuHaly wants to merge 9 commits intoChevey339:masterfrom
XiaoBuHaly:refactor/re-editor-input
Open

重构(编辑器):re editor 库#280
XiaoBuHaly wants to merge 9 commits intoChevey339:masterfrom
XiaoBuHaly:refactor/re-editor-input

Conversation

@XiaoBuHaly
Copy link
Copy Markdown
Contributor

@XiaoBuHaly XiaoBuHaly commented Jan 24, 2026

refactor(editor): 统一文本编辑迁移至 re_editor,抽取共享组件与防抖保存

共享 PlainTextCodeEditor · Markdown 预览加固 · 多场景迁移至 CodeLineEditingController · BREAKING

Fixes #186


PR 类型
Refactor
破坏性变更
文件数
25
代码增删
▰▰▰▰▰▱▱▱▱▱
$$\color{green} \text{+1942}$$ $$\color{red} \text{-1717}$$


核心目标

本次 PR 解决四类问题:

1 重复与不一致 - 多处文本编辑分别使用 TextField / 裸 CodeEditor,样式、快捷键与同步逻辑分散;本次抽取共享 PlainTextCodeEditor、高度约束与 Controller 工具,统一编辑体验与维护入口。

2 稳定性与数据安全 - Markdown 预览模板缺少兜底,媒体替换对异常正则捕获不够稳健;本次补充 fallback HTML 与 null-safe 处理,避免预览/流式渲染被中断。

3 性能与保存抖动 - 翻译流式输出与桌面设置场景存在频繁刷新/写盘;本次引入缓冲 flush 与 debounce 保存,降低 UI 抖动和配置写入噪声。

4 聊天输入迁移(BREAKING) - 聊天输入体系从 TextEditingController 迁移到 CodeLineEditingController,统一换行、粘贴、IME composing 与快捷键处理;依赖旧 Controller 类型的调用方需要适配。

架构设计总览

flowchart LR
  subgraph Shared["共享层"]
    Editor["PlainTextCodeEditor\n(shared widget)"] --> Style["buildPlainTextCodeEditorStyle()"]
    Editor --> Utils["CodeLineEditingControllerX\nsetTextSafely()"]
    Editor --> Height["input_height_constraints\ncomputeInputMaxHeight()"]
  end

  subgraph Usage["使用场景"]
    Translate["翻译页\nmobile + desktop"] --> Editor
    Model["模型配置\nprompt sheets / OCR prompt"] --> Editor
    Instruction["指令注入\nprompt editors"] --> Editor
    MsgEdit["消息编辑\npage + sheet + dialog"] --> Editor
    Settings["桌面设置\nproviders pane"] --> Editor
    ChatInput["聊天输入栏\nBREAKING"] --> Utils
  end

  subgraph Markdown["Markdown 配套"]
    Preview["markdown_preview_html\nfallback template"] --> Render["WebView preview"]
    Sanitize["markdown_media_sanitizer\nnull-safe group"] --> Render
  end
Loading

变更详情漫游

共享编辑器与工具

文件 变更要点 增删
new
plain_text_code_editor.dart
lib/shared/widgets/
统一 PlainTextCodeEditor
  • 封装 CodeEditor 的通用配置:NonCodeChunkAnalyzer、隐藏 indicator、统一主题样式
  • 支持按需覆写字体、行高、选区色、提示文本透明度、padding 等参数
+140
new
re_editor_utils.dart
lib/utils/
setTextSafely:统一安全同步
  • 统一 StringCodeLineEditingValue 的转换与 selection 定位
  • 默认跳过 IME composing 阶段,避免打断组合输入
  • 异常时回退到直接设置 controller.text,降低同步失败导致的数据丢失风险
+58
new
input_height_constraints.dart
lib/shared/widgets/
统一大文本输入高度上限计算,综合考虑 viewInsets、预留区域与最小高度,减少弹层/编辑器溢出。 +62

小计: +260

Markdown 预览与媒体安全

文件 变更要点 增删
fix
markdown_preview_html.dart
markdown_media_sanitizer.dart
  • 预览模板加载失败时回退到内置 fallback HTML,避免直接崩溃
  • 主题 token 同步到 surfaceContainerHighest,与新配色体系更一致
  • 行内 base64 / 本地媒体替换改为 null-safe 捕获处理,异常输入保留原片段而不是中断渲染
+87
-21

页面迁移(翻译 / 模型 / 指令 / 消息编辑 / 设置)

模块 涉及文件 变更要点 增删
translate translate_page.dart
desktop_translate_page.dart
迁移到共享编辑器;流式输出增加缓冲、定时 flush 与 runId 防回填,减少 chunk 级频繁刷新带来的 UI 抖动。 +252
-217
model default_model_page.dart
default_model_pane.dart
ocr_prompt_sheet.dart
移动端/通用 Prompt Sheet 与 OCR Prompt 迁移至 PlainTextCodeEditor;桌面默认模型 pane 保留现有 TextField 交互,但接入统一高度约束,避免大文本输入区域溢出。 +450
-559
instruction instruction_injection_page.dart
instruction_injection_pane.dart
指令 Prompt 编辑迁移至共享编辑器,并通过 setTextSafely() 统一同步逻辑,减少 composing/selection 被打断的风险。 +161
-44
message edit message_edit_page.dart
message_edit_sheet.dart
message_edit_dialog.dart
消息编辑页、Sheet、桌面对话框统一迁移到共享编辑器,并复用 setTextSafely() 处理文本同步。 +92
-97
settings desktop_settings_page.dart
providers_pane.dart
Service Account JSON 编辑迁移到 CodeLineEditingController + PlainTextCodeEditor,引入 debounce(400ms)、失焦保存与 dispose flush。desktop_settings_page.dart 仅补齐接入所需依赖与结构衔接。 +99
-38

聊天输入迁移(BREAKING)

破坏性变更说明:

输入栏 Controller 类型升级为 CodeLineEditingController,涉及以下 API:
  • ChatInputBar.controllerTextEditingController? -> CodeLineEditingController?
  • ChatInputSection.inputControllerTextEditingController -> CodeLineEditingController
  • HomePageController.inputControllerTextEditingController -> CodeLineEditingController
文件 变更要点 增删
chat_input_bar.dart
chat_input_section.dart
home_page.dart
home_page_controller.dart
  • 输入区切换到 PlainTextCodeEditor,统一短文本编辑模式
  • 使用 replaceSelection()applyNewLine()makeCursorVisible() 等 API 替代原有 TextField 逻辑
  • 将快捷键与 IME composing 保护集中到 _ComposingAwareNewLineAction 等路径中处理
  • 粘贴文本、快捷短语插入等场景改为基于 CodeLineEditingController 的原生编辑能力
+535
-737

依赖与杂项

文件 变更要点 增删
pubspec.yaml
app_directories.dart
avatar_cache.dart
sandbox_path_resolver.dart
  • 新增依赖:re_editor: ^0.8.0
  • 补充少量工具层兼容与清理,整体无额外功能面扩张
+6
-4

行为变化对比

场景 变更前 变更后
多场景文本编辑 各页面自建 TextField / CodeEditor,风格与行为不一 统一使用 PlainTextCodeEditor + 共享样式、高度约束与同步工具
翻译流式输出 chunk 级频繁刷新,容易造成 UI 抖动和旧流回填 缓冲 + 定时 flush + runId 防回填,降低 UI churn
桌面设置 SA JSON 保存 每次输入都可能触发写入,存在卡顿/乱序风险 debounce(400ms) + 失焦保存 + dispose flush,减少写盘次数
Markdown 预览 模板缺失或异常媒体片段可能导致预览失败 fallback 模板兜底;sanitizer null-safe 处理异常输入
聊天输入 基于 TextField / TextEditingController 的分散逻辑 统一到 CodeLineEditingController,换行、粘贴、IME 保护路径集中处理

风险控制与回滚

风险点 应对措施 回滚方案
聊天输入 BREAKING 在标题、正文和审阅指引中明确标注 BREAKING;改动集中在输入链路,方便单独 review。 优先单独回滚 refactor(chat-input)! 相关提交,必要时整体回滚本 PR。
防抖导致“未保存”感 关键场景保留失焦保存与 dispose flush;后续如有需要可增加“保存中”提示。 可调小 debounce 间隔,或回退为即时保存。
re_editor 行为差异 通过共享组件统一封装样式、快捷键和 composing 策略,降低各页面自行分叉实现的风险。 可按场景局部回退到旧编辑器实现,而不必整体回滚所有改动。
Markdown fallback 行为差异 仅在模板加载失败时启用 fallback,不影响正常模板路径。 如 fallback 样式不满足预期,可单独回退对应修复提交。

审阅指引

建议重点审阅以下文件:

优先级 文件 原因
P0 plain_text_code_editor.dart 共享编辑器入口,影响所有迁移场景
P0 re_editor_utils.dart setTextSafely() 与 IME 保护是同步正确性的核心
P0 chat_input_bar.dart BREAKING 改动核心,覆盖换行、粘贴、快捷键、输入框布局
P1 translate_page.dart / desktop_translate_page.dart 流式输出缓冲、flush 与 runId 防回填
P1 providers_pane.dart SA JSON debounce 保存、失焦保存、dispose flush
P2 markdown_preview_html.dart / markdown_media_sanitizer.dart fallback 模板与媒体替换安全性

验证清单

构建与静态检查
flutter pub get
flutter analyze

预期:无新增错误;核心路径可运行

手动验证 - 编辑与保存
步骤 操作 预期结果
1 在翻译页、模型 Prompt、指令注入、消息编辑中编辑内容 使用统一编辑器样式,输入流畅
2 翻译流式输出过程中多次点击“停止/重新翻译” 不会出现旧内容回填
3 桌面设置 SA JSON 连续输入后停顿 约 400ms 后保存一次;失焦和退出时也会保存
手动验证 - 聊天输入(BREAKING 路径)
步骤 操作 预期结果
1 输入、换行、发送(Enter / Shift / Ctrl 组合) 行为与设置项一致,IME composing 不被意外打断
2 粘贴文本/图片、附件、快捷短语插入 正常工作,不出现 selection 错乱或内容丢失
3 切换移动端/桌面布局,展开与收起输入栏 高度变化自然,光标仍可见

@XiaoBuHaly XiaoBuHaly force-pushed the refactor/re-editor-input branch 4 times, most recently from 28c0766 to 0316799 Compare February 5, 2026 11:26
@XiaoBuHaly XiaoBuHaly marked this pull request as ready for review February 6, 2026 01:48
@XiaoBuHaly XiaoBuHaly changed the title refactor/re editor input 重构(编辑器):re editor 库 Feb 6, 2026
@XiaoBuHaly XiaoBuHaly force-pushed the refactor/re-editor-input branch from 0316799 to 95e49b1 Compare February 7, 2026 09:31
@XiaoBuHaly
Copy link
Copy Markdown
Contributor Author

@Chevey339 找时间可以审一下谢谢

@XiaoBuHaly XiaoBuHaly force-pushed the refactor/re-editor-input branch from 95e49b1 to 0c0cc5c Compare February 8, 2026 12:16
@XiaoBuHaly XiaoBuHaly force-pushed the refactor/re-editor-input branch from 0c0cc5c to 25c6855 Compare March 9, 2026 21:08
@XiaoBuHaly
Copy link
Copy Markdown
Contributor Author

冲突处理好了。

@Chevey339
Copy link
Copy Markdown
Owner

AI-assisted review:

  1. lib/features/home/widgets/chat_input_bar.dart
    IME 组合输入(中文/日文等)下,Enter 现在有回归风险。CodeShortcutNewLineIntent 被自定义 Action 接管后,composing 状态下虽然没有执行发送/换行,但按键仍可能被 Shortcuts/Actions 吃掉,导致无法稳定用回车确认候选词。旧实现这里是放行给 IME的。

  2. lib/features/home/widgets/chat_input_bar.dart
    iOS 触屏长按“粘贴图片/截图到聊天输入框”这条现有路径看起来被删掉了。现在 _handlePasteFromClipboard() 主要只在硬件键盘Cmd/Ctrl+V 路径可达;原来用于 iOS 的 selection toolbar 逻辑已经移除,迁移到 re_editor 后长按粘贴大概率只剩纯文本paste。

  3. lib/desktop/setting/providers_pane.dart
    Service Account JSON 这里改成 debounce 保存后,存在“输入后 400ms 内如果页面发生 rebuild,刚输入内容被旧值回灌覆盖”的窗口。原因是 build 里仍然会先用持久化配置反向同步 controller,而保存不是即时的。这个会导致用户刚编辑的 JSON 偶发丢失。

  4. lib/features/home/widgets/chat_input_bar.dart
    键盘快捷键行为有变化:

  • tablet 外接键盘现在不再走 desktopSendShortcut,而是走 mobile 分支,和之前语义不一致;
  • activator 只注册了 enter,没有 numpadEnter,数字小键盘回车不会触发原有发送/换行逻辑。
  1. lib/desktop/message_edit_dialog.dart
    lib/features/chat/widgets/message_edit_sheet.dart
    这两个入口现在对空内容是静默 return,用户点“保存 / 保存并发送”会像“按钮没反应”。而移动message_edit_page 仍允许保存空文本,三个入口行为不一致。

  2. 建议提交前统一跑一次格式化,减少后续 review 噪音。

@XiaoBuHaly
Copy link
Copy Markdown
Contributor Author

XiaoBuHaly commented Mar 13, 2026

@Chevey339

1977a83 提交说明
  1. lib/features/home/widgets/chat_input_bar.dart
    已修复。这里保留了 CodeShortcutNewLineIntent 的自定义处理,但在 IME composing 状态下不再继续消费 Enter,会放行给输入法确认候选词;非 composing 状态下仍按原有发送/换行逻辑执行,避免中文/日文输入回归。

  2. lib/features/home/widgets/chat_input_bar.dart
    已修复。迁移到 re_editor 后,我在 PlainTextCodeEditor 包装层补充了 toolbarController 透传,并在聊天输入框接入了移动端 selection toolbar。现在 iOS 触屏长按菜单里的“粘贴”会走 _handlePasteFromClipboard(),图片/截图粘贴链路重新可达,不再只剩纯文本粘贴。

  3. lib/desktop/setting/providers_pane.dart
    已修复。Service Account JSON 的同步逻辑调整为区分“已持久化值”和“本地待保存值”:当 debounce 尚未落盘或本地存在 pending changes 时,不再在 build() 里用配置旧值反向覆盖 _saJsonCtrl;只有保存完成后才更新 persisted 标记,避免刚输入内容被旧值回灌覆盖。

  4. lib/features/home/widgets/chat_input_bar.dart
    已修复。

    • tablet 外接键盘现在恢复按 desktop shortcut 语义处理,不再落到 mobile 分支;
    • 同时补齐了 numpadEnter,现在普通回车、Shift+EnterCtrl/Cmd+Enter 的小键盘回车分支都会正常触发对应发送/换行逻辑。
  5. lib/desktop/message_edit_dialog.dart
    lib/features/chat/widgets/message_edit_sheet.dart
    已修复。这里不再对空内容静默 return,现在已经和移动端 message_edit_page 对齐,统一允许保存空文本,避免用户点击“保存 / 保存并发送”时出现“按钮没反应”的体验不一致问题。

  6. 提交前统一跑一次格式化,减少后续 review 噪音。
    已处理。相关文件已经统一执行格式化,并做了局部检查。

@XiaoBuHaly XiaoBuHaly force-pushed the refactor/re-editor-input branch from fec6436 to 7b28c7e Compare March 18, 2026 04:52
Introduce shared building blocks for the re_editor migration:
- Add PlainTextCodeEditor wrapper and theme-based style builder
- Add CodeLineEditingController.setTextSafely() helper (IME-safe)
- Add input height constraints helper for large text inputs

Also include small supporting cleanups in utils.
- Add fallback HTML template and catch asset load failures in markdown preview
- Make base64 image sanitizer regex group access null-safe to avoid crashes
- Replace TextField/TextEditingController with CodeLineEditingController
  and PlainTextCodeEditor in translate pages (mobile + desktop)
- Buffer streaming output and flush on a short timer to reduce UI churn
- Track runId to prevent stale stream chunks from overwriting new runs
- Migrate model prompt editors to CodeLineEditingController + PlainTextCodeEditor
- Apply shared input height constraints for large prompt fields
- Reduce duplicated CodeEditor configuration across sheets/dialogs
- Migrate instruction injection prompt editors to CodeLineEditingController
  and PlainTextCodeEditor (mobile + desktop)
- Reuse shared input height constraints and safe controller text sync
- Migrate message editing UI (page/sheet/desktop dialog) to CodeLineEditingController
- Replace hand-rolled text syncing with setTextSafely() to avoid IME issues
- Migrate Service Account JSON editor to PlainTextCodeEditor
- Sync CodeLineEditingController content safely (IME-aware)
- Debounce config writes (400ms) and flush on blur/dispose
Migrate the chat input stack from TextField/TextEditingController to
re_editor (CodeLineEditingController + PlainTextCodeEditor) and unify
shortcut handling.

BREAKING CHANGE: Chat input controllers are now CodeLineEditingController.
External code must migrate:
- ChatInputBar.controller (TextEditingController? -> CodeLineEditingController?)
- ChatInputSection.inputController (TextEditingController -> CodeLineEditingController)
- HomePageController.inputController (TextEditingController -> CodeLineEditingController)
Restore IME-safe enter handling, touch paste access, and pending JSON edits after the re_editor migration. Also align empty-message saves across edit surfaces.
@XiaoBuHaly XiaoBuHaly force-pushed the refactor/re-editor-input branch from 7b28c7e to 1977a83 Compare March 25, 2026 16:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

输入框超级卡

2 participants