Skip to content

soloterm/screen

一个用纯 PHP 编写的终端模拟器。

许可协议

MIT license 32 stars 0 forks

Solo Screen

Screen 是一个用纯 PHP 编写的终端模拟器。它为 Solo for Laravel 提供支持,并且可以用于在任何 PHP 应用程序中构建富文本的用户界面。

注意

Screen 是一个旨在集成到 PHP 应用程序中的库,它不是一个独立的终端应用程序。

关于终端模拟器

终端模拟器是一种软件,可以复制经典硬件计算机终端的功能。它可以处理文本的输入和输出,以及特殊的控制序列 (ANSI escape codes),这些控制序列控制格式化、光标移动和其他终端功能。

终端模拟器会解释这些转义序列来实现:

Screen 使用纯 PHP 实现此功能,允许开发人员构建终端用户界面,而无需依赖外部依赖项或原生代码。

为什么会有这个东西

Screen 最初是为了解决 Solo for Laravel 中的一个特定问题而创建的。

Solo 提供了一个 TUI (文本用户界面),该界面在单独的面板中同时运行多个进程,类似于 tmux。但是,当这些进程输出用于光标移动和屏幕操作的 ANSI escape codes 时,它们可能会“突破”其视觉容器并干扰界面的其他部分。

为了解决这个问题,Screen 创建了一个虚拟终端缓冲区,其中:

  1. 所有 ANSI 操作(光标移动、颜色更改、屏幕清除)都在一个隔离的环境中安全地进行。
  2. 在处理完所有操作后,捕获最终的渲染状态。
  3. 仅将最终的视觉输出显示给用户的终端。

这种方法可以完全控制终端输出的渲染方式,确保复杂的 ANSI 操作保持在其指定的区域内。虽然最初是为 Solo 构建的,但 Screen 已经发展成为一个独立的库,可以在任何需要终端模拟的 PHP 应用程序中使用。

功能特性

安装

通过 Composer 安装:

composer require soloterm/screen

要求

基本用法

这是一个使用 Screen 的简单示例:

use SoloTerm\Screen\Screen;

// 创建一个具有尺寸(列,行)的屏幕
$screen = new Screen(80, 24);

// 写入文本和 ANSI escape sequences
$screen->write("Hello, \e[1;32mWorld!\e[0m");

// 移动光标并添加更多文本
$screen->write("\e[5;10HPositioned text");

// 获取渲染的内容
echo $screen->output();

核心概念

Screen 运行的几个关键组件:

Screen

协调所有功能的主类。它负责光标定位、内容写入以及渲染最终输出。

$screen = new Screen(80, 24); // 宽度, 高度
$screen->write("Text and ANSI codes");

Buffers

Screen 使用多种缓冲区类型来跟踪内容和样式:

ANSI 处理

Screen 正确处理 ANSI escape sequences 以进行以下操作:

高级功能

光标定位

// 将光标移动到位置(第 5 行,第 10 列)
$screen->write("\e[5;10H");

// 向上移动光标 3 行
$screen->write("\e[3A");

// 保存和恢复光标位置
$screen->write("\e7"); // 保存
$screen->write("More text");
$screen->write("\e8"); // 恢复

文本样式

// 粗体红色文本
$screen->write("\e[1;31mImportant message\e[0m");

// 背景颜色
$screen->write("\e[44mBlue background\e[0m");

// 256 色支持
$screen->write("\e[38;5;208mOrange text\e[0m");

// RGB 颜色
$screen->write("\e[38;2;255;100;0mCustom color\e[0m");

屏幕操作

// 清除屏幕
$screen->write("\e[2J");

// 从光标清除到行尾
$screen->write("\e[0K");

// 插入行
$screen->write("\e[2L");

// 向上滚动
$screen->write("\e[2S");

自定义集成

您可以通过设置回调来响应终端查询:

$screen->respondToQueriesVia(function($response) {
  // 处理响应(如光标位置)
  echo $response;
});

注意

这仍然是一个正在进行的工作。我们需要更多测试/用例。

示例:构建一个简单的 UI

use SoloTerm\Screen\Screen;

$screen = new Screen(80, 24);

// 绘制边框
$screen->write("┌" . str_repeat("─", 78) . "┐\n");
for ($i = 0; $i < 22; $i++) {
  $screen->write("│" . str_repeat("", 78) . "│\n");
}
$screen->write("└" . str_repeat("─", 78) . "┘");

// 添加标题
$screen->write("\e[1;30H\e[1;36mMy Application\e[0m");

// 添加一些内容
$screen->write("\e[5;5HWelcome to the application!");
$screen->write("\e[7;5HPress 'q' to quit.");

// 渲染
echo $screen->output();

处理 unicode 和宽字符

Screen 正确处理 Unicode 字符,包括占用多列的 emoji 和 CJK 字符:

$screen->write("Regular text: Hello");
$screen->write("\nWide characters: 你好世界");
$screen->write("\nEmoji: 🚀 👨‍👩‍👧‍👦 🌍");

测试

Screen 包含一个全面的测试套件,该套件具有独特的视觉比较系统:

composer test

可视化测试

Screen 采用了一种创新的基于屏幕截图的测试方法(请参阅 ComparesVisually 特性),该方法验证了视觉输出:

  1. 测试在真实的终端 (iTerm) 中渲染内容
  2. 它捕获终端输出的屏幕截图
  3. 它通过 Screen 模拟器运行相同的内容
  4. 它捕获模拟输出的屏幕截图
  5. 它逐像素比较屏幕截图以确保准确性

这种测试策略确保 Screen 的仿真能够准确地匹配真实终端的行为,尤其是在涉及以下方面的复杂场景中:

对于没有屏幕截图功能的环境,测试可以回退到基于 fixture 的比较,从而使测试套件对于 CI/CD 管道具有通用性。

要为所有测试启用屏幕截图,请使用以下命令:

ENABLE_SCREENSHOT_TESTING=1 composer test

要仅为尚未具有 fixture 的测试启用屏幕截图,请使用以下命令:

ENABLE_SCREENSHOT_TESTING=2 composer test

贡献

欢迎贡献!请随时提交 pull request。

许可协议

The MIT License (MIT).

支持

This is free! If you want to support me:

Credits

Solo Screen was developed by Aaron Francis. If you like it, please let me know!