diff options
| author | Marc André Tanner <mat@brain-dump.org> | 2017-07-08 09:52:56 +0200 |
|---|---|---|
| committer | Marc André Tanner <mat@brain-dump.org> | 2017-07-08 09:52:56 +0200 |
| commit | ad10da5cc094204eb6f319841ab73246b689abb4 (patch) | |
| tree | 9493aadbf020088befc922d61187c80c72f0f2dc /vis-marks.c | |
| parent | 5c600e15c1c1ab64f385de918c93d2bdb23955d5 (diff) | |
| download | vis-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.c | 103 |
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") }, +}; |
