dte test coverage


Directory: ./
File: src/show.c
Date: 2025-02-14 16:55:22
Exec Total Coverage
Lines: 159 313 50.8%
Functions: 28 42 66.7%
Branches: 35 112 31.2%

Line Branch Exec Source
1 #include <stdlib.h>
2 #include <string.h>
3 #include "show.h"
4 #include "bind.h"
5 #include "buffer.h"
6 #include "change.h"
7 #include "cmdline.h"
8 #include "command/alias.h"
9 #include "command/error.h"
10 #include "command/macro.h"
11 #include "command/serialize.h"
12 #include "commands.h"
13 #include "compiler.h"
14 #include "completion.h"
15 #include "config.h"
16 #include "edit.h"
17 #include "file-option.h"
18 #include "filetype.h"
19 #include "frame.h"
20 #include "mode.h"
21 #include "msg.h"
22 #include "options.h"
23 #include "syntax/color.h"
24 #include "tag.h"
25 #include "terminal/cursor.h"
26 #include "terminal/key.h"
27 #include "terminal/style.h"
28 #include "util/array.h"
29 #include "util/bsearch.h"
30 #include "util/debug.h"
31 #include "util/intern.h"
32 #include "util/log.h"
33 #include "util/unicode.h"
34 #include "util/xmalloc.h"
35 #include "util/xsnprintf.h"
36 #include "util/xstring.h"
37 #include "view.h"
38 #include "window.h"
39
40 // NOLINTNEXTLINE(*-avoid-non-const-global-variables)
41 extern char **environ;
42
43 1 static void open_temporary_buffer (
44 EditorState *e,
45 const char *text,
46 size_t text_len,
47 const char *cmd,
48 const char *cmd_arg,
49 ShowHandlerFlags flags
50 ) {
51 1 View *view = window_open_new_file(e->window);
52 1 Buffer *buffer = view->buffer;
53 1 buffer_set_display_filename(buffer, xasprintf("(%s %s)", cmd, cmd_arg));
54 1 buffer->temporary = true;
55
56
1/2
✓ Branch 0 (5→6) taken 1 times.
✗ Branch 1 (5→9) not taken.
1 if (flags & SHOW_DTERC) {
57 1 buffer->options.filetype = str_intern("dte");
58 1 set_file_options(e, buffer);
59 1 buffer_update_syntax(e, buffer);
60 }
61
62
1/2
✓ Branch 0 (9→10) taken 1 times.
✗ Branch 1 (9→22) not taken.
1 if (text_len == 0) {
63 return;
64 }
65
66 1 BUG_ON(!text);
67
68 // We don't use buffer_insert_bytes() here, because the call to
69 // record_insert() would make the initial text contents undoable
70
1/2
✗ Branch 0 (12→13) not taken.
✓ Branch 1 (12→15) taken 1 times.
1 if (unlikely(text[text_len - 1] != '\n')) {
71 LOG_ERROR("no final newline in text");
72 do_insert(view, "\n", 1);
73 }
74 1 do_insert(view, text, text_len);
75
76
1/2
✗ Branch 0 (16→17) not taken.
✓ Branch 1 (16→19) taken 1 times.
1 if (flags & SHOW_LASTLINE) {
77 block_iter_eof(&view->cursor);
78 block_iter_prev_line(&view->cursor);
79
1/4
✗ Branch 0 (19→20) not taken.
✓ Branch 1 (19→22) taken 1 times.
✗ Branch 2 (20→21) not taken.
✗ Branch 3 (20→22) not taken.
1 } else if ((flags & SHOW_MSGLINE) && e->messages.array.count > 0) {
80 block_iter_goto_line(&view->cursor, e->messages.pos);
81 }
82 }
83
84 static bool show_normal_alias(EditorState *e, const char *alias_name, bool cflag)
85 {
86 const char *cmd_str = find_alias(&e->aliases, alias_name);
87 if (!cmd_str) {
88 if (find_normal_command(alias_name)) {
89 return info_msg(&e->err, "%s is a built-in command, not an alias", alias_name);
90 }
91 return info_msg(&e->err, "%s is not a known alias", alias_name);
92 }
93
94 if (!cflag) {
95 return info_msg(&e->err, "%s is aliased to: %s", alias_name, cmd_str);
96 }
97
98 push_input_mode(e, e->command_mode);
99 cmdline_set_text(&e->cmdline, cmd_str);
100 return true;
101 }
102
103 1 static bool show_binding(EditorState *e, const char *keystr, bool cflag)
104 {
105 1 KeyCode key = parse_key_string(keystr);
106
1/2
✓ Branch 0 (3→4) taken 1 times.
✗ Branch 1 (3→5) not taken.
1 if (key == KEY_NONE) {
107 1 return error_msg(&e->err, "invalid key string: %s", keystr);
108 }
109
110 // Use canonical key string in printed messages
111 char buf[KEYCODE_STR_MAX];
112 size_t len = keycode_to_string(key, buf);
113 BUG_ON(len == 0);
114 keystr = buf;
115
116 if (u_is_unicode(key)) {
117 return error_msg(&e->err, "%s is not a bindable key", keystr);
118 }
119
120 const CachedCommand *b = lookup_binding(&e->normal_mode->key_bindings, key);
121 if (!b) {
122 return info_msg(&e->err, "%s is not bound to a command", keystr);
123 }
124
125 if (!cflag) {
126 return info_msg(&e->err, "%s is bound to: %s", keystr, b->cmd_str);
127 }
128
129 push_input_mode(e, e->command_mode);
130 cmdline_set_text(&e->cmdline, b->cmd_str);
131 return true;
132 }
133
134 static bool show_color(EditorState *e, const char *name, bool cflag)
135 {
136 const TermStyle *hl = find_style(&e->styles, name);
137 if (!hl) {
138 return info_msg(&e->err, "no color entry with name '%s'", name);
139 }
140
141 if (!cflag) {
142 char buf[TERM_STYLE_BUFSIZE];
143 const char *style_str = term_style_to_string(buf, hl);
144 return info_msg(&e->err, "color '%s' is set to: %s", name, style_str);
145 }
146
147 CommandLine *c = &e->cmdline;
148 push_input_mode(e, e->command_mode);
149 cmdline_clear(c);
150 string_append_hl_style(&c->buf, name, hl);
151 c->pos = c->buf.len;
152 return true;
153 }
154
155 1 static bool show_cursor(EditorState *e, const char *mode_str, bool cflag)
156 {
157 1 CursorInputMode mode = cursor_mode_from_str(mode_str);
158
1/2
✓ Branch 0 (3→4) taken 1 times.
✗ Branch 1 (3→5) not taken.
1 if (mode >= NR_CURSOR_MODES) {
159 1 return error_msg(&e->err, "no cursor entry for '%s'", mode_str);
160 }
161
162 TermCursorStyle style = e->cursor_styles[mode];
163 char colorbuf[COLOR_STR_BUFSIZE];
164 const char *type = cursor_type_to_str(style.type);
165 const char *color = cursor_color_to_str(colorbuf, style.color);
166
167 if (!cflag) {
168 return info_msg(&e->err, "cursor '%s' is set to: %s %s", mode_str, type, color);
169 }
170
171 char buf[64];
172 xsnprintf(buf, sizeof buf, "cursor %s %s %s", mode_str, type, color);
173 push_input_mode(e, e->command_mode);
174 cmdline_set_text(&e->cmdline, buf);
175 return true;
176 }
177
178 static bool show_env(EditorState *e, const char *name, bool cflag)
179 {
180 const char *value = getenv(name);
181 if (!value) {
182 return info_msg(&e->err, "no environment variable with name '%s'", name);
183 }
184
185 if (!cflag) {
186 return info_msg(&e->err, "$%s is set to: %s", name, value);
187 }
188
189 push_input_mode(e, e->command_mode);
190 cmdline_set_text(&e->cmdline, value);
191 return true;
192 }
193
194 static String dump_env(EditorState* UNUSED_ARG(e))
195 {
196 String buf = string_new(4096);
197 for (size_t i = 0; environ[i]; i++) {
198 string_append_cstring(&buf, environ[i]);
199 string_append_byte(&buf, '\n');
200 }
201 return buf;
202 }
203
204 static String dump_setenv(EditorState* UNUSED_ARG(e))
205 {
206 String buf = string_new(4096);
207 for (size_t i = 0; environ[i]; i++) {
208 const char *str = environ[i];
209 const char *delim = strchr(str, '=');
210 if (unlikely(!delim || delim == str)) {
211 continue;
212 }
213 string_append_literal(&buf, "setenv ");
214 if (unlikely(str[0] == '-' || delim[1] == '-')) {
215 string_append_literal(&buf, "-- ");
216 }
217 const StringView name = string_view(str, delim - str);
218 string_append_escaped_arg_sv(&buf, name, true);
219 string_append_byte(&buf, ' ');
220 string_append_escaped_arg(&buf, delim + 1, true);
221 string_append_byte(&buf, '\n');
222 }
223 return buf;
224 }
225
226 1 static bool show_builtin(EditorState *e, const char *name, bool cflag)
227 {
228 1 const BuiltinConfig *cfg = get_builtin_config(name);
229
1/2
✓ Branch 0 (2→3) taken 1 times.
✗ Branch 1 (2→4) not taken.
1 if (!cfg) {
230 1 return error_msg(&e->err, "no built-in config with name '%s'", name);
231 }
232
233 const StringView sv = cfg->text;
234 if (cflag) {
235 buffer_insert_bytes(e->view, sv.data, sv.length);
236 } else {
237 open_temporary_buffer(e, sv.data, sv.length, "builtin", name, SHOW_DTERC);
238 }
239
240 return true;
241 }
242
243 static bool show_compiler(EditorState *e, const char *name, bool cflag)
244 {
245 const Compiler *compiler = find_compiler(&e->compilers, name);
246 if (!compiler) {
247 return info_msg(&e->err, "no errorfmt entry found for '%s'", name);
248 }
249
250 String str = string_new(512);
251 dump_compiler(compiler, name, &str);
252 if (cflag) {
253 buffer_insert_bytes(e->view, str.buffer, str.len);
254 } else {
255 open_temporary_buffer(e, str.buffer, str.len, "errorfmt", name, SHOW_DTERC);
256 }
257
258 string_free(&str);
259 return true;
260 }
261
262 1 static bool show_option(EditorState *e, const char *name, bool cflag)
263 {
264 1 const char *value = get_option_value_string(e, name);
265
1/2
✓ Branch 0 (3→4) taken 1 times.
✗ Branch 1 (3→5) not taken.
1 if (!value) {
266 1 return error_msg(&e->err, "invalid option name: %s", name);
267 }
268
269 if (!cflag) {
270 return info_msg(&e->err, "%s is set to: %s", name, value);
271 }
272
273 push_input_mode(e, e->command_mode);
274 cmdline_set_text(&e->cmdline, value);
275 return true;
276 }
277
278 1 static void collect_all_options(EditorState* UNUSED_ARG(e), PointerArray *a, const char *prefix)
279 {
280 1 collect_options(a, prefix, false, false);
281 1 }
282
283 static void do_collect_cursor_modes(EditorState* UNUSED_ARG(e), PointerArray *a, const char *prefix)
284 {
285 collect_cursor_modes(a, prefix);
286 }
287
288 1 static void do_collect_builtin_configs(EditorState* UNUSED_ARG(e), PointerArray *a, const char *prefix)
289 {
290 1 collect_builtin_configs(a, prefix);
291 1 }
292
293 static void do_collect_builtin_includes(EditorState* UNUSED_ARG(e), PointerArray *a, const char *prefix)
294 {
295 collect_builtin_includes(a, prefix);
296 }
297
298 1 static bool show_wsplit(EditorState *e, const char *name, bool cflag)
299 {
300
1/2
✓ Branch 0 (2→3) taken 1 times.
✗ Branch 1 (2→4) not taken.
1 if (!streq(name, "this")) {
301 1 return error_msg(&e->err, "invalid window: %s", name);
302 }
303
304 const Window *w = e->window;
305 char buf[(4 * DECIMAL_STR_MAX(w->x)) + 4];
306 xsnprintf(buf, sizeof buf, "%d,%d %dx%d", w->x, w->y, w->w, w->h);
307
308 if (!cflag) {
309 return info_msg(&e->err, "current window dimensions: %s", buf);
310 }
311
312 push_input_mode(e, e->command_mode);
313 cmdline_set_text(&e->cmdline, buf);
314 return true;
315 }
316
317 typedef struct {
318 const char *name;
319 const char *value;
320 } CommandAlias;
321
322 77 static int alias_cmp(const void *ap, const void *bp)
323 {
324 77 const CommandAlias *a = ap;
325 77 const CommandAlias *b = bp;
326 77 return strcmp(a->name, b->name);
327 }
328
329 1 static String dump_normal_aliases(EditorState *e)
330 {
331 1 const size_t count = e->aliases.count;
332
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 1 times.
1 if (unlikely(count == 0)) {
333 return string_new(0);
334 }
335
336 // Clone the contents of the HashMap as an array of name/value pairs
337 1 CommandAlias *array = xnew(CommandAlias, count);
338 1 size_t n = 0;
339
2/2
✓ Branch 0 (8→6) taken 24 times.
✓ Branch 1 (8→9) taken 1 times.
25 for (HashMapIter it = hashmap_iter(&e->aliases); hashmap_next(&it); ) {
340 24 array[n++] = (CommandAlias) {
341 24 .name = it.entry->key,
342 24 .value = it.entry->value,
343 };
344 }
345
346 // Sort the array
347 1 BUG_ON(n != count);
348 1 qsort(array, count, sizeof(array[0]), alias_cmp);
349
350 // Serialize the aliases in sorted order
351 1 String buf = string_new(4096);
352
2/2
✓ Branch 0 (22→14) taken 24 times.
✓ Branch 1 (22→23) taken 1 times.
25 for (size_t i = 0; i < count; i++) {
353 24 const char *name = array[i].name;
354 24 string_append_literal(&buf, "alias ");
355
1/2
✗ Branch 0 (15→16) not taken.
✓ Branch 1 (15→17) taken 24 times.
24 if (unlikely(name[0] == '-')) {
356 string_append_literal(&buf, "-- ");
357 }
358 24 string_append_escaped_arg(&buf, name, true);
359 24 string_append_byte(&buf, ' ');
360 24 string_append_escaped_arg(&buf, array[i].value, true);
361 24 string_append_byte(&buf, '\n');
362 }
363
364 1 free(array);
365 1 return buf;
366 }
367
368 typedef struct {
369 const char *name;
370 const ModeHandler *handler;
371 } ModeHandlerEntry;
372
373 static int mhe_cmp(const void *ap, const void *bp)
374 {
375 const ModeHandlerEntry *a = ap;
376 const ModeHandlerEntry *b = bp;
377 return strcmp(a->name, b->name);
378 }
379
380 static bool is_builtin_mode(const EditorState *e, const ModeHandler *m)
381 {
382 return m == e->normal_mode || m == e->command_mode || m == e->search_mode;
383 }
384
385 1 static String dump_all_bindings(EditorState *e)
386 {
387 1 String buf = string_new(4096);
388
1/2
✓ Branch 0 (4→5) taken 1 times.
✗ Branch 1 (4→6) not taken.
1 if (dump_bindings(&e->normal_mode->key_bindings, "", &buf)) {
389 1 string_append_byte(&buf, '\n');
390 }
391
392 1 size_t count = e->modes.count;
393 1 BUG_ON(count < 3);
394 1 count -= 3;
395
396
1/2
✗ Branch 0 (8→9) not taken.
✓ Branch 1 (8→27) taken 1 times.
1 if (count) {
397 // Clone custom modes in HashMap as an array
398 ModeHandlerEntry *array = xnew(ModeHandlerEntry, count);
399 size_t n = 0;
400 for (HashMapIter it = hashmap_iter(&e->modes); hashmap_next(&it); ) {
401 const char *name = it.entry->key;
402 const ModeHandler *handler = it.entry->value;
403 if (is_builtin_mode(e, handler)) {
404 continue;
405 }
406 array[n++] = (ModeHandlerEntry) {
407 .name = name,
408 .handler = handler,
409 };
410 }
411
412 // Sort the array
413 BUG_ON(n != count);
414 qsort(array, count, sizeof(array[0]), mhe_cmp);
415
416 // Serialize bindings for each mode, sorted by mode name
417 for (size_t i = 0; i < count; i++) {
418 const char *name = array[i].name;
419 const ModeHandler *handler = array[i].handler;
420 const IntMap *bindings = &handler->key_bindings;
421 if (dump_bindings(bindings, name, &buf)) {
422 string_append_byte(&buf, '\n');
423 }
424 }
425
426 free(array);
427 }
428
429 1 dump_bindings(&e->command_mode->key_bindings, "-c ", &buf);
430 1 string_append_byte(&buf, '\n');
431 1 dump_bindings(&e->search_mode->key_bindings, "-s ", &buf);
432 1 return buf;
433 }
434
435 1 static String dump_modes(EditorState *e)
436 {
437 1 String buf = string_new(256);
438
439 // TODO: Serialize in alphabetical order, instead of table order?
440
2/2
✓ Branch 0 (17→4) taken 3 times.
✓ Branch 1 (17→18) taken 1 times.
4 for (HashMapIter it = hashmap_iter(&e->modes); hashmap_next(&it); ) {
441 3 const ModeHandler *mode = it.entry->value;
442 3 string_append_literal(&buf, "def-mode ");
443
1/2
✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→7) taken 3 times.
3 if (mode->flags & MHF_NO_TEXT_INSERTION_RECURSIVE) {
444 string_append_literal(&buf, "-U ");
445
1/2
✗ Branch 0 (7→8) not taken.
✓ Branch 1 (7→9) taken 3 times.
3 } else if (mode->flags & MHF_NO_TEXT_INSERTION) {
446 string_append_literal(&buf, "-u ");
447 }
448 3 string_append_cstring(&buf, mode->name);
449 3 const PointerArray *ftmodes = &mode->fallthrough_modes;
450
1/2
✗ Branch 0 (14→11) not taken.
✓ Branch 1 (14→15) taken 3 times.
3 for (size_t i = 0, n = ftmodes->count; i < n; i++) {
451 const ModeHandler *ftmode = ftmodes->ptrs[i];
452 string_append_byte(&buf, ' ');
453 string_append_cstring(&buf, ftmode->name);
454 }
455 3 string_append_byte(&buf, '\n');
456 }
457
458 1 return buf;
459 }
460
461 1 static String dump_frames(EditorState *e)
462 {
463 1 String str = string_new(4096);
464 1 dump_frame(e->root_frame, 0, &str);
465 1 return str;
466 }
467
468 1 static String dump_compilers(EditorState *e)
469 {
470 1 String buf = string_new(4096);
471
2/2
✓ Branch 0 (7→4) taken 3 times.
✓ Branch 1 (7→8) taken 1 times.
4 for (HashMapIter it = hashmap_iter(&e->compilers); hashmap_next(&it); ) {
472 3 const char *name = it.entry->key;
473 3 const Compiler *c = it.entry->value;
474 3 dump_compiler(c, name, &buf);
475 3 string_append_byte(&buf, '\n');
476 }
477 1 return buf;
478 }
479
480 1 static String dump_cursors(EditorState *e)
481 {
482 1 String buf = string_new(128);
483 1 char colorbuf[COLOR_STR_BUFSIZE];
484
2/2
✓ Branch 0 (15→4) taken 4 times.
✓ Branch 1 (15→16) taken 1 times.
5 for (CursorInputMode m = 0; m < ARRAYLEN(e->cursor_styles); m++) {
485 4 const TermCursorStyle *style = &e->cursor_styles[m];
486 4 string_append_literal(&buf, "cursor ");
487 4 string_append_cstring(&buf, cursor_mode_to_str(m));
488 4 string_append_byte(&buf, ' ');
489 4 string_append_cstring(&buf, cursor_type_to_str(style->type));
490 4 string_append_byte(&buf, ' ');
491 4 string_append_cstring(&buf, cursor_color_to_str(colorbuf, style->color));
492 4 string_append_byte(&buf, '\n');
493 }
494 1 return buf;
495 }
496
497 // Dump option values and FileOption entries
498 1 static String dump_options_and_fileopts(EditorState *e)
499 {
500 1 String str = dump_options(&e->options, &e->buffer->options);
501 1 string_append_literal(&str, "\n\n");
502 1 dump_file_options(&e->file_options, &str);
503 1 return str;
504 }
505
506 1 static String do_dump_options(EditorState *e) {return dump_options(&e->options, &e->buffer->options);}
507 1 static String do_dump_builtin_configs(EditorState* UNUSED_ARG(e)) {return dump_builtin_configs();}
508 1 static String do_dump_hl_styles(EditorState *e) {return dump_hl_styles(&e->styles);}
509 1 static String do_dump_filetypes(EditorState *e) {return dump_filetypes(&e->filetypes);}
510 static String do_dump_messages(EditorState *e) {return dump_messages(&e->messages);}
511 2 static String do_dump_macro(EditorState *e) {return dump_macro(&e->macro);}
512 1 static String do_dump_buffer(EditorState *e) {return dump_buffer(e->view);}
513 static String do_dump_tags(EditorState *e) {return dump_tags(&e->tagfile, &e->err);}
514 static String dump_command_history(EditorState *e) {return history_dump(&e->command_history);}
515 static String dump_search_history(EditorState *e) {return history_dump(&e->search_history);}
516 1 static String dump_file_history(EditorState *e) {return file_history_dump(&e->file_history);}
517
518 // Shorter aliases for ShowHandlerFlags
519 enum {
520 DTERC = SHOW_DTERC,
521 LASTLINE = SHOW_LASTLINE,
522 MSGLINE = SHOW_MSGLINE,
523 };
524
525 static const ShowHandler show_handlers[] = {
526 {"alias", DTERC, dump_normal_aliases, show_normal_alias, collect_normal_aliases},
527 {"bind", DTERC, dump_all_bindings, show_binding, collect_bound_normal_keys},
528 {"buffer", 0, do_dump_buffer, NULL, NULL},
529 {"builtin", 0, do_dump_builtin_configs, show_builtin, do_collect_builtin_configs},
530 {"color", DTERC, do_dump_hl_styles, show_color, collect_hl_styles},
531 {"command", DTERC | LASTLINE, dump_command_history, NULL, NULL},
532 {"cursor", DTERC, dump_cursors, show_cursor, do_collect_cursor_modes},
533 {"def-mode", DTERC, dump_modes, NULL, NULL},
534 {"env", 0, dump_env, show_env, collect_env},
535 {"errorfmt", DTERC, dump_compilers, show_compiler, collect_compilers},
536 {"ft", DTERC, do_dump_filetypes, NULL, NULL},
537 {"hi", DTERC, do_dump_hl_styles, show_color, collect_hl_styles},
538 {"include", 0, do_dump_builtin_configs, show_builtin, do_collect_builtin_includes},
539 {"macro", DTERC, do_dump_macro, NULL, NULL},
540 {"msg", MSGLINE, do_dump_messages, NULL, NULL},
541 {"open", LASTLINE, dump_file_history, NULL, NULL},
542 {"option", DTERC, dump_options_and_fileopts, show_option, collect_all_options},
543 {"search", LASTLINE, dump_search_history, NULL, NULL},
544 {"set", DTERC, do_dump_options, show_option, collect_all_options},
545 {"setenv", DTERC, dump_setenv, show_env, collect_env},
546 {"tag", 0, do_dump_tags, NULL, NULL},
547 {"wsplit", 0, dump_frames, show_wsplit, NULL},
548 };
549
550 134 const ShowHandler *lookup_show_handler(const char *name)
551 {
552 134 const ShowHandler *handler = BSEARCH(name, show_handlers, vstrcmp);
553 134 return handler;
554 }
555
556 18 UNITTEST {
557 // NOLINTBEGIN(bugprone-assert-side-effect)
558 18 CHECK_BSEARCH_ARRAY(show_handlers, name, strcmp);
559 18 BUG_ON(!lookup_show_handler("alias"));
560 18 BUG_ON(!lookup_show_handler("set"));
561 18 BUG_ON(!lookup_show_handler("wsplit"));
562 18 BUG_ON(lookup_show_handler("alia"));
563 18 BUG_ON(lookup_show_handler("sete"));
564 18 BUG_ON(lookup_show_handler(""));
565 // NOLINTEND(bugprone-assert-side-effect)
566 18 }
567
568 8 bool show(EditorState *e, const char *type, const char *key, bool cflag)
569 {
570 8 const ShowHandler *handler = lookup_show_handler(type);
571
2/2
✓ Branch 0 (3→4) taken 1 times.
✓ Branch 1 (3→5) taken 7 times.
8 if (!handler) {
572 1 return error_msg(&e->err, "invalid argument: '%s'", type);
573 }
574
575
2/2
✓ Branch 0 (5→6) taken 6 times.
✓ Branch 1 (5→9) taken 1 times.
7 if (key) {
576
2/2
✓ Branch 0 (6→7) taken 1 times.
✓ Branch 1 (6→8) taken 5 times.
6 if (!handler->show) {
577 1 return error_msg(&e->err, "'show %s' doesn't take extra arguments", type);
578 }
579 5 return handler->show(e, key, cflag);
580 }
581
582 1 String str = handler->dump(e);
583 1 open_temporary_buffer(e, str.buffer, str.len, "show", type, handler->flags);
584 1 string_free(&str);
585 1 return true;
586 }
587
588 2 void collect_show_subcommands(PointerArray *a, const char *prefix)
589 {
590 2 COLLECT_STRING_FIELDS(show_handlers, name, a, prefix);
591 2 }
592
593 4 void collect_show_subcommand_args(EditorState *e, PointerArray *a, const char *name, const char *arg_prefix)
594 {
595 4 const ShowHandler *handler = lookup_show_handler(name);
596
2/4
✓ Branch 0 (3→4) taken 4 times.
✗ Branch 1 (3→6) not taken.
✓ Branch 2 (4→5) taken 4 times.
✗ Branch 3 (4→6) not taken.
4 if (handler && handler->complete_arg) {
597 4 handler->complete_arg(e, a, arg_prefix);
598 }
599 4 }
600