¿Cómo soluciono el ajuste rápido del color bash?

9

He definido un indicador de bash (usando PROMPT_FUNCTION) así:

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 general, esto me da un mensaje de varias líneas que muestra información de estado de hg, así como mi virtualenv actual, con este aspecto (sin color):

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

El problema es que esto está enredado con el cálculo de la longitud de la solicitud (¡creo!) Y está causando problemas extraños de ajuste de terminales y colocación del cursor. Por ejemplo, en un terminal de 80 caracteres, aquí está el mensaje que veo (el carácter rodeado por ** es la ubicación del cursor):

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

En terminales lo suficientemente anchos como para mostrar la solicitud, el ajuste de línea ocurre mucho antes de lo que debería; aquí está la mayor cantidad de texto que puedo caber en la primera línea del indicador en una ventana de terminal de 108 caracteres de ancho (nuevamente, el ** marca la ubicación de mi cursor):

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

Cuando la línea se ajusta, sobrescribe la solicitud. Sin embargo, la segunda línea de entrada corre directamente al borde del terminal y luego se ajusta correctamente.

Entonces, claramente algo está jugando con el ancho de la solicitud. ¿Cómo puedo hacer que bash determine la longitud de la cadena PS1 no de acuerdo con los códigos de escape ANSI, sino de acuerdo con la longitud real que se muestra en el mensaje?

Chris R
fuente

Respuestas:

21

bashse utiliza \[ \]para determinar la "longitud mostrada": el texto entre esos dos escapes se considera no imprimible y no se cuenta en la longitud total; todo lo demás es

Parece que hay un problema con sus variables: en bright='\[[01m\]'realidad no incluye un carácter ESC, por lo que [01mse imprime como texto normal pero no se cuenta en la longitud. Debería ser '\[\e[01m\]'. Lo mismo para todas las demás variables.


Relacionado:

  • en Bash, puede poner \$(hg_status)a $PS1directamente, sin la necesidad de una por separado PROMPT_COMMAND.
usuario1686
fuente
1
Eso proporciona una solución parcial; la longitud de la línea se detecta correctamente ahora, pero no soluciona el problema con la escritura de la primera línea sobre el indicador.
Chris R
1
Chris R: Intenté su solicitud y simplemente reemplacé todo '\[[con '\[\e[trabajado en bash en Ubuntu 12.04. Los colores de escape (y algunas otras partes irrelevantes para el tamaño del mensaje) \[...\]también me ayudaron, pero tengo una PS1 mucho más mucho más compleja que usted (con el texto alineado a la derecha en la misma línea que el mensaje y el texto en la parte inferior derecha esquina). Solucionó los problemas de envoltura temprana y de envoltura superpuesta.
TWiStErRob