Files
liyepan 580abbcadf feat: VoiletXterm - Qt5 terminal workspace for SSH, Telnet and serial
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
2026-10-23 17:38:16 +08:00

51 lines
2.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 面板、标签内搜索、分屏