mirror of
https://github.com/janet-lang/janet
synced 2024-11-25 17:57:17 +00:00
Add preliminary repl completion via tab.
This commit is contained in:
parent
7f9b2b34d1
commit
6471b4d100
@ -1809,7 +1809,7 @@
|
|||||||
:source where
|
:source where
|
||||||
:expander expand} opts)
|
:expander expand} opts)
|
||||||
(default env (fiber/getenv (fiber/current)))
|
(default env (fiber/getenv (fiber/current)))
|
||||||
(default chunks (fn [buf p] (getline "" buf)))
|
(default chunks (fn [buf p] (getline "" buf env)))
|
||||||
(default onstatus debug/stacktrace)
|
(default onstatus debug/stacktrace)
|
||||||
(default on-compile-error bad-compile)
|
(default on-compile-error bad-compile)
|
||||||
(default on-parse-error bad-parse)
|
(default on-parse-error bad-parse)
|
||||||
@ -2168,7 +2168,7 @@
|
|||||||
((parser/where p) 0)
|
((parser/where p) 0)
|
||||||
":"
|
":"
|
||||||
(parser/state p :delimiters) "> ")
|
(parser/state p :delimiters) "> ")
|
||||||
buf)))
|
buf env)))
|
||||||
(defn make-onsignal
|
(defn make-onsignal
|
||||||
[e level]
|
[e level]
|
||||||
|
|
||||||
@ -2183,7 +2183,7 @@
|
|||||||
(def status (parser/state p :delimiters))
|
(def status (parser/state p :delimiters))
|
||||||
(def c ((parser/where p) 0))
|
(def c ((parser/where p) 0))
|
||||||
(def prompt (string "debug[" level "]:" c ":" status "> "))
|
(def prompt (string "debug[" level "]:" c ":" status "> "))
|
||||||
(getline prompt buf))
|
(getline prompt buf nextenv))
|
||||||
(print "entering debug[" level "] - (quit) to exit")
|
(print "entering debug[" level "] - (quit) to exit")
|
||||||
(repl debugger-chunks (make-onsignal nextenv (+ 1 level)) nextenv)
|
(repl debugger-chunks (make-onsignal nextenv (+ 1 level)) nextenv)
|
||||||
(print "exiting debug[" level "]")
|
(print "exiting debug[" level "]")
|
||||||
@ -2315,17 +2315,18 @@
|
|||||||
(def [line] (parser/where p))
|
(def [line] (parser/where p))
|
||||||
(string "janet:" line ":" (parser/state p :delimiters) "> "))
|
(string "janet:" line ":" (parser/state p :delimiters) "> "))
|
||||||
(def prompter (if *quiet* noprompt getprompt))
|
(def prompter (if *quiet* noprompt getprompt))
|
||||||
(defn getstdin [prompt buf]
|
(defn getstdin [prompt buf _]
|
||||||
(file/write stdout prompt)
|
(file/write stdout prompt)
|
||||||
(file/flush stdout)
|
(file/flush stdout)
|
||||||
(file/read stdin :line buf))
|
(file/read stdin :line buf))
|
||||||
|
(def env (make-env))
|
||||||
(def getter (if *raw-stdin* getstdin getline))
|
(def getter (if *raw-stdin* getstdin getline))
|
||||||
(defn getchunk [buf p]
|
(defn getchunk [buf p]
|
||||||
(getter (prompter p) buf))
|
(getter (prompter p) buf env))
|
||||||
(def onsig (if *quiet* (fn [x &] x) nil))
|
(def onsig (if *quiet* (fn [x &] x) nil))
|
||||||
(setdyn :pretty-format (if *colorize* "%.20Q" "%.20q"))
|
(setdyn :pretty-format (if *colorize* "%.20Q" "%.20q"))
|
||||||
(setdyn :err-color (if *colorize* true))
|
(setdyn :err-color (if *colorize* true))
|
||||||
(repl getchunk onsig)))
|
(repl getchunk onsig env)))
|
||||||
|
|
||||||
|
|
||||||
###
|
###
|
||||||
|
@ -28,12 +28,16 @@
|
|||||||
#include "line.h"
|
#include "line.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static JANET_THREAD_LOCAL JanetTable *gbl_complete_env;
|
||||||
|
|
||||||
/* Common */
|
/* Common */
|
||||||
Janet janet_line_getter(int32_t argc, Janet *argv) {
|
Janet janet_line_getter(int32_t argc, Janet *argv) {
|
||||||
janet_arity(argc, 0, 2);
|
janet_arity(argc, 0, 3);
|
||||||
const char *str = (argc >= 1) ? (const char *) janet_getstring(argv, 0) : "";
|
const char *str = (argc >= 1) ? (const char *) janet_getstring(argv, 0) : "";
|
||||||
JanetBuffer *buf = (argc >= 2) ? janet_getbuffer(argv, 1) : janet_buffer(10);
|
JanetBuffer *buf = (argc >= 2) ? janet_getbuffer(argv, 1) : janet_buffer(10);
|
||||||
|
gbl_complete_env = (argc >= 3) ? janet_gettable(argv, 2) : janet_current_fiber()->env;
|
||||||
janet_line_get(str, buf);
|
janet_line_get(str, buf);
|
||||||
|
gbl_complete_env = NULL;
|
||||||
return janet_wrap_buffer(buf);
|
return janet_wrap_buffer(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,6 +80,8 @@ void janet_line_get(const char *p, JanetBuffer *buffer) {
|
|||||||
https://github.com/antirez/linenoise/blob/master/linenoise.c
|
https://github.com/antirez/linenoise/blob/master/linenoise.c
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <janet.h>
|
||||||
|
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -124,7 +130,7 @@ static char *sdup(const char *s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Ansi terminal raw mode */
|
/* Ansi terminal raw mode */
|
||||||
static int rawmode() {
|
static int rawmode(void) {
|
||||||
struct termios t;
|
struct termios t;
|
||||||
if (!isatty(STDIN_FILENO)) goto fatal;
|
if (!isatty(STDIN_FILENO)) goto fatal;
|
||||||
if (tcgetattr(STDIN_FILENO, &gbl_termios_start) == -1) goto fatal;
|
if (tcgetattr(STDIN_FILENO, &gbl_termios_start) == -1) goto fatal;
|
||||||
@ -143,12 +149,12 @@ fatal:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Disable raw mode */
|
/* Disable raw mode */
|
||||||
static void norawmode() {
|
static void norawmode(void) {
|
||||||
if (gbl_israwmode && tcsetattr(STDIN_FILENO, TCSAFLUSH, &gbl_termios_start) != -1)
|
if (gbl_israwmode && tcsetattr(STDIN_FILENO, TCSAFLUSH, &gbl_termios_start) != -1)
|
||||||
gbl_israwmode = 0;
|
gbl_israwmode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int curpos() {
|
static int curpos(void) {
|
||||||
char buf[32];
|
char buf[32];
|
||||||
int cols, rows;
|
int cols, rows;
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
@ -164,7 +170,7 @@ static int curpos() {
|
|||||||
return cols;
|
return cols;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getcols() {
|
static int getcols(void) {
|
||||||
struct winsize ws;
|
struct winsize ws;
|
||||||
if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
|
if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
|
||||||
int start, cols;
|
int start, cols;
|
||||||
@ -188,13 +194,13 @@ failed:
|
|||||||
return 80;
|
return 80;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear() {
|
static void clear(void) {
|
||||||
if (write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7) <= 0) {
|
if (write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7) <= 0) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void refresh() {
|
static void refresh(void) {
|
||||||
char seq[64];
|
char seq[64];
|
||||||
JanetBuffer b;
|
JanetBuffer b;
|
||||||
|
|
||||||
@ -227,23 +233,25 @@ static void refresh() {
|
|||||||
janet_buffer_deinit(&b);
|
janet_buffer_deinit(&b);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int insert(char c) {
|
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) {
|
||||||
gbl_buf[gbl_pos++] = c;
|
gbl_buf[gbl_pos++] = c;
|
||||||
gbl_buf[++gbl_len] = '\0';
|
gbl_buf[++gbl_len] = '\0';
|
||||||
if (gbl_plen + gbl_len < gbl_cols) {
|
if (draw) {
|
||||||
/* Avoid a full update of the line in the
|
if (gbl_plen + gbl_len < gbl_cols) {
|
||||||
* trivial case. */
|
/* Avoid a full update of the line in the
|
||||||
if (write(STDOUT_FILENO, &c, 1) == -1) return -1;
|
* trivial case. */
|
||||||
} else {
|
if (write(STDOUT_FILENO, &c, 1) == -1) return -1;
|
||||||
refresh();
|
} else {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
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_buf[gbl_pos++] = c;
|
gbl_buf[gbl_pos++] = c;
|
||||||
gbl_buf[++gbl_len] = '\0';
|
gbl_buf[++gbl_len] = '\0';
|
||||||
refresh();
|
if (draw) refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -270,7 +278,7 @@ static void historymove(int delta) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addhistory() {
|
static void addhistory(void) {
|
||||||
int i, len;
|
int i, len;
|
||||||
char *newline = sdup(gbl_buf);
|
char *newline = sdup(gbl_buf);
|
||||||
if (!newline) return;
|
if (!newline) return;
|
||||||
@ -287,28 +295,28 @@ static void addhistory() {
|
|||||||
gbl_history[0] = newline;
|
gbl_history[0] = newline;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void replacehistory() {
|
static void replacehistory(void) {
|
||||||
char *newline = sdup(gbl_buf);
|
char *newline = sdup(gbl_buf);
|
||||||
if (!newline) return;
|
if (!newline) return;
|
||||||
free(gbl_history[0]);
|
free(gbl_history[0]);
|
||||||
gbl_history[0] = newline;
|
gbl_history[0] = newline;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kleft() {
|
static void kleft(void) {
|
||||||
if (gbl_pos > 0) {
|
if (gbl_pos > 0) {
|
||||||
gbl_pos--;
|
gbl_pos--;
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kright() {
|
static void kright(void) {
|
||||||
if (gbl_pos != gbl_len) {
|
if (gbl_pos != gbl_len) {
|
||||||
gbl_pos++;
|
gbl_pos++;
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kbackspace() {
|
static void kbackspace(void) {
|
||||||
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--;
|
||||||
@ -317,7 +325,7 @@ static void kbackspace() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kdelete() {
|
static void kdelete(void) {
|
||||||
if (gbl_pos != gbl_len) {
|
if (gbl_pos != gbl_len) {
|
||||||
memmove(gbl_buf + gbl_pos, gbl_buf + gbl_pos + 1, gbl_len - gbl_pos);
|
memmove(gbl_buf + gbl_pos, gbl_buf + gbl_pos + 1, gbl_len - gbl_pos);
|
||||||
gbl_buf[--gbl_len] = '\0';
|
gbl_buf[--gbl_len] = '\0';
|
||||||
@ -325,6 +333,117 @@ static void kdelete() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See tools/symchargen.c */
|
||||||
|
static int is_symbol_char_gen(uint8_t c) {
|
||||||
|
if (c & 0x80) return 1;
|
||||||
|
if (c >= 'a' && c <= 'z') return 1;
|
||||||
|
if (c >= 'A' && c <= 'Z') return 1;
|
||||||
|
if (c >= '0' && c <= '9') return 1;
|
||||||
|
return (c == '!' ||
|
||||||
|
c == '$' ||
|
||||||
|
c == '%' ||
|
||||||
|
c == '&' ||
|
||||||
|
c == '*' ||
|
||||||
|
c == '+' ||
|
||||||
|
c == '-' ||
|
||||||
|
c == '.' ||
|
||||||
|
c == '/' ||
|
||||||
|
c == ':' ||
|
||||||
|
c == '<' ||
|
||||||
|
c == '?' ||
|
||||||
|
c == '=' ||
|
||||||
|
c == '>' ||
|
||||||
|
c == '@' ||
|
||||||
|
c == '^' ||
|
||||||
|
c == '_');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO - check against special forms and print in alphabetical order */
|
||||||
|
static void kshowcomp(void) {
|
||||||
|
JanetTable *env = gbl_complete_env;
|
||||||
|
|
||||||
|
/* Calculate current partial symbol. Maybe we could actually hook up the Janet
|
||||||
|
* parser here...*/
|
||||||
|
int i;
|
||||||
|
int32_t sym_len = 0;
|
||||||
|
for (i = gbl_pos - 1; i >= 0; i--) {
|
||||||
|
uint8_t c = (uint8_t) gbl_buf[i];
|
||||||
|
if (!is_symbol_char_gen(c)) break;
|
||||||
|
sym_len++;
|
||||||
|
}
|
||||||
|
char *sym_start = gbl_buf + i + 1;
|
||||||
|
|
||||||
|
if (sym_len == 0) return;
|
||||||
|
|
||||||
|
int32_t common_prefix_len = 0;
|
||||||
|
int32_t max_test_len = 0;
|
||||||
|
int32_t match_count = 0;
|
||||||
|
const uint8_t *first_match = NULL;
|
||||||
|
|
||||||
|
/* First pass, find match count and common prefix */
|
||||||
|
while (NULL != env) {
|
||||||
|
JanetKV *kvend = env->data + env->capacity;
|
||||||
|
for (JanetKV *kv = env->data; kv < kvend; kv++) {
|
||||||
|
if (janet_checktype(kv->key, JANET_NIL)) continue;
|
||||||
|
const uint8_t *test_str;
|
||||||
|
int32_t test_len;
|
||||||
|
if (!janet_bytes_view(kv->key, &test_str, &test_len)) continue;
|
||||||
|
if (test_len <= sym_len) continue;
|
||||||
|
if (strncmp((char *)test_str, sym_start, sym_len)) continue;
|
||||||
|
/* Found a prefix match */
|
||||||
|
match_count++;
|
||||||
|
if (NULL == first_match) {
|
||||||
|
common_prefix_len = max_test_len = test_len;
|
||||||
|
first_match = test_str;
|
||||||
|
} else {
|
||||||
|
if (max_test_len < test_len) max_test_len = test_len;
|
||||||
|
for (int32_t i = 0; i < common_prefix_len; i++) {
|
||||||
|
if (first_match[i] != test_str[i]) {
|
||||||
|
common_prefix_len = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
env = env->proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Complete common_prefix_len - sym_len characters */
|
||||||
|
for (int i = sym_len; i < common_prefix_len; i++) {
|
||||||
|
insert(first_match[i], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_cols = getcols();
|
||||||
|
|
||||||
|
norawmode();
|
||||||
|
|
||||||
|
/* Second pass, print */
|
||||||
|
int col_width = max_test_len + 4;
|
||||||
|
int cols = num_cols / col_width;
|
||||||
|
if (cols == 0) cols = 1;
|
||||||
|
int current_col = 0;
|
||||||
|
env = gbl_complete_env;
|
||||||
|
while (NULL != env) {
|
||||||
|
JanetKV *kvend = env->data + env->capacity;
|
||||||
|
for (JanetKV *kv = env->data; kv < kvend; kv++) {
|
||||||
|
if (janet_checktype(kv->key, JANET_NIL)) continue;
|
||||||
|
const uint8_t *test_str;
|
||||||
|
int32_t test_len;
|
||||||
|
if (!janet_bytes_view(kv->key, &test_str, &test_len)) continue;
|
||||||
|
if (test_len <= sym_len) continue;
|
||||||
|
if (strncmp((char *)test_str, sym_start, sym_len)) continue;
|
||||||
|
/* Found a prefix match */
|
||||||
|
if (current_col == 0) printf("\n");
|
||||||
|
printf("%-*s", col_width, test_str);
|
||||||
|
current_col = (current_col + 1) % cols;
|
||||||
|
}
|
||||||
|
env = env->proto;
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
rawmode();
|
||||||
|
}
|
||||||
|
|
||||||
static int line() {
|
static int line() {
|
||||||
gbl_cols = getcols();
|
gbl_cols = getcols();
|
||||||
gbl_plen = 0;
|
gbl_plen = 0;
|
||||||
@ -346,11 +465,11 @@ static int line() {
|
|||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
default:
|
default:
|
||||||
if (insert(c)) return -1;
|
if (insert(c, 1)) return -1;
|
||||||
break;
|
break;
|
||||||
case 9: /* tab */
|
case 9: /* tab */
|
||||||
if (insert(' ')) return -1;
|
kshowcomp();
|
||||||
if (insert(' ')) return -1;
|
refresh();
|
||||||
break;
|
break;
|
||||||
case 13: /* enter */
|
case 13: /* enter */
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user