dte test coverage


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 50.0% high: ≥ 85.0%
Coverage Exec / Excl / Total
Lines: 98.8% 161 / 0 / 163
Functions: 100.0% 15 / 0 / 15
Branches: 88.2% 60 / 12 / 80

src/config.c
Line Branch Exec Source
1 #include "build-defs.h"
2 #include <errno.h>
3 #include <stdbool.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sys/types.h>
7 #include "config.h"
8 #include "command/cache.h"
9 #include "command/error.h"
10 #include "commands.h"
11 #include "compiler.h"
12 #include "editor.h"
13 #include "syntax/color.h"
14 #include "util/debug.h"
15 #include "util/hashmap.h"
16 #include "util/intmap.h"
17 #include "util/log.h"
18 #include "util/readfile.h"
19 #include "util/str-util.h"
20 #include "util/xsnprintf.h"
21
22 #if HAVE_EMBED
23 #include "builtin-config-embed.h"
24 #else
25 #include "builtin-config.h"
26 #endif
27
28 // Odd number of backslashes at end of line?
29 10000 static bool has_line_continuation(StringView line)
30 {
31 10000 ssize_t pos = line.length - 1;
32
4/4
✓ Branch 4 → 5 taken 9379 times.
✓ Branch 4 → 6 taken 1538 times.
✓ Branch 5 → 3 taken 917 times.
✓ Branch 5 → 6 taken 8462 times.
10917 while (pos >= 0 && line.data[pos] == '\\') {
33 917 pos--;
34 }
35 10000 return (line.length - 1 - pos) & 1;
36 }
37
38 24 UNITTEST {
39 // NOLINTBEGIN(bugprone-assert-side-effect)
40 24 BUG_ON(has_line_continuation(strview(NULL)));
41 24 BUG_ON(has_line_continuation(strview("0")));
42 24 BUG_ON(!has_line_continuation(strview("1 \\")));
43 24 BUG_ON(has_line_continuation(strview("2 \\\\")));
44 24 BUG_ON(!has_line_continuation(strview("3 \\\\\\")));
45 24 BUG_ON(has_line_continuation(strview("4 \\\\\\\\")));
46 // NOLINTEND(bugprone-assert-side-effect)
47 24 }
48
49 229 bool exec_config(CommandRunner *runner, StringView config)
50 {
51 229 EditorState *e = runner->e;
52 229 ErrorBuffer *ebuf = runner->ebuf;
53
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 228 times.
229 if (unlikely(e->include_recursion_count > 64)) {
54 1 return error_msg_for_cmd(ebuf, NULL, "config recursion limit reached");
55 }
56
57 228 bool stop_at_first_err = (runner->flags & CMDRUNNER_STOP_AT_FIRST_ERROR);
58 228 size_t nfailed = 0;
59 228 String buf = string_new(1024);
60 228 e->include_recursion_count++;
61
62
2/2
✓ Branch 24 → 6 taken 10129 times.
✓ Branch 24 → 25 taken 227 times.
10356 for (size_t i = 0, n = config.length; i < n; ebuf->config_line++) {
63 10129 StringView line = buf_slice_next_line(config.data, &i, n);
64 10129 strview_trim_left(&line);
65
4/4
✓ Branch 8 → 9 taken 9454 times.
✓ Branch 8 → 12 taken 675 times.
✓ Branch 10 → 11 taken 273 times.
✓ Branch 10 → 12 taken 9181 times.
10129 if (buf.len == 0 && strview_has_prefix(line, "#")) {
66 // Comment line
67 950 continue;
68 }
69
70
2/2
✓ Branch 12 → 13 taken 677 times.
✓ Branch 12 → 15 taken 9179 times.
9856 if (has_line_continuation(line)) {
71 // Line with backslash-escaped newline; append to buffer
72 // but don't execute yet
73 677 line.length--;
74 677 string_append_strview(&buf, line);
75 677 continue;
76 }
77
78 9179 string_append_strview(&buf, line);
79 9179 bool r = handle_command(runner, string_borrow_cstring(&buf));
80 9179 string_clear(&buf);
81 9179 nfailed += !r;
82
2/2
✓ Branch 19 → 20 taken 1 time.
✓ Branch 19 → 21 taken 9178 times.
9179 if (unlikely(!r && stop_at_first_err)) {
83 1 goto out;
84 }
85 }
86
87
2/2
✓ Branch 25 → 26 taken 225 times.
✓ Branch 25 → 27 taken 2 times.
227 if (unlikely(buf.len)) {
88 // This can only happen if the last line had a line continuation
89 2 bool r = handle_command(runner, string_borrow_cstring(&buf));
90 2 nfailed += !r;
91 }
92
93 225 out:
94 228 e->include_recursion_count--;
95 228 string_free(&buf);
96 228 return (nfailed == 0);
97 }
98
99 3 String dump_builtin_configs(void)
100 {
101 3 String str = string_new(1024);
102
2/2
✓ Branch 7 → 4 taken 237 times.
✓ Branch 7 → 8 taken 3 times.
240 for (size_t i = 0; i < ARRAYLEN(builtin_configs); i++) {
103 237 string_append_cstring(&str, builtin_configs[i].name);
104 237 string_append_byte(&str, '\n');
105 }
106 3 return str;
107 }
108
109 102 const BuiltinConfig *get_builtin_config(const char *name)
110 {
111
2/2
✓ Branch 6 → 3 taken 5240 times.
✓ Branch 6 → 7 taken 59 times.
5299 for (size_t i = 0; i < ARRAYLEN(builtin_configs); i++) {
112
2/2
✓ Branch 3 → 4 taken 43 times.
✓ Branch 3 → 5 taken 5197 times.
5240 if (streq(name, builtin_configs[i].name)) {
113 43 return &builtin_configs[i];
114 }
115 }
116 return NULL;
117 }
118
119 1 const BuiltinConfig *get_builtin_configs_array(size_t *nconfigs)
120 {
121 1 *nconfigs = ARRAYLEN(builtin_configs);
122 1 return &builtin_configs[0];
123 }
124
125 111 static SystemErrno do_read_config (
126 CommandRunner *runner,
127 const char *filename,
128 ConfigFlags flags
129 ) {
130 111 ErrorBuffer *ebuf = runner->ebuf;
131 111 bool must_exist = flags & CFG_MUST_EXIST;
132 111 bool stop_at_first_err = runner->flags & CMDRUNNER_STOP_AT_FIRST_ERROR;
133
134
2/2
✓ Branch 2 → 3 taken 42 times.
✓ Branch 2 → 11 taken 69 times.
111 if (flags & CFG_BUILTIN) {
135 42 const BuiltinConfig *cfg = get_builtin_config(filename);
136
2/2
✓ Branch 3 → 4 taken 41 times.
✓ Branch 3 → 8 taken 1 time.
42 if (cfg) {
137 41 ebuf->config_filename = filename;
138 41 ebuf->config_line = 1;
139 41 bool r = exec_config(runner, cfg->text);
140
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 41 times.
41 return (r || !stop_at_first_err) ? 0 : EINVAL;
141 }
142
1/2
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 10 not taken.
1 if (must_exist) {
143 1 error_msg(ebuf, "no built-in config with name '%s'", filename);
144 }
145 1 return ENOENT;
146 }
147
148 69 char *buf;
149 69 ssize_t size = read_file(filename, &buf, 0);
150
2/2
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 17 taken 68 times.
69 if (size < 0) {
151 1 int err = errno;
152
1/2
✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 16 not taken.
1 if (err != ENOENT || must_exist) {
153 1 error_msg(ebuf, "Error reading %s: %s", filename, strerror(err));
154 }
155 1 return err;
156 }
157
158 68 ebuf->config_filename = filename;
159 68 ebuf->config_line = 1;
160 68 bool r = exec_config(runner, string_view(buf, size));
161 68 free(buf);
162
1/2
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 68 times.
68 return (r || !stop_at_first_err) ? 0 : EINVAL;
163 }
164
165 111 SystemErrno read_config(CommandRunner *runner, const char *filename, ConfigFlags flags)
166 {
167 111 ErrorBuffer *ebuf = runner->ebuf;
168 111 const char *saved_file = ebuf->config_filename;
169 111 const unsigned int saved_line = ebuf->config_line;
170 111 SystemErrno ret = do_read_config(runner, filename, flags);
171 111 ebuf->config_filename = saved_file;
172 111 ebuf->config_line = saved_line;
173 111 return ret;
174 }
175
176 27 static void exec_builtin_config(EditorState *e, StringView cfg, const char *name)
177 {
178 27 ErrorBuffer *ebuf = &e->err;
179 27 const char *saved_file = ebuf->config_filename;
180 27 const unsigned int saved_line = ebuf->config_line;
181 27 ebuf->config_filename = name;
182 27 ebuf->config_line = 1;
183 27 exec_normal_config(e, cfg);
184 27 ebuf->config_filename = saved_file;
185 27 ebuf->config_line = saved_line;
186 27 }
187
188 18 void exec_builtin_color_reset(EditorState *e)
189 {
190 18 StringView reset = string_view(builtin_color_reset, sizeof(builtin_color_reset) - 1);
191 18 clear_hl_styles(&e->styles);
192 18 exec_builtin_config(e, reset, "color/reset");
193 18 e->screen_update |= UPDATE_SYNTAX_STYLES | UPDATE_ALL_WINDOWS;
194 18 }
195
196 9 static void log_config_counts(const EditorState *e)
197 {
198
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 17 taken 8 times.
9 if (!log_level_enabled(LOG_LEVEL_INFO)) {
199 return;
200 }
201
202 1 size_t nbinds = 0;
203 1 size_t nbinds_cached = 0;
204
2/2
✓ Branch 11 → 5 taken 3 times.
✓ Branch 11 → 12 taken 1 time.
4 for (HashMapIter modeiter = hashmap_iter(&e->modes); hashmap_next(&modeiter); ) {
205 3 const ModeHandler *mode = modeiter.entry->value;
206 3 const IntMap *binds = &mode->key_bindings;
207 3 nbinds += binds->count;
208
2/2
✓ Branch 8 → 6 taken 217 times.
✓ Branch 8 → 9 taken 3 times.
220 for (IntMapIter binditer = intmap_iter(binds); intmap_next(&binditer); ) {
209 217 const CachedCommand *cc = binditer.entry->value;
210 217 nbinds_cached += !!cc->cmd;
211 }
212 }
213
214 1 size_t nerrorfmts = 0;
215
2/2
✓ Branch 15 → 13 taken 3 times.
✓ Branch 15 → 16 taken 1 time.
4 for (HashMapIter it = hashmap_iter(&e->compilers); hashmap_next(&it); ) {
216 3 const Compiler *compiler = it.entry->value;
217 3 nerrorfmts += compiler->error_formats.count;
218 }
219
220 1 LOG_INFO (
221 "bind=%zu(%zu) alias=%zu hi=%zu ft=%zu option=%zu errorfmt=%zu(%zu)",
222 nbinds,
223 nbinds_cached,
224 e->aliases.count,
225 e->styles.other.count + NR_BSE,
226 e->filetypes.count,
227 e->file_options.count,
228 e->compilers.count,
229 nerrorfmts
230 );
231 }
232
233 9 void exec_rc_files(EditorState *e, const char *filename, bool read_user_rc)
234 {
235 9 StringView rc = string_view(builtin_rc, sizeof(builtin_rc) - 1);
236 9 exec_builtin_color_reset(e);
237 9 exec_builtin_config(e, rc, "rc");
238
239
2/2
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 10 taken 7 times.
9 if (read_user_rc) {
240 2 ConfigFlags flags = CFG_NOFLAGS;
241 2 char buf[8192];
242
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 2 times.
2 if (filename) {
243 flags |= CFG_MUST_EXIST;
244 } else {
245 xsnprintf(buf, sizeof buf, "%s/%s", e->user_config_dir, "rc");
246 filename = buf;
247 }
248 2 LOG_INFO("loading configuration from %s", filename);
249 2 read_normal_config(e, filename, flags);
250 }
251
252 9 log_config_counts(e);
253 9 }
254
255 1 void collect_builtin_configs(PointerArray *a, const char *prefix)
256 {
257 1 size_t prefix_len = strlen(prefix);
258
2/2
✓ Branch 7 → 3 taken 79 times.
✓ Branch 7 → 8 taken 1 time.
80 for (size_t i = 0; i < ARRAYLEN(builtin_configs); i++) {
259 79 const char *name = builtin_configs[i].name;
260
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 6 taken 78 times.
79 if (str_has_strn_prefix(name, prefix, prefix_len)) {
261 1 ptr_array_append(a, xstrdup(name));
262 }
263 }
264 1 }
265
266 // Collect ${builtin:path/name} style variables (minus the leading "${")
267 // TODO: Support ${script:name} variables
268 2 void collect_builtin_config_variables(PointerArray *a, StringView prefix)
269 {
270 2 static const char builtin[] = "builtin:";
271 2 const size_t blen = sizeof(builtin) - 1;
272 2 const size_t cmplen = MIN(prefix.length, blen);
273
274
1/2
✓ Branch 3 → 9 taken 2 times.
✗ Branch 3 → 10 not taken.
2 if (!strview_remove_matching_sv_prefix(&prefix, string_view(builtin, cmplen))) {
275 return;
276 }
277
278
2/2
✓ Branch 9 → 4 taken 158 times.
✓ Branch 9 → 10 taken 2 times.
160 for (size_t i = 0; i < ARRAYLEN(builtin_configs); i++) {
279 158 StringView name = strview(builtin_configs[i].name);
280
2/2
✓ Branch 5 → 6 taken 84 times.
✓ Branch 5 → 8 taken 74 times.
158 if (strview_has_sv_prefix(name, prefix)) {
281 84 ptr_array_append(a, xmemjoin3(builtin, blen, name.data, name.length, "}", 2));
282 }
283 }
284 }
285
286 1 void collect_builtin_includes(PointerArray *a, const char *prefix)
287 {
288 1 size_t prefix_len = strlen(prefix);
289
2/2
✓ Branch 9 → 3 taken 79 times.
✓ Branch 9 → 10 taken 1 time.
80 for (size_t i = 0; i < ARRAYLEN(builtin_configs); i++) {
290 79 const char *name = builtin_configs[i].name;
291 79 if (
292
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 8 taken 78 times.
79 str_has_strn_prefix(name, prefix, prefix_len)
293
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 8 not taken.
1 && !str_has_prefix(name, "syntax/")
294
1/2
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 8 not taken.
1 && !str_has_prefix(name, "script/")
295 ) {
296 1 ptr_array_append(a, xstrdup(name));
297 }
298 }
299 1 }
300