비동기식 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.

그것은 사용한다내가 직접 최적화gitstatusgits 명령 대신 백엔드로 사용 되며 gitstatus백그라운드에서 비동기식으로 호출됩니다.

관련 정보