| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include <stdlib.h> | ||
| 2 | #include <string.h> | ||
| 3 | #include "cmdline.h" | ||
| 4 | #include "command/args.h" | ||
| 5 | #include "command/macro.h" | ||
| 6 | #include "commands.h" | ||
| 7 | #include "completion.h" | ||
| 8 | #include "copy.h" | ||
| 9 | #include "editor.h" | ||
| 10 | #include "history.h" | ||
| 11 | #include "options.h" | ||
| 12 | #include "regexp.h" | ||
| 13 | #include "search.h" | ||
| 14 | #include "selection.h" | ||
| 15 | #include "terminal/osc52.h" | ||
| 16 | #include "util/arith.h" | ||
| 17 | #include "util/ascii.h" | ||
| 18 | #include "util/bsearch.h" | ||
| 19 | #include "util/debug.h" | ||
| 20 | #include "util/log.h" | ||
| 21 | #include "util/utf8.h" | ||
| 22 | |||
| 23 | 4 | static void cmdline_delete(CommandLine *c) | |
| 24 | { | ||
| 25 | 4 | size_t pos = c->pos; | |
| 26 |
2/2✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→4) taken 3 times.
|
4 | if (pos == c->buf.len) { |
| 27 | 1 | return; | |
| 28 | } | ||
| 29 | |||
| 30 | 3 | u_get_char(c->buf.buffer, c->buf.len, &pos); | |
| 31 | 3 | string_remove(&c->buf, c->pos, pos - c->pos); | |
| 32 | } | ||
| 33 | |||
| 34 | 13 | void cmdline_clear(CommandLine *c) | |
| 35 | { | ||
| 36 | 13 | string_clear(&c->buf); | |
| 37 | 13 | c->pos = 0; | |
| 38 | 13 | c->search_pos = NULL; | |
| 39 | 13 | } | |
| 40 | |||
| 41 | 11 | void cmdline_free(CommandLine *c) | |
| 42 | { | ||
| 43 | 11 | cmdline_clear(c); | |
| 44 | 11 | string_free(&c->buf); | |
| 45 | 11 | free(c->search_text); | |
| 46 | 11 | reset_completion(c); | |
| 47 | 11 | } | |
| 48 | |||
| 49 | 172 | static void set_text(CommandLine *c, const char *text) | |
| 50 | { | ||
| 51 | 172 | size_t text_len = strlen(text); | |
| 52 | 172 | c->pos = text_len; | |
| 53 | 172 | string_clear(&c->buf); | |
| 54 | 172 | string_append_buf(&c->buf, text, text_len); | |
| 55 | 172 | } | |
| 56 | |||
| 57 | 172 | void cmdline_set_text(CommandLine *c, const char *text) | |
| 58 | { | ||
| 59 | 172 | c->search_pos = NULL; | |
| 60 | 172 | set_text(c, text); | |
| 61 | 172 | } | |
| 62 | |||
| 63 | // Reset command completion and history search state (after cursor | ||
| 64 | // position or buffer is changed) | ||
| 65 | 20 | static bool cmdline_soft_reset(CommandLine *c) | |
| 66 | { | ||
| 67 | 20 | c->search_pos = NULL; | |
| 68 | 20 | maybe_reset_completion(c); | |
| 69 | 20 | return true; | |
| 70 | } | ||
| 71 | |||
| 72 | 2 | static bool cmd_bol(EditorState *e, const CommandArgs *a) | |
| 73 | { | ||
| 74 | 2 | BUG_ON(a->nr_args); | |
| 75 | 2 | e->cmdline.pos = 0; | |
| 76 | 2 | return cmdline_soft_reset(&e->cmdline); | |
| 77 | } | ||
| 78 | |||
| 79 | 1 | static bool cmd_cancel(EditorState *e, const CommandArgs *a) | |
| 80 | { | ||
| 81 | 1 | BUG_ON(a->nr_args); | |
| 82 | 1 | CommandLine *c = &e->cmdline; | |
| 83 | 1 | cmdline_clear(c); | |
| 84 | 1 | pop_input_mode(e); | |
| 85 | 1 | reset_completion(c); | |
| 86 | 1 | return true; | |
| 87 | } | ||
| 88 | |||
| 89 | ✗ | static bool cmd_clear(EditorState *e, const CommandArgs *a) | |
| 90 | { | ||
| 91 | ✗ | BUG_ON(a->nr_args); | |
| 92 | ✗ | cmdline_clear(&e->cmdline); | |
| 93 | ✗ | return true; | |
| 94 | } | ||
| 95 | |||
| 96 | ✗ | static bool cmd_copy(EditorState *e, const CommandArgs *a) | |
| 97 | { | ||
| 98 | ✗ | static const FlagMapping map[] = { | |
| 99 | {'b', TCOPY_CLIPBOARD}, | ||
| 100 | {'p', TCOPY_PRIMARY}, | ||
| 101 | }; | ||
| 102 | |||
| 103 | ✗ | Terminal *term = &e->terminal; | |
| 104 | ✗ | TermCopyFlags flags = cmdargs_convert_flags(a, map, ARRAYLEN(map)); | |
| 105 | ✗ | bool internal = cmdargs_has_flag(a, 'i') || flags == 0; | |
| 106 | ✗ | bool osc52 = flags && (term->features & TFLAG_OSC52_COPY); | |
| 107 | ✗ | String *buf = &e->cmdline.buf; | |
| 108 | ✗ | size_t len = buf->len; | |
| 109 | |||
| 110 | ✗ | if (internal) { | |
| 111 | ✗ | char *str = string_clone_cstring(buf); | |
| 112 | ✗ | record_copy(&e->clipboard, str, len, false); | |
| 113 | } | ||
| 114 | |||
| 115 | ✗ | if (osc52) { | |
| 116 | ✗ | bool ok = term_osc52_copy(&term->obuf, strview_from_string(buf), flags); | |
| 117 | ✗ | LOG_ERRNO_ON(!ok, "term_osc52_copy"); | |
| 118 | } | ||
| 119 | |||
| 120 | ✗ | return true; | |
| 121 | } | ||
| 122 | |||
| 123 | 2 | static bool cmd_delete(EditorState *e, const CommandArgs *a) | |
| 124 | { | ||
| 125 | 2 | BUG_ON(a->nr_args); | |
| 126 | 2 | CommandLine *c = &e->cmdline; | |
| 127 | 2 | cmdline_delete(c); | |
| 128 | 2 | return cmdline_soft_reset(c); | |
| 129 | } | ||
| 130 | |||
| 131 | 1 | static bool cmd_delete_eol(EditorState *e, const CommandArgs *a) | |
| 132 | { | ||
| 133 | 1 | BUG_ON(a->nr_args); | |
| 134 | 1 | CommandLine *c = &e->cmdline; | |
| 135 | 1 | c->buf.len = c->pos; | |
| 136 | 1 | return cmdline_soft_reset(c); | |
| 137 | } | ||
| 138 | |||
| 139 | 1 | static bool cmd_delete_word(EditorState *e, const CommandArgs *a) | |
| 140 | { | ||
| 141 | 1 | BUG_ON(a->nr_args); | |
| 142 | 1 | CommandLine *c = &e->cmdline; | |
| 143 | 1 | const char *buf = c->buf.buffer; | |
| 144 | 1 | const size_t len = c->buf.len; | |
| 145 | 1 | size_t i = c->pos; | |
| 146 | |||
| 147 |
1/2✓ Branch 0 (4→6) taken 1 times.
✗ Branch 1 (4→14) not taken.
|
1 | if (i == len) { |
| 148 | return true; | ||
| 149 | } | ||
| 150 | |||
| 151 |
3/4✓ Branch 0 (6→7) taken 6 times.
✗ Branch 1 (6→8) not taken.
✓ Branch 2 (7→5) taken 5 times.
✓ Branch 3 (7→8) taken 1 times.
|
6 | while (i < len && is_word_byte(buf[i])) { |
| 152 | 5 | i++; | |
| 153 | } | ||
| 154 | |||
| 155 |
3/4✓ Branch 0 (10→11) taken 2 times.
✗ Branch 1 (10→12) not taken.
✓ Branch 2 (11→9) taken 1 times.
✓ Branch 3 (11→12) taken 1 times.
|
2 | while (i < len && !is_word_byte(buf[i])) { |
| 156 | 1 | i++; | |
| 157 | } | ||
| 158 | |||
| 159 | 1 | string_remove(&c->buf, c->pos, i - c->pos); | |
| 160 | 1 | return cmdline_soft_reset(c); | |
| 161 | } | ||
| 162 | |||
| 163 | 2 | static bool cmd_eol(EditorState *e, const CommandArgs *a) | |
| 164 | { | ||
| 165 | 2 | BUG_ON(a->nr_args); | |
| 166 | 2 | CommandLine *c = &e->cmdline; | |
| 167 | 2 | c->pos = c->buf.len; | |
| 168 | 2 | return cmdline_soft_reset(c); | |
| 169 | } | ||
| 170 | |||
| 171 | 2 | static bool cmd_erase(EditorState *e, const CommandArgs *a) | |
| 172 | { | ||
| 173 | 2 | BUG_ON(a->nr_args); | |
| 174 | 2 | CommandLine *c = &e->cmdline; | |
| 175 |
1/2✓ Branch 0 (4→5) taken 2 times.
✗ Branch 1 (4→7) not taken.
|
2 | if (c->pos > 0) { |
| 176 | 2 | u_prev_char(c->buf.buffer, &c->pos); | |
| 177 | 2 | cmdline_delete(c); | |
| 178 | } | ||
| 179 | 2 | return cmdline_soft_reset(c); | |
| 180 | } | ||
| 181 | |||
| 182 | 1 | static bool cmd_erase_bol(EditorState *e, const CommandArgs *a) | |
| 183 | { | ||
| 184 | 1 | BUG_ON(a->nr_args); | |
| 185 | 1 | CommandLine *c = &e->cmdline; | |
| 186 | 1 | string_remove(&c->buf, 0, c->pos); | |
| 187 | 1 | c->pos = 0; | |
| 188 | 1 | return cmdline_soft_reset(c); | |
| 189 | } | ||
| 190 | |||
| 191 | 2 | static bool cmd_erase_word(EditorState *e, const CommandArgs *a) | |
| 192 | { | ||
| 193 | 2 | BUG_ON(a->nr_args); | |
| 194 | 2 | CommandLine *c = &e->cmdline; | |
| 195 | 2 | size_t i = c->pos; | |
| 196 |
1/2✓ Branch 0 (4→5) taken 2 times.
✗ Branch 1 (4→15) not taken.
|
2 | if (i == 0) { |
| 197 | return true; | ||
| 198 | } | ||
| 199 | |||
| 200 | // open /path/to/file^W => open /path/to/ | ||
| 201 | |||
| 202 | // erase whitespace | ||
| 203 |
3/4✓ Branch 0 (5→6) taken 3 times.
✗ Branch 1 (5→7) not taken.
✓ Branch 2 (6→5) taken 1 times.
✓ Branch 3 (6→7) taken 2 times.
|
3 | while (i && ascii_isspace(c->buf.buffer[i - 1])) { |
| 204 | i--; | ||
| 205 | } | ||
| 206 | |||
| 207 | // erase non-word bytes | ||
| 208 |
2/4✓ Branch 0 (8→9) taken 2 times.
✗ Branch 1 (8→10) not taken.
✗ Branch 2 (9→8) not taken.
✓ Branch 3 (9→10) taken 2 times.
|
2 | while (i && !is_word_byte(c->buf.buffer[i - 1])) { |
| 209 | i--; | ||
| 210 | } | ||
| 211 | |||
| 212 | // erase word bytes | ||
| 213 |
3/4✓ Branch 0 (11→12) taken 12 times.
✗ Branch 1 (11→13) not taken.
✓ Branch 2 (12→11) taken 10 times.
✓ Branch 3 (12→13) taken 2 times.
|
12 | while (i && is_word_byte(c->buf.buffer[i - 1])) { |
| 214 | i--; | ||
| 215 | } | ||
| 216 | |||
| 217 | 2 | string_remove(&c->buf, i, c->pos - i); | |
| 218 | 2 | c->pos = i; | |
| 219 | 2 | return cmdline_soft_reset(c); | |
| 220 | } | ||
| 221 | |||
| 222 | ✗ | static bool do_history_prev(const History *hist, CommandLine *c, bool prefix_search) | |
| 223 | { | ||
| 224 | ✗ | if (!c->search_pos) { | |
| 225 | ✗ | free(c->search_text); | |
| 226 | ✗ | c->search_text = string_clone_cstring(&c->buf); | |
| 227 | } | ||
| 228 | |||
| 229 | ✗ | const char *search_text = prefix_search ? c->search_text : ""; | |
| 230 | ✗ | if (history_search_forward(hist, &c->search_pos, search_text)) { | |
| 231 | ✗ | BUG_ON(!c->search_pos); | |
| 232 | ✗ | set_text(c, c->search_pos->text); | |
| 233 | } | ||
| 234 | |||
| 235 | ✗ | maybe_reset_completion(c); | |
| 236 | ✗ | return true; | |
| 237 | } | ||
| 238 | |||
| 239 | ✗ | static bool do_history_next(const History *hist, CommandLine *c, bool prefix_search) | |
| 240 | { | ||
| 241 | ✗ | if (!c->search_pos) { | |
| 242 | ✗ | goto out; | |
| 243 | } | ||
| 244 | |||
| 245 | ✗ | const char *search_text = prefix_search ? c->search_text : ""; | |
| 246 | ✗ | if (history_search_backward(hist, &c->search_pos, search_text)) { | |
| 247 | ✗ | BUG_ON(!c->search_pos); | |
| 248 | ✗ | set_text(c, c->search_pos->text); | |
| 249 | } else { | ||
| 250 | ✗ | set_text(c, c->search_text); | |
| 251 | ✗ | c->search_pos = NULL; | |
| 252 | } | ||
| 253 | |||
| 254 | ✗ | out: | |
| 255 | ✗ | maybe_reset_completion(c); | |
| 256 | ✗ | return true; | |
| 257 | } | ||
| 258 | |||
| 259 | ✗ | static bool cmd_search_history_next(EditorState *e, const CommandArgs *a) | |
| 260 | { | ||
| 261 | ✗ | BUG_ON(a->nr_args); | |
| 262 | ✗ | bool prefix_search = !cmdargs_has_flag(a, 'S'); | |
| 263 | ✗ | return do_history_next(&e->search_history, &e->cmdline, prefix_search); | |
| 264 | } | ||
| 265 | |||
| 266 | ✗ | static bool cmd_search_history_prev(EditorState *e, const CommandArgs *a) | |
| 267 | { | ||
| 268 | ✗ | BUG_ON(a->nr_args); | |
| 269 | ✗ | bool prefix_search = !cmdargs_has_flag(a, 'S'); | |
| 270 | ✗ | return do_history_prev(&e->search_history, &e->cmdline, prefix_search); | |
| 271 | } | ||
| 272 | |||
| 273 | ✗ | static bool cmd_command_history_next(EditorState *e, const CommandArgs *a) | |
| 274 | { | ||
| 275 | ✗ | BUG_ON(a->nr_args); | |
| 276 | ✗ | bool prefix_search = !cmdargs_has_flag(a, 'S'); | |
| 277 | ✗ | return do_history_next(&e->command_history, &e->cmdline, prefix_search); | |
| 278 | } | ||
| 279 | |||
| 280 | ✗ | static bool cmd_command_history_prev(EditorState *e, const CommandArgs *a) | |
| 281 | { | ||
| 282 | ✗ | BUG_ON(a->nr_args); | |
| 283 | ✗ | bool prefix_search = !cmdargs_has_flag(a, 'S'); | |
| 284 | ✗ | return do_history_prev(&e->command_history, &e->cmdline, prefix_search); | |
| 285 | } | ||
| 286 | |||
| 287 | 2 | static bool cmd_left(EditorState *e, const CommandArgs *a) | |
| 288 | { | ||
| 289 | 2 | BUG_ON(a->nr_args); | |
| 290 | 2 | CommandLine *c = &e->cmdline; | |
| 291 |
2/2✓ Branch 0 (4→5) taken 1 times.
✓ Branch 1 (4→6) taken 1 times.
|
2 | if (c->pos) { |
| 292 | 1 | u_prev_char(c->buf.buffer, &c->pos); | |
| 293 | } | ||
| 294 | 2 | return cmdline_soft_reset(c); | |
| 295 | } | ||
| 296 | |||
| 297 | ✗ | static bool cmd_paste(EditorState *e, const CommandArgs *a) | |
| 298 | { | ||
| 299 | ✗ | const Clipboard *clip = &e->clipboard; | |
| 300 | ✗ | const size_t len = clip->len; | |
| 301 | ✗ | if (len == 0) { | |
| 302 | return true; | ||
| 303 | } | ||
| 304 | |||
| 305 | ✗ | CommandLine *c = &e->cmdline; | |
| 306 | ✗ | char newline_replacement = cmdargs_has_flag(a, 'n') ? ';' : ' '; | |
| 307 | ✗ | string_insert_buf(&c->buf, c->pos, clip->buf, len); | |
| 308 | ✗ | strn_replace_byte(c->buf.buffer + c->pos, len, '\n', newline_replacement); | |
| 309 | ✗ | c->pos += cmdargs_has_flag(a, 'm') ? len : 0; | |
| 310 | ✗ | return cmdline_soft_reset(c); | |
| 311 | } | ||
| 312 | |||
| 313 | 2 | static bool cmd_right(EditorState *e, const CommandArgs *a) | |
| 314 | { | ||
| 315 | 2 | BUG_ON(a->nr_args); | |
| 316 | 2 | CommandLine *c = &e->cmdline; | |
| 317 |
1/2✓ Branch 0 (4→5) taken 2 times.
✗ Branch 1 (4→6) not taken.
|
2 | if (c->pos < c->buf.len) { |
| 318 | 2 | u_get_char(c->buf.buffer, c->buf.len, &c->pos); | |
| 319 | } | ||
| 320 | 2 | return cmdline_soft_reset(c); | |
| 321 | } | ||
| 322 | |||
| 323 | ✗ | static bool cmd_toggle(EditorState *e, const CommandArgs *a) | |
| 324 | { | ||
| 325 | ✗ | const char *option_name = a->args[0]; | |
| 326 | ✗ | bool global = cmdargs_has_flag(a, 'g'); | |
| 327 | ✗ | size_t nr_values = a->nr_args - 1; | |
| 328 | ✗ | if (nr_values == 0) { | |
| 329 | ✗ | return toggle_option(e, option_name, global, false); | |
| 330 | } | ||
| 331 | |||
| 332 | ✗ | char **values = a->args + 1; | |
| 333 | ✗ | return toggle_option_values(e, option_name, global, false, values, nr_values); | |
| 334 | } | ||
| 335 | |||
| 336 | 2 | static bool cmd_word_bwd(EditorState *e, const CommandArgs *a) | |
| 337 | { | ||
| 338 | 2 | BUG_ON(a->nr_args); | |
| 339 | 2 | CommandLine *c = &e->cmdline; | |
| 340 |
2/2✓ Branch 0 (4→5) taken 1 times.
✓ Branch 1 (4→6) taken 1 times.
|
2 | if (c->pos <= 1) { |
| 341 | 1 | c->pos = 0; | |
| 342 | 1 | return cmdline_soft_reset(c); | |
| 343 | } | ||
| 344 | |||
| 345 | 1 | const char *const buf = c->buf.buffer; | |
| 346 | 1 | size_t i = c->pos - 1; | |
| 347 | |||
| 348 |
3/4✓ Branch 0 (8→9) taken 2 times.
✗ Branch 1 (8→10) not taken.
✓ Branch 2 (9→7) taken 1 times.
✓ Branch 3 (9→10) taken 1 times.
|
2 | while (i > 0 && !is_word_byte(buf[i])) { |
| 349 | 1 | i--; | |
| 350 | } | ||
| 351 | |||
| 352 |
3/4✓ Branch 0 (12→13) taken 6 times.
✗ Branch 1 (12→14) not taken.
✓ Branch 2 (13→11) taken 5 times.
✓ Branch 3 (13→14) taken 1 times.
|
6 | while (i > 0 && is_word_byte(buf[i])) { |
| 353 | 5 | i--; | |
| 354 | } | ||
| 355 | |||
| 356 |
1/2✓ Branch 0 (14→15) taken 1 times.
✗ Branch 1 (14→16) not taken.
|
1 | if (i > 0) { |
| 357 | 1 | i++; | |
| 358 | } | ||
| 359 | |||
| 360 | 1 | c->pos = i; | |
| 361 | 1 | return cmdline_soft_reset(c); | |
| 362 | } | ||
| 363 | |||
| 364 | 1 | static bool cmd_word_fwd(EditorState *e, const CommandArgs *a) | |
| 365 | { | ||
| 366 | 1 | BUG_ON(a->nr_args); | |
| 367 | 1 | CommandLine *c = &e->cmdline; | |
| 368 | 1 | const char *buf = c->buf.buffer; | |
| 369 | 1 | const size_t len = c->buf.len; | |
| 370 | 1 | size_t i = c->pos; | |
| 371 | |||
| 372 |
3/4✓ Branch 0 (6→7) taken 6 times.
✗ Branch 1 (6→8) not taken.
✓ Branch 2 (7→5) taken 5 times.
✓ Branch 3 (7→8) taken 1 times.
|
6 | while (i < len && is_word_byte(buf[i])) { |
| 373 | 5 | i++; | |
| 374 | } | ||
| 375 | |||
| 376 |
3/4✓ Branch 0 (10→11) taken 1 times.
✓ Branch 1 (10→12) taken 1 times.
✓ Branch 2 (11→9) taken 1 times.
✗ Branch 3 (11→12) not taken.
|
2 | while (i < len && !is_word_byte(buf[i])) { |
| 377 | 1 | i++; | |
| 378 | } | ||
| 379 | |||
| 380 | 1 | c->pos = i; | |
| 381 | 1 | return cmdline_soft_reset(c); | |
| 382 | } | ||
| 383 | |||
| 384 | ✗ | static bool cmd_complete_next(EditorState *e, const CommandArgs *a) | |
| 385 | { | ||
| 386 | ✗ | BUG_ON(a->nr_args); | |
| 387 | ✗ | complete_command_next(e); | |
| 388 | ✗ | return true; | |
| 389 | } | ||
| 390 | |||
| 391 | ✗ | static bool cmd_complete_prev(EditorState *e, const CommandArgs *a) | |
| 392 | { | ||
| 393 | ✗ | BUG_ON(a->nr_args); | |
| 394 | ✗ | complete_command_prev(e); | |
| 395 | ✗ | return true; | |
| 396 | } | ||
| 397 | |||
| 398 | ✗ | static bool cmd_direction(EditorState *e, const CommandArgs *a) | |
| 399 | { | ||
| 400 | ✗ | BUG_ON(a->nr_args); | |
| 401 | ✗ | toggle_search_direction(&e->search); | |
| 402 | ✗ | return true; | |
| 403 | } | ||
| 404 | |||
| 405 | ✗ | static bool cmd_command_mode_accept(EditorState *e, const CommandArgs *a) | |
| 406 | { | ||
| 407 | ✗ | CommandLine *c = &e->cmdline; | |
| 408 | ✗ | reset_completion(c); | |
| 409 | ✗ | pop_input_mode(e); | |
| 410 | |||
| 411 | ✗ | const char *str = string_borrow_cstring(&c->buf); | |
| 412 | ✗ | cmdline_clear(c); | |
| 413 | ✗ | if (!cmdargs_has_flag(a, 'H') && str[0] != ' ') { | |
| 414 | // This is done before handle_command() because "command [text]" | ||
| 415 | // can modify the contents of the command-line | ||
| 416 | ✗ | history_append(&e->command_history, str); | |
| 417 | } | ||
| 418 | |||
| 419 | ✗ | e->err.command_name = NULL; | |
| 420 | ✗ | return handle_normal_command(e, str, true); | |
| 421 | } | ||
| 422 | |||
| 423 | ✗ | static bool cmd_search_mode_accept(EditorState *e, const CommandArgs *a) | |
| 424 | { | ||
| 425 | ✗ | CommandLine *c = &e->cmdline; | |
| 426 | ✗ | bool add_to_history = !cmdargs_has_flag(a, 'H'); | |
| 427 | ✗ | const char *pat = NULL; | |
| 428 | |||
| 429 | ✗ | if (c->buf.len > 0) { | |
| 430 | ✗ | String *s = &c->buf; | |
| 431 | ✗ | if (cmdargs_has_flag(a, 'e')) { | |
| 432 | // Escape the regex; to match as plain text | ||
| 433 | ✗ | char *original = string_clone_cstring(s); | |
| 434 | ✗ | size_t origlen = string_clear(s); | |
| 435 | ✗ | size_t bufsize = xmul(2, origlen) + 1; | |
| 436 | ✗ | char *buf = string_reserve_space(s, bufsize); | |
| 437 | ✗ | s->len = regexp_escapeb(buf, bufsize, original, origlen); | |
| 438 | ✗ | BUG_ON(s->len < origlen); | |
| 439 | ✗ | free(original); | |
| 440 | } | ||
| 441 | |||
| 442 | ✗ | pat = string_borrow_cstring(s); | |
| 443 | ✗ | search_set_regexp(&e->search, pat); | |
| 444 | ✗ | if (add_to_history) { | |
| 445 | ✗ | history_append(&e->search_history, pat); | |
| 446 | } | ||
| 447 | } | ||
| 448 | |||
| 449 | ✗ | if (e->macro.recording) { | |
| 450 | ✗ | macro_search_hook(&e->macro, pat, e->search.reverse, add_to_history); | |
| 451 | } | ||
| 452 | |||
| 453 | // Unselect, unless selection mode is active | ||
| 454 | ✗ | view_set_selection_type(e->view, e->view->select_mode); | |
| 455 | |||
| 456 | ✗ | e->err.command_name = NULL; | |
| 457 | ✗ | bool found = search_next(e->view, &e->search, e->options.case_sensitive_search); | |
| 458 | ✗ | cmdline_clear(c); | |
| 459 | ✗ | pop_input_mode(e); | |
| 460 | ✗ | return found; | |
| 461 | } | ||
| 462 | |||
| 463 | // Note that some of the `Command::flags` entries here aren't actually | ||
| 464 | // used in the `cmd` handler and are only included to mirror commands | ||
| 465 | // of the same name in normal mode. This is done as a convenience for | ||
| 466 | // allowing key binding commands like e.g. `bind -cns C-M-c 'copy -bk'` | ||
| 467 | // to be used, instead of needing 2 different commands (with and without | ||
| 468 | // the `-k` flag for normal vs. command/search modes). | ||
| 469 | |||
| 470 | #define CMD(name, flags, min, max, func) \ | ||
| 471 | {name, flags, 0, min, max, func} | ||
| 472 | |||
| 473 | static const Command common_cmds[] = { | ||
| 474 | CMD("bol", "st", 0, 0, cmd_bol), // Ignored flags: s, t | ||
| 475 | CMD("cancel", "", 0, 0, cmd_cancel), | ||
| 476 | CMD("clear", "Ii", 0, 0, cmd_clear), // Ignored flags: I, i | ||
| 477 | CMD("copy", "bikp", 0, 0, cmd_copy), // Ignored flag: k | ||
| 478 | CMD("delete", "", 0, 0, cmd_delete), | ||
| 479 | CMD("delete-eol", "n", 0, 0, cmd_delete_eol), // Ignored flag: n | ||
| 480 | CMD("delete-word", "s", 0, 0, cmd_delete_word), // Ignored flag: s | ||
| 481 | CMD("eol", "", 0, 0, cmd_eol), | ||
| 482 | CMD("erase", "", 0, 0, cmd_erase), | ||
| 483 | CMD("erase-bol", "", 0, 0, cmd_erase_bol), | ||
| 484 | CMD("erase-word", "s", 0, 0, cmd_erase_word), // Ignored flag: s | ||
| 485 | CMD("left", "", 0, 0, cmd_left), | ||
| 486 | CMD("paste", "acmn", 0, 0, cmd_paste), // Ignored flags: a, c | ||
| 487 | CMD("right", "", 0, 0, cmd_right), | ||
| 488 | CMD("toggle", "gv", 1, -1, cmd_toggle), // Ignored flag: v | ||
| 489 | CMD("word-bwd", "s", 0, 0, cmd_word_bwd), // Ignored flag: s | ||
| 490 | CMD("word-fwd", "s", 0, 0, cmd_word_fwd), // Ignored flag: s | ||
| 491 | }; | ||
| 492 | |||
| 493 | static const Command search_cmds[] = { | ||
| 494 | CMD("accept", "eH", 0, 0, cmd_search_mode_accept), | ||
| 495 | CMD("direction", "", 0, 0, cmd_direction), | ||
| 496 | CMD("history-next", "S", 0, 0, cmd_search_history_next), | ||
| 497 | CMD("history-prev", "S", 0, 0, cmd_search_history_prev), | ||
| 498 | }; | ||
| 499 | |||
| 500 | static const Command command_cmds[] = { | ||
| 501 | CMD("accept", "H", 0, 0, cmd_command_mode_accept), | ||
| 502 | CMD("complete-next", "", 0, 0, cmd_complete_next), | ||
| 503 | CMD("complete-prev", "", 0, 0, cmd_complete_prev), | ||
| 504 | CMD("history-next", "S", 0, 0, cmd_command_history_next), | ||
| 505 | CMD("history-prev", "S", 0, 0, cmd_command_history_prev), | ||
| 506 | }; | ||
| 507 | |||
| 508 | 373 | static const Command *find_cmd_mode_command(const char *name) | |
| 509 | { | ||
| 510 | 373 | const Command *cmd = BSEARCH(name, common_cmds, command_cmp); | |
| 511 |
2/2✓ Branch 0 (3→4) taken 64 times.
✓ Branch 1 (3→5) taken 309 times.
|
373 | return cmd ? cmd : BSEARCH(name, command_cmds, command_cmp); |
| 512 | } | ||
| 513 | |||
| 514 | 360 | static const Command *find_search_mode_command(const char *name) | |
| 515 | { | ||
| 516 | 360 | const Command *cmd = BSEARCH(name, common_cmds, command_cmp); | |
| 517 |
2/2✓ Branch 0 (3→4) taken 63 times.
✓ Branch 1 (3→5) taken 297 times.
|
360 | return cmd ? cmd : BSEARCH(name, search_cmds, command_cmp); |
| 518 | } | ||
| 519 | |||
| 520 | const CommandSet cmd_mode_commands = { | ||
| 521 | .lookup = find_cmd_mode_command | ||
| 522 | }; | ||
| 523 | |||
| 524 | const CommandSet search_mode_commands = { | ||
| 525 | .lookup = find_search_mode_command | ||
| 526 | }; | ||
| 527 |