非同期RPROMPT?

非同期RPROMPT?

私の友人はこう書いています。スタックオーバーフローで、私の考えでは、ここで答えを得る可能性が高いようです。彼の記事ではスピードが言及されていますが、私たちはgitの状態を解析するために使用するPythonスクリプトが遅いことを知っており、ある時点でそれをより速くするために書き直すつもりです。しかし、非同期設定の問題はRPROMPTまだ興味深いので、ここに彼の質問を引用したいと思います。

gitの使用を開始して以来、現在のブランチを表示するようにRPROMPTを設定しました。私は最近、un / stagedファイルの数やその他の有用な情報を一目で見るために「クール」スクリプトを使用しています。 (https://github.com/olivierverdier/zsh-git-prompt/tree/master)

1〜2週間ほど使用した後は、パフォーマンスが私を悩ませ始めました。

この情報を取得するより高速な方法はありますか、それともRPROMPTに非同期的に書き込む方法はありますか? RPROMPTが計算されている間にコマンドが入力されるのを待ちたくないので、デフォルトのプロンプトより少し遅くなるのはとても嬉しいです。

上記のスクリプトに対する攻撃はありません。私は辛抱強くない。

答え1

以下は、バックグラウンドタスクとシグナルを使用してメッセージを非同期的に更新するソリューションです。

アイデアは、プロンプト関数がプロンプトをビルドし、それをファイルに書き込んでから親シェルに完了シグナルを送信するバックグラウンドタスクを生成することです。親シェルがシグナルを受け取ったら、ファイルからプロンプトを読み取り、プロンプトを再描画します。

プロンプト機能に次のように入力します。

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_branchPS1

サポートされるバージョンは zsh 5.0.6+ です。

答え4

外部プロンプトを使用する場合は、以下を試してください。パワーレベル10k

それを使う私は直接最適化gitstatusgit■コマンドの代わりにバックエンドとして使用され、バックgitstatusグラウンドで非同期的に呼び出されます。

関連情報