Colorized Output Breaks Linewrapping with Readline

Colorized output breaks linewrapping with readline

I always throw this string extension in when I need to colorize strings for console. The problem in your code seems to be the terminator, there should be just one zero "\e[0m".

# encoding: utf-8
class String
def console_red; colorize(self, "\e[1m\e[31m"); end
def console_dark_red; colorize(self, "\e[31m"); end
def console_green; colorize(self, "\e[1m\e[32m"); end
def console_dark_green; colorize(self, "\e[32m"); end
def console_yellow; colorize(self, "\e[1m\e[33m"); end
def console_dark_yellow; colorize(self, "\e[33m"); end
def console_blue; colorize(self, "\e[1m\e[34m"); end
def console_dark_blue; colorize(self, "\e[34m"); end
def console_purple; colorize(self, "\e[1m\e[35m"); end

def console_def; colorize(self, "\e[1m"); end
def console_bold; colorize(self, "\e[1m"); end
def console_blink; colorize(self, "\e[5m"); end

def colorize(text, color_code) "#{color_code}#{text}\e[0m" end
end

puts "foo\nbar".console_dark_red

Colorized readline prompt breaks control-a

Mac OS X uses the NetBSD editline library, which includes a partial compatibility implementation of readline.

It appears that an attempt was made to add readline's feature of allowing the user to bracket terminal control sequences in the prompt using the characters RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE (defined as '\1' and '\2' respectively in readline.h). Unfortunately, due to a small typo, the feature is never enabled in rl_initialize.

As I read the code (I haven't tested this), the fix would be to change line 327 of readline.c [see note 1] from:

el_set(e, EL_PROMPT, _get_prompt, RL_PROMPT_START_IGNORE);

to:

el_set(e, EL_PROMPT_ESC, _get_prompt, RL_PROMPT_START_IGNORE);

That would require you to find the source code for libedit, make that trivial change, reconfigure and recompile it, and then install it. I don't have a Mac so I can't guide you through that process. (See Note 1 for links to source repositories which might be useful.)

Another solution would be to use the GNU readline library in your project. It's apparently available in MacPorts, so if you use that, it should be easy enough to install.



Notes:

  1. I got that line number from this OS X source repository. In the head revision of the NetBSD distribution, it's at line 337. But it should be easy enough to find by searching for EL_PROMPT. Just make sure that the symbol EL_PROMPT_ESC is defined in histedit.h; if it isn't, the version of the editline library you've found is probably too old.

Bash PS1 prompt breaks line wrapping when generating ANSI escapes by an external program

Note first that \[ and \] are interpreted by Bash itself, not the console, so they must be explicitly present in the PS1 value, not in the output of the program generating actual prompt.

Now, you want the non-escape chars to count, while colors are not to be counted. For this, you can modify your program to have two modes:

  • Colored output (for actual prompt)
  • Text-only output (for character counting)

Then you can use something like

PS1='$(/tmp/test)\[\r$(/tmp/test c)\]'

which would work for code modified to the following:

void PrintPrompt(string cwd, string hostname, string username, bool colors){
string cwdString = cwd;
cout << (colors ? WHITEDGRAY : "") << username <<
(colors ? DGRAYORANGE : "") << ARROW << " " <<
(colors ? WHITEORANGE : "") << hostname <<
(colors ? ORANGEDGRAY : "") << ARROW << " " <<
(colors ? WHITEDGRAY : "") << cwd << (colors ? DGRAYDEFAULT : "") <<
ARROW << (colors ? RESET : "") << endl;
}

with colors being passed as e.g. argc>1.

We use the \r escape sequence to go to the beginning of the line, enabling us to overwrite our already printed non-colored text with the fancy-colored one, making Bash think that the additional text and escape sequences (including the carriage return) don't take any space.

Screenshot:

screenshot of resulting output



Related Topics



Leave a reply



Submit