【问题标题】:ZSH prompt substitution issuesZSH 提示替换问题
【发布时间】:2015-09-18 21:57:31
【问题描述】:

我在这里和通过 Google 搜索了几个答案,但我仍然不确定我的提示出了什么问题。

根据我阅读的文档,这应该可以工作

setopt prompt_subst
autoload -U colors && colors
PROMPT="%{[00m[38;5;245m%}test %D%{[00m%}"

不过,我的提示如下:

[00m[38;5;245mtest 15-07-01[00m

请注意,日期扩展确实有效,因此提示替换有效。用于提示扩展的 ZSH 手册页指出 %{...%} 应被视为原始转义码,但这似乎没有发生。将该字符串传递给print -P 也会产生上面的输出。我在 Internet 上找到了 ZSH 的示例提示,这些提示似乎也表明上述语法应该有效。参见this 的一个示例 - $FG 和 $FX 数组填充了转义码并定义为here。我已经通过合并上面的两个文件直接尝试了这个示例,将setopt prompt_subst 添加到开头只是为了确保它已设置,然后获取它并且提示是一堆转义码。

以下作品

setopt prompt_subst
autoload -U colors && colors
PROMPT=$'%{\e[00m\e[38;5;245m%}test %D%{\e[00m%}'

我得到了test 15-07-01 的预期结果,颜色正确。

我已经在 OSX Yosimite 的 ZSH 5.0.5、MacPorts 的 5.0.7 和 Debian 的 4.3.17 上对此进行了测试,结果相同。我知道我已经通过工作示例在这里为我自己的问题提供了一个有效的解决方案,但我想知道为什么第一个语法不能正常工作。

【问题讨论】:

  • 这里没有问题;如果您正在阅读的文档省略了转义字符,那就错了。指示终端切换颜色的 ANSI 代码都以ESC[ 开头,而不仅仅是[
  • 请注意,使用内置转义来更改颜色比处理原始控制序列更容易。 prompt="%F{245}test %D%f"
  • 您可能会假设%{ ... %} 为每个序列的开头提供了转义字符;它实际上所做的只是指示 shell 大括号的内容在输出中占用零空间,以便可以计算正确的屏幕提示长度。
  • zshmisc 的手册页指出“%{...%} 包含一个字符串作为文字转义序列。大括号内的字符串不应更改光标位置。大括号对可以嵌套。”这似乎表明内容不应该改变光标位置,而不是 %{...%} 本身的功能。它确实声明内容将被视为文字转义序列。我很困惑,因为我看到了据称在 %{...%} 序列中不包含转义字符 ESC[ 的工作示例。
  • 文档措辞不佳。转义序列不包含可打印字符;整个事情由终端解释而不是显示。如果您确实将可打印字符放在大括号内,那么您的提示实际上会longer 计算出的zsh,相比之下,如果您计算出的提示短于zsh根本没有使用%{...%}

标签: zsh prompt ansi-escape


【解决方案1】:

我认为这一切都与逃避问题的永恒和长期问题有关。值得提醒自己什么是转义,简单地说:转义字符是对计算机的一个指示符,表明后面的内容不应按字面意思输出。

因此有 2 个转义问题: PROMPT="%{[00m[38;5;245m%}test %D%{[00m%}"

  1. 首先,颜色转义序列(例如[00m)都应该以控制字符开头,例如\e[00m。您可能还看到它写成^[00m\003[00m。我怀疑发生的事情是其中一种变体遭受了不经意间被作者的复制/粘贴或网站的框架堆栈(无论是在数据库中的某个地方、HTTP 渲染还是 JS 解析)中逃脱的共同命运。您可能知道,控制字符(即^\e\003)没有文字表示,如果您在键盘上按下它。这就是为什么如果 Web 堆栈在字符串中看到任何内容,它可能会决定不显示任何内容。所以现在让我们更正一下:

    PROMPT="%{\e[00m\e[38;5;245m%}test %D%{\e[00m%}"

  2. 这实际上很好地进入了下一个转义问题。有点滑稽的是\e[ 实际上是ESC 的表示,因此它本身就是一个转义序列标记,是的,它又被\ 转义。这是对旧的\\\\\\\\\\ 类玩笑的即兴表演。现在,重要的是,我们必须清楚终端的转义表达式和提示的字符串替换之间的区别,在伪代码中:

    PROMPT="%{terminal colour stuff%}test %D%{terminal colour stuff%}"

    现在我怀疑正在发生的事情,虽然我找不到任何文档来证明这一点,但一旦 ZSH 完成了替换,或者实际上在替换过程中,所有文字字符,无论转义含义如何,都被提升为真实人物¹。更进一步的闹剧,这个提升很可能是通过转义所有转义字符来完成的。例如,如果你真的想在命令行上打印'\e',你必须做echo "\\\e"。所以为了克服这个问题,我们只需要确保'终端颜色的东西'转义序列在分配给PROMPT之前得到评估,这可以简单地完成$'' 模式,像这样:

    PROMPT=$'%{\e[00m\e[38;5;245m%}test %D%{\e[00m%}'

    请注意,$''$()${} 具有相同的性质,只是它的唯一功能是解释转义序列。

[1] 我对此的怀疑是基于您实际上可以执行以下操作:

PROMPT='$(date)'

其中$(date) 的作用与%D 相同,通过为屏幕上的每个新提示输出打印一个实时 版本的日期。这个具体的例子用来证明PROMPT 变量真的应该被认为是一个迷你脚本的存储,而不是一个字符串(尽管这两个概念之间存在重叠,因此可以避免混淆)。因此,作为一个脚本,字符串是first 评估和then 打印的。我没有看过 ZSH 的提示渲染代码,但我认为这样的评估将受益于本机使用转义序列。例如,如果您想将转义序列作为参数传递给提示符中的命令(为每个提示符渲染运行的命令)怎么办?例如,以下内容在功能上与上面讨论的提示相同:

PROMPT='%{$(print "\e[00m\e[38;5;245m")%}test $(date)%{$(print "\e[00m")%}'

转义序列按字面意思存储,仅在每次提示呈现时进行解释。

【讨论】:

  • \e 的正确八进制表示是 \033,而不是 \003。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-25
  • 2010-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-08
相关资源
最近更新 更多