计算zsh提示符的用户可见字符串的长度

sim*_*ont 14 zsh

我想将我当前的git分支放入我的多行ZSH提示符中.然而,这会弄乱两条线 - 我希望它们很好地排成一行.


??(simont@charmander:s000)?[master *]????????????????
???(~  )??  
??(127:15:44)??                       ??(Sat,May12)??
Run Code Online (Sandbox Code Playgroud)

应该:


??(simont@charmander:s000)?[master *]?????????(~  )??  
??(127:15:44)??                       ??(Sat,May12)??
Run Code Online (Sandbox Code Playgroud)

git分支是从抓住oh-my-zsh功能,git_prompt_info(),它带给我的分支,脏状态,以及颜色的东西很好一堆提示,逃逸的.

如何计算将在ZSH提示中明显插入的字符 - 而不是提示转义序列?

sim*_*ont 11

假设提示转义的字符串存储在变量中FOO,这将只计算用户可见的字符:

                                                                                                                                
FOO=$(git_prompt_info)                                                                                                                     
local zero='%([BSUbfksu]|([FK]|){*})'
FOOLENGTH=${#${(S%%)FOO//$~zero/}} 
Run Code Online (Sandbox Code Playgroud)

这来自于此.zshrc.

这是一个粗略的解释,为什么它的工作,自由引用man zshexpn,部分PARAMETER EXPANSION.我不是100%确定细节,因此,如果您使用它来开发自己的等效物,请阅读相关man zshall章节.

在线上工作FOOLENGTH=${#${(S%%)FOO//$~zero/}},我们有很多位.从内到外:

  1. $~zero:~确保zero我们定义为'%([BSUbfksu]|([FB]|){*})'被视为模式而不是普通字符串.

  2. ${(S%%)FOO//$~zero/}:这匹配${name//pattern/repl}:

    通过字符串repl替换参数名称扩展中模式的最长匹配

    请注意,我们没有repl; 我们pattern用什么都没有替换最长的匹配,从而删除它.用几个标志
    (S%%)FOO进行扩展FOO.我不太关注它.

  3. ${#${(S%%)FOO//$~zero/}}:如果是${#spec}替换spec,将替换替换结果的字符长度spec.在我们的例子中,spec是取代的结果${(S%%)FOO//$~zero/}; 所以这基本上返回在正则表达式的结果的字符的长度s/zero//FOO,其中zero高于所述图案.

  • `(S)`使得匹配非贪婪从而将"最长可能的匹配"变成"最短可能的匹配"(如果没有它在模式中的`{*}`会变成'%F {蓝色}%M%F {黄色}%#%f`只是'%#`,而它应该把它变成'%M%#`),`(%%)`在PROMPT_*选项之后对字符串执行快速扩展.注意:如果PROMPT字符串包含带有一些副作用的命令,则应避免使用此方法:例如,如果要使用它来计算提示的显示频率.大多数时候你不会受此影响. (4认同)