2 * Copyright Neil Brown ©2015 <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 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 {
29 char *prefix safe, *str;
32 static char *add_highlight_prefix(char *orig, int plen, char *attr safe)
41 buf_concat(&ret, attr);
42 while (plen > 0 && *c) {
44 buf_append_byte(&ret, *c++);
45 buf_append_byte(&ret, *c++);
48 buf_concat(&ret, "</>");
50 return buf_final(&ret);
53 DEF_CMD(save_highlighted)
55 struct call_return *cr = container_of(ci->comm, struct call_return, c);
56 cr->s = add_highlight_prefix(ci->str, cr->i, "<fg:red>");
62 struct rlcb *cb = container_of(ci->comm, struct rlcb, c);
66 cb->cmp = strncmp(ci->str, cb->prefix, cb->plen);
69 DEF_CMD(render_complete_line)
71 /* The first line *must* match the prefix.
72 * skip over any following lines that don't
74 struct complete_data *cd = ci->home->data;
75 int plen = strlen(cd->prefix);
76 struct call_return cr;
81 if (!ci->mark || !ci->home->parent)
84 cr.c = save_highlighted;
87 if (call_comm(ci->key, ci->home->parent, &cr.c, ci->num, ci->mark, NULL,
91 ret = comm_call(ci->comm2, "callback:render", ci->focus, 0, NULL, cr.s);
93 if (ci->num != NO_NUMERIC)
95 /* Need to continue over other matching lines */
96 m = mark_dup(ci->mark, 1);
100 cb.prefix = cd->prefix;
102 call_comm(ci->key, ci->home->parent, &cb.c, ci->num, m, NULL,
108 /* have a non-match, so move the mark over it. */
109 mark_to_mark(ci->mark, m);
117 struct rlcb *cb = container_of(ci->comm, struct rlcb, c);
121 cb->cmp = strncmp(ci->str, cb->prefix, cb->plen);
122 if (cb->cmp == 0 && cb->keep && ci->str)
123 cb->str = strdup(ci->str);
127 static int do_render_complete_prev(struct complete_data *cd safe, struct mark *m safe,
128 struct pane *focus safe, int n, char **savestr)
130 /* If 'n' is 0 we just need 'start of line' so use
131 * underlying function.
132 * otherwise call repeatedly and then render the line and see if
133 * it matches the prefix.
137 struct mark *m2, *m3;
147 cb.prefix = cd->prefix;
148 cb.plen = strlen(cb.prefix);
151 ret = call("render-line-prev", focus, n2, m2);
152 if (ret <= 0 || n == 0)
153 /* Either hit start-of-file, or have what we need */
155 /* we must be looking at a possible option for the previous
160 m3 = mark_dup(m2, 1);
161 cb.keep = n2 == 1 && savestr;
163 if (call_comm("render-line", focus, &cb.c, NO_NUMERIC, m3)
173 if (cb.cmp == 0 && n2 == 1)
174 /* This is a valid new start-of-line */
176 /* step back once more */
181 /* move m back to m2 */
188 DEF_CMD(render_complete_prev)
190 /* If ->num is 0 we just need 'start of line' so use
191 * underlying function.
192 * otherwise call repeatedly and then render the line and see if
193 * it matches the prefix.
195 struct complete_data *cd = ci->home->data;
196 if (!ci->mark || !ci->home->parent)
198 return do_render_complete_prev(cd, ci->mark, ci->home->parent, ci->num, NULL);
201 DEF_CMD(complete_close)
203 struct pane *p = ci->home;
204 struct complete_data *cd = p->data;
210 DEF_CMD(complete_attach);
211 DEF_CMD(complete_clone)
213 struct pane *parent = ci->focus;
215 complete_attach.func(ci);
216 pane_clone_children(ci->home, parent->focus);
220 DEF_CMD(complete_nomove)
222 if (strcmp(ci->key, "Move-File") == 0)
224 if (strcmp(ci->key, "Move-to") == 0)
226 if (strcmp(ci->key, "Move-Line") == 0)
233 /* don't save anything */
237 DEF_CMD(complete_eol)
239 int rpt = RPT_NUM(ci);
241 if (!ci->mark || !ci->focus->parent)
243 if (rpt >= -1 && rpt <= 1)
244 /* movement within the line */
247 if (do_render_complete_prev(ci->home->data, ci->mark,
248 ci->focus->parent, 1, NULL) < 0)
253 struct call_return cr;
255 if (pane_call(ci->home, "render-line",
256 ci->focus, NO_NUMERIC, ci->mark, NULL,
257 0, NULL, NULL, 0,0, &cr.c) <= 0)
264 static int common_len(char *a safe, char *b safe)
267 while (*a && *a == *b) {
275 DEF_CMD(complete_set_prefix)
277 /* Set the prefix, force a full refresh, and move point
278 * to the first match.
279 * If there is no match, return -1.
280 * Otherwise return number of matches in ->num2 and
281 * the longest common prefix in ->str.
283 struct pane *p = ci->home;
284 struct complete_data *cd = p->data;
293 cd->prefix = strdup(ci->str);
295 m = mark_at_point(ci->focus, NULL, MARK_UNGROUPED);
296 if (!m || !p->parent)
298 call("Move-File", ci->focus, 1, m);
300 while (do_render_complete_prev(cd, m, p->parent, 1, &c) > 0 && c) {
305 common = strndup(c, l);
307 common[common_len(c, common)] = 0;
310 comm_call(ci->comm2, "callback:prefix", ci->focus, 0, NULL, common);
312 call("Move-to", ci->focus, 0, m);
314 pane_damaged(ci->focus, DAMAGED_VIEW);
320 struct call_return *cr = container_of(ci->comm, struct call_return, c);
321 cr->s = ci->str ? strdup(ci->str) : NULL;
325 DEF_CMD(complete_return)
327 /* submit the selected entry to the popup */
328 struct pane *p = ci->home;
329 struct complete_data *cd = p->data;
330 struct call_return cr;
334 if (!ci->mark || !ci->home->parent)
339 pane_call(ci->home, "render-line",
340 ci->home, NO_NUMERIC, ci->mark, NULL, 0, NULL,
345 if (l && cr.s[l-1] == '\n')
358 while (*c2 && c2[-1] != '>')
363 call("popup:close", ci->home->parent, NO_NUMERIC, NULL,
364 cr.s + strlen(cd->prefix), 0);
369 static struct map *rc_map;
371 DEF_LOOKUP_CMD(complete_handle, rc_map)
373 static void register_map(void)
375 rc_map = key_alloc();
377 key_add(rc_map, "render-line", &render_complete_line);
378 key_add(rc_map, "render-line-prev", &render_complete_prev);
379 key_add(rc_map, "Close", &complete_close);
380 key_add(rc_map, "Clone", &complete_clone);
382 key_add_range(rc_map, "Move-", "Move-\377", &complete_nomove);
383 key_add(rc_map, "Move-EOL", &complete_eol);
385 key_add(rc_map, "Return", &complete_return);
387 key_add(rc_map, "Complete:prefix", &complete_set_prefix);
390 REDEF_CMD(complete_attach)
392 struct pane *complete;
393 struct complete_data *cd;
398 cd = calloc(1, sizeof(*cd));
399 complete = pane_register(ci->focus, 0, &complete_handle.c, cd, NULL);
404 cd->prefix = strdup("");
406 return comm_call(ci->comm2, "callback:attach", complete);
409 void edlib_init(struct pane *ed safe)
411 call_comm("global-set-command", ed, &complete_attach, 0, NULL, "attach-render-complete");