Added support for readline-style Ctrl-v/Ctrl-q for literal char insert,
Ctrl-t transpose, and fixed weird chars to render as escape sequences. Also changed redrawing code to not use saved cursor position and use left movement instead.
This commit is contained in:
parent
03dd8d56f3
commit
38ef3c8d9e
89
ask.c
89
ask.c
@ -68,39 +68,56 @@ static int matches(const char *str, const char *patt)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_line(FILE *out, const char *line, const char *patt, int cursor, int stop_at_cursor)
|
static int fputc_escaped(char c, FILE *out)
|
||||||
|
{
|
||||||
|
static const char *escapes = " abtnvfr e";
|
||||||
|
if (c > 0 && c <= '\x1b' && escapes[(int)c] != ' ') { // "\n", etc.
|
||||||
|
fprintf(out, "\033[35m\\%c\033[37m", escapes[(int)c]);
|
||||||
|
return 2;
|
||||||
|
} else if (c >= 0 && !(' ' <= c && c <= '~')) { // "\x02", etc.
|
||||||
|
fprintf(out, "\033[35m\\x%02X\033[37m", c);
|
||||||
|
return 4;
|
||||||
|
} else {
|
||||||
|
fputc(c, out);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int draw_line(FILE *out, const char *line, const char *patt, int cursor)
|
||||||
{
|
{
|
||||||
size_t linelen = strlen(line), patlen = strlen(patt);
|
size_t linelen = strlen(line), patlen = strlen(patt);
|
||||||
int dim = 0;
|
int dim = 0;
|
||||||
int p = 0;
|
int p = 0;
|
||||||
int run = 0;
|
int run = 0;
|
||||||
int *cache = calloc((linelen+1)*(patlen+1), sizeof(int));
|
int *cache = calloc((linelen+1)*(patlen+1), sizeof(int));
|
||||||
if (patlen == 0 && stop_at_cursor)
|
int backtrack = 0;
|
||||||
return;
|
int to_start = 0;
|
||||||
for (int i = 0; i < (int)linelen; i++) {
|
for (int i = 0; i < (int)linelen; i++) {
|
||||||
if (EQ(patt[p], line[i]) &&
|
if (EQ(patt[p], line[i]) &&
|
||||||
run + lcs(line,patt,(int)linelen,(int)patlen,i,p,cache)
|
run + lcs(line,patt,(int)linelen,(int)patlen,i,p,cache)
|
||||||
>= lcs(line,patt,(int)linelen,(int)patlen,i+1,p,cache)) {
|
>= lcs(line,patt,(int)linelen,(int)patlen,i+1,p,cache)) {
|
||||||
if (dim) {
|
if (dim) {
|
||||||
fputs("\033[22m", out);
|
fputs("\033[22;1m", out);
|
||||||
dim = 0;
|
dim = 0;
|
||||||
}
|
}
|
||||||
if (cursor == p && stop_at_cursor)
|
int len = fputc_escaped(line[i], out);
|
||||||
return;
|
if (p >= cursor) backtrack += len;
|
||||||
fputc(patt[p], out);
|
else to_start += len;
|
||||||
++run;
|
++run;
|
||||||
++p;
|
++p;
|
||||||
if (cursor == p && stop_at_cursor)
|
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
run = 0;
|
run = 0;
|
||||||
if (!dim) {
|
if (!dim) {
|
||||||
fputs("\033[2m", out);
|
fputs("\033[22;2m", out);
|
||||||
dim = 1;
|
dim = 1;
|
||||||
}
|
}
|
||||||
fputc(line[i], out);
|
int len = fputc_escaped(line[i], out);
|
||||||
|
if (p >= cursor) backtrack += len;
|
||||||
|
else to_start += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (backtrack) fprintf(out, "\033[0m\033[%dD", backtrack);
|
||||||
|
return to_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -108,8 +125,8 @@ static void draw_line(FILE *out, const char *line, const char *patt, int cursor,
|
|||||||
*/
|
*/
|
||||||
static char *get_input(FILE *in, FILE *out, const char *prompt, const char *initial, int nopts, char **opts)
|
static char *get_input(FILE *in, FILE *out, const char *prompt, const char *initial, int nopts, char **opts)
|
||||||
{
|
{
|
||||||
fputs("\0337", out);
|
|
||||||
if (!prompt) prompt = "> ";
|
if (!prompt) prompt = "> ";
|
||||||
|
fprintf(out, "\033[K\033[0;1m%s\033[0m", prompt);
|
||||||
size_t cap = initial ? strlen(initial) + 100 : 100;
|
size_t cap = initial ? strlen(initial) + 100 : 100;
|
||||||
char *buf = memcheck(calloc(cap, 1));
|
char *buf = memcheck(calloc(cap, 1));
|
||||||
char *picked = NULL;
|
char *picked = NULL;
|
||||||
@ -120,7 +137,7 @@ static char *get_input(FILE *in, FILE *out, const char *prompt, const char *init
|
|||||||
b = len;
|
b = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
int start = 0;
|
int start = 0, backtrack = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
case_sensitive = 0;
|
case_sensitive = 0;
|
||||||
for (const char *p = buf; *p; ++p)
|
for (const char *p = buf; *p; ++p)
|
||||||
@ -144,29 +161,20 @@ static char *get_input(FILE *in, FILE *out, const char *prompt, const char *init
|
|||||||
if (quickpick && ncandidates == 1 && picked)
|
if (quickpick && ncandidates == 1 && picked)
|
||||||
goto finished;
|
goto finished;
|
||||||
|
|
||||||
fprintf(out, "\0338\033[K\033[0;1m%s\033[0m", prompt);
|
if (backtrack) fprintf(out, "\033[%dD", backtrack);
|
||||||
|
fputs("\033[K", out);
|
||||||
if (password) {
|
if (password) {
|
||||||
if (picked) fputs("\033[0;32m", out);
|
if (picked) fputs("\033[0;32m", out);
|
||||||
else if (nopts > 0) fputs("\033[0;31m", out);
|
else if (nopts > 0) fputs("\033[0;31m", out);
|
||||||
else fputs("\033[0;2m", out);
|
else fputs("\033[0;2m", out);
|
||||||
fputc((PASSWORD)[strlen(buf) % strlen(PASSWORD)], out);
|
fputc((PASSWORD)[strlen(buf) % strlen(PASSWORD)], out);
|
||||||
fputs("\033[0m", out);
|
fputs("\033[0m", out);
|
||||||
|
backtrack = 1;
|
||||||
} else {
|
} else {
|
||||||
if (picked) {
|
if (picked) {
|
||||||
// Because stuff can have tabs and whatnot and the saved cusor
|
backtrack = draw_line(out, picked, buf, b);
|
||||||
// position is already in use, the most reliable way to make
|
|
||||||
// sure the cursor ends up in the right place is to draw the
|
|
||||||
// whole line, then redraw everything up to the cursor.
|
|
||||||
draw_line(out, picked, buf, b, 0);
|
|
||||||
fprintf(out, "\0338\033[0m\033[37;1m%s\033[0m", prompt);
|
|
||||||
draw_line(out, picked, buf, b, 1);
|
|
||||||
} else {
|
} else {
|
||||||
if (nopts > 0)
|
backtrack = draw_line(out, buf, buf, b);
|
||||||
fprintf(out, "\033[0;31m%s\033[0m", buf);
|
|
||||||
else
|
|
||||||
fprintf(out, "\033[0m%s\033[0m", buf);
|
|
||||||
if (b < (int)strlen(buf))
|
|
||||||
fprintf(out, "\033[%dD", (int)strlen(buf) - b);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fflush(out);
|
fflush(out);
|
||||||
@ -184,10 +192,10 @@ static char *get_input(FILE *in, FILE *out, const char *prompt, const char *init
|
|||||||
picked = NULL;
|
picked = NULL;
|
||||||
goto finished;
|
goto finished;
|
||||||
case KEY_CTRL_A:
|
case KEY_CTRL_A:
|
||||||
if (b > 0) b = 0;
|
b = 0;
|
||||||
break;
|
break;
|
||||||
case KEY_CTRL_E:
|
case KEY_CTRL_E:
|
||||||
if (b < len) b = len;
|
b = len;
|
||||||
break;
|
break;
|
||||||
case KEY_CTRL_U: {
|
case KEY_CTRL_U: {
|
||||||
int to_clear = b;
|
int to_clear = b;
|
||||||
@ -243,8 +251,29 @@ static char *get_input(FILE *in, FILE *out, const char *prompt, const char *init
|
|||||||
case KEY_ARROW_RIGHT: case KEY_CTRL_F:
|
case KEY_ARROW_RIGHT: case KEY_CTRL_F:
|
||||||
if (b < len) ++b;
|
if (b < len) ++b;
|
||||||
break;
|
break;
|
||||||
|
case KEY_CTRL_Q: case KEY_CTRL_V: {
|
||||||
|
int nextkey;
|
||||||
|
while ((nextkey = bgetkey(in, NULL, NULL, -1)) < 0)
|
||||||
|
;
|
||||||
|
if (len + 1 >= (int)cap)
|
||||||
|
buf = memcheck(realloc(buf, (cap += 100)));
|
||||||
|
if (b < len)
|
||||||
|
memmove(buf+b+1, buf+b, (size_t)(len-b+1));
|
||||||
|
buf[b++] = (char)nextkey;
|
||||||
|
buf[++len] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case KEY_CTRL_T: {
|
||||||
|
if (len < 2 || b == 0) break;
|
||||||
|
if (b < len)
|
||||||
|
b++;
|
||||||
|
char tmp = buf[b-1];
|
||||||
|
buf[b-1] = buf[b-2];
|
||||||
|
buf[b-2] = tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if (' ' <= key && key <= '~') {
|
if ((' ' <= key && key <= '~') || key == '\t') {
|
||||||
if (len + 1 >= (int)cap)
|
if (len + 1 >= (int)cap)
|
||||||
buf = memcheck(realloc(buf, (cap += 100)));
|
buf = memcheck(realloc(buf, (cap += 100)));
|
||||||
if (b < len)
|
if (b < len)
|
||||||
|
Loading…
Reference in New Issue
Block a user