I have a script, that when run sometimes/often outputs an "unescaped" ANSI escape sequence when encountering this line:
vim -X -u NONE -c "helptags ~/.vim/plugged/vim-fugitive/doc" -c q
The result looks like this:
I have no idea why this happens, as running the command on its own seems to never produce this "garbage". It only ever happens if the line is run; commenting it out removes the issue. Even weirder is the fact that it sometimes does not happen. It could be good, then I do something and it appears. The output of running the script is fine. Once it manifests, though, it seems persistent (* not true, see below) ... opening another terminal tab will usually show the problem.
Any idea what is happening here? Is vim picking up no some terminal setting ($TERM
?) and interfering with the output? Or is there something else going on?
My utility functions for colored output is here, should it matter.
EDIT:
- It turns out that changing the
PS1
prompt to something like$
made the issue go away when it materialized, but re-instating the prompt to the colorful one did not bring the issue back, so I have a hard time finding some determinism here.
PS1 prompt setup is done here:
set_prompt(){
local user=$(green "\u")
local host=$(dark_yellow "\h")
local workdir=$(pink "\w")
local gitbranch=$(dark_red \$\(__git_ps1 "\(%s\)" \))
local at=$(dark_grey at)
local in=$(dark_grey in)
export PS1="\n${user} ${at} ${host} ${in} ${workdir} ${gitbranch}"$'\n\$ '
}
# Now set it. If any of these colors are later overridden, then just rerun `set_prompt`
set_prompt
and uses these utility functions and variables:
# Color escape codes @see http://misc.flogisoft.com/bash/tip_colors_and_formatting
# Use \033 instead of \e. Workes better across platforms
# \e works in PS1 prompts, but not other places
c_X_reset_all='\033[0m' #stop code for color escape
c_X_bold='\033[21m'
c_X_reset_bold='\033[21m'
c_green='\033[01;32m'
c_blue='\033[01;34m'
c_pink='\033[01;35m'
c_dark_grey='\033[90m'
c_dark_yellow='\033[38;5;178m'
c_dark_red='\033[38;5;196m'
green(){
echo -n -e ${c_green}$@${c_X_reset_all}
}
blue(){
echo -n -e ${c_blue}$@${c_X_reset_all}
}
pink(){
echo -n -e ${c_pink}$@${c_X_reset_all}
}
dark_grey(){
echo -n -e ${c_dark_grey}$@${c_X_reset_all}
}
dark_yellow(){
echo -n -e ${c_dark_yellow}$@${c_X_reset_all}
}
dark_red(){
echo -n -e ${c_dark_red}$@${c_X_reset_all}
}
Prompt (pre-changes)
This is the prompt before implementing the changes from the comments:
$ perl -e 'print quotemeta($ENV{PS1})'
\\n\[01\;32m\\u\[0m\ \[90mat\[0m\ \[38\;5\;178m\\h\[0m\ \[90min\[0m\ \[01\;35m\\w\[0m\ \[38\;5\;196m\$\(__git_ps1\ \\\(\%s\\\)\ \)\[0m\
\\\$\
You can see all the \033
bits being gone and replaced with \
. That is because it is the octal representation of the ESC character (27 in decimal, 1B in hex) and is now shown as \
in the output (\033[
becomes \]
).
Prompt (after introducing escape sequences)
This seems to have fixed the issue
The comments suggested introducing escape sequences around non-printable characters. That seems to have changed things a bit, as the ESC characters are no longer being replaced:
$ perl -e 'print quotemeta($ENV{PS1})'
\\n\\\[\\033\[01\;32m\\\]\\u\ \\\[\\033\[90m\\\]at\ \\\[\\033\[38\;5\;178m\\\]\\h\ \\\[\\033\[90m\\\]in\ \\\[\\033\[01\;35m\\\]\\w\ \\\[\\033\[38\;5\;196m\\\]\(master\)\\\[\\033\[00m\\\]\
\\\$\
PS1='$ '
and then try the command again? Is the terminal still garbled? If so, you probably have a syntax error in your PS1 variable.\[
and\]
around all non-printing characters such as color codes. It's kind of hard to get exactly what your PS1 is from your code (this approach makes for clean, readable code, but it's tricky to see what the final PS1 will be), but tryprintf '%s\n' "$PS1"
and look for non-printing characters (color codes, most likely) that are not in\[ \]
.