| 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 "editor.h" | ||
| 18 | #include "file-option.h" | ||
| 19 | #include "filetype.h" | ||
| 20 | #include "frame.h" | ||
| 21 | #include "mode.h" | ||
| 22 | #include "msg.h" | ||
| 23 | #include "options.h" | ||
| 24 | #include "syntax/color.h" | ||
| 25 | #include "tag.h" | ||
| 26 | #include "terminal/cursor.h" | ||
| 27 | #include "terminal/key.h" | ||
| 28 | #include "terminal/style.h" | ||
| 29 | #include "util/array.h" | ||
| 30 | #include "util/bsearch.h" | ||
| 31 | #include "util/debug.h" | ||
| 32 | #include "util/environ.h" | ||
| 33 | #include "util/intern.h" | ||
| 34 | #include "util/log.h" | ||
| 35 | #include "util/unicode.h" | ||
| 36 | #include "util/xmalloc.h" | ||
| 37 | #include "util/xsnprintf.h" | ||
| 38 | #include "util/xstring.h" | ||
| 39 | #include "view.h" | ||
| 40 | #include "window.h" | ||
| 41 | |||
| 42 | typedef enum { | ||
| 43 | DTERC = 1 << 0, // Use "dte" filetype (and syntax highlighter) | ||
| 44 | LASTLINE = 1 << 1, // Move cursor to last line (e.g. most recent history entry) | ||
| 45 | MSGLINE = 1 << 2, // Move cursor to line corresponding to `e->messages[0].pos` | ||
| 46 | } ShowHandlerFlags; | ||
| 47 | |||
| 48 | typedef bool (*ShowHandlerFunc)(EditorState *e, const char *name, bool cmdline); | ||
| 49 | typedef void (*CompleteArgFunc)(EditorState *e, PointerArray *a, const char *prefix); | ||
| 50 | |||
| 51 | typedef struct { | ||
| 52 | const char name[10]; | ||
| 53 | uint8_t flags; // ShowHandlerFlags | ||
| 54 | DumpFunc dump; | ||
| 55 | ShowHandlerFunc show; | ||
| 56 | CompleteArgFunc complete_arg; | ||
| 57 | } ShowHandler; | ||
| 58 | |||
| 59 | // NOLINTNEXTLINE(readability-function-size) | ||
| 60 | 1 | static void open_temporary_buffer ( | |
| 61 | EditorState *e, | ||
| 62 | const char *text, | ||
| 63 | size_t text_len, | ||
| 64 | const char *cmd, | ||
| 65 | const char *cmd_arg, | ||
| 66 | const char *filetype, | ||
| 67 | ShowHandlerFlags flags | ||
| 68 | ) { | ||
| 69 |
1/2✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 1 times.
|
1 | const char *sp = cmd_arg[0] ? " " : ""; |
| 70 | 1 | View *view = window_open_new_file(e->window); | |
| 71 | 1 | Buffer *buffer = view->buffer; | |
| 72 | 1 | buffer_set_display_filename(buffer, xasprintf("(%s%s%s)", cmd, sp, cmd_arg)); | |
| 73 | 1 | buffer->temporary = true; | |
| 74 | |||
| 75 |
2/4✓ Branch 0 (7→8) taken 1 times.
✗ Branch 1 (7→9) not taken.
✓ Branch 2 (8→9) taken 1 times.
✗ Branch 3 (8→12) not taken.
|
1 | filetype = filetype ? filetype : ((flags & DTERC) ? "dte" : NULL); |
| 76 | if (filetype) { | ||
| 77 | 1 | buffer->options.filetype = str_intern(filetype); | |
| 78 | 1 | set_file_options(e, buffer); | |
| 79 | 1 | buffer_update_syntax(e, buffer); | |
| 80 | } | ||
| 81 | |||
| 82 |
1/2✓ Branch 0 (12→13) taken 1 times.
✗ Branch 1 (12→25) not taken.
|
1 | if (text_len == 0) { |
| 83 | return; | ||
| 84 | } | ||
| 85 | |||
| 86 | 1 | BUG_ON(!text); | |
| 87 | |||
| 88 | // We don't use buffer_insert_bytes() here, because the call to | ||
| 89 | // record_insert() would make the initial text contents undoable | ||
| 90 |
1/2✗ Branch 0 (15→16) not taken.
✓ Branch 1 (15→18) taken 1 times.
|
1 | if (unlikely(text[text_len - 1] != '\n')) { |
| 91 | ✗ | LOG_ERROR("no final newline in text"); | |
| 92 | ✗ | do_insert(view, "\n", 1); | |
| 93 | } | ||
| 94 | 1 | do_insert(view, text, text_len); | |
| 95 | |||
| 96 |
1/2✗ Branch 0 (19→20) not taken.
✓ Branch 1 (19→22) taken 1 times.
|
1 | if (flags & LASTLINE) { |
| 97 | ✗ | block_iter_eof(&view->cursor); | |
| 98 | ✗ | block_iter_prev_line(&view->cursor); | |
| 99 |
1/2✗ Branch 0 (22→23) not taken.
✓ Branch 1 (22→25) taken 1 times.
|
1 | } else if (flags & MSGLINE) { |
| 100 | ✗ | const MessageList *msgs = &e->messages[0]; | |
| 101 | ✗ | if (msgs->array.count > 0) { | |
| 102 | ✗ | block_iter_goto_line(&view->cursor, msgs->pos); | |
| 103 | } | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | ✗ | static bool show_normal_alias(EditorState *e, const char *alias_name, bool cflag) | |
| 108 | { | ||
| 109 | ✗ | const char *cmd_str = find_alias(&e->aliases, alias_name); | |
| 110 | ✗ | if (!cmd_str) { | |
| 111 | ✗ | if (find_normal_command(alias_name)) { | |
| 112 | ✗ | return info_msg(&e->err, "%s is a built-in command, not an alias", alias_name); | |
| 113 | } | ||
| 114 | ✗ | return info_msg(&e->err, "%s is not a known alias", alias_name); | |
| 115 | } | ||
| 116 | |||
| 117 | ✗ | if (!cflag) { | |
| 118 | ✗ | return info_msg(&e->err, "%s is aliased to: %s", alias_name, cmd_str); | |
| 119 | } | ||
| 120 | |||
| 121 | ✗ | push_input_mode(e, e->command_mode); | |
| 122 | ✗ | cmdline_set_text(&e->cmdline, cmd_str); | |
| 123 | ✗ | return true; | |
| 124 | } | ||
| 125 | |||
| 126 | 1 | static bool show_binding(EditorState *e, const char *keystr, bool cflag) | |
| 127 | { | ||
| 128 | 1 | KeyCode key = keycode_from_str(keystr); | |
| 129 |
1/2✓ Branch 0 (3→4) taken 1 times.
✗ Branch 1 (3→5) not taken.
|
1 | if (key == KEY_NONE) { |
| 130 | 1 | return error_msg(&e->err, "invalid key string: %s", keystr); | |
| 131 | } | ||
| 132 | |||
| 133 | // Use canonical key string in printed messages | ||
| 134 | ✗ | char buf[KEYCODE_STR_BUFSIZE]; | |
| 135 | ✗ | size_t len = keycode_to_str(key, buf); | |
| 136 | ✗ | BUG_ON(len == 0); | |
| 137 | ✗ | keystr = buf; | |
| 138 | |||
| 139 | ✗ | if (u_is_unicode(key)) { | |
| 140 | ✗ | return error_msg(&e->err, "%s is not a bindable key", keystr); | |
| 141 | } | ||
| 142 | |||
| 143 | ✗ | const CachedCommand *b = lookup_binding(&e->normal_mode->key_bindings, key); | |
| 144 | ✗ | if (!b) { | |
| 145 | ✗ | return info_msg(&e->err, "%s is not bound to a command", keystr); | |
| 146 | } | ||
| 147 | |||
| 148 | ✗ | if (!cflag) { | |
| 149 | ✗ | return info_msg(&e->err, "%s is bound to: %s", keystr, b->cmd_str); | |
| 150 | } | ||
| 151 | |||
| 152 | ✗ | push_input_mode(e, e->command_mode); | |
| 153 | ✗ | cmdline_set_text(&e->cmdline, b->cmd_str); | |
| 154 | ✗ | return true; | |
| 155 | } | ||
| 156 | |||
| 157 | ✗ | static bool show_color(EditorState *e, const char *name, bool cflag) | |
| 158 | { | ||
| 159 | ✗ | const TermStyle *hl = find_style(&e->styles, name); | |
| 160 | ✗ | if (!hl) { | |
| 161 | ✗ | return info_msg(&e->err, "no color entry with name '%s'", name); | |
| 162 | } | ||
| 163 | |||
| 164 | ✗ | if (!cflag) { | |
| 165 | ✗ | char buf[TERM_STYLE_BUFSIZE]; | |
| 166 | ✗ | const char *style_str = term_style_to_string(buf, hl); | |
| 167 | ✗ | return info_msg(&e->err, "color '%s' is set to: %s", name, style_str); | |
| 168 | } | ||
| 169 | |||
| 170 | ✗ | CommandLine *c = &e->cmdline; | |
| 171 | ✗ | push_input_mode(e, e->command_mode); | |
| 172 | ✗ | cmdline_clear(c); | |
| 173 | ✗ | string_append_hl_style(&c->buf, name, hl); | |
| 174 | ✗ | c->pos = c->buf.len; | |
| 175 | ✗ | return true; | |
| 176 | } | ||
| 177 | |||
| 178 | 1 | static bool show_cursor(EditorState *e, const char *mode_str, bool cflag) | |
| 179 | { | ||
| 180 | 1 | CursorInputMode mode = cursor_mode_from_str(mode_str); | |
| 181 |
1/2✓ Branch 0 (3→4) taken 1 times.
✗ Branch 1 (3→5) not taken.
|
1 | if (mode >= NR_CURSOR_MODES) { |
| 182 | 1 | return error_msg(&e->err, "no cursor entry for '%s'", mode_str); | |
| 183 | } | ||
| 184 | |||
| 185 | ✗ | TermCursorStyle style = e->cursor_styles[mode]; | |
| 186 | ✗ | char colorbuf[COLOR_STR_BUFSIZE]; | |
| 187 | ✗ | const char *type = cursor_type_to_str(style.type); | |
| 188 | ✗ | const char *color = cursor_color_to_str(colorbuf, style.color); | |
| 189 | |||
| 190 | ✗ | if (!cflag) { | |
| 191 | ✗ | return info_msg(&e->err, "cursor '%s' is set to: %s %s", mode_str, type, color); | |
| 192 | } | ||
| 193 | |||
| 194 | ✗ | char buf[64]; | |
| 195 | ✗ | xsnprintf(buf, sizeof buf, "cursor %s %s %s", mode_str, type, color); | |
| 196 | ✗ | push_input_mode(e, e->command_mode); | |
| 197 | ✗ | cmdline_set_text(&e->cmdline, buf); | |
| 198 | ✗ | return true; | |
| 199 | } | ||
| 200 | |||
| 201 | ✗ | static bool show_env(EditorState *e, const char *name, bool cflag) | |
| 202 | { | ||
| 203 | ✗ | const char *value = getenv(name); | |
| 204 | ✗ | if (!value) { | |
| 205 | ✗ | return info_msg(&e->err, "no environment variable with name '%s'", name); | |
| 206 | } | ||
| 207 | |||
| 208 | ✗ | if (!cflag) { | |
| 209 | ✗ | return info_msg(&e->err, "$%s is set to: %s", name, value); | |
| 210 | } | ||
| 211 | |||
| 212 | ✗ | push_input_mode(e, e->command_mode); | |
| 213 | ✗ | cmdline_set_text(&e->cmdline, value); | |
| 214 | ✗ | return true; | |
| 215 | } | ||
| 216 | |||
| 217 | 1 | static String dump_env(EditorState* UNUSED_ARG(e)) | |
| 218 | { | ||
| 219 | 1 | String buf = string_new(4096); | |
| 220 |
2/2✓ Branch 0 (7→4) taken 169 times.
✓ Branch 1 (7→8) taken 1 times.
|
170 | for (size_t i = 0; environ[i]; i++) { |
| 221 | 169 | string_append_cstring(&buf, environ[i]); | |
| 222 | 169 | string_append_byte(&buf, '\n'); | |
| 223 | } | ||
| 224 | 1 | return buf; | |
| 225 | } | ||
| 226 | |||
| 227 | 1 | static String dump_setenv(EditorState* UNUSED_ARG(e)) | |
| 228 | { | ||
| 229 | 1 | String buf = string_new(4096); | |
| 230 |
2/2✓ Branch 0 (16→4) taken 169 times.
✓ Branch 1 (16→17) taken 1 times.
|
170 | for (size_t i = 0; environ[i]; i++) { |
| 231 | 169 | const char *str = environ[i]; | |
| 232 | 169 | const char *delim = strchr(str, '='); | |
| 233 |
1/2✗ Branch 0 (4→5) not taken.
✓ Branch 1 (4→6) taken 169 times.
|
169 | if (unlikely(!delim || delim == str)) { |
| 234 | ✗ | continue; | |
| 235 | } | ||
| 236 | 169 | string_append_literal(&buf, "setenv "); | |
| 237 |
3/4✓ Branch 0 (7→8) taken 169 times.
✗ Branch 1 (7→9) not taken.
✓ Branch 2 (8→9) taken 3 times.
✓ Branch 3 (8→10) taken 166 times.
|
169 | if (unlikely(str[0] == '-' || delim[1] == '-')) { |
| 238 | 3 | string_append_literal(&buf, "-- "); | |
| 239 | } | ||
| 240 | 169 | const StringView name = string_view(str, delim - str); | |
| 241 | 169 | string_append_escaped_arg_sv(&buf, name, true); | |
| 242 | 169 | string_append_byte(&buf, ' '); | |
| 243 | 169 | string_append_escaped_arg(&buf, delim + 1, true); | |
| 244 | 169 | string_append_byte(&buf, '\n'); | |
| 245 | } | ||
| 246 | 1 | return buf; | |
| 247 | } | ||
| 248 | |||
| 249 | ✗ | static const char *flag_for_builtin_mode(const EditorState *e, const ModeHandler *m) | |
| 250 | { | ||
| 251 | ✗ | if (m == e->normal_mode) { | |
| 252 | return ""; | ||
| 253 | ✗ | } else if (m == e->command_mode) { | |
| 254 | return "-c "; | ||
| 255 | ✗ | } else if (m == e->search_mode) { | |
| 256 | ✗ | return "-s "; | |
| 257 | } | ||
| 258 | return NULL; | ||
| 259 | } | ||
| 260 | |||
| 261 | ✗ | static bool show_mode(EditorState *e, const char *name, bool cflag) | |
| 262 | { | ||
| 263 | ✗ | const ModeHandler *mode = get_mode_handler(&e->modes, name); | |
| 264 | ✗ | if (!mode) { | |
| 265 | ✗ | return info_msg(&e->err, "no mode with name '%s'", name); | |
| 266 | } | ||
| 267 | |||
| 268 | ✗ | String str = string_new(4096); | |
| 269 | ✗ | const char *flag = flag_for_builtin_mode(e, mode); | |
| 270 | ✗ | if (!flag) { | |
| 271 | ✗ | string_append_def_mode(&str, mode); | |
| 272 | ✗ | string_append_byte(&str, '\n'); | |
| 273 | } | ||
| 274 | |||
| 275 | ✗ | dump_bindings(&mode->key_bindings, flag ? flag : name, &str); | |
| 276 | |||
| 277 | ✗ | if (cflag) { | |
| 278 | ✗ | buffer_insert_bytes(e->view, str.buffer, str.len); | |
| 279 | } else { | ||
| 280 | ✗ | open_temporary_buffer(e, str.buffer, str.len, "def-mode", name, NULL, DTERC); | |
| 281 | } | ||
| 282 | |||
| 283 | ✗ | string_free(&str); | |
| 284 | ✗ | return true; | |
| 285 | } | ||
| 286 | |||
| 287 | 1 | static bool show_builtin(EditorState *e, const char *name, bool cflag) | |
| 288 | { | ||
| 289 | 1 | const BuiltinConfig *cfg = get_builtin_config(name); | |
| 290 |
1/2✓ Branch 0 (2→3) taken 1 times.
✗ Branch 1 (2→4) not taken.
|
1 | if (!cfg) { |
| 291 | 1 | return error_msg(&e->err, "no built-in config with name '%s'", name); | |
| 292 | } | ||
| 293 | |||
| 294 | ✗ | const StringView sv = cfg->text; | |
| 295 | ✗ | if (cflag) { | |
| 296 | ✗ | buffer_insert_bytes(e->view, sv.data, sv.length); | |
| 297 | } else { | ||
| 298 | ✗ | bool script = str_has_prefix(name, "script/"); | |
| 299 | ✗ | const char *ft = script ? filetype_str_from_extension(name) : "dte"; | |
| 300 | ✗ | open_temporary_buffer(e, sv.data, sv.length, "builtin", name, ft, 0); | |
| 301 | } | ||
| 302 | |||
| 303 | return true; | ||
| 304 | } | ||
| 305 | |||
| 306 | ✗ | static bool show_compiler(EditorState *e, const char *name, bool cflag) | |
| 307 | { | ||
| 308 | ✗ | const Compiler *compiler = find_compiler(&e->compilers, name); | |
| 309 | ✗ | if (!compiler) { | |
| 310 | ✗ | return info_msg(&e->err, "no errorfmt entry found for '%s'", name); | |
| 311 | } | ||
| 312 | |||
| 313 | ✗ | String str = string_new(512); | |
| 314 | ✗ | dump_compiler(compiler, name, &str); | |
| 315 | ✗ | if (cflag) { | |
| 316 | ✗ | buffer_insert_bytes(e->view, str.buffer, str.len); | |
| 317 | } else { | ||
| 318 | ✗ | open_temporary_buffer(e, str.buffer, str.len, "errorfmt", name, NULL, DTERC); | |
| 319 | } | ||
| 320 | |||
| 321 | ✗ | string_free(&str); | |
| 322 | ✗ | return true; | |
| 323 | } | ||
| 324 | |||
| 325 | ✗ | static bool show_msg(EditorState *e, const char *name, bool cflag) | |
| 326 | { | ||
| 327 | ✗ | size_t idx = name[0] - 'A'; | |
| 328 | ✗ | if (idx >= ARRAYLEN(e->messages) || name[1] != '\0') { | |
| 329 | ✗ | return info_msg(&e->err, "no message list '%s'", name); | |
| 330 | } | ||
| 331 | |||
| 332 | ✗ | const MessageList *msgs = &e->messages[idx]; | |
| 333 | ✗ | String str = dump_messages(msgs); | |
| 334 | |||
| 335 | ✗ | if (cflag) { | |
| 336 | ✗ | buffer_insert_bytes(e->view, str.buffer, str.len); | |
| 337 | } else { | ||
| 338 | ✗ | open_temporary_buffer(e, str.buffer, str.len, "msg", name, NULL, 0); | |
| 339 | ✗ | if (msgs->array.count > 0) { | |
| 340 | ✗ | block_iter_goto_line(&e->view->cursor, msgs->pos); | |
| 341 | } | ||
| 342 | } | ||
| 343 | |||
| 344 | ✗ | string_free(&str); | |
| 345 | ✗ | return true; | |
| 346 | } | ||
| 347 | |||
| 348 | 1 | static bool show_option(EditorState *e, const char *name, bool cflag) | |
| 349 | { | ||
| 350 | 1 | const char *value = get_option_value_string(e, name); | |
| 351 |
1/2✓ Branch 0 (3→4) taken 1 times.
✗ Branch 1 (3→5) not taken.
|
1 | if (!value) { |
| 352 | 1 | return error_msg(&e->err, "invalid option name: %s", name); | |
| 353 | } | ||
| 354 | |||
| 355 | ✗ | if (!cflag) { | |
| 356 | ✗ | return info_msg(&e->err, "%s is set to: %s", name, value); | |
| 357 | } | ||
| 358 | |||
| 359 | ✗ | push_input_mode(e, e->command_mode); | |
| 360 | ✗ | cmdline_set_text(&e->cmdline, value); | |
| 361 | ✗ | return true; | |
| 362 | } | ||
| 363 | |||
| 364 | 1 | static void collect_all_options(EditorState* UNUSED_ARG(e), PointerArray *a, const char *prefix) | |
| 365 | { | ||
| 366 | 1 | collect_options(a, prefix, false, false); | |
| 367 | 1 | } | |
| 368 | |||
| 369 | ✗ | static void do_collect_cursor_modes(EditorState* UNUSED_ARG(e), PointerArray *a, const char *prefix) | |
| 370 | { | ||
| 371 | ✗ | collect_cursor_modes(a, prefix); | |
| 372 | ✗ | } | |
| 373 | |||
| 374 | 1 | static void do_collect_builtin_configs(EditorState* UNUSED_ARG(e), PointerArray *a, const char *prefix) | |
| 375 | { | ||
| 376 | 1 | collect_builtin_configs(a, prefix); | |
| 377 | 1 | } | |
| 378 | |||
| 379 | ✗ | static void do_collect_builtin_includes(EditorState* UNUSED_ARG(e), PointerArray *a, const char *prefix) | |
| 380 | { | ||
| 381 | ✗ | collect_builtin_includes(a, prefix); | |
| 382 | ✗ | } | |
| 383 | |||
| 384 | ✗ | static void do_collect_modes(EditorState *e, PointerArray *a, const char *prefix) | |
| 385 | { | ||
| 386 | ✗ | collect_modes(&e->modes, a, prefix); | |
| 387 | ✗ | } | |
| 388 | |||
| 389 | ✗ | static void do_collect_env(EditorState* UNUSED_ARG(e), PointerArray *a, const char *prefix) | |
| 390 | { | ||
| 391 | ✗ | collect_env(environ, a, strview(prefix), ""); | |
| 392 | ✗ | } | |
| 393 | |||
| 394 | ✗ | static void collect_show_msg_args(EditorState* UNUSED_ARG(e), PointerArray *a, const char *prefix) | |
| 395 | { | ||
| 396 | ✗ | static const char args[][2] = {"A", "B", "C"}; | |
| 397 | ✗ | COLLECT_STRINGS(args, a, prefix); | |
| 398 | ✗ | } | |
| 399 | |||
| 400 | 1 | static bool show_wsplit(EditorState *e, const char *name, bool cflag) | |
| 401 | { | ||
| 402 |
1/2✓ Branch 0 (2→3) taken 1 times.
✗ Branch 1 (2→4) not taken.
|
1 | if (!streq(name, "this")) { |
| 403 | 1 | return error_msg(&e->err, "invalid window: %s", name); | |
| 404 | } | ||
| 405 | |||
| 406 | ✗ | const Window *w = e->window; | |
| 407 | ✗ | char buf[(4 * DECIMAL_STR_MAX(w->x)) + 4]; | |
| 408 | ✗ | xsnprintf(buf, sizeof buf, "%d,%d %dx%d", w->x, w->y, w->w, w->h); | |
| 409 | |||
| 410 | ✗ | if (!cflag) { | |
| 411 | ✗ | return info_msg(&e->err, "current window dimensions: %s", buf); | |
| 412 | } | ||
| 413 | |||
| 414 | ✗ | push_input_mode(e, e->command_mode); | |
| 415 | ✗ | cmdline_set_text(&e->cmdline, buf); | |
| 416 | ✗ | return true; | |
| 417 | } | ||
| 418 | |||
| 419 | typedef struct { | ||
| 420 | const char *name; | ||
| 421 | const char *value; | ||
| 422 | } CommandAlias; | ||
| 423 | |||
| 424 | 77 | static int alias_cmp(const void *ap, const void *bp) | |
| 425 | { | ||
| 426 | 77 | const CommandAlias *a = ap; | |
| 427 | 77 | const CommandAlias *b = bp; | |
| 428 | 77 | return strcmp(a->name, b->name); | |
| 429 | } | ||
| 430 | |||
| 431 | 1 | static String dump_normal_aliases(EditorState *e) | |
| 432 | { | ||
| 433 | 1 | const size_t count = e->aliases.count; | |
| 434 |
1/2✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 1 times.
|
1 | if (unlikely(count == 0)) { |
| 435 | ✗ | return string_new(0); | |
| 436 | } | ||
| 437 | |||
| 438 | // Clone the contents of the HashMap as an array of name/value pairs | ||
| 439 | 1 | CommandAlias *array = xmallocarray(count, sizeof(*array)); | |
| 440 | 1 | size_t n = 0; | |
| 441 |
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); ) { |
| 442 | 24 | array[n++] = (CommandAlias) { | |
| 443 | 24 | .name = it.entry->key, | |
| 444 | 24 | .value = it.entry->value, | |
| 445 | }; | ||
| 446 | } | ||
| 447 | |||
| 448 | // Sort the array | ||
| 449 | 1 | BUG_ON(n != count); | |
| 450 | 1 | qsort(array, count, sizeof(array[0]), alias_cmp); | |
| 451 | |||
| 452 | // Serialize the aliases in sorted order | ||
| 453 | 1 | String buf = string_new(4096); | |
| 454 |
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++) { |
| 455 | 24 | const char *name = array[i].name; | |
| 456 | 24 | string_append_literal(&buf, "alias "); | |
| 457 |
1/2✗ Branch 0 (15→16) not taken.
✓ Branch 1 (15→17) taken 24 times.
|
24 | if (unlikely(name[0] == '-')) { |
| 458 | ✗ | string_append_literal(&buf, "-- "); | |
| 459 | } | ||
| 460 | 24 | string_append_escaped_arg(&buf, name, true); | |
| 461 | 24 | string_append_byte(&buf, ' '); | |
| 462 | 24 | string_append_escaped_arg(&buf, array[i].value, true); | |
| 463 | 24 | string_append_byte(&buf, '\n'); | |
| 464 | } | ||
| 465 | |||
| 466 | 1 | free(array); | |
| 467 | 1 | return buf; | |
| 468 | } | ||
| 469 | |||
| 470 | typedef struct { | ||
| 471 | const char *name; | ||
| 472 | const ModeHandler *handler; | ||
| 473 | } ModeHandlerEntry; | ||
| 474 | |||
| 475 | ✗ | static int mhe_cmp(const void *ap, const void *bp) | |
| 476 | { | ||
| 477 | ✗ | const ModeHandlerEntry *a = ap; | |
| 478 | ✗ | const ModeHandlerEntry *b = bp; | |
| 479 | ✗ | return strcmp(a->name, b->name); | |
| 480 | } | ||
| 481 | |||
| 482 | 1 | static String dump_all_bindings(EditorState *e) | |
| 483 | { | ||
| 484 | 1 | String buf = string_new(4096); | |
| 485 |
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)) { |
| 486 | 1 | string_append_byte(&buf, '\n'); | |
| 487 | } | ||
| 488 | |||
| 489 | 1 | size_t count = e->modes.count; | |
| 490 | 1 | BUG_ON(count < 3); | |
| 491 | 1 | count -= 3; | |
| 492 | |||
| 493 |
1/2✗ Branch 0 (8→9) not taken.
✓ Branch 1 (8→27) taken 1 times.
|
1 | if (count) { |
| 494 | // Clone custom modes in HashMap as an array | ||
| 495 | ✗ | ModeHandlerEntry *array = xmallocarray(count, sizeof(*array)); | |
| 496 | ✗ | size_t n = 0; | |
| 497 | ✗ | for (HashMapIter it = hashmap_iter(&e->modes); hashmap_next(&it); ) { | |
| 498 | ✗ | const char *name = it.entry->key; | |
| 499 | ✗ | const ModeHandler *handler = it.entry->value; | |
| 500 | ✗ | bool is_builtin_mode = !!flag_for_builtin_mode(e, handler); | |
| 501 | ✗ | if (is_builtin_mode) { | |
| 502 | ✗ | continue; | |
| 503 | } | ||
| 504 | ✗ | array[n++] = (ModeHandlerEntry) { | |
| 505 | .name = name, | ||
| 506 | .handler = handler, | ||
| 507 | }; | ||
| 508 | } | ||
| 509 | |||
| 510 | // Sort the array | ||
| 511 | ✗ | BUG_ON(n != count); | |
| 512 | ✗ | qsort(array, count, sizeof(array[0]), mhe_cmp); | |
| 513 | |||
| 514 | // Serialize bindings for each mode, sorted by mode name | ||
| 515 | ✗ | for (size_t i = 0; i < count; i++) { | |
| 516 | ✗ | const char *name = array[i].name; | |
| 517 | ✗ | const ModeHandler *handler = array[i].handler; | |
| 518 | ✗ | const IntMap *bindings = &handler->key_bindings; | |
| 519 | ✗ | if (dump_bindings(bindings, name, &buf)) { | |
| 520 | ✗ | string_append_byte(&buf, '\n'); | |
| 521 | } | ||
| 522 | } | ||
| 523 | |||
| 524 | ✗ | free(array); | |
| 525 | } | ||
| 526 | |||
| 527 | 1 | dump_bindings(&e->command_mode->key_bindings, "-c ", &buf); | |
| 528 | 1 | string_append_byte(&buf, '\n'); | |
| 529 | 1 | dump_bindings(&e->search_mode->key_bindings, "-s ", &buf); | |
| 530 | 1 | return buf; | |
| 531 | } | ||
| 532 | |||
| 533 | 1 | static String dump_modes(EditorState *e) | |
| 534 | { | ||
| 535 | // TODO: Serialize in alphabetical order, instead of table order? | ||
| 536 | 1 | String buf = string_new(256); | |
| 537 |
2/2✓ Branch 0 (7→4) taken 3 times.
✓ Branch 1 (7→8) taken 1 times.
|
4 | for (HashMapIter it = hashmap_iter(&e->modes); hashmap_next(&it); ) { |
| 538 | 3 | const ModeHandler *mode = it.entry->value; | |
| 539 | 3 | string_append_def_mode(&buf, mode); | |
| 540 | 3 | string_append_byte(&buf, '\n'); | |
| 541 | } | ||
| 542 | 1 | return buf; | |
| 543 | } | ||
| 544 | |||
| 545 | 1 | static String dump_frames(EditorState *e) | |
| 546 | { | ||
| 547 | 1 | String str = string_new(4096); | |
| 548 | 1 | dump_frame(e->root_frame, 0, &str); | |
| 549 | 1 | return str; | |
| 550 | } | ||
| 551 | |||
| 552 | 1 | static String dump_compilers(EditorState *e) | |
| 553 | { | ||
| 554 | 1 | String buf = string_new(4096); | |
| 555 |
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); ) { |
| 556 | 3 | const char *name = it.entry->key; | |
| 557 | 3 | const Compiler *c = it.entry->value; | |
| 558 | 3 | dump_compiler(c, name, &buf); | |
| 559 | 3 | string_append_byte(&buf, '\n'); | |
| 560 | } | ||
| 561 | 1 | return buf; | |
| 562 | } | ||
| 563 | |||
| 564 | 1 | static String dump_cursors(EditorState *e) | |
| 565 | { | ||
| 566 | 1 | String buf = string_new(128); | |
| 567 | 1 | char colorbuf[COLOR_STR_BUFSIZE]; | |
| 568 |
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++) { |
| 569 | 4 | const TermCursorStyle *style = &e->cursor_styles[m]; | |
| 570 | 4 | string_append_literal(&buf, "cursor "); | |
| 571 | 4 | string_append_cstring(&buf, cursor_mode_to_str(m)); | |
| 572 | 4 | string_append_byte(&buf, ' '); | |
| 573 | 4 | string_append_cstring(&buf, cursor_type_to_str(style->type)); | |
| 574 | 4 | string_append_byte(&buf, ' '); | |
| 575 | 4 | string_append_cstring(&buf, cursor_color_to_str(colorbuf, style->color)); | |
| 576 | 4 | string_append_byte(&buf, '\n'); | |
| 577 | } | ||
| 578 | 1 | return buf; | |
| 579 | } | ||
| 580 | |||
| 581 | // Dump option values and FileOption entries | ||
| 582 | 1 | static String dump_options_and_fileopts(EditorState *e) | |
| 583 | { | ||
| 584 | 1 | String str = dump_options(&e->options, &e->buffer->options); | |
| 585 | 1 | string_append_literal(&str, "\n\n"); | |
| 586 | 1 | dump_file_options(&e->file_options, &str); | |
| 587 | 1 | return str; | |
| 588 | } | ||
| 589 | |||
| 590 | 1 | static String dump_paste(EditorState *e) | |
| 591 | { | ||
| 592 | 1 | const Clipboard *clip = &e->clipboard; | |
| 593 | 1 | return string_new_from_buf(clip->buf, clip->len); | |
| 594 | } | ||
| 595 | |||
| 596 | 1 | static String do_dump_options(EditorState *e) {return dump_options(&e->options, &e->buffer->options);} | |
| 597 | 2 | static String do_dump_builtin_configs(EditorState* UNUSED_ARG(e)) {return dump_builtin_configs();} | |
| 598 | 2 | static String do_dump_hl_styles(EditorState *e) {return dump_hl_styles(&e->styles);} | |
| 599 | 1 | static String do_dump_filetypes(EditorState *e) {return dump_filetypes(&e->filetypes);} | |
| 600 | 1 | static String do_dump_messages_a(EditorState *e) {return dump_messages(&e->messages[0]);} | |
| 601 | 2 | static String do_dump_macro(EditorState *e) {return dump_macro(&e->macro);} | |
| 602 | 1 | static String do_dump_buffer(EditorState *e) {return dump_buffer(e->view);} | |
| 603 | ✗ | static String do_dump_tags(EditorState *e) {return dump_tags(&e->tagfile, &e->err);} | |
| 604 | 1 | static String dump_command_history(EditorState *e) {return history_dump(&e->command_history);} | |
| 605 | 1 | static String dump_search_history(EditorState *e) {return history_dump(&e->search_history);} | |
| 606 | 1 | static String dump_file_history(EditorState *e) {return file_history_dump(&e->file_history);} | |
| 607 | static String dump_show_subcmds(EditorState *e); // Forward declaration | ||
| 608 | |||
| 609 | static const ShowHandler show_handlers[] = { | ||
| 610 | {"alias", DTERC, dump_normal_aliases, show_normal_alias, collect_normal_aliases}, | ||
| 611 | {"bind", DTERC, dump_all_bindings, show_binding, collect_bound_normal_keys}, | ||
| 612 | {"buffer", 0, do_dump_buffer, NULL, NULL}, | ||
| 613 | {"builtin", 0, do_dump_builtin_configs, show_builtin, do_collect_builtin_configs}, | ||
| 614 | {"color", DTERC, do_dump_hl_styles, show_color, collect_hl_styles}, | ||
| 615 | {"command", DTERC | LASTLINE, dump_command_history, NULL, NULL}, | ||
| 616 | {"cursor", DTERC, dump_cursors, show_cursor, do_collect_cursor_modes}, | ||
| 617 | {"def-mode", DTERC, dump_modes, show_mode, do_collect_modes}, | ||
| 618 | {"env", 0, dump_env, show_env, do_collect_env}, | ||
| 619 | {"errorfmt", DTERC, dump_compilers, show_compiler, collect_compilers}, | ||
| 620 | {"ft", DTERC, do_dump_filetypes, NULL, NULL}, | ||
| 621 | {"hi", DTERC, do_dump_hl_styles, show_color, collect_hl_styles}, | ||
| 622 | {"include", 0, do_dump_builtin_configs, show_builtin, do_collect_builtin_includes}, | ||
| 623 | {"macro", DTERC, do_dump_macro, NULL, NULL}, | ||
| 624 | {"msg", MSGLINE, do_dump_messages_a, show_msg, collect_show_msg_args}, | ||
| 625 | {"open", LASTLINE, dump_file_history, NULL, NULL}, | ||
| 626 | {"option", DTERC, dump_options_and_fileopts, show_option, collect_all_options}, | ||
| 627 | {"paste", 0, dump_paste, NULL, NULL}, | ||
| 628 | {"search", LASTLINE, dump_search_history, NULL, NULL}, | ||
| 629 | {"set", DTERC, do_dump_options, show_option, collect_all_options}, | ||
| 630 | {"setenv", DTERC, dump_setenv, show_env, do_collect_env}, | ||
| 631 | {"show", DTERC, dump_show_subcmds, NULL, NULL}, | ||
| 632 | {"tag", 0, do_dump_tags, NULL, NULL}, | ||
| 633 | {"wsplit", 0, dump_frames, show_wsplit, NULL}, | ||
| 634 | }; | ||
| 635 | |||
| 636 | 24 | static const char *arg_hint_for_subcmd(const ShowHandler *handler) | |
| 637 | { | ||
| 638 | 24 | const ShowHandlerFunc func = handler->show; | |
| 639 |
4/4✓ Branch 0 (2→3) taken 23 times.
✓ Branch 1 (2→5) taken 1 times.
✓ Branch 2 (3→4) taken 9 times.
✓ Branch 3 (3→5) taken 14 times.
|
24 | return (func == show_binding) ? " [key]" : (func ? " [name]" : ""); |
| 640 | } | ||
| 641 | |||
| 642 | 1 | static String dump_show_subcmds(EditorState* UNUSED_ARG(e)) | |
| 643 | { | ||
| 644 | 1 | String str = string_new(256); | |
| 645 | 1 | string_append_literal(&str, "# Available `show` sub-commands:\n"); | |
| 646 |
2/2✓ Branch 0 (10→5) taken 24 times.
✓ Branch 1 (10→11) taken 1 times.
|
25 | for (size_t i = 0; i < ARRAYLEN(show_handlers); i++) { |
| 647 | 24 | const ShowHandler *handler = &show_handlers[i]; | |
| 648 | 24 | string_append_cstring(&str, "show "); | |
| 649 | 24 | string_append_cstring(&str, handler->name); | |
| 650 | 24 | string_append_cstring(&str, arg_hint_for_subcmd(handler)); | |
| 651 | 24 | string_append_byte(&str, '\n'); | |
| 652 | } | ||
| 653 | 1 | return str; | |
| 654 | } | ||
| 655 | |||
| 656 | 251 | static const ShowHandler *lookup_show_handler(const char *name) | |
| 657 | { | ||
| 658 | 251 | const ShowHandler *handler = BSEARCH(name, show_handlers, vstrcmp); | |
| 659 | 251 | return handler; | |
| 660 | } | ||
| 661 | |||
| 662 | 71 | DumpFunc get_dump_function(const char *name) | |
| 663 | { | ||
| 664 | 71 | const ShowHandler *handler = lookup_show_handler(name); | |
| 665 |
2/2✓ Branch 0 (3→4) taken 47 times.
✓ Branch 1 (3→5) taken 24 times.
|
71 | return handler ? handler->dump : NULL; |
| 666 | } | ||
| 667 | |||
| 668 | 24 | UNITTEST { | |
| 669 | // NOLINTBEGIN(bugprone-assert-side-effect) | ||
| 670 | 24 | CHECK_BSEARCH_ARRAY(show_handlers, name); | |
| 671 | 24 | BUG_ON(!lookup_show_handler("alias")); | |
| 672 | 24 | BUG_ON(!lookup_show_handler("set")); | |
| 673 | 24 | BUG_ON(!lookup_show_handler("show")); | |
| 674 | 24 | BUG_ON(!lookup_show_handler("wsplit")); | |
| 675 | 24 | BUG_ON(lookup_show_handler("alia")); | |
| 676 | 24 | BUG_ON(lookup_show_handler("sete")); | |
| 677 | 24 | BUG_ON(lookup_show_handler("")); | |
| 678 | 24 | BUG_ON(!get_dump_function("msg")); | |
| 679 | 24 | BUG_ON(get_dump_function("_")); | |
| 680 | // NOLINTEND(bugprone-assert-side-effect) | ||
| 681 | 24 | } | |
| 682 | |||
| 683 | 8 | bool show(EditorState *e, const char *type, const char *key, bool cflag) | |
| 684 | { | ||
| 685 |
1/2✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 8 times.
|
8 | const ShowHandler *handler = lookup_show_handler(type ? type : "show"); |
| 686 |
2/2✓ Branch 0 (5→6) taken 1 times.
✓ Branch 1 (5→7) taken 7 times.
|
8 | if (!handler) { |
| 687 | 1 | return error_msg(&e->err, "invalid argument: '%s'", type); | |
| 688 | } | ||
| 689 | |||
| 690 |
1/2✗ Branch 0 (7→8) not taken.
✓ Branch 1 (7→9) taken 7 times.
|
7 | if (!type) { |
| 691 | ✗ | type = ""; | |
| 692 | } | ||
| 693 | |||
| 694 |
2/2✓ Branch 0 (9→10) taken 6 times.
✓ Branch 1 (9→13) taken 1 times.
|
7 | if (key) { |
| 695 |
2/2✓ Branch 0 (10→11) taken 1 times.
✓ Branch 1 (10→12) taken 5 times.
|
6 | if (!handler->show) { |
| 696 | 1 | return error_msg(&e->err, "'show %s' doesn't take extra arguments", type); | |
| 697 | } | ||
| 698 | 5 | return handler->show(e, key, cflag); | |
| 699 | } | ||
| 700 | |||
| 701 | 1 | String str = handler->dump(e); | |
| 702 | 1 | open_temporary_buffer(e, str.buffer, str.len, "show", type, NULL, handler->flags); | |
| 703 | 1 | string_free(&str); | |
| 704 | 1 | return true; | |
| 705 | } | ||
| 706 | |||
| 707 | 2 | void collect_show_subcommands(PointerArray *a, const char *prefix) | |
| 708 | { | ||
| 709 | 2 | COLLECT_STRING_FIELDS(show_handlers, name, a, prefix); | |
| 710 | 2 | } | |
| 711 | |||
| 712 | 4 | void collect_show_subcommand_args(EditorState *e, PointerArray *a, const char *name, const char *arg_prefix) | |
| 713 | { | ||
| 714 | 4 | const ShowHandler *handler = lookup_show_handler(name); | |
| 715 |
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) { |
| 716 | 4 | handler->complete_arg(e, a, arg_prefix); | |
| 717 | } | ||
| 718 | 4 | } | |
| 719 |