Bagaimana cara memperbaiki pembungkus bash prompt warna saya?

9

Saya telah mendefinisikan bash prompt (menggunakan PROMPT_FUNCTION) seperti:

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

Secara umum, ini memberi saya prompt multi-baris yang menampilkan beberapa info status hg serta virtualenv saya saat ini, tampak (tanpa warna) seperti ini:

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

Masalahnya adalah, ini mengacaukan dengan perhitungan panjang prompt (saya pikir!) Dan menyebabkan masalah pembungkus terminal yang aneh dan penempatan kursor. Sebagai contoh, di terminal 80-char, inilah prompt yang saya lihat (karakter ** --round adalah lokasi kursor):

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

Di terminal yang cukup lebar untuk menampilkan prompt, pembungkus garis terjadi jauh lebih awal dari yang seharusnya; inilah teks terbanyak yang dapat saya muat di baris pertama prompt di jendela terminal 108-char-wide (sekali lagi, ** menandai lokasi kursor saya):

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

Ketika garis membungkus, itu menimpa prompt. Input baris kedua berjalan tepat ke tepi terminal, dan kemudian membungkus dengan benar.

Jadi, jelas ada sesuatu yang mengacaukan lebar prompt. Bagaimana saya bisa menyebabkan bash untuk menentukan panjang string PS1 tidak sesuai dengan kode escape ANSI, tetapi menurut panjang aktual prompt yang ditampilkan?

Chris R
sumber

Jawaban:

21

bashmenggunakan \[ \]untuk menentukan "panjang yang ditampilkan": teks antara kedua lolos dianggap tidak dapat dicetak dan tidak dihitung dalam total panjang; yang lainnya.

Tampaknya ada masalah dengan variabel Anda: bright='\[[01m\]'sebenarnya tidak menyertakan karakter ESC, jadi [01mdicetak sebagai teks normal tetapi tidak dihitung dalam panjangnya. Seharusnya begitu '\[\e[01m\]'. Sama untuk semua variabel lainnya.


Terkait:

  • di Bash, Anda dapat menempatkan \$(hg_status)untuk $PS1langsung, tanpa perlu terpisah PROMPT_COMMAND.
pengguna1686
sumber
1
Itu memberikan perbaikan parsial; panjang baris terdeteksi dengan benar sekarang, tetapi itu tidak memperbaiki masalah dengan penulisan baris pertama atas prompt.
Chris R
1
Chris R: Saya mencoba prompt Anda dan hanya mengganti semua '\[[dengan '\[\e[bekerja di bash di Ubuntu 12.04. Meloloskan warna (dan beberapa bagian lain yang tidak relevan untuk diminta) juga \[...\]membantu saya, tetapi saya memiliki PS1 yang jauh lebih kompleks daripada Anda (dengan teks rata kanan pada baris yang sama dengan prompt dan teks di kanan bawah sudut). Itu memperbaiki kedua pembungkus awal dan masalah pembungkus yang tumpang tindih.
TWiStErRob