由于 zsh 中的日期命令,多行提示格式不正确

Multiline prompt formatting incorrectly due to date command in zsh

我的 .zshrc 中有以下内容:

setopt PROMPT_SUBST
precmd(){
  echo""
  LEFT="$fg[cyan]$USERNAME@$HOST $fg[green]$PWD"
  RIGHT="$fg[yellow]$(date +%I:%M\ %P)"
  RIGHTWIDTH=$(($COLUMNS-${#LEFT}))
  echo $LEFT${(l:$RIGHTWIDTH:)RIGHT}
}
PROMPT="$ "

这给了我下面的截图

即使调整大小时,右侧的时间部分始终不会一直延伸到终端的边缘。我认为这是由于 $(date +%I:%M\ %P) 有人知道如何解决这个问题吗?

编辑:放大截图

虽然您的想法值得称赞,但您遇到的问题是您的 LEFTRIGHT 包含 ANSI 转义序列(用于颜色),它们应该是零宽度字符,但仍然是如果您天真地使用 $#name${(l:expr:)name}.

,则计入字符串的长度

此外,就风格而言,您最好使用 Zsh 的内置 prompt expansion,它用简短的百分比转义序列包装了人们可能希望在提示中看到的许多常见内容。特别是,有内置的颜色序列,所以你不需要依赖非标准 $fg[blah].

下面是用我喜欢的编码风格编写的大致提示...不完全是,我把所有内容都写得超级冗长以便于理解(希望如此)。左右预提示的长度是在去除颜色的转义序列并执行提示扩展后计算的,这给出了正确的显示长度(我不可能在几分钟内完成它;我把表达式撕掉了 pure) .

precmd(){
    local preprompt_left="%F{cyan}%n@%m %F{green}%~"
    local preprompt_right="%F{yellow}%D{%I:%M %p}%f"
    local preprompt_left_length=${#${(S%%)preprompt_left//(\%([KF1]|)\{*\}|\%[Bbkf])}}
    local preprompt_right_length=${#${(S%%)preprompt_right//(\%([KF1]|)\{*\}|\%[Bbkf])}}
    local num_filler_spaces=$((COLUMNS - preprompt_left_length - preprompt_right_length))
    print -Pr $'\n'"$preprompt_left${(l:$num_filler_spaces:)}$preprompt_right"
}

PROMPT="$ "

编辑:在某些终端仿真器中,精确打印 $COLUMN 个字符可能会换行。在这种情况下,将适当的行替换为

local num_filler_spaces=$((COLUMNS - preprompt_left_length - preprompt_right_length - 1))

编辑结束。

这是非常可定制的,因为您几乎可以在 preprompt_leftpreprompt_right 中放置任何内容,并且仍然可以获得正确的长度 — 只需记住对零宽度序列使用提示转义序列,例如 %F{}%f 表示颜色,%B%b 表示粗体等。再次阅读有关提示扩展的文档:http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html.

注意:您可能会注意到 %D{%I:%M %p} 扩展为 11:35 PM 之类的东西。那是因为我想用%P得到pm,但不是每个strftime的实现都支持%P。最坏的情况:如果你真的想要小写但 %P 不受支持,请使用你原来的命令替换 $(date +'%I:%M %P').

另外,我使用的是 %~ 而不是 %/,所以你会得到 ~/Desktop 而不是 /c/Users/johndoe/Desktop。有些人喜欢,有些人不喜欢。然而,正如我所说,这很容易定制。