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