1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-25 09:47:17 +00:00

Make autocompletion more zsh like

Also add a few ctrl sequences from readline, and
ignore unknown ctrl sequences.

Address #264

Adds Ctrl-n, Ctrl-p, and Ctrl-w
Ignores unknown ctrl sequences
No alt-* sequences yet.
This commit is contained in:
Calvin Rose 2020-01-19 10:37:05 -06:00
parent 9f8bc6bb8a
commit da70807292
2 changed files with 65 additions and 34 deletions

View File

@ -301,16 +301,14 @@
[[binding ctor dtor] & body] [[binding ctor dtor] & body]
~(do ~(do
(def ,binding ,ctor) (def ,binding ,ctor)
(defer (,(or dtor :close) ,binding) ,(apply defer [(or dtor :close) binding] body)))
,;body)))
(defmacro when-with (defmacro when-with
"Similar to with, but if binding is false or nil, returns "Similar to with, but if binding is false or nil, returns
nil without evaluating the body. Otherwise, the same as with." nil without evaluating the body. Otherwise, the same as with."
[[binding ctor dtor] & body] [[binding ctor dtor] & body]
~(if-let [,binding ,ctor] ~(if-let [,binding ,ctor]
(defer (,(or dtor :close) ,binding) ,(apply defer [(or dtor :close) binding] body)))
,;body)))
(defmacro if-with (defmacro if-with
"Similar to with, but if binding is false or nil, evaluates "Similar to with, but if binding is false or nil, evaluates
@ -318,7 +316,7 @@
ctor is bound to binding." ctor is bound to binding."
[[binding ctor dtor] truthy &opt falsey ] [[binding ctor dtor] truthy &opt falsey ]
~(if-let [,binding ,ctor] ~(if-let [,binding ,ctor]
(defer (,(or dtor :close) ,binding) ,truthy) ,(apply defer [(or dtor :close) binding] [truthy])
,falsey)) ,falsey))
(defn- for-template (defn- for-template

View File

@ -114,6 +114,7 @@ static JANET_THREAD_LOCAL int gbl_sigint_flag = 0;
static JANET_THREAD_LOCAL struct termios gbl_termios_start; static JANET_THREAD_LOCAL struct termios gbl_termios_start;
static JANET_THREAD_LOCAL JanetByteView gbl_matches[JANET_MATCH_MAX]; static JANET_THREAD_LOCAL JanetByteView gbl_matches[JANET_MATCH_MAX];
static JANET_THREAD_LOCAL int gbl_match_count = 0; static JANET_THREAD_LOCAL int gbl_match_count = 0;
static JANET_THREAD_LOCAL int gbl_lines_below = 0;
/* Unsupported terminal list from linenoise */ /* Unsupported terminal list from linenoise */
static const char *badterms[] = { static const char *badterms[] = {
@ -236,6 +237,17 @@ static void refresh(void) {
janet_buffer_deinit(&b); janet_buffer_deinit(&b);
} }
static void clearlines(void) {
for (int i = 0; i < gbl_lines_below; i++) {
fprintf(stderr, "\x1b[1B\x1b[999D\x1b[K");
}
if (gbl_lines_below) {
fprintf(stderr, "\x1b[%dA\x1b[999D", gbl_lines_below);
fflush(stderr);
gbl_lines_below = 0;
}
}
static int insert(char c, int draw) { static int insert(char c, int draw) {
if (gbl_len < JANET_LINE_MAX - 1) { if (gbl_len < JANET_LINE_MAX - 1) {
if (gbl_len == gbl_pos) { if (gbl_len == gbl_pos) {
@ -329,12 +341,12 @@ static void kright(void) {
} }
} }
static void kbackspace(void) { static void kbackspace(int draw) {
if (gbl_pos > 0) { if (gbl_pos > 0) {
memmove(gbl_buf + gbl_pos - 1, gbl_buf + gbl_pos, gbl_len - gbl_pos); memmove(gbl_buf + gbl_pos - 1, gbl_buf + gbl_pos, gbl_len - gbl_pos);
gbl_pos--; gbl_pos--;
gbl_buf[--gbl_len] = '\0'; gbl_buf[--gbl_len] = '\0';
refresh(); if (draw) refresh();
} }
} }
@ -494,15 +506,17 @@ static void kshowcomp(void) {
int num_cols = getcols(); int num_cols = getcols();
if (gbl_match_count >= 2) { if (gbl_match_count >= 2) {
norawmode();
/* Second pass, print */ /* Second pass, print */
clearlines();
int col_width = maxlen + 4; int col_width = maxlen + 4;
int cols = num_cols / col_width; int cols = num_cols / col_width;
if (cols == 0) cols = 1; if (cols == 0) cols = 1;
int current_col = 0; int current_col = 0;
for (int i = 0; i < gbl_match_count; i++) { for (int i = 0; i < gbl_match_count; i++) {
if (current_col == 0) putc('\n', stderr); if (current_col == 0) {
putc('\n', stderr);
gbl_lines_below++;
}
JanetByteView s = gbl_matches[i]; JanetByteView s = gbl_matches[i];
fprintf(stderr, "%s", (const char *) s.bytes); fprintf(stderr, "%s", (const char *) s.bytes);
for (int j = s.len; j < col_width; j++) { for (int j = s.len; j < col_width; j++) {
@ -510,10 +524,11 @@ static void kshowcomp(void) {
} }
current_col = (current_col + 1) % cols; current_col = (current_col + 1) % cols;
} }
putc('\n', stderr);
fflush(stderr);
rawmode(); /* Go up to original line (zsh-like autocompletion) */
fprintf(stderr, "\x1B[%dA", gbl_lines_below);
fflush(stderr);
} }
} }
@ -538,24 +553,9 @@ static int line() {
switch (c) { switch (c) {
default: default:
if (c < 0x20) break;
if (insert(c, 1)) return -1; if (insert(c, 1)) return -1;
break; break;
case 9: /* tab */
kshowcomp();
refresh();
break;
case 13: /* enter */
return 0;
case 3: /* ctrl-c */
errno = EAGAIN;
gbl_sigint_flag = 1;
return -1;
case 127: /* backspace */
case 8: /* ctrl-h */
kbackspace();
break;
case 4: /* ctrl-d, eof */
return -1;
case 1: /* ctrl-a */ case 1: /* ctrl-a */
gbl_pos = 0; gbl_pos = 0;
refresh(); refresh();
@ -563,6 +563,14 @@ static int line() {
case 2: /* ctrl-b */ case 2: /* ctrl-b */
kleft(); kleft();
break; break;
case 3: /* ctrl-c */
errno = EAGAIN;
gbl_sigint_flag = 1;
clearlines();
return -1;
case 4: /* ctrl-d, eof */
clearlines();
return -1;
case 5: /* ctrl-e */ case 5: /* ctrl-e */
gbl_pos = gbl_len; gbl_pos = gbl_len;
refresh(); refresh();
@ -570,21 +578,44 @@ static int line() {
case 6: /* ctrl-f */ case 6: /* ctrl-f */
kright(); kright();
break; break;
case 21: case 127: /* backspace */
case 8: /* ctrl-h */
kbackspace(1);
break;
case 9: /* tab */
kshowcomp();
refresh();
break;
case 12: /* ctrl-l */
clear();
refresh();
break;
case 13: /* enter */
clearlines();
return 0;
case 14: /* ctrl-n */
historymove(-1);
break;
case 16: /* ctrl-p */
historymove(1);
break;
case 21: /* ctrl-u */
gbl_buf[0] = '\0'; gbl_buf[0] = '\0';
gbl_pos = gbl_len = 0; gbl_pos = gbl_len = 0;
refresh(); refresh();
break; break;
case 23: /* ctrl-w */
while (gbl_pos && is_symbol_char_gen(gbl_buf[gbl_pos - 1])) {
kbackspace(0);
}
refresh();
break;
case 26: /* ctrl-z */ case 26: /* ctrl-z */
norawmode(); norawmode();
kill(getpid(), SIGSTOP); kill(getpid(), SIGSTOP);
rawmode(); rawmode();
refresh(); refresh();
break; break;
case 12:
clear();
refresh();
break;
case 27: /* escape sequence */ case 27: /* escape sequence */
/* Read the next two bytes representing the escape sequence. /* Read the next two bytes representing the escape sequence.
* Use two calls to handle slow terminals returning the two * Use two calls to handle slow terminals returning the two
@ -606,6 +637,7 @@ static int line() {
} }
} else { } else {
switch (seq[1]) { switch (seq[1]) {
/* Single escape sequences */
default: default:
break; break;
case 'A': case 'A':
@ -631,6 +663,7 @@ static int line() {
} }
} }
} else if (seq[0] == 'O') { } else if (seq[0] == 'O') {
/* Alt codes */
switch (seq[1]) { switch (seq[1]) {
default: default:
break; break;