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 |