异步RPROMPT?

异步RPROMPT?

我的一个朋友发了这个在 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

我有一段异步更新提示的代码,但它有一些问题:

  1. 有时会打印一条错误消息,说找不到后台作业。
  2. 有时执行命令后,输出的最后一行会被覆盖(因此您看不到它),或者不会重新打印提示。

代码:

# 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+。

答案4

如果您愿意使用外部提示,请尝试功率等级10k

它用自己优化过的gitstatus作为后端,而不是gits 命令,并且它gitstatus在后台异步调用。

相关内容