2 * Copyright Neil Brown ©2015-2023 <neil@brown.name>
3 * May be distributed under terms of GPLv2 - see file:COPYING
7 * A 'Mark' is a reference to a location in a text. The location
8 * is between two characters and remains there while characters
9 * are added or removed before or after.
10 * All marks are linked together in text order and are assigned
11 * sparse ordered numbers so that it is easy to determine the
12 * relative order of two points.
14 * Each mark is optionally in two lists. There is one list that
15 * contains all marks on a given text, and arbitrary other lists
16 * that contain only select marks. A given mark can only be in one
17 * of these extra lists - except for points which are described below.
19 * A mark has a list of attributes and a pointer to a handler
20 * which can be called in various circumstances to customise
21 * handling of different sections of text.
23 * A 'point' is a special mark which identifies a place where
24 * things can happen. Text can be added or removed, marks can
25 * be created or destroyed, only at a 'point'.
26 * A 'point' is on all lists. This allows nearby marks on any list to be
29 * As the 'group' lists can hold either marks or points, and with a
30 * different anchor in each, we use 'tlist_head'. Pointers in a
31 * tlist use the bottom 2 bits to store a type. We only have
32 * two types: mark or point. When we find a point we know which of the
33 * various lists because we know the index of the list we are walking.
35 * The text buffer can only be modified at a point.
36 * Prior to deleting text, all marks/points must be moved off the removed
37 * section. After adding text ... something.
39 * A mark or point can be deleted at any time with impunity.
40 * A point can be duplicated, or can fork a mark. When this happens
41 * we might need to re-assign some seq numbers to keep them sparse.
42 * A point can move forward or backward, or can jump to a mark.
43 * When that happens, various lists might need to be adjusted and
44 * seq number might need to be reassigned.
46 * There can only be one (non-borrowed) reference to a mark. So
47 * a second reference is wanted, the mark must be duplicated.
48 * How these references are stored is not yet clear. Maybe that is
49 * up to whatever module uses it.
51 * Each mark has a 'type' identifying which group it is of.
52 * Type -1 is points. They aren't like other groups.
53 * Other types(groups) can be defined as needed
54 * The number is an index into text->groups and point->lists.
56 * This is distinct from the type used by the tlist to differentiate
57 * points the location of the tlist_head. There 'GRP_MARK' is the 'group'
58 * in each mark of that group, and 'GRP_LIST' is the 'lists[n]' in each
59 * point. GRP_HEAD is the head of the list.
66 #define DOC_DATA_TYPE struct doc
68 #include "core-pane.h"
74 static struct mark *vmark_or_point_next(struct mark *m safe, int view);
75 static struct mark *vmark_or_point_prev(struct mark *m safe, int view);
77 /* seq numbers added to the end are given a gap of 128.
78 * seq numbers at other locations are placed at mean of before and after.
79 * If there is no room, seq add 256 to the 'next' seq, 255 to the one
80 * after etc until we find a seq already above the target, or reach
81 * gap size of 64. In later case we continue with fixed gap size.
83 static void assign_seq(struct mark *m safe)
91 /* First mark: start in the middle */
96 if (n && p && n->seq - p->seq >= 2) {
97 /* There is room here, so insert */
98 m->seq = p->seq + (n->seq - p->seq)/2;
101 if (!n && p->seq < INT_MAX - 1) {
102 if (INT_MAX - p->seq < gap)
103 gap = INT_MAX - p->seq;
104 m->seq = p->seq + gap / 2;
107 if (!p && n->seq > 1) {
110 m->seq = n->seq - gap / 2;
114 /* We are between two marks with no room for a seq number,
115 * need to reshuffle and try to find space somewhere.
116 * Try to spread out the current marks more so there is
117 * 'gap' space between them, but let 'gap' decrease as we
118 * go to avoid pushing too hard.
120 if (p && n && p->seq > INT_MAX / 2) {
121 while (p && n->seq - p->seq < gap) {
122 /* step back to 'p' and leave 'm' with a larger
126 m->seq = n->seq - gap;
130 m->seq = 0; /* Ouch! */
138 while (n && n->seq - p->seq < gap) {
139 if (INT_MAX - p->seq > gap)
140 m->seq = p->seq + gap;
141 else if (p->seq < INT_MAX)
144 m->seq = INT_MAX; /* Ouch! */
152 /* NOTE: p->seq may now exceed n->seq, and
153 * there might be adjacent seq numbers if we hit 0 or INT_MAX.
154 * These will be fixed up on next loop through.
157 /* We must have scanned all the way to one end, and all the way to the
158 * other, and found no space, so 4 billion marks. Seems unlikely.
163 static void point_free(struct mark *p safe)
166 struct point_links *lnk = safe_cast p->mdata;
167 for (i = 0; i < lnk->size; i++)
168 tlist_del_init(&lnk->lists[i]);
169 unalloc_buf(p->mdata, sizeof(*lnk) + lnk->size * sizeof(lnk->lists[0]),
173 void do_mark_free(struct mark *m)
178 static void mark_refcnt(struct mark *m safe, int inc)
180 struct doc *d = &m->owner->doc;
186 void mark_free(struct mark *m)
190 /* mark might have already been freed by the
191 * pane getting closed.
195 if (m->viewnum == MARK_POINT)
197 ASSERT(m->mdata == NULL);
199 hlist_del_init(&m->all);
200 if (m->viewnum != MARK_UNGROUPED)
201 tlist_del_init(&m->view);
202 attr_free(&m->attrs);
206 memset(m, 0xff, sizeof(*m));
209 m->viewnum = MARK_UNGROUPED;
210 editor_delayed_mark_free(m);
213 static void notify_mark_moving(struct mark *m safe, struct mark *m2)
215 if (m->flags & MARK_FLAG_WATCHED) {
216 m->flags &= ~MARK_FLAG_WATCHED;
217 pane_notify("mark:moving", m->owner, 0, m);
220 if (m2 && (m2->flags & MARK_FLAG_WATCHED))
221 pane_notify("mark:arrived", m->owner, 0, m, NULL, 0, m2);
224 void mark_watch(struct mark *m)
227 m->flags |= MARK_FLAG_WATCHED;
230 static void mark_ref_copy(struct mark *to safe, struct mark *from safe)
232 if (!mark_valid(to) || !mark_valid(from))
235 if ((void*)to->owner && to->owner != from->owner) {
236 LOG("mark_ref_copy given marks with different owners");
239 if (!(void*)to->owner) {
240 from->owner->marks += 1;
241 ASSERT(from->owner->marks < 20000000);
243 to->owner = from->owner;
244 if (to->ref.p == from->ref.p &&
245 to->ref.i == from->ref.i)
252 static void dup_mark(struct mark *orig safe, struct mark *new safe)
254 hlist_add_after(&orig->all, &new->all);
255 INIT_TLIST_HEAD(&new->view, GRP_MARK);
259 mark_ref_copy(new, orig);
262 struct mark *do_mark_at_point(struct mark *pt safe, int view)
265 struct point_links *lnk;
267 if (pt->viewnum != MARK_POINT)
269 lnk = safe_cast pt->mdata;
276 tlist_add(&ret->view, GRP_MARK, &lnk->lists[view]);
278 INIT_TLIST_HEAD(&ret->view, GRP_MARK);
279 notify_mark_moving(ret, pt);
283 struct mark *mark_at_point(struct pane *p safe, struct mark *pm, int view)
285 return call_ret(mark, "doc:dup-point", p, 0, pm, NULL, view);
288 struct mark *safe point_dup(struct mark *p safe)
291 struct point_links *old = safe_cast p->mdata;
293 struct point_links *lnk;
296 lnk = alloc_buf(sizeof(*lnk) + old->size * sizeof(lnk->lists[0]),
300 ret->viewnum = MARK_POINT;
302 lnk->size = old->size;
304 tlist_add(&ret->view, GRP_MARK, &p->view);
305 for (i = 0; lnk && i < lnk->size; i++)
306 if (tlist_empty(&old->lists[i]))
307 INIT_TLIST_HEAD(&lnk->lists[i], GRP_LIST);
309 tlist_add(&lnk->lists[i], GRP_LIST, &old->lists[i]);
310 notify_mark_moving(ret, p);
314 void points_resize(struct doc *d safe)
317 tlist_for_each_entry(p, &d->points, view) {
319 struct point_links *old = safe_cast p->mdata;
320 struct point_links *new = alloc_buf(sizeof(*new) +
322 sizeof(new->lists[0]),
325 new->size = d->nviews;
327 for (i = 0; i < old->size; i++) {
328 tlist_add(&new->lists[i], GRP_LIST, &old->lists[i]);
329 tlist_del(&old->lists[i]);
331 for (; i < new->size; i++)
332 INIT_TLIST_HEAD(&new->lists[i], GRP_HEAD);
337 void points_attach(struct doc *d safe, int view)
340 tlist_for_each_entry(p, &d->points, view) {
341 struct point_links *lnk = safe_cast p->mdata;
342 tlist_add_tail(&lnk->lists[view], GRP_LIST,
343 &d->views[view].head);
347 struct mark *safe mark_dup(struct mark *m safe)
356 ret->viewnum = MARK_UNGROUPED;
357 INIT_TLIST_HEAD(&ret->view, GRP_MARK);
358 notify_mark_moving(ret, m);
362 struct mark *safe mark_dup_view(struct mark *m safe)
369 if (m->viewnum == MARK_POINT)
374 if (m->viewnum == MARK_POINT) abort();
375 ret->viewnum = m->viewnum;
376 if (ret->viewnum == MARK_UNGROUPED)
377 INIT_TLIST_HEAD(&ret->view, GRP_MARK);
379 tlist_add(&ret->view, GRP_MARK, &m->view);
380 notify_mark_moving(ret, m);
384 /* if 'end', move mark after all other marks, else move before all others */
385 void mark_to_end(struct pane *p safe, struct mark *m safe, int end)
387 struct doc *d = &p->doc;
389 struct point_links *lnk;
394 ASSERT(m->owner == p);
395 notify_mark_moving(m, NULL);
399 if (hlist_empty(&d->marks))
400 hlist_add_head(&m->all, &d->marks);
402 struct mark *last = hlist_first_entry(&d->marks,
404 while (last->all.next)
405 last = hlist_next_entry(last, all);
406 hlist_add_after(&last->all, &m->all);
409 hlist_add_head(&m->all, &d->marks);
412 if (m->viewnum == MARK_UNGROUPED)
414 if (m->viewnum != MARK_POINT) {
417 tlist_add_tail(&m->view, GRP_MARK,
418 &d->views[m->viewnum].head);
420 tlist_add(&m->view, GRP_MARK,
421 &d->views[m->viewnum].head);
427 tlist_add_tail(&m->view, GRP_MARK, &d->points);
429 tlist_add(&m->view, GRP_MARK, &d->points);
431 lnk = safe_cast m->mdata;
432 for (i = 0; d->views && i < lnk->size; i++)
433 if (d->views[i].owner) {
434 tlist_del(&lnk->lists[i]);
436 tlist_add_tail(&lnk->lists[i], GRP_LIST,
439 tlist_add(&lnk->lists[i],
440 GRP_LIST, &d->views[i].head);
444 void mark_reset(struct pane *p safe, struct mark *m safe, int end)
446 ASSERT((void*)m->owner == NULL || m->owner == p);
451 if (!(void*)m->owner) {
453 ASSERT(p->marks < 20000000);
456 pane_call(p, "doc:set-ref", p, !end, m);
459 struct mark *mark_first(struct doc *d safe)
461 if (!hlist_empty(&d->marks))
462 return hlist_first_entry(&d->marks, struct mark, all);
466 struct mark *mark_next(struct mark *m safe)
468 if (mark_valid(m) && m->all.next)
469 return hlist_next_entry(m, all);
473 struct mark *mark_prev(struct mark *m safe)
475 if (mark_valid(m) && !HLIST_IS_HEAD(m->all.pprev))
476 return hlist_prev_entry(m, all);
480 struct mark *doc_new_mark(struct pane *p safe, int view, struct pane *owner)
482 /* FIXME view is >= -1 */
484 struct doc *d = &p->doc;
486 if (view >= d->nviews ||
487 view < MARK_UNGROUPED ||
488 (view >= 0 && (!d->views || d->views[view].owner != owner))) {
489 /* Erroneous call, or race with document closing down */
493 INIT_HLIST_NODE(&ret->all);
494 INIT_TLIST_HEAD(&ret->view, GRP_MARK);
496 hlist_add_head(&ret->all, &d->marks);
498 if (view == MARK_POINT) {
499 struct point_links *lnk = alloc_buf(sizeof(*lnk) +
501 sizeof(lnk->lists[0]),
505 lnk->size = d->nviews;
507 for (i = 0; i < d->nviews; i++)
508 INIT_TLIST_HEAD(&lnk->lists[i], GRP_LIST);
511 mark_reset(p, ret, 0);
512 if (hlist_unhashed(&ret->all)) {
513 /* Document misbehaved, fail gracefully */
520 /* Movement of points and marks.
522 * Both points and marks can move.
523 * Marks can move forward or backward one character. They only
524 * step over other marks if they have to.
525 * To move a mark to another mark of the same group, or to a
526 * point, the mark needs to be deleted and a new one created.
527 * Points can step fore/back like marks. They can jump to another
528 * point easily but to move to mark they must walk one mark at a time.
530 * Note that 'm' isn't 'safe' - A NULL mark will be step to point
531 * by the doc redirector.
534 wint_t do_doc_step(struct pane *p safe, struct mark *m,
535 int forward, int move)
538 static int dodebug = -1;
542 dodebug = atoi(getenv("EDLIB_DEBUG_MARKS")?:"10000");
544 if (m && dodebug && count++ >= dodebug) {
546 doc_check_consistent(&m->owner->doc);
550 ret = call("doc:char", p, forward ? 1 : -1, m);
552 ret = call("doc:char", p, 0, m, NULL, forward ? 1 : -1);
555 if ((unsigned)ret >= CHAR_RET(WEOF))
558 return ret & 0x1fffff;
561 /* Move the point so it is at the same location as the mark, both in the
563 * Firstly find the point closest to the mark, though that will often
564 * be the point we already have.
565 * Then for each mark group we find the last that is before the target,
566 * and move the point to there.
567 * Then update 'all' list, text ref and seq number.
570 static void point_forward_to_mark(struct mark *p safe, struct mark *m safe)
572 struct mark *ptmp, *pnear;
574 struct point_links *plnk = safe_cast p->mdata;
578 tlist_for_each_entry_continue(ptmp, GRP_HEAD, view) {
579 if (ptmp->seq <= m->seq)
584 /* pnear is the nearest point to m that is before m. So
585 * move p after pnear in the point list. */
588 tlist_add(&p->view, GRP_MARK, &pnear->view);
591 /* Now move 'p' in the various mark lists */
592 for (i = 0; i < plnk->size; i++) {
593 struct mark *mnear = NULL;
594 struct tlist_head *tl;
595 struct point_links *pnlnk = safe_cast pnear->mdata;
597 tl = &pnlnk->lists[i];
600 tlist_for_each_continue(tl, GRP_HEAD) {
602 if (TLIST_TYPE(tl) != GRP_MARK)
604 mtmp = container_of(tl, struct mark, view);
605 if (mtmp->seq <= m->seq)
611 tlist_del(&plnk->lists[i]);
612 tlist_add(&plnk->lists[i], GRP_LIST, &mnear->view);
613 } else if (p != pnear) {
614 tlist_del(&plnk->lists[i]);
615 tlist_add(&plnk->lists[i], GRP_LIST, &pnlnk->lists[i]);
618 /* finally move in the overall list */
620 hlist_add_after(&m->all, &p->all);
624 static void point_backward_to_mark(struct mark *p safe, struct mark *m safe)
626 struct mark *ptmp, *pnear;
628 struct point_links *plnk = safe_cast p->mdata;
632 tlist_for_each_entry_continue_reverse(ptmp, GRP_HEAD, view) {
633 if (ptmp->seq >= m->seq)
638 /* pnear is the nearest point to m that is after m. So
639 * move p before pnear in the point list */
642 tlist_add_tail(&p->view, GRP_MARK, &pnear->view);
645 /* Now move 'p' in the various mark lists */
646 for (i = 0; i < plnk->size; i++) {
647 struct mark *mnear = NULL;
648 struct tlist_head *tl;
649 struct point_links *pnlnk = safe_cast pnear->mdata;
651 tl = &pnlnk->lists[i];
654 tlist_for_each_continue_reverse(tl, GRP_HEAD) {
656 if (TLIST_TYPE(tl) != GRP_MARK)
658 mtmp = container_of(tl, struct mark, view);
659 if (mtmp->seq >= m->seq)
665 tlist_del(&plnk->lists[i]);
666 tlist_add_tail(&plnk->lists[i], GRP_LIST, &mnear->view);
667 } else if (p != pnear) {
668 tlist_del(&plnk->lists[i]);
669 tlist_add_tail(&plnk->lists[i], GRP_LIST,
673 /* finally move in the overall list */
675 hlist_add_before(&p->all, &m->all);
679 static void _mark_to_mark_noref(struct mark *m safe, struct mark *target safe)
681 /* DEBUG: Make sure they are on same list */
682 struct mark *a = m, *b = target;
684 if (!mark_valid(m) || !mark_valid(target))
686 if (a->owner != b->owner)
687 LOG("mark_to_mark: marks have different owners");
689 if (m->seq > target->seq) {
695 LOG("mark_to_mark with marks on different list - same owner");
698 call("editor:notify:Message:broadcast",
700 "WARNING marks inconsistent - see log");
707 if (!mark_same(m, target))
708 notify_mark_moving(m, target);
709 if (m->viewnum == MARK_POINT) {
710 /* Lots of linkage to fix up */
711 if (m->seq < target->seq)
712 point_forward_to_mark(m, target);
713 else if (m->seq > target->seq)
714 point_backward_to_mark(m, target);
717 if (m->viewnum == MARK_UNGROUPED) {
718 /* Only one linked list to worry about */
719 if (m->seq < target->seq) {
721 hlist_add_after(&target->all, &m->all);
725 hlist_add_before(&m->all, &target->all);
726 m->seq = target->seq;
731 if (m->viewnum == target->viewnum) {
732 /* Same view, both on the same 2 lists */
733 if (m->seq < target->seq) {
735 hlist_add_after(&target->all, &m->all);
737 tlist_add(&m->view, GRP_MARK, &target->view);
741 hlist_add_before(&m->all, &target->all);
743 tlist_add_tail(&m->view, GRP_MARK, &target->view);
744 m->seq = target->seq;
749 if (target->viewnum == MARK_POINT) {
750 /* A vmark and a point, both on the only 2 lists
751 * that need changing */
752 struct point_links *lnks = safe_cast target->mdata;
753 if (m->seq < target->seq) {
755 hlist_add_after(&target->all, &m->all);
757 tlist_add(&m->view, GRP_MARK, &lnks->lists[m->viewnum]);
761 hlist_add_before(&m->all, &target->all);
763 tlist_add_tail(&m->view, GRP_MARK,
764 &lnks->lists[m->viewnum]);
765 m->seq = target->seq;
770 /* Hard case: We have a vmark and a mark which isn't on the same list.
771 * We need to find a matching vmark 'close' to the destination and link
774 if (m->seq < target->seq) {
775 struct mark *m1 = m, *n;
776 while ((n = vmark_or_point_next(m1, m->viewnum)) != NULL &&
777 n->seq <= target->seq)
781 if (m1->viewnum == MARK_POINT) {
782 struct point_links *lnks = safe_cast m1->mdata;
783 tlist_add(&m->view, GRP_MARK,
784 &lnks->lists[m->viewnum]);
786 tlist_add(&m->view, GRP_MARK, &m1->view);
789 hlist_add_after(&target->all, &m->all);
792 struct mark *m1 = m, *n;
793 while ((n = vmark_or_point_prev(m1, m->viewnum)) != NULL &&
794 n->seq >= target->seq)
798 if (m1->viewnum == MARK_POINT) {
799 struct point_links *lnks = safe_cast m1->mdata;
800 tlist_add_tail(&m->view, GRP_MARK,
801 &lnks->lists[m->viewnum]);
803 tlist_add_tail(&m->view, GRP_MARK, &m1->view);
806 hlist_add_before(&m->all, &target->all);
807 m->seq = target->seq;
812 void mark_to_mark_noref(struct mark *m safe, struct mark *target safe)
816 static bool warned = False;
818 _mark_to_mark_noref(m, target);
820 if (m2 && !mark_same(m2, m) &&
821 pane_call(m->owner, "debug:validate-marks", m->owner,
822 0, m2, NULL, 0, m) < 0)
825 if (m2 && !mark_same(m, m2) &&
826 pane_call(m->owner, "debug:validate-marks", m->owner,
827 0, m, NULL, 0, m2) < 0)
830 if (err && !warned) {
832 call("editor:notify:Message:broadcast",
834 "WARNING: marks inconsistent in mark_to_mark, check log");
839 void mark_to_mark(struct mark *m safe, struct mark *target safe)
841 _mark_to_mark_noref(m, target);
842 mark_ref_copy(m, target);
845 void mark_step(struct mark *m safe, int forward)
847 /* step mark forward, or backward, over all marks with same
850 struct mark *m2, *target = m;
852 /* This is called after .ref has been updated, so we can
853 * assume the point really is moving.
855 notify_mark_moving(m, NULL);
858 for (m2 = mark_next(m);
859 m2 && mark_same(m, m2);
863 for (m2 = mark_prev(m);
864 m2 && mark_same(m, m2);
868 mark_to_mark_noref(m, target);
871 void mark_step_sharesref(struct mark *m safe, int forward)
873 /* step mark forward, or backward, over all marks with same
874 * ref, ignoring the .i, and sets '.i' to a safe value wrt the
875 * last mark stepped over.
877 struct mark *m2, *target = m;
879 /* This is called after .ref has been updated, so we can
880 * assume the point really is moving.
882 notify_mark_moving(m, NULL);
885 for (m2 = mark_next(m);
886 m2 && m->ref.p == m2->ref.p;
890 for (m2 = mark_prev(m);
891 m2 && m->ref.p == m2->ref.p;
895 m->ref.i = target->ref.i;
896 mark_to_mark_noref(m, target);
899 /* A 'vmark' is a mark in a particular view. We can walk around those
900 * silently skipping over the points.
903 static struct mark *_vmark_next(struct tlist_head *tl safe)
905 while (TLIST_TYPE(tl) != GRP_HEAD) {
906 if (TLIST_TYPE(tl) == GRP_LIST) {
907 tl = TLIST_PTR(tl->next);
910 return container_of(tl, struct mark, view);
915 struct mark *vmark_next(struct mark *m safe)
917 struct tlist_head *tl;
922 tl = TLIST_PTR(m->view.next);
923 return _vmark_next(tl);
926 static struct mark *vmark_or_point_next(struct mark *m safe, int view)
928 struct tlist_head *tl;
929 struct point_links *lnk;
931 if (m->viewnum == view)
932 tl = TLIST_PTR(m->view.next);
933 else if (m->viewnum == MARK_POINT) {
934 lnk = safe_cast m->mdata;
935 tl = TLIST_PTR(lnk->lists[view].next);
938 switch(TLIST_TYPE(tl)) {
943 return container_of(tl, struct mark, view);
945 lnk = container_of_array(tl, struct point_links, lists, view);
950 static struct mark *_vmark_prev(struct tlist_head *tl safe)
952 while (TLIST_TYPE(tl) != GRP_HEAD) {
953 if (TLIST_TYPE(tl) == GRP_LIST) {
954 tl = TLIST_PTR(tl->prev);
957 return container_of(tl, struct mark, view);
962 struct mark *vmark_prev(struct mark *m safe)
964 struct tlist_head *tl;
969 tl = TLIST_PTR(m->view.prev);
970 return _vmark_prev(tl);
973 static struct mark *vmark_or_point_prev(struct mark *m safe, int view)
975 struct tlist_head *tl;
976 struct point_links *lnk;
978 if (m->viewnum == view)
979 tl = TLIST_PTR(m->view.prev);
980 else if (m->viewnum == MARK_POINT) {
981 lnk = safe_cast m->mdata;
982 tl = TLIST_PTR(lnk->lists[view].prev);
985 switch(TLIST_TYPE(tl)) {
990 return container_of(tl, struct mark, view);
992 lnk = container_of_array(tl, struct point_links, lists, view);
997 struct mark *do_vmark_first(struct doc *d safe, int view,
998 struct pane *owner safe)
1000 struct tlist_head *tl;
1002 if (view < 0 || view >= d->nviews || d->views == NULL)
1004 if (d->views[view].owner != owner)
1007 tl = TLIST_PTR(d->views[view].head.next);
1008 while (TLIST_TYPE(tl) != GRP_HEAD) {
1009 if (TLIST_TYPE(tl) == GRP_LIST) {
1010 tl = TLIST_PTR(tl->next);
1013 return container_of(tl, struct mark, view);
1018 struct mark *do_vmark_last(struct doc *d safe, int view,
1019 struct pane *owner safe)
1021 struct tlist_head *tl;
1023 if (view < 0 || view >= d->nviews || d->views == NULL)
1025 if (d->views[view].owner != owner)
1028 tl = TLIST_PTR(d->views[view].head.prev);
1029 while (TLIST_TYPE(tl) != GRP_HEAD) {
1030 if (TLIST_TYPE(tl) == GRP_LIST) {
1031 tl = TLIST_PTR(tl->prev);
1034 return container_of(tl, struct mark, view);
1039 struct mark *vmark_first(struct pane *p safe, int view, struct pane *owner safe)
1041 return home_call_ret(mark, p, "doc:vmark-get", owner, view);
1044 struct mark *vmark_last(struct pane *p safe, int view, struct pane *owner safe)
1046 return home_call_ret(mark2, p, "doc:vmark-get", owner, view);
1049 struct mark *vmark_at_or_before(struct pane *p safe, struct mark *m safe,
1050 int view, struct pane *owner)
1052 return home_call_ret(mark, p, "doc:vmark-prev", owner?:p,
1056 struct mark *vmark_new(struct pane *p safe, int view, struct pane *owner)
1058 return home_call_ret(mark, p, "doc:vmark-new", owner?:p, view);
1061 struct mark *vmark_matching(struct mark *m safe)
1063 /* Find a nearby mark in the same view with the same ref */
1070 if (m2 && mark_same(m, m2))
1073 if (m2 && mark_same(m, m2))
1078 struct mark *do_vmark_at_or_before(struct doc *d safe,
1079 struct mark *m safe,
1080 int view, struct pane *owner)
1082 /* Find the last 'view' mark that is not later in the document than 'm'.
1083 * It might be later in the mark list, but not in the document.
1084 * Return NULL if all 'view' marks are after 'm' in the document.
1086 struct mark *vm = m;
1091 if (&m->owner->doc != d) {
1092 LOG("vmark_at_or_before called with incorrect mark");
1096 if ((view < 0 && view != MARK_POINT) || view >= d->nviews ||
1097 d->views == NULL || d->views[view].owner != owner)
1100 /* might need to hunt along 'all' list for something suitable */
1101 while (vm && vm->viewnum != MARK_POINT && vm->viewnum != view)
1105 while (vm && vm->viewnum != MARK_POINT && vm->viewnum != view)
1109 /* No 'view' marks at all! */
1111 /* 'vm' is either a point or a 'view' mark. It is probably after 'm',
1112 * but if it is before, then no 'view' mark is after.
1114 if (vm->viewnum == MARK_POINT) {
1115 struct point_links *lnk = safe_cast vm->mdata;
1116 struct tlist_head *tl = &lnk->lists[view];
1117 vm = _vmark_next(tl);
1119 vm = _vmark_prev(tl);
1120 else if (mark_same(vm, m)) {
1121 /* maybe there are even more */
1123 while ((vm2 = vmark_next(vm)) != NULL &&
1127 } else if (vm->viewnum == view) {
1128 /* Just use this, or nearby */
1130 while ((vm2 = vmark_next(vm)) != NULL &&
1134 while (vm && !mark_ordered_or_same(vm, m))
1135 vm = vmark_prev(vm);
1140 void mark_clip(struct mark *m safe, struct mark *start, struct mark *end,
1143 /* Note: if this is called while looping over a list of marks,
1144 * the loop should move forward when tostart,
1145 * and backward when !tostart.
1147 if (!mark_valid(m) || !mark_valid(start) || !mark_valid(end))
1149 if (!mark_ordered_or_same(start, m))
1151 if (!mark_ordered_not_same(m, end))
1155 mark_to_mark(m, start);
1157 mark_to_mark(m, end);
1160 void marks_clip(struct pane *p safe, struct mark *start, struct mark *end,
1161 int view, struct pane *owner, bool tostart)
1163 struct mark *m, *m2;
1165 if (!mark_valid(start) || !mark_valid(end))
1169 m = vmark_at_or_before(p, start, view, owner);
1170 while (m && (m2=vmark_prev(m)) && mark_same(start, m2))
1172 while (m && !mark_ordered_or_same(start, m))
1175 while (m && !mark_ordered_or_same(end, m)) {
1177 mark_clip(m, start, end, tostart);
1181 m = vmark_at_or_before(p, end, view, owner);
1182 while (m && (m2=vmark_next(m)) && mark_same(end,m2))
1184 while (m && !mark_ordered_not_same(m, end))
1187 while (m && !mark_ordered_not_same(m, start)) {
1189 mark_clip(m, start, end, tostart);
1195 void doc_check_consistent(struct doc *d safe)
1197 /* Check consistency of marks, and abort if not.
1199 * - all marks are in seq order
1200 * - all view lists are in seq order
1202 struct mark *m, *m2 = NULL;
1206 static bool warned = False;
1208 if (pane_no_consistency(safe_cast container_of(d, struct pane, doc)))
1211 hlist_for_each_entry(m, &d->marks, all) {
1212 ASSERT(m->seq >= seq);
1213 ASSERT(&m->owner->doc == d);
1215 if (m2 && !marks_validate(m2, m) && !warned) {
1217 call("editor:notify:Message:broadcast",
1219 "WARNING: mark inconsistency, check log");
1226 for (i = 0; d->views && i < d->nviews; i++)
1227 if (d->views[i].owner == NULL) {
1228 if (!tlist_empty(&d->views[i].head)) abort();
1230 struct tlist_head *tl;
1231 struct point_links *pl;
1233 tlist_for_each(tl, &d->views[i].head) {
1234 switch(TLIST_TYPE(tl)) {
1235 case GRP_HEAD: abort();
1237 m = container_of(tl, struct mark, view);
1240 pl = container_of_array(
1241 tl, struct point_links,
1256 bool marks_validate(struct mark *m1 safe, struct mark *m2 safe)
1259 struct doc *d = &m1->owner->doc;
1265 for (m = mark_first(d); m; m = mark_next(m)) {
1271 LOG("marks_validate: marks not found");
1274 if (m1->seq >= m2->seq) {
1275 m = m1; m1 = m2; m2 = m;
1278 for (m = mark_first(d); m; m = mark_next(m)) {
1279 if (m == m1 || m == m2)
1285 LOG("log_val_marks not both found, only %d", found);
1288 if (mark_same(m1, m2))
1290 ret = pane_call(m1->owner, "debug:validate-marks", m1->owner,
1291 0, m1, NULL, 0, m2);
1292 return (ret > 0 || ret == Efallthrough);