输入框
Hunea 里用户使用频率最高的,是输入框(在 Hunea 内部叫 composer)。其实其他产品也是如此。
它不是「底部固定、输入内容多了就在框里滚动」的那种输入区,而是和上方 transcript 一起,排在同一份可滚动文档里。你多写几行,它会跟着往下延伸;哪怕占满视口时,也可以和整份文档一起滚动,而不是在输入框内部再开一层滚动。这点和 前言 里讲的 altscreen / 主文档布局是一致的。
空的时候会看到类似 Enter to send Prompt 的占位提示(这个占位提示未来也会进行优化哦)。提示符样式会随 user_input_style 变化(cx / cc / ms),但用法一样:在这里写草稿、插入引用、回填历史,然后发出去。
效果简要预览:

在 TUI 中获得与平时使用其他软件一致的体验。
输入框的功能设计,我在 26 年初,也就是前言部分提到的刚开始尝试用 go 做的时候,就已经想的差不多了。
其实也没有什么特别的原因,就是纯觉得这样好用不少。
我个人有时候会写不少的提示词,或者包括一些笔记什么的。我知道可以先打好草稿,然后复制粘贴,或者放在某处,让 AI 自己调用工具去阅读。或者用快捷键使用外部编辑器比如 vim 或者 nvim 编辑,然后保存好的……
但是我大部分情况下就是喜欢在输入框中写东西。然后我用换行也多,因为我要排一下版(说不定排一下版 AI 理解更舒服呢是不是哈哈?)。所以一不小心就会输入超过十行的内容。
而碰到那种只能用键盘方向键移动光标的,或者那种固定输入框高度然后内部滚动的,还有更让我不舒服的,就是这两个结合起来的同时,我才写了几十行,就在内部移动卡顿的不得了要卡死的!!!甚至还不能启用外部编辑器编辑的!!!我就不说是哪个了。
总之体验非常糟糕。
所以输入框这部分我在做的时候还是尽可能进行了优化的,就是为了体验感更好。毕竟我想做的产品是给人用的,所以我觉得很有必要。
不过也需要见谅的是,限于精力,我也不可能做的十全十美。所以也希望能够多理解和包容。以后如果碰到了类似的情况,会继续打磨的。
比如一个常见的示例就是,我复制了几千行的日志进行粘贴的时候,因为当前输入框的无界设计,会直接将这些内容展示。那么就不便于我们进行提示词的撰写,因为内容太多,翻阅起来也比较麻烦(这里暂不考虑新建一个文件将日志放进去的场景)。
所以后续会考虑实现一个可选的功能,或者,是一种渐进式的设计,就是对于长内容粘贴,第一次粘贴的话是会变成一个"缩写"的标记。表示这里粘贴了多少行或者多少字的内容。这样的占位设计也是很值得借鉴的。
如果需要展开的话,可以考虑在同位置再次粘贴同样的内容,或者,可以进行点击亦或是其他的操作进行展开。
总之这个部分的设计还是有很多可以优化的地方的~
发送与换行
默认语义:
哈哈,这么多换行的方式!这也是兼容性考虑了!选择一个自己喜欢的就可以了
如果你更习惯「回车换行、组合键发送」,可以把 swap_enter_and_send 设为 true:此时 Enter 改成换行,Shift + Enter / Ctrl + J 改成发送。Alt + Enter / Ctrl + M 始终是换行,不受这项交换影响。
发送前会做几道检查:
- 草稿去掉空白后为空 → 不发送
- 还没选好模型 → toast 提示先配置模型
- 当前已有一轮对话在跑 → toast 提示请求已在进行
- 选中的 provider 不可用、或 OpenAI 兼容端点缺
base_url→ 同样拦住并提示
过了这些检查,草稿会作为用户消息进 transcript,composer 清空,并真正发起这一轮对话。
文本编辑
编辑键贴近常见的 readline / shell 习惯:
几点实现上的取舍,用起来会直接感觉到:
- Undo 是按 grapheme 分组的。连续输入同一个 emoji / 组合字符时,不会拆成半个字符才能撤回来;
Ctrl + G开外部编辑、发送等会成为 undo 边界。 - Undo 深度由
composer_undo_limit控制(默认 50,范围 1..200),只作用在当前进程里,不写进会话。 - Kill buffer 只保留最近一次
Ctrl + K/ 词删除等 kill 结果;Ctrl + Y不是完整的系统剪贴板。 - 草稿里若已有完成态选区,再敲普通字符、粘贴、换行、删除类按键时,会先替换/删掉选区,而不是在旁边另插一段。
粘贴走 bracketed paste:大段文本一次进来,换行会规范化(\r\n / 单独的 \r 都会收成 \n),同样支持「有选区就替换选区」。
Ctrl + C 在输入框已有草稿时,默认会先清空草稿(ctrl_c_clears_input = true),而不是直接走退出确认;空输入时仍是退出确认那套。清空时,纯文本草稿还会记进消息历史,方便后面回填;带图片附件的草稿则不会硬塞进那份文本历史。
鼠标
主界面默认是应用捕获鼠标(见 前言),所以 composer 上可以:
- 单击:把光标落到对应字符位置(空草稿时没有可点内容,点了也不会硬定位)
- 拖拽:在输入内容上拉出选区;有选区后,键盘输入 / 粘贴 / 删除会按「替换选区」处理
- 中键:复制当前屏幕选区(和 transcript 上的中键复制是同一套选区路径)
这样的实现可以让我们在输入的时候更自然。尽量不用借助外部的工具来完成长提示词的编辑。
外部编辑器
长草稿不想一直在 TUI 里改时,按 Ctrl + G 会把当前内容丢进临时文件,挂起 TUI,打开外部编辑器;保存退出后再回写草稿。
- 编辑器命令由
external_editor配置;不配则依次尝试VISUAL、EDITOR和平台常见编辑器 - GUI 编辑器(VS Code / Cursor / Zed / Sublime 等)需要带「等关闭再返回」的参数,例如
["code", "--wait"],否则 Hunea 会在编辑器刚起来时就回到 TUI - 草稿变多行时,状态区可能短暂提示
ctrl+g to edit in …;可用show_external_editor_helper = false关掉 - 外部编辑器回写是一次可撤销的整段替换:
Ctrl + Z能回到打开编辑器之前的草稿
前缀补全与附件
这个部分未来会进行优化,因为触发符号有些多,不利于上手和使用
未来优化后这里的内容也会更新的
composer 里有几类「打前缀就出浮窗」的能力,都锚在光标附近的 token 上,而不是另开一套命令行:
@ 文件、skill 与图片
@是统一 mention:默认 All 档同时搜索文件与 skill,←/→在 All / Files / Skills 三档间切换,Tab循环。- 普通文件:插入的是路径引用(例如
@src/main.rs)。TUI 不会在发送时把文件内容展开进 prompt;需要读内容时,模型应再走read一类工具。这样用户指令和文件快照不会混在一起(也许会调整,但是当前的设计应该是合理的)。 - 图片(当前支持 png / jpeg / gif / webp):选中后会在草稿里变成图片占位标签,并作为结构化附件一起发送(需要注意:使用的模型需要支持多模态识图能力,否则会报错)。
- 选中 skill 会建立结构化绑定:发送时按绑定展开 skill 正文,会话里会留下
@skill名可见标记。 - 浮窗高度由
file_picker_popup_height控制(默认 9 行);宽度铺满终端,垂直方向以@位置为锚,空间不够会自动翻转到另一侧。
#
选中后会把当前 token 换成可读名称,并在消息里带上对应绑定。之后发送时,runtime 能区分「这是用户正文」和「这是挂上的 custom prompt」。skill 的绑定走 @ mention(见上)。
/ 斜杠菜单
只有输入框内容整体落在「斜杠命令查询」形态时才会出菜单(空输入后键入 /,再继续过滤)。输入框里已经写了一大段正文时,中间再敲 / 不会突然弹出整份菜单,这点和 斜杠菜单 一致。
历史回填
composer 上有两条「把以前写过的东西再拿回来」的路径,侧重点不同:
- 盲回填(Up / Down)
在适合的边界条件下(常见是空草稿,或光标落在整段草稿的首尾边界),↑/↓会在本地 + 已持久化的消息历史里前后翻,把旧文本直接填回输入框。
草稿已经多行、光标在中间时,上下键优先在草稿内部移动,而不会误触发历史翻页。 - 消息历史面板(
Ctrl + R//resend)
打开全屏/面板式的历史列表,适合「我想搜一下、看一眼再决定回填哪条」。
全局历史条数上限由message_history_limit控制(默认 100)。
和状态行、样式的关系
输入框下方可以挂状态行(status_line / status_line_2),用来显示分支、目录、当前模型、吞吐、首 token 延迟、上下文已用/剩余百分比等。没配置、或当前一项都拿不到内容时,状态行会直接隐藏,不会空占一行。
user_input_style 只影响「输入中 / 发送后用户消息」的视觉框和着色,不改变发送、补全、鼠标这些交互语义。
相关配置速查
都在 [tui] 下,改完需重启才生效:
综合来讲,Hunea 的 composer 想解决的是「在终端里也能舒服地写长输入」:无界增高、鼠标可点可选、外部编辑器可逃、历史可回填、@/#// 就地补全,同时尽量不把文件内容偷偷塞进 prompt。