diff --git a/ask.c b/ask.c index 42b7b3b..38f3201 100644 --- a/ask.c +++ b/ask.c @@ -71,9 +71,9 @@ static void draw_line(FILE *out, const char *line, const char *hl, const char *c } /* - * A basic fuzzly matcher + * A basic fuzzy matcher and line inputter */ -static char *fzline(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) { size_t cap = initial ? strlen(initial) + 100 : 100; char *buf = memcheck(calloc(cap, 1)); @@ -124,7 +124,10 @@ static char *fzline(FILE *in, FILE *out, const char *prompt, const char *initial if (best) { draw_line(out, best, buf, &buf[b]); } else { - fprintf(out, "\033[0;31m%s\033[0m", buf); + if (nopts > 0) + 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); } @@ -139,6 +142,7 @@ static char *fzline(FILE *in, FILE *out, const char *prompt, const char *initial goto finished; case KEY_CTRL_C: case KEY_ESC: free(buf); + buf = NULL; picked = NULL; goto finished; case KEY_CTRL_A: @@ -189,10 +193,8 @@ static char *fzline(FILE *in, FILE *out, const char *prompt, const char *initial break; default: if (' ' <= key && key <= '~') { - if (len + 1 >= (int)cap) { + if (len + 1 >= (int)cap) buf = memcheck(realloc(buf, (cap += 100))); - if (!buf) goto finished; - } if (b < len) memmove(buf+b+1, buf+b, (size_t)(len-b+1)); buf[b++] = (char)key; @@ -202,133 +204,11 @@ static char *fzline(FILE *in, FILE *out, const char *prompt, const char *initial } } finished: + if (picked) picked = memcheck(strdup(picked)); + else picked = buf; return picked; } -/** - * A basic readline implementation. No history, but all the normal editing - * key bindings like Ctrl-U to clear to the beginning of the line, backspace, - * arrow keys, etc. - * - * Takes an input file and output file, and an optional prompt and returns - * a malloc'd string containing the user's input or NULL if an error occurred - * or if the user hit Escape or Ctrl-c. - */ -static char *breadline(FILE *in, FILE *out, const char *prompt, const char *initial) -{ - size_t cap = initial ? strlen(initial) + 100 : 100; - char *buf = calloc(cap, 1); - if (!buf) return NULL; - int i = 0, len = 0; - if (prompt) { - fputs("\033[1G\033[K\033[37;1m", out); - fputs(prompt, out); - fputs("\033[0m", out); - } - if (initial) { - strcpy(buf, initial); - len = (int)strlen(initial); - i = len; - fputs(initial, out); - } - // Show cursor - fputs("\033[?25h", out); - while (1) { - fflush(out); - int key = bgetkey(in, NULL, NULL, -1); - switch (key) { - case -1: case -2: case -3: continue; - case '\r': - // TODO: support backslash-enter - goto finished; - case KEY_CTRL_C: case KEY_ESC: - free(buf); - buf = NULL; - goto finished; - case KEY_CTRL_A: - if (i > 0) { - fprintf(out, "\033[%dD", i); - i = 0; - } - break; - case KEY_CTRL_E: - if (i < len) { - fprintf(out, "\033[%dC", len-i); - i = len; - } - break; - case KEY_CTRL_U: { - int to_clear = i; - if (to_clear) { - memmove(buf, buf+i, (size_t)(len-i)); - buf[len -= i] = 0; - i = 0; - fprintf(out, "\033[%dD\033[K", to_clear); - if (len > 0) - fprintf(out, "%s\033[%dD", buf, len); - } - break; - } - case KEY_CTRL_K: - if (i < len) { - buf[len = i] = 0; - fputs("\033[K", out); - } - break; - case KEY_BACKSPACE: case KEY_BACKSPACE2: - if (i > 0) { - --i; - memmove(buf+i, buf+i+1, (size_t)(len-i)); - buf[--len] = 0; - if (i == len) fputs("\033[D \033[D", out); - else fprintf(out, "\033[D%s\033[K\033[%dD", buf+i, len-i); - } - break; - case KEY_DELETE: case KEY_CTRL_D: - if (i < len) { - memmove(buf+i, buf+i+1, (size_t)(len-i)); - buf[--len] = 0; - if (i == len) fputs(" \033[D", out); - else fprintf(out, "%s\033[K\033[%dD", buf+i, len-i); - } - break; - case KEY_ARROW_LEFT: case KEY_CTRL_B: - if (i > 0) { - --i; - fputs("\033[D", out); - } - break; - case KEY_ARROW_RIGHT: case KEY_CTRL_F: - if (i < len) { - ++i; - fputs("\033[C", out); - } - break; - default: - if (' ' <= key && key <= '~') { - if (len + 1 >= (int)cap) { - cap += 100; - buf = realloc(buf, cap); - if (!buf) goto finished; - } - if (i < len) - memmove(buf+i+1, buf+i, (size_t)(len-i+1)); - buf[i++] = (char)key; - buf[++len] = 0; - if (i == len) - fputc(key, out); - else - fprintf(out, "%c%s\033[%dD", (char)key, buf+i, len-i); - } - break; - } - } - finished: - // Reset cursor to block - fputs("\033[1G\033[1 q\033[2K", out); - return buf; -} - int main(int argc, char *argv[]) { FILE *tty_in = fopen("/dev/tty", "r"); @@ -373,9 +253,7 @@ int main(int argc, char *argv[]) lines[nlines++] = argv[a++]; } - char *output = nlines > 0 - ? fzline(tty_in, tty_out, prompt, initial, nlines, lines) - : breadline(tty_in, tty_out, prompt, initial); + char *output = get_input(tty_in, tty_out, prompt, initial, nlines, lines); fputs("\033[G\033[K\033[0m", tty_out); fflush(tty_out); @@ -388,6 +266,10 @@ int main(int argc, char *argv[]) if (!output) return 1; puts(output); + free(output); + + // This doesn't free the memory in lines, but it doesn't need to because + // the program is exiting return 0; } // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1