dte test coverage


Directory: ./
File: src/command/run.c
Date: 2025-07-05 20:19:48
Exec Total Coverage
Lines: 70 70 100.0%
Functions: 3 3 100.0%
Branches: 33 34 97.1%

Line Branch Exec Source
1 #include "run.h"
2 #include "args.h"
3 #include "parse.h"
4 #include "change.h"
5 #include "util/debug.h"
6 #include "util/ptr-array.h"
7 #include "util/xmalloc.h"
8
9 enum {
10 MAX_RECURSION_DEPTH = 16, // Maximum number of `alias` expansions
11 };
12
13 static bool run_commands(CommandRunner *runner, const PointerArray *array);
14
15 // Recursion is limited by MAX_RECURSION_DEPTH
16 // NOLINTNEXTLINE(misc-no-recursion)
17 7830 static bool run_command(CommandRunner *runner, char **av)
18 {
19 7830 const CommandSet *cmds = runner->cmds;
20 7830 const Command *cmd = cmds->lookup(av[0]);
21 7830 struct EditorState *e = runner->e;
22 7830 ErrorBuffer *ebuf = runner->ebuf;
23
24
2/2
✓ Branch 0 (3→4) taken 35 times.
✓ Branch 1 (3→24) taken 7795 times.
7830 if (!cmd) {
25 35 const char *name = av[0];
26
2/2
✓ Branch 0 (4→5) taken 2 times.
✓ Branch 1 (4→6) taken 33 times.
35 if (!runner->lookup_alias) {
27 2 return error_msg_for_cmd(ebuf, NULL, "No such command: %s", name);
28 }
29
30 33 const char *alias_value = runner->lookup_alias(e, name);
31
2/2
✓ Branch 0 (7→8) taken 2 times.
✓ Branch 1 (7→9) taken 31 times.
33 if (unlikely(!alias_value)) {
32 2 return error_msg_for_cmd(ebuf, NULL, "No such command or alias: %s", name);
33 }
34
35 31 PointerArray array = PTR_ARRAY_INIT;
36 31 CommandParseError err = parse_commands(runner, &array, alias_value);
37
2/2
✓ Branch 0 (10→11) taken 1 times.
✓ Branch 1 (10→14) taken 30 times.
31 if (unlikely(err != CMDERR_NONE)) {
38 1 const char *err_msg = command_parse_error_to_string(err);
39 1 ptr_array_free(&array);
40 1 return error_msg_for_cmd(ebuf, NULL, "Parsing alias %s: %s", name, err_msg);
41 }
42
43 // Remove NULL
44 30 array.count--;
45
46
2/2
✓ Branch 0 (18→15) taken 35 times.
✓ Branch 1 (18→19) taken 30 times.
65 for (size_t i = 1; av[i]; i++) {
47 35 ptr_array_append(&array, xstrdup(av[i]));
48 }
49 30 ptr_array_append(&array, NULL);
50
51 30 bool r = run_commands(runner, &array);
52 30 ptr_array_free(&array);
53 30 return r;
54 }
55
56
4/4
✓ Branch 0 (24→25) taken 7179 times.
✓ Branch 1 (24→27) taken 616 times.
✓ Branch 2 (25→26) taken 1 times.
✓ Branch 3 (25→27) taken 7178 times.
7795 if (unlikely(ebuf->config_filename && !(cmd->cmdopts & CMDOPT_ALLOW_IN_RC))) {
57 1 return error_msg_for_cmd(ebuf, NULL, "Command %s not allowed in config file", cmd->name);
58 }
59
60 // Record command in macro buffer, if recording (this needs to be done
61 // before parse_args() mutates the array)
62
3/4
✓ Branch 0 (27→28) taken 5 times.
✓ Branch 1 (27→30) taken 7789 times.
✓ Branch 2 (28→29) taken 5 times.
✗ Branch 3 (28→30) not taken.
7794 if ((runner->flags & CMDRUNNER_ALLOW_RECORDING) && runner->cmds->macro_record) {
63 5 runner->cmds->macro_record(e, cmd, av + 1);
64 }
65
66 // By default change can't be merged with previous one.
67 // Any command can override this by calling begin_change() again.
68 7794 begin_change(CHANGE_MERGE_NONE);
69
70 7794 CommandArgs a = cmdargs_new(av + 1);
71
4/4
✓ Branch 0 (32→33) taken 7787 times.
✓ Branch 1 (32→36) taken 7 times.
✓ Branch 2 (34→35) taken 138 times.
✓ Branch 3 (34→36) taken 7649 times.
7794 bool r = likely(parse_args(cmd, &a, ebuf)) && command_func_call(e, ebuf, cmd, &a);
72
73 7794 end_change();
74 7794 return r;
75 }
76
77 // Recursion is limited by MAX_RECURSION_DEPTH
78 // NOLINTNEXTLINE(misc-no-recursion)
79 9231 static bool run_commands(CommandRunner *runner, const PointerArray *array)
80 {
81
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→4) taken 9230 times.
9231 if (unlikely(runner->recursion_count > MAX_RECURSION_DEPTH)) {
82 1 return error_msg_for_cmd(runner->ebuf, NULL, "alias recursion limit reached");
83 }
84
85 9230 bool stop_at_first_err = (runner->flags & CMDRUNNER_STOP_AT_FIRST_ERROR);
86 9230 void **ptrs = array->ptrs;
87 9230 size_t len = array->count;
88 9230 size_t nfailed = 0;
89 9230 BUG_ON(len == 0);
90 9230 BUG_ON(ptrs[len - 1] != NULL);
91 9230 runner->recursion_count++;
92
93
2/2
✓ Branch 0 (18→11) taken 9327 times.
✓ Branch 1 (18→19) taken 9228 times.
18555 for (size_t s = 0, e = 0; s < len; ) {
94 // Iterate over strings, until a terminating NULL is encountered
95 36761 while (ptrs[e]) {
96 27434 e++;
97 36761 BUG_ON(e >= len);
98 }
99
100 // If the value of `e` (end) changed, there's a run of at least
101 // 1 string, which is a command followed by 0 or more arguments
102
2/2
✓ Branch 0 (12→13) taken 7830 times.
✓ Branch 1 (12→17) taken 1497 times.
9327 if (e != s) {
103
2/2
✓ Branch 0 (14→15) taken 168 times.
✓ Branch 1 (14→17) taken 7662 times.
7830 if (!run_command(runner, (char**)ptrs + s)) {
104 168 nfailed++;
105
2/2
✓ Branch 0 (15→16) taken 2 times.
✓ Branch 1 (15→17) taken 166 times.
168 if (stop_at_first_err) {
106 2 goto out;
107 }
108 }
109 }
110
111 // Skip past the NULL, onto the next command (if any)
112 9325 s = ++e;
113 }
114
115 9228 out:
116 9230 runner->recursion_count--;
117 9230 return (nfailed == 0);
118 }
119
120 9206 bool handle_command(CommandRunner *runner, const char *cmd)
121 {
122 9206 BUG_ON(runner->recursion_count != 0);
123 9206 PointerArray array = PTR_ARRAY_INIT;
124 9206 CommandParseError err = parse_commands(runner, &array, cmd);
125 9206 bool r;
126
2/2
✓ Branch 0 (5→6) taken 9201 times.
✓ Branch 1 (5→9) taken 5 times.
9206 if (likely(err == CMDERR_NONE)) {
127 9201 r = run_commands(runner, &array);
128 9201 BUG_ON(runner->recursion_count != 0);
129 } else {
130 5 const char *str = command_parse_error_to_string(err);
131 5 error_msg_for_cmd(runner->ebuf, NULL, "Command syntax error: %s", str);
132 5 r = false;
133 }
134 9206 ptr_array_free(&array);
135 9206 return r;
136 }
137