commit b1e1e41a7e4757b4b9e028031431db0e0a304f25 from: Omar Polo date: Wed Jul 14 07:38:35 2021 UTC finally start this completion-read commit - af29d739553d6efe6ff97d2cba50406122a99ff6 commit + b1e1e41a7e4757b4b9e028031431db0e0a304f25 blob - b7f36fd2312f9fcc2535cd7cfc24023380fa91a9 blob + e1a1f074b8ab728c5cb9320c8938c8195a08f358 --- Makefile.am +++ Makefile.am @@ -5,6 +5,8 @@ telescope_SOURCES = cmd.c \ cmd.h \ compat.h \ compat/*.[ch] \ + compl.c \ + compl.h \ defaults.c \ defaults.h \ fs.c \ blob - 42c6cf2f7c3255420553a008549209927297e980 blob + 3c700286dfa06f282179020891c070f993c8960e --- cmd.c +++ cmd.c @@ -18,6 +18,7 @@ #include #include +#include "compl.h" #include "defaults.h" #include "minibuffer.h" #include "telescope.h" @@ -347,7 +348,7 @@ cmd_execute_extended_command(struct buffer *buffer) } enter_minibuffer(eecmd_self_insert, eecmd_select, exit_minibuffer, - &eecmd_history, NULL, NULL); + &eecmd_history, compl_eecmd, NULL); len = sizeof(ministate.prompt); strlcpy(ministate.prompt, "", len); @@ -583,6 +584,8 @@ cmd_mini_delete_char(struct buffer *buffer) n = utf8_next_cp(c); memmove(c, n, strlen(n)+1); + + recompute_completions(0); } void @@ -605,6 +608,8 @@ cmd_mini_delete_backward_char(struct buffer *buffer) memmove(p, c, strlen(c)+1); buffer->cpoff--; + + recompute_completions(0); } void @@ -620,6 +625,8 @@ cmd_mini_kill_line(struct buffer *buffer) minibuffer_taint_hist(); c = utf8_nth(buffer->current_line->line, buffer->cpoff); *c = '\0'; + + recompute_completions(0); } void blob - /dev/null blob + 8d01e57a79a67f027ffbb5055e4b6d1189314455 (mode 644) --- /dev/null +++ compl.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 Omar Polo + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "compl.h" +#include "telescope.h" + +const char * +compl_eecmd(void **data) +{ + struct cmd **state = (struct cmd **)data; + + /* first time: init the state */ + if (*state == NULL) + *state = cmds; + + if ((*state)->cmd == NULL) + return NULL; + + (*state)++; + return (*state)->cmd; +} blob - /dev/null blob + 8bf04bcb4c4660854bfa2ed924c52f23eb9c1c0c (mode 644) --- /dev/null +++ compl.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2021 Omar Polo + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef COMPL_H +#define COMPL_H + +const char *compl_eecmd(void **); + +#endif blob - 5354c5fd3f762db6e1f280b5d2f04c8d41708314 blob + 00e7a2d4e24e1f49fbd241b3dacfecb83efeb8f1 --- minibuffer.c +++ minibuffer.c @@ -42,6 +42,30 @@ struct histhead eecmd_history, struct ministate ministate; +struct buffer minibufferwin; + +/* + * Recompute the visible completions. If add is 1, don't consider the + * ones already hidden. + */ +void +recompute_completions(int add) +{ + struct line *l; + + if (in_minibuffer != MB_COMPREAD) + return; + + TAILQ_FOREACH(l, &ministate.compl.buffer.page.head, lines) { + if (add && l->flags & L_HIDDEN) + continue; + if (strstr(l->line, ministate.buf) != NULL) + l->flags &= ~L_HIDDEN; + else + l->flags |= L_HIDDEN; + } +} + static void minibuffer_hist_save_entry(void) { @@ -97,6 +121,8 @@ minibuffer_self_insert(void) memmove(c + len, c, strlen(c)+1); memcpy(c, tmp, len); ministate.buffer.cpoff++; + + recompute_completions(1); } void @@ -226,6 +252,51 @@ read_select(void) exit_minibuffer(); minibuffer_hist_save_entry(); read_cb(ministate.buf, read_data); +} + +/* + * Just like erase_buffer, but don't call free(l->line); + */ +static inline void +erase_compl_buffer(struct buffer *buffer) +{ + struct line *l, *lt; + + empty_vlist(buffer); + + TAILQ_FOREACH_SAFE(l, &buffer->page.head, lines, lt) { + TAILQ_REMOVE(&buffer->page.head, l, lines); + /* don't free l->line! */ + free(l); + } +} + +/* + * TODO: we should collect this asynchronously... + */ +static inline void +populate_compl_buffer(complfn *fn, void *data) +{ + const char *s; + struct line *l; + struct buffer *b; + struct parser *p; + + b = &ministate.compl.buffer; + p = &b->page; + + while ((s = fn(&data)) != NULL) { + if ((l = calloc(1, sizeof(*l))) == NULL) + abort(); + + l->type = LINE_TEXT; + l->line = s; + + if (TAILQ_EMPTY(&p->head)) + TAILQ_INSERT_HEAD(&p->head, l, lines); + else + TAILQ_INSERT_TAIL(&p->head, l, lines); + } } void @@ -233,7 +304,17 @@ enter_minibuffer(void (*self_insert_fn)(void), void (* void (*abortfn)(void), struct histhead *hist, complfn *complfn, void *compldata) { - in_minibuffer = 1; + in_minibuffer = complfn == NULL ? MB_READ : MB_COMPREAD; + if (in_minibuffer == MB_COMPREAD) { + ui_schedule_redraw(); + + erase_compl_buffer(&ministate.compl.buffer); + + ministate.compl.fn = complfn; + ministate.compl.data = compldata; + populate_compl_buffer(complfn, compldata); + } + base_map = &minibuffer_map; current_map = &minibuffer_map; @@ -255,6 +336,9 @@ enter_minibuffer(void (*self_insert_fn)(void), void (* void exit_minibuffer(void) { + if (in_minibuffer == MB_COMPREAD) + ui_schedule_redraw(); + in_minibuffer = 0; base_map = &global_map; current_map = &global_map; @@ -286,7 +370,7 @@ yornp(const char *prompt, void (*fn)(int, struct tab*) */ void completing_read(const char *prompt, void (*fn)(const char *, struct tab *), - struct tab *data, complfn *complfn, void *compldata) + struct tab *data) { size_t len; @@ -296,7 +380,7 @@ completing_read(const char *prompt, void (*fn)(const c read_cb = fn; read_data = data; enter_minibuffer(read_self_insert, read_select, read_abort, - &read_history, complfn, compldata); + &read_history, NULL, NULL); len = sizeof(ministate.prompt); strlcpy(ministate.prompt, prompt, len); blob - e6577cbd7191c8338c24499cb418c43757f399fd blob + 73e4f9f746397c6856c0ce65b15083e15bd7380c --- minibuffer.h +++ minibuffer.h @@ -23,8 +23,44 @@ #define MB_READ 1 #define MB_COMPREAD 2 -typedef char *(complfn)(void *); +/* + * Completion provider function. These functions are called + * asynchronously. The function should compute the next completion + * using the given parameter `state' and modify it eventually. To + * signal the end of the completions, complfn should return NULL: the + * value of state will then be discarded and the function never called + * again. + */ +typedef const char *(complfn)(void **); +struct ministate { + char *curmesg; + + char prompt[64]; + void (*donefn)(void); + void (*abortfn)(void); + + char buf[1025]; + struct line line; + struct vline vline; + struct buffer buffer; + + struct histhead *history; + struct hist *hist_cur; + size_t hist_off; + + struct { + struct buffer buffer; + complfn *fn; + void *data; + } compl; +}; +extern struct ministate ministate; + +extern struct buffer minibufferwin; + +void recompute_completions(int); + void enter_minibuffer(void(*)(void), void(*)(void), void(*)(void), struct histhead *, complfn *, void *); @@ -36,12 +72,9 @@ void yornp(const char *, void (*)(int, struct tab *), * completing_read asks the user for something using the minibuffer. * The first argument is the string prompt. The second and third are * the callback to call when done and the data; the callback function - * can't be NULL. The last two arguments are the completion function - * and its data; if not given, no completion will be shown. The - * function providing the completion will be called asynchronously. + * can't be NULL. */ void completing_read(const char *, - void (*)(const char *, struct tab *), struct tab *, - complfn *, void *); + void (*)(const char *, struct tab *), struct tab *); #endif blob - f06eeb66d293166c1ef048fc6445686a3dcaa295 blob + 540de79098f2017095d3d728b08ede7f01a69e79 --- ui.c +++ ui.c @@ -66,6 +66,7 @@ static void redraw_modeline(struct tab*); static void redraw_minibuffer(void); static void do_redraw_echoarea(void); static void do_redraw_minibuffer(void); +static void do_redraw_minibuffer_compl(void); static void place_cursor(int); static void redraw_tab(struct tab*); static void emit_help_item(char*, void*); @@ -331,6 +332,14 @@ handle_resize_nodelay(int s, short ev, void *d) /* move and resize the windows, in reverse order! */ + if (in_minibuffer == MB_COMPREAD) { + mvwin(minibuffer, lines-10, 0); + wresize(minibuffer, 10, COLS); + lines -= 10; + + wrap_page(&ministate.compl.buffer, COLS); + } + mvwin(echoarea, --lines, 0); wresize(echoarea, 1, COLS); @@ -597,6 +606,9 @@ adjust_line(struct vline *vl, struct buffer *buffer) { struct vline *t; + if (vl == NULL) + return NULL; + if (!(vl->parent->flags & L_HIDDEN)) return vl; @@ -641,6 +653,9 @@ again: if (TAILQ_EMPTY(&buffer->head)) goto end; + if (buffer->top_line == NULL) + buffer->top_line = TAILQ_FIRST(&buffer->head); + buffer->top_line = adjust_line(buffer->top_line, buffer); if (buffer->top_line == NULL) goto end; @@ -773,6 +788,9 @@ redraw_minibuffer(void) else do_redraw_echoarea(); + if (in_minibuffer == MB_COMPREAD) + do_redraw_minibuffer_compl(); + wattr_off(echoarea, minibuffer_face.background, NULL); } @@ -826,6 +844,13 @@ do_redraw_minibuffer(void) wprintw(echoarea, " [%s]", ministate.curmesg); wmove(echoarea, 0, off_x + utf8_swidth_between(start, c)); +} + +static void +do_redraw_minibuffer_compl(void) +{ + redraw_window(minibuffer, 10, body_cols, + &ministate.compl.buffer); } /* @@ -871,6 +896,9 @@ redraw_tab(struct tab *tab) wnoutrefresh(tabline); wnoutrefresh(modeline); + if (in_minibuffer == MB_COMPREAD) + wnoutrefresh(minibuffer); + place_cursor(1); doupdate(); @@ -1196,7 +1224,13 @@ ui_toggle_side_window(void) void ui_schedule_redraw(void) { - handle_resize_nodelay(0, 0, NULL); + struct timeval tv = {0, 0}; + + if (event_pending(&resizeev, EV_TIMEOUT, NULL)) + event_del(&resizeev); + + evtimer_set(&resizeev, handle_resize_nodelay, NULL); + evtimer_add(&resizeev, &tv); } void @@ -1224,7 +1258,7 @@ void ui_read(const char *prompt, void (*fn)(const char*, struct tab *), struct tab *data) { - completing_read(prompt, fn, data, NULL, NULL); + completing_read(prompt, fn, data); redraw_tab(current_tab()); } blob - f88c1530477be74f4bd8856b0c55dd1381795c9d blob + 909ba81917a545d6a5e0a29aaad82c3b3ee8f1f8 --- ui.h +++ ui.h @@ -89,24 +89,6 @@ extern struct histhead eecmd_history, lu_history, read_history; -struct ministate { - char *curmesg; - - char prompt[64]; - void (*donefn)(void); - void (*abortfn)(void); - - char buf[1025]; - struct line line; - struct vline vline; - struct buffer buffer; - - struct histhead *history; - struct hist *hist_cur; - size_t hist_off; -}; -extern struct ministate ministate; - void save_excursion(struct excursion *, struct buffer *); void restore_excursion(struct excursion *, struct buffer *); void global_key_unbound(void);