diff options
Diffstat (limited to 'vis-marks.c')
| -rw-r--r-- | vis-marks.c | 144 |
1 files changed, 136 insertions, 8 deletions
diff --git a/vis-marks.c b/vis-marks.c index 26dfd71..e04f6b0 100644 --- a/vis-marks.c +++ b/vis-marks.c @@ -25,7 +25,19 @@ void vis_mark_normalize(Array *a) { } } -void marks_init(Array *arr) { +bool vis_mark_equal(Array *a, Array *b) { + size_t len = array_length(a); + if (len != array_length(b)) + return false; + for (size_t i = 0; i < len; i++) { + if (!text_range_equal(array_get(a, i), array_get(b, i))) + return false; + } + + return true; +} + +void mark_init(Array *arr) { array_init_sized(arr, sizeof(SelectionRegion)); } @@ -35,7 +47,6 @@ void mark_release(Array *arr) { array_release(arr); } - static Array *mark_from(Vis *vis, enum VisMark id) { if (id == VIS_MARK_SELECTION && vis->win) return &vis->win->saved_selections; @@ -54,13 +65,12 @@ void vis_mark(Vis *vis, enum VisMark mark) { vis->action.mark = mark; } -Array vis_mark_get(Vis *vis, enum VisMark id) { +static Array mark_get(Win *win, Array *mark) { Array sel; array_init_sized(&sel, sizeof(Filerange)); - Array *mark = mark_from(vis, id); if (!mark) return sel; - View *view = vis->win->view; + View *view = win->view; size_t len = array_length(mark); array_reserve(&sel, len); for (size_t i = 0; i < len; i++) { @@ -73,12 +83,15 @@ Array vis_mark_get(Vis *vis, enum VisMark id) { return sel; } -void vis_mark_set(Vis *vis, enum VisMark id, Array *sel) { - Array *mark = mark_from(vis, id); +Array vis_mark_get(Vis *vis, enum VisMark id) { + return mark_get(vis->win, mark_from(vis, id)); +} + +static void mark_set(Win *win, Array *mark, Array *sel) { if (!mark) return; array_clear(mark); - View *view = vis->win->view; + View *view = win->view; for (size_t i = 0, len = array_length(sel); i < len; i++) { SelectionRegion ss; Filerange *r = array_get(sel, i); @@ -87,6 +100,121 @@ void vis_mark_set(Vis *vis, enum VisMark id, Array *sel) { } } +void vis_mark_set(Vis *vis, enum VisMark id, Array *sel) { + mark_set(vis->win, mark_from(vis, id), sel); +} + +void marklist_init(MarkList *list, size_t max) { + array_init_sized(&list->prev, sizeof(Array)); + array_reserve(&list->prev, max); + array_init_sized(&list->next, sizeof(Array)); + array_reserve(&list->next, max); +} + +void marklist_release(MarkList *list) { + for (size_t i = 0, len = array_length(&list->prev); i < len; i++) + array_release(array_get(&list->prev, i)); + array_release(&list->prev); + for (size_t i = 0, len = array_length(&list->next); i < len; i++) + array_release(array_get(&list->next, i)); + array_release(&list->next); +} + +static bool marklist_push(Win *win, MarkList *list, Array *sel) { + Array *top = array_peek(&list->prev); + if (top) { + Array top_sel = mark_get(win, top); + bool eq = vis_mark_equal(&top_sel, sel); + array_release(&top_sel); + if (eq) + return true; + } + + for (size_t i = 0, len = array_length(&list->next); i < len; i++) + array_release(array_get(&list->next, i)); + array_clear(&list->next); + Array arr; + mark_init(&arr); + if (array_length(&list->prev) >= array_capacity(&list->prev)) { + Array *tmp = array_get(&list->prev, 0); + arr = *tmp; + array_remove(&list->prev, 0); + } + mark_set(win, &arr, sel); + return array_push(&list->prev, &arr); +} + +bool vis_jumplist_save(Vis *vis) { + View *view = vis->win->view; + Array sel = view_selections_get_all(view); + bool ret = marklist_push(vis->win, &vis->win->jumplist, &sel); + array_release(&sel); + return ret; +} + +static bool marklist_prev(Win *win, MarkList *list) { + View *view = win->view; + bool restore = false; + Array cur = view_selections_get_all(view); + bool anchored = view_selections_anchored(view_selections_primary_get(view)); + Array *top = array_peek(&list->prev); + if (!top) + goto out; + Array top_sel = mark_get(win, top); + restore = !vis_mark_equal(&top_sel, &cur); + if (restore) + view_selections_set_all(view, &top_sel, anchored); + array_release(&top_sel); + if (restore) + goto out; + + for (;;) { + Array *prev = array_pop(&list->prev); + if (!prev) + goto out; + array_push(&list->next, prev); + prev = array_peek(&list->prev); + if (!prev) + goto out; + Array sel = mark_get(win, prev); + restore = array_length(&sel) > 0; + if (restore) + view_selections_set_all(view, &sel, anchored); + array_release(&sel); + if (restore) + goto out; + } +out: + array_release(&cur); + return restore; +} + +static bool marklist_next(Win *win, MarkList *list) { + View *view = win->view; + bool anchored = view_selections_anchored(view_selections_primary_get(view)); + for (;;) { + Array *next = array_pop(&list->next); + if (!next) + return false; + Array sel = mark_get(win, next); + if (array_length(&sel) > 0) { + view_selections_set_all(view, &sel, anchored); + array_release(&sel); + array_push(&list->prev, next); + return true; + } + array_release(next); + } +} + +bool vis_jumplist_prev(Vis *vis) { + return marklist_prev(vis->win, &vis->win->jumplist); +} + +bool vis_jumplist_next(Vis *vis) { + return marklist_next(vis->win, &vis->win->jumplist); +} + enum VisMark vis_mark_from(Vis *vis, char mark) { if (mark >= 'a' && mark <= 'z') return VIS_MARK_a + mark - 'a'; |
