2 * Copyright Neil Brown ©2015-2019 <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 prefix and it suppresses all
9 * lines which don't start with the prefix.
10 * All events are redirected to the controlling window (where the text
11 * to be completed is being entered)
13 * This module doesn't hold any marks on any document. The marks
14 * held by the rendered should be sufficient.
22 struct complete_data {
31 char *prefix safe, *str;
34 static char *add_highlight_prefix(char *orig, int start, int plen, char *attr safe)
43 while (start > 0 && *c) {
45 buf_append_byte(&ret, *c++);
46 buf_append_byte(&ret, *c++);
49 buf_concat(&ret, attr);
50 while (plen > 0 && *c) {
52 buf_append_byte(&ret, *c++);
53 buf_append_byte(&ret, *c++);
56 buf_concat(&ret, "</>");
58 return buf_final(&ret);
61 DEF_CMD(save_highlighted)
63 struct rlcb *cb = container_of(ci->comm, struct rlcb, c);
69 start = strstr(ci->str, cb->prefix);
72 cb->str = add_highlight_prefix(ci->str, start - ci->str, cb->plen, "<fg:red>");
78 struct rlcb *cb = container_of(ci->comm, struct rlcb, c);
81 else if (cb->prefix_only)
82 cb->cmp = strncmp(ci->str, cb->prefix, cb->plen);
84 cb->cmp = strstr(ci->str, cb->prefix) ? 0 : 1;
87 DEF_CMD(render_complete_line)
89 /* The first line *must* match the prefix.
90 * skip over any following lines that don't
92 struct complete_data *cd = ci->home->data;
93 int plen = strlen(cd->prefix);
98 if (!ci->mark || !ci->home->parent)
101 cb.c = save_highlighted;
103 cb.prefix_only = cd->prefix_only;
104 cb.prefix = cd->prefix;
106 if (call_comm(ci->key, ci->home->parent, &cb.c, ci->num, ci->mark, NULL,
110 ret = comm_call(ci->comm2, "callback:render", ci->focus, 0, NULL, cb.str);
112 if (ci->num != NO_NUMERIC)
114 /* Need to continue over other matching lines */
115 m = mark_dup(ci->mark);
119 cb.prefix = cd->prefix;
120 cb.prefix_only = cd->prefix_only;
122 call_comm(ci->key, ci->home->parent, &cb.c, ci->num, m, NULL,
128 /* have a non-match, so move the mark over it. */
129 mark_to_mark(ci->mark, m);
137 struct rlcb *cb = container_of(ci->comm, struct rlcb, c);
140 else if (cb->prefix_only)
141 cb->cmp = strncmp(ci->str, cb->prefix, cb->plen);
143 cb->cmp = strstr(ci->str, cb->prefix) ? 0 : 1;
144 if (cb->cmp == 0 && cb->keep && ci->str)
145 cb->str = strdup(ci->str);
149 static int do_render_complete_prev(struct complete_data *cd safe, struct mark *m safe,
150 struct pane *focus safe, int n, char **savestr)
152 /* If 'n' is 0 we just need 'start of line' so use
153 * underlying function.
154 * otherwise call repeatedly and then render the line and see if
155 * it matches the prefix.
159 struct mark *m2, *m3;
169 cb.prefix = cd->prefix;
170 cb.prefix_only = cd->prefix_only;
171 cb.plen = strlen(cb.prefix);
174 ret = call("render-line-prev", focus, n2, m2);
175 if (ret <= 0 || n == 0)
176 /* Either hit start-of-file, or have what we need */
178 /* we must be looking at a possible option for the previous
184 cb.keep = n2 == 1 && savestr;
186 if (call_comm("render-line", focus, &cb.c, NO_NUMERIC, m3)
196 if (cb.cmp == 0 && n2 == 1)
197 /* This is a valid new start-of-line */
199 /* step back once more */
204 /* move m back to m2 */
211 DEF_CMD(render_complete_prev)
213 /* If ->num is 0 we just need 'start of line' so use
214 * underlying function.
215 * otherwise call repeatedly and then render the line and see if
216 * it matches the prefix.
218 struct complete_data *cd = ci->home->data;
219 if (!ci->mark || !ci->home->parent)
221 return do_render_complete_prev(cd, ci->mark, ci->home->parent, ci->num, NULL);
224 DEF_CMD(complete_close)
226 struct complete_data *cd = ci->home->data;
233 DEF_CMD(complete_attach);
234 DEF_CMD(complete_clone)
236 struct pane *parent = ci->focus;
238 complete_attach.func(ci);
239 pane_clone_children(ci->home, parent->focus);
243 DEF_CMD(complete_nomove)
245 if (strcmp(ci->key, "Move-File") == 0)
247 if (strcmp(ci->key, "Move-to") == 0)
249 if (strcmp(ci->key, "Move-Line") == 0)
256 /* don't save anything */
260 DEF_CMD(complete_eol)
262 int rpt = RPT_NUM(ci);
264 if (!ci->mark || !ci->focus->parent)
266 if (rpt >= -1 && rpt <= 1)
267 /* movement within the line */
270 if (do_render_complete_prev(ci->home->data, ci->mark,
271 ci->focus->parent, 1, NULL) < 0)
276 struct call_return cr;
278 if (home_call(ci->home, "render-line",
279 ci->focus, NO_NUMERIC, ci->mark, NULL,
280 0, NULL, NULL, 0,0, &cr.c) <= 0)
287 static int common_len(char *a safe, char *b safe)
290 while (*a && *a == *b) {
298 DEF_CMD(complete_set_prefix)
300 /* Set the prefix, force a full refresh, and move point
301 * to the first match at start-of-line, or first match
302 * If there is no match, return -1.
303 * Otherwise return number of matches in ->num2 and
304 * the longest common prefix in ->str.
306 struct pane *p = ci->home;
307 struct complete_data *cd = p->data;
309 struct mark *m2 = NULL;
318 cd->prefix = strdup(ci->str);
319 cd->prefix_only = !ci->num;
321 m = mark_at_point(ci->focus, NULL, MARK_UNGROUPED);
322 if (!m || !p->parent)
324 /* Move to end-of-document */
325 call("Move-File", ci->focus, 1, m);
327 while (do_render_complete_prev(cd, m, p->parent, 1, &c) > 0 && c) {
330 if (!cd->prefix_only)
331 match = strstr(match, cd->prefix);
335 if (l && match[l-1] == '\n')
337 if (!cd->prefix_only && strncmp(c, cd->prefix, strlen(cd->prefix)) == 0) {
342 /* If there are matches at the start, the common prefix
343 * calculation only noticed them
353 common = strndup(match, l);
355 common[common_len(match, common)] = 0;
359 comm_call(ci->comm2, "callback:prefix", ci->focus, 0, NULL, common);
362 call("Move-to", ci->focus, 0, m2);
365 call("Move-to", ci->focus, 0, m);
368 pane_damaged(ci->focus, DAMAGED_VIEW);
374 struct call_return *cr = container_of(ci->comm, struct call_return, c);
375 cr->s = ci->str ? strdup(ci->str) : NULL;
379 DEF_CMD(complete_return)
381 /* submit the selected entry to the popup */
382 struct call_return cr;
386 if (!ci->mark || !ci->home->parent)
391 home_call(ci->home, "render-line",
392 ci->home, NO_NUMERIC, ci->mark, NULL, 0, NULL,
397 if (l && cr.s[l-1] == '\n')
410 while (*c2 && c2[-1] != '>')
415 call("popup:close", ci->home->parent, NO_NUMERIC, NULL,
421 static struct map *rc_map;
423 DEF_LOOKUP_CMD(complete_handle, rc_map)
425 static void register_map(void)
427 rc_map = key_alloc();
429 key_add(rc_map, "render-line", &render_complete_line);
430 key_add(rc_map, "render-line-prev", &render_complete_prev);
431 key_add(rc_map, "Close", &complete_close);
432 key_add(rc_map, "Clone", &complete_clone);
434 key_add_range(rc_map, "Move-", "Move-\377", &complete_nomove);
435 key_add(rc_map, "Move-EOL", &complete_eol);
437 key_add(rc_map, "Enter", &complete_return);
439 key_add(rc_map, "Complete:prefix", &complete_set_prefix);
442 REDEF_CMD(complete_attach)
444 struct pane *complete;
445 struct complete_data *cd;
450 cd = calloc(1, sizeof(*cd));
451 complete = pane_register(ci->focus, 0, &complete_handle.c, cd, NULL);
456 cd->prefix = strdup("");
459 return comm_call(ci->comm2, "callback:attach", complete);
462 void edlib_init(struct pane *ed safe)
464 call_comm("global-set-command", ed, &complete_attach, 0, NULL, "attach-render-complete");