RPROMPT assíncrono?

5

Um amigo meu postou este no StackOverflow , e achei que poderíamos ter uma resposta mais provável aqui. Sua postagem se refere à velocidade, mas agora sabemos que o script python que estamos usando para analisar o status do git é lento e, em algum momento, pretendemos reescrevê-lo para que seja mais rápido. no entanto, a questão do settign RPROMPT de forma assíncrona ainda é interessante para mim, então eu pensei em citar a pergunta dele aqui:

Desde que comecei a usar o git, tive a configuração RPROMPT para mostrar a ramificação atual. Eu tenho usado recentemente alguns dos scripts "fantasia" para mostrar as contagens de arquivos não / encenado e outras coisas úteis de relance. ( link )

Depois de usar isso por uma semana ou duas, seu desempenho começou a me incomodar.

Existem formas mais rápidas de obter esta informação ou existem formas de escrever de forma assíncrona o RPROMPT? Eu não quero esperar para digitar um comando enquanto o RPROMPT é calculado e ficaria perfeitamente feliz com ele aparecendo um pouco mais tarde do que o meu PROMPT principal.

Sem ofensa ao script acima mencionado; é ótimo. Eu sou apenas impaciente.

    
por Zev Eisenberg 17.09.2013 / 19:19

3 respostas

4

Aqui está uma solução que usa um trabalho em segundo plano e sinaliza para atualizar o prompt de forma assíncrona.

A idéia é fazer com que sua função prompt gere um trabalho em segundo plano que construa o prompt, grave-o em um arquivo e, em seguida, envie um sinal para o shell pai que foi feito. Quando o shell pai recebe o sinal, ele lê o prompt do arquivo e redesenha o prompt.

Na sua função de prompt, coloque isso:

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 &!

E no seu .zshrc, coloque isso:

function TRAPUSR2 {
    RPROMPT=$(cat "${TMPPREFIX}/prompt.$$")

    # Force zsh to redisplay the prompt.
    zle && zle reset-prompt
}
    
por 25.09.2013 / 07:27
1

Eu teria o git_super_status() lido de um arquivo (diga algo como /tmp/rprompt.$$ ). O arquivo conteria o "conteúdo" de qual git_super_status() normalmente retornaria. Então, git_super_status() poderia disparar um script de segundo plano para fazer a parte "assíncrona" (ou seja, fazer o processamento normal, mas, em vez disso, exibir sua saída, gravar a saída nesse arquivo).

Isso significa que o prompt levará alguns segundos para detectar novas alterações no git e só será atualizado na próxima vez que um comando for emitido, o que não é perfeito. Não consigo ver uma alternativa, pois não acho que haja um mecanismo de retorno de chamada ou tipo de pesquisa oferecido com o RPROMPT.

    
por 17.09.2013 / 19:38
0

Eu tenho um trecho de código atualizando o prompt de forma assíncrona, mas tem alguns problemas:

  1. ocasionalmente, uma mensagem de erro é impressa, dizendo que não é possível encontrar o trabalho em segundo plano.
  2. algumas vezes depois de executar um comando, a última linha da saída é sobrescrita (assim você não pode vê-la) ou o prompt não é reimpresso.

O código:

# 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

Então, setopt PROMPT_SUBST e use \$_current_branch em PS1 .

Versões suportadas são zsh 5.0.6 +.

    
por 01.04.2015 / 10:59