跳转到主内容

弃用 bash 的 rprompt 功能

· 1 分钟阅读
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

经过慎重考虑,我们决定在 bash 中移除对 rprompt 的支持。如果你 想了解这个决定背后的原因,请继续阅读。

背景

rprompt 是一个让你能在终端右侧、与光标同一行显示提示信息的功能。 虽然很多 shell 原生支持此功能,但 bash 并不支持。为绕过这个限制, Oh My Posh 开发了自定义实现方案,同时适用于 bash 和 PowerShell。

演进历程

初代实现

Oh My Posh 中 bash 的 rprompt 经历过两次迭代。初代方案将 rprompt 与主提示符一同输出到 PS1 变量中,这样只需一次 CLI 调用就能显示完整提示符。

难点在于,由于 rprompt 与主提示符一同输出,我们需要确保 bash 的 readline 库能正确解析提示符。在 bash 中,每个不可打印字符(例如颜色代码) 都必须包裹在 \[\] 中。这是确保 bash 能够计算提示符长度 并最终正确定位光标的必要条件。

结果发现,对于 rprompt 功能,必须采用不同的处理方式。因为 rprompt 是在 bash 解释为提示符结束之后才输出的。我们发现需要将整个 rprompt 包裹在 \[\] 中,而不是单独转义每个不可打印字符。

这个方案运行了一段时间,但显然不够健壮。readline 的光标位置计算 很容易被破坏,且调试困难。不同平台上的表现也存在差异, 这迫使我们重新设计方案。

二代实现

第二代 rprompt 实现方案健壮性大幅提升。我们决定通过单独的 CLI 调用来输出 rprompt,以便更轻松地控制输出。该方案利用了 bash 中的 PROMPT_COMMAND 变量(这是一个在提示符输出前执行的钩子)。我们首先在 PROMPT_COMMAND 中输出 rprompt,然后在 PS1 变量中设置主提示符,这样 bash 就不会受到 rprompt 存在的影响。

从架构角度看,这个方案更加清晰,但也带来了新挑战: 最明显的是需要两次 CLI 调用来显示提示符,导致渲染速度比初代方案慢。

此外,由于我们在 PS1 解析前输出内容,陆续发现了以下问题:

  1. 当上一条命令的输出未以换行符结束时,rprompt 会与命令输出显示在同一行

  2. 当提示符位于终端缓冲区底部时,rprompt 会与提示符显示在同一行,导致提示符显示异常

  3. 在某些平台上仍会破坏命令历史导航功能

  4. 对多行提示符需要特殊处理,因为输出在 PS1 解析前完成,必须重新定位光标

在以上问题中,只有第4点可以修复。其他问题都超出了我们的控制范围。

结论

Oh My Posh 是一款需要易用、易维护且100%可靠的工具。其核心原则之一是绝不破坏 shell 功能。然而 bash 中的 rprompt 功能始终不够可靠,且在故障时_难以调试_。我花费了大量时间调试 bash 中的 rprompt 问题,但现在是时候向前看了。如果你需要使用 rprompt 功能,我推荐使用原生支持该功能的 shell,例如 nushellzshfish

PowerShell 怎么办?

PowerShell 中的 rprompt 功能100%可靠,尽管它不是原生支持的。PowerShell 没有像 bash 那样计算实际提示宽度的挑战,因此_不需要转义任何内容_。我们可以使用上面提到的第一种实现方式,效果非常好。