diff options
Diffstat (limited to 'data/vim/patches/8.1.1210')
-rw-r--r-- | data/vim/patches/8.1.1210 | 4639 |
1 files changed, 0 insertions, 4639 deletions
diff --git a/data/vim/patches/8.1.1210 b/data/vim/patches/8.1.1210 deleted file mode 100644 index 4405c63ae..000000000 --- a/data/vim/patches/8.1.1210 +++ /dev/null @@ -1,4639 +0,0 @@ -To: vim_dev@googlegroups.com -Subject: Patch 8.1.1210 -Fcc: outbox -From: Bram Moolenaar <Bram@moolenaar.net> -Mime-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit ------------- - -Patch 8.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. -Files: src/usercmd.c, src/proto/usercmd.pro, Filelist, src/Make_bc5.mak, - src/Make_cyg_ming.mak, src/Make_dice.mak, src/Make_ivc.mak, - src/Make_manx.mak, src/Make_morph.mak, src/Make_mvc.mak, - src/Make_sas.mak, src/Make_vms.mms, src/Makefile, src/README.md, - src/buffer.c, src/eval.c, src/evalfunc.c, src/ex_cmds.h, - src/ex_docmd.c, src/proto/ex_docmd.pro, src/ex_getln.c, - src/feature.h, src/macros.h, src/misc2.c, src/proto.h, - src/structs.h, src/version.c, runtime/doc/eval.txt, - runtime/doc/various.txt - - -*** ../vim-8.1.1209/src/usercmd.c 2019-04-27 12:58:18.994395422 +0200 ---- src/usercmd.c 2019-04-27 12:54:00.423836989 +0200 -*************** -*** 0 **** ---- 1,1656 ---- -+ /* vi:set ts=8 sts=4 sw=4 noet: -+ * -+ * VIM - Vi IMproved by Bram Moolenaar -+ * -+ * Do ":help uganda" in Vim to read copying and usage conditions. -+ * Do ":help credits" in Vim to see a list of people who contributed. -+ * See README.txt for an overview of the Vim source code. -+ */ -+ -+ /* -+ * usercmd.c: User defined command support -+ */ -+ -+ #include "vim.h" -+ -+ 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; -+ -+ // List of all user commands. -+ 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]) -+ -+ /* -+ * 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} -+ }; -+ -+ /* -+ * List of names of address types. Must be alphabetical for completion. -+ */ -+ 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} -+ }; -+ -+ #define UC_BUFFER 1 // -buffer: local to current buffer -+ -+ /* -+ * 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. -+ */ -+ 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 UNUSED) // 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; -+ } -+ -+ #if defined(FEAT_CMDL_COMPL) || defined(PROTO) -+ -+ char_u * -+ set_context_in_user_cmd(expand_T *xp, char_u *arg_in) -+ { -+ char_u *arg = arg_in; -+ char_u *p; -+ -+ // 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; -+ return NULL; -+ } -+ -+ // And finally comes a normal command -+ return skipwhite(p); -+ } -+ -+ char_u * -+ get_user_command_name(int idx) -+ { -+ return get_user_commands(NULL, idx - (int)CMD_SIZE); -+ } -+ -+ /* -+ * Function given to ExpandGeneric() to obtain the list of user command names. -+ */ -+ char_u * -+ get_user_commands(expand_T *xp UNUSED, int idx) -+ { -+ if (idx < curbuf->b_ucmds.ga_len) -+ return USER_CMD_GA(&curbuf->b_ucmds, idx)->uc_name; -+ idx -= curbuf->b_ucmds.ga_len; -+ if (idx < ucmds.ga_len) -+ return USER_CMD(idx)->uc_name; -+ return NULL; -+ } -+ -+ /* -+ * Function given to ExpandGeneric() to obtain the list of user address type -+ * names. -+ */ -+ char_u * -+ get_user_cmd_addr_type(expand_T *xp UNUSED, int idx) -+ { -+ return (char_u *)addr_type_complete[idx].name; -+ } -+ -+ /* -+ * Function given to ExpandGeneric() to obtain the list of user command -+ * attributes. -+ */ -+ char_u * -+ get_user_cmd_flags(expand_T *xp UNUSED, int idx) -+ { -+ static char *user_cmd_flags[] = { -+ "addr", "bang", "bar", "buffer", "complete", -+ "count", "nargs", "range", "register" -+ }; -+ -+ if (idx >= (int)(sizeof(user_cmd_flags) / sizeof(user_cmd_flags[0]))) -+ return NULL; -+ return (char_u *)user_cmd_flags[idx]; -+ } -+ -+ /* -+ * Function given to ExpandGeneric() to obtain the list of values for -nargs. -+ */ -+ char_u * -+ get_user_cmd_nargs(expand_T *xp UNUSED, int idx) -+ { -+ static char *user_cmd_nargs[] = {"0", "1", "*", "?", "+"}; -+ -+ if (idx >= (int)(sizeof(user_cmd_nargs) / sizeof(user_cmd_nargs[0]))) -+ return NULL; -+ return (char_u *)user_cmd_nargs[idx]; -+ } -+ -+ /* -+ * Function given to ExpandGeneric() to obtain the list of values for -+ * -complete. -+ */ -+ char_u * -+ get_user_cmd_complete(expand_T *xp UNUSED, int idx) -+ { -+ return (char_u *)command_complete[idx].name; -+ } -+ -+ int -+ cmdcomplete_str_to_type(char_u *complete_str) -+ { -+ int i; -+ -+ for (i = 0; command_complete[i].expand != 0; ++i) -+ if (STRCMP(complete_str, command_complete[i].name) == 0) -+ return command_complete[i].expand; -+ -+ return EXPAND_NOTHING; -+ } -+ -+ #endif // FEAT_CMDL_COMPL -+ -+ /* -+ * List user commands starting with "name[name_len]". -+ */ -+ 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")); -+ } -+ -+ 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; -+ } -+ -+ /* -+ * Parse address type argument -+ */ -+ static int -+ parse_addr_type_arg( -+ char_u *value, -+ int vallen, -+ long *argt, -+ int *addr_type_arg) -+ { -+ int i, a, b; -+ -+ for (i = 0; addr_type_complete[i].expand != -1; ++i) -+ { -+ a = (int)STRLEN(addr_type_complete[i].name) == vallen; -+ b = STRNCMP(value, addr_type_complete[i].name, vallen) == 0; -+ if (a && b) -+ { -+ *addr_type_arg = addr_type_complete[i].expand; -+ break; -+ } -+ } -+ -+ if (addr_type_complete[i].expand == -1) -+ { -+ char_u *err = value; -+ -+ for (i = 0; err[i] != NUL && !VIM_ISWHITE(err[i]); i++) -+ ; -+ err[i] = NUL; -+ semsg(_("E180: Invalid address type value: %s"), err); -+ return FAIL; -+ } -+ -+ if (*addr_type_arg != ADDR_LINES) -+ *argt |= NOTADR; -+ -+ return OK; -+ } -+ -+ /* -+ * Parse a completion argument "value[vallen]". -+ * The detected completion goes in "*complp", argument type in "*argt". -+ * When there is an argument, for function and user defined completion, it's -+ * copied to allocated memory and stored in "*compl_arg". -+ * Returns FAIL if something is wrong. -+ */ -+ int -+ parse_compl_arg( -+ char_u *value, -+ int vallen, -+ int *complp, -+ long *argt, -+ char_u **compl_arg UNUSED) -+ { -+ char_u *arg = NULL; -+ # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) -+ size_t arglen = 0; -+ # endif -+ int i; -+ int valend = vallen; -+ -+ // Look for any argument part - which is the part after any ',' -+ for (i = 0; i < vallen; ++i) -+ { -+ if (value[i] == ',') -+ { -+ arg = &value[i + 1]; -+ # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) -+ arglen = vallen - i - 1; -+ # endif -+ valend = i; -+ break; -+ } -+ } -+ -+ for (i = 0; command_complete[i].expand != 0; ++i) -+ { -+ if ((int)STRLEN(command_complete[i].name) == valend -+ && STRNCMP(value, command_complete[i].name, valend) == 0) -+ { -+ *complp = command_complete[i].expand; -+ if (command_complete[i].expand == EXPAND_BUFFERS) -+ *argt |= BUFNAME; -+ else if (command_complete[i].expand == EXPAND_DIRECTORIES -+ || command_complete[i].expand == EXPAND_FILES) -+ *argt |= XFILE; -+ break; -+ } -+ } -+ -+ if (command_complete[i].expand == 0) -+ { -+ semsg(_("E180: Invalid complete value: %s"), value); -+ return FAIL; -+ } -+ -+ # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) -+ if (*complp != EXPAND_USER_DEFINED && *complp != EXPAND_USER_LIST -+ && arg != NULL) -+ # else -+ if (arg != NULL) -+ # endif -+ { -+ emsg(_("E468: Completion argument only allowed for custom completion")); -+ return FAIL; -+ } -+ -+ # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) -+ if ((*complp == EXPAND_USER_DEFINED || *complp == EXPAND_USER_LIST) -+ && arg == NULL) -+ { -+ emsg(_("E467: Custom completion requires a function argument")); -+ return FAIL; -+ } -+ -+ if (arg != NULL) -+ *compl_arg = vim_strnsave(arg, (int)arglen); -+ # endif -+ return OK; -+ } -+ -+ /* -+ * Scan attributes in the ":command" command. -+ * Return FAIL when something is wrong. -+ */ -+ 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; -+ } -+ -+ /* -+ * Add a user command to the list or replace an existing one. -+ */ -+ 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 UNUSED, -+ 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 -+ #ifdef FEAT_EVAL -+ && (cmd->uc_script_ctx.sc_sid != current_sctx.sc_sid -+ || cmd->uc_script_ctx.sc_seq == current_sctx.sc_seq) -+ #endif -+ ) -+ { -+ 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; -+ } -+ -+ /* -+ * ":command ..." implementation -+ */ -+ 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" implementation -+ * 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); -+ } -+ -+ /* -+ * ":delcommand" implementation -+ */ -+ 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) -+ { -+ size_t result = 0; -+ char_u *p = code + 1; -+ size_t l = len - 2; -+ int quote = 0; -+ enum { -+ ct_ARGS, -+ ct_BANG, -+ ct_COUNT, -+ ct_LINE1, -+ ct_LINE2, -+ ct_RANGE, -+ ct_MODS, -+ ct_REGISTER, -+ ct_LT, -+ ct_NONE -+ } type = ct_NONE; -+ -+ if ((vim_strchr((char_u *)"qQfF", *p) != NULL) && p[1] == '-') -+ { -+ quote = (*p == 'q' || *p == 'Q') ? 1 : 2; -+ p += 2; -+ l -= 2; -+ } -+ -+ ++l; -+ if (l <= 1) -+ type = ct_NONE; -+ else if (STRNICMP(p, "args>", l) == 0) -+ type = ct_ARGS; -+ else if (STRNICMP(p, "bang>", l) == 0) -+ type = ct_BANG; -+ else if (STRNICMP(p, "count>", l) == 0) -+ type = ct_COUNT; -+ else if (STRNICMP(p, "line1>", l) == 0) -+ type = ct_LINE1; -+ else if (STRNICMP(p, "line2>", l) == 0) -+ type = ct_LINE2; -+ else if (STRNICMP(p, "range>", l) == 0) -+ type = ct_RANGE; -+ else if (STRNICMP(p, "lt>", l) == 0) -+ type = ct_LT; -+ else if (STRNICMP(p, "reg>", l) == 0 || STRNICMP(p, "register>", l) == 0) -+ type = ct_REGISTER; -+ else if (STRNICMP(p, "mods>", l) == 0) -+ type = ct_MODS; -+ -+ switch (type) -+ { -+ case ct_ARGS: -+ // Simple case first -+ if (*eap->arg == NUL) -+ { -+ if (quote == 1) -+ { -+ result = 2; -+ if (buf != NULL) -+ STRCPY(buf, "''"); -+ } -+ else -+ result = 0; -+ break; -+ } -+ -+ // When specified there is a single argument don't split it. -+ // Works for ":Cmd %" when % is "a b c". -+ if ((eap->argt & NOSPC) && quote == 2) -+ quote = 1; -+ -+ switch (quote) -+ { -+ case 0: // No quoting, no splitting -+ result = STRLEN(eap->arg); -+ if (buf != NULL) -+ STRCPY(buf, eap->arg); -+ break; -+ case 1: // Quote, but don't split -+ result = STRLEN(eap->arg) + 2; -+ for (p = eap->arg; *p; ++p) -+ { -+ if (enc_dbcs != 0 && (*mb_ptr2len)(p) == 2) -+ // DBCS can contain \ in a trail byte, skip the -+ // double-byte character. -+ ++p; -+ else -+ if (*p == '\\' || *p == '"') -+ ++result; -+ } -+ -+ if (buf != NULL) -+ { -+ *buf++ = '"'; -+ for (p = eap->arg; *p; ++p) -+ { -+ if (enc_dbcs != 0 && (*mb_ptr2len)(p) == 2) -+ // DBCS can contain \ in a trail byte, copy the -+ // double-byte character to avoid escaping. -+ *buf++ = *p++; -+ else -+ if (*p == '\\' || *p == '"') -+ *buf++ = '\\'; -+ *buf++ = *p; -+ } -+ *buf = '"'; -+ } -+ -+ break; -+ case 2: // Quote and split (<f-args>) -+ // This is hard, so only do it once, and cache the result -+ if (*split_buf == NULL) -+ *split_buf = uc_split_args(eap->arg, split_len); -+ -+ result = *split_len; -+ if (buf != NULL && result != 0) -+ STRCPY(buf, *split_buf); -+ -+ break; -+ } -+ break; -+ -+ case ct_BANG: -+ result = eap->forceit ? 1 : 0; -+ if (quote) -+ result += 2; -+ if (buf != NULL) -+ { -+ if (quote) -+ *buf++ = '"'; -+ if (eap->forceit) -+ *buf++ = '!'; -+ if (quote) -+ *buf = '"'; -+ } -+ break; -+ -+ case ct_LINE1: -+ case ct_LINE2: -+ case ct_RANGE: -+ case ct_COUNT: -+ { -+ char num_buf[20]; -+ long num = (type == ct_LINE1) ? eap->line1 : -+ (type == ct_LINE2) ? eap->line2 : -+ (type == ct_RANGE) ? eap->addr_count : -+ (eap->addr_count > 0) ? eap->line2 : cmd->uc_def; -+ size_t num_len; -+ -+ sprintf(num_buf, "%ld", num); -+ num_len = STRLEN(num_buf); -+ result = num_len; -+ -+ if (quote) -+ result += 2; -+ -+ if (buf != NULL) -+ { -+ if (quote) -+ *buf++ = '"'; -+ STRCPY(buf, num_buf); -+ buf += num_len; -+ if (quote) -+ *buf = '"'; -+ } -+ -+ break; -+ } -+ -+ case ct_MODS: -+ { -+ int multi_mods = 0; -+ typedef struct { -+ int *varp; -+ char *name; -+ } mod_entry_T; -+ static mod_entry_T mod_entries[] = { -+ #ifdef FEAT_BROWSE_CMD -+ {&cmdmod.browse, "browse"}, -+ #endif -+ #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) -+ {&cmdmod.confirm, "confirm"}, -+ #endif -+ {&cmdmod.hide, "hide"}, -+ {&cmdmod.keepalt, "keepalt"}, -+ {&cmdmod.keepjumps, "keepjumps"}, -+ {&cmdmod.keepmarks, "keepmarks"}, -+ {&cmdmod.keeppatterns, "keeppatterns"}, -+ {&cmdmod.lockmarks, "lockmarks"}, -+ {&cmdmod.noswapfile, "noswapfile"}, -+ {NULL, NULL} -+ }; -+ int i; -+ -+ result = quote ? 2 : 0; -+ if (buf != NULL) -+ { -+ if (quote) -+ *buf++ = '"'; -+ *buf = '\0'; -+ } -+ -+ // :aboveleft and :leftabove -+ if (cmdmod.split & WSP_ABOVE) -+ result += add_cmd_modifier(buf, "aboveleft", &multi_mods); -+ // :belowright and :rightbelow -+ if (cmdmod.split & WSP_BELOW) -+ result += add_cmd_modifier(buf, "belowright", &multi_mods); -+ // :botright -+ if (cmdmod.split & WSP_BOT) -+ result += add_cmd_modifier(buf, "botright", &multi_mods); -+ -+ // the modifiers that are simple flags -+ for (i = 0; mod_entries[i].varp != NULL; ++i) -+ if (*mod_entries[i].varp) -+ result += add_cmd_modifier(buf, mod_entries[i].name, -+ &multi_mods); -+ -+ // TODO: How to support :noautocmd? -+ #ifdef HAVE_SANDBOX -+ // TODO: How to support :sandbox? -+ #endif -+ // :silent -+ if (msg_silent > 0) -+ result += add_cmd_modifier(buf, -+ emsg_silent > 0 ? "silent!" : "silent", &multi_mods); -+ // :tab -+ if (cmdmod.tab > 0) -+ result += add_cmd_modifier(buf, "tab", &multi_mods); -+ // :topleft -+ if (cmdmod.split & WSP_TOP) -+ result += add_cmd_modifier(buf, "topleft", &multi_mods); -+ // TODO: How to support :unsilent? -+ // :verbose -+ if (p_verbose > 0) -+ result += add_cmd_modifier(buf, "verbose", &multi_mods); -+ // :vertical -+ if (cmdmod.split & WSP_VERT) -+ result += add_cmd_modifier(buf, "vertical", &multi_mods); -+ if (quote && buf != NULL) -+ { -+ buf += result - 2; -+ *buf = '"'; -+ } -+ break; -+ } -+ -+ case ct_REGISTER: -+ result = eap->regname ? 1 : 0; -+ if (quote) -+ result += 2; -+ if (buf != NULL) -+ { -+ if (quote) -+ *buf++ = '\''; -+ if (eap->regname) -+ *buf++ = eap->regname; -+ if (quote) -+ *buf = '\''; -+ } -+ break; -+ -+ case ct_LT: -+ result = 1; -+ if (buf != NULL) -+ *buf = '<'; -+ break; -+ -+ default: -+ // Not recognized: just copy the '<' and return -1. -+ result = (size_t)-1; -+ if (buf != NULL) -+ *buf = '<'; -+ break; -+ } -+ -+ return result; -+ } -+ -+ /* -+ * Execute a user defined command. -+ */ -+ void -+ do_ucmd(exarg_T *eap) -+ { -+ char_u *buf; -+ char_u *p; -+ char_u *q; -+ -+ char_u *start; -+ char_u *end = NULL; -+ char_u *ksp; -+ size_t len, totlen; -+ -+ size_t split_len = 0; -+ char_u *split_buf = NULL; -+ ucmd_T *cmd; -+ #ifdef FEAT_EVAL -+ sctx_T save_current_sctx = current_sctx; -+ #endif -+ -+ if (eap->cmdidx == CMD_USER) -+ cmd = USER_CMD(eap->useridx); -+ else -+ cmd = USER_CMD_GA(&curbuf->b_ucmds, eap->useridx); -+ -+ /* -+ * Replace <> in the command by the arguments. -+ * First round: "buf" is NULL, compute length, allocate "buf". -+ * Second round: copy result into "buf". -+ */ -+ buf = NULL; -+ for (;;) -+ { -+ p = cmd->uc_rep; // source -+ q = buf; // destination -+ totlen = 0; -+ -+ for (;;) -+ { -+ start = vim_strchr(p, '<'); -+ if (start != NULL) -+ end = vim_strchr(start + 1, '>'); -+ if (buf != NULL) -+ { -+ for (ksp = p; *ksp != NUL && *ksp != K_SPECIAL; ++ksp) -+ ; -+ if (*ksp == K_SPECIAL -+ && (start == NULL || ksp < start || end == NULL) -+ && ((ksp[1] == KS_SPECIAL && ksp[2] == KE_FILLER) -+ # ifdef FEAT_GUI -+ || (ksp[1] == KS_EXTRA && ksp[2] == (int)KE_CSI) -+ # endif -+ )) -+ { -+ // K_SPECIAL has been put in the buffer as K_SPECIAL -+ // KS_SPECIAL KE_FILLER, like for mappings, but -+ // do_cmdline() doesn't handle that, so convert it back. -+ // Also change K_SPECIAL KS_EXTRA KE_CSI into CSI. -+ len = ksp - p; -+ if (len > 0) -+ { -+ mch_memmove(q, p, len); -+ q += len; -+ } -+ *q++ = ksp[1] == KS_SPECIAL ? K_SPECIAL : CSI; -+ p = ksp + 3; -+ continue; -+ } -+ } -+ -+ // break if no <item> is found -+ if (start == NULL || end == NULL) -+ break; -+ -+ // Include the '>' -+ ++end; -+ -+ // Take everything up to the '<' -+ len = start - p; -+ if (buf == NULL) -+ totlen += len; -+ else -+ { -+ mch_memmove(q, p, len); -+ q += len; -+ } -+ -+ len = uc_check_code(start, end - start, q, cmd, eap, -+ &split_buf, &split_len); -+ if (len == (size_t)-1) -+ { -+ // no match, continue after '<' -+ p = start + 1; -+ len = 1; -+ } -+ else -+ p = end; -+ if (buf == NULL) -+ totlen += len; -+ else -+ q += len; -+ } -+ if (buf != NULL) // second time here, finished -+ { -+ STRCPY(q, p); -+ break; -+ } -+ -+ totlen += STRLEN(p); // Add on the trailing characters -+ buf = alloc((unsigned)(totlen + 1)); -+ if (buf == NULL) -+ { -+ vim_free(split_buf); -+ return; -+ } -+ } -+ -+ #ifdef FEAT_EVAL -+ current_sctx.sc_sid = cmd->uc_script_ctx.sc_sid; -+ #endif -+ (void)do_cmdline(buf, eap->getline, eap->cookie, -+ DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED); -+ #ifdef FEAT_EVAL -+ current_sctx = save_current_sctx; -+ #endif -+ vim_free(buf); -+ vim_free(split_buf); -+ } -*** ../vim-8.1.1209/src/proto/usercmd.pro 2019-04-27 12:58:18.998395402 +0200 ---- src/proto/usercmd.pro 2019-04-26 23:38:55.830203144 +0200 -*************** -*** 0 **** ---- 1,18 ---- -+ /* usercmd.c */ -+ char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int *compl); -+ char_u *set_context_in_user_cmd(expand_T *xp, char_u *arg_in); -+ char_u *get_user_command_name(int idx); -+ char_u *get_user_commands(expand_T *xp, int idx); -+ char_u *get_user_cmd_addr_type(expand_T *xp, int idx); -+ char_u *get_user_cmd_flags(expand_T *xp, int idx); -+ char_u *get_user_cmd_nargs(expand_T *xp, int idx); -+ char_u *get_user_cmd_complete(expand_T *xp, int idx); -+ char *uc_fun_cmd(void); -+ void ex_command(exarg_T *eap); -+ void ex_comclear(exarg_T *eap); -+ void uc_clear(garray_T *gap); -+ void ex_delcommand(exarg_T *eap); -+ void do_ucmd(exarg_T *eap); -+ int parse_compl_arg(char_u *value, int vallen, int *complp, long *argt, char_u **compl_arg); -+ int cmdcomplete_str_to_type(char_u *complete_str); -+ /* vim: set ft=c : */ -*** ../vim-8.1.1209/Filelist 2019-04-21 11:34:36.331256556 +0200 ---- Filelist 2019-04-26 22:48:16.009112851 +0200 -*************** -*** 98,103 **** ---- 98,104 ---- - src/textprop.c \ - src/ui.c \ - src/undo.c \ -+ src/usercmd.c \ - src/userfunc.c \ - src/version.c \ - src/version.h \ -*************** -*** 212,217 **** ---- 213,219 ---- - src/proto/textprop.pro \ - src/proto/ui.pro \ - src/proto/undo.pro \ -+ src/proto/usercmd.pro \ - src/proto/userfunc.pro \ - src/proto/version.pro \ - src/proto/winclip.pro \ -*** ../vim-8.1.1209/src/Make_bc5.mak 2019-04-21 11:34:36.331256556 +0200 ---- src/Make_bc5.mak 2019-04-26 22:59:10.810260994 +0200 -*************** -*** 565,570 **** ---- 565,571 ---- - $(OBJDIR)\term.obj \ - $(OBJDIR)\ui.obj \ - $(OBJDIR)\undo.obj \ -+ $(OBJDIR)\usercmd.obj \ - $(OBJDIR)\userfunc.obj \ - $(OBJDIR)\version.obj \ - $(OBJDIR)\window.obj \ -*** ../vim-8.1.1209/src/Make_cyg_ming.mak 2019-04-21 11:34:36.331256556 +0200 ---- src/Make_cyg_ming.mak 2019-04-26 22:59:26.026194275 +0200 -*************** -*** 757,762 **** ---- 757,763 ---- - $(OUTDIR)/textprop.o \ - $(OUTDIR)/ui.o \ - $(OUTDIR)/undo.o \ -+ $(OUTDIR)/usercmd.o \ - $(OUTDIR)/userfunc.o \ - $(OUTDIR)/version.o \ - $(OUTDIR)/vimrc.o \ -*** ../vim-8.1.1209/src/Make_dice.mak 2019-04-21 11:34:36.331256556 +0200 ---- src/Make_dice.mak 2019-04-26 22:59:54.982067281 +0200 -*************** -*** 83,88 **** ---- 83,89 ---- - term.c \ - ui.c \ - undo.c \ -+ usercmd.c \ - userfunc.c \ - window.c \ - version.c -*************** -*** 144,149 **** ---- 145,151 ---- - o/term.o \ - o/ui.o \ - o/undo.o \ -+ o/usercmd.o \ - o/userfunc.o \ - o/window.o \ - $(TERMLIB) -*************** -*** 288,293 **** ---- 290,297 ---- - - o/undo.o: undo.c $(SYMS) - -+ o/usercmd.o: usercmd.c $(SYMS) -+ - o/userfunc.o: userfunc.c $(SYMS) - - o/window.o: window.c $(SYMS) -*** ../vim-8.1.1209/src/Make_ivc.mak 2019-04-21 11:34:36.331256556 +0200 ---- src/Make_ivc.mak 2019-04-26 23:00:12.165991891 +0200 -*************** -*** 269,274 **** ---- 269,275 ---- - "$(INTDIR)/term.obj" \ - "$(INTDIR)/ui.obj" \ - "$(INTDIR)/undo.obj" \ -+ "$(INTDIR)/usercmd.obj" \ - "$(INTDIR)/userfunc.obj" \ - "$(INTDIR)/version.obj" \ - "$(INTDIR)/window.obj" -*************** -*** 728,733 **** ---- 729,738 ---- - # End Source File - # Begin Source File - -+ SOURCE=.\usercmd.c -+ # End Source File -+ # Begin Source File -+ - SOURCE=.\userfunc.c - # End Source File - # Begin Source File -*** ../vim-8.1.1209/src/Make_manx.mak 2019-04-21 11:34:36.331256556 +0200 ---- src/Make_manx.mak 2019-04-26 23:00:42.393859245 +0200 -*************** -*** 93,98 **** ---- 93,99 ---- - term.c \ - ui.c \ - undo.c \ -+ usercmd.c \ - userfunc.c \ - window.c \ - version.c -*************** -*** 156,161 **** ---- 157,163 ---- - obj/term.o \ - obj/ui.o \ - obj/undo.o \ -+ obj/usercmd.o \ - obj/userfunc.o \ - obj/window.o \ - $(TERMLIB) -*************** -*** 218,223 **** ---- 220,226 ---- - proto/termlib.pro \ - proto/ui.pro \ - proto/undo.pro \ -+ proto/usercmd.pro \ - proto/userfunc.pro \ - proto/window.pro - -*************** -*** 443,448 **** ---- 446,454 ---- - obj/undo.o: undo.c - $(CCSYM) $@ undo.c - -+ obj/usercmd.o: usercmd.c -+ $(CCSYM) $@ usercmd.c -+ - obj/userfunc.o: userfunc.c - $(CCSYM) $@ userfunc.c - -*** ../vim-8.1.1209/src/Make_morph.mak 2019-04-21 11:34:36.331256556 +0200 ---- src/Make_morph.mak 2019-04-26 23:00:55.717800764 +0200 -*************** -*** 81,86 **** ---- 81,87 ---- - term.c \ - ui.c \ - undo.c \ -+ usercmd.c \ - userfunc.c \ - version.c \ - window.c \ -*** ../vim-8.1.1209/src/Make_mvc.mak 2019-04-21 11:34:36.331256556 +0200 ---- src/Make_mvc.mak 2019-04-26 23:01:17.701704254 +0200 -*************** -*** 765,770 **** ---- 765,771 ---- - $(OUTDIR)\textprop.obj \ - $(OUTDIR)\ui.obj \ - $(OUTDIR)\undo.obj \ -+ $(OUTDIR)\usercmd.obj \ - $(OUTDIR)\userfunc.obj \ - $(OUTDIR)\winclip.obj \ - $(OUTDIR)\window.obj \ -*************** -*** 1550,1555 **** ---- 1551,1558 ---- - - $(OUTDIR)/undo.obj: $(OUTDIR) undo.c $(INCL) - -+ $(OUTDIR)/usercmd.obj: $(OUTDIR) usercmd.c $(INCL) -+ - $(OUTDIR)/userfunc.obj: $(OUTDIR) userfunc.c $(INCL) - - $(OUTDIR)/window.obj: $(OUTDIR) window.c $(INCL) -*************** -*** 1693,1698 **** ---- 1696,1702 ---- - proto/textprop.pro \ - proto/ui.pro \ - proto/undo.pro \ -+ proto/usercmd.pro \ - proto/userfunc.pro \ - proto/window.pro \ - $(NETBEANS_PRO) \ -*** ../vim-8.1.1209/src/Make_sas.mak 2019-04-21 11:34:36.335256531 +0200 ---- src/Make_sas.mak 2019-04-26 23:01:55.393538739 +0200 -*************** -*** 146,151 **** ---- 146,152 ---- - term.c \ - ui.c \ - undo.c \ -+ usercmd.c \ - userfunc.c \ - window.c \ - version.c -*************** -*** 208,213 **** ---- 209,215 ---- - term.o \ - ui.o \ - undo.o \ -+ usercmd.o \ - userfunc.o \ - window.o \ - $(TERMLIB) -*************** -*** 271,276 **** ---- 273,279 ---- - proto/termlib.pro \ - proto/ui.pro \ - proto/undo.pro \ -+ proto/usercmd.pro \ - proto/userfunc.pro \ - proto/window.pro - -*************** -*** 445,450 **** ---- 448,455 ---- - proto/ui.pro: ui.c - undo.o: undo.c - proto/undo.pro: undo.c -+ usercmd.o: usercmd.c -+ proto/usercmd.pro: usercmd.c - userfunc.o: userfunc.c - proto/userfunc.pro: userfunc.c - window.o: window.c -*** ../vim-8.1.1209/src/Make_vms.mms 2019-04-21 11:34:36.335256531 +0200 ---- src/Make_vms.mms 2019-04-26 23:02:58.693260644 +0200 -*************** -*** 2,8 **** - # Makefile for Vim on OpenVMS - # - # Maintainer: Zoltan Arpadffy <arpadffy@polarhome.com> -! # Last change: 2019 Mar 22 - # - # This has script been tested on VMS 6.2 to 8.2 on DEC Alpha, VAX and IA64 - # with MMS and MMK ---- 2,8 ---- - # Makefile for Vim on OpenVMS - # - # Maintainer: Zoltan Arpadffy <arpadffy@polarhome.com> -! # Last change: 2019 Apr 26 - # - # This has script been tested on VMS 6.2 to 8.2 on DEC Alpha, VAX and IA64 - # with MMS and MMK -*************** -*** 315,322 **** - menu.c mbyte.c memfile.c memline.c message.c misc1.c misc2.c move.c \ - normal.c ops.c option.c popupmnu.c quickfix.c regexp.c search.c \ - sha256.c sign.c spell.c spellfile.c syntax.c tag.c term.c termlib.c \ -! textprop.c ui.c undo.c userfunc.c version.c screen.c window.c \ -! os_unix.c os_vms.c pathdef.c \ - $(GUI_SRC) $(PERL_SRC) $(PYTHON_SRC) $(TCL_SRC) \ - $(RUBY_SRC) $(HANGULIN_SRC) $(MZSCH_SRC) $(XDIFF_SRC) - ---- 315,322 ---- - menu.c mbyte.c memfile.c memline.c message.c misc1.c misc2.c move.c \ - normal.c ops.c option.c popupmnu.c quickfix.c regexp.c search.c \ - sha256.c sign.c spell.c spellfile.c syntax.c tag.c term.c termlib.c \ -! textprop.c ui.c undo.c usercmd.c userfunc.c version.c screen.c \ -! window.c os_unix.c os_vms.c pathdef.c \ - $(GUI_SRC) $(PERL_SRC) $(PYTHON_SRC) $(TCL_SRC) \ - $(RUBY_SRC) $(HANGULIN_SRC) $(MZSCH_SRC) $(XDIFF_SRC) - -*************** -*** 330,336 **** - move.obj mbyte.obj normal.obj ops.obj option.obj popupmnu.obj \ - quickfix.obj regexp.obj search.obj sha256.obj sign.obj spell.obj \ - spellfile.obj syntax.obj tag.obj term.obj termlib.obj textprop.obj \ -! ui.obj undo.obj userfunc.obj screen.obj version.obj \ - window.obj os_unix.obj os_vms.obj pathdef.obj if_mzsch.obj \ - $(GUI_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(TCL_OBJ) \ - $(RUBY_OBJ) $(HANGULIN_OBJ) $(MZSCH_OBJ) $(XDIFF_OBJ) ---- 330,336 ---- - move.obj mbyte.obj normal.obj ops.obj option.obj popupmnu.obj \ - quickfix.obj regexp.obj search.obj sha256.obj sign.obj spell.obj \ - spellfile.obj syntax.obj tag.obj term.obj termlib.obj textprop.obj \ -! ui.obj undo.obj usercmd.obj userfunc.obj screen.obj version.obj \ - window.obj os_unix.obj os_vms.obj pathdef.obj if_mzsch.obj \ - $(GUI_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(TCL_OBJ) \ - $(RUBY_OBJ) $(HANGULIN_OBJ) $(MZSCH_OBJ) $(XDIFF_OBJ) -*************** -*** 744,753 **** ---- 744,759 ---- - ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \ - [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \ - -+ usercmd.obj : usercmd.c vim.h [.auto]config.h feature.h os_unix.h \ -+ ascii.h keymap.h term.h macros.h option.h structs.h \ -+ regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \ -+ proto.h globals.h -+ - userfunc.obj : userfunc.c vim.h [.auto]config.h feature.h os_unix.h \ - ascii.h keymap.h term.h macros.h option.h structs.h \ - regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \ - proto.h globals.h -+ - version.obj : version.c vim.h [.auto]config.h feature.h os_unix.h \ - ascii.h keymap.h term.h macros.h structs.h regexp.h \ - gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ -*** ../vim-8.1.1209/src/Makefile 2019-04-25 20:28:53.327979592 +0200 ---- src/Makefile 2019-04-26 23:03:46.865048917 +0200 -*************** -*** 1635,1640 **** ---- 1635,1641 ---- - textprop.c \ - ui.c \ - undo.c \ -+ usercmd.c \ - userfunc.c \ - version.c \ - window.c \ -*************** -*** 1747,1752 **** ---- 1748,1754 ---- - objects/textprop.o \ - objects/ui.o \ - objects/undo.o \ -+ objects/usercmd.o \ - objects/userfunc.o \ - objects/version.o \ - objects/window.o \ -*************** -*** 1885,1890 **** ---- 1887,1893 ---- - textprop.pro \ - ui.pro \ - undo.pro \ -+ usercmd.pro \ - userfunc.pro \ - version.pro \ - window.pro \ -*************** -*** 3242,3247 **** ---- 3245,3253 ---- - objects/undo.o: undo.c - $(CCC) -o $@ undo.c - -+ objects/usercmd.o: usercmd.c -+ $(CCC) -o $@ usercmd.c -+ - objects/userfunc.o: userfunc.c - $(CCC) -o $@ userfunc.c - -*************** -*** 3657,3662 **** ---- 3663,3672 ---- - auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ - proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ - proto.h globals.h -+ objects/usercmd.o: usercmd.c vim.h protodef.h auto/config.h feature.h os_unix.h \ -+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ -+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ -+ proto.h globals.h - objects/userfunc.o: userfunc.c vim.h protodef.h auto/config.h feature.h os_unix.h \ - auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ - proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ -*** ../vim-8.1.1209/src/README.md 2019-04-26 21:31:34.019272940 +0200 ---- src/README.md 2019-04-26 23:05:11.488676798 +0200 -*************** -*** 28,33 **** ---- 28,34 ---- - debugger.c | vim script debugger - diff.c | diff mode (vimdiff) - eval.c | expression evaluation -+ evalfunc.c | built-in functions - fileio.c | reading and writing files - findfile.c | search for files in 'path' - fold.c | folding -*************** -*** 40,46 **** - memline.c | storing lines for buffers in memory - menu.c | menus - message.c | (error) messages -! ops.c | handling operators ("d", "y", "p") - option.c | options - quickfix.c | quickfix commands (":make", ":cn") - regexp.c | pattern matching ---- 41,47 ---- - memline.c | storing lines for buffers in memory - menu.c | menus - message.c | (error) messages -! ops.c | handling operators ("d", "y", "p") - option.c | options - quickfix.c | quickfix commands (":make", ":cn") - regexp.c | pattern matching -*************** -*** 49,57 **** - sign.c | signs - spell.c | spell checking - syntax.c | syntax and other highlighting -! tag.c | tags - term.c | terminal handling, termcap codes - undo.c | undo and redo - window.c | handling split windows - - ---- 50,60 ---- - sign.c | signs - spell.c | spell checking - syntax.c | syntax and other highlighting -! tag.c | tags - term.c | terminal handling, termcap codes - undo.c | undo and redo -+ usercmd.c | user defined commands -+ userfunc.c | user defined functions - window.c | handling split windows - - -*** ../vim-8.1.1209/src/buffer.c 2019-04-07 14:19:06.323149516 +0200 ---- src/buffer.c 2019-04-26 23:07:09.612157048 +0200 -*************** -*** 925,935 **** - CHANGEDTICK(buf) = tick; - } - #endif -! #ifdef FEAT_USR_CMDS -! uc_clear(&buf->b_ucmds); /* clear local user commands */ -! #endif - #ifdef FEAT_SIGNS -! buf_delete_signs(buf, (char_u *)"*"); // delete any signs */ - #endif - #ifdef FEAT_NETBEANS_INTG - netbeans_file_killed(buf); ---- 925,933 ---- - CHANGEDTICK(buf) = tick; - } - #endif -! uc_clear(&buf->b_ucmds); // clear local user commands - #ifdef FEAT_SIGNS -! buf_delete_signs(buf, (char_u *)"*"); // delete any signs - #endif - #ifdef FEAT_NETBEANS_INTG - netbeans_file_killed(buf); -*** ../vim-8.1.1209/src/eval.c 2019-04-26 20:32:57.082296551 +0200 ---- src/eval.c 2019-04-26 23:08:08.499897821 +0200 -*************** -*** 1120,1129 **** - return retval; - } - -! #if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) \ - || defined(FEAT_COMPL_FUNC) || defined(PROTO) - -! # if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) || defined(PROTO) - /* - * Call Vim script function "func" and return the result as a string. - * Returns NULL when calling the function fails. ---- 1120,1129 ---- - return retval; - } - -! #if defined(FEAT_CMDL_COMPL) \ - || defined(FEAT_COMPL_FUNC) || defined(PROTO) - -! # if defined(FEAT_CMDL_COMPL) || defined(PROTO) - /* - * Call Vim script function "func" and return the result as a string. - * Returns NULL when calling the function fails. -*** ../vim-8.1.1209/src/evalfunc.c 2019-04-26 22:33:44.896723710 +0200 ---- src/evalfunc.c 2019-04-26 23:08:24.535827217 +0200 -*************** -*** 6611,6620 **** - #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11) - "unnamedplus", - #endif -- #ifdef FEAT_USR_CMDS - "user-commands", /* was accidentally included in 5.4 */ - "user_commands", -- #endif - #ifdef FEAT_VARTABS - "vartabs", - #endif ---- 6611,6618 ---- -*** ../vim-8.1.1209/src/ex_cmds.h 2019-04-04 18:15:05.766857086 +0200 ---- src/ex_cmds.h 2019-04-26 23:27:26.194430566 +0200 -*************** -*** 1753,1765 **** - ADDR_LINES), - - #ifndef DO_DECLARE_EXCMD -- #ifdef FEAT_USR_CMDS - CMD_SIZE, /* MUST be after all real commands! */ - CMD_USER = -1, /* User-defined command */ - CMD_USER_BUF = -2 /* User-defined command local to buffer */ -- #else -- CMD_SIZE /* MUST be the last one! */ -- #endif - #endif - }; - ---- 1753,1761 ---- -*************** -*** 1795,1803 **** - int force_ff; /* ++ff= argument (first char of argument) */ - int force_enc; /* ++enc= argument (index in cmd[]) */ - int bad_char; /* BAD_KEEP, BAD_DROP or replacement byte */ -- #ifdef FEAT_USR_CMDS - int useridx; /* user command index */ -- #endif - char *errmsg; /* returned error message */ - char_u *(*getline)(int, void *, int); - void *cookie; /* argument for getline() */ ---- 1791,1797 ---- -*** ../vim-8.1.1209/src/ex_docmd.c 2019-04-25 21:27:40.562186830 +0200 ---- src/ex_docmd.c 2019-04-27 12:51:27.040691361 +0200 -*************** -*** 19,66 **** - # 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 ---- 19,24 ---- -*************** -*** 300,309 **** - 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 ---- 258,263 ---- -*************** -*** 1929,1949 **** - ) ? 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. */ - 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) ---- 1883,1902 ---- - ) ? find_command(&ea, NULL) : ea.cmd; - } - - if (p == NULL) - { - if (!ea.skip) - errormsg = _("E464: Ambiguous use of user-defined command"); - goto doend; - } -! // 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; - } -! - if (ea.cmdidx == CMD_SIZE) - { - if (!ea.skip) -*************** -*** 2508,2514 **** - * 7. Execute the command. - */ - -- #ifdef FEAT_USR_CMDS - if (IS_USER_CMDIDX(ea.cmdidx)) - { - /* ---- 2461,2466 ---- -*************** -*** 2517,2526 **** - do_ucmd(&ea); - } - else -- #endif - { - /* -! * Call the function to execute the command. - */ - ea.errmsg = NULL; - (cmdnames[ea.cmdidx].cmd_func)(&ea); ---- 2469,2477 ---- - do_ucmd(&ea); - } - else - { - /* -! * Call the function to execute the builtin command. - */ - ea.errmsg = NULL; - (cmdnames[ea.cmdidx].cmd_func)(&ea); -*************** -*** 3235,3252 **** - break; - } - -! #ifdef FEAT_USR_CMDS -! /* 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. */ - while (ASCII_ISALNUM(*p)) - ++p; - p = find_ucmd(eap, p, full, NULL, NULL); - } -- #endif - if (p == eap->cmd) - eap->cmdidx = CMD_SIZE; - } ---- 3186,3201 ---- - break; - } - -! // 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. - while (ASCII_ISALNUM(*p)) - ++p; - p = find_ucmd(eap, p, full, NULL, NULL); - } - if (p == eap->cmd) - eap->cmdidx = CMD_SIZE; - } -*************** -*** 3254,3377 **** - 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 - { ---- 3203,3208 ---- -*************** -*** 3483,3492 **** - 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 delim; - #endif - int forceit = FALSE; ---- 3314,3321 ---- - char_u *cmd, *arg; - int len = 0; - exarg_T ea; - #ifdef FEAT_CMDL_COMPL -+ int compl = EXPAND_NOTHING; - int delim; - #endif - int forceit = FALSE; -*************** -*** 3572,3582 **** - (size_t)len) == 0) - break; - -- #ifdef FEAT_USR_CMDS - if (cmd[0] >= 'A' && cmd[0] <= 'Z') -! while (ASCII_ISALNUM(*p) || *p == '*') /* Allow * wild card */ - ++p; -- #endif - } - - /* ---- 3401,3409 ---- - (size_t)len) == 0) - break; - - if (cmd[0] >= 'A' && cmd[0] <= 'Z') -! while (ASCII_ISALNUM(*p) || *p == '*') // Allow * wild card - ++p; - } - - /* -*************** -*** 3593,3613 **** - 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) - &compl -! # else - NULL -! # endif - ); - if (p == NULL) -! ea.cmdidx = CMD_SIZE; /* ambiguous user command */ - } -- #endif - } - if (ea.cmdidx == CMD_SIZE) - { ---- 3420,3438 ---- - ea.cmdidx = CMD_substitute; - p = cmd + 1; - } - else if (cmd[0] >= 'A' && cmd[0] <= 'Z') - { - ea.cmd = cmd; - p = find_ucmd(&ea, p, NULL, xp, -! #if defined(FEAT_CMDL_COMPL) - &compl -! #else - NULL -! #endif - ); - if (p == NULL) -! ea.cmdidx = CMD_SIZE; // ambiguous user command - } - } - if (ea.cmdidx == CMD_SIZE) - { -*************** -*** 3828,3834 **** - { - xp->xp_context = EXPAND_ENV_VARS; - ++xp->xp_pattern; -! #if defined(FEAT_USR_CMDS) && 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; ---- 3653,3659 ---- - { - xp->xp_context = EXPAND_ENV_VARS; - ++xp->xp_pattern; -! #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,4011 **** - * 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); - - case CMD_delcommand: - xp->xp_context = EXPAND_USER_COMMANDS; - xp->xp_pattern = arg; - break; -- # endif - - case CMD_global: - case CMD_vglobal: ---- 3769,3781 ---- - * All completion for the +cmdline_compl feature goes here. - */ - - case CMD_command: -! return set_context_in_user_cmd(xp, arg); - - case CMD_delcommand: - xp->xp_context = EXPAND_USER_COMMANDS; - xp->xp_pattern = arg; - break; - - case CMD_global: - case CMD_vglobal: -*************** -*** 4186,4217 **** - 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 */ - if (!(ea.argt & XFILE)) - { -! # ifdef FEAT_MENU - if (compl == EXPAND_MENUS) - return set_context_in_menu_cmd(xp, cmd, arg, forceit); -! # 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. */ - p = arg; - while (*p) - { - if (*p == ' ') -! /* argument starts after a space */ - arg = p + 1; - else if (*p == '\\' && *(p + 1) != NUL) -! ++p; /* skip over escaped character */ - MB_PTR_ADV(p); - } - xp->xp_pattern = arg; ---- 3956,3987 ---- - xp->xp_context = EXPAND_BUFFERS; - xp->xp_pattern = arg; - break; -! - case CMD_USER: - case CMD_USER_BUF: - if (compl != EXPAND_NOTHING) - { -! // XFILE: file names are handled above - if (!(ea.argt & XFILE)) - { -! #ifdef FEAT_MENU - if (compl == EXPAND_MENUS) - return set_context_in_menu_cmd(xp, cmd, arg, forceit); -! #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. - p = arg; - while (*p) - { - if (*p == ' ') -! // argument starts after a space - arg = p + 1; - else if (*p == '\\' && *(p + 1) != NUL) -! ++p; // skip over escaped character - MB_PTR_ADV(p); - } - xp->xp_pattern = arg; -*************** -*** 4219,4225 **** - xp->xp_context = compl; - } - break; -! #endif - case CMD_map: case CMD_noremap: - case CMD_nmap: case CMD_nnoremap: - case CMD_vmap: case CMD_vnoremap: ---- 3989,3995 ---- - xp->xp_context = compl; - } - break; -! - case CMD_map: case CMD_noremap: - case CMD_nmap: case CMD_nnoremap: - case CMD_vmap: case CMD_vnoremap: -*************** -*** 5771,5777 **** - return OK; - } - -! #ifdef FEAT_CMDL_COMPL - /* - * Function given to ExpandGeneric() to obtain the list of command names. - */ ---- 5541,5547 ---- - return OK; - } - -! #if defined(FEAT_CMDL_COMPL) || defined(PROTO) - /* - * Function given to ExpandGeneric() to obtain the list of command names. - */ -*************** -*** 5779,7218 **** - 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) -- { -- size_t result = 0; -- char_u *p = code + 1; -- size_t l = len - 2; -- int quote = 0; -- enum { -- ct_ARGS, -- ct_BANG, -- ct_COUNT, -- ct_LINE1, -- ct_LINE2, -- ct_RANGE, -- ct_MODS, -- ct_REGISTER, -- ct_LT, -- ct_NONE -- } type = ct_NONE; -- -- if ((vim_strchr((char_u *)"qQfF", *p) != NULL) && p[1] == '-') -- { -- quote = (*p == 'q' || *p == 'Q') ? 1 : 2; -- p += 2; -- l -= 2; -- } -- -- ++l; -- if (l <= 1) -- type = ct_NONE; -- else if (STRNICMP(p, "args>", l) == 0) -- type = ct_ARGS; -- else if (STRNICMP(p, "bang>", l) == 0) -- type = ct_BANG; -- else if (STRNICMP(p, "count>", l) == 0) -- type = ct_COUNT; -- else if (STRNICMP(p, "line1>", l) == 0) -- type = ct_LINE1; -- else if (STRNICMP(p, "line2>", l) == 0) -- type = ct_LINE2; -- else if (STRNICMP(p, "range>", l) == 0) -- type = ct_RANGE; -- else if (STRNICMP(p, "lt>", l) == 0) -- type = ct_LT; -- else if (STRNICMP(p, "reg>", l) == 0 || STRNICMP(p, "register>", l) == 0) -- type = ct_REGISTER; -- else if (STRNICMP(p, "mods>", l) == 0) -- type = ct_MODS; -- -- switch (type) -- { -- case ct_ARGS: -- /* Simple case first */ -- if (*eap->arg == NUL) -- { -- if (quote == 1) -- { -- result = 2; -- if (buf != NULL) -- STRCPY(buf, "''"); -- } -- else -- result = 0; -- break; -- } -- -- /* When specified there is a single argument don't split it. -- * Works for ":Cmd %" when % is "a b c". */ -- if ((eap->argt & NOSPC) && quote == 2) -- quote = 1; -- -- switch (quote) -- { -- case 0: /* No quoting, no splitting */ -- result = STRLEN(eap->arg); -- if (buf != NULL) -- STRCPY(buf, eap->arg); -- break; -- case 1: /* Quote, but don't split */ -- result = STRLEN(eap->arg) + 2; -- for (p = eap->arg; *p; ++p) -- { -- if (enc_dbcs != 0 && (*mb_ptr2len)(p) == 2) -- /* DBCS can contain \ in a trail byte, skip the -- * double-byte character. */ -- ++p; -- else -- if (*p == '\\' || *p == '"') -- ++result; -- } -- -- if (buf != NULL) -- { -- *buf++ = '"'; -- for (p = eap->arg; *p; ++p) -- { -- if (enc_dbcs != 0 && (*mb_ptr2len)(p) == 2) -- /* DBCS can contain \ in a trail byte, copy the -- * double-byte character to avoid escaping. */ -- *buf++ = *p++; -- else -- if (*p == '\\' || *p == '"') -- *buf++ = '\\'; -- *buf++ = *p; -- } -- *buf = '"'; -- } -- -- break; -- case 2: /* Quote and split (<f-args>) */ -- /* This is hard, so only do it once, and cache the result */ -- if (*split_buf == NULL) -- *split_buf = uc_split_args(eap->arg, split_len); -- -- result = *split_len; -- if (buf != NULL && result != 0) -- STRCPY(buf, *split_buf); -- -- break; -- } -- break; -- -- case ct_BANG: -- result = eap->forceit ? 1 : 0; -- if (quote) -- result += 2; -- if (buf != NULL) -- { -- if (quote) -- *buf++ = '"'; -- if (eap->forceit) -- *buf++ = '!'; -- if (quote) -- *buf = '"'; -- } -- break; -- -- case ct_LINE1: -- case ct_LINE2: -- case ct_RANGE: -- case ct_COUNT: -- { -- char num_buf[20]; -- long num = (type == ct_LINE1) ? eap->line1 : -- (type == ct_LINE2) ? eap->line2 : -- (type == ct_RANGE) ? eap->addr_count : -- (eap->addr_count > 0) ? eap->line2 : cmd->uc_def; -- size_t num_len; -- -- sprintf(num_buf, "%ld", num); -- num_len = STRLEN(num_buf); -- result = num_len; -- -- if (quote) -- result += 2; -- -- if (buf != NULL) -- { -- if (quote) -- *buf++ = '"'; -- STRCPY(buf, num_buf); -- buf += num_len; -- if (quote) -- *buf = '"'; -- } -- -- break; -- } -- -- case ct_MODS: -- { -- int multi_mods = 0; -- typedef struct { -- int *varp; -- char *name; -- } mod_entry_T; -- static mod_entry_T mod_entries[] = { -- #ifdef FEAT_BROWSE_CMD -- {&cmdmod.browse, "browse"}, -- #endif -- #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) -- {&cmdmod.confirm, "confirm"}, -- #endif -- {&cmdmod.hide, "hide"}, -- {&cmdmod.keepalt, "keepalt"}, -- {&cmdmod.keepjumps, "keepjumps"}, -- {&cmdmod.keepmarks, "keepmarks"}, -- {&cmdmod.keeppatterns, "keeppatterns"}, -- {&cmdmod.lockmarks, "lockmarks"}, -- {&cmdmod.noswapfile, "noswapfile"}, -- {NULL, NULL} -- }; -- int i; -- -- result = quote ? 2 : 0; -- if (buf != NULL) -- { -- if (quote) -- *buf++ = '"'; -- *buf = '\0'; -- } -- -- /* :aboveleft and :leftabove */ -- if (cmdmod.split & WSP_ABOVE) -- result += add_cmd_modifier(buf, "aboveleft", &multi_mods); -- /* :belowright and :rightbelow */ -- if (cmdmod.split & WSP_BELOW) -- result += add_cmd_modifier(buf, "belowright", &multi_mods); -- /* :botright */ -- if (cmdmod.split & WSP_BOT) -- result += add_cmd_modifier(buf, "botright", &multi_mods); -- -- /* the modifiers that are simple flags */ -- for (i = 0; mod_entries[i].varp != NULL; ++i) -- if (*mod_entries[i].varp) -- result += add_cmd_modifier(buf, mod_entries[i].name, -- &multi_mods); -- -- /* TODO: How to support :noautocmd? */ -- #ifdef HAVE_SANDBOX -- /* TODO: How to support :sandbox?*/ -- #endif -- /* :silent */ -- if (msg_silent > 0) -- result += add_cmd_modifier(buf, -- emsg_silent > 0 ? "silent!" : "silent", &multi_mods); -- /* :tab */ -- if (cmdmod.tab > 0) -- result += add_cmd_modifier(buf, "tab", &multi_mods); -- /* :topleft */ -- if (cmdmod.split & WSP_TOP) -- result += add_cmd_modifier(buf, "topleft", &multi_mods); -- /* TODO: How to support :unsilent?*/ -- /* :verbose */ -- if (p_verbose > 0) -- result += add_cmd_modifier(buf, "verbose", &multi_mods); -- /* :vertical */ -- if (cmdmod.split & WSP_VERT) -- result += add_cmd_modifier(buf, "vertical", &multi_mods); -- if (quote && buf != NULL) -- { -- buf += result - 2; -- *buf = '"'; -- } -- break; -- } -- -- case ct_REGISTER: -- result = eap->regname ? 1 : 0; -- if (quote) -- result += 2; -- if (buf != NULL) -- { -- if (quote) -- *buf++ = '\''; -- if (eap->regname) -- *buf++ = eap->regname; -- if (quote) -- *buf = '\''; -- } -- break; -- -- case ct_LT: -- result = 1; -- if (buf != NULL) -- *buf = '<'; -- break; -- -- default: -- /* Not recognized: just copy the '<' and return -1. */ -- result = (size_t)-1; -- if (buf != NULL) -- *buf = '<'; -- break; -- } -- -- return result; -- } -- -- static void -- do_ucmd(exarg_T *eap) -- { -- char_u *buf; -- char_u *p; -- char_u *q; -- -- char_u *start; -- char_u *end = NULL; -- char_u *ksp; -- size_t len, totlen; -- -- size_t split_len = 0; -- char_u *split_buf = NULL; -- ucmd_T *cmd; -- #ifdef FEAT_EVAL -- sctx_T save_current_sctx = current_sctx; -- #endif -- -- if (eap->cmdidx == CMD_USER) -- cmd = USER_CMD(eap->useridx); -- else -- cmd = USER_CMD_GA(&curbuf->b_ucmds, eap->useridx); -- -- /* -- * Replace <> in the command by the arguments. -- * First round: "buf" is NULL, compute length, allocate "buf". -- * Second round: copy result into "buf". -- */ -- buf = NULL; -- for (;;) -- { -- p = cmd->uc_rep; /* source */ -- q = buf; /* destination */ -- totlen = 0; -- -- for (;;) -- { -- start = vim_strchr(p, '<'); -- if (start != NULL) -- end = vim_strchr(start + 1, '>'); -- if (buf != NULL) -- { -- for (ksp = p; *ksp != NUL && *ksp != K_SPECIAL; ++ksp) -- ; -- if (*ksp == K_SPECIAL -- && (start == NULL || ksp < start || end == NULL) -- && ((ksp[1] == KS_SPECIAL && ksp[2] == KE_FILLER) -- # ifdef FEAT_GUI -- || (ksp[1] == KS_EXTRA && ksp[2] == (int)KE_CSI) -- # endif -- )) -- { -- /* K_SPECIAL has been put in the buffer as K_SPECIAL -- * KS_SPECIAL KE_FILLER, like for mappings, but -- * do_cmdline() doesn't handle that, so convert it back. -- * Also change K_SPECIAL KS_EXTRA KE_CSI into CSI. */ -- len = ksp - p; -- if (len > 0) -- { -- mch_memmove(q, p, len); -- q += len; -- } -- *q++ = ksp[1] == KS_SPECIAL ? K_SPECIAL : CSI; -- p = ksp + 3; -- continue; -- } -- } -- -- /* break if no <item> is found */ -- if (start == NULL || end == NULL) -- break; -- -- /* Include the '>' */ -- ++end; -- -- /* Take everything up to the '<' */ -- len = start - p; -- if (buf == NULL) -- totlen += len; -- else -- { -- mch_memmove(q, p, len); -- q += len; -- } -- -- len = uc_check_code(start, end - start, q, cmd, eap, -- &split_buf, &split_len); -- if (len == (size_t)-1) -- { -- /* no match, continue after '<' */ -- p = start + 1; -- len = 1; -- } -- else -- p = end; -- if (buf == NULL) -- totlen += len; -- else -- q += len; -- } -- if (buf != NULL) /* second time here, finished */ -- { -- STRCPY(q, p); -- break; -- } -- -- totlen += STRLEN(p); /* Add on the trailing characters */ -- buf = alloc((unsigned)(totlen + 1)); -- if (buf == NULL) -- { -- vim_free(split_buf); -- return; -- } -- } -- -- #ifdef FEAT_EVAL -- current_sctx.sc_sid = cmd->uc_script_ctx.sc_sid; -- #endif -- (void)do_cmdline(buf, eap->getline, eap->cookie, -- DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED); -- #ifdef FEAT_EVAL -- current_sctx = save_current_sctx; -- #endif -- vim_free(buf); -- vim_free(split_buf); -- } -- -- # if defined(FEAT_CMDL_COMPL) || defined(PROTO) -- static char_u * -- get_user_command_name(int idx) -- { -- return get_user_commands(NULL, idx - (int)CMD_SIZE); -- } -- -- /* -- * Function given to ExpandGeneric() to obtain the list of user command names. -- */ -- char_u * -- get_user_commands(expand_T *xp UNUSED, int idx) -- { -- if (idx < curbuf->b_ucmds.ga_len) -- return USER_CMD_GA(&curbuf->b_ucmds, idx)->uc_name; -- idx -= curbuf->b_ucmds.ga_len; -- if (idx < ucmds.ga_len) -- return USER_CMD(idx)->uc_name; -- return NULL; -- } -- -- /* -- * Function given to ExpandGeneric() to obtain the list of user address type names. -- */ -- char_u * -- get_user_cmd_addr_type(expand_T *xp UNUSED, int idx) -- { -- return (char_u *)addr_type_complete[idx].name; -- } -- -- /* -- * Function given to ExpandGeneric() to obtain the list of user command -- * attributes. -- */ -- char_u * -- get_user_cmd_flags(expand_T *xp UNUSED, int idx) -- { -- static char *user_cmd_flags[] = -- {"addr", "bang", "bar", "buffer", "complete", -- "count", "nargs", "range", "register"}; -- -- if (idx >= (int)(sizeof(user_cmd_flags) / sizeof(user_cmd_flags[0]))) -- return NULL; -- return (char_u *)user_cmd_flags[idx]; -- } -- -- /* -- * Function given to ExpandGeneric() to obtain the list of values for -nargs. -- */ -- char_u * -- get_user_cmd_nargs(expand_T *xp UNUSED, int idx) -- { -- static char *user_cmd_nargs[] = {"0", "1", "*", "?", "+"}; -- -- if (idx >= (int)(sizeof(user_cmd_nargs) / sizeof(user_cmd_nargs[0]))) -- return NULL; -- return (char_u *)user_cmd_nargs[idx]; -- } -- -- /* -- * Function given to ExpandGeneric() to obtain the list of values for -complete. -- */ -- char_u * -- get_user_cmd_complete(expand_T *xp UNUSED, int idx) -- { -- return (char_u *)command_complete[idx].name; -- } -- # endif /* FEAT_CMDL_COMPL */ -- -- /* -- * Parse address type argument -- */ -- int -- parse_addr_type_arg( -- char_u *value, -- int vallen, -- long *argt, -- int *addr_type_arg) -- { -- int i, a, b; -- -- for (i = 0; addr_type_complete[i].expand != -1; ++i) -- { -- a = (int)STRLEN(addr_type_complete[i].name) == vallen; -- b = STRNCMP(value, addr_type_complete[i].name, vallen) == 0; -- if (a && b) -- { -- *addr_type_arg = addr_type_complete[i].expand; -- break; -- } -- } -- -- if (addr_type_complete[i].expand == -1) -- { -- char_u *err = value; -- -- for (i = 0; err[i] != NUL && !VIM_ISWHITE(err[i]); i++) -- ; -- err[i] = NUL; -- semsg(_("E180: Invalid address type value: %s"), err); -- return FAIL; -- } -- -- if (*addr_type_arg != ADDR_LINES) -- *argt |= NOTADR; -- -- return OK; -- } -- -- #endif /* FEAT_USR_CMDS */ -- -- #if defined(FEAT_USR_CMDS) || defined(FEAT_EVAL) || defined(PROTO) -- /* -- * Parse a completion argument "value[vallen]". -- * The detected completion goes in "*complp", argument type in "*argt". -- * When there is an argument, for function and user defined completion, it's -- * copied to allocated memory and stored in "*compl_arg". -- * Returns FAIL if something is wrong. -- */ -- int -- parse_compl_arg( -- char_u *value, -- int vallen, -- int *complp, -- long *argt, -- char_u **compl_arg UNUSED) -- { -- char_u *arg = NULL; -- # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) -- size_t arglen = 0; -- # endif -- int i; -- int valend = vallen; -- -- /* Look for any argument part - which is the part after any ',' */ -- for (i = 0; i < vallen; ++i) -- { -- if (value[i] == ',') -- { -- arg = &value[i + 1]; -- # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) -- arglen = vallen - i - 1; -- # endif -- valend = i; -- break; -- } -- } -- -- for (i = 0; command_complete[i].expand != 0; ++i) -- { -- if ((int)STRLEN(command_complete[i].name) == valend -- && STRNCMP(value, command_complete[i].name, valend) == 0) -- { -- *complp = command_complete[i].expand; -- if (command_complete[i].expand == EXPAND_BUFFERS) -- *argt |= BUFNAME; -- else if (command_complete[i].expand == EXPAND_DIRECTORIES -- || command_complete[i].expand == EXPAND_FILES) -- *argt |= XFILE; -- break; -- } -- } -- -- if (command_complete[i].expand == 0) -- { -- semsg(_("E180: Invalid complete value: %s"), value); -- return FAIL; -- } -- -- # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) -- if (*complp != EXPAND_USER_DEFINED && *complp != EXPAND_USER_LIST -- && arg != NULL) -- # else -- if (arg != NULL) -- # endif -- { -- emsg(_("E468: Completion argument only allowed for custom completion")); -- return FAIL; -- } -- -- # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) -- if ((*complp == EXPAND_USER_DEFINED || *complp == EXPAND_USER_LIST) -- && arg == NULL) -- { -- emsg(_("E467: Custom completion requires a function argument")); -- return FAIL; -- } -- -- if (arg != NULL) -- *compl_arg = vim_strnsave(arg, (int)arglen); -- # endif -- return OK; -- } -- -- int -- cmdcomplete_str_to_type(char_u *complete_str) -- { -- int i; -- -- for (i = 0; command_complete[i].expand != 0; ++i) -- if (STRCMP(complete_str, command_complete[i].name) == 0) -- return command_complete[i].expand; -- -- return EXPAND_NOTHING; -- } -- #endif -- - static void - ex_colorscheme(exarg_T *eap) - { ---- 5549,5559 ---- -*** ../vim-8.1.1209/src/proto/ex_docmd.pro 2019-01-13 23:38:33.407773189 +0100 ---- src/proto/ex_docmd.pro 2019-04-26 23:39:53.321890880 +0200 -*************** -*** 19,34 **** - char_u *find_nextcmd(char_u *p); - char_u *check_nextcmd(char_u *p); - char_u *get_command_name(expand_T *xp, int idx); -- void ex_comclear(exarg_T *eap); -- void uc_clear(garray_T *gap); -- char_u *get_user_commands(expand_T *xp, int idx); -- char_u *get_user_cmd_addr_type(expand_T *xp, int idx); -- char_u *get_user_cmd_flags(expand_T *xp, int idx); -- char_u *get_user_cmd_nargs(expand_T *xp, int idx); -- char_u *get_user_cmd_complete(expand_T *xp, int idx); -- int parse_addr_type_arg(char_u *value, int vallen, long *argt, int *addr_type_arg); -- int parse_compl_arg(char_u *value, int vallen, int *complp, long *argt, char_u **compl_arg); -- int cmdcomplete_str_to_type(char_u *complete_str); - void not_exiting(void); - void tabpage_close(int forceit); - void tabpage_close_other(tabpage_T *tp, int forceit); ---- 19,24 ---- -*** ../vim-8.1.1209/src/ex_getln.c 2019-04-11 13:45:53.125298538 +0200 ---- src/ex_getln.c 2019-04-26 23:26:22.726894948 +0200 -*************** -*** 111,117 **** - # ifdef FEAT_CMDHIST - static char_u *get_history_arg(expand_T *xp, int idx); - # endif -! # if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) - static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file); - static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file); - # endif ---- 111,117 ---- - # ifdef FEAT_CMDHIST - static char_u *get_history_arg(expand_T *xp, int idx); - # endif -! # if defined(FEAT_EVAL) - static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file); - static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file); - # endif -*************** -*** 939,945 **** - { - xpc.xp_context = ccline.xp_context; - xpc.xp_pattern = ccline.cmdbuff; -! # if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL) - xpc.xp_arg = ccline.xp_arg; - # endif - } ---- 939,945 ---- - { - xpc.xp_context = ccline.xp_context; - xpc.xp_pattern = ccline.cmdbuff; -! # if defined(FEAT_CMDL_COMPL) - xpc.xp_arg = ccline.xp_arg; - # endif - } -*************** -*** 4210,4216 **** - #endif - xp->xp_numfiles = -1; - xp->xp_files = NULL; -! #if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) - xp->xp_arg = NULL; - #endif - xp->xp_line = NULL; ---- 4210,4216 ---- - #endif - xp->xp_numfiles = -1; - xp->xp_files = NULL; -! #if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) - xp->xp_arg = NULL; - #endif - xp->xp_line = NULL; -*************** -*** 4879,4885 **** - { - xp->xp_context = ccline.xp_context; - xp->xp_pattern = ccline.cmdbuff; -! # if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL) - xp->xp_arg = ccline.xp_arg; - # endif - } ---- 4879,4885 ---- - { - xp->xp_context = ccline.xp_context; - xp->xp_pattern = ccline.cmdbuff; -! # if defined(FEAT_CMDL_COMPL) - xp->xp_arg = ccline.xp_arg; - # endif - } -*************** -*** 5130,5136 **** - char *directories[] = {"syntax", "indent", "ftplugin", NULL}; - return ExpandRTDir(pat, 0, num_file, file, directories); - } -! # if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) - if (xp->xp_context == EXPAND_USER_LIST) - return ExpandUserList(xp, num_file, file); - # endif ---- 5130,5136 ---- - char *directories[] = {"syntax", "indent", "ftplugin", NULL}; - return ExpandRTDir(pat, 0, num_file, file, directories); - } -! # if defined(FEAT_EVAL) - if (xp->xp_context == EXPAND_USER_LIST) - return ExpandUserList(xp, num_file, file); - # endif -*************** -*** 5149,5155 **** - ret = ExpandSettings(xp, ®match, num_file, file); - else if (xp->xp_context == EXPAND_MAPPINGS) - ret = ExpandMappings(®match, num_file, file); -! # if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) - else if (xp->xp_context == EXPAND_USER_DEFINED) - ret = ExpandUserDefined(xp, ®match, num_file, file); - # endif ---- 5149,5155 ---- - ret = ExpandSettings(xp, ®match, num_file, file); - else if (xp->xp_context == EXPAND_MAPPINGS) - ret = ExpandMappings(®match, num_file, file); -! # if defined(FEAT_EVAL) - else if (xp->xp_context == EXPAND_USER_DEFINED) - ret = ExpandUserDefined(xp, ®match, num_file, file); - # endif -*************** -*** 5170,5182 **** - #ifdef FEAT_CMDHIST - {EXPAND_HISTORY, get_history_arg, TRUE, TRUE}, - #endif -- #ifdef FEAT_USR_CMDS - {EXPAND_USER_COMMANDS, get_user_commands, FALSE, TRUE}, - {EXPAND_USER_ADDR_TYPE, get_user_cmd_addr_type, FALSE, TRUE}, - {EXPAND_USER_CMD_FLAGS, get_user_cmd_flags, FALSE, TRUE}, - {EXPAND_USER_NARGS, get_user_cmd_nargs, FALSE, TRUE}, - {EXPAND_USER_COMPLETE, get_user_cmd_complete, FALSE, TRUE}, -- #endif - #ifdef FEAT_EVAL - {EXPAND_USER_VARS, get_user_var_name, FALSE, TRUE}, - {EXPAND_FUNCTIONS, get_function_name, FALSE, TRUE}, ---- 5170,5180 ---- -*************** -*** 5473,5479 **** - } - - -! # if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) - /* - * Call "user_expand_func()" to invoke a user defined Vim script function and - * return the result (either a string or a List). ---- 5471,5477 ---- - } - - -! # if defined(FEAT_EVAL) - /* - * Call "user_expand_func()" to invoke a user defined Vim script function and - * return the result (either a string or a List). -*** ../vim-8.1.1209/src/feature.h 2019-03-30 21:19:16.426170240 +0100 ---- src/feature.h 2019-04-26 23:27:34.074374224 +0200 -*************** -*** 379,388 **** - - /* - * +user_commands Allow the user to define his own commands. - */ -- #ifdef FEAT_NORMAL -- # define FEAT_USR_CMDS -- #endif - - /* - * +printer ":hardcopy" command ---- 379,386 ---- - - /* - * +user_commands Allow the user to define his own commands. -+ * Now always enabled. - */ - - /* - * +printer ":hardcopy" command -*** ../vim-8.1.1209/src/macros.h 2019-03-30 18:46:57.356077354 +0100 ---- src/macros.h 2019-04-26 23:12:15.806808513 +0200 -*************** -*** 336,338 **** ---- 336,341 ---- - (p) = NULL; \ - } \ - } while (0) -+ -+ /* Wether a command index indicates a user command. */ -+ #define IS_USER_CMDIDX(idx) ((int)(idx) < 0) -*** ../vim-8.1.1209/src/misc2.c 2019-03-30 13:53:26.174425093 +0100 ---- src/misc2.c 2019-04-26 23:51:39.458250238 +0200 -*************** -*** 1082,1091 **** - ui_remove_balloon(); - # endif - -! # if defined(FEAT_USR_CMDS) -! /* Clear user commands (before deleting buffers). */ - ex_comclear(NULL); -- # endif - - # ifdef FEAT_MENU - /* Clear menus. */ ---- 1082,1089 ---- - ui_remove_balloon(); - # endif - -! // Clear user commands (before deleting buffers). - ex_comclear(NULL); - - # ifdef FEAT_MENU - /* Clear menus. */ -*************** -*** 1130,1136 **** ---- 1128,1136 ---- - free_search_patterns(); - free_old_sub(); - free_last_insert(); -+ # if defined(FEAT_INS_EXPAND) - free_insexpand_stuff(); -+ # endif - free_prev_shellcmd(); - free_regexp_stuff(); - free_tag_stuff(); -*** ../vim-8.1.1209/src/proto.h 2019-04-21 11:34:36.335256531 +0200 ---- src/proto.h 2019-04-26 23:05:42.872538740 +0200 -*************** -*** 227,232 **** ---- 227,233 ---- - # endif - # include "ui.pro" - # include "undo.pro" -+ # include "usercmd.pro" - # include "userfunc.pro" - # include "version.pro" - # include "window.pro" -*** ../vim-8.1.1209/src/structs.h 2019-04-25 22:21:56.931749183 +0200 ---- src/structs.h 2019-04-26 23:28:26.458006469 +0200 -*************** -*** 549,555 **** - int xp_context; /* type of expansion */ - char_u *xp_pattern; /* start of item to expand */ - int xp_pattern_len; /* bytes in xp_pattern before cursor */ -! #if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) - char_u *xp_arg; /* completion function */ - sctx_T xp_script_ctx; /* SCTX for completion function */ - #endif ---- 549,555 ---- - int xp_context; /* type of expansion */ - char_u *xp_pattern; /* start of item to expand */ - int xp_pattern_len; /* bytes in xp_pattern before cursor */ -! #if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) - char_u *xp_arg; /* completion function */ - sctx_T xp_script_ctx; /* SCTX for completion function */ - #endif -*************** -*** 2143,2152 **** - /* First abbreviation local to a buffer. */ - mapblock_T *b_first_abbr; - #endif -! #ifdef FEAT_USR_CMDS -! /* User commands local to the buffer. */ - garray_T b_ucmds; -- #endif - /* - * start and end of an operator, also used for '[ and '] - */ ---- 2143,2150 ---- - /* First abbreviation local to a buffer. */ - mapblock_T *b_first_abbr; - #endif -! // User commands local to the buffer. - garray_T b_ucmds; - /* - * start and end of an operator, also used for '[ and '] - */ -*** ../vim-8.1.1209/src/version.c 2019-04-26 22:33:44.896723710 +0200 ---- src/version.c 2019-04-26 23:33:32.156048100 +0200 -*************** -*** 672,682 **** - #else - "-toolbar", - #endif -- #ifdef FEAT_USR_CMDS - "+user_commands", -- #else -- "-user_commands", -- #endif - #ifdef FEAT_VARTABS - "+vartabs", - #else ---- 672,678 ---- -*** ../vim-8.1.1209/runtime/doc/eval.txt 2019-04-20 14:39:42.796386124 +0200 ---- runtime/doc/eval.txt 2019-04-27 12:38:38.744951183 +0200 -*************** -*** 10491,10497 **** - ttyout output is a terminal (tty) - unix Unix version of Vim. *+unix* - unnamedplus Compiled with support for "unnamedplus" in 'clipboard' -! user_commands User-defined commands. - vcon Win32: Virtual console support is working, can use - 'termguicolors'. Also see |+vtp|. - vertsplit Compiled with vertically split windows |:vsplit|. ---- 10550,10556 ---- - ttyout output is a terminal (tty) - unix Unix version of Vim. *+unix* - unnamedplus Compiled with support for "unnamedplus" in 'clipboard' -! user_commands User-defined commands. (always true) - vcon Win32: Virtual console support is working, can use - 'termguicolors'. Also see |+vtp|. - vertsplit Compiled with vertically split windows |:vsplit|. -*************** -*** 10501,10506 **** ---- 10560,10566 ---- - viminfo Compiled with viminfo support. - vimscript-1 Compiled Vim script version 1 support - vimscript-2 Compiled Vim script version 2 support -+ vimscript-3 Compiled Vim script version 3 support - virtualedit Compiled with 'virtualedit' option. (always true) - visual Compiled with Visual mode. (always true) - visualextra Compiled with extra Visual mode commands. (always -*************** -*** 12700,12706 **** - - These items are not allowed in the sandbox: - - changing the buffer text -! - defining or changing mapping, autocommands, functions, user commands - - setting certain options (see |option-summary|) - - setting certain v: variables (see |v:var|) *E794* - - executing a shell command ---- 12771,12777 ---- - - These items are not allowed in the sandbox: - - changing the buffer text -! - defining or changing mapping, autocommands, user commands - - setting certain options (see |option-summary|) - - setting certain v: variables (see |v:var|) *E794* - - executing a shell command -*** ../vim-8.1.1209/runtime/doc/various.txt 2019-01-11 14:37:16.689248837 +0100 ---- runtime/doc/various.txt 2019-04-27 12:40:20.376390811 +0200 -*************** -*** 458,464 **** - N *+timers* the |timer_start()| function - N *+title* Setting the window 'title' and 'icon' - N *+toolbar* |gui-toolbar| -! N *+user_commands* User-defined commands. |user-commands| - B *+vartabs* Variable-width tabstops. |'vartabstop'| - N *+viminfo* |'viminfo'| - *+vertsplit* Vertically split windows |:vsplit|; Always enabled ---- 456,463 ---- - N *+timers* the |timer_start()| function - N *+title* Setting the window 'title' and 'icon' - N *+toolbar* |gui-toolbar| -! T *+user_commands* User-defined commands. |user-commands| -! Always enabled since 8.1.1210. - B *+vartabs* Variable-width tabstops. |'vartabstop'| - N *+viminfo* |'viminfo'| - *+vertsplit* Vertically split windows |:vsplit|; Always enabled -*** ../vim-8.1.1209/src/version.c 2019-04-26 22:33:44.896723710 +0200 ---- src/version.c 2019-04-26 23:33:32.156048100 +0200 -*************** -*** 773,774 **** ---- 769,772 ---- - { /* Add new patch number below this line */ -+ /**/ -+ 1210, - /**/ - --- -Shit makes the flowers grow and that's beautiful - - /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ -/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ -\\\ an exciting new programming language -- http://www.Zimbu.org /// - \\\ help me help AIDS victims -- http://ICCF-Holland.org /// |