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