timzaak / blog

8 stars 1 forks source link

video terminals 研究 #116

Closed timzaak closed 2 months ago

timzaak commented 2 months ago

最开始研究 wezterm, 看看是如何做 SSH 渲染的,但 Rust 代码看的麻烦,且渲染外的功能过多,于是找了 typescript实现的 xterm.js 来看,它提供 Dom Render,Canvas Render,WebGPU Render[WIP],相互比对着看,会更容易找规律,也不需要应对 Rust 的编程繁琐性。

xterm.js 的关键文件有: Keyboard.ts 将输入转译成 ASCII 控制码, 从而适配 SSH字符流的交互。 EscapeSequenceParser.ts 解析ssh 传递过来的 ANSI/DEC 字符流,并转换到UI表达数据结构。 CanvasRenderer.ts 解构了 video terminals 的渲染图层:文字(背景、前景)、选中、光标、链接。

关于文字排版布局再复杂的样例,可以参考 facebook/Lexical 富文本编辑器的设计思路。它有 Dom Render 实现 以及 iOS TextKit Render实现。

timzaak commented 2 months ago

wezterm 相较于 xterm.js 解决的问题有:

  1. window 跨平台适配, 例如监听键盘、鼠标事件: run_message_loop。 Linux x11 基于 xcb rust bindings,wayland 基于 Smithay/client-toolkit(wayland-client rust 封装)。 macOS 基于 cocoa rust bindings。 Windows 基于 winapi rust bindings。 还有诸如 toast, pty,粘贴板 等兼容性封装。
  2. powershell 、bash、zsh、Fig 等 Shell 自动完成适配, domain、tab、window 等概念的实现。
  3. 弹窗、快捷键、pane 等场景下的 key、mouse 映射(did_process_key 函数实现)
  4. asciinema 支持。用来 shell 录制、播放。
  5. command line、客户端交互支持, WebGPU 渲染支持。
  6. line edit 等更精致的交互。
  7. Terminal graphics protocol 支持。 kitty、sixel
  8. lua 插件配置
timzaak commented 2 months ago

基于 ANSI/DEC 字符流 绘图的有:

https://github.com/crossterm-rs/crossterm 抹平 cmd 、unix terminal 差异。 https://github.com/ratatui-org/ratatui 在命令行上绘制UI,提供UI组件封装。

timzaak commented 2 months ago

alacritty 也是 Rust 实现 video terminals。不过没搞插件,更纯粹。

  1. 窗口跨平台适配基于 winit ,剪贴板 基于自己fork的 copypast。 pty unix 基于openpty, windows 自己封装。
  2. 解析自己另开一个库: vte

渲染

渲染除了pty output 渲染外,还有交互渲染,例如程序模态框、搜索、光标。这里只研究针对 pty output 的渲染。 变动触发入口:pty.reader().read,

布局变动处理函数:impl Handler for Term。video terminals 的布局较为简单, 用 Grid 表示, 内部由 Cell 为组成,代表屏幕上每一个点(char)显示什么内容。 PS:有的 unicode,宽度大于一个点。

变动先触发 Grid 数据变化,再发出渲染请求(request_redraw)。 针对 Grid 构建 RenderableContent, 并依据 damagedTracker 确认全量渲染还是部份渲染。 剩下的就是常规GPU渲染操作了:

  1. shader 编写、字体处理。
  2. 依据RenderableContent double buffer 重绘。
  3. 特殊字体cache。
  4. scrool => viewpoint、制表字符、非单点字体处理。
timzaak commented 2 months ago

asciinema 的实现原理是开一个 pty,劫持input、output。ssh 监控等工具也可以这么搞。 核心代码 在此 nix 库的 pty::forkpty函数, 注意 fork 回来的父子线程问题。

timzaak commented 2 months ago

GPU 渲染字体

字体渲染技术(A Survey of Font Rendering Techniques) 在 WebGL 中渲染文字 GreenLightning/gpu-font-rendering

webgpu text render 这个讲的比较直白。