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 |