dte test coverage


Directory: ./
File: src/move.c
Date: 2025-02-14 16:55:22
Exec Total Coverage
Lines: 131 176 74.4%
Functions: 18 19 94.7%
Branches: 57 92 62.0%

Line Branch Exec Source
1 #include "move.h"
2 #include "buffer.h"
3 #include "indent.h"
4 #include "util/ascii.h"
5 #include "util/debug.h"
6 #include "util/macros.h"
7 #include "util/utf8.h"
8
9 typedef enum {
10 CT_SPACE,
11 CT_NEWLINE,
12 CT_WORD,
13 CT_OTHER,
14 } CharTypeEnum;
15
16 59 void move_to_preferred_x(View *view, long preferred_x)
17 {
18 59 const LocalOptions *options = &view->buffer->options;
19 59 view->preferred_x = preferred_x;
20 59 block_iter_bol(&view->cursor);
21 59 StringView line = block_iter_get_line(&view->cursor);
22
23
4/4
✓ Branch 0 (4→5) taken 24 times.
✓ Branch 1 (4→12) taken 35 times.
✓ Branch 2 (5→6) taken 9 times.
✓ Branch 3 (5→12) taken 15 times.
59 if (options->emulate_tab && view->preferred_x < line.length) {
24 9 const size_t iw = options->indent_width;
25 9 const size_t ilevel = indent_level(view->preferred_x, iw);
26
3/4
✓ Branch 0 (10→11) taken 77 times.
✗ Branch 1 (10→12) not taken.
✓ Branch 2 (11→7) taken 68 times.
✓ Branch 3 (11→12) taken 9 times.
77 for (size_t i = 0; i < line.length && line.data[i] == ' '; i++) {
27
1/2
✗ Branch 0 (7→8) not taken.
✓ Branch 1 (7→10) taken 68 times.
68 if (i + 1 == (ilevel + 1) * iw) {
28 // Force cursor to beginning of the indentation level
29 view->cursor.offset += ilevel * iw;
30 return;
31 }
32 }
33 }
34
35 59 const unsigned int tw = options->tab_width;
36 59 unsigned long x = 0;
37 59 size_t i = 0;
38
4/4
✓ Branch 0 (24→25) taken 283 times.
✓ Branch 1 (24→26) taken 40 times.
✓ Branch 2 (25→13) taken 264 times.
✓ Branch 3 (25→26) taken 19 times.
323 while (x < view->preferred_x && i < line.length) {
39 264 CodePoint u = line.data[i++];
40
1/2
✓ Branch 0 (13→14) taken 264 times.
✗ Branch 1 (13→20) not taken.
264 if (likely(u < 0x80)) {
41
2/2
✓ Branch 0 (14→15) taken 262 times.
✓ Branch 1 (14→16) taken 2 times.
264 if (likely(!ascii_iscntrl(u))) {
42 262 x++;
43
1/2
✓ Branch 0 (16→17) taken 2 times.
✗ Branch 1 (16→18) not taken.
2 } else if (u == '\t') {
44 2 x = next_indent_width(x, tw);
45 } else if (u == '\n') {
46 break;
47 } else {
48 x += 2;
49 }
50 } else {
51 const size_t next = i;
52 i--;
53 u = u_get_nonascii(line.data, line.length, &i);
54 x += u_char_width(u);
55 if (x > view->preferred_x) {
56 i = next;
57 break;
58 }
59 }
60 }
61
1/2
✗ Branch 0 (26→27) not taken.
✓ Branch 1 (26→28) taken 59 times.
59 if (x > view->preferred_x) {
62 i--;
63 }
64 59 view->cursor.offset += i;
65
66 // If cursor stopped on a zero-width char, move to the next spacing char
67 59 CodePoint u;
68
3/4
✓ Branch 0 (29→30) taken 55 times.
✓ Branch 1 (29→33) taken 4 times.
✗ Branch 2 (31→32) not taken.
✓ Branch 3 (31→33) taken 55 times.
59 if (block_iter_get_char(&view->cursor, &u) && u_is_zero_width(u)) {
69 block_iter_next_column(&view->cursor);
70 }
71 }
72
73 16 void move_cursor_left(View *view)
74 {
75 16 const LocalOptions *options = &view->buffer->options;
76
2/2
✓ Branch 0 (2→3) taken 2 times.
✓ Branch 1 (2→8) taken 14 times.
16 if (options->emulate_tab) {
77 2 size_t size = get_indent_level_bytes_left(options, &view->cursor);
78
1/2
✗ Branch 0 (4→5) not taken.
✓ Branch 1 (4→8) taken 2 times.
2 if (size) {
79 block_iter_back_bytes(&view->cursor, size);
80 view_reset_preferred_x(view);
81 return;
82 }
83 }
84 16 block_iter_prev_column(&view->cursor);
85 16 view_reset_preferred_x(view);
86 }
87
88 31 void move_cursor_right(View *view)
89 {
90 31 const LocalOptions *options = &view->buffer->options;
91
2/2
✓ Branch 0 (2→3) taken 15 times.
✓ Branch 1 (2→8) taken 16 times.
31 if (options->emulate_tab) {
92 15 size_t size = get_indent_level_bytes_right(options, &view->cursor);
93
1/2
✗ Branch 0 (4→5) not taken.
✓ Branch 1 (4→8) taken 15 times.
15 if (size) {
94 block_iter_skip_bytes(&view->cursor, size);
95 view_reset_preferred_x(view);
96 return;
97 }
98 }
99 31 block_iter_next_column(&view->cursor);
100 31 view_reset_preferred_x(view);
101 }
102
103 7 void move_bol(View *view)
104 {
105 7 block_iter_bol(&view->cursor);
106 7 view_reset_preferred_x(view);
107 7 }
108
109 7 void move_bol_smart(View *view, SmartBolType type)
110 {
111
1/2
✓ Branch 0 (2→3) taken 7 times.
✗ Branch 1 (2→5) not taken.
7 if (type == BOL_SIMPLE) {
112 7 move_bol(view);
113 7 return;
114 }
115
116 StringView line;
117 size_t cursor_offset = fetch_this_line(&view->cursor, &line);
118 bool at_bol = (cursor_offset == 0);
119 if (at_bol && type == BOL_INDENT) {
120 // At BOL and not using toggle; nothing to do
121 goto out;
122 }
123
124 size_t indent = ascii_blank_prefix_length(line.data, line.length);
125 if (at_bol) {
126 // At BOL and using toggle; move right to first non-blank char
127 block_iter_skip_bytes(&view->cursor, indent);
128 goto out;
129 }
130
131 // Not at BOL; move left (either to BOL or leftmost non-blank) depending on
132 // `type` and whether the cursor is before or after the leftmost non-blank
133 size_t co = cursor_offset;
134 size_t move = (co > indent && type != BOL_TOGGLE_LR) ? co - indent : co;
135 block_iter_back_bytes(&view->cursor, move);
136
137 out:
138 view_reset_preferred_x(view);
139 }
140
141 6 void move_eol(View *view)
142 {
143 6 block_iter_eol(&view->cursor);
144 6 view_reset_preferred_x(view);
145 6 }
146
147 19 void move_up(View *view, long count)
148 {
149 19 const long x = view_get_preferred_x(view);
150
2/2
✓ Branch 0 (7→4) taken 20 times.
✓ Branch 1 (7→8) taken 16 times.
36 while (count > 0) {
151
2/2
✓ Branch 0 (5→6) taken 17 times.
✓ Branch 1 (5→8) taken 3 times.
20 if (!block_iter_prev_line(&view->cursor)) {
152 break;
153 }
154 17 count--;
155 }
156 19 move_to_preferred_x(view, x);
157 19 }
158
159 15 void move_down(View *view, long count)
160 {
161 15 const long x = view_get_preferred_x(view);
162
2/2
✓ Branch 0 (7→4) taken 12 times.
✓ Branch 1 (7→8) taken 15 times.
27 while (count > 0) {
163
1/2
✓ Branch 0 (5→6) taken 12 times.
✗ Branch 1 (5→8) not taken.
12 if (!block_iter_eat_line(&view->cursor)) {
164 break;
165 }
166 12 count--;
167 }
168 15 move_to_preferred_x(view, x);
169 15 }
170
171 7 void move_bof(View *view)
172 {
173 7 block_iter_bof(&view->cursor);
174 7 view_reset_preferred_x(view);
175 7 }
176
177 6 void move_eof(View *view)
178 {
179 6 block_iter_eof(&view->cursor);
180 6 view_reset_preferred_x(view);
181 6 }
182
183 3 void move_to_line(View *view, size_t line)
184 {
185 3 BUG_ON(line == 0);
186 3 view->center_on_scroll = true;
187 3 block_iter_goto_line(&view->cursor, line - 1);
188 3 }
189
190 void move_to_column(View *view, size_t column)
191 {
192 BUG_ON(column == 0);
193 block_iter_bol(&view->cursor);
194 while (column-- > 1) {
195 CodePoint u;
196 if (!block_iter_next_char(&view->cursor, &u)) {
197 break;
198 }
199 if (u == '\n') {
200 block_iter_prev_char(&view->cursor, &u);
201 break;
202 }
203 }
204 view_reset_preferred_x(view);
205 }
206
207 2 void move_to_filepos(View *view, size_t line, size_t column)
208 {
209 2 move_to_line(view, line);
210 2 BUG_ON(!block_iter_is_bol(&view->cursor));
211
1/2
✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→7) taken 2 times.
2 if (column != 1) {
212 move_to_column(view, column);
213 }
214 2 view_reset_preferred_x(view);
215 2 }
216
217 61 static CharTypeEnum get_char_type(CodePoint u)
218 {
219
2/2
✓ Branch 0 (2→3) taken 53 times.
✓ Branch 1 (2→6) taken 8 times.
61 if (u == '\n') {
220 return CT_NEWLINE;
221 }
222
2/2
✓ Branch 0 (3→4) taken 47 times.
✓ Branch 1 (3→6) taken 6 times.
53 if (u_is_breakable_whitespace(u)) {
223 return CT_SPACE;
224 }
225
1/2
✓ Branch 0 (4→5) taken 47 times.
✗ Branch 1 (4→6) not taken.
47 if (u_is_word_char(u)) {
226 47 return CT_WORD;
227 }
228 return CT_OTHER;
229 }
230
231 10 static bool get_current_char_type(BlockIter *bi, CharTypeEnum *type)
232 {
233 10 CodePoint u;
234
1/2
✓ Branch 0 (3→4) taken 10 times.
✗ Branch 1 (3→5) not taken.
10 if (!block_iter_get_char(bi, &u)) {
235 return false;
236 }
237
238 10 *type = get_char_type(u);
239 10 return true;
240 }
241
242 15 static size_t skip_fwd_char_type(BlockIter *bi, CharTypeEnum type)
243 {
244 15 size_t count = 0;
245 15 CodePoint u;
246
1/2
✓ Branch 0 (8→3) taken 45 times.
✗ Branch 1 (8→9) not taken.
45 while (block_iter_next_char(bi, &u)) {
247
2/2
✓ Branch 0 (3→4) taken 15 times.
✓ Branch 1 (3→6) taken 30 times.
45 if (get_char_type(u) != type) {
248 15 block_iter_prev_char(bi, &u);
249 15 break;
250 }
251 30 count += u_char_size(u);
252 }
253 15 return count;
254 }
255
256 5 static size_t skip_bwd_char_type(BlockIter *bi, CharTypeEnum type)
257 {
258 5 size_t count = 0;
259 5 CodePoint u;
260
2/2
✓ Branch 0 (8→3) taken 4 times.
✓ Branch 1 (8→9) taken 2 times.
6 while (block_iter_prev_char(bi, &u)) {
261
2/2
✓ Branch 0 (3→4) taken 3 times.
✓ Branch 1 (3→6) taken 1 times.
4 if (get_char_type(u) != type) {
262 3 block_iter_next_char(bi, &u);
263 3 break;
264 }
265 1 count += u_char_size(u);
266 }
267 5 return count;
268 }
269
270 5 size_t word_fwd(BlockIter *bi, bool skip_non_word)
271 {
272 5 size_t count = 0;
273 10 CharTypeEnum type;
274
275 15 while (1) {
276 10 count += skip_fwd_char_type(bi, CT_SPACE);
277
1/2
✓ Branch 0 (5→6) taken 10 times.
✗ Branch 1 (5→11) not taken.
10 if (!get_current_char_type(bi, &type)) {
278 return count;
279 }
280
281
2/2
✓ Branch 0 (6→7) taken 5 times.
✓ Branch 1 (6→9) taken 5 times.
10 if (
282 count
283
3/4
✓ Branch 0 (7→8) taken 3 times.
✓ Branch 1 (7→11) taken 2 times.
✗ Branch 2 (8→9) not taken.
✓ Branch 3 (8→11) taken 3 times.
5 && (!skip_non_word || (type == CT_WORD || type == CT_NEWLINE))
284 ) {
285 return count;
286 }
287
288 5 count += skip_fwd_char_type(bi, type);
289 }
290 }
291
292 3 size_t word_bwd(BlockIter *bi, bool skip_non_word)
293 {
294 3 size_t count = 0;
295 3 CharTypeEnum type;
296 3 CodePoint u;
297
298 3 do {
299 3 count += skip_bwd_char_type(bi, CT_SPACE);
300
2/2
✓ Branch 0 (5→6) taken 2 times.
✓ Branch 1 (5→9) taken 1 times.
3 if (!block_iter_prev_char(bi, &u)) {
301 return count;
302 }
303
304 2 type = get_char_type(u);
305 2 count += u_char_size(u);
306 2 count += skip_bwd_char_type(bi, type);
307
1/4
✗ Branch 0 (7→8) not taken.
✓ Branch 1 (7→9) taken 2 times.
✗ Branch 2 (8→3) not taken.
✗ Branch 3 (8→9) not taken.
2 } while (skip_non_word && type != CT_WORD && type != CT_NEWLINE);
308 return count;
309 }
310