aboutsummaryrefslogtreecommitdiff
path: root/vis-marks.c
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2017-07-08 09:52:56 +0200
committerMarc André Tanner <mat@brain-dump.org>2017-07-08 09:52:56 +0200
commitad10da5cc094204eb6f319841ab73246b689abb4 (patch)
tree9493aadbf020088befc922d61187c80c72f0f2dc /vis-marks.c
parent5c600e15c1c1ab64f385de918c93d2bdb23955d5 (diff)
downloadvis-ad10da5cc094204eb6f319841ab73246b689abb4.tar.gz
vis-ad10da5cc094204eb6f319841ab73246b689abb4.tar.xz
vis: cleanup marks implementation
We now use ' to refer to marks. Mark a is set using 'am and restored using 'aM while this is slightly harder to type than ma and 'a it is consistent with register usage for yank/put and allows a default mark to be used which is handy for quick selection manipulation primitives.
Diffstat (limited to 'vis-marks.c')
-rw-r--r--vis-marks.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/vis-marks.c b/vis-marks.c
new file mode 100644
index 0000000..edf0757
--- /dev/null
+++ b/vis-marks.c
@@ -0,0 +1,103 @@
+#include "vis-core.h"
+
+static int ranges_comparator(const void *a, const void *b) {
+ const Filerange *r1 = a, *r2 = b;
+ if (!text_range_valid(r1))
+ return text_range_valid(r2) ? 1 : 0;
+ if (!text_range_valid(r2))
+ return -1;
+ return (r1->start < r2->start || (r1->start == r2->start && r1->end < r2->end)) ? -1 : 1;
+}
+
+void vis_mark_normalize(Array *a) {
+ array_sort(a, ranges_comparator);
+ Filerange *prev = NULL, *r = array_get(a, 0);
+ for (size_t i = 0; r; r = array_get(a, i)) {
+ if (text_range_size(r) == 0) {
+ array_remove(a, i);
+ } else if (prev && text_range_overlap(prev, r)) {
+ *prev = text_range_union(prev, r);
+ array_remove(a, i);
+ } else {
+ prev = r;
+ i++;
+ }
+ }
+}
+
+void marks_init(Array *arr) {
+ array_init_sized(arr, sizeof(SelectionRegion));
+}
+
+void mark_release(Array *arr) {
+ if (!arr)
+ return;
+ array_release(arr);
+}
+
+
+static Array *mark_from(Vis *vis, enum VisMark id) {
+ if (id == VIS_MARK_SELECTION && vis->win)
+ return &vis->win->saved_selections;
+ File *file = vis->win->file;
+ if (id < LENGTH(file->marks))
+ return &file->marks[id];
+ return NULL;
+}
+
+enum VisMark vis_mark_used(Vis *vis) {
+ return vis->action.mark;
+}
+
+void vis_mark(Vis *vis, enum VisMark mark) {
+ if (mark < LENGTH(vis->win->file->marks))
+ vis->action.mark = mark;
+}
+
+Array vis_mark_get(Vis *vis, enum VisMark id) {
+ Array sel;
+ array_init_sized(&sel, sizeof(Filerange));
+ Array *mark = mark_from(vis, id);
+ if (!mark)
+ return sel;
+ View *view = vis->win->view;
+ size_t len = array_length(mark);
+ array_reserve(&sel, len);
+ for (size_t i = 0; i < len; i++) {
+ SelectionRegion *sr = array_get(mark, i);
+ Filerange r = view_regions_restore(view, sr);
+ if (text_range_valid(&r))
+ array_add(&sel, &r);
+ }
+ vis_mark_normalize(&sel);
+ return sel;
+}
+
+void vis_mark_set(Vis *vis, enum VisMark id, Array *sel) {
+ Array *mark = mark_from(vis, id);
+ if (!mark)
+ return;
+ array_clear(mark);
+ View *view = vis->win->view;
+ for (size_t i = 0, len = array_length(sel); i < len; i++) {
+ SelectionRegion ss;
+ Filerange *r = array_get(sel, i);
+ if (view_regions_save(view, r, &ss))
+ array_add(mark, &ss);
+ }
+}
+
+enum VisMark vis_mark_from(Vis *vis, char mark) {
+ if (mark >= 'a' && mark <= 'z')
+ return VIS_MARK_a + mark - 'a';
+ for (size_t i = 0; i < LENGTH(vis_marks); i++) {
+ if (vis_marks[i].name == mark)
+ return i;
+ }
+ return VIS_MARK_INVALID;
+}
+
+const MarkDef vis_marks[] = {
+ [VIS_MARK_DEFAULT] = { '"', VIS_HELP("Default mark") },
+ [VIS_MARK_SELECTION] = { '^', VIS_HELP("Last selections") },
+};