首页 > 解决方案 > 用抽象层控制交互式终端程序

问题描述

我希望less在终端中运行一个分页命令(通常是一个 git diff,但可能只是我的一些其他程序),它是完全交互式的,但它是外部可控的。最初只是能够终止并重新启动内部进程就可以了,但是能够以交互方式注入输入会很好。

我认为一个简单的方法可能是使用一个简单地运行内部命令的 bash 脚本,我们假设它是git diff.

我将以这样的方式编写我的文本编辑器 vim 脚本,当我保存文件时,它会“发送一个信号”,上述 bash 脚本已以某种方式注册。在这种情况下,它将中断交互式子less进程(例如,给它一个 SIGTERM 似乎有点工作,尽管它无法重新绘制)并再次运行它。这样我就可以通过保存我的文件来实时更新我的​​ git diff。

我的另一个用例可以使用相同的框架:我希望我的光标在编辑器中悬停的标记用于搜索项目,以查找它的所有其他实例。例如,在这里,触发器将不同于保存缓冲区,并且比保存缓冲区更频繁。

应该保持交互性(例如,终端连接到 STDIN)的原因是我可以使用鼠标/键在寻呼机内交互地上下滚动。

实现此目的的一种简单且看似脆弱的方法是将 vim 配置为直接向 less 提供 SIGTERM 或向父级提供 SIGKILL git diff(仅从经验测试来看,这似乎在我的 Mac 上有效)。

但是我想要如何杀死内部交互进程的逻辑和实现住在 shell 脚本中。

我在想我可以使用 fifo 并发送一些 shell 脚本解释的协议消息。但似乎发生的是终端交互式标准输入是通过 shell 脚本传递的……我可能还需要某种守护进程或由它管理的东西。需要有另一个组件监听该事件。

这让我想知道:也许这意味着实现它的更实用和更简单的方法是使用运行时(例如 node.js),它可以为我提供异步控制或其他 i/o 多路复用或异步 i/o 方法。它保持空闲状态,并通过管道/转发标准输入(交互)到子进程。它还异步侦听 fifo 或其他 IPC 方法,并将根据从它接收到的命令采取行动,例如注入进一步的交互式输入或杀死/重新启动子...

似乎应该有规范的 bashisms 来实现这一点,尽管我觉得我可能记得如何使用较低级别的 OS API 来做到这一点select(我传统上从我的研究中记得是 i/o 多路复用),多路复用是可能的就像这超出了 shell 的范围,shell 在 i/o重定向方面有很多糖和功能。

标签: bashprocessioio-redirectionfifo

解决方案


跟进我漫无边际的问题。

我继续沿着这条路走下去,并探索了一些选择。我或多或少地构建了一个 node.js 应用程序,该应用程序使用明确定义的(和非 terminfo 检查的)终端转义码来实现我自己的寻呼机工具,它可以完全按照我的意愿去做,不多也不少。

我也一直在围绕通过 tmux 实现的这种能力(例如,使用它的capture-pane命令)构建自动化测试基础设施。例如,为了测试分页是否正常工作,我可以在打开缓冲区后检查,在向下滚动 3 页并备份 2 页后,输出是否与在 1 页后显示的内容相同。

尽管可以很好地争论它可能应该只是一个简单的 ncurses 应用程序,但我发现它是一种有益的体验,让我沉迷于这些东西并继续使用 typescript,我已经为其他任务写了很多,而且它有助于继续积累使用该语言的经验。对于这种专门构建的工具,当然不是理想的语言或运行时,但这没关系。


推荐阅读