dte test coverage


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 50.0% high: ≥ 85.0%
Coverage Exec / Excl / Total
Lines: 73.8% 121 / 1 / 165
Functions: 92.3% 12 / 0 / 13
Branches: 46.9% 46 / 8 / 106

src/view.c
Line Branch Exec Source
1 #include "view.h"
2 #include "block.h"
3 #include "buffer.h"
4 #include "editor.h"
5 #include "indent.h"
6 #include "util/ascii.h"
7 #include "util/debug.h"
8 #include "util/numtostr.h"
9 #include "util/str-util.h"
10 #include "util/time-util.h"
11 #include "util/utf8.h"
12 #include "window.h"
13
14 484 void view_update_cursor_y(View *view)
15 {
16 484 const Buffer *buffer = view->buffer;
17 484 const Block *blk;
18 484 size_t nl = 0;
19
1/2
✓ Branch 7 → 3 taken 484 times.
✗ Branch 7 → 8 not taken.
484 block_for_each(blk, &buffer->blocks) {
20
1/2
✓ Branch 3 → 4 taken 484 times.
✗ Branch 3 → 6 not taken.
484 if (blk == view->cursor.blk) {
21 484 nl += count_nl(blk->data, view->cursor.offset);
22 484 view->cy = nl;
23 484 return;
24 }
25 nl += blk->nl;
26 }
27 BUG("unreachable");
28 }
29
30 32 static void view_update_cursor_x(View *view)
31 {
32 32 const unsigned int tw = view->buffer->options.tab_width;
33 32 const CurrentLineRef lr = get_current_line_and_offset(view->cursor);
34 32 const size_t cx = lr.cursor_offset;
35 32 long cx_char = 0;
36 32 long w = 0;
37
38
2/2
✓ Branch 14 → 4 taken 83 times.
✓ Branch 14 → 15 taken 32 times.
115 for (size_t idx = 0; idx < cx; cx_char++) {
39 83 unsigned char ch = lr.line.data[idx];
40
1/2
✓ Branch 4 → 5 taken 83 times.
✗ Branch 4 → 11 not taken.
83 if (likely(ch < 0x80)) {
41 83 idx++;
42
2/2
✓ Branch 5 → 6 taken 79 times.
✓ Branch 5 → 7 taken 4 times.
83 if (likely(!ascii_iscntrl(ch))) {
43 79 w++;
44
1/2
✓ Branch 7 → 8 taken 4 times.
✗ Branch 7 → 10 not taken.
4 } else if (ch == '\t') {
45 4 w = next_indent_width(w, tw);
46 } else {
47 w += 2;
48 }
49 } else {
50 CodePoint u = u_get_nonascii(lr.line.data, lr.line.length, &idx);
51 w += u_char_width(u);
52 }
53 }
54
55 32 view->cx = cx;
56 32 view->cx_char = cx_char;
57 32 view->cx_display = w;
58 32 }
59
60 1 static bool view_is_cursor_visible(const View *v)
61 {
62
2/4
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 5 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
1 return v->cy < v->vy || v->cy > v->vy + v->window->edit_h - 1;
63 }
64
65 1 static void view_center_to_cursor(View *view)
66 {
67 1 unsigned long height = view->window->edit_h;
68 1 unsigned long half_height = height / 2;
69 1 unsigned long lines = view->buffer->nl;
70 1 unsigned long cursor_y = view->cy;
71
72
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1 time.
1 if (height >= lines || half_height >= cursor_y) {
73 view->vy = 0;
74 return;
75 }
76
77 // +1 here makes one "~" line visible, so that the EOF position can
78 // still be seen even when center_at_eof is false
79 1 bool center_at_eof = view->window->editor->options.center_at_eof;
80 1 unsigned long new_y = cursor_y - half_height;
81
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1 time.
1 view->vy = center_at_eof ? new_y : MIN(new_y, (lines - height) + 1);
82 }
83
84 1 static void view_update_vx(View *v)
85 {
86 1 Window *window = v->window;
87 1 unsigned int c = 8;
88
89
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1 time.
1 if (v->cx_display - v->vx >= window->edit_w) {
90 v->vx = (v->cx_display - window->edit_w + c) / c * c;
91 }
92
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1 time.
1 if (v->cx_display < v->vx) {
93 v->vx = v->cx_display / c * c;
94 }
95 1 }
96
97 static void view_update_vy(View *v)
98 {
99 Window *window = v->window;
100 long margin = window_get_scroll_margin(window);
101 long max_y = v->vy + window->edit_h - 1 - margin;
102
103 if (v->cy < v->vy + margin) {
104 v->vy = MAX(v->cy - margin, 0);
105 } else if (v->cy > max_y) {
106 v->vy += v->cy - max_y;
107 max_y = v->buffer->nl - window->edit_h + 1;
108 if (v->vy > max_y && max_y >= 0) {
109 v->vy = max_y;
110 }
111 }
112 }
113
114 1 void view_update(View *v)
115 {
116 1 view_update_cursor_x(v);
117 1 view_update_cursor_y(v);
118 1 view_update_vx(v);
119
3/6
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 8 not taken.
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 9 not taken.
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 9 not taken.
1 if (v->force_center || (v->center_on_scroll && view_is_cursor_visible(v))) {
120 1 view_center_to_cursor(v);
121 } else {
122 view_update_vy(v);
123 }
124 1 v->force_center = false;
125 1 v->center_on_scroll = false;
126 1 }
127
128 63 long view_get_preferred_x(View *v)
129 {
130
2/2
✓ Branch 2 → 3 taken 31 times.
✓ Branch 2 → 5 taken 32 times.
63 if (v->preferred_x < 0) {
131 31 view_update_cursor_x(v);
132 31 v->preferred_x = v->cx_display;
133 }
134 63 return v->preferred_x;
135 }
136
137 25 bool view_can_close(const View *view)
138 {
139 25 const Buffer *buffer = view->buffer;
140
4/4
✓ Branch 2 → 3 taken 5 times.
✓ Branch 2 → 5 taken 20 times.
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 5 taken 1 time.
25 return !buffer_modified(buffer) || buffer->views.count > 1;
141 }
142
143 // Like window_remove_view(), but searching for the index of `view` in
144 // `view->window->views` by pointer
145 28 size_t view_remove(View *view)
146 {
147 28 Window *window = view->window;
148 28 size_t view_idx = ptr_array_xindex(&window->views, view);
149 28 window_remove_view_at_index(window, view_idx);
150 28 return view_idx;
151 }
152
153 4 WordBounds get_bounds_for_word_under_cursor(CurrentLineRef lr)
154 {
155 4 const size_t len = lr.line.length;
156 4 size_t si = lr.cursor_offset;
157 4 BUG_ON(si > len);
158
159 // Move right, until over a word char (if not already)
160
1/2
✓ Branch 8 → 4 taken 4 times.
✗ Branch 8 → 9 not taken.
4 while (si < len) {
161 4 size_t i = si;
162
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 4 times.
4 if (u_is_word_char(u_get_char(lr.line.data, len, &i))) {
163 break;
164 }
165 si = i;
166 }
167
168
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 15 taken 4 times.
4 if (si == len) {
169 // No word char between cursor and EOL; no word
170 return (WordBounds){0};
171 }
172
173 // Move left, to start of word (if cursor is already within one)
174 8 size_t ei = si;
175
2/2
✓ Branch 15 → 11 taken 4 times.
✓ Branch 15 → 20 taken 4 times.
8 while (si) {
176 4 size_t i = si;
177
1/2
✓ Branch 12 → 13 taken 4 times.
✗ Branch 12 → 14 not taken.
4 if (!u_is_word_char(u_prev_char(lr.line.data, &i))) {
178 break;
179 }
180 4 si = i;
181 }
182
183 // Move right, to end of word
184
2/2
✓ Branch 21 → 16 taken 4114 times.
✓ Branch 21 → 22 taken 4 times.
4118 while (ei < len) {
185 4114 size_t i = ei;
186
1/2
✓ Branch 17 → 18 taken 4114 times.
✗ Branch 17 → 19 not taken.
4114 if (!u_is_word_char(u_get_char(lr.line.data, len, &i))) {
187 break;
188 }
189 4114 ei = i;
190 }
191
192 4 bool empty = (si == ei);
193 4 BUG_ON(si > ei);
194
195 4 return (WordBounds) {
196
1/2
✓ Branch 24 → 25 taken 4 times.
✗ Branch 24 → 26 not taken.
4 .start = empty ? 0 : si,
197
1/2
✓ Branch 26 → 27 taken 4 times.
✗ Branch 26 → 28 not taken.
4 .end = empty ? 0 : ei,
198 };
199 }
200
201 4 StringView view_get_word_under_cursor(const View *view)
202 {
203 4 CurrentLineRef lr = get_current_line_and_offset(view->cursor);
204 4 WordBounds wb = get_bounds_for_word_under_cursor(lr);
205
1/2
✓ Branch 4 → 5 taken 4 times.
✗ Branch 4 → 6 not taken.
4 return string_view(lr.line.data + wb.start, wb.end ? wb.end - wb.start : 0);
206 }
207
208 1 String dump_buffer(const View *view)
209 {
210 1 const Buffer *buffer = view->buffer;
211 1 uintmax_t counts[2];
212 1 char sizestr[FILESIZE_STR_MAX];
213 1 buffer_count_blocks_and_bytes(buffer, counts);
214 1 BUG_ON(counts[0] < 1);
215 1 BUG_ON(!buffer->setup);
216 1 String buf = string_new(1024 + (DEBUG ? 24 * counts[0] : 0));
217
218 2 string_sprintf (
219 &buf,
220 "%s %s\n%s %lu\n%s %s\n%s %s\n%s %ju\n%s %zu\n%s %s\n",
221 " Name:", buffer_filename(buffer),
222 1 " ID:", buffer->id,
223 1 " Encoding:", buffer->encoding,
224 1 " Filetype:", buffer->options.filetype,
225 " Blocks:", counts[0],
226 1 " Lines:", buffer->nl,
227 " Size:", filesize_to_str(counts[1], sizestr)
228 );
229
230 1 if (
231
3/6
✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 17 not taken.
✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 17 not taken.
✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 17 not taken.
1 buffer->stdout_buffer || buffer->temporary || buffer->readonly
232
3/6
✓ Branch 14 → 15 taken 1 time.
✗ Branch 14 → 17 not taken.
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 17 not taken.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 30 taken 1 time.
1 || buffer->locked || buffer->crlf_newlines || buffer->bom
233 ) {
234 string_sprintf (
235 &buf,
236 " Flags:%s%s%s%s%s%s\n",
237 buffer->stdout_buffer ? " STDOUT" : "",
238 buffer->temporary ? " TMP" : "",
239 buffer->readonly ? " RO" : "",
240 buffer->locked ? " LOCKED" : "",
241 buffer->crlf_newlines ? " CRLF" : "",
242 buffer->bom ? " BOM" : ""
243 );
244 }
245
246
1/2
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 1 time.
1 if (buffer->views.count > 1) {
247 string_sprintf(&buf, " Views: %zu\n", buffer->views.count);
248 }
249
250
1/2
✗ Branch 32 → 33 not taken.
✓ Branch 32 → 40 taken 1 time.
1 if (buffer->abs_filename) {
251 const FileInfo *file = &buffer->file;
252 unsigned int perms = file->mode & 07777;
253 char tstr[TIME_STR_BUFSIZE];
254 char modestr[FILE_PERMISSIONS_BUFSIZE];
255 string_sprintf (
256 &buf,
257 "\nLast stat:\n----------\n\n"
258 "%s %s\n%s %s\n%s -%s (%04o)\n%s %jd\n%s %jd\n%s %s\n%s %jd\n%s %ju\n",
259 " Path:", buffer->abs_filename,
260 " Modified:", timespec_to_str(&file->mtime, tstr) ? tstr : "-",
261 " Mode:", file_permissions_to_str(file->mode, modestr), perms,
262 " User:", (intmax_t)file->uid,
263 " Group:", (intmax_t)file->gid,
264 " Size:", filesize_to_str(file->size, sizestr),
265 " Device:", (intmax_t)file->dev,
266 " Inode:", (uintmax_t)file->ino
267 );
268 }
269
270 1 if (DEBUG >= 1) {
271 1 const BlockIter *cursor = &view->cursor;
272 1 string_append_literal(&buf, "\nBlocks:\n-------\n\n");
273 1 size_t i = 1;
274 1 const Block *b;
275
2/2
✓ Branch 47 → 42 taken 1 time.
✓ Branch 47 → 48 taken 1 time.
2 block_for_each(b, &buffer->blocks) {
276 1 string_sprintf(&buf, "%4zu: %zu/%zu nl=%zu", i++, b->size, b->alloc, b->nl);
277
1/2
✓ Branch 43 → 44 taken 1 time.
✗ Branch 43 → 45 not taken.
1 if (b == cursor->blk) {
278 1 string_sprintf(&buf, " (cursor; offset=%zu)", cursor->offset);
279 }
280 1 string_append_byte(&buf, '\n');
281 }
282 }
283
284 1 return buf;
285 }
286