1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 10 /* 11 * usercmd.c: User defined command support 12 */ 13 14 #include "vim.h" 15 16 typedef struct ucmd 17 { 18 char_u *uc_name; // The command name 19 long_u uc_argt; // The argument type 20 char_u *uc_rep; // The command's replacement string 21 long uc_def; // The default value for a range/count 22 int uc_compl; // completion type 23 cmd_addr_T uc_addr_type; // The command's address type 24 # ifdef FEAT_EVAL 25 sctx_T uc_script_ctx; // SCTX where the command was defined 26 char_u *uc_compl_arg; // completion argument if any 27 # endif 28 } ucmd_T; 29 30 // List of all user commands. 31 static garray_T ucmds = {0, 0, sizeof(ucmd_T), 4, NULL}; 32 33 #define USER_CMD(i) (&((ucmd_T *)(ucmds.ga_data))[i]) 34 #define USER_CMD_GA(gap, i) (&((ucmd_T *)((gap)->ga_data))[i]) 35 36 /* 37 * List of names for completion for ":command" with the EXPAND_ flag. 38 * Must be alphabetical for completion. 39 */ 40 static struct 41 { 42 int expand; 43 char *name; 44 } command_complete[] = 45 { 46 {EXPAND_ARGLIST, "arglist"}, 47 {EXPAND_AUGROUP, "augroup"}, 48 {EXPAND_BEHAVE, "behave"}, 49 {EXPAND_BUFFERS, "buffer"}, 50 {EXPAND_COLORS, "color"}, 51 {EXPAND_COMMANDS, "command"}, 52 {EXPAND_COMPILER, "compiler"}, 53 #if defined(FEAT_CSCOPE) 54 {EXPAND_CSCOPE, "cscope"}, 55 #endif 56 #if defined(FEAT_EVAL) 57 {EXPAND_USER_DEFINED, "custom"}, 58 {EXPAND_USER_LIST, "customlist"}, 59 #endif 60 {EXPAND_DIFF_BUFFERS, "diff_buffer"}, 61 {EXPAND_DIRECTORIES, "dir"}, 62 {EXPAND_ENV_VARS, "environment"}, 63 {EXPAND_EVENTS, "event"}, 64 {EXPAND_EXPRESSION, "expression"}, 65 {EXPAND_FILES, "file"}, 66 {EXPAND_FILES_IN_PATH, "file_in_path"}, 67 {EXPAND_FILETYPE, "filetype"}, 68 {EXPAND_FUNCTIONS, "function"}, 69 {EXPAND_HELP, "help"}, 70 {EXPAND_HIGHLIGHT, "highlight"}, 71 {EXPAND_HISTORY, "history"}, 72 #if defined(HAVE_LOCALE_H) || defined(X_LOCALE) 73 {EXPAND_LOCALES, "locale"}, 74 #endif 75 {EXPAND_MAPCLEAR, "mapclear"}, 76 {EXPAND_MAPPINGS, "mapping"}, 77 {EXPAND_MENUS, "menu"}, 78 {EXPAND_MESSAGES, "messages"}, 79 {EXPAND_OWNSYNTAX, "syntax"}, 80 #if defined(FEAT_PROFILE) 81 {EXPAND_SYNTIME, "syntime"}, 82 #endif 83 {EXPAND_SETTINGS, "option"}, 84 {EXPAND_PACKADD, "packadd"}, 85 {EXPAND_SHELLCMD, "shellcmd"}, 86 #if defined(FEAT_SIGNS) 87 {EXPAND_SIGN, "sign"}, 88 #endif 89 {EXPAND_TAGS, "tag"}, 90 {EXPAND_TAGS_LISTFILES, "tag_listfiles"}, 91 {EXPAND_USER, "user"}, 92 {EXPAND_USER_VARS, "var"}, 93 {0, NULL} 94 }; 95 96 /* 97 * List of names of address types. Must be alphabetical for completion. 98 */ 99 static struct 100 { 101 cmd_addr_T expand; 102 char *name; 103 char *shortname; 104 } addr_type_complete[] = 105 { 106 {ADDR_ARGUMENTS, "arguments", "arg"}, 107 {ADDR_LINES, "lines", "line"}, 108 {ADDR_LOADED_BUFFERS, "loaded_buffers", "load"}, 109 {ADDR_TABS, "tabs", "tab"}, 110 {ADDR_BUFFERS, "buffers", "buf"}, 111 {ADDR_WINDOWS, "windows", "win"}, 112 {ADDR_QUICKFIX, "quickfix", "qf"}, 113 {ADDR_OTHER, "other", "?"}, 114 {ADDR_NONE, NULL, NULL} 115 }; 116 117 #define UC_BUFFER 1 // -buffer: local to current buffer 118 119 /* 120 * Search for a user command that matches "eap->cmd". 121 * Return cmdidx in "eap->cmdidx", flags in "eap->argt", idx in "eap->useridx". 122 * Return a pointer to just after the command. 123 * Return NULL if there is no matching command. 124 */ 125 char_u * 126 find_ucmd( 127 exarg_T *eap, 128 char_u *p, // end of the command (possibly including count) 129 int *full, // set to TRUE for a full match 130 expand_T *xp, // used for completion, NULL otherwise 131 int *complp UNUSED) // completion flags or NULL 132 { 133 int len = (int)(p - eap->cmd); 134 int j, k, matchlen = 0; 135 ucmd_T *uc; 136 int found = FALSE; 137 int possible = FALSE; 138 char_u *cp, *np; // Point into typed cmd and test name 139 garray_T *gap; 140 int amb_local = FALSE; // Found ambiguous buffer-local command, 141 // only full match global is accepted. 142 143 /* 144 * Look for buffer-local user commands first, then global ones. 145 */ 146 gap = &curbuf->b_ucmds; 147 for (;;) 148 { 149 for (j = 0; j < gap->ga_len; ++j) 150 { 151 uc = USER_CMD_GA(gap, j); 152 cp = eap->cmd; 153 np = uc->uc_name; 154 k = 0; 155 while (k < len && *np != NUL && *cp++ == *np++) 156 k++; 157 if (k == len || (*np == NUL && vim_isdigit(eap->cmd[k]))) 158 { 159 // If finding a second match, the command is ambiguous. But 160 // not if a buffer-local command wasn't a full match and a 161 // global command is a full match. 162 if (k == len && found && *np != NUL) 163 { 164 if (gap == &ucmds) 165 return NULL; 166 amb_local = TRUE; 167 } 168 169 if (!found || (k == len && *np == NUL)) 170 { 171 // If we matched up to a digit, then there could 172 // be another command including the digit that we 173 // should use instead. 174 if (k == len) 175 found = TRUE; 176 else 177 possible = TRUE; 178 179 if (gap == &ucmds) 180 eap->cmdidx = CMD_USER; 181 else 182 eap->cmdidx = CMD_USER_BUF; 183 eap->argt = (long)uc->uc_argt; 184 eap->useridx = j; 185 eap->addr_type = uc->uc_addr_type; 186 187 if (complp != NULL) 188 *complp = uc->uc_compl; 189 # ifdef FEAT_EVAL 190 if (xp != NULL) 191 { 192 xp->xp_arg = uc->uc_compl_arg; 193 xp->xp_script_ctx = uc->uc_script_ctx; 194 xp->xp_script_ctx.sc_lnum += SOURCING_LNUM; 195 } 196 # endif 197 // Do not search for further abbreviations 198 // if this is an exact match. 199 matchlen = k; 200 if (k == len && *np == NUL) 201 { 202 if (full != NULL) 203 *full = TRUE; 204 amb_local = FALSE; 205 break; 206 } 207 } 208 } 209 } 210 211 // Stop if we found a full match or searched all. 212 if (j < gap->ga_len || gap == &ucmds) 213 break; 214 gap = &ucmds; 215 } 216 217 // Only found ambiguous matches. 218 if (amb_local) 219 { 220 if (xp != NULL) 221 xp->xp_context = EXPAND_UNSUCCESSFUL; 222 return NULL; 223 } 224 225 // The match we found may be followed immediately by a number. Move "p" 226 // back to point to it. 227 if (found || possible) 228 return p + (matchlen - len); 229 return p; 230 } 231 232 char_u * 233 set_context_in_user_cmd(expand_T *xp, char_u *arg_in) 234 { 235 char_u *arg = arg_in; 236 char_u *p; 237 238 // Check for attributes 239 while (*arg == '-') 240 { 241 arg++; // Skip "-" 242 p = skiptowhite(arg); 243 if (*p == NUL) 244 { 245 // Cursor is still in the attribute 246 p = vim_strchr(arg, '='); 247 if (p == NULL) 248 { 249 // No "=", so complete attribute names 250 xp->xp_context = EXPAND_USER_CMD_FLAGS; 251 xp->xp_pattern = arg; 252 return NULL; 253 } 254 255 // For the -complete, -nargs and -addr attributes, we complete 256 // their arguments as well. 257 if (STRNICMP(arg, "complete", p - arg) == 0) 258 { 259 xp->xp_context = EXPAND_USER_COMPLETE; 260 xp->xp_pattern = p + 1; 261 return NULL; 262 } 263 else if (STRNICMP(arg, "nargs", p - arg) == 0) 264 { 265 xp->xp_context = EXPAND_USER_NARGS; 266 xp->xp_pattern = p + 1; 267 return NULL; 268 } 269 else if (STRNICMP(arg, "addr", p - arg) == 0) 270 { 271 xp->xp_context = EXPAND_USER_ADDR_TYPE; 272 xp->xp_pattern = p + 1; 273 return NULL; 274 } 275 return NULL; 276 } 277 arg = skipwhite(p); 278 } 279 280 // After the attributes comes the new command name 281 p = skiptowhite(arg); 282 if (*p == NUL) 283 { 284 xp->xp_context = EXPAND_USER_COMMANDS; 285 xp->xp_pattern = arg; 286 return NULL; 287 } 288 289 // And finally comes a normal command 290 return skipwhite(p); 291 } 292 293 char_u * 294 get_user_command_name(int idx) 295 { 296 return get_user_commands(NULL, idx - (int)CMD_SIZE); 297 } 298 299 /* 300 * Function given to ExpandGeneric() to obtain the list of user command names. 301 */ 302 char_u * 303 get_user_commands(expand_T *xp UNUSED, int idx) 304 { 305 // In cmdwin, the alternative buffer should be used. 306 buf_T *buf = 307 #ifdef FEAT_CMDWIN 308 (cmdwin_type != 0 && get_cmdline_type() == NUL) ? prevwin->w_buffer : 309 #endif 310 curbuf; 311 312 if (idx < buf->b_ucmds.ga_len) 313 return USER_CMD_GA(&buf->b_ucmds, idx)->uc_name; 314 idx -= buf->b_ucmds.ga_len; 315 if (idx < ucmds.ga_len) 316 return USER_CMD(idx)->uc_name; 317 return NULL; 318 } 319 320 /* 321 * Function given to ExpandGeneric() to obtain the list of user address type 322 * names. 323 */ 324 char_u * 325 get_user_cmd_addr_type(expand_T *xp UNUSED, int idx) 326 { 327 return (char_u *)addr_type_complete[idx].name; 328 } 329 330 /* 331 * Function given to ExpandGeneric() to obtain the list of user command 332 * attributes. 333 */ 334 char_u * 335 get_user_cmd_flags(expand_T *xp UNUSED, int idx) 336 { 337 static char *user_cmd_flags[] = { 338 "addr", "bang", "bar", "buffer", "complete", 339 "count", "nargs", "range", "register" 340 }; 341 342 if (idx >= (int)(sizeof(user_cmd_flags) / sizeof(user_cmd_flags[0]))) 343 return NULL; 344 return (char_u *)user_cmd_flags[idx]; 345 } 346 347 /* 348 * Function given to ExpandGeneric() to obtain the list of values for -nargs. 349 */ 350 char_u * 351 get_user_cmd_nargs(expand_T *xp UNUSED, int idx) 352 { 353 static char *user_cmd_nargs[] = {"0", "1", "*", "?", "+"}; 354 355 if (idx >= (int)(sizeof(user_cmd_nargs) / sizeof(user_cmd_nargs[0]))) 356 return NULL; 357 return (char_u *)user_cmd_nargs[idx]; 358 } 359 360 /* 361 * Function given to ExpandGeneric() to obtain the list of values for 362 * -complete. 363 */ 364 char_u * 365 get_user_cmd_complete(expand_T *xp UNUSED, int idx) 366 { 367 return (char_u *)command_complete[idx].name; 368 } 369 370 int 371 cmdcomplete_str_to_type(char_u *complete_str) 372 { 373 int i; 374 375 for (i = 0; command_complete[i].expand != 0; ++i) 376 if (STRCMP(complete_str, command_complete[i].name) == 0) 377 return command_complete[i].expand; 378 379 return EXPAND_NOTHING; 380 } 381 382 /* 383 * List user commands starting with "name[name_len]". 384 */ 385 static void 386 uc_list(char_u *name, size_t name_len) 387 { 388 int i, j; 389 int found = FALSE; 390 ucmd_T *cmd; 391 int len; 392 int over; 393 long a; 394 garray_T *gap; 395 396 // In cmdwin, the alternative buffer should be used. 397 gap = 398 #ifdef FEAT_CMDWIN 399 (cmdwin_type != 0 && get_cmdline_type() == NUL) ? 400 &prevwin->w_buffer->b_ucmds : 401 #endif 402 &curbuf->b_ucmds; 403 for (;;) 404 { 405 for (i = 0; i < gap->ga_len; ++i) 406 { 407 cmd = USER_CMD_GA(gap, i); 408 a = (long)cmd->uc_argt; 409 410 // Skip commands which don't match the requested prefix and 411 // commands filtered out. 412 if (STRNCMP(name, cmd->uc_name, name_len) != 0 413 || message_filtered(cmd->uc_name)) 414 continue; 415 416 // Put out the title first time 417 if (!found) 418 msg_puts_title(_("\n Name Args Address Complete Definition")); 419 found = TRUE; 420 msg_putchar('\n'); 421 if (got_int) 422 break; 423 424 // Special cases 425 len = 4; 426 if (a & EX_BANG) 427 { 428 msg_putchar('!'); 429 --len; 430 } 431 if (a & EX_REGSTR) 432 { 433 msg_putchar('"'); 434 --len; 435 } 436 if (gap != &ucmds) 437 { 438 msg_putchar('b'); 439 --len; 440 } 441 if (a & EX_TRLBAR) 442 { 443 msg_putchar('|'); 444 --len; 445 } 446 while (len-- > 0) 447 msg_putchar(' '); 448 449 msg_outtrans_attr(cmd->uc_name, HL_ATTR(HLF_D)); 450 len = (int)STRLEN(cmd->uc_name) + 4; 451 452 do { 453 msg_putchar(' '); 454 ++len; 455 } while (len < 22); 456 457 // "over" is how much longer the name is than the column width for 458 // the name, we'll try to align what comes after. 459 over = len - 22; 460 len = 0; 461 462 // Arguments 463 switch ((int)(a & (EX_EXTRA|EX_NOSPC|EX_NEEDARG))) 464 { 465 case 0: IObuff[len++] = '0'; break; 466 case (EX_EXTRA): IObuff[len++] = '*'; break; 467 case (EX_EXTRA|EX_NOSPC): IObuff[len++] = '?'; break; 468 case (EX_EXTRA|EX_NEEDARG): IObuff[len++] = '+'; break; 469 case (EX_EXTRA|EX_NOSPC|EX_NEEDARG): IObuff[len++] = '1'; break; 470 } 471 472 do { 473 IObuff[len++] = ' '; 474 } while (len < 5 - over); 475 476 // Address / Range 477 if (a & (EX_RANGE|EX_COUNT)) 478 { 479 if (a & EX_COUNT) 480 { 481 // -count=N 482 sprintf((char *)IObuff + len, "%ldc", cmd->uc_def); 483 len += (int)STRLEN(IObuff + len); 484 } 485 else if (a & EX_DFLALL) 486 IObuff[len++] = '%'; 487 else if (cmd->uc_def >= 0) 488 { 489 // -range=N 490 sprintf((char *)IObuff + len, "%ld", cmd->uc_def); 491 len += (int)STRLEN(IObuff + len); 492 } 493 else 494 IObuff[len++] = '.'; 495 } 496 497 do { 498 IObuff[len++] = ' '; 499 } while (len < 8 - over); 500 501 // Address Type 502 for (j = 0; addr_type_complete[j].expand != ADDR_NONE; ++j) 503 if (addr_type_complete[j].expand != ADDR_LINES 504 && addr_type_complete[j].expand == cmd->uc_addr_type) 505 { 506 STRCPY(IObuff + len, addr_type_complete[j].shortname); 507 len += (int)STRLEN(IObuff + len); 508 break; 509 } 510 511 do { 512 IObuff[len++] = ' '; 513 } while (len < 13 - over); 514 515 // Completion 516 for (j = 0; command_complete[j].expand != 0; ++j) 517 if (command_complete[j].expand == cmd->uc_compl) 518 { 519 STRCPY(IObuff + len, command_complete[j].name); 520 len += (int)STRLEN(IObuff + len); 521 break; 522 } 523 524 do { 525 IObuff[len++] = ' '; 526 } while (len < 25 - over); 527 528 IObuff[len] = '\0'; 529 msg_outtrans(IObuff); 530 531 msg_outtrans_special(cmd->uc_rep, FALSE, 532 name_len == 0 ? Columns - 47 : 0); 533 #ifdef FEAT_EVAL 534 if (p_verbose > 0) 535 last_set_msg(cmd->uc_script_ctx); 536 #endif 537 out_flush(); 538 ui_breakcheck(); 539 if (got_int) 540 break; 541 } 542 if (gap == &ucmds || i < gap->ga_len) 543 break; 544 gap = &ucmds; 545 } 546 547 if (!found) 548 msg(_("No user-defined commands found")); 549 } 550 551 char * 552 uc_fun_cmd(void) 553 { 554 static char_u fcmd[] = {0x84, 0xaf, 0x60, 0xb9, 0xaf, 0xb5, 0x60, 0xa4, 555 0xa5, 0xad, 0xa1, 0xae, 0xa4, 0x60, 0xa1, 0x60, 556 0xb3, 0xa8, 0xb2, 0xb5, 0xa2, 0xa2, 0xa5, 0xb2, 557 0xb9, 0x7f, 0}; 558 int i; 559 560 for (i = 0; fcmd[i]; ++i) 561 IObuff[i] = fcmd[i] - 0x40; 562 IObuff[i] = 0; 563 return (char *)IObuff; 564 } 565 566 /* 567 * Parse address type argument 568 */ 569 static int 570 parse_addr_type_arg( 571 char_u *value, 572 int vallen, 573 cmd_addr_T *addr_type_arg) 574 { 575 int i, a, b; 576 577 for (i = 0; addr_type_complete[i].expand != ADDR_NONE; ++i) 578 { 579 a = (int)STRLEN(addr_type_complete[i].name) == vallen; 580 b = STRNCMP(value, addr_type_complete[i].name, vallen) == 0; 581 if (a && b) 582 { 583 *addr_type_arg = addr_type_complete[i].expand; 584 break; 585 } 586 } 587 588 if (addr_type_complete[i].expand == ADDR_NONE) 589 { 590 char_u *err = value; 591 592 for (i = 0; err[i] != NUL && !VIM_ISWHITE(err[i]); i++) 593 ; 594 err[i] = NUL; 595 semsg(_("E180: Invalid address type value: %s"), err); 596 return FAIL; 597 } 598 599 return OK; 600 } 601 602 /* 603 * Parse a completion argument "value[vallen]". 604 * The detected completion goes in "*complp", argument type in "*argt". 605 * When there is an argument, for function and user defined completion, it's 606 * copied to allocated memory and stored in "*compl_arg". 607 * Returns FAIL if something is wrong. 608 */ 609 int 610 parse_compl_arg( 611 char_u *value, 612 int vallen, 613 int *complp, 614 long *argt, 615 char_u **compl_arg UNUSED) 616 { 617 char_u *arg = NULL; 618 # if defined(FEAT_EVAL) 619 size_t arglen = 0; 620 # endif 621 int i; 622 int valend = vallen; 623 624 // Look for any argument part - which is the part after any ',' 625 for (i = 0; i < vallen; ++i) 626 { 627 if (value[i] == ',') 628 { 629 arg = &value[i + 1]; 630 # if defined(FEAT_EVAL) 631 arglen = vallen - i - 1; 632 # endif 633 valend = i; 634 break; 635 } 636 } 637 638 for (i = 0; command_complete[i].expand != 0; ++i) 639 { 640 if ((int)STRLEN(command_complete[i].name) == valend 641 && STRNCMP(value, command_complete[i].name, valend) == 0) 642 { 643 *complp = command_complete[i].expand; 644 if (command_complete[i].expand == EXPAND_BUFFERS) 645 *argt |= EX_BUFNAME; 646 else if (command_complete[i].expand == EXPAND_DIRECTORIES 647 || command_complete[i].expand == EXPAND_FILES) 648 *argt |= EX_XFILE; 649 break; 650 } 651 } 652 653 if (command_complete[i].expand == 0) 654 { 655 semsg(_("E180: Invalid complete value: %s"), value); 656 return FAIL; 657 } 658 659 # if defined(FEAT_EVAL) 660 if (*complp != EXPAND_USER_DEFINED && *complp != EXPAND_USER_LIST 661 && arg != NULL) 662 # else 663 if (arg != NULL) 664 # endif 665 { 666 emsg(_("E468: Completion argument only allowed for custom completion")); 667 return FAIL; 668 } 669 670 # if defined(FEAT_EVAL) 671 if ((*complp == EXPAND_USER_DEFINED || *complp == EXPAND_USER_LIST) 672 && arg == NULL) 673 { 674 emsg(_("E467: Custom completion requires a function argument")); 675 return FAIL; 676 } 677 678 if (arg != NULL) 679 *compl_arg = vim_strnsave(arg, (int)arglen); 680 # endif 681 return OK; 682 } 683 684 /* 685 * Scan attributes in the ":command" command. 686 * Return FAIL when something is wrong. 687 */ 688 static int 689 uc_scan_attr( 690 char_u *attr, 691 size_t len, 692 long *argt, 693 long *def, 694 int *flags, 695 int *complp, 696 char_u **compl_arg, 697 cmd_addr_T *addr_type_arg) 698 { 699 char_u *p; 700 701 if (len == 0) 702 { 703 emsg(_("E175: No attribute specified")); 704 return FAIL; 705 } 706 707 // First, try the simple attributes (no arguments) 708 if (STRNICMP(attr, "bang", len) == 0) 709 *argt |= EX_BANG; 710 else if (STRNICMP(attr, "buffer", len) == 0) 711 *flags |= UC_BUFFER; 712 else if (STRNICMP(attr, "register", len) == 0) 713 *argt |= EX_REGSTR; 714 else if (STRNICMP(attr, "bar", len) == 0) 715 *argt |= EX_TRLBAR; 716 else 717 { 718 int i; 719 char_u *val = NULL; 720 size_t vallen = 0; 721 size_t attrlen = len; 722 723 // Look for the attribute name - which is the part before any '=' 724 for (i = 0; i < (int)len; ++i) 725 { 726 if (attr[i] == '=') 727 { 728 val = &attr[i + 1]; 729 vallen = len - i - 1; 730 attrlen = i; 731 break; 732 } 733 } 734 735 if (STRNICMP(attr, "nargs", attrlen) == 0) 736 { 737 if (vallen == 1) 738 { 739 if (*val == '0') 740 // Do nothing - this is the default 741 ; 742 else if (*val == '1') 743 *argt |= (EX_EXTRA | EX_NOSPC | EX_NEEDARG); 744 else if (*val == '*') 745 *argt |= EX_EXTRA; 746 else if (*val == '?') 747 *argt |= (EX_EXTRA | EX_NOSPC); 748 else if (*val == '+') 749 *argt |= (EX_EXTRA | EX_NEEDARG); 750 else 751 goto wrong_nargs; 752 } 753 else 754 { 755 wrong_nargs: 756 emsg(_("E176: Invalid number of arguments")); 757 return FAIL; 758 } 759 } 760 else if (STRNICMP(attr, "range", attrlen) == 0) 761 { 762 *argt |= EX_RANGE; 763 if (vallen == 1 && *val == '%') 764 *argt |= EX_DFLALL; 765 else if (val != NULL) 766 { 767 p = val; 768 if (*def >= 0) 769 { 770 two_count: 771 emsg(_("E177: Count cannot be specified twice")); 772 return FAIL; 773 } 774 775 *def = getdigits(&p); 776 *argt |= EX_ZEROR; 777 778 if (p != val + vallen || vallen == 0) 779 { 780 invalid_count: 781 emsg(_("E178: Invalid default value for count")); 782 return FAIL; 783 } 784 } 785 // default for -range is using buffer lines 786 if (*addr_type_arg == ADDR_NONE) 787 *addr_type_arg = ADDR_LINES; 788 } 789 else if (STRNICMP(attr, "count", attrlen) == 0) 790 { 791 *argt |= (EX_COUNT | EX_ZEROR | EX_RANGE); 792 // default for -count is using any number 793 if (*addr_type_arg == ADDR_NONE) 794 *addr_type_arg = ADDR_OTHER; 795 796 if (val != NULL) 797 { 798 p = val; 799 if (*def >= 0) 800 goto two_count; 801 802 *def = getdigits(&p); 803 804 if (p != val + vallen) 805 goto invalid_count; 806 } 807 808 if (*def < 0) 809 *def = 0; 810 } 811 else if (STRNICMP(attr, "complete", attrlen) == 0) 812 { 813 if (val == NULL) 814 { 815 emsg(_("E179: argument required for -complete")); 816 return FAIL; 817 } 818 819 if (parse_compl_arg(val, (int)vallen, complp, argt, compl_arg) 820 == FAIL) 821 return FAIL; 822 } 823 else if (STRNICMP(attr, "addr", attrlen) == 0) 824 { 825 *argt |= EX_RANGE; 826 if (val == NULL) 827 { 828 emsg(_("E179: argument required for -addr")); 829 return FAIL; 830 } 831 if (parse_addr_type_arg(val, (int)vallen, addr_type_arg) == FAIL) 832 return FAIL; 833 if (*addr_type_arg != ADDR_LINES) 834 *argt |= EX_ZEROR; 835 } 836 else 837 { 838 char_u ch = attr[len]; 839 attr[len] = '\0'; 840 semsg(_("E181: Invalid attribute: %s"), attr); 841 attr[len] = ch; 842 return FAIL; 843 } 844 } 845 846 return OK; 847 } 848 849 /* 850 * Add a user command to the list or replace an existing one. 851 */ 852 static int 853 uc_add_command( 854 char_u *name, 855 size_t name_len, 856 char_u *rep, 857 long argt, 858 long def, 859 int flags, 860 int compl, 861 char_u *compl_arg UNUSED, 862 cmd_addr_T addr_type, 863 int force) 864 { 865 ucmd_T *cmd = NULL; 866 char_u *p; 867 int i; 868 int cmp = 1; 869 char_u *rep_buf = NULL; 870 garray_T *gap; 871 872 replace_termcodes(rep, &rep_buf, 0, NULL); 873 if (rep_buf == NULL) 874 { 875 // Can't replace termcodes - try using the string as is 876 rep_buf = vim_strsave(rep); 877 878 // Give up if out of memory 879 if (rep_buf == NULL) 880 return FAIL; 881 } 882 883 // get address of growarray: global or in curbuf 884 if (flags & UC_BUFFER) 885 { 886 gap = &curbuf->b_ucmds; 887 if (gap->ga_itemsize == 0) 888 ga_init2(gap, (int)sizeof(ucmd_T), 4); 889 } 890 else 891 gap = &ucmds; 892 893 // Search for the command in the already defined commands. 894 for (i = 0; i < gap->ga_len; ++i) 895 { 896 size_t len; 897 898 cmd = USER_CMD_GA(gap, i); 899 len = STRLEN(cmd->uc_name); 900 cmp = STRNCMP(name, cmd->uc_name, name_len); 901 if (cmp == 0) 902 { 903 if (name_len < len) 904 cmp = -1; 905 else if (name_len > len) 906 cmp = 1; 907 } 908 909 if (cmp == 0) 910 { 911 // Command can be replaced with "command!" and when sourcing the 912 // same script again, but only once. 913 if (!force 914 #ifdef FEAT_EVAL 915 && (cmd->uc_script_ctx.sc_sid != current_sctx.sc_sid 916 || cmd->uc_script_ctx.sc_seq == current_sctx.sc_seq) 917 #endif 918 ) 919 { 920 semsg(_("E174: Command already exists: add ! to replace it: %s"), 921 name); 922 goto fail; 923 } 924 925 VIM_CLEAR(cmd->uc_rep); 926 #if defined(FEAT_EVAL) 927 VIM_CLEAR(cmd->uc_compl_arg); 928 #endif 929 break; 930 } 931 932 // Stop as soon as we pass the name to add 933 if (cmp < 0) 934 break; 935 } 936 937 // Extend the array unless we're replacing an existing command 938 if (cmp != 0) 939 { 940 if (ga_grow(gap, 1) != OK) 941 goto fail; 942 if ((p = vim_strnsave(name, (int)name_len)) == NULL) 943 goto fail; 944 945 cmd = USER_CMD_GA(gap, i); 946 mch_memmove(cmd + 1, cmd, (gap->ga_len - i) * sizeof(ucmd_T)); 947 948 ++gap->ga_len; 949 950 cmd->uc_name = p; 951 } 952 953 cmd->uc_rep = rep_buf; 954 cmd->uc_argt = argt; 955 cmd->uc_def = def; 956 cmd->uc_compl = compl; 957 #ifdef FEAT_EVAL 958 cmd->uc_script_ctx = current_sctx; 959 cmd->uc_script_ctx.sc_lnum += SOURCING_LNUM; 960 cmd->uc_compl_arg = compl_arg; 961 #endif 962 cmd->uc_addr_type = addr_type; 963 964 return OK; 965 966 fail: 967 vim_free(rep_buf); 968 #if defined(FEAT_EVAL) 969 vim_free(compl_arg); 970 #endif 971 return FAIL; 972 } 973 974 /* 975 * ":command ..." implementation 976 */ 977 void 978 ex_command(exarg_T *eap) 979 { 980 char_u *name; 981 char_u *end; 982 char_u *p; 983 long argt = 0; 984 long def = -1; 985 int flags = 0; 986 int compl = EXPAND_NOTHING; 987 char_u *compl_arg = NULL; 988 cmd_addr_T addr_type_arg = ADDR_NONE; 989 int has_attr = (eap->arg[0] == '-'); 990 int name_len; 991 992 p = eap->arg; 993 994 // Check for attributes 995 while (*p == '-') 996 { 997 ++p; 998 end = skiptowhite(p); 999 if (uc_scan_attr(p, end - p, &argt, &def, &flags, &compl, 1000 &compl_arg, &addr_type_arg) == FAIL) 1001 return; 1002 p = skipwhite(end); 1003 } 1004 1005 // Get the name (if any) and skip to the following argument 1006 name = p; 1007 if (ASCII_ISALPHA(*p)) 1008 while (ASCII_ISALNUM(*p)) 1009 ++p; 1010 if (!ends_excmd(*p) && !VIM_ISWHITE(*p)) 1011 { 1012 emsg(_("E182: Invalid command name")); 1013 return; 1014 } 1015 end = p; 1016 name_len = (int)(end - name); 1017 1018 // If there is nothing after the name, and no attributes were specified, 1019 // we are listing commands 1020 p = skipwhite(end); 1021 if (!has_attr && ends_excmd(*p)) 1022 { 1023 uc_list(name, end - name); 1024 } 1025 else if (!ASCII_ISUPPER(*name)) 1026 { 1027 emsg(_("E183: User defined commands must start with an uppercase letter")); 1028 return; 1029 } 1030 else if ((name_len == 1 && *name == 'X') 1031 || (name_len <= 4 1032 && STRNCMP(name, "Next", name_len > 4 ? 4 : name_len) == 0)) 1033 { 1034 emsg(_("E841: Reserved name, cannot be used for user defined command")); 1035 return; 1036 } 1037 else 1038 uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg, 1039 addr_type_arg, eap->forceit); 1040 } 1041 1042 /* 1043 * ":comclear" implementation 1044 * Clear all user commands, global and for current buffer. 1045 */ 1046 void 1047 ex_comclear(exarg_T *eap UNUSED) 1048 { 1049 uc_clear(&ucmds); 1050 if (curbuf != NULL) 1051 uc_clear(&curbuf->b_ucmds); 1052 } 1053 1054 /* 1055 * Clear all user commands for "gap". 1056 */ 1057 void 1058 uc_clear(garray_T *gap) 1059 { 1060 int i; 1061 ucmd_T *cmd; 1062 1063 for (i = 0; i < gap->ga_len; ++i) 1064 { 1065 cmd = USER_CMD_GA(gap, i); 1066 vim_free(cmd->uc_name); 1067 vim_free(cmd->uc_rep); 1068 # if defined(FEAT_EVAL) 1069 vim_free(cmd->uc_compl_arg); 1070 # endif 1071 } 1072 ga_clear(gap); 1073 } 1074 1075 /* 1076 * ":delcommand" implementation 1077 */ 1078 void 1079 ex_delcommand(exarg_T *eap) 1080 { 1081 int i = 0; 1082 ucmd_T *cmd = NULL; 1083 int cmp = -1; 1084 garray_T *gap; 1085 1086 gap = &curbuf->b_ucmds; 1087 for (;;) 1088 { 1089 for (i = 0; i < gap->ga_len; ++i) 1090 { 1091 cmd = USER_CMD_GA(gap, i); 1092 cmp = STRCMP(eap->arg, cmd->uc_name); 1093 if (cmp <= 0) 1094 break; 1095 } 1096 if (gap == &ucmds || cmp == 0) 1097 break; 1098 gap = &ucmds; 1099 } 1100 1101 if (cmp != 0) 1102 { 1103 semsg(_("E184: No such user-defined command: %s"), eap->arg); 1104 return; 1105 } 1106 1107 vim_free(cmd->uc_name); 1108 vim_free(cmd->uc_rep); 1109 # if defined(FEAT_EVAL) 1110 vim_free(cmd->uc_compl_arg); 1111 # endif 1112 1113 --gap->ga_len; 1114 1115 if (i < gap->ga_len) 1116 mch_memmove(cmd, cmd + 1, (gap->ga_len - i) * sizeof(ucmd_T)); 1117 } 1118 1119 /* 1120 * Split and quote args for <f-args>. 1121 */ 1122 static char_u * 1123 uc_split_args(char_u *arg, size_t *lenp) 1124 { 1125 char_u *buf; 1126 char_u *p; 1127 char_u *q; 1128 int len; 1129 1130 // Precalculate length 1131 p = arg; 1132 len = 2; // Initial and final quotes 1133 1134 while (*p) 1135 { 1136 if (p[0] == '\\' && p[1] == '\\') 1137 { 1138 len += 2; 1139 p += 2; 1140 } 1141 else if (p[0] == '\\' && VIM_ISWHITE(p[1])) 1142 { 1143 len += 1; 1144 p += 2; 1145 } 1146 else if (*p == '\\' || *p == '"') 1147 { 1148 len += 2; 1149 p += 1; 1150 } 1151 else if (VIM_ISWHITE(*p)) 1152 { 1153 p = skipwhite(p); 1154 if (*p == NUL) 1155 break; 1156 len += 3; // "," 1157 } 1158 else 1159 { 1160 int charlen = (*mb_ptr2len)(p); 1161 1162 len += charlen; 1163 p += charlen; 1164 } 1165 } 1166 1167 buf = alloc(len + 1); 1168 if (buf == NULL) 1169 { 1170 *lenp = 0; 1171 return buf; 1172 } 1173 1174 p = arg; 1175 q = buf; 1176 *q++ = '"'; 1177 while (*p) 1178 { 1179 if (p[0] == '\\' && p[1] == '\\') 1180 { 1181 *q++ = '\\'; 1182 *q++ = '\\'; 1183 p += 2; 1184 } 1185 else if (p[0] == '\\' && VIM_ISWHITE(p[1])) 1186 { 1187 *q++ = p[1]; 1188 p += 2; 1189 } 1190 else if (*p == '\\' || *p == '"') 1191 { 1192 *q++ = '\\'; 1193 *q++ = *p++; 1194 } 1195 else if (VIM_ISWHITE(*p)) 1196 { 1197 p = skipwhite(p); 1198 if (*p == NUL) 1199 break; 1200 *q++ = '"'; 1201 *q++ = ','; 1202 *q++ = '"'; 1203 } 1204 else 1205 { 1206 MB_COPY_CHAR(p, q); 1207 } 1208 } 1209 *q++ = '"'; 1210 *q = 0; 1211 1212 *lenp = len; 1213 return buf; 1214 } 1215 1216 static size_t 1217 add_cmd_modifier(char_u *buf, char *mod_str, int *multi_mods) 1218 { 1219 size_t result; 1220 1221 result = STRLEN(mod_str); 1222 if (*multi_mods) 1223 result += 1; 1224 if (buf != NULL) 1225 { 1226 if (*multi_mods) 1227 STRCAT(buf, " "); 1228 STRCAT(buf, mod_str); 1229 } 1230 1231 *multi_mods = 1; 1232 1233 return result; 1234 } 1235 1236 /* 1237 * Check for a <> code in a user command. 1238 * "code" points to the '<'. "len" the length of the <> (inclusive). 1239 * "buf" is where the result is to be added. 1240 * "split_buf" points to a buffer used for splitting, caller should free it. 1241 * "split_len" is the length of what "split_buf" contains. 1242 * Returns the length of the replacement, which has been added to "buf". 1243 * Returns -1 if there was no match, and only the "<" has been copied. 1244 */ 1245 static size_t 1246 uc_check_code( 1247 char_u *code, 1248 size_t len, 1249 char_u *buf, 1250 ucmd_T *cmd, // the user command we're expanding 1251 exarg_T *eap, // ex arguments 1252 char_u **split_buf, 1253 size_t *split_len) 1254 { 1255 size_t result = 0; 1256 char_u *p = code + 1; 1257 size_t l = len - 2; 1258 int quote = 0; 1259 enum { 1260 ct_ARGS, 1261 ct_BANG, 1262 ct_COUNT, 1263 ct_LINE1, 1264 ct_LINE2, 1265 ct_RANGE, 1266 ct_MODS, 1267 ct_REGISTER, 1268 ct_LT, 1269 ct_NONE 1270 } type = ct_NONE; 1271 1272 if ((vim_strchr((char_u *)"qQfF", *p) != NULL) && p[1] == '-') 1273 { 1274 quote = (*p == 'q' || *p == 'Q') ? 1 : 2; 1275 p += 2; 1276 l -= 2; 1277 } 1278 1279 ++l; 1280 if (l <= 1) 1281 type = ct_NONE; 1282 else if (STRNICMP(p, "args>", l) == 0) 1283 type = ct_ARGS; 1284 else if (STRNICMP(p, "bang>", l) == 0) 1285 type = ct_BANG; 1286 else if (STRNICMP(p, "count>", l) == 0) 1287 type = ct_COUNT; 1288 else if (STRNICMP(p, "line1>", l) == 0) 1289 type = ct_LINE1; 1290 else if (STRNICMP(p, "line2>", l) == 0) 1291 type = ct_LINE2; 1292 else if (STRNICMP(p, "range>", l) == 0) 1293 type = ct_RANGE; 1294 else if (STRNICMP(p, "lt>", l) == 0) 1295 type = ct_LT; 1296 else if (STRNICMP(p, "reg>", l) == 0 || STRNICMP(p, "register>", l) == 0) 1297 type = ct_REGISTER; 1298 else if (STRNICMP(p, "mods>", l) == 0) 1299 type = ct_MODS; 1300 1301 switch (type) 1302 { 1303 case ct_ARGS: 1304 // Simple case first 1305 if (*eap->arg == NUL) 1306 { 1307 if (quote == 1) 1308 { 1309 result = 2; 1310 if (buf != NULL) 1311 STRCPY(buf, "''"); 1312 } 1313 else 1314 result = 0; 1315 break; 1316 } 1317 1318 // When specified there is a single argument don't split it. 1319 // Works for ":Cmd %" when % is "a b c". 1320 if ((eap->argt & EX_NOSPC) && quote == 2) 1321 quote = 1; 1322 1323 switch (quote) 1324 { 1325 case 0: // No quoting, no splitting 1326 result = STRLEN(eap->arg); 1327 if (buf != NULL) 1328 STRCPY(buf, eap->arg); 1329 break; 1330 case 1: // Quote, but don't split 1331 result = STRLEN(eap->arg) + 2; 1332 for (p = eap->arg; *p; ++p) 1333 { 1334 if (enc_dbcs != 0 && (*mb_ptr2len)(p) == 2) 1335 // DBCS can contain \ in a trail byte, skip the 1336 // double-byte character. 1337 ++p; 1338 else 1339 if (*p == '\\' || *p == '"') 1340 ++result; 1341 } 1342 1343 if (buf != NULL) 1344 { 1345 *buf++ = '"'; 1346 for (p = eap->arg; *p; ++p) 1347 { 1348 if (enc_dbcs != 0 && (*mb_ptr2len)(p) == 2) 1349 // DBCS can contain \ in a trail byte, copy the 1350 // double-byte character to avoid escaping. 1351 *buf++ = *p++; 1352 else 1353 if (*p == '\\' || *p == '"') 1354 *buf++ = '\\'; 1355 *buf++ = *p; 1356 } 1357 *buf = '"'; 1358 } 1359 1360 break; 1361 case 2: // Quote and split (<f-args>) 1362 // This is hard, so only do it once, and cache the result 1363 if (*split_buf == NULL) 1364 *split_buf = uc_split_args(eap->arg, split_len); 1365 1366 result = *split_len; 1367 if (buf != NULL && result != 0) 1368 STRCPY(buf, *split_buf); 1369 1370 break; 1371 } 1372 break; 1373 1374 case ct_BANG: 1375 result = eap->forceit ? 1 : 0; 1376 if (quote) 1377 result += 2; 1378 if (buf != NULL) 1379 { 1380 if (quote) 1381 *buf++ = '"'; 1382 if (eap->forceit) 1383 *buf++ = '!'; 1384 if (quote) 1385 *buf = '"'; 1386 } 1387 break; 1388 1389 case ct_LINE1: 1390 case ct_LINE2: 1391 case ct_RANGE: 1392 case ct_COUNT: 1393 { 1394 char num_buf[20]; 1395 long num = (type == ct_LINE1) ? eap->line1 : 1396 (type == ct_LINE2) ? eap->line2 : 1397 (type == ct_RANGE) ? eap->addr_count : 1398 (eap->addr_count > 0) ? eap->line2 : cmd->uc_def; 1399 size_t num_len; 1400 1401 sprintf(num_buf, "%ld", num); 1402 num_len = STRLEN(num_buf); 1403 result = num_len; 1404 1405 if (quote) 1406 result += 2; 1407 1408 if (buf != NULL) 1409 { 1410 if (quote) 1411 *buf++ = '"'; 1412 STRCPY(buf, num_buf); 1413 buf += num_len; 1414 if (quote) 1415 *buf = '"'; 1416 } 1417 1418 break; 1419 } 1420 1421 case ct_MODS: 1422 { 1423 int multi_mods = 0; 1424 typedef struct { 1425 int *varp; 1426 char *name; 1427 } mod_entry_T; 1428 static mod_entry_T mod_entries[] = { 1429 #ifdef FEAT_BROWSE_CMD 1430 {&cmdmod.browse, "browse"}, 1431 #endif 1432 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 1433 {&cmdmod.confirm, "confirm"}, 1434 #endif 1435 {&cmdmod.hide, "hide"}, 1436 {&cmdmod.keepalt, "keepalt"}, 1437 {&cmdmod.keepjumps, "keepjumps"}, 1438 {&cmdmod.keepmarks, "keepmarks"}, 1439 {&cmdmod.keeppatterns, "keeppatterns"}, 1440 {&cmdmod.lockmarks, "lockmarks"}, 1441 {&cmdmod.noswapfile, "noswapfile"}, 1442 {NULL, NULL} 1443 }; 1444 int i; 1445 1446 result = quote ? 2 : 0; 1447 if (buf != NULL) 1448 { 1449 if (quote) 1450 *buf++ = '"'; 1451 *buf = '\0'; 1452 } 1453 1454 // :aboveleft and :leftabove 1455 if (cmdmod.split & WSP_ABOVE) 1456 result += add_cmd_modifier(buf, "aboveleft", &multi_mods); 1457 // :belowright and :rightbelow 1458 if (cmdmod.split & WSP_BELOW) 1459 result += add_cmd_modifier(buf, "belowright", &multi_mods); 1460 // :botright 1461 if (cmdmod.split & WSP_BOT) 1462 result += add_cmd_modifier(buf, "botright", &multi_mods); 1463 1464 // the modifiers that are simple flags 1465 for (i = 0; mod_entries[i].varp != NULL; ++i) 1466 if (*mod_entries[i].varp) 1467 result += add_cmd_modifier(buf, mod_entries[i].name, 1468 &multi_mods); 1469 1470 // TODO: How to support :noautocmd? 1471 #ifdef HAVE_SANDBOX 1472 // TODO: How to support :sandbox? 1473 #endif 1474 // :silent 1475 if (msg_silent > 0) 1476 result += add_cmd_modifier(buf, 1477 emsg_silent > 0 ? "silent!" : "silent", &multi_mods); 1478 // :tab 1479 if (cmdmod.tab > 0) 1480 result += add_cmd_modifier(buf, "tab", &multi_mods); 1481 // :topleft 1482 if (cmdmod.split & WSP_TOP) 1483 result += add_cmd_modifier(buf, "topleft", &multi_mods); 1484 // TODO: How to support :unsilent? 1485 // :verbose 1486 if (p_verbose > 0) 1487 result += add_cmd_modifier(buf, "verbose", &multi_mods); 1488 // :vertical 1489 if (cmdmod.split & WSP_VERT) 1490 result += add_cmd_modifier(buf, "vertical", &multi_mods); 1491 if (quote && buf != NULL) 1492 { 1493 buf += result - 2; 1494 *buf = '"'; 1495 } 1496 break; 1497 } 1498 1499 case ct_REGISTER: 1500 result = eap->regname ? 1 : 0; 1501 if (quote) 1502 result += 2; 1503 if (buf != NULL) 1504 { 1505 if (quote) 1506 *buf++ = '\''; 1507 if (eap->regname) 1508 *buf++ = eap->regname; 1509 if (quote) 1510 *buf = '\''; 1511 } 1512 break; 1513 1514 case ct_LT: 1515 result = 1; 1516 if (buf != NULL) 1517 *buf = '<'; 1518 break; 1519 1520 default: 1521 // Not recognized: just copy the '<' and return -1. 1522 result = (size_t)-1; 1523 if (buf != NULL) 1524 *buf = '<'; 1525 break; 1526 } 1527 1528 return result; 1529 } 1530 1531 /* 1532 * Execute a user defined command. 1533 */ 1534 void 1535 do_ucmd(exarg_T *eap) 1536 { 1537 char_u *buf; 1538 char_u *p; 1539 char_u *q; 1540 1541 char_u *start; 1542 char_u *end = NULL; 1543 char_u *ksp; 1544 size_t len, totlen; 1545 1546 size_t split_len = 0; 1547 char_u *split_buf = NULL; 1548 ucmd_T *cmd; 1549 #ifdef FEAT_EVAL 1550 sctx_T save_current_sctx = current_sctx; 1551 #endif 1552 1553 if (eap->cmdidx == CMD_USER) 1554 cmd = USER_CMD(eap->useridx); 1555 else 1556 cmd = USER_CMD_GA(&curbuf->b_ucmds, eap->useridx); 1557 1558 /* 1559 * Replace <> in the command by the arguments. 1560 * First round: "buf" is NULL, compute length, allocate "buf". 1561 * Second round: copy result into "buf". 1562 */ 1563 buf = NULL; 1564 for (;;) 1565 { 1566 p = cmd->uc_rep; // source 1567 q = buf; // destination 1568 totlen = 0; 1569 1570 for (;;) 1571 { 1572 start = vim_strchr(p, '<'); 1573 if (start != NULL) 1574 end = vim_strchr(start + 1, '>'); 1575 if (buf != NULL) 1576 { 1577 for (ksp = p; *ksp != NUL && *ksp != K_SPECIAL; ++ksp) 1578 ; 1579 if (*ksp == K_SPECIAL 1580 && (start == NULL || ksp < start || end == NULL) 1581 && ((ksp[1] == KS_SPECIAL && ksp[2] == KE_FILLER) 1582 # ifdef FEAT_GUI 1583 || (ksp[1] == KS_EXTRA && ksp[2] == (int)KE_CSI) 1584 # endif 1585 )) 1586 { 1587 // K_SPECIAL has been put in the buffer as K_SPECIAL 1588 // KS_SPECIAL KE_FILLER, like for mappings, but 1589 // do_cmdline() doesn't handle that, so convert it back. 1590 // Also change K_SPECIAL KS_EXTRA KE_CSI into CSI. 1591 len = ksp - p; 1592 if (len > 0) 1593 { 1594 mch_memmove(q, p, len); 1595 q += len; 1596 } 1597 *q++ = ksp[1] == KS_SPECIAL ? K_SPECIAL : CSI; 1598 p = ksp + 3; 1599 continue; 1600 } 1601 } 1602 1603 // break if no <item> is found 1604 if (start == NULL || end == NULL) 1605 break; 1606 1607 // Include the '>' 1608 ++end; 1609 1610 // Take everything up to the '<' 1611 len = start - p; 1612 if (buf == NULL) 1613 totlen += len; 1614 else 1615 { 1616 mch_memmove(q, p, len); 1617 q += len; 1618 } 1619 1620 len = uc_check_code(start, end - start, q, cmd, eap, 1621 &split_buf, &split_len); 1622 if (len == (size_t)-1) 1623 { 1624 // no match, continue after '<' 1625 p = start + 1; 1626 len = 1; 1627 } 1628 else 1629 p = end; 1630 if (buf == NULL) 1631 totlen += len; 1632 else 1633 q += len; 1634 } 1635 if (buf != NULL) // second time here, finished 1636 { 1637 STRCPY(q, p); 1638 break; 1639 } 1640 1641 totlen += STRLEN(p); // Add on the trailing characters 1642 buf = alloc(totlen + 1); 1643 if (buf == NULL) 1644 { 1645 vim_free(split_buf); 1646 return; 1647 } 1648 } 1649 1650 #ifdef FEAT_EVAL 1651 current_sctx.sc_sid = cmd->uc_script_ctx.sc_sid; 1652 #endif 1653 (void)do_cmdline(buf, eap->getline, eap->cookie, 1654 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED); 1655 #ifdef FEAT_EVAL 1656 current_sctx = save_current_sctx; 1657 #endif 1658 vim_free(buf); 1659 vim_free(split_buf); 1660 } 1661