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