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