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
) {
51 if (id
== VIS_MARK_SELECTION
&& vis
->win
)
52 return array_peek(&vis
->win
->jumplist
.prev
);
53 File
*file
= vis
->win
->file
;
54 if (id
< LENGTH(file
->marks
))
55 return &file
->marks
[id
];
59 enum VisMark
vis_mark_used(Vis
*vis
) {
60 return vis
->action
.mark
;
63 void vis_mark(Vis
*vis
, enum VisMark mark
) {
64 if (mark
< LENGTH(vis
->win
->file
->marks
))
65 vis
->action
.mark
= mark
;
68 static Array
mark_get(Win
*win
, Array
*mark
) {
70 array_init_sized(&sel
, sizeof(Filerange
));
73 View
*view
= win
->view
;
74 size_t len
= array_length(mark
);
75 array_reserve(&sel
, len
);
76 for (size_t i
= 0; i
< len
; i
++) {
77 SelectionRegion
*sr
= array_get(mark
, i
);
78 Filerange r
= view_regions_restore(view
, sr
);
79 if (text_range_valid(&r
))
82 vis_mark_normalize(&sel
);
86 Array
vis_mark_get(Vis
*vis
, enum VisMark id
) {
87 return mark_get(vis
->win
, mark_from(vis
, id
));
90 static void mark_set(Win
*win
, Array
*mark
, Array
*sel
) {
94 View
*view
= win
->view
;
95 for (size_t i
= 0, len
= array_length(sel
); i
< len
; i
++) {
97 Filerange
*r
= array_get(sel
, i
);
98 if (view_regions_save(view
, r
, &ss
))
103 void vis_mark_set(Vis
*vis
, enum VisMark id
, Array
*sel
) {
104 mark_set(vis
->win
, mark_from(vis
, id
), sel
);
107 void marklist_init(MarkList
*list
, size_t max
) {
110 array_init_sized(&list
->prev
, sizeof(Array
));
111 array_reserve(&list
->prev
, max
);
112 array_add(&list
->prev
, &mark
);
113 array_init_sized(&list
->next
, sizeof(Array
));
114 array_reserve(&list
->next
, max
);
117 void marklist_release(MarkList
*list
) {
118 for (size_t i
= 0, len
= array_length(&list
->prev
); i
< len
; i
++)
119 array_release(array_get(&list
->prev
, i
));
120 array_release(&list
->prev
);
121 for (size_t i
= 0, len
= array_length(&list
->next
); i
< len
; i
++)
122 array_release(array_get(&list
->next
, i
));
123 array_release(&list
->next
);
126 static bool marklist_push(Win
*win
, MarkList
*list
, Array
*sel
) {
127 Array
*top
= array_peek(&list
->prev
);
129 Array top_sel
= mark_get(win
, top
);
130 bool eq
= vis_mark_equal(&top_sel
, sel
);
131 array_release(&top_sel
);
136 for (size_t i
= 0, len
= array_length(&list
->next
); i
< len
; i
++)
137 array_release(array_get(&list
->next
, i
));
138 array_clear(&list
->next
);
141 if (array_length(&list
->prev
) >= array_capacity(&list
->prev
)) {
142 Array
*tmp
= array_get(&list
->prev
, 0);
144 array_remove(&list
->prev
, 0);
146 mark_set(win
, &arr
, sel
);
147 return array_push(&list
->prev
, &arr
);
150 bool vis_jumplist_save(Vis
*vis
) {
151 View
*view
= vis
->win
->view
;
152 Array sel
= view_selections_get_all(view
);
153 bool ret
= marklist_push(vis
->win
, &vis
->win
->jumplist
, &sel
);
158 static bool marklist_prev(Win
*win
, MarkList
*list
) {
159 View
*view
= win
->view
;
160 bool restore
= false;
161 Array cur
= view_selections_get_all(view
);
162 bool anchored
= view_selections_anchored(view_selections_primary_get(view
));
163 Array
*top
= array_peek(&list
->prev
);
166 Array top_sel
= mark_get(win
, top
);
167 restore
= !vis_mark_equal(&top_sel
, &cur
);
169 view_selections_set_all(view
, &top_sel
, anchored
);
170 array_release(&top_sel
);
174 while (array_length(&list
->prev
) > 1) {
175 Array
*prev
= array_pop(&list
->prev
);
176 array_push(&list
->next
, prev
);
177 prev
= array_peek(&list
->prev
);
178 Array sel
= mark_get(win
, prev
);
179 restore
= array_length(&sel
) > 0;
181 view_selections_set_all(view
, &sel
, anchored
);
191 static bool marklist_next(Win
*win
, MarkList
*list
) {
192 View
*view
= win
->view
;
193 bool anchored
= view_selections_anchored(view_selections_primary_get(view
));
195 Array
*next
= array_pop(&list
->next
);
198 Array sel
= mark_get(win
, next
);
199 if (array_length(&sel
) > 0) {
200 view_selections_set_all(view
, &sel
, anchored
);
202 array_push(&list
->prev
, next
);
209 bool vis_jumplist_prev(Vis
*vis
) {
210 return marklist_prev(vis
->win
, &vis
->win
->jumplist
);
213 bool vis_jumplist_next(Vis
*vis
) {
214 return marklist_next(vis
->win
, &vis
->win
->jumplist
);
217 enum VisMark
vis_mark_from(Vis
*vis
, char mark
) {
218 if (mark
>= 'a' && mark
<= 'z')
219 return VIS_MARK_a
+ mark
- 'a';
220 for (size_t i
= 0; i
< LENGTH(vis_marks
); i
++) {
221 if (vis_marks
[i
].name
== mark
)
224 return VIS_MARK_INVALID
;
227 const MarkDef vis_marks
[] = {
228 [VIS_MARK_DEFAULT
] = { '\'', VIS_HELP("Default mark") },
229 [VIS_MARK_SELECTION
] = { '^', VIS_HELP("Last selections") },