TUI 输入法组件(term-terminal)
term-ime 的终端层(term-terminal 库)把「输入法怎么在 TUI 里展示」抽成了可复用组件:候选栏、状态栏、设置面板。它们不依赖 term-ime 应用本体,任何 TUI 程序都能拿来渲染中文输入界面。
组件清单
候选栏 Renderer::render_candidates
void render_candidates(const std::vector<Candidate>& candidates,
size_t selected,
const std::string& buffer,
const std::string& mode = "EN",
int max_items = 9,
bool page_prev = false,
bool page_next = false);
在终端最后一行绘制候选栏(mode + 拼音串 + 数字编号候选)。核心契约:
- 按宽度自适应:只显示能完整放下的候选,放不下的不显示;
max_items是上限,窄终端自动少显示 - 显示的集合 = 可选的集合:显示与
select()的索引严格对齐,不会出现"显示了却选不中" - 翻页提示器:
page_prev/page_next为真时画‹/›,分别贴在第一个候选前面和最后一个候选后面 (候选两侧,不是行尾——右端对齐的箭头隔着一排 filler 看不出属于候选)。两侧是常驻槽位: 没有可翻的方向时那一列留白,候选词不会因箭头出现/消失而左右平移,宽度预算也是常数而不是 「按 flags 反推」的定点。ui::page_hint_prev_text()/page_hint_next_text()同时是「画什么」和 「留几列」的唯一来源(page_hint_width()= 两者之和 = 2),调用方在切窗口时按同一个函数预留, 所以箭头既不会把这行挤出终端宽度,也不会因预留而少画一个已经切进窗口的候选 - 去重重绘:IME 空闲时连续绘制是 no-op(有
BAR_FORCE_REDRAW_EVERY兜底),避免 shell 输出驱动的高频重绘刷屏
状态栏与滚动区 update_scroll_region / redraw_shell
update_scroll_region():把可滚动区限定为rows-1,状态栏独占最后一行;resize 后必须调用redraw_shell(screen):全屏覆盖(如设置面板)关闭后,从Screen网格恢复 shell 视图- 状态栏契约:任何
ESC[2J/resize 清掉最后一行后,下一次绘制必须强制重画(last_bar_sig_失效),不会留下空白状态栏
设置面板 ui::SettingsState
// 面板状态:items 是行列表,focus_index 是焦点行;on_change/on_close 是回调
struct SettingsState {
bool visible;
int focus_index;
std::vector<SettingsItem> items; // label/key/options/selected_index
std::function<void(const std::string&, const std::string&)> on_change;
std::function<void()> on_close;
};
Element SettingsPanel(SettingsState& state); // 渲染(ftxui)
bool settings_handle_key(SettingsState& state, int key); // 键盘处理(jk/↑↓ 移动、hl/←→ 改值)
void settings_init(SettingsState& state, const AppConfig& config);
void settings_apply(SettingsState& state, AppConfig& config);
面板是全屏覆盖层,打开时保存 shell 视图、关闭时 redraw_shell 恢复。模糊音 5 组、候选数量、界面语言都是面板里的行。
与 IME 引擎的组合
term-terminal 直接依赖 term-ime-lib:Candidate / ImeMode 类型来自引擎层,渲染层只管画。典型用法:
// 输入:IME 消费按键后取状态渲染
if (ime.input(key)) {
renderer.render_candidates(ime.candidates(), /*selected=*/0, ime.buffer(), "拼", 9);
} else {
// 非 IME 按键:正常转发
}
渲染能力
- SGR 颜色:16 色、256 色(
38;5)、24bit 真彩(38;2),前景/背景/加亮/反显 - ED/EL 擦除:清屏、清行各 mode
- CJK 宽字符正确对齐:两格宽度按续格标记,重绘/擦除不会拆出半字残影
- 完整 VT/ANSI 解析:CUP/HVP 光标定位、参数上限防护、Tab 制表位
构建与链接
target_link_libraries(your_tui_app PRIVATE term-terminal)
依赖树:term-terminal → term-ime-lib → librime / utf8proc,全部静态。