dte test coverage


Directory: ./
File: src/config.c
Date: 2025-05-08 15:05:54
Exec Total Coverage
Lines: 122 122 100.0%
Functions: 14 14 100.0%
Branches: 41 42 97.6%

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/error.h"
9 #include "commands.h"
10 #include "editor.h"
11 #include "syntax/color.h"
12 #include "util/debug.h"
13 #include "util/readfile.h"
14 #include "util/str-util.h"
15
16 #if HAVE_EMBED
17 #include "builtin-config-embed.h"
18 #else
19 #include "builtin-config.h"
20 #endif
21
22 // Odd number of backslashes at end of line?
23 8874 static bool has_line_continuation(StringView line)
24 {
25 8874 ssize_t pos = line.length - 1;
26
4/4
✓ Branch 0 (4→5) taken 8298 times.
✓ Branch 1 (4→6) taken 1432 times.
✓ Branch 2 (5→3) taken 856 times.
✓ Branch 3 (5→6) taken 7442 times.
9730 while (pos >= 0 && line.data[pos] == '\\') {
27 856 pos--;
28 }
29 8874 return (line.length - 1 - pos) & 1;
30 }
31
32 22 UNITTEST {
33 // NOLINTBEGIN(bugprone-assert-side-effect)
34 22 BUG_ON(has_line_continuation(string_view(NULL, 0)));
35 22 BUG_ON(has_line_continuation(strview_from_cstring("0")));
36 22 BUG_ON(!has_line_continuation(strview_from_cstring("1 \\")));
37 22 BUG_ON(has_line_continuation(strview_from_cstring("2 \\\\")));
38 22 BUG_ON(!has_line_continuation(strview_from_cstring("3 \\\\\\")));
39 22 BUG_ON(has_line_continuation(strview_from_cstring("4 \\\\\\\\")));
40 // NOLINTEND(bugprone-assert-side-effect)
41 22 }
42
43 197 void exec_config(CommandRunner *runner, StringView config)
44 {
45 197 EditorState *e = runner->e;
46 197 ErrorBuffer *ebuf = runner->ebuf;
47
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→5) taken 196 times.
197 if (unlikely(e->include_recursion_count > 64)) {
48 1 error_msg_for_cmd(ebuf, NULL, "config recursion limit reached");
49 1 return;
50 }
51
52 196 String buf = string_new(1024);
53 196 e->include_recursion_count++;
54
55
2/2
✓ Branch 0 (21→7) taken 8941 times.
✓ Branch 1 (21→22) taken 196 times.
9137 for (size_t i = 0, n = config.length; i < n; ebuf->config_line++) {
56 8941 StringView line = buf_slice_next_line(config.data, &i, n);
57 8941 strview_trim_left(&line);
58
4/4
✓ Branch 0 (9→10) taken 8307 times.
✓ Branch 1 (9→13) taken 634 times.
✓ Branch 2 (11→12) taken 199 times.
✓ Branch 3 (11→13) taken 8108 times.
8941 if (buf.len == 0 && strview_has_prefix(&line, "#")) {
59 // Comment line
60 199 continue;
61 }
62
2/2
✓ Branch 0 (13→14) taken 636 times.
✓ Branch 1 (13→15) taken 8106 times.
8742 if (has_line_continuation(line)) {
63 636 line.length--;
64 636 string_append_strview(&buf, &line);
65 } else {
66 8106 string_append_strview(&buf, &line);
67 8106 handle_command(runner, string_borrow_cstring(&buf));
68 8106 string_clear(&buf);
69 }
70 }
71
72
2/2
✓ Branch 0 (22→23) taken 2 times.
✓ Branch 1 (22→25) taken 194 times.
196 if (unlikely(buf.len)) {
73 // This can only happen if the last line had a line continuation
74 2 handle_command(runner, string_borrow_cstring(&buf));
75 }
76
77 196 e->include_recursion_count--;
78 196 string_free(&buf);
79 }
80
81 2 String dump_builtin_configs(void)
82 {
83 2 String str = string_new(1024);
84
2/2
✓ Branch 0 (7→4) taken 130 times.
✓ Branch 1 (7→8) taken 2 times.
132 for (size_t i = 0; i < ARRAYLEN(builtin_configs); i++) {
85 130 string_append_cstring(&str, builtin_configs[i].name);
86 130 string_append_byte(&str, '\n');
87 }
88 2 return str;
89 }
90
91 189 const BuiltinConfig *get_builtin_config(const char *name)
92 {
93
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++) {
94
2/2
✓ Branch 0 (3→4) taken 133 times.
✓ Branch 1 (3→5) taken 5934 times.
6067 if (streq(name, builtin_configs[i].name)) {
95 133 return &builtin_configs[i];
96 }
97 }
98 return NULL;
99 }
100
101 1 const BuiltinConfig *get_builtin_configs_array(size_t *nconfigs)
102 {
103 1 *nconfigs = ARRAYLEN(builtin_configs);
104 1 return &builtin_configs[0];
105 }
106
107 269 int do_read_config(CommandRunner *runner, const char *filename, ConfigFlags flags)
108 {
109 269 ErrorBuffer *ebuf = runner->ebuf;
110 269 bool must_exist = flags & CFG_MUST_EXIST;
111
112
2/2
✓ Branch 0 (2→3) taken 141 times.
✓ Branch 1 (2→9) taken 128 times.
269 if (flags & CFG_BUILTIN) {
113 141 const BuiltinConfig *cfg = get_builtin_config(filename);
114
2/2
✓ Branch 0 (3→4) taken 87 times.
✓ Branch 1 (3→6) taken 54 times.
141 if (cfg) {
115 87 ebuf->config_filename = filename;
116 87 ebuf->config_line = 1;
117 87 exec_config(runner, cfg->text);
118 87 return 0;
119 }
120
2/2
✓ Branch 0 (6→7) taken 1 times.
✓ Branch 1 (6→17) taken 53 times.
54 if (!must_exist) {
121 return 0;
122 }
123 1 error_msg(ebuf, "no built-in config with name '%s'", filename);
124 1 return 1;
125 }
126
127 128 char *buf;
128 128 ssize_t size = read_file(filename, &buf, 0);
129
2/2
✓ Branch 0 (10→11) taken 59 times.
✓ Branch 1 (10→15) taken 69 times.
128 if (size < 0) {
130 59 int err = errno;
131
2/2
✓ Branch 0 (11→12) taken 1 times.
✓ Branch 1 (11→14) taken 58 times.
59 if (err != ENOENT || must_exist) {
132 1 error_msg(ebuf, "Error reading %s: %s", filename, strerror(err));
133 }
134 59 return err;
135 }
136
137 69 ebuf->config_filename = filename;
138 69 ebuf->config_line = 1;
139 69 exec_config(runner, string_view(buf, size));
140 69 free(buf);
141 69 return 0;
142 }
143
144 107 int read_config(CommandRunner *runner, const char *filename, ConfigFlags flags)
145 {
146 // Recursive
147 107 ErrorBuffer *ebuf = runner->ebuf;
148 107 const char *saved_file = ebuf->config_filename;
149 107 const unsigned int saved_line = ebuf->config_line;
150 107 int ret = do_read_config(runner, filename, flags);
151 107 ebuf->config_filename = saved_file;
152 107 ebuf->config_line = saved_line;
153 107 return ret;
154 }
155
156 21 static void exec_builtin_config(EditorState *e, StringView cfg, const char *name)
157 {
158 21 ErrorBuffer *ebuf = &e->err;
159 21 const char *saved_file = ebuf->config_filename;
160 21 const unsigned int saved_line = ebuf->config_line;
161 21 ebuf->config_filename = name;
162 21 ebuf->config_line = 1;
163 21 exec_normal_config(e, cfg);
164 21 ebuf->config_filename = saved_file;
165 21 ebuf->config_line = saved_line;
166 21 }
167
168 14 void exec_builtin_color_reset(EditorState *e)
169 {
170 14 clear_hl_styles(&e->styles);
171 14 StringView reset = string_view(builtin_color_reset, sizeof(builtin_color_reset) - 1);
172 14 exec_builtin_config(e, reset, "color/reset");
173 14 }
174
175 7 void exec_builtin_rc(EditorState *e)
176 {
177 7 exec_builtin_color_reset(e);
178 7 StringView rc = string_view(builtin_rc, sizeof(builtin_rc) - 1);
179 7 exec_builtin_config(e, rc, "rc");
180 7 }
181
182 1 void collect_builtin_configs(PointerArray *a, const char *prefix)
183 {
184 1 size_t prefix_len = strlen(prefix);
185
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++) {
186 65 const char *name = builtin_configs[i].name;
187
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)) {
188 1 ptr_array_append(a, xstrdup(name));
189 }
190 }
191 1 }
192
193 1 void collect_builtin_includes(PointerArray *a, const char *prefix)
194 {
195 1 size_t prefix_len = strlen(prefix);
196
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++) {
197 65 const char *name = builtin_configs[i].name;
198 65 if (
199
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)
200
1/2
✓ Branch 0 (4→5) taken 1 times.
✗ Branch 1 (4→7) not taken.
1 && !str_has_prefix(name, "syntax/")
201 ) {
202 1 ptr_array_append(a, xstrdup(name));
203 }
204 }
205 1 }
206
207 22 UNITTEST {
208 // NOLINTBEGIN(bugprone-assert-side-effect)
209 22 BUG_ON(!get_builtin_config("rc"));
210 22 BUG_ON(!get_builtin_config("color/reset"));
211 // NOLINTEND(bugprone-assert-side-effect)
212 22 }
213