diff options
author | Bram Moolenaar <Bram@vim.org> | 2019-04-27 13:04:13 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2019-04-27 13:04:13 +0200 |
commit | ac9fb18020d7e8bf16d02d45fbb02cf47328aaf7 (patch) | |
tree | 439cf73bcd9696032bfe85cd170b0623a9dffa9a /src/ex_docmd.c | |
parent | 5431589d25e73892fcf7ad1eaca53f742c1c9303 (diff) |
patch 8.1.1210: support for user commands is spread outv8.1.1210
Problem: Support for user commands is spread out. No good reason to make
user commands optional.
Solution: Move user command support to usercmd.c. Always enable the
user_commands feature.
Diffstat (limited to 'src/ex_docmd.c')
-rw-r--r-- | src/ex_docmd.c | 1705 |
1 files changed, 23 insertions, 1682 deletions
diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 6b2fe4628e..0086589342 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -19,48 +19,6 @@ static int ex_pressedreturn = FALSE; # define ex_hardcopy ex_ni #endif -#ifdef FEAT_USR_CMDS -typedef struct ucmd -{ - char_u *uc_name; /* The command name */ - long_u uc_argt; /* The argument type */ - char_u *uc_rep; /* The command's replacement string */ - long uc_def; /* The default value for a range/count */ - int uc_compl; /* completion type */ - int uc_addr_type; /* The command's address type */ -# ifdef FEAT_EVAL - sctx_T uc_script_ctx; /* SCTX where the command was defined */ -# ifdef FEAT_CMDL_COMPL - char_u *uc_compl_arg; /* completion argument if any */ -# endif -# endif -} ucmd_T; - -#define UC_BUFFER 1 /* -buffer: local to current buffer */ - -static garray_T ucmds = {0, 0, sizeof(ucmd_T), 4, NULL}; - -#define USER_CMD(i) (&((ucmd_T *)(ucmds.ga_data))[i]) -#define USER_CMD_GA(gap, i) (&((ucmd_T *)((gap)->ga_data))[i]) - -static void do_ucmd(exarg_T *eap); -static void ex_command(exarg_T *eap); -static void ex_delcommand(exarg_T *eap); -# ifdef FEAT_CMDL_COMPL -static char_u *get_user_command_name(int idx); -# endif - -/* Wether a command index indicates a user command. */ -# define IS_USER_CMDIDX(idx) ((int)(idx) < 0) - -#else -# define ex_command ex_ni -# define ex_comclear ex_ni -# define ex_delcommand ex_ni -/* Wether a command index indicates a user command. */ -# define IS_USER_CMDIDX(idx) (FALSE) -#endif - #ifdef FEAT_EVAL static char_u *do_one_cmd(char_u **, int, struct condstack *, char_u *(*fgetline)(int, void *, int), void *cookie); #else @@ -300,10 +258,6 @@ static void ex_redrawtabline(exarg_T *eap); static void close_redir(void); static void ex_mkrc(exarg_T *eap); static void ex_mark(exarg_T *eap); -#ifdef FEAT_USR_CMDS -static char *uc_fun_cmd(void); -static char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int *compl); -#endif static void ex_startinsert(exarg_T *eap); static void ex_stopinsert(exarg_T *eap); #ifdef FEAT_FIND_ID @@ -1929,21 +1883,20 @@ do_one_cmd( ) ? find_command(&ea, NULL) : ea.cmd; } -#ifdef FEAT_USR_CMDS if (p == NULL) { if (!ea.skip) errormsg = _("E464: Ambiguous use of user-defined command"); goto doend; } - /* Check for wrong commands. */ + // Check for wrong commands. if (*p == '!' && ea.cmd[1] == 0151 && ea.cmd[0] == 78 && !IS_USER_CMDIDX(ea.cmdidx)) { errormsg = uc_fun_cmd(); goto doend; } -#endif + if (ea.cmdidx == CMD_SIZE) { if (!ea.skip) @@ -2508,7 +2461,6 @@ do_one_cmd( * 7. Execute the command. */ -#ifdef FEAT_USR_CMDS if (IS_USER_CMDIDX(ea.cmdidx)) { /* @@ -2517,10 +2469,9 @@ do_one_cmd( do_ucmd(&ea); } else -#endif { /* - * Call the function to execute the command. + * Call the function to execute the builtin command. */ ea.errmsg = NULL; (cmdnames[ea.cmdidx].cmd_func)(&ea); @@ -3235,18 +3186,16 @@ find_command(exarg_T *eap, int *full UNUSED) break; } -#ifdef FEAT_USR_CMDS - /* Look for a user defined command as a last resort. Let ":Print" be - * overruled by a user defined command. */ + // Look for a user defined command as a last resort. Let ":Print" be + // overruled by a user defined command. if ((eap->cmdidx == CMD_SIZE || eap->cmdidx == CMD_Print) && *eap->cmd >= 'A' && *eap->cmd <= 'Z') { - /* User defined commands may contain digits. */ + // User defined commands may contain digits. while (ASCII_ISALNUM(*p)) ++p; p = find_ucmd(eap, p, full, NULL, NULL); } -#endif if (p == eap->cmd) eap->cmdidx = CMD_SIZE; } @@ -3254,124 +3203,6 @@ find_command(exarg_T *eap, int *full UNUSED) return p; } -#ifdef FEAT_USR_CMDS -/* - * Search for a user command that matches "eap->cmd". - * Return cmdidx in "eap->cmdidx", flags in "eap->argt", idx in "eap->useridx". - * Return a pointer to just after the command. - * Return NULL if there is no matching command. - */ - static char_u * -find_ucmd( - exarg_T *eap, - char_u *p, /* end of the command (possibly including count) */ - int *full, /* set to TRUE for a full match */ - expand_T *xp, /* used for completion, NULL otherwise */ - int *compl) /* completion flags or NULL */ -{ - int len = (int)(p - eap->cmd); - int j, k, matchlen = 0; - ucmd_T *uc; - int found = FALSE; - int possible = FALSE; - char_u *cp, *np; /* Point into typed cmd and test name */ - garray_T *gap; - int amb_local = FALSE; /* Found ambiguous buffer-local command, - only full match global is accepted. */ - - /* - * Look for buffer-local user commands first, then global ones. - */ - gap = &curbuf->b_ucmds; - for (;;) - { - for (j = 0; j < gap->ga_len; ++j) - { - uc = USER_CMD_GA(gap, j); - cp = eap->cmd; - np = uc->uc_name; - k = 0; - while (k < len && *np != NUL && *cp++ == *np++) - k++; - if (k == len || (*np == NUL && vim_isdigit(eap->cmd[k]))) - { - /* If finding a second match, the command is ambiguous. But - * not if a buffer-local command wasn't a full match and a - * global command is a full match. */ - if (k == len && found && *np != NUL) - { - if (gap == &ucmds) - return NULL; - amb_local = TRUE; - } - - if (!found || (k == len && *np == NUL)) - { - /* If we matched up to a digit, then there could - * be another command including the digit that we - * should use instead. - */ - if (k == len) - found = TRUE; - else - possible = TRUE; - - if (gap == &ucmds) - eap->cmdidx = CMD_USER; - else - eap->cmdidx = CMD_USER_BUF; - eap->argt = (long)uc->uc_argt; - eap->useridx = j; - eap->addr_type = uc->uc_addr_type; - -# ifdef FEAT_CMDL_COMPL - if (compl != NULL) - *compl = uc->uc_compl; -# ifdef FEAT_EVAL - if (xp != NULL) - { - xp->xp_arg = uc->uc_compl_arg; - xp->xp_script_ctx = uc->uc_script_ctx; - xp->xp_script_ctx.sc_lnum += sourcing_lnum; - } -# endif -# endif - /* Do not search for further abbreviations - * if this is an exact match. */ - matchlen = k; - if (k == len && *np == NUL) - { - if (full != NULL) - *full = TRUE; - amb_local = FALSE; - break; - } - } - } - } - - /* Stop if we found a full match or searched all. */ - if (j < gap->ga_len || gap == &ucmds) - break; - gap = &ucmds; - } - - /* Only found ambiguous matches. */ - if (amb_local) - { - if (xp != NULL) - xp->xp_context = EXPAND_UNSUCCESSFUL; - return NULL; - } - - /* The match we found may be followed immediately by a number. Move "p" - * back to point to it. */ - if (found || possible) - return p + (matchlen - len); - return p; -} -#endif - #if defined(FEAT_EVAL) || defined(PROTO) static struct cmdmod { @@ -3483,10 +3314,8 @@ set_one_cmd_context( char_u *cmd, *arg; int len = 0; exarg_T ea; -#if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL) - int compl = EXPAND_NOTHING; -#endif #ifdef FEAT_CMDL_COMPL + int compl = EXPAND_NOTHING; int delim; #endif int forceit = FALSE; @@ -3572,11 +3401,9 @@ set_one_cmd_context( (size_t)len) == 0) break; -#ifdef FEAT_USR_CMDS if (cmd[0] >= 'A' && cmd[0] <= 'Z') - while (ASCII_ISALNUM(*p) || *p == '*') /* Allow * wild card */ + while (ASCII_ISALNUM(*p) || *p == '*') // Allow * wild card ++p; -#endif } /* @@ -3593,21 +3420,19 @@ set_one_cmd_context( ea.cmdidx = CMD_substitute; p = cmd + 1; } -#ifdef FEAT_USR_CMDS else if (cmd[0] >= 'A' && cmd[0] <= 'Z') { ea.cmd = cmd; p = find_ucmd(&ea, p, NULL, xp, -# if defined(FEAT_CMDL_COMPL) +#if defined(FEAT_CMDL_COMPL) &compl -# else +#else NULL -# endif +#endif ); if (p == NULL) - ea.cmdidx = CMD_SIZE; /* ambiguous user command */ + ea.cmdidx = CMD_SIZE; // ambiguous user command } -#endif } if (ea.cmdidx == CMD_SIZE) { @@ -3828,7 +3653,7 @@ set_one_cmd_context( { xp->xp_context = EXPAND_ENV_VARS; ++xp->xp_pattern; -#if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL) +#if defined(FEAT_CMDL_COMPL) /* Avoid that the assignment uses EXPAND_FILES again. */ if (compl != EXPAND_USER_DEFINED && compl != EXPAND_USER_LIST) compl = EXPAND_ENV_VARS; @@ -3944,68 +3769,13 @@ set_one_cmd_context( * All completion for the +cmdline_compl feature goes here. */ -# ifdef FEAT_USR_CMDS case CMD_command: - /* Check for attributes */ - while (*arg == '-') - { - arg++; /* Skip "-" */ - p = skiptowhite(arg); - if (*p == NUL) - { - /* Cursor is still in the attribute */ - p = vim_strchr(arg, '='); - if (p == NULL) - { - /* No "=", so complete attribute names */ - xp->xp_context = EXPAND_USER_CMD_FLAGS; - xp->xp_pattern = arg; - return NULL; - } - - /* For the -complete, -nargs and -addr attributes, we complete - * their arguments as well. - */ - if (STRNICMP(arg, "complete", p - arg) == 0) - { - xp->xp_context = EXPAND_USER_COMPLETE; - xp->xp_pattern = p + 1; - return NULL; - } - else if (STRNICMP(arg, "nargs", p - arg) == 0) - { - xp->xp_context = EXPAND_USER_NARGS; - xp->xp_pattern = p + 1; - return NULL; - } - else if (STRNICMP(arg, "addr", p - arg) == 0) - { - xp->xp_context = EXPAND_USER_ADDR_TYPE; - xp->xp_pattern = p + 1; - return NULL; - } - return NULL; - } - arg = skipwhite(p); - } - - /* After the attributes comes the new command name */ - p = skiptowhite(arg); - if (*p == NUL) - { - xp->xp_context = EXPAND_USER_COMMANDS; - xp->xp_pattern = arg; - break; - } - - /* And finally comes a normal command */ - return skipwhite(p); + return set_context_in_user_cmd(xp, arg); case CMD_delcommand: xp->xp_context = EXPAND_USER_COMMANDS; xp->xp_pattern = arg; break; -# endif case CMD_global: case CMD_vglobal: @@ -4186,32 +3956,32 @@ set_one_cmd_context( xp->xp_context = EXPAND_BUFFERS; xp->xp_pattern = arg; break; -#ifdef FEAT_USR_CMDS + case CMD_USER: case CMD_USER_BUF: if (compl != EXPAND_NOTHING) { - /* XFILE: file names are handled above */ + // XFILE: file names are handled above if (!(ea.argt & XFILE)) { -# ifdef FEAT_MENU +#ifdef FEAT_MENU if (compl == EXPAND_MENUS) return set_context_in_menu_cmd(xp, cmd, arg, forceit); -# endif +#endif if (compl == EXPAND_COMMANDS) return arg; if (compl == EXPAND_MAPPINGS) return set_context_in_map_cmd(xp, (char_u *)"map", arg, forceit, FALSE, FALSE, CMD_map); - /* Find start of last argument. */ + // Find start of last argument. p = arg; while (*p) { if (*p == ' ') - /* argument starts after a space */ + // argument starts after a space arg = p + 1; else if (*p == '\\' && *(p + 1) != NUL) - ++p; /* skip over escaped character */ + ++p; // skip over escaped character MB_PTR_ADV(p); } xp->xp_pattern = arg; @@ -4219,7 +3989,7 @@ set_one_cmd_context( xp->xp_context = compl; } break; -#endif + case CMD_map: case CMD_noremap: case CMD_nmap: case CMD_nnoremap: case CMD_vmap: case CMD_vnoremap: @@ -5771,7 +5541,7 @@ check_more( return OK; } -#ifdef FEAT_CMDL_COMPL +#if defined(FEAT_CMDL_COMPL) || defined(PROTO) /* * Function given to ExpandGeneric() to obtain the list of command names. */ @@ -5779,1440 +5549,11 @@ check_more( get_command_name(expand_T *xp UNUSED, int idx) { if (idx >= (int)CMD_SIZE) -# ifdef FEAT_USR_CMDS return get_user_command_name(idx); -# else - return NULL; -# endif return cmdnames[idx].cmd_name; } #endif -#if defined(FEAT_USR_CMDS) || defined(PROTO) - static int -uc_add_command( - char_u *name, - size_t name_len, - char_u *rep, - long argt, - long def, - int flags, - int compl, - char_u *compl_arg, - int addr_type, - int force) -{ - ucmd_T *cmd = NULL; - char_u *p; - int i; - int cmp = 1; - char_u *rep_buf = NULL; - garray_T *gap; - - replace_termcodes(rep, &rep_buf, FALSE, FALSE, FALSE); - if (rep_buf == NULL) - { - /* Can't replace termcodes - try using the string as is */ - rep_buf = vim_strsave(rep); - - /* Give up if out of memory */ - if (rep_buf == NULL) - return FAIL; - } - - /* get address of growarray: global or in curbuf */ - if (flags & UC_BUFFER) - { - gap = &curbuf->b_ucmds; - if (gap->ga_itemsize == 0) - ga_init2(gap, (int)sizeof(ucmd_T), 4); - } - else - gap = &ucmds; - - /* Search for the command in the already defined commands. */ - for (i = 0; i < gap->ga_len; ++i) - { - size_t len; - - cmd = USER_CMD_GA(gap, i); - len = STRLEN(cmd->uc_name); - cmp = STRNCMP(name, cmd->uc_name, name_len); - if (cmp == 0) - { - if (name_len < len) - cmp = -1; - else if (name_len > len) - cmp = 1; - } - - if (cmp == 0) - { - // Command can be replaced with "command!" and when sourcing the - // same script again, but only once. - if (!force && (cmd->uc_script_ctx.sc_sid != current_sctx.sc_sid - || cmd->uc_script_ctx.sc_seq == current_sctx.sc_seq)) - { - semsg(_("E174: Command already exists: add ! to replace it: %s"), - name); - goto fail; - } - - VIM_CLEAR(cmd->uc_rep); -#if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) - VIM_CLEAR(cmd->uc_compl_arg); -#endif - break; - } - - /* Stop as soon as we pass the name to add */ - if (cmp < 0) - break; - } - - /* Extend the array unless we're replacing an existing command */ - if (cmp != 0) - { - if (ga_grow(gap, 1) != OK) - goto fail; - if ((p = vim_strnsave(name, (int)name_len)) == NULL) - goto fail; - - cmd = USER_CMD_GA(gap, i); - mch_memmove(cmd + 1, cmd, (gap->ga_len - i) * sizeof(ucmd_T)); - - ++gap->ga_len; - - cmd->uc_name = p; - } - - cmd->uc_rep = rep_buf; - cmd->uc_argt = argt; - cmd->uc_def = def; - cmd->uc_compl = compl; -#ifdef FEAT_EVAL - cmd->uc_script_ctx = current_sctx; - cmd->uc_script_ctx.sc_lnum += sourcing_lnum; -# ifdef FEAT_CMDL_COMPL - cmd->uc_compl_arg = compl_arg; -# endif -#endif - cmd->uc_addr_type = addr_type; - - return OK; - -fail: - vim_free(rep_buf); -#if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) - vim_free(compl_arg); -#endif - return FAIL; -} -#endif - -#if defined(FEAT_USR_CMDS) -static struct -{ - int expand; - char *name; - char *shortname; -} addr_type_complete[] = -{ - {ADDR_ARGUMENTS, "arguments", "arg"}, - {ADDR_LINES, "lines", "line"}, - {ADDR_LOADED_BUFFERS, "loaded_buffers", "load"}, - {ADDR_TABS, "tabs", "tab"}, - {ADDR_BUFFERS, "buffers", "buf"}, - {ADDR_WINDOWS, "windows", "win"}, - {ADDR_QUICKFIX, "quickfix", "qf"}, - {ADDR_OTHER, "other", "?"}, - {-1, NULL, NULL} -}; -#endif - -#if defined(FEAT_USR_CMDS) || defined(FEAT_EVAL) || defined(PROTO) -/* - * List of names for completion for ":command" with the EXPAND_ flag. - * Must be alphabetical for completion. - */ -static struct -{ - int expand; - char *name; -} command_complete[] = -{ - {EXPAND_ARGLIST, "arglist"}, - {EXPAND_AUGROUP, "augroup"}, - {EXPAND_BEHAVE, "behave"}, - {EXPAND_BUFFERS, "buffer"}, - {EXPAND_COLORS, "color"}, - {EXPAND_COMMANDS, "command"}, - {EXPAND_COMPILER, "compiler"}, -#if defined(FEAT_CSCOPE) - {EXPAND_CSCOPE, "cscope"}, -#endif -#if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) - {EXPAND_USER_DEFINED, "custom"}, - {EXPAND_USER_LIST, "customlist"}, -#endif - {EXPAND_DIRECTORIES, "dir"}, - {EXPAND_ENV_VARS, "environment"}, - {EXPAND_EVENTS, "event"}, - {EXPAND_EXPRESSION, "expression"}, - {EXPAND_FILES, "file"}, - {EXPAND_FILES_IN_PATH, "file_in_path"}, - {EXPAND_FILETYPE, "filetype"}, - {EXPAND_FUNCTIONS, "function"}, - {EXPAND_HELP, "help"}, - {EXPAND_HIGHLIGHT, "highlight"}, -#if defined(FEAT_CMDHIST) - {EXPAND_HISTORY, "history"}, -#endif -#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) - {EXPAND_LOCALES, "locale"}, -#endif - {EXPAND_MAPCLEAR, "mapclear"}, - {EXPAND_MAPPINGS, "mapping"}, - {EXPAND_MENUS, "menu"}, - {EXPAND_MESSAGES, "messages"}, - {EXPAND_OWNSYNTAX, "syntax"}, -#if defined(FEAT_PROFILE) - {EXPAND_SYNTIME, "syntime"}, -#endif - {EXPAND_SETTINGS, "option"}, - {EXPAND_PACKADD, "packadd"}, - {EXPAND_SHELLCMD, "shellcmd"}, -#if defined(FEAT_SIGNS) - {EXPAND_SIGN, "sign"}, -#endif - {EXPAND_TAGS, "tag"}, - {EXPAND_TAGS_LISTFILES, "tag_listfiles"}, - {EXPAND_USER, "user"}, - {EXPAND_USER_VARS, "var"}, - {0, NULL} -}; -#endif - -#if defined(FEAT_USR_CMDS) || defined(PROTO) - static void -uc_list(char_u *name, size_t name_len) -{ - int i, j; - int found = FALSE; - ucmd_T *cmd; - int len; - int over; - long a; - garray_T *gap; - - gap = &curbuf->b_ucmds; - for (;;) - { - for (i = 0; i < gap->ga_len; ++i) - { - cmd = USER_CMD_GA(gap, i); - a = (long)cmd->uc_argt; - - /* Skip commands which don't match the requested prefix and - * commands filtered out. */ - if (STRNCMP(name, cmd->uc_name, name_len) != 0 - || message_filtered(cmd->uc_name)) - continue; - - /* Put out the title first time */ - if (!found) - msg_puts_title(_("\n Name Args Address Complete Definition")); - found = TRUE; - msg_putchar('\n'); - if (got_int) - break; - - // Special cases - len = 4; - if (a & BANG) - { - msg_putchar('!'); - --len; - } - if (a & REGSTR) - { - msg_putchar('"'); - --len; - } - if (gap != &ucmds) - { - msg_putchar('b'); - --len; - } - if (a & TRLBAR) - { - msg_putchar('|'); - --len; - } - while (len-- > 0) - msg_putchar(' '); - - msg_outtrans_attr(cmd->uc_name, HL_ATTR(HLF_D)); - len = (int)STRLEN(cmd->uc_name) + 4; - - do { - msg_putchar(' '); - ++len; - } while (len < 22); - - // "over" is how much longer the name is than the column width for - // the name, we'll try to align what comes after. - over = len - 22; - len = 0; - - // Arguments - switch ((int)(a & (EXTRA|NOSPC|NEEDARG))) - { - case 0: IObuff[len++] = '0'; break; - case (EXTRA): IObuff[len++] = '*'; break; - case (EXTRA|NOSPC): IObuff[len++] = '?'; break; - case (EXTRA|NEEDARG): IObuff[len++] = '+'; break; - case (EXTRA|NOSPC|NEEDARG): IObuff[len++] = '1'; break; - } - - do { - IObuff[len++] = ' '; - } while (len < 5 - over); - - // Address / Range - if (a & (RANGE|COUNT)) - { - if (a & COUNT) - { - // -count=N - sprintf((char *)IObuff + len, "%ldc", cmd->uc_def); - len += (int)STRLEN(IObuff + len); - } - else if (a & DFLALL) - IObuff[len++] = '%'; - else if (cmd->uc_def >= 0) - { - // -range=N - sprintf((char *)IObuff + len, "%ld", cmd->uc_def); - len += (int)STRLEN(IObuff + len); - } - else - IObuff[len++] = '.'; - } - - do { - IObuff[len++] = ' '; - } while (len < 8 - over); - - // Address Type - for (j = 0; addr_type_complete[j].expand != -1; ++j) - if (addr_type_complete[j].expand != ADDR_LINES - && addr_type_complete[j].expand == cmd->uc_addr_type) - { - STRCPY(IObuff + len, addr_type_complete[j].shortname); - len += (int)STRLEN(IObuff + len); - break; - } - - do { - IObuff[len++] = ' '; - } while (len < 13 - over); - - // Completion - for (j = 0; command_complete[j].expand != 0; ++j) - if (command_complete[j].expand == cmd->uc_compl) - { - STRCPY(IObuff + len, command_complete[j].name); - len += (int)STRLEN(IObuff + len); - break; - } - - do { - IObuff[len++] = ' '; - } while (len < 25 - over); - - IObuff[len] = '\0'; - msg_outtrans(IObuff); - - msg_outtrans_special(cmd->uc_rep, FALSE, - name_len == 0 ? Columns - 47 : 0); -#ifdef FEAT_EVAL - if (p_verbose > 0) - last_set_msg(cmd->uc_script_ctx); -#endif - out_flush(); - ui_breakcheck(); - if (got_int) - break; - } - if (gap == &ucmds || i < gap->ga_len) - break; - gap = &ucmds; - } - - if (!found) - msg(_("No user-defined commands found")); -} - - static char * -uc_fun_cmd(void) -{ - static char_u fcmd[] = {0x84, 0xaf, 0x60, 0xb9, 0xaf, 0xb5, 0x60, 0xa4, - 0xa5, 0xad, 0xa1, 0xae, 0xa4, 0x60, 0xa1, 0x60, - 0xb3, 0xa8, 0xb2, 0xb5, 0xa2, 0xa2, 0xa5, 0xb2, - 0xb9, 0x7f, 0}; - int i; - - for (i = 0; fcmd[i]; ++i) - IObuff[i] = fcmd[i] - 0x40; - IObuff[i] = 0; - return (char *)IObuff; -} - - static int -uc_scan_attr( - char_u *attr, - size_t len, - long *argt, - long *def, - int *flags, - int *compl, - char_u **compl_arg, - int *addr_type_arg) -{ - char_u *p; - - if (len == 0) - { - emsg(_("E175: No attribute specified")); - return FAIL; - } - - /* First, try the simple attributes (no arguments) */ - if (STRNICMP(attr, "bang", len) == 0) - *argt |= BANG; - else if (STRNICMP(attr, "buffer", len) == 0) - *flags |= UC_BUFFER; - else if (STRNICMP(attr, "register", len) == 0) - *argt |= REGSTR; - else if (STRNICMP(attr, "bar", len) == 0) - *argt |= TRLBAR; - else - { - int i; - char_u *val = NULL; - size_t vallen = 0; - size_t attrlen = len; - - /* Look for the attribute name - which is the part before any '=' */ - for (i = 0; i < (int)len; ++i) - { - if (attr[i] == '=') - { - val = &attr[i + 1]; - vallen = len - i - 1; - attrlen = i; - break; - } - } - - if (STRNICMP(attr, "nargs", attrlen) == 0) - { - if (vallen == 1) - { - if (*val == '0') - /* Do nothing - this is the default */; - else if (*val == '1') - *argt |= (EXTRA | NOSPC | NEEDARG); - else if (*val == '*') - *argt |= EXTRA; - else if (*val == '?') - *argt |= (EXTRA | NOSPC); - else if (*val == '+') - *argt |= (EXTRA | NEEDARG); - else - goto wrong_nargs; - } - else - { -wrong_nargs: - emsg(_("E176: Invalid number of arguments")); - return FAIL; - } - } - else if (STRNICMP(attr, "range", attrlen) == 0) - { - *argt |= RANGE; - if (vallen == 1 && *val == '%') - *argt |= DFLALL; - else if (val != NULL) - { - p = val; - if (*def >= 0) - { -two_count: - emsg(_("E177: Count cannot be specified twice")); - return FAIL; - } - - *def = getdigits(&p); - *argt |= (ZEROR | NOTADR); - - if (p != val + vallen || vallen == 0) - { -invalid_count: - emsg(_("E178: Invalid default value for count")); - return FAIL; - } - } - } - else if (STRNICMP(attr, "count", attrlen) == 0) - { - *argt |= (COUNT | ZEROR | RANGE | NOTADR); - - if (val != NULL) - { - p = val; - if (*def >= 0) - goto two_count; - - *def = getdigits(&p); - - if (p != val + vallen) - goto invalid_count; - } - - if (*def < 0) - *def = 0; - } - else if (STRNICMP(attr, "complete", attrlen) == 0) - { - if (val == NULL) - { - emsg(_("E179: argument required for -complete")); - return FAIL; - } - - if (parse_compl_arg(val, (int)vallen, compl, argt, compl_arg) - == FAIL) - return FAIL; - } - else if (STRNICMP(attr, "addr", attrlen) == 0) - { - *argt |= RANGE; - if (val == NULL) - { - emsg(_("E179: argument required for -addr")); - return FAIL; - } - if (parse_addr_type_arg(val, (int)vallen, argt, addr_type_arg) - == FAIL) - return FAIL; - if (addr_type_arg != ADDR_LINES) - *argt |= (ZEROR | NOTADR) ; - } - else - { - char_u ch = attr[len]; - attr[len] = '\0'; - semsg(_("E181: Invalid attribute: %s"), attr); - attr[len] = ch; - return FAIL; - } - } - - return OK; -} - -/* - * ":command ..." - */ - static void -ex_command(exarg_T *eap) -{ - char_u *name; - char_u *end; - char_u *p; - long argt = 0; - long def = -1; - int flags = 0; - int compl = EXPAND_NOTHING; - char_u *compl_arg = NULL; - int addr_type_arg = ADDR_LINES; - int has_attr = (eap->arg[0] == '-'); - int name_len; - - p = eap->arg; - - /* Check for attributes */ - while (*p == '-') - { - ++p; - end = skiptowhite(p); - if (uc_scan_attr(p, end - p, &argt, &def, &flags, &compl, - &compl_arg, &addr_type_arg) - == FAIL) - return; - p = skipwhite(end); - } - - /* Get the name (if any) and skip to the following argument */ - name = p; - if (ASCII_ISALPHA(*p)) - while (ASCII_ISALNUM(*p)) - ++p; - if (!ends_excmd(*p) && !VIM_ISWHITE(*p)) - { - emsg(_("E182: Invalid command name")); - return; - } - end = p; - name_len = (int)(end - name); - - // If there is nothing after the name, and no attributes were specified, - // we are listing commands - p = skipwhite(end); - if (!has_attr && ends_excmd(*p)) - { - uc_list(name, end - name); - } - else if (!ASCII_ISUPPER(*name)) - { - emsg(_("E183: User defined commands must start with an uppercase letter")); - return; - } - else if ((name_len == 1 && *name == 'X') - || (name_len <= 4 - && STRNCMP(name, "Next", name_len > 4 ? 4 : name_len) == 0)) - { - emsg(_("E841: Reserved name, cannot be used for user defined command")); - return; - } - else - uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg, - addr_type_arg, eap->forceit); -} - -/* - * ":comclear" - * Clear all user commands, global and for current buffer. - */ - void -ex_comclear(exarg_T *eap UNUSED) -{ - uc_clear(&ucmds); - uc_clear(&curbuf->b_ucmds); -} - -/* - * Clear all user commands for "gap". - */ - void -uc_clear(garray_T *gap) -{ - int i; - ucmd_T *cmd; - - for (i = 0; i < gap->ga_len; ++i) - { - cmd = USER_CMD_GA(gap, i); - vim_free(cmd->uc_name); - vim_free(cmd->uc_rep); -# if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) - vim_free(cmd->uc_compl_arg); -# endif - } - ga_clear(gap); -} - - static void -ex_delcommand(exarg_T *eap) -{ - int i = 0; - ucmd_T *cmd = NULL; - int cmp = -1; - garray_T *gap; - - gap = &curbuf->b_ucmds; - for (;;) - { - for (i = 0; i < gap->ga_len; ++i) - { - cmd = USER_CMD_GA(gap, i); - cmp = STRCMP(eap->arg, cmd->uc_name); - if (cmp <= 0) - break; - } - if (gap == &ucmds || cmp == 0) - break; - gap = &ucmds; - } - - if (cmp != 0) - { - semsg(_("E184: No such user-defined command: %s"), eap->arg); - return; - } - - vim_free(cmd->uc_name); - vim_free(cmd->uc_rep); -# if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) - vim_free(cmd->uc_compl_arg); -# endif - - --gap->ga_len; - - if (i < gap->ga_len) - mch_memmove(cmd, cmd + 1, (gap->ga_len - i) * sizeof(ucmd_T)); -} - -/* - * split and quote args for <f-args> - */ - static char_u * -uc_split_args(char_u *arg, size_t *lenp) -{ - char_u *buf; - char_u *p; - char_u *q; - int len; - - /* Precalculate length */ - p = arg; - len = 2; /* Initial and final quotes */ - - while (*p) - { - if (p[0] == '\\' && p[1] == '\\') - { - len += 2; - p += 2; - } - else if (p[0] == '\\' && VIM_ISWHITE(p[1])) - { - len += 1; - p += 2; - } - else if (*p == '\\' || *p == '"') - { - len += 2; - p += 1; - } - else if (VIM_ISWHITE(*p)) - { - p = skipwhite(p); - if (*p == NUL) - break; - len += 3; /* "," */ - } - else - { - int charlen = (*mb_ptr2len)(p); - - len += charlen; - p += charlen; - } - } - - buf = alloc(len + 1); - if (buf == NULL) - { - *lenp = 0; - return buf; - } - - p = arg; - q = buf; - *q++ = '"'; - while (*p) - { - if (p[0] == '\\' && p[1] == '\\') - { - *q++ = '\\'; - *q++ = '\\'; - p += 2; - } - else if (p[0] == '\\' && VIM_ISWHITE(p[1])) - { - *q++ = p[1]; - p += 2; - } - else if (*p == '\\' || *p == '"') - { - *q++ = '\\'; - *q++ = *p++; - } - else if (VIM_ISWHITE(*p)) - { - p = skipwhite(p); - if (*p == NUL) - break; - *q++ = '"'; - *q++ = ','; - *q++ = '"'; - } - else - { - MB_COPY_CHAR(p, q); - } - } - *q++ = '"'; - *q = 0; - - *lenp = len; - return buf; -} - - static size_t -add_cmd_modifier(char_u *buf, char *mod_str, int *multi_mods) -{ - size_t result; - - result = STRLEN(mod_str); - if (*multi_mods) - result += 1; - if (buf != NULL) - { - if (*multi_mods) - STRCAT(buf, " "); - STRCAT(buf, mod_str); - } - - *multi_mods = 1; - - return result; -} - -/* - * Check for a <> code in a user command. - * "code" points to the '<'. "len" the length of the <> (inclusive). - * "buf" is where the result is to be added. - * "split_buf" points to a buffer used for splitting, caller should free it. - * "split_len" is the length of what "split_buf" contains. - * Returns the length of the replacement, which has been added to "buf". - * Returns -1 if there was no match, and only the "<" has been copied. - */ - static size_t -uc_check_code( - char_u *code, - size_t len, - char_u *buf, - ucmd_T *cmd, /* the user command we're expanding */ - exarg_T *eap, /* ex arguments */ - char_u **split_buf, - size_t *split_len) -{ - |