jart / bestline Goto Github PK
View Code? Open in Web Editor NEWANSI Standard X3.64 Teletypewriter Command Session Library
License: Other
ANSI Standard X3.64 Teletypewriter Command Session Library
License: Other
We are using https://github.com/AmokHuginnsson/replxx/ in ClickHouse.
It is also a self-contained alternative to readline
with many needed features comparing to linenoise
.
How does bestline
compares to replxx
in terms of feature set and usability?
milovidov@milovidov-desktop:~/work/bestline$ clang++ --version
clang version 11.0.0 (https://github.com/llvm/llvm-project.git f5df584a5077e726ad851ccfe8496deda3e5ef07)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/local/bin
milovidov@milovidov-desktop:~/work/bestline$ CC=clang make
clang -c -o bestline.o bestline.c
In file included from bestline.c:122:
In file included from /usr/include/termios.h:25:
/usr/include/features.h:314:53: error: invalid token at start of a preprocessor expression
|| (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 1) \
^
/usr/include/features.h:319:48: error: invalid token at start of a preprocessor expression
#if defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 2 || defined _XOPEN_SOURCE
^
bestline.c:213:25: warning: tentative definition of variable with internal linkage has incomplete non-array type 'struct sigaction' [-Wtentative-definition-incomplete-type]
static struct sigaction orig_int;
^
bestline.c:213:15: note: forward declaration of 'struct sigaction'
static struct sigaction orig_int;
^
bestline.c:214:25: warning: tentative definition of variable with internal linkage has incomplete non-array type 'struct sigaction' [-Wtentative-definition-incomplete-type]
static struct sigaction orig_quit;
^
bestline.c:213:15: note: forward declaration of 'struct sigaction'
static struct sigaction orig_int;
^
bestline.c:215:25: warning: tentative definition of variable with internal linkage has incomplete non-array type 'struct sigaction' [-Wtentative-definition-incomplete-type]
static struct sigaction orig_cont;
^
bestline.c:213:15: note: forward declaration of 'struct sigaction'
static struct sigaction orig_int;
^
bestline.c:216:25: warning: tentative definition of variable with internal linkage has incomplete non-array type 'struct sigaction' [-Wtentative-definition-incomplete-type]
static struct sigaction orig_winch;
^
bestline.c:213:15: note: forward declaration of 'struct sigaction'
static struct sigaction orig_int;
^
bestline.c:1107:15: warning: implicit declaration of function 'getdelim' is invalid in C99 [-Wimplicit-function-declaration]
if ((rc = getdelim(&p, &c, '\n', f)) != EOF) {
^
bestline.c:1652:22: error: variable has incomplete type 'struct sigaction'
struct sigaction sa;
^
bestline.c:213:15: note: forward declaration of 'struct sigaction'
static struct sigaction orig_int;
^
bestline.c:1665:13: warning: implicit declaration of function 'sigemptyset' is invalid in C99 [-Wimplicit-function-declaration]
sigemptyset(&sa.sa_mask);
^
bestline.c:1666:13: warning: implicit declaration of function 'sigaction' is invalid in C99 [-Wimplicit-function-declaration]
sigaction(SIGCONT,&sa,&orig_cont);
^
bestline.c:1681:9: warning: implicit declaration of function 'sigaction' is invalid in C99 [-Wimplicit-function-declaration]
sigaction(SIGCONT,&orig_cont,0);
^
bestline.c:1875:43: warning: implicitly declaring library function 'strdup' with type 'char *(const char *)' [-Wimplicit-function-declaration]
history[historylen - 1 - l->hindex] = strdup(l->buf);
^
bestline.c:1875:43: note: include the header <string.h> or explicitly provide a declaration for 'strdup'
bestline.c:2023:26: warning: implicitly declaring library function 'strndup' with type 'char *(const char *, unsigned long)' [-Wimplicit-function-declaration]
ring.p[ring.i] = strndup(p, n);
^
bestline.c:2023:26: note: include the header <string.h> or explicitly provide a declaration for 'strndup'
bestline.c:2742:5: error: unknown type name 'sigset_t'; did you mean '__sigset_t'?
sigset_t omask;
^~~~~~~~
__sigset_t
/usr/include/x86_64-linux-gnu/bits/types/__sigset_t.h:8:3: note: '__sigset_t' declared here
} __sigset_t;
^
bestline.c:2744:22: error: variable has incomplete type 'struct sigaction'
struct sigaction sa;
^
bestline.c:213:15: note: forward declaration of 'struct sigaction'
static struct sigaction orig_int;
^
bestline.c:2748:5: warning: implicit declaration of function 'sigemptyset' is invalid in C99 [-Wimplicit-function-declaration]
sigemptyset(&sa.sa_mask);
^
bestline.c:2749:5: warning: implicit declaration of function 'sigaddset' is invalid in C99 [-Wimplicit-function-declaration]
sigaddset(&sa.sa_mask,SIGINT);
^
bestline.c:2751:5: warning: implicit declaration of function 'sigprocmask' is invalid in C99 [-Wimplicit-function-declaration]
sigprocmask(SIG_BLOCK,&sa.sa_mask,&omask);
^
bestline.c:2751:17: error: use of undeclared identifier 'SIG_BLOCK'
sigprocmask(SIG_BLOCK,&sa.sa_mask,&omask);
^
bestline.c:2752:19: error: use of undeclared identifier 'SA_NODEFER'
sa.sa_flags = SA_NODEFER;
^
bestline.c:2754:5: warning: implicit declaration of function 'sigaction' is invalid in C99 [-Wimplicit-function-declaration]
sigaction(SIGINT,&sa,&orig_int);
^
bestline.c:2758:21: error: use of undeclared identifier 'SIG_UNBLOCK'
sigprocmask(SIG_UNBLOCK,&sa.sa_mask,0);
^
bestline.c:2766:17: error: use of undeclared identifier 'SIG_SETMASK'
sigprocmask(SIG_SETMASK,&omask,0);
^
bestline.c:2797:18: warning: implicit declaration of function 'fileno' is invalid in C99 [-Wimplicit-function-declaration]
if ((!isatty(fileno(stdin)) ||
^
bestline.c:213:25: error: tentative definition has type 'struct sigaction' that is never completed
static struct sigaction orig_int;
^
bestline.c:213:15: note: forward declaration of 'struct sigaction'
static struct sigaction orig_int;
^
bestline.c:214:25: error: tentative definition has type 'struct sigaction' that is never completed
static struct sigaction orig_quit;
^
bestline.c:213:15: note: forward declaration of 'struct sigaction'
static struct sigaction orig_int;
^
bestline.c:215:25: error: tentative definition has type 'struct sigaction' that is never completed
static struct sigaction orig_cont;
^
bestline.c:213:15: note: forward declaration of 'struct sigaction'
static struct sigaction orig_int;
^
bestline.c:216:25: error: tentative definition has type 'struct sigaction' that is never completed
static struct sigaction orig_winch;
^
bestline.c:213:15: note: forward declaration of 'struct sigaction'
static struct sigaction orig_int;
^
15 warnings and 13 errors generated.
make: *** [<builtin>: bestline.o] Error 1
milovidov@milovidov-desktop:~/work/bestline$ ldd --version
ldd (Ubuntu GLIBC 2.31-0ubuntu9.2) 2.31
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
A few suggestions to improve the README; feel free to incorporate any of these if you'd like (or not at all):
Line 17 in 837ea51
dependencies, which means
Line 113 in 837ea51
diacratics → diacritics
Line 124 in 837ea51
There are, however, some differences [...]
Line 149 in 837ea51
"the needed" → "they needed"
Hi,
this might just be my misunderstanding of the way this library deals with interrupts, but the current behaviour seems a bit broken.
When one presses Ctrl+C
, I would expect bestline
to do some cleanup and then re-raise the interrupt for the calling function.
This is not what happens at all.
Currently, when pressing Ctrl+C
, the library seemingly does nothing, though it "eats" the next key press (meaning, the next key press seems to be ignored, but after that everything works as expected again). Only when pressing Ctrl+C
twice, the interrupt is propagated properly and errno is set to EINTR
.
After looking at the source code and seeing that there are signal handlers in place, I tried to track down the issue and I found this in bestline.c:1360
:
rc = read(fd,&c,1);
For some reason, if the program receives an interrupt during this read
call, it does not call the interrupt handler or set errno
. Instead, read
sets c
to 3
(ETX
). I'm honestly not sure what this means or if it is intended, but I was able to get the expected behaviour by simply calling the interrupt handler manually in this case.
rc = read(fd,&c,1);
if (c == 3){
bestlineOnInt(SIGINT);
}
While this works for me right now, I doubt this is a robust fix.
Am I on the right track here, or is the current behaviour intended?
Thanks in advance.
Some cultural reference that I don't get?
PS. Maybe ez
means easy
, then the function better to be named easy_bestline
.
Or better, bestline_with_history
- so our grandchildren will be able to grok the code.
I'm looking for a GNU readline alternative, mostly to make sure https://www.oilshell.org/ doesn't become too tied to that interface (which is very hairy).
I did some research and it seems like the only line editors that support vi mode (set -o vi
) are GNU readline and libedit (derived from NetBSD with few docs). It looks like it is a few thousand lines of logic in each.
I wonder if this is in scope for bestline? I looked at the code a little and maybe it can be done with an alternative bestlineEdit()
? The main difference is that vi is modal and hitting escape brings you into edit mode, but I think that could be handled in such a wrapper.
~/src/readline-8.1$ wc -l vi*.c
875 vi_keymap.c
2408 vi_mode.c
3283 total
~/src/libedit-20210910-3.1/src$ wc -l vi*.c
1160 vi.c
774 vis.c
1934 total
minimal docs on vi mode: https://tiswww.case.edu/php/chet/readline/rluserman.html#SEC22
Hi jart, thanks for the excellent work of both cosmopolitan and bestline.
Recently, I need a cross-platform readline replacement for python since it simply not working on windows, and with some researching I found this repo.
I initially tried to compile bestline.c to libbestline.so, with GNU gcc and it's std lib, I could get it work, but it is not really portable since it rely on libc and several libs at runtime, see:
Then I tried to compile it with cosmopolitan which I consider it features a portable libc runtime, I tried the following build command:
libbestline.so: bestline.c crt.o ape.o ape.lds cosmopolitan.a cosmopolitan.h
gcc -g -Os -fPIC -shared -fno-pie -no-pie -mno-red-zone -nostdlib -nostdinc -fno-omit-frame-pointer -pg -mnop-\
mcount -o $@ bestline.c -Wl,--gc-sections -fuse-ld=bfd -Wl,-T,ape.lds -include cosmopolitan.h crt.o ape.o cosmopolitan\
.a
Unfortunatelly, it produces a ELF 64-bit LSB executable
instead of a shared object:
what I want is to build is a dynamic library with ldd comand shows not a dynamic executable
.
Could you send some help to me? I would be very appreciate for that.
thank you in advance :D
I have a rather odd syntax I want to support using bestline, that uses unmatched parenthesis.
I've disabled this locally by just forcing IsBalanced()
to return 1
.
Should this be a runtime option?
If there's interest, I can dig further on a more elegant way to handle.
Hello
Windows has now an emulation of pty (called ConPTY) and it seems that there are some support of VT100 codes. For example : https://learn.microsoft.com/en-us/windows/terminal/samples
do you think it would be possible to port bestline to conpty ?
In readline and editline (and zle and emacs), CTRL-T transposes two letters as in bestline, but with the following addition: if cursor is at eol, swap the two last letters:
> ab<CTRL-T>
> ba
readline also implements this for ALT-T to transpose the last two words:
$ foo bar<ALT-T>
$ bar foo
Line 126 in 8ab535e
Just compiled bestline_example
and tried its Unicode-handling, because I looking for a replacement of a hacked version of linenoise with partial Unicode support.
The following was run in a terminal of size 80x24 in a gnome terminal window on Ubuntu 21.10.
$ echo $TERM
xterm-256color
The initial prompt is hello>
, which is fine.
Pasting the string 💩🍺🌧 ⛈ 🌩 ⚡🔥💥🌨 "ሰማይ አይታረስ ንጉሥ አይከሰስ።
into bestline also works fine.
Now when pasting the same string 💩🍺🌧 ⛈ 🌩 ⚡🔥💥🌨 "ሰማይ አይታረስ ንጉሥ አይከሰስ።
again, the line would be longer than 80 characters, so bestline wraps the line (correctly).
However, on its way to there bestline prints the complete input line once again for each overflow character.
Example ("x" denotes cursor position):
Initial:
hello> x
After pasting the string once:
hello> 💩🍺🌧 ⛈ 🌩 ⚡🔥💥🌨 "ሰማይ አይታረስ ንጉሥ አይከሰስ።x
After pasting the string twice:
hello> 💩🍺🌧 ⛈ 🌩 ⚡🔥💥🌨 "ሰማይ አይታረስ ንጉሥ አይከሰስ።💩🍺🌧 ⛈ 🌩 ⚡🔥💥🌨 "ሰማይ አይታረስ ንጉሥ አ
hello> 💩🍺🌧 ⛈ 🌩 ⚡🔥💥🌨 "ሰማይ አይታረስ ንጉሥ አይከሰስ።💩🍺🌧 ⛈ 🌩 ⚡🔥💥🌨 "ሰማይ አይታረስ ንጉሥ አ
hello> 💩🍺🌧 ⛈ 🌩 ⚡🔥💥🌨 "ሰማይ አይታረስ ንጉሥ አይከሰስ።💩🍺🌧 ⛈ 🌩 ⚡🔥💥🌨 "ሰማይ አይታረስ ንጉሥ አ
hello> 💩🍺🌧 ⛈ 🌩 ⚡🔥💥🌨 "ሰማይ አይታረስ ንጉሥ አይከሰስ።💩🍺🌧 ⛈ 🌩 ⚡🔥💥🌨 "ሰማይ አይታረስ ንጉሥ አ
hello> 💩🍺🌧 ⛈ 🌩 ⚡🔥💥🌨 "ሰማይ አይታረስ ንጉሥ አይከሰስ።💩🍺🌧 ⛈ 🌩 ⚡🔥💥🌨 "ሰማይ አይታረስ ንጉሥ አ
ይከሰስ።x
This should instead be just
hello> 💩🍺🌧 ⛈ 🌩 ⚡🔥💥🌨 "ሰማይ አይታረስ ንጉሥ አይከሰስ።💩🍺🌧 ⛈ 🌩 ⚡🔥💥🌨 "ሰማይ አይታረስ ንጉሥ አ
ይከሰስ።x
As a follow-up, I was trying to go down in history (pressing the down arrow key), which brings up the last used line.
It provides the correct line, but pressing it several times moves everything else up even one line. This shouldn't be the case because when there is room to display the last full history entry, nothing should be moved around.
Thanks for the amazing work on bestline! IMO a modern linenoise successor is much needed!
This library, as all your work, looks awesome!
I am pretty sure it should be possible to add a function readNextKey()
so that it would return the "logical key" that the user pressed: k
, S
, 4
, Enter
, F5
, Page-Up
, Ctrl-C
, Alt-D
, Ctrl-Alt-L
, etc. This would require decoding the escape sequences associated to keys such as Page-Up
(which is something that is at least partially done today, right?), and might require adding defines / enums for the possible key values.
Do you think something like this could be useful?
bestline_example
.Ctrl-q
.Alt-Shift-x
.One of the lines in the README:
Line 111 in 67f41f0
uses 日本 in a list of supported languages to mean "Japanese". However, 日本 (Nihon) is Japan (the country), whereas what you probably intended to use here is 日本語 (Nihongo) which is the Japanese language.
Sources:
#define BESTLINE_MAX_LINE 4096
Way too small. We often need to copy-paste megabyte of queries in clickhouse-client
.
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.