3 static int ranges_comparator(const void *a
, const void *b
) {
4 const Filerange
*r1
= a
, *r2
= b
;
5 if (!text_range_valid(r1
))
6 return text_range_valid(r2
) ? 1 : 0;
7 if (!text_range_valid(r2
))
9 return (r1
->start
< r2
->start
|| (r1
->start
== r2
->start
&& r1
->end
< r2
->end
)) ? -1 : 1;
12 void vis_mark_normalize(Array
*a
) {
13 array_sort(a
, ranges_comparator
);
14 Filerange
*prev
= NULL
, *r
= array_get(a
, 0);
15 for (size_t i
= 0; r
; r
= array_get(a
, i
)) {
16 if (text_range_size(r
) == 0) {
18 } else if (prev
&& text_range_overlap(prev
, r
)) {
19 *prev
= text_range_union(prev
, r
);
28 bool vis_mark_equal(Array
*a
, Array
*b
) {
29 size_t len
= array_length(a
);
30 if (len
!= array_length(b
))
32 for (size_t i
= 0; i
< len
; i
++) {
33 if (!text_range_equal(array_get(a
, i
), array_get(b
, i
)))
40 void mark_init(Array
*arr
) {
41 array_init_sized(arr
, sizeof(SelectionRegion
));
44 void mark_release(Array
*arr
) {
50 static Array
*mark_from(Vis
*vis
, enum VisMark id
) {
53 if (id
== VIS_MARK_SELECTION
)
54 return &vis
->win
->saved_selections
;
55 File
*file
= vis
->win
->file
;
56 if (id
< LENGTH(file
->marks
))
57 return &file
->marks
[id
];
61 enum VisMark
vis_mark_used(Vis
*vis
) {
62 return vis
->action
.mark
;
65 void vis_mark(Vis
*vis
, enum VisMark mark
) {
66 if (mark
< LENGTH(vis
->win
->file
->marks
))
67 vis
->action
.mark
= mark
;
70 static Array
mark_get(Win
*win
, Array
*mark
) {
72 array_init_sized(&sel
, sizeof(Filerange
));
75 View
*view
= win
->view
;
76 size_t len
= array_length(mark
);
77 array_reserve(&sel
, len
);
78 for (size_t i
= 0; i
< len
; i
++) {
79 SelectionRegion
*sr
= array_get(mark
, i
);
80 Filerange r
= view_regions_restore(view
, sr
);
81 if (text_range_valid(&r
))
84 vis_mark_normalize(&sel
);
88 Array
vis_mark_get(Win
*win
, enum VisMark id
) {
89 return mark_get(win
, mark_from(win
->vis
, id
));
92 static void mark_set(Win
*win
, Array
*mark
, Array
*sel
) {
96 View
*view
= win
->view
;
97 for (size_t i
= 0, len
= array_length(sel
); i
< len
; i
++) {
99 Filerange
*r
= array_get(sel
, i
);
100 if (view_regions_save(view
, r
, &ss
))
101 array_add(mark
, &ss
);
105 void vis_mark_set(Win
*win
, enum VisMark id
, Array
*sel
) {
106 mark_set(win
, mark_from(win
->vis
, id
), sel
);
109 void marklist_init(MarkList
*list
, size_t max
) {
112 array_init_sized(&list
->prev
, sizeof(Array
));
113 array_reserve(&list
->prev
, max
);
114 array_add(&list
->prev
, &mark
);
115 array_init_sized(&list
->next
, sizeof(Array
));
116 array_reserve(&list
->next
, max
);
119 void marklist_release(MarkList
*list
) {
120 for (size_t i
= 0, len
= array_length(&list
->prev
); i
< len
; i
++)
121 array_release(array_get(&list
->prev
, i
));
122 array_release(&list
->prev
);
123 for (size_t i
= 0, len
= array_length(&list
->next
); i
< len
; i
++)
124 array_release(array_get(&list
->next
, i
));
125 array_release(&list
->next
);
128 static bool marklist_push(Win
*win
, MarkList
*list
, Array
*sel
) {
129 Array
*top
= array_peek(&list
->prev
);
131 Array top_sel
= mark_get(win
, top
);
132 bool eq
= vis_mark_equal(&top_sel
, sel
);
133 array_release(&top_sel
);
138 for (size_t i
= 0, len
= array_length(&list
->next
); i
< len
; i
++)
139 array_release(array_get(&list
->next
, i
));
140 array_clear(&list
->next
);
143 if (array_length(&list
->prev
) >= array_capacity(&list
->prev
)) {
144 Array
*tmp
= array_get(&list
->prev
, 0);
146 array_remove(&list
->prev
, 0);
148 mark_set(win
, &arr
, sel
);
149 return array_push(&list
->prev
, &arr
);
152 bool vis_jumplist_save(Vis
*vis
) {
153 View
*view
= vis
->win
->view
;
154 Array sel
= view_selections_get_all(view
);
155 bool ret
= marklist_push(vis
->win
, &vis
->win
->jumplist
, &sel
);
160 static bool marklist_prev(Win
*win
, MarkList
*list
) {
161 View
*view
= win
->view
;
162 bool restore
= false;
163 Array cur
= view_selections_get_all(view
);
164 bool anchored
= view_selections_anchored(view_selections_primary_get(view
));
165 Array
*top
= array_peek(&list
->prev
);
168 Array top_sel
= mark_get(win
, top
);
169 restore
= !vis_mark_equal(&top_sel
, &cur
);
171 view_selections_set_all(view
, &top_sel
, anchored
);
172 array_release(&top_sel
);
176 while (array_length(&list
->prev
) > 1) {
177 Array
*prev
= array_pop(&list
->prev
);
178 array_push(&list
->next
, prev
);
179 prev
= array_peek(&list
->prev
);
180 Array sel
= mark_get(win
, prev
);
181 restore
= array_length(&sel
) > 0;
183 view_selections_set_all(view
, &sel
, anchored
);
193 static bool marklist_next(Win
*win
, MarkList
*list
) {
194 View
*view
= win
->view
;
195 bool anchored
= view_selections_anchored(view_selections_primary_get(view
));
197 Array
*next
= array_pop(&list
->next
);
200 Array sel
= mark_get(win
, next
);
201 if (array_length(&sel
) > 0) {
202 view_selections_set_all(view
, &sel
, anchored
);
204 array_push(&list
->prev
, next
);
211 bool vis_jumplist_prev(Vis
*vis
) {
212 return marklist_prev(vis
->win
, &vis
->win
->jumplist
);
215 bool vis_jumplist_next(Vis
*vis
) {
216 return marklist_next(vis
->win
, &vis
->win
->jumplist
);
219 enum VisMark
vis_mark_from(Vis
*vis
, char mark
) {
220 if (mark
>= 'a' && mark
<= 'z')
221 return VIS_MARK_a
+ mark
- 'a';
222 for (size_t i
= 0; i
< LENGTH(vis_marks
); i
++) {
223 if (vis_marks
[i
].name
== mark
)
226 return VIS_MARK_INVALID
;
229 const MarkDef vis_marks
[] = {
230 [VIS_MARK_DEFAULT
] = { '\'', VIS_HELP("Default mark") },
231 [VIS_MARK_SELECTION
] = { '^', VIS_HELP("Last selections") },