我的一个朋友发了这个在 StackOverflow 上,我想我们可能更有可能在这里得到答案。他的帖子提到了速度,但我们现在知道我们用来解析 git status 的 python 脚本很慢,在某些时候我们打算重写它以使其更快。然而,异步设置的问题RPROMPT
对我来说仍然很有趣,所以我想我应该在这里引用他的问题:
自从我开始使用 git 以来,我已经设置了 RPROMPT 来显示当前分支。我最近一直在使用一些“花哨”的脚本来显示未/暂存的文件计数和其他有用的一目了然的东西。 (https://github.com/olivierverdier/zsh-git-prompt/tree/master)
使用一两周后,它的性能开始令我困扰。
是否有更快的方法来获取此信息,或者是否有异步写入 RPROMPT 的方法?我不想在计算 RPROMPT 时等待输入命令,并且非常高兴它在我的主提示稍晚一些时弹出。
无意冒犯上述脚本;这很棒。我只是不耐烦了。
答案1
这是一个使用后台作业和信号来异步更新提示的解决方案。
这个想法是让你的提示函数产生一个后台作业,该作业构建提示,将其写入文件,然后向父 shell 发送已完成的信号。当父 shell 收到信号时,它从文件中读取提示并重绘提示。
在你的提示函数中,输入:
function async-build-prompt {
# Simulate a function that takes a couple seconds to build the prompt.
# Replace this line with your actual function.
sleep 2 && RPROMPT=$(date)
# Save the prompt in a temp file so the parent shell can read it.
printf "%s" $RPROMPT > ${TMPPREFIX}/prompt.$$
# Signal the parent shell to update the prompt.
kill --signal USR2 $$
}
# Build the prompt in a background job.
async-build-prompt &!
在你的 .zshrc 中,输入:
function TRAPUSR2 {
RPROMPT=$(cat "${TMPPREFIX}/prompt.$$")
# Force zsh to redisplay the prompt.
zle && zle reset-prompt
}
答案2
我将从git_super_status()
文件中读取内容(例如/tmp/rprompt.$$
)。该文件将包含git_super_status()
通常返回的“内容” 。然后git_super_status()
可以启动后台脚本来执行“异步”部分(即进行正常处理,但不显示其输出,而是将输出写入该文件)。
这意味着提示需要几秒钟的时间来获取新的 git 更改,并且只会在下次发出命令时更新,这并不完美。我看不到替代方案,因为我认为 RPROMPT 没有提供回调或轮询类型机制。
答案3
我有一段异步更新提示的代码,但它有一些问题:
- 有时会打印一条错误消息,说找不到后台作业。
- 有时执行命令后,输出的最后一行会被覆盖(因此您看不到它),或者不会重新打印提示。
代码:
# git branch in prompt {{{3
_setup_current_branch_async () { # {{{4
typeset -g _current_branch= vcs_info_fd=
zmodload zsh/zselect 2>/dev/null
_vcs_update_info () {
eval $(read -rE -u$1)
zle -F $1 && vcs_info_fd=
exec {1}>&-
# update prompt only when necessary to avoid double first line
[[ -n $_current_branch ]] && zle reset-prompt
}
_set_current_branch () {
_current_branch=
[[ -n $vcs_info_fd ]] && zle -F $vcs_info_fd
cwd=$(pwd -P)
for p in $_nogit_dir; do
if [[ $cwd == $p* ]]; then
return
fi
done
setopt localoptions no_monitor
coproc {
_br=$(git branch --no-color 2>/dev/null)
if [[ $? -eq 0 ]]; then
_current_branch=$(echo $_br|awk '$1 == "*" {print "%{\x1b[33m%} (" substr($0, 3) ")"}')
fi
# always gives something for reading, or _vcs_update_info won't be
# called, fd not closed
#
# "typeset -p" won't add "-g", so reprinting prompt (e.g. after status
# of a bg job is printed) would miss it
#
# need to substitute single ' with double ''
print "typeset -g _current_branch='${_current_branch//''''/''}'"
}
disown %{\ _br
exec {vcs_info_fd}<&p
# wait 0.1 seconds before showing up to avoid unnecessary double update
# precmd functions are called *after* prompt is expanded, and we can't call
# zle reset-prompt outside zle, so turn to zselect
zselect -r -t 10 $vcs_info_fd 2>/dev/null
zle -F $vcs_info_fd _vcs_update_info
}
}
_setup_current_branch_async
typeset -gaU precmd_functions
precmd_functions+=_set_current_branch
然后setopt PROMPT_SUBST
并\$_current_branch
在 中使用PS1
。
支持的版本是 zsh 5.0.6+。