2 * Copyright Neil Brown ©2015-2021 <neil@brown.name>
3 * May be distributed under terms of GPLv2 - see file:COPYING
5 * render-complete - support string completion.
7 * This should be attached between render-lines and the pane which
8 * provides the lines. It is given a string and it suppresses all
9 * lines which don't match the string. Matching can be case-insensitive,
10 * and may require the string to be at the start of the line.
12 * The linefilter module is used manage the selective display of lines.
13 * This module examine the results provided by linefilter and extends the
14 * string to the maximum that still matches the same set of lines.
15 * Keystrokes can extend or contract the match, which will cause display
18 * This module doesn't hold any marks on any document. The marks
19 * held by the rendered should be sufficient.
22 #define _GNU_SOURCE for strcasestr
29 struct complete_data {
33 const char *substr safe;
38 static struct map *rc_map;
40 DEF_LOOKUP_CMD(complete_handle, rc_map);
45 const char *prefix safe, *str;
48 static char *add_highlight_prefix(const char *orig, int start, int plen,
49 const char *attr safe)
58 while (start > 0 && *c) {
60 buf_append_byte(&ret, *c++);
61 buf_append_byte(&ret, *c++);
64 buf_concat(&ret, attr);
65 while (plen > 0 && *c) {
67 buf_append_byte(&ret, *c++);
68 buf_append_byte(&ret, *c++);
71 buf_concat(&ret, "</>");
73 return buf_final(&ret);
76 DEF_CMD(render_complete_line)
78 struct complete_data *cd = ci->home->data;
79 char *line, *start, *hl;
86 line = call_ret(str, ci->key, ci->home->parent, ci->num, ci->mark, NULL,
90 match = cd->stk->substr;
91 start = strcasestr(line, match);
94 hl = add_highlight_prefix(line, start - line, strlen(match),
97 ret = comm_call(ci->comm2, "callback:render", ci->focus, 0, NULL, hl);
103 DEF_CMD(complete_free)
105 struct complete_data *cd = ci->home->data;
106 struct stk *stk = cd->stk;
111 free((void*)t->substr);
119 static struct pane *complete_pane(struct pane *focus)
121 struct pane *complete;
122 struct complete_data *cd;
125 complete = pane_register(focus, 0, &complete_handle.c, cd);
130 cd->stk = malloc(sizeof(cd->stk[0]));
131 cd->stk->prev = NULL;
132 cd->stk->substr = strdup("");
137 DEF_CMD(complete_clone)
139 struct pane *parent = ci->focus;
140 struct pane *complete;
142 complete = complete_pane(parent);
144 pane_clone_children(ci->home, complete);
148 DEF_CMD(complete_ignore_replace)
153 DEF_CMD(complete_escape)
155 /* submit the original prefix back*/
156 struct complete_data *cd = ci->home->data;
158 /* This pane might be closed before the reply string is used,
159 * so we need to save it.
161 call("popup:close", ci->home->parent, NO_NUMERIC, NULL,
162 strsave(ci->home, cd->orig));
166 DEF_CMD(complete_char)
168 struct complete_data *cd = ci->home->data;
170 int pl = strlen(cd->stk->substr);
171 const char *suffix = ksuffix(ci, "doc:char-");
173 np = malloc(pl + strlen(suffix) + 1);
174 strcpy(np, cd->stk->substr);
175 strcpy(np+pl, suffix);
176 call("Complete:prefix", ci->focus, !cd->prefix_only, NULL, np);
182 struct complete_data *cd = ci->home->data;
183 struct stk *stk = cd->stk;
188 if (stk->substr[0] && !stk->prev->substr[0]) {
189 old = (void*)stk->substr;
190 old[strlen(old)-1] = 0;
193 free((void*)stk->substr);
196 call("Complete:prefix", ci->home, 0, NULL, NULL, 1);
200 static int csame(char a, char b)
209 static int common_len(const char *a safe, const char *b safe)
212 while (*a && csame(*a, *b)) {
220 static void adjust_pre(char *common safe, const char *new safe, int len)
222 int l = strlen(common);
225 while (l && len && csame(common[l-1], new[len-1])) {
231 memmove(common, common+l, newlen+1);
236 struct complete_data *cd safe;
240 /* common_pre is the longest common prefix to 'common' that
241 * appears in all matches in which 'common' appears. It is
242 * allocated with enough space to append 'common' after the
252 struct setcb *cb = container_of(ci->comm, struct setcb, c);
253 struct complete_data *cd = cb->cd;
254 const char *ss = cb->ss;
255 int len = strlen(ss);
256 const char *c = ci->str;
263 if (cd->prefix_only) {
265 if (strncmp(match, ss, len) == 0)
268 match = strcasestr(c, ss);
269 if (strncasecmp(c, ss, len) == 0) {
271 if (strncmp(c, ss, len) == 0)
273 } else if (strstr(c, ss))
278 /* should be impossible */
282 if (l && match[l-1] == '\n')
285 if (this_match > cb->best_match) {
286 /* Only use matches at least this good to calculate
289 cb->best_match = this_match;
292 free(cb->common_pre);
293 cb->common_pre = NULL;
296 if (this_match == cb->best_match) {
297 /* This match can be used for 'common' and
300 mark_free(cb->bestm);
302 cb->bestm = mark_dup(ci->mark);
305 cb->common = strndup(match, l);
307 cb->common[common_len(match, cb->common)] = 0;
308 /* If 'match' and 'common' disagree on case of
309 * 'prefix', use that of 'prefix'
311 if (memcmp(cb->common, match, len) != 0)
312 memcpy(cb->common, ss, len);
314 if (!cb->common_pre) {
315 cb->common_pre = strndup(c, l + match-c);
316 strncpy(cb->common_pre, c, match-c);
317 cb->common_pre[match-c] = 0;
319 adjust_pre(cb->common_pre, c, match-c);
325 DEF_CMD(complete_set_prefix)
327 /* Set the prefix, force a full refresh, and move point
328 * to the first match at start-of-line, or first match
329 * If there is no match, return -1.
330 * Otherwise return number of matches in ->num2 and
331 * the longest common prefix in ->str.
332 * If ci->num with ->str, allow substrings, else prefix-only
333 * if ci->num2, don't autocomplete, just display matches
335 struct pane *p = ci->home;
336 struct complete_data *cd = p->data;
341 /* Save a copy of the point so we can restore it if needed */
342 m = call_ret(mark, "doc:point", ci->focus);
350 cb.common_pre = NULL;
355 cd->prefix_only = !ci->num;
357 cb.ss = cd->stk->substr;
360 call_comm("Filter:set", ci->focus, &cb.c,
361 cd->prefix_only ? 3 : 2, NULL, cb.ss);
365 call("Filter:set", ci->focus,
366 cd->prefix_only ? 3 : 2, NULL, cd->stk->substr);
368 call("Move-to", ci->focus, 0, m);
372 if (cb.common_pre && cb.common && cb.cnt && ci->str) {
374 strcat(cb.common_pre, cb.common);
375 stk = malloc(sizeof(*stk));
376 stk->substr = cb.common_pre;
379 cb.common_pre = NULL;
380 call("Filter:set", ci->focus,
381 cd->prefix_only ? 3 : 2, NULL, cd->stk->substr);
382 comm_call(ci->comm2, "callback:prefix", ci->focus, cb.cnt,
383 NULL, cd->stk->substr);
385 cd->orig = strdup(ci->str);
387 comm_call(ci->comm2, "callback:prefix", ci->focus, 0);
392 call("Move-to", ci->focus, 0, cb.bestm);
396 call("view:changed", ci->focus);
403 struct call_return *cr = container_of(ci->comm, struct call_return, c);
404 cr->s = ci->str ? strdup(ci->str) : NULL;
408 DEF_CMD(complete_return)
410 /* submit the selected entry to the popup */
411 struct call_return cr;
420 home_call(ci->home, "doc:render-line",
421 ci->home, NO_NUMERIC, ci->mark, NULL, 0, NULL,
426 if (l && cr.s[l-1] == '\n')
439 while (*c2 && c2[-1] != '>')
444 call("popup:close", ci->home->parent, NO_NUMERIC, NULL,
450 static void register_map(void)
452 rc_map = key_alloc();
454 key_add(rc_map, "doc:render-line", &render_complete_line);
455 key_add(rc_map, "Free", &complete_free);
456 key_add(rc_map, "Clone", &complete_clone);
458 key_add(rc_map, "Replace", &complete_ignore_replace);
459 key_add(rc_map, "K:ESC", &complete_escape);
460 key_add_range(rc_map, "doc:char- ", "doc:char-~", &complete_char);
461 key_add(rc_map, "K:Backspace", &complete_bs);
463 key_add(rc_map, "K:Enter", &complete_return);
465 key_add(rc_map, "Complete:prefix", &complete_set_prefix);
468 DEF_CMD(complete_attach)
470 struct pane *p = ci->focus;
471 struct pane *complete;
476 p = call_ret(pane, "attach-linefilter", p);
479 complete = complete_pane(p);
485 return comm_call(ci->comm2, "callback:attach", complete);
488 void edlib_init(struct pane *ed safe)
490 call_comm("global-set-command", ed, &complete_attach,
491 0, NULL, "attach-render-complete");