bash:提示在视觉上被破坏

bash:提示在视觉上被破坏

我的配置的想法PS1是显示一些扩展信息,例如 Mercurial 或 Git 存储库状态、命令执行时间等。提示符被分成两行,因为它产生太多字符而无法放入一行。这是我的PS1.bashrc不确定这里是否需要整个源代码):

function prompt_status {
        local color_app="\e[1;38;5;214m"
        local color_branch="\e[1;38;5;32m"
        local color_revision="\e[0;38;5;64m"
        if git rev-parse --is-inside-work-tree &> /dev/null; then
                local branch="$(git rev-parse --abbrev-ref HEAD | tr -d '\n')"
                local revision="$(git rev-parse HEAD | tr -d '\n')"
                echo -ne $color_app"git "$color_branch"$branch "$color_revision"($revision)"
        elif hg status &> /dev/null; then
                local branch="$(hg branch | tr -d '\n')"
                local revision_number="$(hg identify -n | tr -d '\n')"
                local revision="$(hg parent --template '{node}' | tr -d '\n')"
                echo -ne $color_app"hg "$color_branch"$branch "$color_revision"($revision_number:$revision)"
        else
                return
        fi
        echo -e " \e[0m"
}

function prompt_return_value {
        RET=$?
        if [[ $RET -eq 0 ]]; then
                echo -ne "" #echo -ne "\e[32m$RET\e[0m"
        else
                echo -ne "\e[1;37;41m$RET\e[0m "
        fi
}

function timer_start {
        timer=${timer:-$SECONDS}
}

function timer_stop {
        seconds_elapsed=$(($SECONDS - $timer))
        unset timer
}

function prompt_seconds_elapsed {
        local c;
        local t=${seconds_elapsed}s
        if [ $seconds_elapsed -ge 60 ]; then
                c=196
                t=$(format_seconds $seconds_elapsed)
        elif [ $seconds_elapsed -ge 20 ]; then
                c=214
        elif [ $seconds_elapsed -ge 10 ]; then
                c=100
        elif [ $seconds_elapsed -ge 5 ]; then
                c=34
        elif [ $seconds_elapsed -ge 1 ]; then
                c=22
        else
                return
        fi
        echo -ne "\e[0;38;5;${c}m${t} \e[0m"
}

function format_seconds {
        ((h=${1}/3600))
        ((m=(${1}%3600)/60))
        ((s=${1}%60))
        printf "%02d:%02d:%02d\n" $h $m $s
}

trap 'timer_start' DEBUG
PROMPT_COMMAND=timer_stop

export PS1="\n\e[1;38;5;106m\u@\h \e[0;38;5;136m\w\[\e[0m\]\n\$(prompt_return_value)\$(prompt_seconds_elapsed)\$(prompt_status)\$ "

问题在于,当终端窗口宽度较小时,提示看起来会损坏。这是我从 80 列中得到的结果:

username@some-very-long-hostname ~/tmp/d
06a14b06cac) $ 9866c9d0d26d2b27063a89ee1c330

就像包裹在第二行导致完全混乱(参见中间的 $ 符号)。对于较大的终端列数(例如 120),它几乎完美地工作:

username@some-very-long-hostname ~/tmp/d
hg default (0:69866c9d0d26d2b27063a89ee1c3306a14b06cac) $

我还注意到,在终端行末尾添加更多文本会导致与上面 80 列描述的效果非常相似的问题。问题是:是否bash错误地处理新行或“太长” PS1

谢谢。


更新

这个问题并不完全重复为什么当我浏览历史记录时,我的 bash 提示符会出现问题?。经过与@AdamKatz的一些讨论后,似乎零长度输出转义\[并且']仅当它们字面地放入PS1字符串中时才起作用,但是当从函数返回时它们似乎不起作用,导致在终端上出现未转义。

答案1

对于多行提示(包括换行时,包括来自命令的提示),您需要将颜色代码括在转义的方括号中(喜欢\[$color\])。

此示例是绿色的,user@hostname:workingdir $然后恢复为无色:

PS1='\[\e[1;32m\]\u@\h:\w \$\[\e[0;0m\]'

如果您看到文字\[[出现在提示中,则它可能在被解释为提示扩展之前从 扩展\[为。[在这种情况下,\001不断\[尝试\002\]你应该就可以开始了。如果您没有运气\e,请尝试\033一下。这些八进制代码更易于移植,因为它们会通过(类似的程序sed不会尝试转义或解释它们)。

相关内容