aboutsummaryrefslogtreecommitdiff
path: root/vis-marks.c
blob: 26dfd71fdf2252520f1084bda5532f9e24703691 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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") },
};