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 // In cmdwin, the alternative buffer should be used. 313 buf_T *buf = 314 #ifdef FEAT_CMDWIN 315 (cmdwin_type != 0 && get_cmdline_type() == NUL) ? prevwin->w_buffer : 316 #endif 317 curbuf; 318 319 if (idx < buf->b_ucmds.ga_len) 320 return USER_CMD_GA(&buf->b_ucmds, idx)->uc_name; 321 idx -= buf->b_ucmds.ga_len; 322 if (idx < ucmds.ga_len) 323 return USER_CMD(idx)->uc_name; 324 return NULL; 325 } 326 327 /* 328 * Function given to ExpandGeneric() to obtain the list of user address type 329 * names. 330 */ 331 char_u * 332 get_user_cmd_addr_type(expand_T *xp UNUSED, int idx) 333 { 334 return (char_u *)addr_type_complete[idx].name; 335 } 336 337 /* 338 * Function given to ExpandGeneric() to obtain the list of user command 339 * attributes. 340 */ 341 char_u * 342 get_user_cmd_flags(expand_T *xp UNUSED, int idx) 343 { 344 static char *user_cmd_flags[] = { 345 "addr", "bang", "bar", "buffer", "complete", 346 "count", "nargs", "range", "register" 347 }; 348 349 if (idx >= (int)(sizeof(user_cmd_flags) / sizeof(user_cmd_flags[0]))) 350 return NULL; 351 return (char_u *)user_cmd_flags[idx]; 352 } 353 354 /* 355 * Function given to ExpandGeneric() to obtain the list of values for -nargs. 356 */ 357 char_u * 358 get_user_cmd_nargs(expand_T *xp UNUSED, int idx) 359 { 360 static char *user_cmd_nargs[] = {"0", "1", "*", "?", "+"}; 361 362 if (idx >= (int)(sizeof(user_cmd_nargs) / sizeof(user_cmd_nargs[0]))) 363 return NULL; 364 return (char_u *)user_cmd_nargs[idx]; 365 } 366 367 /* 368 * Function given to ExpandGeneric() to obtain the list of values for 369 * -complete. 370 */ 371 char_u * 372 get_user_cmd_complete(expand_T *xp UNUSED, int idx) 373 { 374 return (char_u *)command_complete[idx].name; 375 } 376 377 int 378 cmdcomplete_str_to_type(char_u *complete_str) 379 { 380 int i; 381 382 for (i = 0; command_complete[i].expand != 0; ++i) 383 if (STRCMP(complete_str, command_complete[i].name) == 0) 384 return command_complete[i].expand; 385 386 return EXPAND_NOTHING; 387 } 388 389 #endif // FEAT_CMDL_COMPL 390 391 /* 392 * List user commands starting with "name[name_len]". 393 */ 394 static void 395 uc_list(char_u *name, size_t name_len) 396 { 397 int i, j; 398 int found = FALSE; 399 ucmd_T *cmd; 400 int len; 401 int over; 402 long a; 403 garray_T *gap; 404 405 /* In cmdwin, the alternative buffer should be used. */ 406 gap = 407 #ifdef FEAT_CMDWIN 408 (cmdwin_type != 0 && get_cmdline_type() == NUL) ? 409 &prevwin->w_buffer->b_ucmds : 410 #endif 411 &curbuf->b_ucmds; 412 for (;;) 413 { 414 for (i = 0; i < gap->ga_len; ++i) 415 { 416 cmd = USER_CMD_GA(gap, i); 417 a = (long)cmd->uc_argt; 418 419 // Skip commands which don't match the requested prefix and 420 // commands filtered out. 421 if (STRNCMP(name, cmd->uc_name, name_len) != 0 422 || message_filtered(cmd->uc_name)) 423 continue; 424 425 // Put out the title first time 426 if (!found) 427 msg_puts_title(_("\n Name Args Address Complete Definition")); 428 found = TRUE; 429 msg_putchar('\n'); 430 if (got_int) 431 break; 432 433 // Special cases 434 len = 4; 435 if (a & EX_BANG) 436 { 437 msg_putchar('!'); 438 --len; 439 } 440 if (a & EX_REGSTR) 441 { 442 msg_putchar('"'); 443 --len; 444 } 445 if (gap != &ucmds) 446 { 447 msg_putchar('b'); 448 --len; 449 } 450 if (a & EX_TRLBAR) 451 { 452 msg_putchar('|'); 453 --len; 454 } 455 while (len-- > 0) 456 msg_putchar(' '); 457 458 msg_outtrans_attr(cmd->uc_name, HL_ATTR(HLF_D)); 459 len = (int)STRLEN(cmd->uc_name) + 4; 460 461 do { 462 msg_putchar(' '); 463 ++len; 464 } while (len < 22); 465 466 // "over" is how much longer the name is than the column width for 467 // the name, we'll try to align what comes after. 468 over = len - 22; 469 len = 0; 470 471 // Arguments 472 switch ((int)(a & (EX_EXTRA|EX_NOSPC|EX_NEEDARG))) 473 { 474 case 0: IObuff[len++] = '0'; break; 475 case (EX_EXTRA): IObuff[len++] = '*'; break; 476 case (EX_EXTRA|EX_NOSPC): IObuff[len++] = '?'; break; 477 case (EX_EXTRA|EX_NEEDARG): IObuff[len++] = '+'; break; 478 case (EX_EXTRA|EX_NOSPC|EX_NEEDARG): IObuff[len++] = '1'; break; 479 } 480 481 do { 482 IObuff[len++] = ' '; 483 } while (len < 5 - over); 484 485 // Address / Range 486 if (a & (EX_RANGE|EX_COUNT)) 487 { 488 if (a & EX_COUNT) 489 { 490 // -count=N 491 sprintf((char *)IObuff + len, "%ldc", cmd->uc_def); 492 len += (int)STRLEN(IObuff + len); 493 } 494 else if (a & EX_DFLALL) 495 IObuff[len++] = '%'; 496 else if (cmd->uc_def >= 0) 497 { 498 // -range=N 499 sprintf((char *)IObuff + len, "%ld", cmd->uc_def); 500 len += (int)STRLEN(IObuff + len); 501 } 502 else 503 IObuff[len++] = '.'; 504 } 505 506 do { 507 IObuff[len++] = ' '; 508 } while (len < 8 - over); 509 510 // Address Type 511 for (j = 0; addr_type_complete[j].expand != ADDR_NONE; ++j) 512 if (addr_type_complete[j].expand != ADDR_LINES 513 && addr_type_complete[j].expand == cmd->uc_addr_type) 514 { 515 STRCPY(IObuff + len, addr_type_complete[j].shortname); 516 len += (int)STRLEN(IObuff + len); 517 break; 518 } 519 520 do { 521 IObuff[len++] = ' '; 522 } while (len < 13 - over); 523 524 // Completion 525 for (j = 0; command_complete[j].expand != 0; ++j) 526 if (command_complete[j].expand == cmd->uc_compl) 527 { 528 STRCPY(IObuff + len, command_complete[j].name); 529 len += (int)STRLEN(IObuff + len); 530 break; 531 } 532 533 do { 534 IObuff[len++] = ' '; 535 } while (len < 25 - over); 536 537 IObuff[len] = '\0'; 538 msg_outtrans(IObuff); 539 540 msg_outtrans_special(cmd->uc_rep, FALSE, 541 name_len == 0 ? Columns - 47 : 0); 542 #ifdef FEAT_EVAL 543 if (p_verbose > 0) 544 last_set_msg(cmd->uc_script_ctx); 545 #endif 546 out_flush(); 547 ui_breakcheck(); 548 if (got_int) 549 break; 550 } 551 if (gap == &ucmds || i < gap->ga_len) 552 break; 553 gap = &ucmds; 554 } 555 556 if (!found) 557 msg(_("No user-defined commands found")); 558 } 559 560 char * 561 uc_fun_cmd(void) 562 { 563 static char_u fcmd[] = {0x84, 0xaf, 0x60, 0xb9, 0xaf, 0xb5, 0x60, 0xa4, 564 0xa5, 0xad, 0xa1, 0xae, 0xa4, 0x60, 0xa1, 0x60, 565 0xb3, 0xa8, 0xb2, 0xb5, 0xa2, 0xa2, 0xa5, 0xb2, 566 0xb9, 0x7f, 0}; 567 int i; 568 569 for (i = 0; fcmd[i]; ++i) 570 IObuff[i] = fcmd[i] - 0x40; 571 IObuff[i] = 0; 572 return (char *)IObuff; 573 } 574 575 /* 576 * Parse address type argument 577 */ 578 static int 579 parse_addr_type_arg( 580 char_u *value, 581 int vallen, 582 cmd_addr_T *addr_type_arg) 583 { 584 int i, a, b; 585 586 for (i = 0; addr_type_complete[i].expand != ADDR_NONE; ++i) 587 { 588 a = (int)STRLEN(addr_type_complete[i].name) == vallen; 589 b = STRNCMP(value, addr_type_complete[i].name, vallen) == 0; 590 if (a && b) 591 { 592 *addr_type_arg = addr_type_complete[i].expand; 593 break; 594 } 595 } 596 597 if (addr_type_complete[i].expand == ADDR_NONE) 598 { 599 char_u *err = value; 600 601 for (i = 0; err[i] != NUL && !VIM_ISWHITE(err[i]); i++) 602 ; 603 err[i] = NUL; 604 semsg(_("E180: Invalid address type value: %s"), err); 605 return FAIL; 606 } 607 608 return OK; 609 } 610 611 /* 612 * Parse a completion argument "value[vallen]". 613 * The detected completion goes in "*complp", argument type in "*argt". 614 * When there is an argument, for function and user defined completion, it's 615 * copied to allocated memory and stored in "*compl_arg". 616 * Returns FAIL if something is wrong. 617 */ 618 int 619 parse_compl_arg( 620 char_u *value, 621 int vallen, 622 int *complp, 623 long *argt, 624 char_u **compl_arg UNUSED) 625 { 626 char_u *arg = NULL; 627 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 628 size_t arglen = 0; 629 # endif 630 int i; 631 int valend = vallen; 632 633 // Look for any argument part - which is the part after any ',' 634 for (i = 0; i < vallen; ++i) 635 { 636 if (value[i] == ',') 637 { 638 arg = &value[i + 1]; 639 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 640 arglen = vallen - i - 1; 641 # endif 642 valend = i; 643 break; 644 } 645 } 646 647 for (i = 0; command_complete[i].expand != 0; ++i) 648 { 649 if ((int)STRLEN(command_complete[i].name) == valend 650 && STRNCMP(value, command_complete[i].name, valend) == 0) 651 { 652 *complp = command_complete[i].expand; 653 if (command_complete[i].expand == EXPAND_BUFFERS) 654 *argt |= EX_BUFNAME; 655 else if (command_complete[i].expand == EXPAND_DIRECTORIES 656 || command_complete[i].expand == EXPAND_FILES) 657 *argt |= EX_XFILE; 658 break; 659 } 660 } 661 662 if (command_complete[i].expand == 0) 663 { 664 semsg(_("E180: Invalid complete value: %s"), value); 665 return FAIL; 666 } 667 668 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 669 if (*complp != EXPAND_USER_DEFINED && *complp != EXPAND_USER_LIST 670 && arg != NULL) 671 # else 672 if (arg != NULL) 673 # endif 674 { 675 emsg(_("E468: Completion argument only allowed for custom completion")); 676 return FAIL; 677 } 678 679 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 680 if ((*complp == EXPAND_USER_DEFINED || *complp == EXPAND_USER_LIST) 681 && arg == NULL) 682 { 683 emsg(_("E467: Custom completion requires a function argument")); 684 return FAIL; 685 } 686 687 if (arg != NULL) 688 *compl_arg = vim_strnsave(arg, (int)arglen); 689 # endif 690 return OK; 691 } 692 693 /* 694 * Scan attributes in the ":command" command. 695 * Return FAIL when something is wrong. 696 */ 697 static int 698 uc_scan_attr( 699 char_u *attr, 700 size_t len, 701 long *argt, 702 long *def, 703 int *flags, 704 int *complp, 705 char_u **compl_arg, 706 cmd_addr_T *addr_type_arg) 707 { 708 char_u *p; 709 710 if (len == 0) 711 { 712 emsg(_("E175: No attribute specified")); 713 return FAIL; 714 } 715 716 // First, try the simple attributes (no arguments) 717 if (STRNICMP(attr, "bang", len) == 0) 718 *argt |= EX_BANG; 719 else if (STRNICMP(attr, "buffer", len) == 0) 720 *flags |= UC_BUFFER; 721 else if (STRNICMP(attr, "register", len) == 0) 722 *argt |= EX_REGSTR; 723 else if (STRNICMP(attr, "bar", len) == 0) 724 *argt |= EX_TRLBAR; 725 else 726 { 727 int i; 728 char_u *val = NULL; 729 size_t vallen = 0; 730 size_t attrlen = len; 731 732 // Look for the attribute name - which is the part before any '=' 733 for (i = 0; i < (int)len; ++i) 734 { 735 if (attr[i] == '=') 736 { 737 val = &attr[i + 1]; 738 vallen = len - i - 1; 739 attrlen = i; 740 break; 741 } 742 } 743 744 if (STRNICMP(attr, "nargs", attrlen) == 0) 745 { 746 if (vallen == 1) 747 { 748 if (*val == '0') 749 // Do nothing - this is the default 750 ; 751 else if (*val == '1') 752 *argt |= (EX_EXTRA | EX_NOSPC | EX_NEEDARG); 753 else if (*val == '*') 754 *argt |= EX_EXTRA; 755 else if (*val == '?') 756 *argt |= (EX_EXTRA | EX_NOSPC); 757 else if (*val == '+') 758 *argt |= (EX_EXTRA | EX_NEEDARG); 759 else 760 goto wrong_nargs; 761 } 762 else 763 { 764 wrong_nargs: 765 emsg(_("E176: Invalid number of arguments")); 766 return FAIL; 767 } 768 } 769 else if (STRNICMP(attr, "range", attrlen) == 0) 770 { 771 *argt |= EX_RANGE; 772 if (vallen == 1 && *val == '%') 773 *argt |= EX_DFLALL; 774 else if (val != NULL) 775 { 776 p = val; 777 if (*def >= 0) 778 { 779 two_count: 780 emsg(_("E177: Count cannot be specified twice")); 781 return FAIL; 782 } 783 784 *def = getdigits(&p); 785 *argt |= EX_ZEROR; 786 787 if (p != val + vallen || vallen == 0) 788 { 789 invalid_count: 790 emsg(_("E178: Invalid default value for count")); 791 return FAIL; 792 } 793 } 794 // default for -range is using buffer lines 795 if (*addr_type_arg == ADDR_NONE) 796 *addr_type_arg = ADDR_LINES; 797 } 798 else if (STRNICMP(attr, "count", attrlen) == 0) 799 { 800 *argt |= (EX_COUNT | EX_ZEROR | EX_RANGE); 801 // default for -count is using any number 802 if (*addr_type_arg == ADDR_NONE) 803 *addr_type_arg = ADDR_OTHER; 804 805 if (val != NULL) 806 { 807 p = val; 808 if (*def >= 0) 809 goto two_count; 810 811 *def = getdigits(&p); 812 813 if (p != val + vallen) 814 goto invalid_count; 815 } 816 817 if (*def < 0) 818 *def = 0; 819 } 820 else if (STRNICMP(attr, "complete", attrlen) == 0) 821 { 822 if (val == NULL) 823 { 824 emsg(_("E179: argument required for -complete")); 825 return FAIL; 826 } 827 828 if (parse_compl_arg(val, (int)vallen, complp, argt, compl_arg) 829 == FAIL) 830 return FAIL; 831 } 832 else if (STRNICMP(attr, "addr", attrlen) == 0) 833 { 834 *argt |= EX_RANGE; 835 if (val == NULL) 836 { 837 emsg(_("E179: argument required for -addr")); 838 return FAIL; 839 } 840 if (parse_addr_type_arg(val, (int)vallen, addr_type_arg) == FAIL) 841 return FAIL; 842 if (*addr_type_arg != ADDR_LINES) 843 *argt |= EX_ZEROR; 844 } 845 else 846 { 847 char_u ch = attr[len]; 848 attr[len] = '\0'; 849 semsg(_("E181: Invalid attribute: %s"), attr); 850 attr[len] = ch; 851 return FAIL; 852 } 853 } 854 855 return OK; 856 } 857 858 /* 859 * Add a user command to the list or replace an existing one. 860 */ 861 static int 862 uc_add_command( 863 char_u *name, 864 size_t name_len, 865 char_u *rep, 866 long argt, 867 long def, 868 int flags, 869 int compl, 870 char_u *compl_arg UNUSED, 871 cmd_addr_T addr_type, 872 int force) 873 { 874 ucmd_T *cmd = NULL; 875 char_u *p; 876 int i; 877 int cmp = 1; 878 char_u *rep_buf = NULL; 879 garray_T *gap; 880 881 replace_termcodes(rep, &rep_buf, FALSE, FALSE, FALSE); 882 if (rep_buf == NULL) 883 { 884 // Can't replace termcodes - try using the string as is 885 rep_buf = vim_strsave(rep); 886 887 // Give up if out of memory 888 if (rep_buf == NULL) 889 return FAIL; 890 } 891 892 // get address of growarray: global or in curbuf 893 if (flags & UC_BUFFER) 894 { 895 gap = &curbuf->b_ucmds; 896 if (gap->ga_itemsize == 0) 897 ga_init2(gap, (int)sizeof(ucmd_T), 4); 898 } 899 else 900 gap = &ucmds; 901 902 // Search for the command in the already defined commands. 903 for (i = 0; i < gap->ga_len; ++i) 904 { 905 size_t len; 906 907 cmd = USER_CMD_GA(gap, i); 908 len = STRLEN(cmd->uc_name); 909 cmp = STRNCMP(name, cmd->uc_name, name_len); 910 if (cmp == 0) 911 { 912 if (name_len < len) 913 cmp = -1; 914 else if (name_len > len) 915 cmp = 1; 916 } 917 918 if (cmp == 0) 919 { 920 // Command can be replaced with "command!" and when sourcing the 921 // same script again, but only once. 922 if (!force 923 #ifdef FEAT_EVAL 924 && (cmd->uc_script_ctx.sc_sid != current_sctx.sc_sid 925 || cmd->uc_script_ctx.sc_seq == current_sctx.sc_seq) 926 #endif 927 ) 928 { 929 semsg(_("E174: Command already exists: add ! to replace it: %s"), 930 name); 931 goto fail; 932 } 933 934 VIM_CLEAR(cmd->uc_rep); 935 #if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 936 VIM_CLEAR(cmd->uc_compl_arg); 937 #endif 938 break; 939 } 940 941 // Stop as soon as we pass the name to add 942 if (cmp < 0) 943 break; 944 } 945 946 // Extend the array unless we're replacing an existing command 947 if (cmp != 0) 948 { 949 if (ga_grow(gap, 1) != OK) 950 goto fail; 951 if ((p = vim_strnsave(name, (int)name_len)) == NULL) 952 goto fail; 953 954 cmd = USER_CMD_GA(gap, i); 955 mch_memmove(cmd + 1, cmd, (gap->ga_len - i) * sizeof(ucmd_T)); 956 957 ++gap->ga_len; 958 959 cmd->uc_name = p; 960 } 961 962 cmd->uc_rep = rep_buf; 963 cmd->uc_argt = argt; 964 cmd->uc_def = def; 965 cmd->uc_compl = compl; 966 #ifdef FEAT_EVAL 967 cmd->uc_script_ctx = current_sctx; 968 cmd->uc_script_ctx.sc_lnum += sourcing_lnum; 969 # ifdef FEAT_CMDL_COMPL 970 cmd->uc_compl_arg = compl_arg; 971 # endif 972 #endif 973 cmd->uc_addr_type = addr_type; 974 975 return OK; 976 977 fail: 978 vim_free(rep_buf); 979 #if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 980 vim_free(compl_arg); 981 #endif 982 return FAIL; 983 } 984 985 /* 986 * ":command ..." implementation 987 */ 988 void 989 ex_command(exarg_T *eap) 990 { 991 char_u *name; 992 char_u *end; 993 char_u *p; 994 long argt = 0; 995 long def = -1; 996 int flags = 0; 997 int compl = EXPAND_NOTHING; 998 char_u *compl_arg = NULL; 999 cmd_addr_T addr_type_arg = ADDR_NONE; 1000 int has_attr = (eap->arg[0] == '-'); 1001 int name_len; 1002 1003 p = eap->arg; 1004 1005 // Check for attributes 1006 while (*p == '-') 1007 { 1008 ++p; 1009 end = skiptowhite(p); 1010 if (uc_scan_attr(p, end - p, &argt, &def, &flags, &compl, 1011 &compl_arg, &addr_type_arg) == FAIL) 1012 return; 1013 p = skipwhite(end); 1014 } 1015 1016 // Get the name (if any) and skip to the following argument 1017 name = p; 1018 if (ASCII_ISALPHA(*p)) 1019 while (ASCII_ISALNUM(*p)) 1020 ++p; 1021 if (!ends_excmd(*p) && !VIM_ISWHITE(*p)) 1022 { 1023 emsg(_("E182: Invalid command name")); 1024 return; 1025 } 1026 end = p; 1027 name_len = (int)(end - name); 1028 1029 // If there is nothing after the name, and no attributes were specified, 1030 // we are listing commands 1031 p = skipwhite(end); 1032 if (!has_attr && ends_excmd(*p)) 1033 { 1034 uc_list(name, end - name); 1035 } 1036 else if (!ASCII_ISUPPER(*name)) 1037 { 1038 emsg(_("E183: User defined commands must start with an uppercase letter")); 1039 return; 1040 } 1041 else if ((name_len == 1 && *name == 'X') 1042 || (name_len <= 4 1043 && STRNCMP(name, "Next", name_len > 4 ? 4 : name_len) == 0)) 1044 { 1045 emsg(_("E841: Reserved name, cannot be used for user defined command")); 1046 return; 1047 } 1048 else 1049 uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg, 1050 addr_type_arg, eap->forceit); 1051 } 1052 1053 /* 1054 * ":comclear" implementation 1055 * Clear all user commands, global and for current buffer. 1056 */ 1057 void 1058 ex_comclear(exarg_T *eap UNUSED) 1059 { 1060 uc_clear(&ucmds); 1061 if (curbuf != NULL) 1062 uc_clear(&curbuf->b_ucmds); 1063 } 1064 1065 /* 1066 * Clear all user commands for "gap". 1067 */ 1068 void 1069 uc_clear(garray_T *gap) 1070 { 1071 int i; 1072 ucmd_T *cmd; 1073 1074 for (i = 0; i < gap->ga_len; ++i) 1075 { 1076 cmd = USER_CMD_GA(gap, i); 1077 vim_free(cmd->uc_name); 1078 vim_free(cmd->uc_rep); 1079 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 1080 vim_free(cmd->uc_compl_arg); 1081 # endif 1082 } 1083 ga_clear(gap); 1084 } 1085 1086 /* 1087 * ":delcommand" implementation 1088 */ 1089 void 1090 ex_delcommand(exarg_T *eap) 1091 { 1092 int i = 0; 1093 ucmd_T *cmd = NULL; 1094 int cmp = -1; 1095 garray_T *gap; 1096 1097 gap = &curbuf->b_ucmds; 1098 for (;;) 1099 { 1100 for (i = 0; i < gap->ga_len; ++i) 1101 { 1102 cmd = USER_CMD_GA(gap, i); 1103 cmp = STRCMP(eap->arg, cmd->uc_name); 1104 if (cmp <= 0) 1105 break; 1106 } 1107 if (gap == &ucmds || cmp == 0) 1108 break; 1109 gap = &ucmds; 1110 } 1111 1112 if (cmp != 0) 1113 { 1114 semsg(_("E184: No such user-defined command: %s"), eap->arg); 1115 return; 1116 } 1117 1118 vim_free(cmd->uc_name); 1119 vim_free(cmd->uc_rep); 1120 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 1121 vim_free(cmd->uc_compl_arg); 1122 # endif 1123 1124 --gap->ga_len; 1125 1126 if (i < gap->ga_len) 1127 mch_memmove(cmd, cmd + 1, (gap->ga_len - i) * sizeof(ucmd_T)); 1128 } 1129 1130 /* 1131 * Split and quote args for <f-args>. 1132 */ 1133 static char_u * 1134 uc_split_args(char_u *arg, size_t *lenp) 1135 { 1136 char_u *buf; 1137 char_u *p; 1138 char_u *q; 1139 int len; 1140 1141 // Precalculate length 1142 p = arg; 1143 len = 2; // Initial and final quotes 1144 1145 while (*p) 1146 { 1147 if (p[0] == '\\' && p[1] == '\\') 1148 { 1149 len += 2; 1150 p += 2; 1151 } 1152 else if (p[0] == '\\' && VIM_ISWHITE(p[1])) 1153 { 1154 len += 1; 1155 p += 2; 1156 } 1157 else if (*p == '\\' || *p == '"') 1158 { 1159 len += 2; 1160 p += 1; 1161 } 1162 else if (VIM_ISWHITE(*p)) 1163 { 1164 p = skipwhite(p); 1165 if (*p == NUL) 1166 break; 1167 len += 3; // "," 1168 } 1169 else 1170 { 1171 int charlen = (*mb_ptr2len)(p); 1172 1173 len += charlen; 1174 p += charlen; 1175 } 1176 } 1177 1178 buf = alloc(len + 1); 1179 if (buf == NULL) 1180 { 1181 *lenp = 0; 1182 return buf; 1183 } 1184 1185 p = arg; 1186 q = buf; 1187 *q++ = '"'; 1188 while (*p) 1189 { 1190 if (p[0] == '\\' && p[1] == '\\') 1191 { 1192 *q++ = '\\'; 1193 *q++ = '\\'; 1194 p += 2; 1195 } 1196 else if (p[0] == '\\' && VIM_ISWHITE(p[1])) 1197 { 1198 *q++ = p[1]; 1199 p += 2; 1200 } 1201 else if (*p == '\\' || *p == '"') 1202 { 1203 *q++ = '\\'; 1204 *q++ = *p++; 1205 } 1206 else if (VIM_ISWHITE(*p)) 1207 { 1208 p = skipwhite(p); 1209 if (*p == NUL) 1210 break; 1211 *q++ = '"'; 1212 *q++ = ','; 1213 *q++ = '"'; 1214 } 1215 else 1216 { 1217 MB_COPY_CHAR(p, q); 1218 } 1219 } 1220 *q++ = '"'; 1221 *q = 0; 1222 1223 *lenp = len; 1224 return buf; 1225 } 1226 1227 static size_t 1228 add_cmd_modifier(char_u *buf, char *mod_str, int *multi_mods) 1229 { 1230 size_t result; 1231 1232 result = STRLEN(mod_str); 1233 if (*multi_mods) 1234 result += 1; 1235 if (buf != NULL) 1236 { 1237 if (*multi_mods) 1238 STRCAT(buf, " "); 1239 STRCAT(buf, mod_str); 1240 } 1241 1242 *multi_mods = 1; 1243 1244 return result; 1245 } 1246 1247 /* 1248 * Check for a <> code in a user command. 1249 * "code" points to the '<'. "len" the length of the <> (inclusive). 1250 * "buf" is where the result is to be added. 1251 * "split_buf" points to a buffer used for splitting, caller should free it. 1252 * "split_len" is the length of what "split_buf" contains. 1253 * Returns the length of the replacement, which has been added to "buf". 1254 * Returns -1 if there was no match, and only the "<" has been copied. 1255 */ 1256 static size_t 1257 uc_check_code( 1258 char_u *code, 1259 size_t len, 1260 char_u *buf, 1261 ucmd_T *cmd, // the user command we're expanding 1262 exarg_T *eap, // ex arguments 1263 char_u **split_buf, 1264 size_t *split_len) 1265 { 1266 size_t result = 0; 1267 char_u *p = code + 1; 1268 size_t l = len - 2; 1269 int quote = 0; 1270 enum { 1271 ct_ARGS, 1272 ct_BANG, 1273 ct_COUNT, 1274 ct_LINE1, 1275 ct_LINE2, 1276 ct_RANGE, 1277 ct_MODS, 1278 ct_REGISTER, 1279 ct_LT, 1280 ct_NONE 1281 } type = ct_NONE; 1282 1283 if ((vim_strchr((char_u *)"qQfF", *p) != NULL) && p[1] == '-') 1284 { 1285 quote = (*p == 'q' || *p == 'Q') ? 1 : 2; 1286 p += 2; 1287 l -= 2; 1288 } 1289 1290 ++l; 1291 if (l <= 1) 1292 type = ct_NONE; 1293 else if (STRNICMP(p, "args>", l) == 0) 1294 type = ct_ARGS; 1295 else if (STRNICMP(p, "bang>", l) == 0) 1296 type = ct_BANG; 1297 else if (STRNICMP(p, "count>", l) == 0) 1298 type = ct_COUNT; 1299 else if (STRNICMP(p, "line1>", l) == 0) 1300 type = ct_LINE1; 1301 else if (STRNICMP(p, "line2>", l) == 0) 1302 type = ct_LINE2; 1303 else if (STRNICMP(p, "range>", l) == 0) 1304 type = ct_RANGE; 1305 else if (STRNICMP(p, "lt>", l) == 0) 1306 type = ct_LT; 1307 else if (STRNICMP(p, "reg>", l) == 0 || STRNICMP(p, "register>", l) == 0) 1308 type = ct_REGISTER; 1309 else if (STRNICMP(p, "mods>", l) == 0) 1310 type = ct_MODS; 1311 1312 switch (type) 1313 { 1314 case ct_ARGS: 1315 // Simple case first 1316 if (*eap->arg == NUL) 1317 { 1318 if (quote == 1) 1319 { 1320 result = 2; 1321 if (buf != NULL) 1322 STRCPY(buf, "''"); 1323 } 1324 else 1325 result = 0; 1326 break; 1327 } 1328 1329 // When specified there is a single argument don't split it. 1330 // Works for ":Cmd %" when % is "a b c". 1331 if ((eap->argt & EX_NOSPC) && quote == 2) 1332 quote = 1; 1333 1334 switch (quote) 1335 { 1336 case 0: // No quoting, no splitting 1337 result = STRLEN(eap->arg); 1338 if (buf != NULL) 1339 STRCPY(buf, eap->arg); 1340 break; 1341 case 1: // Quote, but don't split 1342 result = STRLEN(eap->arg) + 2; 1343 for (p = eap->arg; *p; ++p) 1344 { 1345 if (enc_dbcs != 0 && (*mb_ptr2len)(p) == 2) 1346 // DBCS can contain \ in a trail byte, skip the 1347 // double-byte character. 1348 ++p; 1349 else 1350 if (*p == '\\' || *p == '"') 1351 ++result; 1352 } 1353 1354 if (buf != NULL) 1355 { 1356 *buf++ = '"'; 1357 for (p = eap->arg; *p; ++p) 1358 { 1359 if (enc_dbcs != 0 && (*mb_ptr2len)(p) == 2) 1360 // DBCS can contain \ in a trail byte, copy the 1361 // double-byte character to avoid escaping. 1362 *buf++ = *p++; 1363 else 1364 if (*p == '\\' || *p == '"') 1365 *buf++ = '\\'; 1366 *buf++ = *p; 1367 } 1368 *buf = '"'; 1369 } 1370 1371 break; 1372 case 2: // Quote and split (<f-args>) 1373 // This is hard, so only do it once, and cache the result 1374 if (*split_buf == NULL) 1375 *split_buf = uc_split_args(eap->arg, split_len); 1376 1377 result = *split_len; 1378 if (buf != NULL && result != 0) 1379 STRCPY(buf, *split_buf); 1380 1381 break; 1382 } 1383 break; 1384 1385 case ct_BANG: 1386 result = eap->forceit ? 1 : 0; 1387 if (quote) 1388 result += 2; 1389 if (buf != NULL) 1390 { 1391 if (quote) 1392 *buf++ = '"'; 1393 if (eap->forceit) 1394 *buf++ = '!'; 1395 if (quote) 1396 *buf = '"'; 1397 } 1398 break; 1399 1400 case ct_LINE1: 1401 case ct_LINE2: 1402 case ct_RANGE: 1403 case ct_COUNT: 1404 { 1405 char num_buf[20]; 1406 long num = (type == ct_LINE1) ? eap->line1 : 1407 (type == ct_LINE2) ? eap->line2 : 1408 (type == ct_RANGE) ? eap->addr_count : 1409 (eap->addr_count > 0) ? eap->line2 : cmd->uc_def; 1410 size_t num_len; 1411 1412 sprintf(num_buf, "%ld", num); 1413 num_len = STRLEN(num_buf); 1414 result = num_len; 1415 1416 if (quote) 1417 result += 2; 1418 1419 if (buf != NULL) 1420 { 1421 if (quote) 1422 *buf++ = '"'; 1423 STRCPY(buf, num_buf); 1424 buf += num_len; 1425 if (quote) 1426 *buf = '"'; 1427 } 1428 1429 break; 1430 } 1431 1432 case ct_MODS: 1433 { 1434 int multi_mods = 0; 1435 typedef struct { 1436 int *varp; 1437 char *name; 1438 } mod_entry_T; 1439 static mod_entry_T mod_entries[] = { 1440 #ifdef FEAT_BROWSE_CMD 1441 {&cmdmod.browse, "browse"}, 1442 #endif 1443 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 1444 {&cmdmod.confirm, "confirm"}, 1445 #endif 1446 {&cmdmod.hide, "hide"}, 1447 {&cmdmod.keepalt, "keepalt"}, 1448 {&cmdmod.keepjumps, "keepjumps"}, 1449 {&cmdmod.keepmarks, "keepmarks"}, 1450 {&cmdmod.keeppatterns, "keeppatterns"}, 1451 {&cmdmod.lockmarks, "lockmarks"}, 1452 {&cmdmod.noswapfile, "noswapfile"}, 1453 {NULL, NULL} 1454 }; 1455 int i; 1456 1457 result = quote ? 2 : 0; 1458 if (buf != NULL) 1459 { 1460 if (quote) 1461 *buf++ = '"'; 1462 *buf = '\0'; 1463 } 1464 1465 // :aboveleft and :leftabove 1466 if (cmdmod.split & WSP_ABOVE) 1467 result += add_cmd_modifier(buf, "aboveleft", &multi_mods); 1468 // :belowright and :rightbelow 1469 if (cmdmod.split & WSP_BELOW) 1470 result += add_cmd_modifier(buf, "belowright", &multi_mods); 1471 // :botright 1472 if (cmdmod.split & WSP_BOT) 1473 result += add_cmd_modifier(buf, "botright", &multi_mods); 1474 1475 // the modifiers that are simple flags 1476 for (i = 0; mod_entries[i].varp != NULL; ++i) 1477 if (*mod_entries[i].varp) 1478 result += add_cmd_modifier(buf, mod_entries[i].name, 1479 &multi_mods); 1480 1481 // TODO: How to support :noautocmd? 1482 #ifdef HAVE_SANDBOX 1483 // TODO: How to support :sandbox? 1484 #endif 1485 // :silent 1486 if (msg_silent > 0) 1487 result += add_cmd_modifier(buf, 1488 emsg_silent > 0 ? "silent!" : "silent", &multi_mods); 1489 // :tab 1490 if (cmdmod.tab > 0) 1491 result += add_cmd_modifier(buf, "tab", &multi_mods); 1492 // :topleft 1493 if (cmdmod.split & WSP_TOP) 1494 result += add_cmd_modifier(buf, "topleft", &multi_mods); 1495 // TODO: How to support :unsilent? 1496 // :verbose 1497 if (p_verbose > 0) 1498 result += add_cmd_modifier(buf, "verbose", &multi_mods); 1499 // :vertical 1500 if (cmdmod.split & WSP_VERT) 1501 result += add_cmd_modifier(buf, "vertical", &multi_mods); 1502 if (quote && buf != NULL) 1503 { 1504 buf += result - 2; 1505 *buf = '"'; 1506 } 1507 break; 1508 } 1509 1510 case ct_REGISTER: 1511 result = eap->regname ? 1 : 0; 1512 if (quote) 1513 result += 2; 1514 if (buf != NULL) 1515 { 1516 if (quote) 1517 *buf++ = '\''; 1518 if (eap->regname) 1519 *buf++ = eap->regname; 1520 if (quote) 1521 *buf = '\''; 1522 } 1523 break; 1524 1525 case ct_LT: 1526 result = 1; 1527 if (buf != NULL) 1528 *buf = '<'; 1529 break; 1530 1531 default: 1532 // Not recognized: just copy the '<' and return -1. 1533 result = (size_t)-1; 1534 if (buf != NULL) 1535 *buf = '<'; 1536 break; 1537 } 1538 1539 return result; 1540 } 1541 1542 /* 1543 * Execute a user defined command. 1544 */ 1545 void 1546 do_ucmd(exarg_T *eap) 1547 { 1548 char_u *buf; 1549 char_u *p; 1550 char_u *q; 1551 1552 char_u *start; 1553 char_u *end = NULL; 1554 char_u *ksp; 1555 size_t len, totlen; 1556 1557 size_t split_len = 0; 1558 char_u *split_buf = NULL; 1559 ucmd_T *cmd; 1560 #ifdef FEAT_EVAL 1561 sctx_T save_current_sctx = current_sctx; 1562 #endif 1563 1564 if (eap->cmdidx == CMD_USER) 1565 cmd = USER_CMD(eap->useridx); 1566 else 1567 cmd = USER_CMD_GA(&curbuf->b_ucmds, eap->useridx); 1568 1569 /* 1570 * Replace <> in the command by the arguments. 1571 * First round: "buf" is NULL, compute length, allocate "buf". 1572 * Second round: copy result into "buf". 1573 */ 1574 buf = NULL; 1575 for (;;) 1576 { 1577 p = cmd->uc_rep; // source 1578 q = buf; // destination 1579 totlen = 0; 1580 1581 for (;;) 1582 { 1583 start = vim_strchr(p, '<'); 1584 if (start != NULL) 1585 end = vim_strchr(start + 1, '>'); 1586 if (buf != NULL) 1587 { 1588 for (ksp = p; *ksp != NUL && *ksp != K_SPECIAL; ++ksp) 1589 ; 1590 if (*ksp == K_SPECIAL 1591 && (start == NULL || ksp < start || end == NULL) 1592 && ((ksp[1] == KS_SPECIAL && ksp[2] == KE_FILLER) 1593 # ifdef FEAT_GUI 1594 || (ksp[1] == KS_EXTRA && ksp[2] == (int)KE_CSI) 1595 # endif 1596 )) 1597 { 1598 // K_SPECIAL has been put in the buffer as K_SPECIAL 1599 // KS_SPECIAL KE_FILLER, like for mappings, but 1600 // do_cmdline() doesn't handle that, so convert it back. 1601 // Also change K_SPECIAL KS_EXTRA KE_CSI into CSI. 1602 len = ksp - p; 1603 if (len > 0) 1604 { 1605 mch_memmove(q, p, len); 1606 q += len; 1607 } 1608 *q++ = ksp[1] == KS_SPECIAL ? K_SPECIAL : CSI; 1609 p = ksp + 3; 1610 continue; 1611 } 1612 } 1613 1614 // break if no <item> is found 1615 if (start == NULL || end == NULL) 1616 break; 1617 1618 // Include the '>' 1619 ++end; 1620 1621 // Take everything up to the '<' 1622 len = start - p; 1623 if (buf == NULL) 1624 totlen += len; 1625 else 1626 { 1627 mch_memmove(q, p, len); 1628 q += len; 1629 } 1630 1631 len = uc_check_code(start, end - start, q, cmd, eap, 1632 &split_buf, &split_len); 1633 if (len == (size_t)-1) 1634 { 1635 // no match, continue after '<' 1636 p = start + 1; 1637 len = 1; 1638 } 1639 else 1640 p = end; 1641 if (buf == NULL) 1642 totlen += len; 1643 else 1644 q += len; 1645 } 1646 if (buf != NULL) // second time here, finished 1647 { 1648 STRCPY(q, p); 1649 break; 1650 } 1651 1652 totlen += STRLEN(p); // Add on the trailing characters 1653 buf = alloc(totlen + 1); 1654 if (buf == NULL) 1655 { 1656 vim_free(split_buf); 1657 return; 1658 } 1659 } 1660 1661 #ifdef FEAT_EVAL 1662 current_sctx.sc_sid = cmd->uc_script_ctx.sc_sid; 1663 #endif 1664 (void)do_cmdline(buf, eap->getline, eap->cookie, 1665 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED); 1666 #ifdef FEAT_EVAL 1667 current_sctx = save_current_sctx; 1668 #endif 1669 vim_free(buf); 1670 vim_free(split_buf); 1671 } 1672