3

The following program prints a colorized readline prompt. It breaks control-a (the cursor ends up much farther to the right than it should be):

#include <readline/readline.h>
#include <readline/history.h>

#define CYELLOW "\001\e[0;31m\002"
#define RESET   "\001\e[0m\002"

int main(int argc, char **argv)
{
    readline(CYELLOW "prompt> " RESET);
    return 0;
}

control-a works when I call readline() without a colorized prompt:

readline("prompt> ");

I'm using Mac OS X 10.9.4. Here's the output of otool:

/usr/lib/libreadline.dylib:
    /usr/lib/libedit.3.dylib (compatibility version 2.0.0, current version 3.0.0)
    /usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1

There are a couple of stackoverflow questions that seem to touch on this:

Both of them mention that color markers need to be bracketed by \001 and \002. I followed those instructions but control-a is still broken.

Community
  • 1
  • 1
Elector Niklas
  • 151
  • 1
  • 9
  • 1
    I haven't been able to reproduce your issue (using `libreadline6-dev`, 6.3-4ubuntu2 on Linux Mint). I get a red prompt using your code, but Ctrl+A works fine for me with and without coloring. I did get some wrapping issues with the code in "Colorized output breaks linewrapping with readline", so at least his issue I could reproduce. Maybe adding library version and other details could help tracking it down. – anol Jul 09 '15 at 23:35
  • At the shell level, you need to put `\[` and `\]` around any non-printing escape sequences in the prompt string. See http://www.gnu.org/software/bash/manual/bashref.html#Controlling-the-Prompt. I'm sure there's some equivalent for direct readline use but I don't know it right off. – R.. GitHub STOP HELPING ICE Jul 09 '15 at 23:42
  • @anol, thanks for your comment. I tried to reproduce the issue on my Ubuntu Linux machine, and was unable to -- control-a works correctly. The machine that causes me issues is my Mac (running 10.9.4). I don't believe I've installed a new version of libreadline on it, so it looks like a stock library. Here's the output of otool: /usr/lib/libreadline.dylib: /usr/lib/libedit.3.dylib (compatibility version 2.0.0, current version 3.0.0) /usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1 – Elector Niklas Jul 10 '15 at 01:38
  • the column counting has nothing to do with C, Ruby, python, ect. The column counting/line wrapping is strictly a function of the terminal driver. Commands can be given to the terminal driver, via the command line, if not otherwise, to tell the terminal driver how to handle escape sequences. – user3629249 Jul 10 '15 at 01:42
  • @user3629249: That's not really the case. It is true that the terminal emulator (not driver) performs column counting and line wrapping, etc. But it doesn't report the column position back to the process writing to the terminal, so if that process needs to know where on the screen a particular character is being displayed, it needs to track column positions itself. That's what makes writing libraries like readline/editline so annoying. – rici Jul 10 '15 at 05:48

1 Answers1

6

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.
Community
  • 1
  • 1
rici
  • 234,347
  • 28
  • 237
  • 341
  • Would it be possible to replace the native Mac library with a fixed library somehow? Or can I statically link a fixed version into a specific binary somehow? I'm trying to use colors in my mysql prompt and this issue is making it very inconvenient. I don't have the expertise to recompile mysql with readline (google suggests it isn't supported anymore). – stefansundin Apr 04 '18 at 21:25