From ac9fb18020d7e8bf16d02d45fbb02cf47328aaf7 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 27 Apr 2019 13:04:13 +0200 Subject: patch 8.1.1210: support for user commands is spread out 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. --- src/Make_bc5.mak | 1 + src/Make_cyg_ming.mak | 1 + src/Make_dice.mak | 4 + src/Make_ivc.mak | 5 + src/Make_manx.mak | 6 + src/Make_morph.mak | 1 + src/Make_mvc.mak | 4 + src/Make_sas.mak | 5 + src/Make_vms.mms | 14 +- src/Makefile | 10 + src/README.md | 7 +- src/buffer.c | 6 +- src/eval.c | 4 +- src/evalfunc.c | 2 - src/ex_cmds.h | 6 - src/ex_docmd.c | 1705 +----------------------------------------------- src/ex_getln.c | 16 +- src/feature.h | 4 +- src/macros.h | 3 + src/misc2.c | 6 +- src/proto.h | 1 + src/proto/ex_docmd.pro | 10 - src/proto/usercmd.pro | 18 + src/structs.h | 6 +- src/usercmd.c | 1656 ++++++++++++++++++++++++++++++++++++++++++++++ src/version.c | 6 +- 26 files changed, 1772 insertions(+), 1735 deletions(-) create mode 100644 src/proto/usercmd.pro create mode 100644 src/usercmd.c (limited to 'src') diff --git a/src/Make_bc5.mak b/src/Make_bc5.mak index 62d03972e8..a6b4bc96e9 100644 --- a/src/Make_bc5.mak +++ b/src/Make_bc5.mak @@ -565,6 +565,7 @@ vimobj = \ $(OBJDIR)\term.obj \ $(OBJDIR)\ui.obj \ $(OBJDIR)\undo.obj \ + $(OBJDIR)\usercmd.obj \ $(OBJDIR)\userfunc.obj \ $(OBJDIR)\version.obj \ $(OBJDIR)\window.obj \ diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak index 3c01e63fe0..599b9eeb4c 100644 --- a/src/Make_cyg_ming.mak +++ b/src/Make_cyg_ming.mak @@ -757,6 +757,7 @@ OBJ = \ $(OUTDIR)/textprop.o \ $(OUTDIR)/ui.o \ $(OUTDIR)/undo.o \ + $(OUTDIR)/usercmd.o \ $(OUTDIR)/userfunc.o \ $(OUTDIR)/version.o \ $(OUTDIR)/vimrc.o \ diff --git a/src/Make_dice.mak b/src/Make_dice.mak index 93e960a8db..89fa589459 100644 --- a/src/Make_dice.mak +++ b/src/Make_dice.mak @@ -83,6 +83,7 @@ SRC = \ term.c \ ui.c \ undo.c \ + usercmd.c \ userfunc.c \ window.c \ version.c @@ -144,6 +145,7 @@ OBJ = o/arabic.o \ o/term.o \ o/ui.o \ o/undo.o \ + o/usercmd.o \ o/userfunc.o \ o/window.o \ $(TERMLIB) @@ -288,6 +290,8 @@ o/ui.o: ui.c $(SYMS) o/undo.o: undo.c $(SYMS) +o/usercmd.o: usercmd.c $(SYMS) + o/userfunc.o: userfunc.c $(SYMS) o/window.o: window.c $(SYMS) diff --git a/src/Make_ivc.mak b/src/Make_ivc.mak index 08bd87451f..a8b9dffd7b 100644 --- a/src/Make_ivc.mak +++ b/src/Make_ivc.mak @@ -269,6 +269,7 @@ LINK32_OBJS= \ "$(INTDIR)/term.obj" \ "$(INTDIR)/ui.obj" \ "$(INTDIR)/undo.obj" \ + "$(INTDIR)/usercmd.obj" \ "$(INTDIR)/userfunc.obj" \ "$(INTDIR)/version.obj" \ "$(INTDIR)/window.obj" @@ -728,6 +729,10 @@ SOURCE=.\undo.c # End Source File # Begin Source File +SOURCE=.\usercmd.c +# End Source File +# Begin Source File + SOURCE=.\userfunc.c # End Source File # Begin Source File diff --git a/src/Make_manx.mak b/src/Make_manx.mak index 6eb7bfa684..e53522f06e 100644 --- a/src/Make_manx.mak +++ b/src/Make_manx.mak @@ -93,6 +93,7 @@ SRC = arabic.c \ term.c \ ui.c \ undo.c \ + usercmd.c \ userfunc.c \ window.c \ version.c @@ -156,6 +157,7 @@ OBJ = obj/arabic.o \ obj/term.o \ obj/ui.o \ obj/undo.o \ + obj/usercmd.o \ obj/userfunc.o \ obj/window.o \ $(TERMLIB) @@ -218,6 +220,7 @@ PRO = proto/arabic.pro \ proto/termlib.pro \ proto/ui.pro \ proto/undo.pro \ + proto/usercmd.pro \ proto/userfunc.pro \ proto/window.pro @@ -443,6 +446,9 @@ obj/ui.o: ui.c obj/undo.o: undo.c $(CCSYM) $@ undo.c +obj/usercmd.o: usercmd.c + $(CCSYM) $@ usercmd.c + obj/userfunc.o: userfunc.c $(CCSYM) $@ userfunc.c diff --git a/src/Make_morph.mak b/src/Make_morph.mak index 65cf8447be..a5ce62b8c6 100644 --- a/src/Make_morph.mak +++ b/src/Make_morph.mak @@ -81,6 +81,7 @@ SRC = arabic.c \ term.c \ ui.c \ undo.c \ + usercmd.c \ userfunc.c \ version.c \ window.c \ diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak index 7da56bc2d8..ef2b7f3f9d 100644 --- a/src/Make_mvc.mak +++ b/src/Make_mvc.mak @@ -765,6 +765,7 @@ OBJ = \ $(OUTDIR)\textprop.obj \ $(OUTDIR)\ui.obj \ $(OUTDIR)\undo.obj \ + $(OUTDIR)\usercmd.obj \ $(OUTDIR)\userfunc.obj \ $(OUTDIR)\winclip.obj \ $(OUTDIR)\window.obj \ @@ -1550,6 +1551,8 @@ $(OUTDIR)/ui.obj: $(OUTDIR) ui.c $(INCL) $(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,6 +1696,7 @@ proto.h: \ proto/textprop.pro \ proto/ui.pro \ proto/undo.pro \ + proto/usercmd.pro \ proto/userfunc.pro \ proto/window.pro \ $(NETBEANS_PRO) \ diff --git a/src/Make_sas.mak b/src/Make_sas.mak index 78d6d2a93f..0d8eb3d9ec 100644 --- a/src/Make_sas.mak +++ b/src/Make_sas.mak @@ -146,6 +146,7 @@ SRC = \ term.c \ ui.c \ undo.c \ + usercmd.c \ userfunc.c \ window.c \ version.c @@ -208,6 +209,7 @@ OBJ = \ term.o \ ui.o \ undo.o \ + usercmd.o \ userfunc.o \ window.o \ $(TERMLIB) @@ -271,6 +273,7 @@ PRO = \ proto/termlib.pro \ proto/ui.pro \ proto/undo.pro \ + proto/usercmd.pro \ proto/userfunc.pro \ proto/window.pro @@ -445,6 +448,8 @@ ui.o: ui.c 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 diff --git a/src/Make_vms.mms b/src/Make_vms.mms index edf77cb6bd..e25e426fd5 100644 --- a/src/Make_vms.mms +++ b/src/Make_vms.mms @@ -2,7 +2,7 @@ # Makefile for Vim on OpenVMS # # Maintainer: Zoltan Arpadffy -# Last change: 2019 Mar 22 +# 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,8 +315,8 @@ SRC = arabic.c autocmd.c beval.c blob.c blowfish.c buffer.c charset.c \ 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 \ + 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,7 +330,7 @@ OBJ = arabic.obj autocmd.obj beval.obj blob.obj blowfish.obj buffer.obj \ 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 \ + 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,10 +744,16 @@ undo.obj : undo.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 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 \ diff --git a/src/Makefile b/src/Makefile index 40f4b1b90d..0e719ea12f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1635,6 +1635,7 @@ BASIC_SRC = \ textprop.c \ ui.c \ undo.c \ + usercmd.c \ userfunc.c \ version.c \ window.c \ @@ -1747,6 +1748,7 @@ OBJ_COMMON = \ objects/textprop.o \ objects/ui.o \ objects/undo.o \ + objects/usercmd.o \ objects/userfunc.o \ objects/version.o \ objects/window.o \ @@ -1885,6 +1887,7 @@ PRO_AUTO = \ textprop.pro \ ui.pro \ undo.pro \ + usercmd.pro \ userfunc.pro \ version.pro \ window.pro \ @@ -3242,6 +3245,9 @@ objects/ui.o: ui.c 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,6 +3663,10 @@ objects/undo.o: undo.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/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 \ diff --git a/src/README.md b/src/README.md index f1e7ec2c31..c6bb8ac25c 100644 --- a/src/README.md +++ b/src/README.md @@ -28,6 +28,7 @@ buffer.c | manipulating buffers (loaded files) 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,7 +41,7 @@ memfile.c | storing lines for buffers in a swapfile memline.c | storing lines for buffers in memory menu.c | menus message.c | (error) messages -ops.c | handling operators ("d", "y", "p") +ops.c | handling operators ("d", "y", "p") option.c | options quickfix.c | quickfix commands (":make", ":cn") regexp.c | pattern matching @@ -49,9 +50,11 @@ search.c | pattern searching sign.c | signs spell.c | spell checking syntax.c | syntax and other highlighting -tag.c | tags +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 diff --git a/src/buffer.c b/src/buffer.c index 869150006f..5a30affabe 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -925,11 +925,9 @@ free_buffer_stuff( CHANGEDTICK(buf) = tick; } #endif -#ifdef FEAT_USR_CMDS - uc_clear(&buf->b_ucmds); /* clear local user commands */ -#endif + uc_clear(&buf->b_ucmds); // clear local user commands #ifdef FEAT_SIGNS - buf_delete_signs(buf, (char_u *)"*"); // delete any signs */ + buf_delete_signs(buf, (char_u *)"*"); // delete any signs #endif #ifdef FEAT_NETBEANS_INTG netbeans_file_killed(buf); diff --git a/src/eval.c b/src/eval.c index bf82d02633..a1ad0e673b 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1120,10 +1120,10 @@ call_func_retnr( return retval; } -#if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) \ +#if defined(FEAT_CMDL_COMPL) \ || defined(FEAT_COMPL_FUNC) || defined(PROTO) -# if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) || 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. diff --git a/src/evalfunc.c b/src/evalfunc.c index 228b71ad5c..58b8492e56 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -6611,10 +6611,8 @@ f_has(typval_T *argvars, typval_T *rettv) #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 diff --git a/src/ex_cmds.h b/src/ex_cmds.h index c080cbef0f..ac354cda24 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -1753,13 +1753,9 @@ EX(CMD_tilde, "~", do_sub, 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 }; @@ -1795,9 +1791,7 @@ struct exarg 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() */ diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 6b2fe4628e..0086589342 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -19,48 +19,6 @@ static int ex_pressedreturn = FALSE; # define ex_hardcopy ex_ni #endif -#ifdef FEAT_USR_CMDS -typedef struct ucmd -{ - char_u *uc_name; /* The command name */ - long_u uc_argt; /* The argument type */ - char_u *uc_rep; /* The command's replacement string */ - long uc_def; /* The default value for a range/count */ - int uc_compl; /* completion type */ - int uc_addr_type; /* The command's address type */ -# ifdef FEAT_EVAL - sctx_T uc_script_ctx; /* SCTX where the command was defined */ -# ifdef FEAT_CMDL_COMPL - char_u *uc_compl_arg; /* completion argument if any */ -# endif -# endif -} ucmd_T; - -#define UC_BUFFER 1 /* -buffer: local to current buffer */ - -static garray_T ucmds = {0, 0, sizeof(ucmd_T), 4, NULL}; - -#define USER_CMD(i) (&((ucmd_T *)(ucmds.ga_data))[i]) -#define USER_CMD_GA(gap, i) (&((ucmd_T *)((gap)->ga_data))[i]) - -static void do_ucmd(exarg_T *eap); -static void ex_command(exarg_T *eap); -static void ex_delcommand(exarg_T *eap); -# ifdef FEAT_CMDL_COMPL -static char_u *get_user_command_name(int idx); -# endif - -/* Wether a command index indicates a user command. */ -# define IS_USER_CMDIDX(idx) ((int)(idx) < 0) - -#else -# define ex_command ex_ni -# define ex_comclear ex_ni -# define ex_delcommand ex_ni -/* Wether a command index indicates a user command. */ -# define IS_USER_CMDIDX(idx) (FALSE) -#endif - #ifdef FEAT_EVAL static char_u *do_one_cmd(char_u **, int, struct condstack *, char_u *(*fgetline)(int, void *, int), void *cookie); #else @@ -300,10 +258,6 @@ static void ex_redrawtabline(exarg_T *eap); static void close_redir(void); static void ex_mkrc(exarg_T *eap); static void ex_mark(exarg_T *eap); -#ifdef FEAT_USR_CMDS -static char *uc_fun_cmd(void); -static char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int *compl); -#endif static void ex_startinsert(exarg_T *eap); static void ex_stopinsert(exarg_T *eap); #ifdef FEAT_FIND_ID @@ -1929,21 +1883,20 @@ do_one_cmd( ) ? find_command(&ea, NULL) : ea.cmd; } -#ifdef FEAT_USR_CMDS if (p == NULL) { if (!ea.skip) errormsg = _("E464: Ambiguous use of user-defined command"); goto doend; } - /* Check for wrong commands. */ + // Check for wrong commands. if (*p == '!' && ea.cmd[1] == 0151 && ea.cmd[0] == 78 && !IS_USER_CMDIDX(ea.cmdidx)) { errormsg = uc_fun_cmd(); goto doend; } -#endif + if (ea.cmdidx == CMD_SIZE) { if (!ea.skip) @@ -2508,7 +2461,6 @@ do_one_cmd( * 7. Execute the command. */ -#ifdef FEAT_USR_CMDS if (IS_USER_CMDIDX(ea.cmdidx)) { /* @@ -2517,10 +2469,9 @@ do_one_cmd( do_ucmd(&ea); } else -#endif { /* - * Call the function to execute the command. + * Call the function to execute the builtin command. */ ea.errmsg = NULL; (cmdnames[ea.cmdidx].cmd_func)(&ea); @@ -3235,18 +3186,16 @@ find_command(exarg_T *eap, int *full UNUSED) break; } -#ifdef FEAT_USR_CMDS - /* Look for a user defined command as a last resort. Let ":Print" be - * overruled by a user defined command. */ + // Look for a user defined command as a last resort. Let ":Print" be + // overruled by a user defined command. if ((eap->cmdidx == CMD_SIZE || eap->cmdidx == CMD_Print) && *eap->cmd >= 'A' && *eap->cmd <= 'Z') { - /* User defined commands may contain digits. */ + // User defined commands may contain digits. while (ASCII_ISALNUM(*p)) ++p; p = find_ucmd(eap, p, full, NULL, NULL); } -#endif if (p == eap->cmd) eap->cmdidx = CMD_SIZE; } @@ -3254,124 +3203,6 @@ find_command(exarg_T *eap, int *full UNUSED) return p; } -#ifdef FEAT_USR_CMDS -/* - * Search for a user command that matches "eap->cmd". - * Return cmdidx in "eap->cmdidx", flags in "eap->argt", idx in "eap->useridx". - * Return a pointer to just after the command. - * Return NULL if there is no matching command. - */ - static char_u * -find_ucmd( - exarg_T *eap, - char_u *p, /* end of the command (possibly including count) */ - int *full, /* set to TRUE for a full match */ - expand_T *xp, /* used for completion, NULL otherwise */ - int *compl) /* completion flags or NULL */ -{ - int len = (int)(p - eap->cmd); - int j, k, matchlen = 0; - ucmd_T *uc; - int found = FALSE; - int possible = FALSE; - char_u *cp, *np; /* Point into typed cmd and test name */ - garray_T *gap; - int amb_local = FALSE; /* Found ambiguous buffer-local command, - only full match global is accepted. */ - - /* - * Look for buffer-local user commands first, then global ones. - */ - gap = &curbuf->b_ucmds; - for (;;) - { - for (j = 0; j < gap->ga_len; ++j) - { - uc = USER_CMD_GA(gap, j); - cp = eap->cmd; - np = uc->uc_name; - k = 0; - while (k < len && *np != NUL && *cp++ == *np++) - k++; - if (k == len || (*np == NUL && vim_isdigit(eap->cmd[k]))) - { - /* If finding a second match, the command is ambiguous. But - * not if a buffer-local command wasn't a full match and a - * global command is a full match. */ - if (k == len && found && *np != NUL) - { - if (gap == &ucmds) - return NULL; - amb_local = TRUE; - } - - if (!found || (k == len && *np == NUL)) - { - /* If we matched up to a digit, then there could - * be another command including the digit that we - * should use instead. - */ - if (k == len) - found = TRUE; - else - possible = TRUE; - - if (gap == &ucmds) - eap->cmdidx = CMD_USER; - else - eap->cmdidx = CMD_USER_BUF; - eap->argt = (long)uc->uc_argt; - eap->useridx = j; - eap->addr_type = uc->uc_addr_type; - -# ifdef FEAT_CMDL_COMPL - if (compl != NULL) - *compl = uc->uc_compl; -# ifdef FEAT_EVAL - if (xp != NULL) - { - xp->xp_arg = uc->uc_compl_arg; - xp->xp_script_ctx = uc->uc_script_ctx; - xp->xp_script_ctx.sc_lnum += sourcing_lnum; - } -# endif -# endif - /* Do not search for further abbreviations - * if this is an exact match. */ - matchlen = k; - if (k == len && *np == NUL) - { - if (full != NULL) - *full = TRUE; - amb_local = FALSE; - break; - } - } - } - } - - /* Stop if we found a full match or searched all. */ - if (j < gap->ga_len || gap == &ucmds) - break; - gap = &ucmds; - } - - /* Only found ambiguous matches. */ - if (amb_local) - { - if (xp != NULL) - xp->xp_context = EXPAND_UNSUCCESSFUL; - return NULL; - } - - /* The match we found may be followed immediately by a number. Move "p" - * back to point to it. */ - if (found || possible) - return p + (matchlen - len); - return p; -} -#endif - #if defined(FEAT_EVAL) || defined(PROTO) static struct cmdmod { @@ -3483,10 +3314,8 @@ set_one_cmd_context( char_u *cmd, *arg; int len = 0; exarg_T ea; -#if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL) - int compl = EXPAND_NOTHING; -#endif #ifdef FEAT_CMDL_COMPL + int compl = EXPAND_NOTHING; int delim; #endif int forceit = FALSE; @@ -3572,11 +3401,9 @@ set_one_cmd_context( (size_t)len) == 0) break; -#ifdef FEAT_USR_CMDS if (cmd[0] >= 'A' && cmd[0] <= 'Z') - while (ASCII_ISALNUM(*p) || *p == '*') /* Allow * wild card */ + while (ASCII_ISALNUM(*p) || *p == '*') // Allow * wild card ++p; -#endif } /* @@ -3593,21 +3420,19 @@ set_one_cmd_context( ea.cmdidx = CMD_substitute; p = cmd + 1; } -#ifdef FEAT_USR_CMDS else if (cmd[0] >= 'A' && cmd[0] <= 'Z') { ea.cmd = cmd; p = find_ucmd(&ea, p, NULL, xp, -# if defined(FEAT_CMDL_COMPL) +#if defined(FEAT_CMDL_COMPL) &compl -# else +#else NULL -# endif +#endif ); if (p == NULL) - ea.cmdidx = CMD_SIZE; /* ambiguous user command */ + ea.cmdidx = CMD_SIZE; // ambiguous user command } -#endif } if (ea.cmdidx == CMD_SIZE) { @@ -3828,7 +3653,7 @@ set_one_cmd_context( { xp->xp_context = EXPAND_ENV_VARS; ++xp->xp_pattern; -#if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL) +#if defined(FEAT_CMDL_COMPL) /* Avoid that the assignment uses EXPAND_FILES again. */ if (compl != EXPAND_USER_DEFINED && compl != EXPAND_USER_LIST) compl = EXPAND_ENV_VARS; @@ -3944,68 +3769,13 @@ set_one_cmd_context( * All completion for the +cmdline_compl feature goes here. */ -# ifdef FEAT_USR_CMDS case CMD_command: - /* Check for attributes */ - while (*arg == '-') - { - arg++; /* Skip "-" */ - p = skiptowhite(arg); - if (*p == NUL) - { - /* Cursor is still in the attribute */ - p = vim_strchr(arg, '='); - if (p == NULL) - { - /* No "=", so complete attribute names */ - xp->xp_context = EXPAND_USER_CMD_FLAGS; - xp->xp_pattern = arg; - return NULL; - } - - /* For the -complete, -nargs and -addr attributes, we complete - * their arguments as well. - */ - if (STRNICMP(arg, "complete", p - arg) == 0) - { - xp->xp_context = EXPAND_USER_COMPLETE; - xp->xp_pattern = p + 1; - return NULL; - } - else if (STRNICMP(arg, "nargs", p - arg) == 0) - { - xp->xp_context = EXPAND_USER_NARGS; - xp->xp_pattern = p + 1; - return NULL; - } - else if (STRNICMP(arg, "addr", p - arg) == 0) - { - xp->xp_context = EXPAND_USER_ADDR_TYPE; - xp->xp_pattern = p + 1; - return NULL; - } - return NULL; - } - arg = skipwhite(p); - } - - /* After the attributes comes the new command name */ - p = skiptowhite(arg); - if (*p == NUL) - { - xp->xp_context = EXPAND_USER_COMMANDS; - xp->xp_pattern = arg; - break; - } - - /* And finally comes a normal command */ - return skipwhite(p); + return set_context_in_user_cmd(xp, arg); case CMD_delcommand: xp->xp_context = EXPAND_USER_COMMANDS; xp->xp_pattern = arg; break; -# endif case CMD_global: case CMD_vglobal: @@ -4186,32 +3956,32 @@ set_one_cmd_context( xp->xp_context = EXPAND_BUFFERS; xp->xp_pattern = arg; break; -#ifdef FEAT_USR_CMDS + case CMD_USER: case CMD_USER_BUF: if (compl != EXPAND_NOTHING) { - /* XFILE: file names are handled above */ + // XFILE: file names are handled above if (!(ea.argt & XFILE)) { -# ifdef FEAT_MENU +#ifdef FEAT_MENU if (compl == EXPAND_MENUS) return set_context_in_menu_cmd(xp, cmd, arg, forceit); -# endif +#endif if (compl == EXPAND_COMMANDS) return arg; if (compl == EXPAND_MAPPINGS) return set_context_in_map_cmd(xp, (char_u *)"map", arg, forceit, FALSE, FALSE, CMD_map); - /* Find start of last argument. */ + // Find start of last argument. p = arg; while (*p) { if (*p == ' ') - /* argument starts after a space */ + // argument starts after a space arg = p + 1; else if (*p == '\\' && *(p + 1) != NUL) - ++p; /* skip over escaped character */ + ++p; // skip over escaped character MB_PTR_ADV(p); } xp->xp_pattern = arg; @@ -4219,7 +3989,7 @@ set_one_cmd_context( xp->xp_context = compl; } break; -#endif + case CMD_map: case CMD_noremap: case CMD_nmap: case CMD_nnoremap: case CMD_vmap: case CMD_vnoremap: @@ -5771,7 +5541,7 @@ check_more( return OK; } -#ifdef FEAT_CMDL_COMPL +#if defined(FEAT_CMDL_COMPL) || defined(PROTO) /* * Function given to ExpandGeneric() to obtain the list of command names. */ @@ -5779,1438 +5549,9 @@ check_more( get_command_name(expand_T *xp UNUSED, int idx) { if (idx >= (int)CMD_SIZE) -# ifdef FEAT_USR_CMDS return get_user_command_name(idx); -# else - return NULL; -# endif return cmdnames[idx].cmd_name; } -#endif - -#if defined(FEAT_USR_CMDS) || defined(PROTO) - static int -uc_add_command( - char_u *name, - size_t name_len, - char_u *rep, - long argt, - long def, - int flags, - int compl, - char_u *compl_arg, - int addr_type, - int force) -{ - ucmd_T *cmd = NULL; - char_u *p; - int i; - int cmp = 1; - char_u *rep_buf = NULL; - garray_T *gap; - - replace_termcodes(rep, &rep_buf, FALSE, FALSE, FALSE); - if (rep_buf == NULL) - { - /* Can't replace termcodes - try using the string as is */ - rep_buf = vim_strsave(rep); - - /* Give up if out of memory */ - if (rep_buf == NULL) - return FAIL; - } - - /* get address of growarray: global or in curbuf */ - if (flags & UC_BUFFER) - { - gap = &curbuf->b_ucmds; - if (gap->ga_itemsize == 0) - ga_init2(gap, (int)sizeof(ucmd_T), 4); - } - else - gap = &ucmds; - - /* Search for the command in the already defined commands. */ - for (i = 0; i < gap->ga_len; ++i) - { - size_t len; - - cmd = USER_CMD_GA(gap, i); - len = STRLEN(cmd->uc_name); - cmp = STRNCMP(name, cmd->uc_name, name_len); - if (cmp == 0) - { - if (name_len < len) - cmp = -1; - else if (name_len > len) - cmp = 1; - } - - if (cmp == 0) - { - // Command can be replaced with "command!" and when sourcing the - // same script again, but only once. - if (!force && (cmd->uc_script_ctx.sc_sid != current_sctx.sc_sid - || cmd->uc_script_ctx.sc_seq == current_sctx.sc_seq)) - { - semsg(_("E174: Command already exists: add ! to replace it: %s"), - name); - goto fail; - } - - VIM_CLEAR(cmd->uc_rep); -#if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) - VIM_CLEAR(cmd->uc_compl_arg); -#endif - break; - } - - /* Stop as soon as we pass the name to add */ - if (cmp < 0) - break; - } - - /* Extend the array unless we're replacing an existing command */ - if (cmp != 0) - { - if (ga_grow(gap, 1) != OK) - goto fail; - if ((p = vim_strnsave(name, (int)name_len)) == NULL) - goto fail; - - cmd = USER_CMD_GA(gap, i); - mch_memmove(cmd + 1, cmd, (gap->ga_len - i) * sizeof(ucmd_T)); - - ++gap->ga_len; - - cmd->uc_name = p; - } - - cmd->uc_rep = rep_buf; - cmd->uc_argt = argt; - cmd->uc_def = def; - cmd->uc_compl = compl; -#ifdef FEAT_EVAL - cmd->uc_script_ctx = current_sctx; - cmd->uc_script_ctx.sc_lnum += sourcing_lnum; -# ifdef FEAT_CMDL_COMPL - cmd->uc_compl_arg = compl_arg; -# endif -#endif - cmd->uc_addr_type = addr_type; - - return OK; - -fail: - vim_free(rep_buf); -#if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) - vim_free(compl_arg); -#endif - return FAIL; -} -#endif - -#if defined(FEAT_USR_CMDS) -static struct -{ - int expand; - char *name; - char *shortname; -} addr_type_complete[] = -{ - {ADDR_ARGUMENTS, "arguments", "arg"}, - {ADDR_LINES, "lines", "line"}, - {ADDR_LOADED_BUFFERS, "loaded_buffers", "load"}, - {ADDR_TABS, "tabs", "tab"}, - {ADDR_BUFFERS, "buffers", "buf"}, - {ADDR_WINDOWS, "windows", "win"}, - {ADDR_QUICKFIX, "quickfix", "qf"}, - {ADDR_OTHER, "other", "?"}, - {-1, NULL, NULL} -}; -#endif - -#if defined(FEAT_USR_CMDS) || defined(FEAT_EVAL) || defined(PROTO) -/* - * List of names for completion for ":command" with the EXPAND_ flag. - * Must be alphabetical for completion. - */ -static struct -{ - int expand; - char *name; -} command_complete[] = -{ - {EXPAND_ARGLIST, "arglist"}, - {EXPAND_AUGROUP, "augroup"}, - {EXPAND_BEHAVE, "behave"}, - {EXPAND_BUFFERS, "buffer"}, - {EXPAND_COLORS, "color"}, - {EXPAND_COMMANDS, "command"}, - {EXPAND_COMPILER, "compiler"}, -#if defined(FEAT_CSCOPE) - {EXPAND_CSCOPE, "cscope"}, -#endif -#if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) - {EXPAND_USER_DEFINED, "custom"}, - {EXPAND_USER_LIST, "customlist"}, -#endif - {EXPAND_DIRECTORIES, "dir"}, - {EXPAND_ENV_VARS, "environment"}, - {EXPAND_EVENTS, "event"}, - {EXPAND_EXPRESSION, "expression"}, - {EXPAND_FILES, "file"}, - {EXPAND_FILES_IN_PATH, "file_in_path"}, - {EXPAND_FILETYPE, "filetype"}, - {EXPAND_FUNCTIONS, "function"}, - {EXPAND_HELP, "help"}, - {EXPAND_HIGHLIGHT, "highlight"}, -#if defined(FEAT_CMDHIST) - {EXPAND_HISTORY, "history"}, -#endif -#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) - {EXPAND_LOCALES, "locale"}, -#endif - {EXPAND_MAPCLEAR, "mapclear"}, - {EXPAND_MAPPINGS, "mapping"}, - {EXPAND_MENUS, "menu"}, - {EXPAND_MESSAGES, "messages"}, - {EXPAND_OWNSYNTAX, "syntax"}, -#if defined(FEAT_PROFILE) - {EXPAND_SYNTIME, "syntime"}, -#endif - {EXPAND_SETTINGS, "option"}, - {EXPAND_PACKADD, "packadd"}, - {EXPAND_SHELLCMD, "shellcmd"}, -#if defined(FEAT_SIGNS) - {EXPAND_SIGN, "sign"}, -#endif - {EXPAND_TAGS, "tag"}, - {EXPAND_TAGS_LISTFILES, "tag_listfiles"}, - {EXPAND_USER, "user"}, - {EXPAND_USER_VARS, "var"}, - {0, NULL} -}; -#endif - -#if defined(FEAT_USR_CMDS) || defined(PROTO) - static void -uc_list(char_u *name, size_t name_len) -{ - int i, j; - int found = FALSE; - ucmd_T *cmd; - int len; - int over; - long a; - garray_T *gap; - - gap = &curbuf->b_ucmds; - for (;;) - { - for (i = 0; i < gap->ga_len; ++i) - { - cmd = USER_CMD_GA(gap, i); - a = (long)cmd->uc_argt; - - /* Skip commands which don't match the requested prefix and - * commands filtered out. */ - if (STRNCMP(name, cmd->uc_name, name_len) != 0 - || message_filtered(cmd->uc_name)) - continue; - - /* Put out the title first time */ - if (!found) - msg_puts_title(_("\n Name Args Address Complete Definition")); - found = TRUE; - msg_putchar('\n'); - if (got_int) - break; - - // Special cases - len = 4; - if (a & BANG) - { - msg_putchar('!'); - --len; - } - if (a & REGSTR) - { - msg_putchar('"'); - --len; - } - if (gap != &ucmds) - { - msg_putchar('b'); - --len; - } - if (a & TRLBAR) - { - msg_putchar('|'); - --len; - } - while (len-- > 0) - msg_putchar(' '); - - msg_outtrans_attr(cmd->uc_name, HL_ATTR(HLF_D)); - len = (int)STRLEN(cmd->uc_name) + 4; - - do { - msg_putchar(' '); - ++len; - } while (len < 22); - - // "over" is how much longer the name is than the column width for - // the name, we'll try to align what comes after. - over = len - 22; - len = 0; - - // Arguments - switch ((int)(a & (EXTRA|NOSPC|NEEDARG))) - { - case 0: IObuff[len++] = '0'; break; - case (EXTRA): IObuff[len++] = '*'; break; - case (EXTRA|NOSPC): IObuff[len++] = '?'; break; - case (EXTRA|NEEDARG): IObuff[len++] = '+'; break; - case (EXTRA|NOSPC|NEEDARG): IObuff[len++] = '1'; break; - } - - do { - IObuff[len++] = ' '; - } while (len < 5 - over); - - // Address / Range - if (a & (RANGE|COUNT)) - { - if (a & COUNT) - { - // -count=N - sprintf((char *)IObuff + len, "%ldc", cmd->uc_def); - len += (int)STRLEN(IObuff + len); - } - else if (a & DFLALL) - IObuff[len++] = '%'; - else if (cmd->uc_def >= 0) - { - // -range=N - sprintf((char *)IObuff + len, "%ld", cmd->uc_def); - len += (int)STRLEN(IObuff + len); - } - else - IObuff[len++] = '.'; - } - - do { - IObuff[len++] = ' '; - } while (len < 8 - over); - - // Address Type - for (j = 0; addr_type_complete[j].expand != -1; ++j) - if (addr_type_complete[j].expand != ADDR_LINES - && addr_type_complete[j].expand == cmd->uc_addr_type) - { - STRCPY(IObuff + len, addr_type_complete[j].shortname); - len += (int)STRLEN(IObuff + len); - break; - } - - do { - IObuff[len++] = ' '; - } while (len < 13 - over); - - // Completion - for (j = 0; command_complete[j].expand != 0; ++j) - if (command_complete[j].expand == cmd->uc_compl) - { - STRCPY(IObuff + len, command_complete[j].name); - len += (int)STRLEN(IObuff + len); - break; - } - - do { - IObuff[len++] = ' '; - } while (len < 25 - over); - - IObuff[len] = '\0'; - msg_outtrans(IObuff); - - msg_outtrans_special(cmd->uc_rep, FALSE, - name_len == 0 ? Columns - 47 : 0); -#ifdef FEAT_EVAL - if (p_verbose > 0) - last_set_msg(cmd->uc_script_ctx); -#endif - out_flush(); - ui_breakcheck(); - if (got_int) - break; - } - if (gap == &ucmds || i < gap->ga_len) - break; - gap = &ucmds; - } - - if (!found) - msg(_("No user-defined commands found")); -} - - static char * -uc_fun_cmd(void) -{ - static char_u fcmd[] = {0x84, 0xaf, 0x60, 0xb9, 0xaf, 0xb5, 0x60, 0xa4, - 0xa5, 0xad, 0xa1, 0xae, 0xa4, 0x60, 0xa1, 0x60, - 0xb3, 0xa8, 0xb2, 0xb5, 0xa2, 0xa2, 0xa5, 0xb2, - 0xb9, 0x7f, 0}; - int i; - - for (i = 0; fcmd[i]; ++i) - IObuff[i] = fcmd[i] - 0x40; - IObuff[i] = 0; - return (char *)IObuff; -} - - static int -uc_scan_attr( - char_u *attr, - size_t len, - long *argt, - long *def, - int *flags, - int *compl, - char_u **compl_arg, - int *addr_type_arg) -{ - char_u *p; - - if (len == 0) - { - emsg(_("E175: No attribute specified")); - return FAIL; - } - - /* First, try the simple attributes (no arguments) */ - if (STRNICMP(attr, "bang", len) == 0) - *argt |= BANG; - else if (STRNICMP(attr, "buffer", len) == 0) - *flags |= UC_BUFFER; - else if (STRNICMP(attr, "register", len) == 0) - *argt |= REGSTR; - else if (STRNICMP(attr, "bar", len) == 0) - *argt |= TRLBAR; - else - { - int i; - char_u *val = NULL; - size_t vallen = 0; - size_t attrlen = len; - - /* Look for the attribute name - which is the part before any '=' */ - for (i = 0; i < (int)len; ++i) - { - if (attr[i] == '=') - { - val = &attr[i + 1]; - vallen = len - i - 1; - attrlen = i; - break; - } - } - - if (STRNICMP(attr, "nargs", attrlen) == 0) - { - if (vallen == 1) - { - if (*val == '0') - /* Do nothing - this is the default */; - else if (*val == '1') - *argt |= (EXTRA | NOSPC | NEEDARG); - else if (*val == '*') - *argt |= EXTRA; - else if (*val == '?') - *argt |= (EXTRA | NOSPC); - else if (*val == '+') - *argt |= (EXTRA | NEEDARG); - else - goto wrong_nargs; - } - else - { -wrong_nargs: - emsg(_("E176: Invalid number of arguments")); - return FAIL; - } - } - else if (STRNICMP(attr, "range", attrlen) == 0) - { - *argt |= RANGE; - if (vallen == 1 && *val == '%') - *argt |= DFLALL; - else if (val != NULL) - { - p = val; - if (*def >= 0) - { -two_count: - emsg(_("E177: Count cannot be specified twice")); - return FAIL; - } - - *def = getdigits(&p); - *argt |= (ZEROR | NOTADR); - - if (p != val + vallen || vallen == 0) - { -invalid_count: - emsg(_("E178: Invalid default value for count")); - return FAIL; - } - } - } - else if (STRNICMP(attr, "count", attrlen) == 0) - { - *argt |= (COUNT | ZEROR | RANGE | NOTADR); - - if (val != NULL) - { - p = val; - if (*def >= 0) - goto two_count; - - *def = getdigits(&p); - - if (p != val + vallen) - goto invalid_count; - } - - if (*def < 0) - *def = 0; - } - else if (STRNICMP(attr, "complete", attrlen) == 0) - { - if (val == NULL) - { - emsg(_("E179: argument required for -complete")); - return FAIL; - } - - if (parse_compl_arg(val, (int)vallen, compl, argt, compl_arg) - == FAIL) - return FAIL; - } - else if (STRNICMP(attr, "addr", attrlen) == 0) - { - *argt |= RANGE; - if (val == NULL) - { - emsg(_("E179: argument required for -addr")); - return FAIL; - } - if (parse_addr_type_arg(val, (int)vallen, argt, addr_type_arg) - == FAIL) - return FAIL; - if (addr_type_arg != ADDR_LINES) - *argt |= (ZEROR | NOTADR) ; - } - else - { - char_u ch = attr[len]; - attr[len] = '\0'; - semsg(_("E181: Invalid attribute: %s"), attr); - attr[len] = ch; - return FAIL; - } - } - - return OK; -} - -/* - * ":command ..." - */ - static void -ex_command(exarg_T *eap) -{ - char_u *name; - char_u *end; - char_u *p; - long argt = 0; - long def = -1; - int flags = 0; - int compl = EXPAND_NOTHING; - char_u *compl_arg = NULL; - int addr_type_arg = ADDR_LINES; - int has_attr = (eap->arg[0] == '-'); - int name_len; - - p = eap->arg; - - /* Check for attributes */ - while (*p == '-') - { - ++p; - end = skiptowhite(p); - if (uc_scan_attr(p, end - p, &argt, &def, &flags, &compl, - &compl_arg, &addr_type_arg) - == FAIL) - return; - p = skipwhite(end); - } - - /* Get the name (if any) and skip to the following argument */ - name = p; - if (ASCII_ISALPHA(*p)) - while (ASCII_ISALNUM(*p)) - ++p; - if (!ends_excmd(*p) && !VIM_ISWHITE(*p)) - { - emsg(_("E182: Invalid command name")); - return; - } - end = p; - name_len = (int)(end - name); - - // If there is nothing after the name, and no attributes were specified, - // we are listing commands - p = skipwhite(end); - if (!has_attr && ends_excmd(*p)) - { - uc_list(name, end - name); - } - else if (!ASCII_ISUPPER(*name)) - { - emsg(_("E183: User defined commands must start with an uppercase letter")); - return; - } - else if ((name_len == 1 && *name == 'X') - || (name_len <= 4 - && STRNCMP(name, "Next", name_len > 4 ? 4 : name_len) == 0)) - { - emsg(_("E841: Reserved name, cannot be used for user defined command")); - return; - } - else - uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg, - addr_type_arg, eap->forceit); -} - -/* - * ":comclear" - * Clear all user commands, global and for current buffer. - */ - void -ex_comclear(exarg_T *eap UNUSED) -{ - uc_clear(&ucmds); - uc_clear(&curbuf->b_ucmds); -} - -/* - * Clear all user commands for "gap". - */ - void -uc_clear(garray_T *gap) -{ - int i; - ucmd_T *cmd; - - for (i = 0; i < gap->ga_len; ++i) - { - cmd = USER_CMD_GA(gap, i); - vim_free(cmd->uc_name); - vim_free(cmd->uc_rep); -# if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) - vim_free(cmd->uc_compl_arg); -# endif - } - ga_clear(gap); -} - - static void -ex_delcommand(exarg_T *eap) -{ - int i = 0; - ucmd_T *cmd = NULL; - int cmp = -1; - garray_T *gap; - - gap = &curbuf->b_ucmds; - for (;;) - { - for (i = 0; i < gap->ga_len; ++i) - { - cmd = USER_CMD_GA(gap, i); - cmp = STRCMP(eap->arg, cmd->uc_name); - if (cmp <= 0) - break; - } - if (gap == &ucmds || cmp == 0) - break; - gap = &ucmds; - } - - if (cmp != 0) - { - semsg(_("E184: No such user-defined command: %s"), eap->arg); - return; - } - - vim_free(cmd->uc_name); - vim_free(cmd->uc_rep); -# if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) - vim_free(cmd->uc_compl_arg); -# endif - - --gap->ga_len; - - if (i < gap->ga_len) - mch_memmove(cmd, cmd + 1, (gap->ga_len - i) * sizeof(ucmd_T)); -} - -/* - * split and quote args for - */ - 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 () */ - /* 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 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 diff --git a/src/ex_getln.c b/src/ex_getln.c index e6bb815b45..b2b6f534a2 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -111,7 +111,7 @@ static int ExpandPackAddDir(char_u *pat, int *num_file, char_u ***file); # ifdef FEAT_CMDHIST static char_u *get_history_arg(expand_T *xp, int idx); # endif -# if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) +# 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,7 +939,7 @@ getcmdline_int( { xpc.xp_context = ccline.xp_context; xpc.xp_pattern = ccline.cmdbuff; -# if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL) +# if defined(FEAT_CMDL_COMPL) xpc.xp_arg = ccline.xp_arg; # endif } @@ -4210,7 +4210,7 @@ ExpandInit(expand_T *xp) #endif xp->xp_numfiles = -1; xp->xp_files = NULL; -#if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) +#if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) xp->xp_arg = NULL; #endif xp->xp_line = NULL; @@ -4879,7 +4879,7 @@ set_cmd_context( { xp->xp_context = ccline.xp_context; xp->xp_pattern = ccline.cmdbuff; -# if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL) +# if defined(FEAT_CMDL_COMPL) xp->xp_arg = ccline.xp_arg; # endif } @@ -5130,7 +5130,7 @@ ExpandFromContext( char *directories[] = {"syntax", "indent", "ftplugin", NULL}; return ExpandRTDir(pat, 0, num_file, file, directories); } -# if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) +# if defined(FEAT_EVAL) if (xp->xp_context == EXPAND_USER_LIST) return ExpandUserList(xp, num_file, file); # endif @@ -5149,7 +5149,7 @@ ExpandFromContext( 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) +# if defined(FEAT_EVAL) else if (xp->xp_context == EXPAND_USER_DEFINED) ret = ExpandUserDefined(xp, ®match, num_file, file); # endif @@ -5170,13 +5170,11 @@ ExpandFromContext( #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}, @@ -5473,7 +5471,7 @@ expand_shellcmd( } -# if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) +# 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). diff --git a/src/feature.h b/src/feature.h index b900569a59..95701a79a6 100644 --- a/src/feature.h +++ b/src/feature.h @@ -379,10 +379,8 @@ /* * +user_commands Allow the user to define his own commands. + * Now always enabled. */ -#ifdef FEAT_NORMAL -# define FEAT_USR_CMDS -#endif /* * +printer ":hardcopy" command diff --git a/src/macros.h b/src/macros.h index 571fed0a7e..8c0e04a56c 100644 --- a/src/macros.h +++ b/src/macros.h @@ -336,3 +336,6 @@ (p) = NULL; \ } \ } while (0) + +/* Wether a command index indicates a user command. */ +#define IS_USER_CMDIDX(idx) ((int)(idx) < 0) diff --git a/src/misc2.c b/src/misc2.c index 5c5c3ebded..79fe70255c 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -1082,10 +1082,8 @@ free_all_mem(void) ui_remove_balloon(); # endif -# if defined(FEAT_USR_CMDS) - /* Clear user commands (before deleting buffers). */ + // Clear user commands (before deleting buffers). ex_comclear(NULL); -# endif # ifdef FEAT_MENU /* Clear menus. */ @@ -1130,7 +1128,9 @@ free_all_mem(void) 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(); diff --git a/src/proto.h b/src/proto.h index 448233ad12..e34af85007 100644 --- a/src/proto.h +++ b/src/proto.h @@ -227,6 +227,7 @@ void qsort(void *base, size_t elm_count, size_t elm_size, int (*cmp)(const void # endif # include "ui.pro" # include "undo.pro" +# include "usercmd.pro" # include "userfunc.pro" # include "version.pro" # include "window.pro" diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro index 8f3852a4aa..710f48b781 100644 --- a/src/proto/ex_docmd.pro +++ b/src/proto/ex_docmd.pro @@ -19,16 +19,6 @@ int ends_excmd(int c); 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); diff --git a/src/proto/usercmd.pro b/src/proto/usercmd.pro new file mode 100644 index 0000000000..45ae3e7feb --- /dev/null +++ b/src/proto/usercmd.pro @@ -0,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 : */ diff --git a/src/structs.h b/src/structs.h index 104265ecc4..89749e5c21 100644 --- a/src/structs.h +++ b/src/structs.h @@ -549,7 +549,7 @@ typedef struct expand 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) +#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,10 +2143,8 @@ struct file_buffer /* First abbreviation local to a buffer. */ mapblock_T *b_first_abbr; #endif -#ifdef FEAT_USR_CMDS - /* User commands local to the buffer. */ + // User commands local to the buffer. garray_T b_ucmds; -#endif /* * start and end of an operator, also used for '[ and '] */ diff --git a/src/usercmd.c b/src/usercmd.c new file mode 100644 index 0000000000..737b2feef9 --- /dev/null +++ b/src/usercmd.c @@ -0,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 + */ + +#inc