Supporting using ask in the middle of a line without erasing the line.

This commit is contained in:
Bruce Hill 2019-06-05 18:10:40 -07:00
parent 982d4100ab
commit 03dd8d56f3

55
ask.c
View File

@ -68,15 +68,15 @@ 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) static void draw_line(FILE *out, const char *line, const char *patt, int cursor, int stop_at_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 (cursor >= (int)patlen) if (patlen == 0 && stop_at_cursor)
fputs("\0337", out); return;
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)
@ -85,11 +85,13 @@ static void draw_line(FILE *out, const char *line, const char *patt, int cursor)
fputs("\033[22m", out); fputs("\033[22m", out);
dim = 0; dim = 0;
} }
if (cursor == p && stop_at_cursor)
return;
fputc(patt[p], out); fputc(patt[p], out);
++run; ++run;
++p; ++p;
if (cursor == p) if (cursor == p && stop_at_cursor)
fputs("\0337", out); return;
} else { } else {
run = 0; run = 0;
if (!dim) { if (!dim) {
@ -99,7 +101,6 @@ static void draw_line(FILE *out, const char *line, const char *patt, int cursor)
fputc(line[i], out); fputc(line[i], out);
} }
} }
fputs("\0338", out);
} }
/* /*
@ -107,39 +108,35 @@ 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 = "> ";
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;
int b = 0, len = 0; int b = 0, len = 0;
if (initial) { if (initial) {
if (!strcpy(buf, initial)) return NULL; strcpy(buf, initial);
len = (int)strlen(initial); len = (int)strlen(initial);
b = len; b = len;
fputs(initial, out);
} }
int start = 0; int start = 0;
// Show cursor and set to blinking line:
while (1) { while (1) {
fputs("\033[G\033[K\033[0m", out);
if (prompt) {
fputs("\033[1G\033[K\033[37;1m", out);
fputs(prompt, out);
fputs("\033[0m", out);
}
case_sensitive = 0; case_sensitive = 0;
for (const char *p = buf; *p; ++p) for (const char *p = buf; *p; ++p)
case_sensitive |= ('A' <= *p && *p <= 'Z'); case_sensitive |= ('A' <= *p && *p <= 'Z');
int ncandidates = 0; int ncandidates = 0;
picked = NULL; picked = NULL;
for (int i = 0; i < nopts; i++) { if (buf[0]) {
int j = (start + i) % nopts; for (int i = 0; i < nopts; i++) {
if (matches(opts[j], buf)) { int j = (start + i) % nopts;
++ncandidates; if (matches(opts[j], buf)) {
if (!picked) { ++ncandidates;
picked = opts[j]; if (!picked) {
start = j; picked = opts[j];
start = j;
}
} }
} }
} }
@ -147,6 +144,7 @@ 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 (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);
@ -155,7 +153,13 @@ static char *get_input(FILE *in, FILE *out, const char *prompt, const char *init
fputs("\033[0m", out); fputs("\033[0m", out);
} else { } else {
if (picked) { if (picked) {
draw_line(out, picked, buf, b); // Because stuff can have tabs and whatnot and the saved cusor
// 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) if (nopts > 0)
fprintf(out, "\033[0;31m%s\033[0m", buf); fprintf(out, "\033[0;31m%s\033[0m", buf);
@ -254,6 +258,7 @@ static char *get_input(FILE *in, FILE *out, const char *prompt, const char *init
finished: finished:
if (picked) picked = memcheck(strdup(picked)); if (picked) picked = memcheck(strdup(picked));
else picked = buf; else picked = buf;
fputs("\0338\033[0m\033[K", out);
return picked; return picked;
} }
@ -313,7 +318,6 @@ int main(int argc, char *argv[])
++a; ++a;
} }
if (!prompt && a < argc) prompt = argv[a++]; if (!prompt && a < argc) prompt = argv[a++];
if (!prompt) prompt = "> ";
while (a < argc) { while (a < argc) {
if ((size_t)nlines >= linescap) if ((size_t)nlines >= linescap)
@ -323,7 +327,6 @@ int main(int argc, char *argv[])
char *output = get_input(tty_in, tty_out, prompt, initial, nlines, lines); char *output = get_input(tty_in, tty_out, prompt, initial, nlines, lines);
fputs("\033[G\033[K\033[0m", tty_out);
fflush(tty_out); fflush(tty_out);
tcsetattr(fileno(tty_out), TCSAFLUSH, &orig_termios); tcsetattr(fileno(tty_out), TCSAFLUSH, &orig_termios);
fclose(tty_out); fclose(tty_out);
@ -333,7 +336,7 @@ int main(int argc, char *argv[])
if (!output) return 1; if (!output) return 1;
puts(output); fputs(output, stdout);
free(output); free(output);
// This doesn't free the memory in lines, but it doesn't need to because // This doesn't free the memory in lines, but it doesn't need to because