troglobit / editline

A small replacement for GNU readline() for UNIX
https://troglobit.com/projects/editline/
Other
281 stars 58 forks source link

Prompt not redisplayed after displaying completion possibilities #51

Open minfrin opened 3 years ago

minfrin commented 3 years ago

I have a simple application that uses editline v1.17.1, and returns 4 possible completions on the empty string.

The 4 completions are displayed correctly, however the prompt is not re-displayed, ending up with this:

Run cli:

(device) minfrin@localhost.localdomain /> 

Press tab once, you get 4 completions as expected, but no redisplay of the prompt:

(device) minfrin@localhost.localdomain /> 
services  system    exit      quit

Type 's' followed by tab, and you get 2 completions as expected, but no redisplay of prompt, and the 's' character appears twice:

(device) minfrin@localhost.localdomain /> 
services  system    exit      quit
s
services  system
ss

Type 'e' followed by tab, giving you the unique option 'services'. This is displayed, but the prompt is still missing, and we still have a stray s:

(device) minfrin@localhost.localdomain /> 
services  system    exit      quit
s
services  system
sservices 

Press 'enter' despite the corrupt prompt, and the line is returned correctly and the prompt redisplayed:

(device) minfrin@localhost.localdomain /> 
services  system    exit      quit
s
services  system
sservices 
(device) minfrin@localhost.localdomain /services> 

The prompt is "(device) %s@%s /%s> " and contains no special characters.

Is this a known issue?

Apple Terminal on Big Sur, cli running on CentOS8.

minfrin commented 3 years ago

Hmmm...

What made the problem go away was to set the prompt to a single unchanging string, and pass the string:

        result = readline(prompt);

It seems that references to prompt are kept around internally after readline() returns. If an attempt is made to clean up the prompt or regenerate the prompt, chaos follows. I suspect somewhere inside the prompt needs to be strdup'ed.

troglobit commented 3 years ago

In the original code there's no way to free stuff, so it's made to use a static string, or only change the contents of prompt between calls to readline().

Note: this is a very small an limited library. If you need anything more advanced I suggest looking at libedit (or readline) instead).

minfrin commented 3 years ago

Alas in this case I'm only making changes to the contents of prompt in between calls to readline(), but it's not working in this case.

If I hack the code to not free prompt (ie leak), the problem disappears.

Ideally if editline needs to keep prompt past the readline() call, it should strdup it (and then free). Alternatively, store the prompt length only if that is all that's needed.

At this stage we support libedit, but this is not available where we want to run. Readline is not an option because of GPL.