Terminal core (src/core, QtCore only, headless testable): - VT100/xterm parser: CSI/OSC/DCS, SGR 256/truecolor, scroll regions, insert/delete, DEC special graphics, alternate screen - cell grid with 5000 line scrollback, CJK wide chars, combining marks - xterm 256 color palette Terminal widget (src/term): - QPainter renderer with run batching, wide char clipping, cursor blink - mouse selection (char/word/line), auto copy, middle click paste - full key encoding: arrows + DECCKM, F1-F12, modifiers, ctrl/alt - IME support via inputMethodEvent Transports (src/session): - SSH through the system OpenSSH client on a forkpty pseudo terminal, so agent, ProxyJump, known_hosts and 2FA keep working - Telnet with IAC negotiation (NAWS, ECHO, SGA) - Serial via QSerialPort UI (src/ui): - tabbed main window, session dialog with saved profiles - dark violet theme, CLI targets (user@host:port, telnet://, serial:) Tests: - tests/test_core: escape sequence and layout assertions - tests/test_widget: offscreen render checks and key encoding
51 lines
2.8 KiB
Markdown
51 lines
2.8 KiB
Markdown
# ADR-0001:技术选型
|
||
|
||
- 状态:已采纳(2026-10)
|
||
- 替代:早先的「Tauri + Rust sidecar」提案
|
||
|
||
## 结论
|
||
|
||
| 层 | 决定 |
|
||
| --- | --- |
|
||
| UI 框架 | Qt 5.15 + qmake(Widgets,不用 QML) |
|
||
| 终端渲染 | 自研 `QWidget` + `QPainter`(Konsole 路线),抽象出 `Screen`/`VtParser` |
|
||
| SSH | 系统 `ssh` + `forkpty`,不自研协议 |
|
||
| Telnet | 自研 IAC 协商,`QTcpSocket` |
|
||
| 串口 | `QSerialPort` |
|
||
| 范围 | 只做 SSH / Telnet / 串口 |
|
||
|
||
## 背景
|
||
|
||
目标是用开源软件替代 MobaXterm。最初的方案是 Tauri + Rust sidecar(见下文对比),后来范围收敛到三个协议、并且明确只用 Qt 5,于是重新评估。
|
||
|
||
## 决策依据
|
||
|
||
**1. 终端渲染不是"画字"**
|
||
真正的难点是行内多属性分段、CJK 宽字符对齐、IME 候选窗定位、大流量下的帧合并。Qt 提供了 HarfBuzz 整形、字体回退、彩色 emoji、`inputMethodEvent`,前三点不用自己造。剩余工作量集中在 `Screen` 状态机和绘制循环,约 2000 行。
|
||
|
||
**2. SSH 的复杂度在"配置"而不是"协议"**
|
||
内嵌 libssh2 意味着:密钥格式、agent 转发、ProxyJump、known_hosts、键盘交互式认证、多因素,全都要自己实现一遍。直接跑系统 `ssh` 却是零成本——用户已有的配置原样生效。用 pty 包一层即可解决窗口尺寸和 SIGWINCH。
|
||
|
||
**3. 许可**
|
||
Qt 开源版是 LGPLv3:动态链接 + 允许替换库即可合规,本项目 MIT 开源天然满足。不能静态链接、不能用于 Mac App Store 的 DRM 场景;将来若闭源商业化需要商业许可。
|
||
qtermwidget 是 GPL-2.0,会传染整个项目,因此排除——这也是自研内核的直接原因。
|
||
|
||
**4. 为什么不用 Rust sidecar**
|
||
跨进程协议、打包、生命周期管理都是额外成本;在只做三个协议、单人开发的规模下,收益不足以抵消复杂度。这一点在团队/功能扩大(比如要 SFTP 并发传输、X11 转发)时可以重新评估——`Transport` 接口就是为此留的缝。
|
||
|
||
## 被否决的方案
|
||
|
||
| 方案 | 否决原因 |
|
||
| --- | --- |
|
||
| Tauri 2 + xterm.js | 依赖系统 WebView,三平台三个引擎;Linux 下 fcitx5/IME 有坑;终端选择/渲染要和 xterm.js 的内部模型搏斗 |
|
||
| QWebEngineView + xterm.js | 包体 +80MB,内存翻倍,等于把 Electron 装进 Qt |
|
||
| 内嵌 libssh2/libssh | 协议之外的配置成本极高,C 实现的攻击面也更大 |
|
||
| QSsh(Qt Creator 内部库) | 非公开模块,无 API 稳定性承诺,功能覆盖不足 |
|
||
|
||
## 后果
|
||
|
||
- 正面:单二进制、启动快、渲染可控、无第三方终端依赖、内核可无头测试
|
||
- 负面:`forkpty` 绑定 POSIX,Windows 需要单独实现(ConPTY)
|
||
- 负面:Qt 是单一供应商,遇到框架层 bug 只能等上游或绕路
|
||
- 待办:Windows 支持、SFTP 面板、标签内搜索、分屏
|