dte test coverage


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 50.0% high: ≥ 85.0%
Coverage Exec / Excl / Total
Lines: 96.6% 144 / 0 / 149
Functions: 100.0% 13 / 0 / 13
Branches: 87.5% 56 / 6 / 70

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