mirror of
https://github.com/janet-lang/janet
synced 2024-12-28 01:10:26 +00:00
Add special forms and sort completions.
Also fix case when no completion is needed.
This commit is contained in:
parent
6471b4d100
commit
a8e4c4bed0
@ -35,7 +35,7 @@ Janet janet_line_getter(int32_t argc, Janet *argv) {
|
|||||||
janet_arity(argc, 0, 3);
|
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;
|
gbl_complete_env = (argc >= 3) ? janet_gettable(argv, 2) : NULL;
|
||||||
janet_line_get(str, buf);
|
janet_line_get(str, buf);
|
||||||
gbl_complete_env = NULL;
|
gbl_complete_env = NULL;
|
||||||
return janet_wrap_buffer(buf);
|
return janet_wrap_buffer(buf);
|
||||||
@ -98,6 +98,7 @@ https://github.com/antirez/linenoise/blob/master/linenoise.c
|
|||||||
|
|
||||||
/* static state */
|
/* static state */
|
||||||
#define JANET_LINE_MAX 1024
|
#define JANET_LINE_MAX 1024
|
||||||
|
#define JANET_MATCH_MAX 256
|
||||||
#define JANET_HISTORY_MAX 100
|
#define JANET_HISTORY_MAX 100
|
||||||
static JANET_THREAD_LOCAL int gbl_israwmode = 0;
|
static JANET_THREAD_LOCAL int gbl_israwmode = 0;
|
||||||
static JANET_THREAD_LOCAL const char *gbl_prompt = "> ";
|
static JANET_THREAD_LOCAL const char *gbl_prompt = "> ";
|
||||||
@ -111,6 +112,8 @@ static JANET_THREAD_LOCAL int gbl_history_count = 0;
|
|||||||
static JANET_THREAD_LOCAL int gbl_historyi = 0;
|
static JANET_THREAD_LOCAL int gbl_historyi = 0;
|
||||||
static JANET_THREAD_LOCAL int gbl_sigint_flag = 0;
|
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 int gbl_match_count = 0;
|
||||||
|
|
||||||
/* Unsupported terminal list from linenoise */
|
/* Unsupported terminal list from linenoise */
|
||||||
static const char *badterms[] = {
|
static const char *badterms[] = {
|
||||||
@ -358,91 +361,141 @@ static int is_symbol_char_gen(uint8_t c) {
|
|||||||
c == '_');
|
c == '_');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO - check against special forms and print in alphabetical order */
|
static JanetByteView get_symprefix(void) {
|
||||||
static void kshowcomp(void) {
|
|
||||||
JanetTable *env = gbl_complete_env;
|
|
||||||
|
|
||||||
/* Calculate current partial symbol. Maybe we could actually hook up the Janet
|
/* Calculate current partial symbol. Maybe we could actually hook up the Janet
|
||||||
* parser here...*/
|
* parser here...*/
|
||||||
int i;
|
int i;
|
||||||
int32_t sym_len = 0;
|
JanetByteView ret;
|
||||||
|
ret.len = 0;
|
||||||
for (i = gbl_pos - 1; i >= 0; i--) {
|
for (i = gbl_pos - 1; i >= 0; i--) {
|
||||||
uint8_t c = (uint8_t) gbl_buf[i];
|
uint8_t c = (uint8_t) gbl_buf[i];
|
||||||
if (!is_symbol_char_gen(c)) break;
|
if (!is_symbol_char_gen(c)) break;
|
||||||
sym_len++;
|
ret.len++;
|
||||||
|
}
|
||||||
|
/* Will be const for duration of match checking */
|
||||||
|
ret.bytes = (const uint8_t *)(gbl_buf + i + 1);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
char *sym_start = gbl_buf + i + 1;
|
|
||||||
|
|
||||||
if (sym_len == 0) return;
|
static int compare_bytes(JanetByteView a, JanetByteView b) {
|
||||||
|
int32_t minlen = a.len < b.len ? a.len : b.len;
|
||||||
|
int result = strncmp((const char *) a.bytes, (const char *) b.bytes, minlen);
|
||||||
|
if (result) return result;
|
||||||
|
return a.len < b.len ? -1 : a.len > b.len ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t common_prefix_len = 0;
|
static void check_match(JanetByteView src, const uint8_t *testsym, int32_t testlen) {
|
||||||
int32_t max_test_len = 0;
|
JanetByteView test;
|
||||||
int32_t match_count = 0;
|
test.bytes = testsym;
|
||||||
const uint8_t *first_match = NULL;
|
test.len = testlen;
|
||||||
|
if (src.len > test.len || strncmp((const char *) src.bytes, (const char *) test.bytes, src.len)) return;
|
||||||
|
JanetByteView mm = test;
|
||||||
|
for (int i = 0; i < gbl_match_count; i++) {
|
||||||
|
if (compare_bytes(mm, gbl_matches[i]) < 0) {
|
||||||
|
JanetByteView temp = mm;
|
||||||
|
mm = gbl_matches[i];
|
||||||
|
gbl_matches[i] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (gbl_match_count == JANET_MATCH_MAX) return;
|
||||||
|
gbl_matches[gbl_match_count++] = mm;
|
||||||
|
}
|
||||||
|
|
||||||
/* First pass, find match count and common prefix */
|
static void check_cmatch(JanetByteView src, const char *cstr) {
|
||||||
while (NULL != env) {
|
check_match(src, (const uint8_t *) cstr, (int32_t) strlen(cstr));
|
||||||
JanetKV *kvend = env->data + env->capacity;
|
}
|
||||||
for (JanetKV *kv = env->data; kv < kvend; kv++) {
|
|
||||||
if (janet_checktype(kv->key, JANET_NIL)) continue;
|
static JanetByteView longest_common_prefix(void) {
|
||||||
const uint8_t *test_str;
|
JanetByteView bv;
|
||||||
int32_t test_len;
|
if (gbl_match_count == 0) {
|
||||||
if (!janet_bytes_view(kv->key, &test_str, &test_len)) continue;
|
bv.len = 0;
|
||||||
if (test_len <= sym_len) continue;
|
bv.bytes = NULL;
|
||||||
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 {
|
} else {
|
||||||
if (max_test_len < test_len) max_test_len = test_len;
|
bv = gbl_matches[0];
|
||||||
for (int32_t i = 0; i < common_prefix_len; i++) {
|
for (int i = 0; i < gbl_match_count; i++) {
|
||||||
if (first_match[i] != test_str[i]) {
|
JanetByteView other = gbl_matches[i];
|
||||||
common_prefix_len = i;
|
int32_t minlen = other.len < bv.len ? other.len : bv.len;
|
||||||
|
for (bv.len = 0; bv.len < minlen; bv.len++) {
|
||||||
|
if (bv.bytes[bv.len] != other.bytes[bv.len]) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return bv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_specials(JanetByteView src) {
|
||||||
|
check_cmatch(src, "break");
|
||||||
|
check_cmatch(src, "def");
|
||||||
|
check_cmatch(src, "do");
|
||||||
|
check_cmatch(src, "fn");
|
||||||
|
check_cmatch(src, "if");
|
||||||
|
check_cmatch(src, "quasiquote");
|
||||||
|
check_cmatch(src, "quote");
|
||||||
|
check_cmatch(src, "set");
|
||||||
|
check_cmatch(src, "splice");
|
||||||
|
check_cmatch(src, "unquote");
|
||||||
|
check_cmatch(src, "var");
|
||||||
|
check_cmatch(src, "while");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO - check against special forms and print in alphabetical order */
|
||||||
|
static void kshowcomp(void) {
|
||||||
|
JanetTable *env = gbl_complete_env;
|
||||||
|
if (env == NULL) {
|
||||||
|
insert(' ', 0);
|
||||||
|
insert(' ', 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JanetByteView prefix = get_symprefix();
|
||||||
|
if (prefix.len == 0) return;
|
||||||
|
|
||||||
|
/* Find all matches */
|
||||||
|
gbl_match_count = 0;
|
||||||
|
while (NULL != env) {
|
||||||
|
JanetKV *kvend = env->data + env->capacity;
|
||||||
|
for (JanetKV *kv = env->data; kv < kvend; kv++) {
|
||||||
|
if (!janet_checktype(kv->key, JANET_SYMBOL)) continue;
|
||||||
|
const uint8_t *sym = janet_unwrap_symbol(kv->key);
|
||||||
|
check_match(prefix, sym, janet_string_length(sym));
|
||||||
|
}
|
||||||
env = env->proto;
|
env = env->proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Complete common_prefix_len - sym_len characters */
|
check_specials(prefix);
|
||||||
for (int i = sym_len; i < common_prefix_len; i++) {
|
|
||||||
insert(first_match[i], 0);
|
JanetByteView lcp = longest_common_prefix();
|
||||||
|
for (int i = prefix.len; i < lcp.len; i++) {
|
||||||
|
insert(lcp.bytes[i], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t maxlen = 0;
|
||||||
|
for (int i = 0; i < gbl_match_count; i++)
|
||||||
|
if (gbl_matches[i].len > maxlen)
|
||||||
|
maxlen = gbl_matches[i].len;
|
||||||
|
|
||||||
int num_cols = getcols();
|
int num_cols = getcols();
|
||||||
|
if (gbl_match_count >= 2) {
|
||||||
|
|
||||||
norawmode();
|
norawmode();
|
||||||
|
|
||||||
/* Second pass, print */
|
/* Second pass, print */
|
||||||
int col_width = max_test_len + 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;
|
||||||
env = gbl_complete_env;
|
for (int i = 0; i < gbl_match_count; i++) {
|
||||||
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");
|
if (current_col == 0) printf("\n");
|
||||||
printf("%-*s", col_width, test_str);
|
printf("%-*s", col_width, (const char *) gbl_matches[i].bytes);
|
||||||
current_col = (current_col + 1) % cols;
|
current_col = (current_col + 1) % cols;
|
||||||
}
|
}
|
||||||
env = env->proto;
|
|
||||||
}
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
rawmode();
|
rawmode();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int line() {
|
static int line() {
|
||||||
gbl_cols = getcols();
|
gbl_cols = getcols();
|
||||||
|
Loading…
Reference in New Issue
Block a user