dte test coverage


Directory: ./
File: src/insert.c
Date: 2025-02-14 16:55:22
Exec Total Coverage
Lines: 111 119 93.3%
Functions: 6 6 100.0%
Branches: 40 58 69.0%

Line Branch Exec Source
1 #include <stdlib.h>
2 #include <string.h>
3 #include "insert.h"
4 #include "block-iter.h"
5 #include "buffer.h"
6 #include "change.h"
7 #include "indent.h"
8 #include "options.h"
9 #include "selection.h"
10 #include "util/utf8.h"
11
12 76 void insert_text(View *view, const char *text, size_t size, bool move_after)
13 {
14 76 size_t del_count = 0;
15
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→5) taken 75 times.
76 if (view->selection) {
16 1 del_count = prepare_selection(view);
17 1 unselect(view);
18 }
19 76 buffer_replace_bytes(view, del_count, text, size);
20
2/2
✓ Branch 0 (6→7) taken 35 times.
✓ Branch 1 (6→8) taken 41 times.
76 if (move_after) {
21 35 block_iter_skip_bytes(&view->cursor, size);
22 }
23 76 }
24
25 8 void new_line(View *view, bool above)
26 {
27
4/4
✓ Branch 0 (2→3) taken 2 times.
✓ Branch 1 (2→8) taken 6 times.
✓ Branch 2 (4→5) taken 1 times.
✓ Branch 3 (4→8) taken 1 times.
8 if (above && block_iter_prev_line(&view->cursor) == 0) {
28 // Already on first line; insert newline at bof
29 1 block_iter_bol(&view->cursor);
30 1 buffer_insert_bytes(view, "\n", 1);
31 1 return;
32 }
33
34 7 const LocalOptions *options = &view->buffer->options;
35 7 char *ins = NULL;
36 7 block_iter_eol(&view->cursor);
37
38
1/2
✓ Branch 0 (9→10) taken 7 times.
✗ Branch 1 (9→18) not taken.
7 if (options->auto_indent) {
39 7 BlockIter bi = view->cursor;
40
1/2
✗ Branch 0 (11→12) not taken.
✓ Branch 1 (11→13) taken 7 times.
7 if (block_iter_find_non_empty_line_bwd(&bi)) {
41 7 StringView line = block_iter_get_line(&bi);
42 7 ins = get_indent_for_next_line(options, &line);
43 }
44 }
45
46 7 size_t ins_count;
47
2/2
✓ Branch 0 (15→16) taken 2 times.
✓ Branch 1 (15→18) taken 5 times.
7 if (ins) {
48 2 ins_count = strlen(ins);
49 2 memmove(ins + 1, ins, ins_count);
50 2 ins[0] = '\n';
51 2 ins_count++;
52 2 buffer_insert_bytes(view, ins, ins_count);
53 2 free(ins);
54 } else {
55 5 ins_count = 1;
56 5 buffer_insert_bytes(view, "\n", 1);
57 }
58
59 7 block_iter_skip_bytes(&view->cursor, ins_count);
60 }
61
62 // Go to beginning of whitespace (tabs and spaces) under cursor and
63 // return number of whitespace bytes surrounding cursor
64 24 static inline size_t goto_beginning_of_whitespace(BlockIter *cursor)
65 {
66 24 BlockIter tmp = *cursor;
67 24 return block_iter_skip_blanks_fwd(&tmp) + block_iter_skip_blanks_bwd(cursor);
68 }
69
70 25 static void insert_nl(View *view)
71 {
72 // Prepare deleted text (selection or whitespace around cursor)
73 25 size_t del_count = 0;
74
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→5) taken 24 times.
25 if (view->selection) {
75 1 del_count = prepare_selection(view);
76 1 unselect(view);
77 } else {
78 // Trim whitespace around cursor
79 24 del_count = goto_beginning_of_whitespace(&view->cursor);
80 }
81
82 // Prepare inserted indentation
83 25 const LocalOptions *options = &view->buffer->options;
84 25 char *ins = NULL;
85
1/2
✓ Branch 0 (6→7) taken 25 times.
✗ Branch 1 (6→18) not taken.
25 if (options->auto_indent) {
86 // Current line will be split at cursor position
87 25 BlockIter bi = view->cursor;
88 25 size_t len = block_iter_bol(&bi);
89 25 StringView line = block_iter_get_line(&bi);
90 25 line.length = len;
91
2/2
✓ Branch 0 (9→10) taken 5 times.
✓ Branch 1 (9→16) taken 20 times.
25 if (strview_isblank(&line)) {
92 // This line is (or will become) white space only; find previous,
93 // non whitespace only line
94
2/4
✓ Branch 0 (11→12) taken 5 times.
✗ Branch 1 (11→17) not taken.
✓ Branch 2 (13→14) taken 5 times.
✗ Branch 3 (13→17) not taken.
5 if (block_iter_prev_line(&bi) && block_iter_find_non_empty_line_bwd(&bi)) {
95 5 line = block_iter_get_line(&bi);
96 5 ins = get_indent_for_next_line(options, &line);
97 }
98 } else {
99 20 ins = get_indent_for_next_line(options, &line);
100 }
101 }
102
103 25 size_t ins_count;
104 25 begin_change(CHANGE_MERGE_NONE);
105
106
2/2
✓ Branch 0 (19→20) taken 16 times.
✓ Branch 1 (19→22) taken 9 times.
25 if (ins) {
107 16 ins_count = strlen(ins);
108 16 memmove(ins + 1, ins, ins_count);
109 16 ins[0] = '\n'; // Add newline before indent
110 16 ins_count++;
111 16 buffer_replace_bytes(view, del_count, ins, ins_count);
112 16 free(ins);
113 } else {
114 9 ins_count = 1;
115 9 buffer_replace_bytes(view, del_count, "\n", ins_count);
116 }
117
118 25 end_change();
119 25 block_iter_skip_bytes(&view->cursor, ins_count); // Move after inserted text
120 25 }
121
122 1 static int get_indent_of_matching_brace(const View *view)
123 {
124 1 unsigned int tab_width = view->buffer->options.tab_width;
125 1 BlockIter bi = view->cursor;
126 1 StringView line;
127 1 int level = 0;
128
129
1/2
✓ Branch 0 (14→3) taken 4 times.
✗ Branch 1 (14→15) not taken.
4 while (block_iter_prev_line(&bi)) {
130 4 fetch_this_line(&bi, &line);
131
2/2
✓ Branch 0 (5→6) taken 1 times.
✓ Branch 1 (5→9) taken 3 times.
4 if (line_has_opening_brace(line)) {
132
1/2
✓ Branch 0 (6→7) taken 1 times.
✗ Branch 1 (6→9) not taken.
1 if (level++ == 0) {
133 1 return get_indent_width(&line, tab_width);
134 }
135 }
136
1/2
✗ Branch 0 (10→11) not taken.
✓ Branch 1 (10→12) taken 3 times.
3 if (line_has_closing_brace(line)) {
137 level--;
138 }
139 }
140
141 return -1;
142 }
143
144 147 void insert_ch(View *view, CodePoint ch)
145 {
146
2/2
✓ Branch 0 (2→3) taken 25 times.
✓ Branch 1 (2→5) taken 122 times.
147 if (ch == '\n') {
147 25 insert_nl(view);
148 25 return;
149 }
150
151 122 const Buffer *buffer = view->buffer;
152 122 const LocalOptions *options = &buffer->options;
153 122 char buf[8];
154 122 char *ins = buf;
155 122 char *alloc = NULL;
156 122 size_t del_count = 0;
157 122 size_t ins_count = 0;
158
159
1/2
✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→8) taken 122 times.
122 if (view->selection) {
160 // Prepare deleted text (selection)
161 del_count = prepare_selection(view);
162 unselect(view);
163
1/2
✗ Branch 0 (8→9) not taken.
✓ Branch 1 (8→12) taken 122 times.
122 } else if (options->overwrite) {
164 // Delete character under cursor unless we're at end of line
165 BlockIter bi = view->cursor;
166 del_count = block_iter_is_eol(&bi) ? 0 : block_iter_next_column(&bi);
167
4/6
✓ Branch 0 (12→13) taken 1 times.
✓ Branch 1 (12→24) taken 121 times.
✓ Branch 2 (13→14) taken 1 times.
✗ Branch 3 (13→24) not taken.
✓ Branch 4 (14→15) taken 1 times.
✗ Branch 5 (14→24) not taken.
122 } else if (ch == '}' && options->auto_indent && options->brace_indent) {
168 1 StringView curlr;
169 1 fetch_this_line(&view->cursor, &curlr);
170
1/2
✓ Branch 0 (16→17) taken 1 times.
✗ Branch 1 (16→23) not taken.
1 if (strview_isblank(&curlr)) {
171 1 int width = get_indent_of_matching_brace(view);
172
1/2
✓ Branch 0 (18→19) taken 1 times.
✗ Branch 1 (18→23) not taken.
1 if (width >= 0) {
173 // Replace current (ws only) line with some indent + '}'
174 1 block_iter_bol(&view->cursor);
175 1 del_count = curlr.length;
176
1/2
✗ Branch 0 (20→21) not taken.
✓ Branch 1 (20→23) taken 1 times.
1 if (width) {
177 alloc = make_indent(options, width);
178 ins = alloc;
179 ins_count = strlen(ins);
180 // '}' will be replace the terminating NUL
181 }
182 }
183 }
184 }
185
186 // Prepare inserted text
187
3/4
✓ Branch 0 (24→25) taken 12 times.
✓ Branch 1 (24→27) taken 110 times.
✓ Branch 2 (25→26) taken 12 times.
✗ Branch 3 (25→27) not taken.
122 if (ch == '\t' && options->expand_tab) {
188 12 ins_count = options->indent_width;
189 12 static_assert(sizeof(buf) >= INDENT_WIDTH_MAX);
190 12 memset(ins, ' ', ins_count);
191 } else {
192 110 ins_count += u_set_char_raw(ins + ins_count, ch);
193 }
194
195 // Record change
196 122 begin_change(del_count ? CHANGE_MERGE_NONE : CHANGE_MERGE_INSERT);
197 122 buffer_replace_bytes(view, del_count, ins, ins_count);
198 122 end_change();
199 122 free(alloc);
200
201 // Move after inserted text
202 122 block_iter_skip_bytes(&view->cursor, ins_count);
203 }
204