/*
- * Copyright Neil Brown ©2016-2020 <neil@brown.name>
+ * Copyright Neil Brown ©2016-2023 <neil@brown.name>
* May be distributed under terms of GPLv2 - see file:COPYING
*
* doc-multipart: Present a sequence of documents as though it were
int docnum; /* may be 'nparts', in which case 'm' == NULL */
};
-/* mark->refs in marks we create on individual component documents
+/* mark->mdata in marks we create on individual component documents
* is used to track if the mark is shared among multiple marks in the
* multipart document.
*/
+#define GET_REFS(_mark) ((unsigned long)((_mark)->mdata))
+#define SET_REFS(_mark, val) ((_mark)->mdata = (void*)(unsigned long)(val))
+#define ADD_REFS(_mark, inc) SET_REFS(_mark, GET_REFS(_mark) + (inc))
+#define DOC_DATA_TYPE struct mp_info
+
+#define DOC_NEXT(p,m,r,b) multipart_next_prev(p, m, r, 1, b, ci->str)
+#define DOC_PREV(p,m,r,b) multipart_next_prev(p, m, r, 0, b, ci->str)
+#define DOC_NEXT_DECL(p,m,r,b) multipart_next_prev(p, m, r, int forward, b, const char *str)
+#define DOC_PREV_DECL(p,m,r,b) multipart_next_prev(p, m, r, int forward, b, const char *str)
#include "core.h"
struct mp_info {
int nparts;
int parts_size;
struct part {
- struct pane *pane safe;
- } *parts safe;
+ struct pane *pane;
+ } *parts;
};
+#include "core-pane.h"
static struct map *mp_map safe;
{
struct mark *m2;
- if (!m->ref.m || m->ref.m->refs == 1)
+ if (!m->ref.m || GET_REFS(m->ref.m) == 1)
return;
/* Mark is shared, make it unshared */
m2 = mark_dup(m->ref.m);
- m->ref.m->refs -= 1;
- m2->refs = 1;
+ ADD_REFS(m->ref.m, -1);
+ SET_REFS(m2, 1);
m->ref.m = m2;
}
* Then ensure that if neighbouring marks are at same location,
* they use same marks.
*/
- struct mark *m2;
+ struct mark *m2, *mtarget;
if (!m || hlist_unhashed(&m->all))
return;
- ASSERT(m->ref.m == NULL || m->ref.m->refs == 1);
- while ((m2 = mark_next(m)) != NULL &&
+ ASSERT(m->ref.m == NULL || GET_REFS(m->ref.m) == 1);
+ mtarget = m;
+ while ((m2 = mark_next(mtarget)) != NULL &&
(m2->ref.docnum < m->ref.docnum ||
(m2->ref.docnum == m->ref.docnum &&
m2->ref.m && m->ref.m &&
- m2->ref.m->seq < m->ref.m->seq))) {
- /* m should be after m2 */
- mark_to_mark_noref(m, m2);
- }
-
- while ((m2 = mark_prev(m)) != NULL &&
+ m2->ref.m->seq < m->ref.m->seq)))
+ mtarget = m2;
+ if (mtarget != m)
+ /* m should be after mtarget */
+ mark_to_mark_noref(m, mtarget);
+
+ mtarget = m;
+ while ((m2 = mark_prev(mtarget)) != NULL &&
(m2->ref.docnum > m->ref.docnum||
(m2->ref.docnum == m->ref.docnum &&
m2->ref.m && m->ref.m &&
- m2->ref.m->seq > m->ref.m->seq))) {
- /* m should be before m2 */
- mark_to_mark_noref(m, m2);
- }
+ m2->ref.m->seq > m->ref.m->seq)))
+ mtarget = m2;
+ if (mtarget != m)
+ /* m should be before mtarget */
+ mark_to_mark_noref(m, mtarget);
+
if (!m->ref.m)
return;
- ASSERT(m->ref.m->refs == 1);
+ ASSERT(GET_REFS(m->ref.m) == 1);
/* Check if it should be shared */
m2 = mark_next(m);
if (m2 && m2->ref.docnum == m->ref.docnum && m2->ref.m) {
if (m->ref.m != m2->ref.m &&
mark_same(m->ref.m, m2->ref.m)) {
- m->ref.m->refs = 0;
+ SET_REFS(m->ref.m, 0);
mark_free(m->ref.m);
m->ref.m = m2->ref.m;
- m->ref.m->refs += 1;
+ ADD_REFS(m->ref.m, 1);
return;
}
}
if (m2 && m2->ref.docnum == m->ref.docnum && m2->ref.m) {
if (m->ref.m != m2->ref.m &&
mark_same(m->ref.m, m2->ref.m)) {
- m->ref.m->refs = 0;
+ SET_REFS(m->ref.m, 0);
mark_free(m->ref.m);
m->ref.m = m2->ref.m;
- m->ref.m->refs += 1;
+ ADD_REFS(m->ref.m, 1);
return;
}
}
if (inc > 0)
/* Duplicate being created of this mark */
- m->ref.m->refs += 1;
+ ADD_REFS(m->ref.m, 1);
if (inc < 0) {
/* mark is being discarded, or ref over-written */
- m->ref.m->refs -= 1;
- if (m->ref.m->refs == 0)
+ ADD_REFS(m->ref.m, -1);
+ if (GET_REFS(m->ref.m) == 0)
mark_free(m->ref.m);
m->ref.m = NULL;
}
static void mp_check_consistent(struct mp_info *mpi safe)
{
-// struct mark *m;
struct doc *d = &mpi->doc;
-// int s = -1;
-
- doc_check_consistent(d);
#if 0
+ struct mark *m;
+ int s = -1;
+ int max = 1000;
+
for (m = mark_first(d); m; m = mark_next(m)) {
if (!m->ref.m || m->ref.m->seq <= s) {
for (m = mark_first(d); m;
abort();
}
s = m->ref.m->seq;
+ if (max-- < 0)
+ break;
}
- doc_check_consistent(d);
#endif
+ doc_check_consistent(d);
}
static void change_part(struct mp_info *mpi safe, struct mark *m safe,
struct mark *m1;
struct part *p;
- if (part < 0 || part > mpi->nparts)
+ if (part < 0 || part > mpi->nparts || !mpi->parts)
return;
if (m->ref.m) {
- ASSERT(m->ref.m->refs == 1);
- m->ref.m->refs = 0;
+ ASSERT(GET_REFS(m->ref.m) == 1);
+ SET_REFS(m->ref.m, 0);
mark_free(m->ref.m);
+ m->ref.m = NULL;
}
- if (part < mpi->nparts) {
- p = &mpi->parts[part];
- m1 = vmark_new(p->pane, MARK_UNGROUPED, NULL);
+ if (part < mpi->nparts && (p = &mpi->parts[part]) && p->pane) {
+ m1 = mark_new(p->pane);
if (m1) {
call("doc:set-ref", p->pane, !end, m1);
m->ref.m = m1;
- m1->refs = 1;
+ SET_REFS(m1, 1);
}
} else
m->ref.m = NULL;
/* If points the end of a document, point to the start
* of the next instead.
*/
- while (m->ref.m &&
- doc_following(mpi->parts[m->ref.docnum].pane,
- m->ref.m) == WEOF) {
+ struct part *p;
+ if (!mpi->parts)
+ return;
+ while (m->ref.m && (p = &mpi->parts[m->ref.docnum]) && p->pane &&
+ doc_following(p->pane, m->ref.m) == WEOF) {
int n = m->ref.docnum + 1;
while (n < mpi->nparts && vis && vis[n] == 'i')
n += 1;
}
}
-DEF_CMD(mp_close)
+DEF_CMD_CLOSED(mp_close)
{
- struct mp_info *mpi = ci->home->data;
+ struct mp_info *mpi = ci->home->doc_data;
int i;
struct mark *m;
if (m->ref.m) {
struct mark *m2 = m->ref.m;
m->ref.m = NULL;
- m2->refs -= 1;
- if (m2->refs == 0)
+ ADD_REFS(m2, -1);
+ if (GET_REFS(m2) == 0)
mark_free(m2);
}
- for (i = 0; i < mpi->nparts; i++)
- call("doc:closed", mpi->parts[i].pane);
- doc_free(&mpi->doc);
- return 1;
-}
-
-DEF_CMD(mp_free)
-{
- struct mp_info *mpi = ci->home->data;
-
+ if (!mpi->parts)
+ return Efallthrough;
+ for (i = 0; i < mpi->nparts; i++) {
+ struct pane *p = mpi->parts[i].pane;
+ if (p)
+ call("doc:closed", p);
+ }
free(mpi->parts);
- unalloc(mpi, pane);
- return 1;
+ mpi->parts = NULL;
+ return Efallthrough;
}
DEF_CMD(mp_set_ref)
{
- struct mp_info *mpi = ci->home->data;
+ struct mp_info *mpi = ci->home->doc_data;
const char *vis = ci->str && (int)strlen(ci->str) >= mpi->nparts ?
ci->str : NULL;
int ret = 1;
return ret;
}
-DEF_CMD(mp_step)
+static inline wint_t multipart_next_prev(struct pane *home safe, struct mark *mark safe,
+ struct doc_ref *r safe,
+ int forward, bool bytes, const char *str)
{
- struct mp_info *mpi = ci->home->data;
+ int move = r == &mark->ref;
+ struct mp_info *mpi = home->doc_data;
struct mark *m1 = NULL;
- struct mark *m = ci->mark;
- const char *vis = ci->str && (int)strlen(ci->str) >= mpi->nparts ?
- ci->str : NULL;
+ struct mark *m = mark;
+ const char *vis = str && (int)strlen(str) >= mpi->nparts ?
+ str : NULL;
int n;
int ret;
* calls the document. Then make sure the marks are still in
* order.
*/
- mp_check_consistent(mpi);
- if (!m)
- return Enoarg;
mp_check_consistent(mpi);
- if (ci->num2) {
- mark_step(m, ci->num);
+ if (move) {
+ mark_step(m, forward);
pre_move(m);
}
m1 = m->ref.m;
- if (m->ref.docnum == mpi->nparts)
+ if (m->ref.docnum >= mpi->nparts || !mpi->parts)
ret = -1;
else
ret = home_call(mpi->parts[m->ref.docnum].pane,
- ci->key, ci->focus, ci->num, m1, ci->str,
- ci->num2, NULL, ci->str2, 0,0, ci->comm2);
+ "doc:char", home,
+ move ? (forward ? 1 : -1) : 0,
+ m1, str,
+ move ? 0 : (forward ? 1 : -1),
+ NULL, NULL);
while (ret == CHAR_RET(WEOF) || ret == -1) {
- if (!ci->num2 && m == ci->mark) {
- /* don't change ci->mark when not moving */
+ if (!move && m == mark) {
+ /* don't change mark when not moving */
m = mark_dup(m);
pre_move(m);
}
- if (ci->num) {
+ if (forward) {
if (m->ref.docnum >= mpi->nparts)
break;
n = m->ref.docnum + 1;
n += 1;
change_part(mpi, m, n, 0);
} else {
- if (m->ref.docnum == 0)
- break;
n = m->ref.docnum - 1;
while (n >= 0 && vis && vis[n] == 'i')
n -= 1;
change_part(mpi, m, n, 1);
}
m1 = m->ref.m;
- if (m->ref.docnum == mpi->nparts)
+ if (m->ref.docnum >= mpi->nparts || !mpi->parts)
ret = -1;
else
ret = home_call(mpi->parts[m->ref.docnum].pane,
- ci->key, ci->focus,
- ci->num, m1, ci->str,
- ci->num2, NULL, ci->str2,
- 0,0, ci->comm2);
+ "doc:char", home,
+ move ? (forward ? 1 : -1) : 0,
+ m1, str,
+ move ? 0 : (forward ? 1 : -1));
}
- if (ci->num2) {
- mp_normalize(mpi, ci->mark, vis);
- post_move(ci->mark);
+ if (move) {
+ mp_normalize(mpi, mark, vis);
+ post_move(mark);
}
- if (m != ci->mark)
+ if (m != mark)
mark_free(m);
mp_check_consistent(mpi);
return ret == -1 ? (int)CHAR_RET(WEOF) : ret;
}
+DEF_CMD(mp_char)
+{
+ return do_char_byte(ci);
+}
+
DEF_CMD(mp_step_part)
{
/* Step forward or backward to part boundary.
* Return part number plus 1.
* If ->str is given, only consider visible parts.
*/
- struct mp_info *mpi = ci->home->data;
+ struct mp_info *mpi = ci->home->doc_data;
struct mark *m = ci->mark;
const char *vis = ci->str && (int)strlen(ci->str) >= mpi->nparts ?
ci->str : NULL;
+ int start;
+ int first_vis;
int n;
if (!m)
return Enoarg;
pre_move(m);
- n = m->ref.docnum;
+ start = m->ref.docnum;
+ n = start;
if (ci->num > 0) {
/* Forward - start of next part */
n += 1;
/* If this part is empty, need to move to next visible part */
mp_normalize(mpi, m, vis);
+ first_vis = 0;
+ while (vis && vis[first_vis] == 'i')
+ first_vis++;
+ while (ci->num < 0 && m->ref.docnum == start && n > first_vis) {
+ /* didn't move - must have an empty part, try further */
+ n -= 1;
+ change_part(mpi, m, n, 0);
+ mp_normalize(mpi, m, vis);
+ }
post_move(m);
+ if (ci->num && start == m->ref.docnum)
+ return Efail;
return m->ref.docnum + 1;
}
+DEF_CMD(mp_get_boundary)
+{
+ /* return a mark past which rendering must not go. */
+ struct mark *m = ci->mark;
+
+ if (!m || !ci->comm2)
+ return Enoarg;
+ m = mark_dup(m);
+ call("doc:step-part", ci->home, ci->num, m, ci->str);
+ comm_call(ci->comm2, "cb", ci->focus, 0, m);
+ return 1;
+}
+
+struct mp_cb {
+ struct command c;
+ struct command *cb;
+ struct pane *p safe;
+ struct mark *m safe;
+ int last_ret;
+};
+
+DEF_CB(mp_content_cb)
+{
+ struct mp_cb *c = container_of(ci->comm, struct mp_cb, c);
+ struct mark *m1 = NULL;
+
+ if (ci->mark) {
+ m1 = c->m;
+ pre_move(m1);
+ if (m1->ref.m)
+ mark_to_mark(m1->ref.m, ci->mark);
+ post_move(m1);
+ }
+
+ c->last_ret = comm_call(c->cb, ci->key, c->p,
+ ci->num, m1, ci->str,
+ ci->num2, NULL, ci->str2,
+ ci->x, ci->y);
+ return c->last_ret;
+}
+
+DEF_CMD(mp_content)
+{
+ /* Call doc:content on any visible docs in the range.
+ * Callback must re-wrap any marks
+ */
+ struct mp_info *mpi = ci->home->doc_data;
+ struct mp_cb cb;
+ struct mark *m, *m2;
+ const char *invis = ci->str;
+ int ret = 1;
+
+ if (!ci->mark || !ci->comm2)
+ return Enoarg;
+ m = mark_dup(ci->mark);
+ m2 = ci->mark2;
+ cb.last_ret = 1;
+ while (cb.last_ret > 0 && m->ref.docnum < mpi->nparts &&
+ mpi->parts &&
+ (!m2 || m->ref.docnum <= m2->ref.docnum)) {
+ /* Need to call doc:content on this document */
+ int n = m->ref.docnum;
+ if ((!invis || invis[n] != 'i') && m->ref.m) {
+ struct mark *m2a = NULL;
+ struct mark *mtmp = NULL;
+ cb.c = mp_content_cb;
+ cb.cb = ci->comm2;
+ cb.p = ci->focus;
+ cb.m = m;
+
+ if (m->ref.m)
+ mtmp = mark_dup(m->ref.m);
+ if (m2 && m2->ref.docnum == n && m2->ref.m)
+ m2a = mark_dup(m2->ref.m);
+
+ ret = home_call_comm(mpi->parts[n].pane,
+ ci->key, ci->home, &cb.c,
+ ci->num, mtmp, NULL,
+ ci->num2, m2a);
+ mark_free(m2a);
+ mark_free(mtmp);
+ if (ret < 0)
+ break;
+ }
+ if (cb.last_ret > 0) {
+ pre_move(m);
+ change_part(mpi, m, n+1, 0);
+ post_move(m);
+ }
+ }
+ mark_free(m);
+ return ret;
+}
+
DEF_CMD(mp_attr)
{
- struct mp_info *mpi = ci->home->data;
+ struct mp_info *mpi = ci->home->doc_data;
struct mark *m1 = NULL;
- int ret;
+ struct part *p;
+ int ret = Efallthrough;
int d;
const char *attr = ci->str;
m1 = ci->mark->ref.m;
d = ci->mark->ref.docnum;
- if (d < mpi->nparts && m1 &&
- doc_following(mpi->parts[d].pane, m1) == WEOF)
+ if (d < mpi->nparts && m1 && mpi->parts && (p = &mpi->parts[d]) &&
+ p->pane && doc_following(p->pane, m1) == WEOF)
/* at the wrong end of a part */
d += 1;
- if (strncmp(attr, "multipart-next:", 15) == 0) {
+ if (strstarts(attr, "multipart-next:")) {
d += 1;
attr += 15;
if (d >= mpi->nparts)
return 1;
- } else if (strncmp(attr, "multipart-prev:", 15) == 0) {
+ } else if (strstarts(attr, "multipart-prev:")) {
d -= 1;
attr += 15;
if (d < 0)
return 1;
- } else if (strncmp(attr, "multipart-this:", 15) == 0)
+ } else if (strstarts(attr, "multipart-this:"))
attr += 15;
if (strcmp(attr, "multipart:part-num") == 0) {
return 1;
}
- if (d >= mpi->nparts || d < 0)
+ if (d >= mpi->nparts || d < 0 || !mpi->parts)
return 1;
if (attr != ci->str) {
return 1;
}
- if (d != ci->mark->ref.docnum) {
- m1 = vmark_new(mpi->parts[d].pane, MARK_UNGROUPED, NULL);
- call("doc:set-ref", mpi->parts[d].pane,
+ p = &mpi->parts[d];
+ if (d != ci->mark->ref.docnum && p->pane) {
+ m1 = mark_new(p->pane);
+ call("doc:set-ref", p->pane,
(d > ci->mark->ref.docnum), m1);
}
- ret = home_call(mpi->parts[d].pane,
- ci->key, ci->focus, ci->num, m1, ci->str,
- ci->num2, NULL, ci->str2, 0,0, ci->comm2);
+ if (p->pane)
+ ret = home_call(p->pane,
+ ci->key, ci->focus, ci->num, m1, ci->str,
+ ci->num2, NULL, ci->str2, 0,0, ci->comm2);
if (d != ci->mark->ref.docnum)
mark_free(m1);
return ret;
DEF_CMD(mp_set_attr)
{
- struct mp_info *mpi = ci->home->data;
+ struct mp_info *mpi = ci->home->doc_data;
+ struct part *p;
struct mark *m = ci->mark;
struct mark *m1;
int dn;
return Enoarg;
if (!m)
return Efallthrough;
+ if (!mpi->parts)
+ return Efail;
dn = m->ref.docnum;
m1 = m->ref.m;
- if (dn < mpi->nparts && m1 &&
- doc_step(mpi->parts[dn].pane, m1, ci->num, 0) == WEOF) {
- /* at the wrong end of a part */
- if (ci->num)
- dn += 1;
- else if (dn > 0)
- dn -= 1;
- }
-
- if (strncmp(attr, "multipart-prev:", 15) == 0) {
- dn -= 1;
- attr += 15;
- } else if (strncmp(attr, "multipart-next:", 15) == 0) {
- dn += 1;
- attr += 15;
+ if (strstarts(attr, "multipart-")) {
+ /* Set an attribute on a part */
+ if (strstarts(attr, "multipart-prev:") &&
+ dn > 0 && (p = &mpi->parts[dn-1]) && p->pane)
+ attr_set_str(&p->pane->attrs,
+ attr+15, ci->str2);
+ else if (strstarts(attr, "multipart-next:") &&
+ dn < mpi->nparts && (p = &mpi->parts[dn+1]) && p->pane)
+ attr_set_str(&p->pane->attrs,
+ attr+15, ci->str2);
+ else if (strstarts(attr, "multipart-this:") &&
+ (p = &mpi->parts[dn]) && p->pane)
+ attr_set_str(&p->pane->attrs,
+ attr+15, ci->str2);
+ else
+ return Efail;
+ return 1;
}
- return Efallthrough;
+ /* Send the request to a sub-document */
+ p = &mpi->parts[dn];
+ if (p->pane)
+ return call(ci->key, p->pane, ci->num, m1, ci->str,
+ 0, NULL, ci->str2);
+ return Efail;
}
DEF_CMD(mp_notify_close)
/* sub-document has been closed.
* Can we survive? or should we just shut down?
*/
- pane_close(ci->home);
- return 1;
+ struct mp_info *mpi = ci->home->doc_data;
+ int i;
+
+ for (i = 0; i < mpi->nparts && mpi->parts; i++)
+ if (mpi->parts[i].pane == ci->focus) {
+ /* sub-document has been closed.
+ * Can we survive? or should we just shut down?
+ */
+ mpi->parts[i].pane = NULL;
+ pane_close(ci->home);
+ return 1;
+ }
+ /* Not a sub-pane, maybe an owner for vmarks */
+ return Efallthrough;
}
DEF_CMD(mp_notify_viewers)
return 1;
}
+DEF_CMD(mp_doc_replaced)
+{
+ /* Something changed in a component, report that the
+ * whole doc changed - simplest for now.
+ */
+ pane_notify("doc:replaced", ci->home);
+ return 1;
+}
+
static void mp_resize(struct mp_info *mpi safe, int size)
{
if (mpi->parts_size >= size)
DEF_CMD(mp_add)
{
- struct mp_info *mpi = ci->home->data;
+ struct mp_info *mpi = ci->home->doc_data;
struct mark *m;
int n;
pane_add_notify(ci->home, ci->focus, "Notify:Close");
home_call(ci->focus, "doc:request:doc:notify-viewers", ci->home);
+ home_call(ci->focus, "doc:request:doc:replaced", ci->home);
return 1;
}
+DEF_CMD(mp_forward_by_num)
+{
+ struct mp_info *mpi = ci->home->doc_data;
+ struct mark *m1 = NULL, *m2 = NULL;
+ struct part *p;
+ const char *key;
+ int d;
+ int ret;
+
+ key = ksuffix(ci, "doc:multipart-");
+ d = atoi(key);
+ key = strchr(key, '-');
+ if (!key)
+ return Einval;
+ key += 1;
+
+ if (d >= mpi->nparts || d < 0 || !mpi->parts)
+ return 1;
+
+ if (ci->mark && ci->mark->ref.docnum == d)
+ m1 = ci->mark->ref.m;
+ if (ci->mark2 && ci->mark2->ref.docnum == d)
+ m2 = ci->mark2->ref.m;
+
+ p = &mpi->parts[d];
+ if (p->pane)
+ ret = call(key, p->pane, ci->num, m1, ci->str,
+ ci->num2, m2, ci->str2, ci->x, ci->y, ci->comm2);
+ else
+ ret = Efail;
+ return ret;
+}
+
+DEF_CMD(mp_get_part)
+{
+ struct mp_info *mpi = ci->home->doc_data;
+ struct part *p;
+ int d = ci->num;
+
+ if (d < 0 || d >= mpi->nparts || !mpi->parts)
+ return Einval;
+ p = &mpi->parts[d];
+ if (p->pane)
+ comm_call(ci->comm2, "cb", p->pane);
+ return 1;
+}
+
DEF_CMD(mp_forward)
{
/* forward this command to this/next/prev document based on
* ci->mark2.
* ci->mark is forwarded if it is in same document
*/
- struct mp_info *mpi = ci->home->data;
+ struct mp_info *mpi = ci->home->doc_data;
+ struct part *p;
struct mark *m1, *m2;
const char *key;
int d;
if (!ci->mark2)
return Enoarg;
-
+ if (!mpi->parts)
+ return Efail;
m2 = ci->mark2->ref.m;
d = ci->mark2->ref.docnum;
- if (d < mpi->nparts && m2 &&
- doc_following(mpi->parts[d].pane, m2) == WEOF)
+ if (d < mpi->nparts && m2 && (p = &mpi->parts[d]) && p->pane &&
+ doc_following(p->pane, m2) == WEOF)
/* at the wrong end of a part */
d += 1;
m1 = NULL;
if (ci->mark && ci->mark->ref.docnum == d)
m1 = ci->mark->ref.m;
- return call(key, mpi->parts[d].pane, ci->num, m1, ci->str,
- ci->num2, NULL, ci->str2, 0,0, ci->comm2);
+ p = &mpi->parts[d];
+ if (p->pane)
+ return call(key, p->pane, ci->num, m1, ci->str,
+ ci->num2, NULL, ci->str2, 0,0, ci->comm2);
+ return Efail;
+}
+
+DEF_CMD(mp_val_marks)
+{
+ struct mark *m1, *m2;
+
+ if (!ci->mark || !ci->mark2)
+ return Enoarg;
+
+ if (ci->mark->ref.docnum < ci->mark2->ref.docnum)
+ return 1;
+ if (ci->mark->ref.docnum > ci->mark2->ref.docnum) {
+ LOG("mp_val_marks: docs not in order");
+ return Efalse;
+ }
+
+ m1 = ci->mark->ref.m;
+ m2 = ci->mark->ref.m;
+ if (m1 == m2)
+ return 1;
+ if (m1 && m2 && m1->seq > m2->seq) {
+ LOG("mp_val_marks: subordinate marks out of order!");
+ return Efalse;
+ }
+ if (!m1)
+ LOG("mp_val_marks: m1 is NULL");
+ else if (!m2 || marks_validate(m1, m2))
+ return 1;
+ return Efalse;
}
static void mp_init_map(void)
mp_map = key_alloc();
key_add_chain(mp_map, doc_default_cmd);
key_add(mp_map, "doc:set-ref", &mp_set_ref);
- key_add(mp_map, "doc:step", &mp_step);
+ key_add(mp_map, "doc:char", &mp_char);
+ key_add(mp_map, "doc:content", &mp_content);
+ key_add(mp_map, "doc:content-bytes", &mp_content);
key_add(mp_map, "doc:get-attr", &mp_attr);
key_add(mp_map, "doc:set-attr", &mp_set_attr);
key_add(mp_map, "doc:step-part", &mp_step_part);
+ key_add(mp_map, "doc:get-boundary", &mp_get_boundary);
key_add(mp_map, "Close", &mp_close);
- key_add(mp_map, "Free", &mp_free);
key_add(mp_map, "Notify:Close", &mp_notify_close);
key_add(mp_map, "doc:notify-viewers", &mp_notify_viewers);
+ key_add(mp_map, "doc:replaced", &mp_doc_replaced);
key_add(mp_map, "multipart-add", &mp_add);
+ key_add(mp_map, "debug:validate-marks", &mp_val_marks);
+ key_add(mp_map, "doc:multipart:get-part", &mp_get_part);
key_add_prefix(mp_map, "multipart-this:", &mp_forward);
key_add_prefix(mp_map, "multipart-next:", &mp_forward);
key_add_prefix(mp_map, "multipart-prev:", &mp_forward);
+ key_add_prefix(mp_map, "doc:multipart-", &mp_forward_by_num);
}
DEF_LOOKUP_CMD(mp_handle, mp_map);
struct mp_info *mpi;
struct pane *h;
- alloc(mpi, pane);
-
- h = doc_register(ci->home, &mp_handle.c, mpi);
- if (h) {
- mpi->doc.refcnt = mp_mark_refcnt;
- attr_set_str(&h->attrs, "render-default", "text");
- return comm_call(ci->comm2, "callback:doc", h);
- }
+ h = doc_register(ci->home, &mp_handle.c);
+ if (!h)
+ return Efail;
+ mpi = h->doc_data;
- free(mpi);
- return Efail;
+ mpi->doc.refcnt = mp_mark_refcnt;
+ attr_set_str(&h->attrs, "render-default", "text");
+ return comm_call(ci->comm2, "callback:doc", h);
}
void edlib_init(struct pane *ed safe)