dte test coverage


Directory: ./
File: src/mode.c
Date: 2025-11-12 12:04:10
Coverage Exec Excl Total
Lines: 61.1% 44 0 72
Functions: 85.7% 6 0 7
Branches: 38.2% 13 0 34

Line Branch Exec Source
1 #include <stddef.h>
2 #include "mode.h"
3 #include "bind.h"
4 #include "change.h"
5 #include "cmdline.h"
6 #include "command/macro.h"
7 #include "completion.h"
8 #include "editor.h"
9 #include "insert.h"
10 #include "shift.h"
11 #include "terminal/paste.h"
12 #include "util/debug.h"
13 #include "util/unicode.h"
14 #include "util/xmalloc.h"
15 #include "view.h"
16
17 34 ModeHandler *new_mode(HashMap *modes, char *name, const CommandSet *cmds)
18 {
19 34 ModeHandler *mode = xcalloc1(sizeof(*mode));
20 34 mode->name = name;
21 34 mode->cmds = cmds;
22 34 return hashmap_insert(modes, name, mode);
23 }
24
25 static bool insert_paste(EditorState *e, const ModeHandler *handler, bool bracketed)
26 {
27 String str = term_read_paste(&e->terminal.ibuf, bracketed);
28 if (handler->cmds == &normal_commands) {
29 begin_change(CHANGE_MERGE_NONE);
30 insert_text(e->view, str.buffer, str.len, true);
31 end_change();
32 macro_insert_text_hook(&e->macro, str.buffer, str.len);
33 } else {
34 CommandLine *c = &e->cmdline;
35 string_replace_byte(&str, '\n', ' ');
36 string_insert_buf(&c->buf, c->pos, str.buffer, str.len);
37 c->pos += str.len;
38 c->search_pos = NULL;
39 }
40 string_free(&str);
41 return true;
42 }
43
44 7 static bool handle_input_single (
45 EditorState *e,
46 const ModeHandler *handler,
47 KeyCode key,
48 ModeHandlerFlags inherited_flags
49 ) {
50 7 bool bracketed_paste = (key == KEYCODE_BRACKETED_PASTE);
51
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 7 times.
7 if (bracketed_paste || key == KEYCODE_DETECTED_PASTE) {
52 return insert_paste(e, handler, bracketed_paste);
53 }
54
55 7 ModeHandlerFlags noinsert_flags = MHF_NO_TEXT_INSERTION | MHF_NO_TEXT_INSERTION_RECURSIVE;
56 7 ModeHandlerFlags flag_union = handler->flags | inherited_flags;
57 7 bool insert_unicode_range = !(flag_union & noinsert_flags);
58
59
1/2
✓ Branch 4 → 5 taken 7 times.
✗ Branch 4 → 25 not taken.
7 if (insert_unicode_range) {
60 7 const CommandSet *cmds = handler->cmds;
61
2/2
✓ Branch 5 → 6 taken 5 times.
✓ Branch 5 → 16 taken 2 times.
7 if (cmds == &normal_commands) {
62 5 View *view = e->view;
63 5 KeyCode shift = key & MOD_SHIFT;
64
1/4
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 12 taken 5 times.
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 12 not taken.
5 if ((key & ~shift) == KEY_TAB && view->selection == SELECT_LINES) {
65 // In line selections, Tab/S-Tab behave like `shift -- 1/-1`
66 shift_lines(view, shift ? -1 : 1);
67 return true;
68 }
69
1/2
✓ Branch 12 → 13 taken 5 times.
✗ Branch 12 → 25 not taken.
5 if (u_is_unicode(key)) {
70 5 insert_ch(e->view, key);
71 5 macro_insert_char_hook(&e->macro, key);
72 5 return true;
73 }
74 } else {
75 2 BUG_ON(cmds != &cmd_mode_commands && cmds != &search_mode_commands);
76
2/4
✓ Branch 19 → 20 taken 2 times.
✗ Branch 19 → 25 not taken.
✓ Branch 20 → 21 taken 2 times.
✗ Branch 20 → 25 not taken.
2 if (u_is_unicode(key) && (key != KEY_TAB && key != KEY_ENTER)) {
77 2 CommandLine *c = &e->cmdline;
78 2 c->pos += string_insert_codepoint(&c->buf, c->pos, key);
79
1/2
✓ Branch 22 → 23 taken 2 times.
✗ Branch 22 → 24 not taken.
2 if (cmds == &cmd_mode_commands) {
80 2 maybe_reset_completion(c);
81 }
82 2 c->search_pos = NULL;
83 2 return true;
84 }
85 }
86 }
87
88 return handle_binding(e, handler, key);
89 }
90
91 // Recursion is bounded by the depth of fallthrough modes, which is
92 // typically not more than 5 or so
93 // NOLINTNEXTLINE(misc-no-recursion)
94 7 static bool handle_input_recursive (
95 EditorState *e,
96 const ModeHandler *handler,
97 KeyCode key,
98 ModeHandlerFlags inherited_flags
99 ) {
100
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 9 taken 7 times.
7 if (handle_input_single(e, handler, key, inherited_flags)) {
101 return true;
102 }
103
104 const PointerArray *ftmodes = &handler->fallthrough_modes;
105 inherited_flags |= (handler->flags & MHF_NO_TEXT_INSERTION_RECURSIVE);
106
107 for (size_t i = 0, n = ftmodes->count; i < n; i++) {
108 const ModeHandler *h = ftmodes->ptrs[i];
109 if (handle_input_recursive(e, h, key, inherited_flags)) {
110 return true;
111 }
112 }
113
114 return false;
115 }
116
117 3 void string_append_def_mode(String *buf, const ModeHandler *mode)
118 {
119 3 string_append_literal(buf, "def-mode ");
120
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 3 times.
3 if (mode->flags & MHF_NO_TEXT_INSERTION_RECURSIVE) {
121 string_append_literal(buf, "-U ");
122
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 3 times.
3 } else if (mode->flags & MHF_NO_TEXT_INSERTION) {
123 string_append_literal(buf, "-u ");
124 }
125
126 3 string_append_cstring(buf, mode->name);
127
128 3 const PointerArray *ftmodes = &mode->fallthrough_modes;
129
1/2
✗ Branch 12 → 9 not taken.
✓ Branch 12 → 13 taken 3 times.
3 for (size_t i = 0, n = ftmodes->count; i < n; i++) {
130 const ModeHandler *ftmode = ftmodes->ptrs[i];
131 string_append_byte(buf, ' ');
132 string_append_cstring(buf, ftmode->name);
133 }
134 3 }
135
136 7 bool handle_input(EditorState *e, KeyCode key)
137 {
138 7 return handle_input_recursive(e, e->mode, key, 0);
139 }
140
141 2 void collect_modes(const HashMap *modes, PointerArray *a, const char *prefix)
142 {
143 2 collect_hashmap_keys(modes, a, prefix);
144 2 }
145