dte test coverage


Directory: ./
File: src/config.c
Date: 2025-06-04 06:50:24
Exec Total Coverage
Lines: 124 138 89.9%
Functions: 15 15 100.0%
Branches: 42 50 84.0%

Line Branch Exec Source
1 #include "feature.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
21 #if HAVE_EMBED
22 #include "builtin-config-embed.h"
23 #else
24 #include "builtin-config.h"
25 #endif
26
27 22 UNITTEST {
28 // NOLINTBEGIN(bugprone-assert-side-effect)
29 22 BUG_ON(!get_builtin_config("rc"));
30 22 BUG_ON(!get_builtin_config("color/reset"));
31 // NOLINTEND(bugprone-assert-side-effect)
32 22 }
33
34 // Odd number of backslashes at end of line?
35 8958 static bool has_line_continuation(StringView line)
36 {
37 8958 ssize_t pos = line.length - 1;
38
4/4
✓ Branch 0 (4→5) taken 8389 times.
✓ Branch 1 (4→6) taken 1425 times.
✓ Branch 2 (5→3) taken 856 times.
✓ Branch 3 (5→6) taken 7533 times.
9814 while (pos >= 0 && line.data[pos] == '\\') {
39 856 pos--;
40 }
41 8958 return (line.length - 1 - pos) & 1;
42 }
43
44 22 UNITTEST {
45 // NOLINTBEGIN(bugprone-assert-side-effect)
46 22 BUG_ON(has_line_continuation(string_view(NULL, 0)));
47 22 BUG_ON(has_line_continuation(strview_from_cstring("0")));
48 22 BUG_ON(!has_line_continuation(strview_from_cstring("1 \\")));
49 22 BUG_ON(has_line_continuation(strview_from_cstring("2 \\\\")));
50 22 BUG_ON(!has_line_continuation(strview_from_cstring("3 \\\\\\")));
51 22 BUG_ON(has_line_continuation(strview_from_cstring("4 \\\\\\\\")));
52 // NOLINTEND(bugprone-assert-side-effect)
53 22 }
54
55 197 void exec_config(CommandRunner *runner, StringView config)
56 {
57 197 EditorState *e = runner->e;
58 197 ErrorBuffer *ebuf = runner->ebuf;
59
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→5) taken 196 times.
197 if (unlikely(e->include_recursion_count > 64)) {
60 1 error_msg_for_cmd(ebuf, NULL, "config recursion limit reached");
61 1 return;
62 }
63
64 196 String buf = string_new(1024);
65 196 e->include_recursion_count++;
66
67
2/2
✓ Branch 0 (21→7) taken 9011 times.
✓ Branch 1 (21→22) taken 196 times.
9207 for (size_t i = 0, n = config.length; i < n; ebuf->config_line++) {
68 9011 StringView line = buf_slice_next_line(config.data, &i, n);
69 9011 strview_trim_left(&line);
70
4/4
✓ Branch 0 (9→10) taken 8377 times.
✓ Branch 1 (9→13) taken 634 times.
✓ Branch 2 (11→12) taken 185 times.
✓ Branch 3 (11→13) taken 8192 times.
9011 if (buf.len == 0 && strview_has_prefix(&line, "#")) {
71 // Comment line
72 185 continue;
73 }
74
2/2
✓ Branch 0 (13→14) taken 636 times.
✓ Branch 1 (13→15) taken 8190 times.
8826 if (has_line_continuation(line)) {
75 636 line.length--;
76 636 string_append_strview(&buf, &line);
77 } else {
78 8190 string_append_strview(&buf, &line);
79 8190 handle_command(runner, string_borrow_cstring(&buf));
80 8190 string_clear(&buf);
81 }
82 }
83
84
2/2
✓ Branch 0 (22→23) taken 2 times.
✓ Branch 1 (22→25) taken 194 times.
196 if (unlikely(buf.len)) {
85 // This can only happen if the last line had a line continuation
86 2 handle_command(runner, string_borrow_cstring(&buf));
87 }
88
89 196 e->include_recursion_count--;
90 196 string_free(&buf);
91 }
92
93 3 String dump_builtin_configs(void)
94 {
95 3 String str = string_new(1024);
96
2/2
✓ Branch 0 (7→4) taken 195 times.
✓ Branch 1 (7→8) taken 3 times.
198 for (size_t i = 0; i < ARRAYLEN(builtin_configs); i++) {
97 195 string_append_cstring(&str, builtin_configs[i].name);
98 195 string_append_byte(&str, '\n');
99 }
100 3 return str;
101 }
102
103 189 const BuiltinConfig *get_builtin_config(const char *name)
104 {
105
2/2
✓ Branch 0 (6→3) taken 6067 times.
✓ Branch 1 (6→7) taken 56 times.
6123 for (size_t i = 0; i < ARRAYLEN(builtin_configs); i++) {
106
2/2
✓ Branch 0 (3→4) taken 133 times.
✓ Branch 1 (3→5) taken 5934 times.
6067 if (streq(name, builtin_configs[i].name)) {
107 133 return &builtin_configs[i];
108 }
109 }
110 return NULL;
111 }
112
113 1 const BuiltinConfig *get_builtin_configs_array(size_t *nconfigs)
114 {
115 1 *nconfigs = ARRAYLEN(builtin_configs);
116 1 return &builtin_configs[0];
117 }
118
119 269 int do_read_config(CommandRunner *runner, const char *filename, ConfigFlags flags)
120 {
121 269 ErrorBuffer *ebuf = runner->ebuf;
122 269 bool must_exist = flags & CFG_MUST_EXIST;
123
124
2/2
✓ Branch 0 (2→3) taken 141 times.
✓ Branch 1 (2→9) taken 128 times.
269 if (flags & CFG_BUILTIN) {
125 141 const BuiltinConfig *cfg = get_builtin_config(filename);
126
2/2
✓ Branch 0 (3→4) taken 87 times.
✓ Branch 1 (3→6) taken 54 times.
141 if (cfg) {
127 87 ebuf->config_filename = filename;
128 87 ebuf->config_line = 1;
129 87 exec_config(runner, cfg->text);
130 87 return 0;
131 }
132
2/2
✓ Branch 0 (6→7) taken 1 times.
✓ Branch 1 (6→17) taken 53 times.
54 if (!must_exist) {
133 return 0;
134 }
135 1 error_msg(ebuf, "no built-in config with name '%s'", filename);
136 1 return 1;
137 }
138
139 128 char *buf;
140 128 ssize_t size = read_file(filename, &buf, 0);
141
2/2
✓ Branch 0 (10→11) taken 59 times.
✓ Branch 1 (10→15) taken 69 times.
128 if (size < 0) {
142 59 int err = errno;
143
2/2
✓ Branch 0 (11→12) taken 1 times.
✓ Branch 1 (11→14) taken 58 times.
59 if (err != ENOENT || must_exist) {
144 1 error_msg(ebuf, "Error reading %s: %s", filename, strerror(err));
145 }
146 59 return err;
147 }
148
149 69 ebuf->config_filename = filename;
150 69 ebuf->config_line = 1;
151 69 exec_config(runner, string_view(buf, size));
152 69 free(buf);
153 69 return 0;
154 }
155
156 107 int read_config(CommandRunner *runner, const char *filename, ConfigFlags flags)
157 {
158 // Recursive
159 107 ErrorBuffer *ebuf = runner->ebuf;
160 107 const char *saved_file = ebuf->config_filename;
161 107 const unsigned int saved_line = ebuf->config_line;
162 107 int ret = do_read_config(runner, filename, flags);
163 107 ebuf->config_filename = saved_file;
164 107 ebuf->config_line = saved_line;
165 107 return ret;
166 }
167
168 21 static void exec_builtin_config(EditorState *e, StringView cfg, const char *name)
169 {
170 21 ErrorBuffer *ebuf = &e->err;
171 21 const char *saved_file = ebuf->config_filename;
172 21 const unsigned int saved_line = ebuf->config_line;
173 21 ebuf->config_filename = name;
174 21 ebuf->config_line = 1;
175 21 exec_normal_config(e, cfg);
176 21 ebuf->config_filename = saved_file;
177 21 ebuf->config_line = saved_line;
178 21 }
179
180 14 void exec_builtin_color_reset(EditorState *e)
181 {
182 14 clear_hl_styles(&e->styles);
183 14 StringView reset = string_view(builtin_color_reset, sizeof(builtin_color_reset) - 1);
184 14 exec_builtin_config(e, reset, "color/reset");
185 14 }
186
187 7 void exec_builtin_rc(EditorState *e)
188 {
189 7 exec_builtin_color_reset(e);
190 7 StringView rc = string_view(builtin_rc, sizeof(builtin_rc) - 1);
191 7 exec_builtin_config(e, rc, "rc");
192 7 }
193
194 1 void collect_builtin_configs(PointerArray *a, const char *prefix)
195 {
196 1 size_t prefix_len = strlen(prefix);
197
2/2
✓ Branch 0 (7→3) taken 65 times.
✓ Branch 1 (7→8) taken 1 times.
66 for (size_t i = 0; i < ARRAYLEN(builtin_configs); i++) {
198 65 const char *name = builtin_configs[i].name;
199
2/2
✓ Branch 0 (3→4) taken 1 times.
✓ Branch 1 (3→6) taken 64 times.
65 if (str_has_strn_prefix(name, prefix, prefix_len)) {
200 1 ptr_array_append(a, xstrdup(name));
201 }
202 }
203 1 }
204
205 1 void collect_builtin_includes(PointerArray *a, const char *prefix)
206 {
207 1 size_t prefix_len = strlen(prefix);
208
2/2
✓ Branch 0 (8→3) taken 65 times.
✓ Branch 1 (8→9) taken 1 times.
66 for (size_t i = 0; i < ARRAYLEN(builtin_configs); i++) {
209 65 const char *name = builtin_configs[i].name;
210 65 if (
211
2/2
✓ Branch 0 (3→4) taken 1 times.
✓ Branch 1 (3→7) taken 64 times.
65 str_has_strn_prefix(name, prefix, prefix_len)
212
1/2
✓ Branch 0 (4→5) taken 1 times.
✗ Branch 1 (4→7) not taken.
1 && !str_has_prefix(name, "syntax/")
213 ) {
214 1 ptr_array_append(a, xstrdup(name));
215 }
216 }
217 1 }
218
219 7 void log_config_counts(const EditorState *e)
220 {
221
1/2
✗ Branch 0 (3→4) not taken.
✓ Branch 1 (3→17) taken 7 times.
7 if (!log_level_enabled(LOG_LEVEL_INFO)) {
222 return;
223 }
224
225 size_t nbinds = 0;
226 size_t nbinds_cached = 0;
227 for (HashMapIter modeiter = hashmap_iter(&e->modes); hashmap_next(&modeiter); ) {
228 const ModeHandler *mode = modeiter.entry->value;
229 const IntMap *binds = &mode->key_bindings;
230 nbinds += binds->count;
231 for (IntMapIter binditer = intmap_iter(binds); intmap_next(&binditer); ) {
232 const CachedCommand *cc = binditer.entry->value;
233 nbinds_cached += !!cc->cmd;
234 }
235 }
236
237 size_t nerrorfmts = 0;
238 for (HashMapIter it = hashmap_iter(&e->compilers); hashmap_next(&it); ) {
239 const Compiler *compiler = it.entry->value;
240 nerrorfmts += compiler->error_formats.count;
241 }
242
243 LOG_INFO (
244 "bind=%zu(%zu) alias=%zu hi=%zu ft=%zu option=%zu errorfmt=%zu(%zu)",
245 nbinds,
246 nbinds_cached,
247 e->aliases.count,
248 e->styles.other.count + NR_BSE,
249 e->filetypes.count,
250 e->file_options.count,
251 e->compilers.count,
252 nerrorfmts
253 );
254 }
255