我想要一个带有右对齐部分的多行 zsh 提示符,看起来像这样:
2.nate@host:/current/dir 16:00
->
我知道 zsh 中的 RPROMPT,但是它有一个右对齐提示,与你的正常提示相对,与你输入的文本位于同一行。
有没有办法让多行命令提示符的第一行右对齐?我正在寻找 PS1 变量中的一条指令,该指令表示“现在右对齐”,或者一个变量对于 PS1 的作用相当于 RPROMPT 对于 PROMPT 的作用。
谢谢!
答案1
答案2
我也一直在寻找这个。对我来说,绘制的线条在调整大小或用于清除屏幕precmd()
时不会重新绘制这一事实一直困扰着我。我现在正在做的是使用^L
ANSI 转义序列稍微移动光标。虽然我怀疑还有更优雅的方式来发布它们,但这对我来说是有效的:
_newline=$'\n'
_lineup=$'\e[1A'
_linedown=$'\e[1B'
PROMPT=...whatever...${_newline}...whatever...
RPROMPT=%{${_lineup}%}...whatever...%{${_linedown}%}
请记住zsh 手册指出 %{...%} 用于文字转义序列不移动光标即便如此,我还是使用它们,因为它们允许忽略其内容的长度(虽然无法弄清楚如何使用它们来发出移动光标的转义符)
答案3
这是我刚才配置这个东西的方法。这种方法不需要任何转义序列操作,但会让你的主提示有两个不同的变量:PS1
带颜色和NPS1
不带颜色。
# Here NPS1 stands for "naked PS1" and isn't a built-in shell variable. I've
# defined it myself for PS1-PS2 alignment to operate properly.
PS1='%S%F{red}[%l]%f%s %F{green}%n@%m%f %B%#%b '
NPS1='[%l] %n@%m # '
RPS1='%B%F{green}(%~)%f%b'
# Hook function which gets executed right before shell prints prompt.
function precmd() {
local expandedPrompt="$(print -P "$NPS1")"
local promptLength="${#expandedPrompt}"
PS2="> "
PS2="$(printf "%${promptLength}s" "$PS2")"
}
请注意,使用print -P
可快速扩展,${#variable}
使用 可获取存储在变量中的字符串长度,printf "%Nd"
使用 可用空格填充左侧N
。print
和printf
都是内置命令,因此不会对性能造成影响。
答案4
让我们用这个布局定义提示:
top_left top_right
bottom_left bottom_right
为此,我们需要一个函数来告诉我们打印时给定的字符串需要多少个字符。
# Usage: prompt-length TEXT [COLUMNS]
#
# If you run `print -P TEXT`, how many characters will be printed
# on the last line?
#
# Or, equivalently, if you set PROMPT=TEXT with prompt_subst
# option unset, on which column will the cursor be?
#
# The second argument specifies terminal width. Defaults to the
# real terminal width.
#
# Assumes that `%{%}` and `%G` don't lie.
#
# Examples:
#
# prompt-length '' => 0
# prompt-length 'abc' => 3
# prompt-length $'abc\nxy' => 2
# prompt-length '❎' => 2
# prompt-length $'\t' => 8
# prompt-length $'\u274E' => 2
# prompt-length '%F{red}abc' => 3
# prompt-length $'%{a\b%Gb%}' => 1
# prompt-length '%D' => 8
# prompt-length '%1(l..ab)' => 2
# prompt-length '%(!.a.)' => 1 if root, 0 if not
function prompt-length() {
emulate -L zsh
local COLUMNS=${2:-$COLUMNS}
local -i x y=$#1 m
if (( y )); then
while (( ${${(%):-$1%$y(l.1.0)}[-1]} )); do
x=y
(( y *= 2 ));
done
local xy
while (( y > x + 1 )); do
m=$(( x + (y - x) / 2 ))
typeset ${${(%):-$1%$m(l.x.y)}[-1]}=$m
done
fi
echo $x
}
我们需要另一个函数,它接受两个参数并在屏幕的相对两侧打印带有这些参数的完整罚款。
# Usage: fill-line LEFT RIGHT
#
# Prints LEFT<spaces>RIGHT with enough spaces in the middle
# to fill a terminal line.
function fill-line() {
emulate -L zsh
local left_len=$(prompt-length $1)
local right_len=$(prompt-length $2 9999)
local pad_len=$((COLUMNS - left_len - right_len - ${ZLE_RPROMPT_INDENT:-1}))
if (( pad_len < 1 )); then
# Not enough space for the right part. Drop it.
echo -E - ${1}
else
local pad=${(pl.$pad_len.. .)} # pad_len spaces
echo -E - ${1}${pad}${2}
fi
}
最后,我们可以定义一个设置PROMPT
和的函数RPROMPT
,指示 ZSH 在每个提示之前调用它,并设置适当的提示扩展选项:
# Sets PROMPT and RPROMPT.
#
# Requires: prompt_percent and no_prompt_subst.
function set-prompt() {
emulate -L zsh
local git_branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null)"
git_branch=${${git_branch//\%/%%}/\\/\\\\\\} # escape '%' and '\'
local top_left='%F{blue}%~%f'
local top_right="%F{green}${git_branch}%f"
local bottom_left='%B%F{%(?.green.red)}%#%f%b '
local bottom_right='%F{yellow}%T%f'
PROMPT="$(fill-line "$top_left" "$top_right")"$'\n'$bottom_left
RPROMPT=$bottom_right
}
autoload -Uz add-zsh-hook
add-zsh-hook precmd set-prompt
setopt noprompt{bang,subst} prompt{cr,percent,sp}
这将产生以下提示:
~/foo/bar master
% █ 10:51
- 左上角:蓝色的当前目录。
- 右上:Green Git 分支。
- 左下角:
#
如果是 root,%
如果不是,则成功时为绿色,错误时为红色。 - 右下:黄色当前时间。
更多详细信息请访问多行提示:缺少的成分并完成代码这个要点。