troglobit / editline Goto Github PK
View Code? Open in Web Editor NEWA small replacement for GNU readline() for UNIX
Home Page: https://troglobit.com/projects/editline/
License: Other
A small replacement for GNU readline() for UNIX
Home Page: https://troglobit.com/projects/editline/
License: Other
I am looking for a line editing library that I can use together with an event loop. That means no blocking readline function and no direct access to stdin.
Instead, I would call readline() with one or more the user pressed, readline should process these keys and return.
Is this possible with editline, or if not, could you give an estimate on how much work it would be to implement something like this?
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) [email protected] />
Press tab once, you get 4 completions as expected, but no redisplay of the prompt:
(device) [email protected] />
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) [email protected] />
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) [email protected] />
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) [email protected] />
services system exit quit
s
services system
sservices
(device) [email protected] /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.
The command ./configure --disable-eof
does not bite.
I use editline with mpi and have the loop in rank 0. Everything seems OK except the prompt message.
An extra null pointer check is not needed in functions like the following.
When readline()
is running in a thread waiting for input from tty, terminal is prepped, the function blocks until got an "end" (e.g. EOL, EOF, SIGINT or etc) from tty. In case when another thread decided to no longer accept input from tty (e.g. timeout or got a signal from outside), we need a way to gracefully end readline()
and restore terminal, rather than waiting for an end. We can't forcefully end the thread because terminal won't be restored.
Editline currently uses a "one byte per column" heuristic, and one way that breaks down is when it encounters colored prompts. The way readline (and libedit) handles this issue is by having the program tell it what parts of the prompt don't count into the width calculation: \1
(RL_PROMPT_START_IGNORE) starts the width-ignore area and \2
(RL_PROMPT_END_IGNORE) ends it.
See https://github.com/cdesjardins/libedit/search?q=RL_PROMPT_START_IGNORE for how it works in NetBSD libedit.
Newlib (and possibly other C standard library implementations) may return a value greater than nbyte
from read()
without loss of input characters in editline's case. In this scenario the return statement for rl_getc()
improperly returns EOF instead of the character typed into the terminal by the user.
Using the readline
library, one can have this rl_bind_key('\t', rl_insert);
which disables readline
from displaying files that exist on the current working directory when the user presses TAB.
I am now trying to get ride of readline
and use the editline
library instead. I found out function el_bind_key
(which looks like it's the replacement for function rl_bind_key
) but not sure how the second parameter of this function should look like.
Basically, I want to disable editline
displaying files that exist on the current working directory when the user presses TAB.
I am using the mysql client from which comes with editLine in my distribution:
$ mysql --version
mysql Ver 14.14 Distrib 5.7.17, for Linux (x86_64) using EditLine wrapper
I would not mind if it was a in-place replacment behaving similar to readline. Yet certain emac-like keybindings from readline, I am very much used to, don't work anymore, breaking my habitual workflow.
I am very much used to delete the last word by Ctrl + W. Yet via editline, it deletes to the beginning of the line instead just one word back.
I tried adding .editrc
with the content:
bind ^W backward-delete-word
Yet it doesn't work.
How can I bind keys to my liking, and how can I get Ctrl + W to delete one word backwards?
It seems LICENSE is completely custom and similar to Zlib License.
README says:
Copyright 1992,1993 Simmule Turner and Rich Salz
All rights reserved.
This software is not subject to any license of the American Telephone
and Telegraph Company or of the Regents of the University of California.
Permission is granted to anyone to use this software for any purpose on
any computer system, and to alter it and redistribute it freely, subject
to the following restrictions:
1. The authors are not responsible for the consequences of use of this
software, no matter how awful, even if they arise from flaws in it.
2. The origin of this software must not be misrepresented, either by
explicit claim or by omission. Since few users ever read sources,
credits must appear in the documentation.
3. Altered versions must be plainly marked as such, and must not be
misrepresented as being the original software. Since few users
ever read sources, credits must appear in the documentation.
4. This notice may not be removed or altered.
But the text does not resemble Apache-1.0, Apache-1.1, Apache-2.0.
Please, can you state clearly it's licensed under Apache-2.0? Maybe update LICENSE file?
Hi! I'm interested in this library but am wondering how it compares to https://github.com/antirez/linenoise. A quick review leads me to believe linenoise is less mature and supports fewer calls, but is smaller. Is that correct?
I would like to point out that an identifier like "__EDITLINE_H__
" does eventually not fit to the expected naming convention of the C++ language standard.
Would you like to adjust your selection for unique names?
Currently Debian distributes what it seems to be a very old version in comparison (1.12), based solely in the version numbering and release date, I believe is one of the original sources that was merged, based in the readme description. Is there any particular reason why is that? Given that the required build files for such package are already part of this repo (and they do work, recently tested in debian bullseye), is it just a matter of coordination with a debian maintainer? Or is there something else?.
Personally I have a particular interest in this package because is a dependency of Nix and the packaging effort of nix in debian would benefit itself by having a recent editline in the official repos, currently they have opted for trying to implement readline support in nix PR1/merged PR2/pending instead of packaging this library. At this time, Nix doesn't have the autocomplete functionality for the readline
build option and it seems that the the Nix maintainers are even reconsidering the idea of allowing the extra option to support readline
and stick only to editline
.
Not sure if this is the best place to get more context. But I suppose it would be better to have this discussion in some place that can be publicly found for any future reference.
Thanks.
Steps to reproduce:
Maybe this change can fix it?2b75e9e#diff-532aa92b0f7db9561ed48bb41ec87506R694
The title says it all - thanks! :)
Readline and libedit both use Control-V to indicate a verbatim character (including a control char). Editline should somehow make it a thing.
In a project of mine, I wrote a completer function that does only return strdup("\t");
(to disable completion of filenames, which are meaningless for my project). However, this prints ^I
instead of a tab as it should. When I try to return something like strdup("hello world")
, it prints hello\ world
instead. I assume that the issue is due to the very questionable implementation of CTL()
and META()
. It seems to me that the proper way of doing this is to use a type larger than a char, where the modifers are stored in higher bits. Of course this will require changing the public interface to libeditline, so maybe the current functions should be deprecated (but still remain), and new, proper functions should be added.
I just did some digging and found out that the string returned from my completer function is passed to insert_string()
, which passes it to tty_string()
, and then each character goes to tty_show()
, which does use the ISCTL()
and ISMETA()
macros to incorrectly convert a tab into ^I
. Also, it is line 1385 of editline.c which adds a newline before spaces. No idea why it does that though.
( refering to the sentence "The libraries have much in common, but the latter is heavily refactored and also relies on ncurses, whereas this library only uses termios from the standard C library." in README)
at least the libedit version used in sabotage linux, worked fine when linked against stallmann's original termcap library (before i changed the package to use netbsd's curses[0] instead): sabotage-linux/sabotage@9b3107c
#include <stdlib.h>
#include <stdio.h> // This line should put before #include <editline.h>, or it will be failed to compile.
#include <editline.h>
int main(void)
{
char *p;
while ((p = readline("CLI> ")) != NULL) {
puts(p);
free(p);
}
return 0;
}
without #include <stdio.h>
, the error message
$ g++ test.cc -I$HOME/mylib/include -L$HOME/mylib/lib -leditline
/mylib/include/editline.h:87:8: error: ‘FILE’ does not name a type
extern FILE *rl_instream; /* The stdio stream from which input is read. Defaults to stdin if NULL - Not supported yet! */
^~~~
In file included from test.cc:3:0:
mylib/include/editline.h:88:8: error: ‘FILE’ does not name a type
extern FILE *rl_outstream; /* The stdio stream to which output is flushed. Defaults to stdout if NULL - Not supported yet! */
test.cc: In function ‘int main()’:
test.cc:10:9: error: ‘puts’ was not declared in this scope
puts(p);
^~~~
On editline-1.17.1:
co/nix » echo '1+1' | LD_PRELOAD=result/lib/libreadline.so nix repl --quiet | cat
nix-repl> 1+1
2
co/nix » echo '1+1' | nix repl --quiet | cat
Failed tcsetattr(TCSADRAIN): Inappropriate ioctl for device
Failed tcsetattr(TCSADRAIN): Inappropriate ioctl for device
2
Confirmed by inspection of the code: when !isatty()
, prompts aren't printed.
gdb 7.6 seems to be the most elaborate readline user in sabotage linux, but it can be tricked, to link against libedit instead of readline, and i hoped as well against editline...
Here's a list of missing functions:
checking termcap.h usability... no
checking termcap.h presence... no
checking for termcap.h... no
checking for termio.h... no
checking for termios.h... yes
...
make[2]: Entering directory `/src/build/editline/editline-1.15.1/examples'
libtool: link: gcc -I../src -I../include -fdata-sections -ffunction-sections -Os ...
/bin/ld: cannot find -ltermcap
and with --disable-termcap:
libtool: link: gcc -I../src -I../include -fdata-sections -ffunction-sections -Os
../src/.libs/libeditline.a(editline.o): In function `rl_reset_terminal':
editline.c:(.text.rl_reset_terminal+0x57): undefined reference to `tgetent'
editline.c:(.text.rl_reset_terminal+0x68): undefined reference to `tgetstr'
editline.c:(.text.rl_reset_terminal+0x8d): undefined reference to `tgetnum'
editline.c:(.text.rl_reset_terminal+0x9d): undefined reference to `tgetnum'
collect2: error: ld returned 1 exit status
From input mode, after typed anything, press Ctrl+R to enter search mode, press ENTER directly, then the whole screen got cleared. (terminal=screen).
Hi,
I am using editline in a project where I am also enabling address sanitizer. I get a buffer overrun error in completion.c:203. I am not quite sure what the correct way of fixing the issue is, but it seems as the memcpy is trying to read beyond the allocated memory in the av[0] array. Reducing the size of the copy (+1 instead of +2 on line 200) resolves that particular issue, but I can not guarantee that it will not break anything else.
Is it possible editline only supports UTF8?
As you may know, mysql now only supports editline and this causes problems with german umlaut characters on systems with LC_CTYPE=de_DE or de_DE.iso88591 instead of de_DE.utf8
This shows up on macOS 10.13 (and maybe others).
Lines 178 to 182 in 534b389
I believe the realloc should happen before the character is added to the array. Once I made that change, the SIGSEV went away.
Note: The array of items to display had 122 entries, longest 46 (3 columns).
Update: After taking another look, changing the >
to a >=
will do the trick.
Would you like to add more error handling for return values from functions like the following?
When I press CTRL+Z
to suspend the process that runs editline
(I'm in Linux), it doesn't react. FYI, when using the readline
library everything works as expected (i.e. the process would have been suspended and the prompt returns to the terminal). How can this be fixed? Thanks!
This is not an issue with the compilation of the library, more of an issue with that I cannot find where these headers reside, I cannot find much information about them, but it compiles perfectly fine.
#include <sgstat.h>
#include <modes.h>
Any idea if UTF support can be added to this lib?
Preferably without depending on locale stuff from glibc
In src/sysunix.c there is this:
#ifndef HAVE_STRDUP
/* Return an allocated copy of a string. */
char *strdup(const char *p)
{
char *new = malloc(sizeof(char) * strlen(p));
This forgets to malloc the terminating NUL for the string and causes undefined behavior for the subsequent strcpy.
This should be
malloc(strlen(p) + 1);
Note that multiplying by sizeof(char) is considered silly, since it is 1 by definition in the C Standard.
Hi
I've just been looking at this library for use in a simple CLI application.
I see that there is some support for supplying custom auto-complete functions so that (for example) the application can auto-complete commands from a fixed set of command names.
When I try out the example cli application, I see that auto-complete searches the same list with each and every argument.
What I'd like to do is vary the auto-complete function depending on the arguments already entered by the user so that (for example) auto-completing the second argument in a command searches one list if the first argument is 'a', and a different list if the first argument is 'b'.
Is this possible out of the box with this library? Is there a way to obtain the arguments already entered so that auto-complete can be made more context specific?
Thanks
I normally don't still things from github, and I'm sorry if the answer is too obvious. But after cloning, and cd-ing into the editline folder on Fedora I tried the first step. After doing a find for this file in other folders, still nothing.
I try to use alternative API
/* For wcwidth() */
#define _XOPEN_SOURCE 700
#include <locale.h>
#include <ncurses.h>
#include <editline/readline.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
int kurzor;
static int readline_proxy;
static bool readline_proxy_is_valid = false;
char *string = NULL;
/*
* Zkopiruje znak z proxy do readline
*/
static int
readline_getc(FILE *dummy)
{
readline_proxy_is_valid = false;
return readline_proxy;
}
/*
* Touto funkci readline predava vysledek editace
*/
static void
readline_callback(char *line)
{
free(string);
string = NULL;
if (line)
string = strdup(line);
}
/*
* Chceme mit zobrazeni ve vlastni rezii
*/
static void
readline_redisplay()
{
/* do nothing here */
}
/*
* Vrati (zobrazovaci) sirku retezce.
*/
static size_t
strnwidth(const char *s, size_t n)
{
mbstate_t shift_state;
wchar_t wc;
size_t wc_len;
size_t width = 0;
size_t ch_width;
memset(&shift_state, '\0', sizeof shift_state);
for (size_t i = 0; i < n; i += wc_len)
{
wc_len = mbrtowc(&wc, s + i, MB_CUR_MAX, &shift_state);
if (!wc_len)
return width;
if ((wc_len == (size_t) -1) || (wc_len == (size_t) -2))
return width + strnlen(s + i, n - i);
if (iswcntrl(wc))
width += 2;
else if ((ch_width = wcwidth(wc)) > 0)
width += ch_width;
}
return width;
}
int
main()
{
int c = 0;
bool alt = false;
char *prompt = ": ";
setlocale(LC_ALL, "");
initscr();
cbreak();
noecho();
/* ENTER neni \n */
nonl();
/*
* readline vyzaduje neprekodovany vstup tj
* vypnuty keypad a cteni vice bajtovych
* znaku po bajtech (emuluje se binarni
* cteni ze souboru v aktualnim kodovani)
*/
keypad(stdscr, FALSE);
/*
* Instalace hooku - pokud se pouzije rl_getc_function,
* tak by se mel VZDY pouzit i rl_input_available_hook.
*/
rl_getc_function = readline_getc;
rl_redisplay_function = readline_redisplay;
/*
* Nechceme obsluhu signalu v readline, a nechceme tab
* complete (neni nakonfigurovano, hrozi pady.
*/
rl_catch_signals = 0;
rl_catch_sigwinch = 0;
rl_inhibit_completion = 0;
/* Zahajeni editace */
rl_callback_handler_install(prompt, readline_callback);
/* Vlozi vychozi (default) text */
rl_insert_text("Editaci ukonci 2x stisk ESCAPE");
while (1)
{
int cursor_pos;
clear();
mvaddstr(10, 10, rl_prompt);
addstr(rl_line_buffer);
if (string)
{
mvaddstr(12, 6, "text: ");
attron(A_REVERSE);
addstr(string);
attroff(A_REVERSE);
}
/* nastav kurzor */
cursor_pos = strnwidth(rl_prompt, SIZE_MAX) +
strnwidth(rl_line_buffer, rl_point);
move(10, 10 + cursor_pos);
refresh();
get_wch(&c);
/* ignoruj tabelatory */
if (c == '\t')
continue;
if (c == 27)
{
if (alt)
break;
else
alt = true;
}
else
alt = false;
readline_proxy = c;
readline_proxy_is_valid = true;
/* posli echo readline, ze jsou nova data k precteni */
rl_callback_read_char();
}
rl_callback_handler_remove();
endwin();
}
I am able to build this example, but the variables rl_point
and rl_end
are always zero. Unfortunately editline doesn't decode cursor keys or other control keys.
Is this functionality supported? I try to use editline from ncurses application.
tested on FC34
Name : editline
Version : 1.17.1
Release : 3.fc34
Architecture : x86_64
Size : 28 k
Source : editline-1.17.1-3.fc34.src.rpm
Repository : fedora
Summary : A small compatible replacement for readline
URL : https://troglobit.com/projects/editline/
License : HSRL
Description : This is a line editing library for UNIX. It can be linked into almost
: any program to provide command line editing and history. It is call
: compatible with the FSF readline library, but is a fraction of the
: size (and offers fewer features).
I tried to build this library with GCC 11 on Cygwin just now, and it does not compile cleanly:
In file included from editline.c:23:
editline.c: In function 'do_case':
editline.c:497:29: warning: array subscript has type 'char' [-Wchar-subscripts]
497 | if (islower(*p))
| ^~
editline.c:499:32: warning: array subscript has type 'char' [-Wchar-subscripts]
499 | } else if (isupper(*p)) {
| ^~
editline.c: In function 'argify':
editline.c:1878:28: warning: array subscript has type 'char' [-Wchar-subscripts]
1878 | for (c = line; isspace(*c); c++)
| ^~
editline.c:1885:22: warning: array subscript has type 'char' [-Wchar-subscripts]
1885 | if (!isspace(*c)) {
| ^~
CC libeditline_la-complete.lo
In file included from complete.c:23:
complete.c: In function 'rl_find_token':
complete.c:281:35: warning: array subscript has type 'char' [-Wchar-subscripts]
281 | if (isspace(rl_line_buffer[pos])) {
| ~~~~~~~~~~~~~~^~~~~
complete.c:289:47: warning: array subscript has type 'char' [-Wchar-subscripts]
289 | while (pos >= 0 && !isspace(rl_line_buffer[pos])) {
| ~~~~~~~~~~~~~~^~~~~
A "char" subscript can actually be a big deal for characters with the 8th bit set (will get converted to a negative "int"), so the warnings do not look great.
Any chance you can fix these please (e.g. by adding explicit (unsigned char)
casts where necessary)?
Thanks.
P.S. BTW the "Build & Install" instructions in README.md call for running configure
but it is not provided in the source tree if cloned directly from github, and it looks like autogen.sh
needs to be executed first in order to actually build configure
-- but that step is missing entirely from the instructions.
So I'm using rl_attempted_completion_function
to add my own keyword completion, but ever since that the filepath completion doesn't work as expected, it will crash with free(): double free detected in tcache 2. I thought it was my problem, so I tried the fileman.c given in the example, but it ended up the same.
Comment out the binding to rl_attempted_completion_function, then it will work normally. So I guess there's something wrong with executing that function.
If you input ./ <tab>, then it will crash, but if you quote the path it works, e.g "/usr <tab>, it will show /usr/lib.
System: Lubuntu 20.04
GCC Version: 9.3.0
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.