2 * Copyright Neil Brown ©2015-2023 <neil@brown.name>
3 * May be distributed under terms of GPLv2 - see file:COPYING
17 #define ED_MAGIC 0x4321fedcUL
19 static struct map *ed_map safe;
22 struct pane *freelist;
23 struct mark *mark_free_list;
25 struct lookup_cmd cmd;
34 bool edlib_testing(struct pane *p safe)
36 struct ed_info *ei = pane_root(p)->data;
40 DEF_LOOKUP_CMD(ed_handle, ed_map);
42 DEF_CMD(global_set_attr)
48 attr_set_str(&ci->home->attrs, ci->str, ci->str2);
54 v = attr_find(ci->home->attrs, ci->str);
56 attr_set_str(&ci->home->attrs, ci->str, ci->str2);
59 v = strconcat(ci->home, v, ci->str2);
60 attr_set_str(&ci->home->attrs, ci->str, v);
64 DEF_CMD(global_set_command)
66 struct ed_info *ei = ci->home->data;
67 struct map *map = ei->map;
68 bool prefix = strcmp(ci->key, "global-set-command-prefix") == 0;
73 char *e = strconcat(NULL, ci->str, "\xFF\xFF\xFF\xFF");
74 key_add_range(map, ci->str, e, ci->comm2);
77 key_add_range(map, ci->str, ci->str2, ci->comm2);
79 key_add(map, ci->str, ci->comm2);
83 DEF_CMD(global_get_command)
85 struct ed_info *ei = ci->home->data;
86 struct map *map = ei->map;
90 !(cm = key_lookup_cmd(map, ci->str)))
92 return comm_call(ci->comm2, "callback:comm", ci->focus,
94 0, NULL, NULL, 0,0, cm);
97 DEF_CMD(global_config_dir)
99 const char *var = ci->str;
100 char *dir; // ci->str2;
101 char *key, *val = NULL;
102 struct pane *p = ci->home;
105 /* var might be different in different directories.
106 * Config setting are attributes stored on root that
107 * look like "config:var:dir".
108 * We find the best and return that with the dir
110 if (!var || !ci->str2 || !ci->comm2)
112 key = strconcat(p, "config:", var, ":", ci->str2);
113 dir = key + 7 + strlen(var) + 1;
114 end = dir + strlen(dir);
115 while (!val && end > dir) {
117 val = attr_find(p->attrs, key);
118 if (end[-1] == '/') {
119 while (end > dir && end[-1] == '/')
122 while (end > dir && end[-1] != '/')
128 comm_call(ci->comm2, "cb", ci->focus, 0, NULL, val,
134 #include "O/mod-list-decl.h"
135 typedef void init_func(struct pane *ed);
136 static struct builtin {
140 #include "O/mod-list.h"
143 DEF_CMD(editor_load_module)
145 struct ed_info *ei = ci->home->data;
146 struct map *map = ei->map;
147 const char *name = ci->str;
151 void (*s)(struct pane *p);
155 sprintf(buf, "edlib-%s.so", name);
156 /* RTLD_GLOBAL is needed for python, else we get
157 * errors about _Py_ZeroStruct which a python script
161 h = dlopen(buf, RTLD_NOW | RTLD_GLOBAL);
163 path = dlsym(h, "edlib_module_path");
165 if (dlinfo(h, RTLD_DI_ORIGIN, pbuf) == 0)
168 s = dlsym(h, "edlib_init");
170 char *v = dlsym(h, "edlib_version");
171 LOG("Loading %s - version %s", name, v ?: "not provided");
178 char *err = dlerror();
179 if (strstr(err, "No such file or directory") == NULL)
180 LOG("dlopen %s failed %s", buf, err);
186 for (i = 0; buf[i]; i++)
189 for (i = 0; i < sizeof(builtins)/sizeof(builtins[0]); i++)
190 if (strcmp(builtins[i].name, buf) == 0) {
191 builtins[i].func(ci->home);
195 if (key_lookup_prefix(map, ci) > 0)
197 LOG("Failed to load module: %s", name);
201 DEF_CMD(editor_auto_event)
203 /* Event handlers register under a private name so we
204 * have to use key_lookup_prefix to find them.
205 * If nothing is found, autoload lib-libevent (hack?)
207 struct ed_info *ei = ci->home->data;
208 struct map *map = ei->map;
209 int ret = key_lookup_prefix(map, ci);
213 if (strcmp(ci->key, "event:refresh") == 0)
214 /* pointless to autoload for refresh */
216 call("attach-libevent", ci->home);
217 return key_lookup_prefix(map, ci);
220 static const char *initial_panes[] = {
221 "attach-x11selection",
222 "attach-messageline",
223 "attach-global-keymap",
229 DEF_CMD(editor_activate_display)
231 /* Given a display attached to the root, integrate it
232 * into a full initial stack of panes.
234 struct pane *disp = ci->focus;
238 p = pane_root(ci->focus);
239 p2 = call_ret(pane, "attach-input", p);
241 pane_reparent(disp, p2);
243 for (i = 0; initial_panes[i]; i++) {
244 const char *cmd = initial_panes[i];
246 p2 = call_ret(pane, cmd, p);
250 comm_call(ci->comm2, "cb", p);
254 DEF_CMD(editor_multicall)
256 struct ed_info *ei = ci->home->data;
257 struct map *map = ei->map;
259 const char *key = ci->key;
261 ((struct cmd_info*)ci)->key = ksuffix(ci, "global-multicall-");
262 ret = key_lookup_prefix(map, ci);
263 ((struct cmd_info*)ci)->key = key;
267 DEF_CMD(editor_request_notify)
269 pane_add_notify(ci->focus, ci->home, ksuffix(ci, "editor:request:"));
273 DEF_CMD(editor_send_notify)
275 /* editor:notify:... */
276 return home_pane_notify(ci->home, ksuffix(ci, "editor:notify:"),
278 ci->num, ci->mark, ci->str,
279 ci->num2, ci->mark2, ci->str2, ci->comm2);
282 DEF_CMD(editor_free_panes)
284 struct ed_info *ei = ci->home->data;
286 while (ei->freelist) {
287 struct pane *p = ei->freelist;
288 ei->freelist = p->focus;
291 p->damaged &= ~DAMAGED_DEAD;
292 pane_call(p, "Free", p);
293 command_put(p->handle);
295 attr_free(&p->attrs);
301 DEF_CMD(editor_free_marks)
303 struct ed_info *ei = ci->home->data;
305 while (ei->mark_free_list) {
306 struct mark *m = ei->mark_free_list;
307 ei->mark_free_list = (struct mark*)m->all.next;
314 DEF_CMD(editor_free_store)
316 struct ed_info *ei = ci->home->data;
319 struct store *s = ei->store;
326 DEF_EXTERN_CMD(edlib_do_free)
328 if (ci->home->data_size)
329 unalloc_buf_safe(ci->home->data, ci->home->data_size, pane);
333 /* FIXME I should be able to remove things from a keymap, not
336 DEF_EXTERN_CMD(edlib_noop)
341 DEF_CMD(editor_close)
349 /* Freeing the ed_info here mustn't happen. It must be
355 void * safe memsave(struct pane *p safe, const char *buf, int len)
361 ASSERT(ei->magic==ED_MAGIC);
363 call_comm("event:on-idle", p, &editor_free_store, 2);
364 if (ei->store == NULL || ei->store->size < len) {
366 int l = 4096 - sizeof(*s);
369 s = malloc(l + sizeof(*s));
374 ei->store->size -= len;
376 return memcpy(ei->store->space+ei->store->size, buf, len);
378 return ei->store->space+ei->store->size;
381 char *strsave(struct pane *p safe, const char *buf)
385 return memsave(p, buf, strlen(buf)+1);
388 char *strnsave(struct pane *p safe, const char *buf, int len)
393 s = memsave(p, buf, len+1);
399 char * safe __strconcat(struct pane *p, const char *s1 safe, ...)
408 while ((s = va_arg(ap, char*)) != NULL)
413 ret = memsave(p, NULL, len+1);
418 while ((s = va_arg(ap, char*)) != NULL)
424 void editor_delayed_free(struct pane *ed safe, struct pane *p safe)
426 struct ed_info *ei = ed->data;
428 p->damaged &= ~DAMAGED_DEAD;
429 pane_call(p, "Free", p);
430 command_put(p->handle);
432 attr_free(&p->attrs);
436 ASSERT(ei->magic==ED_MAGIC);
438 call_comm("event:on-idle", ed, &editor_free_panes, 2);
439 p->focus = ei->freelist;
443 void editor_delayed_mark_free(struct mark *m safe)
445 struct pane *ed = pane_root(m->owner);
446 struct ed_info *ei = ed ? ed->data : NULL;
452 ASSERT(ei->magic==ED_MAGIC);
453 if (!ei->mark_free_list)
454 call_comm("event:on-idle", ed, &editor_free_marks, 2);
455 m->all.next = (void*)ei->mark_free_list;
456 ei->mark_free_list = m;
459 struct pane *editor_new(void)
465 ei->magic = ED_MAGIC;
466 ei->testing = (getenv("EDLIB_TESTING") != NULL);
467 if (! (void*) ed_map) {
468 ed_map = key_alloc();
469 key_add(ed_map, "global-set-attr", &global_set_attr);
470 key_add(ed_map, "global-set-command", &global_set_command);
471 key_add(ed_map, "global-set-command-prefix", &global_set_command);
472 key_add(ed_map, "global-get-command", &global_get_command);
473 key_add(ed_map, "global-load-module", &editor_load_module);
474 key_add(ed_map, "global-config-dir", &global_config_dir);
475 key_add_prefix(ed_map, "event:", &editor_auto_event);
476 key_add_prefix(ed_map, "global-multicall-", &editor_multicall);
477 key_add_prefix(ed_map, "editor:request:",
478 &editor_request_notify);
479 key_add_prefix(ed_map, "editor:notify:",
480 &editor_send_notify);
481 key_add(ed_map, "editor:activate-display",
482 &editor_activate_display);
483 key_add(ed_map, "Close", &editor_close);
484 key_add(ed_map, "Free", &editor_free);
486 ei->map = key_alloc();
487 key_add_chain(ei->map, ed_map);
489 ei->cmd.m = &ei->map;
490 ed = pane_register_root(&ei->cmd.c, ei, sizeof(ei));