Invite de commande Zsh avec statut Git asynchrone

Vincent Bernat

Zsh propose vcs_info, une fonction permettant de récupérer des informations liées à l’état du système de gestion des versions pour actif dans le répertoire en cours. Il alimente une variable qui peut ensuite être utilisée dans une invite de commande. Plusieurs logiciels sont supportés, notamment Git et SVN. Voici un exemple de configuration :

autoload -Uz vcs_info
zstyle ':vcs_info:*' enable git

() {
    local formats="${PRCH[branch]} %b%c%u"
    local actionformats="${formats}%{${fg[default]}%} ${PRCH[sep]} %{${fg[green]}%}%a"
    zstyle ':vcs_info:*:*' formats           $formats
    zstyle ':vcs_info:*:*' actionformats     $actionformats
    zstyle ':vcs_info:*:*' stagedstr         "%{${fg[green]}%}${PRCH[circle]}"
    zstyle ':vcs_info:*:*' unstagedstr       "%{${fg[yellow]}%}${PRCH[circle]}"
    zstyle ':vcs_info:*:*' check-for-changes true
}

add-zsh-hook precmd vcs_info

Vous pouvez ensuite utiliser la variable ${vcs_info_msg_0_} dans votre invite pour afficher la branche actuelle, la présence de fichiers modifiés ainsi que l’action courante1. Jetez un œil à la documentation pour plus de détails.

Invite comprenant des informations liées à Git telle que la
branche
Exemple d'invite de commande comprenant des informations récupérées via la fonction vcs_info.

Sur les gros dépôts, certaines informations peuvent être coûteuses à récupérer. Pendant que vcs_info interroge Git, les interactions avec Zsh sont bloquées. Une solution est d’exécuter vcs_info de manière asynchrone avec zsh-async.

La première étape est de définir un wrapper autour de vcs_info. Celui-ci s’exécutera dans un processus séparé et devra communiquer son résultat en utilisant la sortie standard. Il attend le répertoire courant en premier argument.

_vbe_vcs_info() {
    cd -q $1
    vcs_info
    print ${vcs_info_msg_0_}
}

La seconde étape est de définir un worker, également nommé vcs_info, et d’attacher une fonction qui traitera le résultat issu du wrapper. Cette fonction appelle zle reset-prompt pour forcer un nouvel affichage de l’invite de commande avec les informations à jour issues de ${vcs_info_msg_0_}.

source $ZSH/.../async.zsh
async_init
async_start_worker vcs_info
async_register_callback vcs_info _vbe_vcs_info_done

_vbe_vcs_info_done() {
    local stdout=$3
    vcs_info_msg_0_=$stdout
    zle reset-prompt
}

La dernière étape est de demander l’exécution du wrapper au worker avant d’afficher le prompt. Cela remplace l’invocation synchrone de vcs_info :

_vbe_vcs_precmd() {
    async_flush_jobs vcs_info
    async_job vcs_info _vbe_vcs_info $PWD
}
add-zsh-hook precmd _vbe_vcs_precmd

C’est tout !

Sans se reposer sur vcs_info, il serait possible d’améliorer l’expérience en consultant le nom de la branche courante avant de récupérer les informations plus coûteuses. Cependant, avec peu d’efforts, cette intégration simple permet de répondre l’invite plus rapide ! Jetez un œil au code complet : il contient quelques améliorations.


  1. Les actions incluent « merge », « rebase » et « bisect ». ↩︎