本文来自依云's Blog,转载请注明。
为什么要异步?当然是因为慢了。比如 Arch 核心仓库 git 版挺大的,第一次进去时显示个 git 分支名要等好一会儿。今天在 zsh-users 列表中看到 Bart Schaefer 给出了一个使用 coprocess 的解决方案,眼前一亮,立即照葫芦画瓢给自己的 zsh 用上了。以下是整个提示符设置部分的代码:
if [[ -n $commands[git] ]]; then _nogit_dir=() for p in $nogit_dir; do [[ -d $p ]] && _nogit_dir+=$(realpath $p) done unset p typeset -g _current_branch= vcs_info_fd= zmodload zsh/zselect 2>/dev/null _vcs_update_info () { eval $(read -rE -u$1) zle -F $1 exec {1}>&- zle reset-prompt } _set_current_branch () { 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 '{if($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 _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 } typeset -gaU precmd_functions precmd_functions+=_set_current_branch setopt PROMPT_SUBST fi [[ -n $ZSH_PS_HOST && $ZSH_PS_HOST != \(*\)\ ]] && ZSH_PS_HOST="($ZSH_PS_HOST) " E=$'\x1b' PS1="%{${E}[2m%}%h $ZSH_PS_HOST%(?..%{${E}[1;31m%}%?%{${E}[0m%} )%{${E}[32m%}%~\$_current_branch %(!.%{${E}[0;31m%}###.%{${E}[1;34m%}>>>)%{${E}[0m%} "
比较坑的是使用chpwd_functions
的话只能在目录改变时显示一次,再随便执行个什么命令分支提示就没了。又想到目录不改变的时候分支也可以变化(切换分支了嘛),所以使用precmd_functions
,每次显示提示符前(单纯的重绘除外)都执行一次。另外,为了避免每次显示提示符时都明显地分为两步干扰视线,所以在那个_set_current_branch
函数里等了 0.1 秒,超时才会不管分支名显示先继续了。
2014年2月24日更新:注意,直到 zsh 5.0.5(就是当前最新版本)有个 bug,在显示提示符之后、用户输入之前,上述代码会经常出现「忙等待」的情况浪费 CPU。这里有个补丁可以修复。
Feb 27, 2014 03:41:46 PM
给oh-my-zsh写个patch吧。
Feb 27, 2014 09:51:19 PM
我从来没了解过 oh-my-zsh 呢。
Feb 27, 2014 10:43:34 PM
有很多可以自由选择加载的插件
https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins
还有很多主题,还有很方便的alias(比如1,2,3...分别是cd -,cd -2, cd -3),但也显得臃肿。