Comment puis-je corriger l'habillage des invites de bash couleur?

9

J'ai défini une invite bash (en utilisant PROMPT_FUNCTION) comme ceci:

function get_hg_prompt_prefix() {
    local APPLIED_COLOR=$1; shift
    local UNAPPLIED_COLOR=$1; shift
    local ALERT_COLOUR=$1; shift
    local TEXTCOLOR=$1; shift
    local mercurial_prompt_line="{{patches|join(:)|pre_applied(${APPLIED_COLOR})|post_applied(${TEXTCOLOR})|pre_unapplied(${UNAPPLIED_COLOR})|post_unapplied(${TEXTCOLOR})}\n\r}"
    local mercurial_status_prompt="{ ${ALERT_COLOUR}{status}${TEXTCOLOR}}"

    echo "$(hg prompt "${mercurial_prompt_line}" 2>/dev/null)$(hg prompt "${mercurial_status_prompt}" 2>/dev/null)"
}

function set_prompt() {
    bright='\[[01m\]'
    colors_reset='\[[00m\]'
    HOSTCOLOR=${colors_reset}='\[[34m\]'
    USERCOLOR=${colors_reset}='\[[01m\]'
    TEXTCOLOR=${colors_reset}='\[[32m\]'
    APPLIED_COLOR=${colors_reset}='\[[32m\]'
    UNAPPLIED_COLOR=${colors_reset}='\[[37m\]'
    ALERT_COLOUR=${colors_reset}='\[[31m\]'

    hg_status="$(get_hg_prompt_prefix $APPLIED_COLOR $UNAPPLIED_COLOR $ALERT_COLOUR $TEXTCOLOR)"
    ps1_prefix="${hg_status}$colors_reset($bright$(basename $VIRTUAL_ENV)$colors_reset) "
    PROMPTEND='$'
    PS1="${ps1_prefix}${USERCOLOR}\u${colors_reset}${TEXTCOLOR}@${colors_reset}${HOSTCOLOR}\h${colors_reset}${TEXTCOLOR} (\W) ${PROMPTEND}${colors_reset} "
}

PROMPT_COMMAND=set_prompt

En général, cela me donne une invite sur plusieurs lignes qui affiche des informations d'état hg ainsi que mon virtualenv actuel, ressemblant (sans couleur) à ceci:

buggy-wins.patch
 ! (saas) user@computer (~) $ 

Le problème est que cela se déroule avec le calcul de la longueur de l'invite (je pense!) Et provoque des problèmes d'emballage de terminal étranges et le placement du curseur. Par exemple, dans un terminal de 80 caractères, voici l'invite que je vois (le caractère ** - entouré est l'emplacement du curseur):

~) $ **a**nis) crose@chris-rose (~

Dans les terminaux suffisamment larges pour afficher l'invite, l'habillage de ligne se produit beaucoup plus tôt qu'il ne devrait; voici le plus de texte que je peux tenir sur la première ligne de l'invite dans une fenêtre de terminal de 108 caractères (encore une fois, le ** marque l'emplacement de mon curseur):

 **(**advanis) crose@chris-rose (~) $ sdkfjlskdjflksdjff

Lorsque la ligne se termine, elle écrase l'invite. Cependant, la deuxième ligne d'entrée s'étend jusqu'au bord du terminal, puis se termine correctement.

Donc, clairement, quelque chose gâche la largeur de l'invite. Comment puis-je faire en sorte que bash détermine la longueur de la chaîne PS1 non pas en fonction des codes d'échappement ANSI, mais en fonction de la longueur réelle affichée de l'invite?

Chris R
la source

Réponses:

21

bashutilise \[ \]pour déterminer la "longueur affichée": le texte entre ces deux échappements est considéré comme non imprimable et n'est pas compté dans la longueur totale; tout le reste est.

Il semble y avoir un problème avec vos variables: bright='\[[01m\]'n'inclut pas réellement de caractère ESC, donc [01mest imprimé en tant que texte normal mais n'est pas compté dans la longueur. Ça devrait l'être '\[\e[01m\]'. Idem pour toutes les autres variables.


En relation:

  • Bash, vous pouvez mettre \$(hg_status)à $PS1directement, sans la nécessité d'un séparé PROMPT_COMMAND.
user1686
la source
1
Cela fournit un correctif partiel; la longueur de ligne est détectée correctement maintenant, mais cela ne résout pas le problème avec l'écriture de retour à la ligne sur l'invite.
Chris R
1
Chris R: J'ai essayé votre invite et je viens de remplacer tout '\[[par '\[\e[travaillé en bash sur Ubuntu 12.04. L'échappement de couleurs (et d'autres parties non pertinentes à la taille de l'invite) \[...\]m'a également aidé, mais j'ai une PS1 beaucoup plus complexe que vous (avec du texte aligné à droite sur la même ligne que l'invite et du texte en bas à droite) coin). Il a corrigé à la fois les problèmes d'emballage précoce et de chevauchement.
TWiStErRob