dte test coverage


Directory: ./
File: src/bind.c
Date: 2025-09-07 23:01:39
Exec Total Coverage
Lines: 59 65 90.8%
Functions: 8 8 100.0%
Branches: 10 16 62.5%

Line Branch Exec Source
1 #include <limits.h>
2 #include <stdlib.h>
3 #include "bind.h"
4 #include "change.h"
5 #include "command/macro.h"
6 #include "command/run.h"
7 #include "command/serialize.h"
8 #include "editor.h"
9 #include "util/debug.h"
10 #include "util/xmalloc.h"
11
12 1955 void add_binding(IntMap *bindings, KeyCode key, CachedCommand *cc)
13 {
14 1955 cached_command_free(intmap_insert_or_replace(bindings, key, cc));
15 1955 }
16
17 1 void remove_binding(IntMap *bindings, KeyCode key)
18 {
19 1 cached_command_free(intmap_remove(bindings, key));
20 1 }
21
22 11 const CachedCommand *lookup_binding(const IntMap *bindings, KeyCode key)
23 {
24 11 return intmap_get(bindings, key);
25 }
26
27 34 void free_bindings(IntMap *bindings)
28 {
29 34 intmap_free(bindings, FREE_FUNC(cached_command_free));
30 34 }
31
32 3 bool handle_binding(EditorState *e, const ModeHandler *handler, KeyCode key)
33 {
34 3 const CachedCommand *binding = lookup_binding(&handler->key_bindings, key);
35
1/2
✓ Branch 0 (3→4) taken 3 times.
✗ Branch 1 (3→15) not taken.
3 if (!binding) {
36 return false;
37 }
38
39 3 const CommandSet *cmds = handler->cmds;
40 3 BUG_ON(!cmds);
41
42 // If the command isn't cached or a macro is being recorded
43
3/6
✓ Branch 0 (6→7) taken 3 times.
✗ Branch 1 (6→9) not taken.
✓ Branch 2 (7→8) taken 3 times.
✗ Branch 3 (7→11) not taken.
✗ Branch 4 (8→9) not taken.
✓ Branch 5 (8→11) taken 3 times.
3 if (!binding->cmd || (cmds->macro_record && macro_is_recording(&e->macro))) {
44 // Parse and run command string
45 CommandRunner runner = cmdrunner(e, cmds);
46 runner.flags |= CMDRUNNER_ALLOW_RECORDING;
47 return handle_command(&runner, binding->cmd_str);
48 }
49
50 // Command is cached; call it directly
51 3 begin_change(CHANGE_MERGE_NONE);
52 3 command_func_call(e, &e->err, binding->cmd, &binding->a);
53 3 end_change();
54 3 return true;
55 }
56
57 typedef struct {
58 KeyCode key;
59 const char *cmd;
60 } KeyBinding;
61
62 1207 static int binding_cmp(const void *ap, const void *bp)
63 {
64 1207 static_assert((MOD_MASK | KEY_SPECIAL_MAX) <= INT_MAX);
65 1207 const KeyBinding *a = ap;
66 1207 const KeyBinding *b = bp;
67 1207 return (int)a->key - (int)b->key;
68 }
69
70 24 UNITTEST {
71 // NOLINTBEGIN(bugprone-assert-side-effect)
72 24 KeyBinding a = {.key = KEY_F5};
73 24 KeyBinding b = {.key = KEY_F5};
74 24 BUG_ON(binding_cmp(&a, &b) != 0);
75 24 b.key = KEY_F3;
76 24 BUG_ON(binding_cmp(&a, &b) <= 0);
77 24 b.key = KEY_F12;
78 24 BUG_ON(binding_cmp(&a, &b) >= 0);
79 // NOLINTEND(bugprone-assert-side-effect)
80 24 }
81
82 3 bool dump_bindings(const IntMap *bindings, const char *flag, String *buf)
83 {
84 3 const size_t count = bindings->count;
85
1/2
✓ Branch 0 (2→3) taken 3 times.
✗ Branch 1 (2→26) not taken.
3 if (unlikely(count == 0)) {
86 return false;
87 }
88
89 // Clone the contents of the map as an array of key/command pairs
90 3 KeyBinding *array = xmallocarray(count, sizeof(*array));
91 3 size_t n = 0;
92
2/2
✓ Branch 0 (7→5) taken 218 times.
✓ Branch 1 (7→8) taken 3 times.
221 for (IntMapIter it = intmap_iter(bindings); intmap_next(&it); ) {
93 218 const CachedCommand *cc = it.entry->value;
94 218 array[n++] = (KeyBinding) {
95 218 .key = it.entry->key,
96 218 .cmd = cc->cmd_str,
97 };
98 }
99
100 // Sort the array
101 3 BUG_ON(n != count);
102 3 qsort(array, count, sizeof(array[0]), binding_cmp);
103
104 // Serialize the bindings in sorted order
105 3 char keystr[KEYCODE_STR_BUFSIZE];
106
2/2
✓ Branch 0 (24→12) taken 218 times.
✓ Branch 1 (24→25) taken 3 times.
221 for (size_t i = 0; i < count; i++) {
107 218 string_append_literal(buf, "bind ");
108
1/2
✗ Branch 0 (13→14) not taken.
✓ Branch 1 (13→17) taken 218 times.
218 if (flag[0] != '\0' && flag[0] != '-') {
109 string_append_cstring(buf, "-T ");
110 string_append_escaped_arg(buf, flag, true);
111 string_append_byte(buf, ' ');
112 } else {
113 218 string_append_cstring(buf, flag);
114 }
115 218 size_t keylen = keycode_to_str(array[i].key, keystr);
116 218 string_append_escaped_arg_sv(buf, string_view(keystr, keylen), true);
117 218 string_append_byte(buf, ' ');
118 218 string_append_escaped_arg(buf, array[i].cmd, true);
119 218 string_append_byte(buf, '\n');
120 }
121
122 3 free(array);
123 3 return true;
124 }
125