/*
- * Copyright Neil Brown ©2015-2020 <neil@brown.name>
+ * Copyright Neil Brown ©2015-2023 <neil@brown.name>
* May be distributed under terms of GPLv2 - see file:COPYING
*
* Keymaps for edlib.
if (!comm)
return;
+ if (strcmp(k, "Close") == 0 &&
+ !comm->closed_ok) {
+ LOG("WARNING: Command %s registered for \"Close\" but not marked closed_ok",
+ comm->name);
+ }
pos = key_find(map, k);
/* cases:
const struct cmd_info *ci safe;
struct backtrace *prev;
} *backtrace;
+static int backtrace_depth;
static char *mark_info(struct mark *m)
{
if (ret)
return ret;
- asprintf(&ret, "M:%x<%p>", m->seq, m);
+ asprintf(&ret, "M:%d<%p>%d", m->seq, m, m->ref.i);
return ret;
}
LOG("End Backtrace");
}
-static int do_comm_call(struct command *comm safe,
- const struct cmd_info *ci safe)
+int do_comm_call(struct command *comm safe, const struct cmd_info *ci safe)
{
struct backtrace bt;
int ret;
+ if (ci->home->damaged & DAMAGED_DEAD)
+ return Efail;
+ if (times_up_fast(ci->home))
+ return Efail;
+ if ((ci->home->damaged & DAMAGED_CLOSED) &&
+ !comm->closed_ok)
+ return Efallthrough;
+
+ if (backtrace_depth > 100) {
+ backtrace_depth = 0;
+ LOG("Recursion limit of 100 reached");
+ LOG_BT();
+ backtrace_depth = 100;
+ pane_root(ci->home)->timestamp = 1;
+ return Efail;
+ }
bt.comm = comm;
bt.ci = ci;
bt.prev = backtrace;
backtrace = &bt;
+ backtrace_depth += 1;
ret = comm->func(ci);
backtrace = bt.prev;
+ backtrace_depth -= 1;
return ret;
}
}
}
-int key_lookup_prefix(struct map *m safe, const struct cmd_info *ci safe)
+int key_lookup_prefix(struct map *m safe, const struct cmd_info *ci safe,
+ bool simple)
{
- int pos = key_find(m, ci->key);
- struct command *comm, *prev = NULL;
- int len = strlen(ci->key);
+ /* A "Simple" lookup avoids the backtrace. It is used in
+ * signal handlers.
+ */
const char *k = ci->key;
- int ret = 0;
+ int len = strlen(k);
+ int pos = key_find(m, k);
+ struct command *comm, *prev = NULL;
+ int ret = Efallthrough;
+ int i;
- while (ret == 0 && pos < m->size &&
- strncmp(m->keys[pos], k, len) == 0) {
- comm = GETCOMM(m->comms[pos]);
+ for (i = 0;
+ ret == Efallthrough && pos+i < m->size &&
+ strncmp(m->keys[pos+i], k, len) == 0;
+ i++) {
+ comm = GETCOMM(m->comms[pos+i]);
if (comm && comm != prev) {
((struct cmd_info*)ci)->comm = comm;
- ((struct cmd_info*)ci)->key = m->keys[pos];
- ret = do_comm_call(comm, ci);
- ASSERT(ret >= 0 || ret < Eunused);
+ ((struct cmd_info*)ci)->key = m->keys[pos+i];
+ if (simple)
+ ret = comm->func(ci);
+ else
+ ret = do_comm_call(comm, ci);
+ ASSERT(ret >= Efallthrough || ret < Eunused);
prev = comm;
+ /* something might have been added, recalc
+ * start pos.
+ */
+ pos = key_find(m, k);
}
- pos += 1;
}
((struct cmd_info*)ci)->key = k;
return ret;
struct pane *p;
unsigned int hash[2];
+ if (ci->mark && !mark_valid(ci->mark))
+ return Einval;
+ if (ci->mark2 && !mark_valid(ci->mark2))
+ return Einval;
+
+ if (times_up(ci->home))
+ return Efail;
time_start_key(ci->key);
if ((void*) ci->comm) {
int ret = do_comm_call(ci->comm, ci);
while (p) {
int ret = Efallthrough;
- if (p->handle && !(p->damaged & DAMAGED_DEAD)) {
+ if (p->handle &&
+ (p->handle->closed_ok ||
+ !(p->damaged & DAMAGED_CLOSED))) {
vci->home = p;
vci->comm = p->handle;
/* Don't add this to the call stack as it
- * should simple call the desired function and
+ * should simply call the desired function and
* that will appear on the call stack.
*/
ret = p->handle->func(ci);