Patch 8.1.1914
Problem:    Command line expansion code is spread out.
Solution:   Move set_one_cmd_context(). (Yegappan Lakshmanan, closes #4855)
Files:      src/cmdexpand.c, src/ex_docmd.c, src/proto/ex_docmd.pro


*** ../vim-8.1.1913/src/cmdexpand.c     2019-08-21 12:54:15.042419066 +0200
--- src/cmdexpand.c     2019-08-23 21:11:35.196716430 +0200
***************
*** 959,964 ****
--- 959,1770 ----
      set_cmd_context(xp, ccline->cmdbuff, ccline->cmdlen, ccline->cmdpos, 
TRUE);
  }
  
+ /*
+  * This is all pretty much copied from do_one_cmd(), with all the extra stuff
+  * we don't need/want deleted.        Maybe this could be done better if we 
didn't
+  * repeat all this stuff.  The only problem is that they may not stay
+  * perfectly compatible with each other, but then the command line syntax
+  * probably won't change that much -- webb.
+  */
+     static char_u *
+ set_one_cmd_context(
+     expand_T  *xp,
+     char_u    *buff)      // buffer for command string
+ {
+     char_u            *p;
+     char_u            *cmd, *arg;
+     int                       len = 0;
+     exarg_T           ea;
+     int                       compl = EXPAND_NOTHING;
+     int                       delim;
+     int                       forceit = FALSE;
+     int                       usefilter = FALSE;  // filter instead of file 
name
+ 
+     ExpandInit(xp);
+     xp->xp_pattern = buff;
+     xp->xp_context = EXPAND_COMMANDS; // Default until we get past command
+     ea.argt = 0;
+ 
+     // 1. skip comment lines and leading space, colons or bars
+     for (cmd = buff; vim_strchr((char_u *)" \t:|", *cmd) != NULL; cmd++)
+       ;
+     xp->xp_pattern = cmd;
+ 
+     if (*cmd == NUL)
+       return NULL;
+     if (*cmd == '"')      // ignore comment lines
+     {
+       xp->xp_context = EXPAND_NOTHING;
+       return NULL;
+     }
+ 
+     // 3. Skip over the range to find the command.
+     cmd = skip_range(cmd, &xp->xp_context);
+     xp->xp_pattern = cmd;
+     if (*cmd == NUL)
+       return NULL;
+     if (*cmd == '"')
+     {
+       xp->xp_context = EXPAND_NOTHING;
+       return NULL;
+     }
+ 
+     if (*cmd == '|' || *cmd == '\n')
+       return cmd + 1;                 // There's another command
+ 
+     // Isolate the command and search for it in the command table.
+     // Exceptions:
+     // - the 'k' command can directly be followed by any character, but
+     //   do accept "keepmarks", "keepalt" and "keepjumps".
+     // - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r'
+     if (*cmd == 'k' && cmd[1] != 'e')
+     {
+       ea.cmdidx = CMD_k;
+       p = cmd + 1;
+     }
+     else
+     {
+       p = cmd;
+       while (ASCII_ISALPHA(*p) || *p == '*')    // Allow * wild card
+           ++p;
+       // a user command may contain digits
+       if (ASCII_ISUPPER(cmd[0]))
+           while (ASCII_ISALNUM(*p) || *p == '*')
+               ++p;
+       // for python 3.x: ":py3*" commands completion
+       if (cmd[0] == 'p' && cmd[1] == 'y' && p == cmd + 2 && *p == '3')
+       {
+           ++p;
+           while (ASCII_ISALPHA(*p) || *p == '*')
+               ++p;
+       }
+       // check for non-alpha command
+       if (p == cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL)
+           ++p;
+       len = (int)(p - cmd);
+ 
+       if (len == 0)
+       {
+           xp->xp_context = EXPAND_UNSUCCESSFUL;
+           return NULL;
+       }
+ 
+       ea.cmdidx = excmd_get_cmdidx(cmd, len);
+ 
+       if (cmd[0] >= 'A' && cmd[0] <= 'Z')
+           while (ASCII_ISALNUM(*p) || *p == '*')      // Allow * wild card
+               ++p;
+     }
+ 
+     // If the cursor is touching the command, and it ends in an alpha-numeric
+     // character, complete the command name.
+     if (*p == NUL && ASCII_ISALNUM(p[-1]))
+       return NULL;
+ 
+     if (ea.cmdidx == CMD_SIZE)
+     {
+       if (*cmd == 's' && vim_strchr((char_u *)"cgriI", cmd[1]) != NULL)
+       {
+           ea.cmdidx = CMD_substitute;
+           p = cmd + 1;
+       }
+       else if (cmd[0] >= 'A' && cmd[0] <= 'Z')
+       {
+           ea.cmd = cmd;
+           p = find_ucmd(&ea, p, NULL, xp, &compl);
+           if (p == NULL)
+               ea.cmdidx = CMD_SIZE;   // ambiguous user command
+       }
+     }
+     if (ea.cmdidx == CMD_SIZE)
+     {
+       // Not still touching the command and it was an illegal one
+       xp->xp_context = EXPAND_UNSUCCESSFUL;
+       return NULL;
+     }
+ 
+     xp->xp_context = EXPAND_NOTHING; // Default now that we're past command
+ 
+     if (*p == '!')                // forced commands
+     {
+       forceit = TRUE;
+       ++p;
+     }
+ 
+     // 6. parse arguments
+     if (!IS_USER_CMDIDX(ea.cmdidx))
+       ea.argt = excmd_get_argt(ea.cmdidx);
+ 
+     arg = skipwhite(p);
+ 
+     if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update)
+     {
+       if (*arg == '>')                        // append
+       {
+           if (*++arg == '>')
+               ++arg;
+           arg = skipwhite(arg);
+       }
+       else if (*arg == '!' && ea.cmdidx == CMD_write) // :w !filter
+       {
+           ++arg;
+           usefilter = TRUE;
+       }
+     }
+ 
+     if (ea.cmdidx == CMD_read)
+     {
+       usefilter = forceit;                    // :r! filter if forced
+       if (*arg == '!')                        // :r !filter
+       {
+           ++arg;
+           usefilter = TRUE;
+       }
+     }
+ 
+     if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift)
+     {
+       while (*arg == *cmd)        // allow any number of '>' or '<'
+           ++arg;
+       arg = skipwhite(arg);
+     }
+ 
+     // Does command allow "+command"?
+     if ((ea.argt & EX_CMDARG) && !usefilter && *arg == '+')
+     {
+       // Check if we're in the +command
+       p = arg + 1;
+       arg = skip_cmd_arg(arg, FALSE);
+ 
+       // Still touching the command after '+'?
+       if (*arg == NUL)
+           return p;
+ 
+       // Skip space(s) after +command to get to the real argument
+       arg = skipwhite(arg);
+     }
+ 
+     // Check for '|' to separate commands and '"' to start comments.
+     // Don't do this for ":read !cmd" and ":write !cmd".
+     if ((ea.argt & EX_TRLBAR) && !usefilter)
+     {
+       p = arg;
+       // ":redir @" is not the start of a comment
+       if (ea.cmdidx == CMD_redir && p[0] == '@' && p[1] == '"')
+           p += 2;
+       while (*p)
+       {
+           if (*p == Ctrl_V)
+           {
+               if (p[1] != NUL)
+                   ++p;
+           }
+           else if ( (*p == '"' && !(ea.argt & EX_NOTRLCOM))
+                   || *p == '|' || *p == '\n')
+           {
+               if (*(p - 1) != '\\')
+               {
+                   if (*p == '|' || *p == '\n')
+                       return p + 1;
+                   return NULL;    // It's a comment
+               }
+           }
+           MB_PTR_ADV(p);
+       }
+     }
+ 
+     if (!(ea.argt & EX_EXTRA) && *arg != NUL
+                                 && vim_strchr((char_u *)"|\"", *arg) == NULL)
+       // no arguments allowed but there is something
+       return NULL;
+ 
+     // Find start of last argument (argument just before cursor):
+     p = buff;
+     xp->xp_pattern = p;
+     len = (int)STRLEN(buff);
+     while (*p && p < buff + len)
+     {
+       if (*p == ' ' || *p == TAB)
+       {
+           // argument starts after a space
+           xp->xp_pattern = ++p;
+       }
+       else
+       {
+           if (*p == '\\' && *(p + 1) != NUL)
+               ++p; // skip over escaped character
+           MB_PTR_ADV(p);
+       }
+     }
+ 
+     if (ea.argt & EX_XFILE)
+     {
+       int     c;
+       int     in_quote = FALSE;
+       char_u  *bow = NULL;    // Beginning of word
+ 
+       // Allow spaces within back-quotes to count as part of the argument
+       // being expanded.
+       xp->xp_pattern = skipwhite(arg);
+       p = xp->xp_pattern;
+       while (*p != NUL)
+       {
+           if (has_mbyte)
+               c = mb_ptr2char(p);
+           else
+               c = *p;
+           if (c == '\\' && p[1] != NUL)
+               ++p;
+           else if (c == '`')
+           {
+               if (!in_quote)
+               {
+                   xp->xp_pattern = p;
+                   bow = p + 1;
+               }
+               in_quote = !in_quote;
+           }
+           // An argument can contain just about everything, except
+           // characters that end the command and white space.
+           else if (c == '|' || c == '\n' || c == '"' || (VIM_ISWHITE(c)
+ #ifdef SPACE_IN_FILENAME
+                                       && (!(ea.argt & EX_NOSPC) || usefilter)
+ #endif
+                   ))
+           {
+               len = 0;  // avoid getting stuck when space is in 'isfname'
+               while (*p != NUL)
+               {
+                   if (has_mbyte)
+                       c = mb_ptr2char(p);
+                   else
+                       c = *p;
+                   if (c == '`' || vim_isfilec_or_wc(c))
+                       break;
+                   if (has_mbyte)
+                       len = (*mb_ptr2len)(p);
+                   else
+                       len = 1;
+                   MB_PTR_ADV(p);
+               }
+               if (in_quote)
+                   bow = p;
+               else
+                   xp->xp_pattern = p;
+               p -= len;
+           }
+           MB_PTR_ADV(p);
+       }
+ 
+       // If we are still inside the quotes, and we passed a space, just
+       // expand from there.
+       if (bow != NULL && in_quote)
+           xp->xp_pattern = bow;
+       xp->xp_context = EXPAND_FILES;
+ 
+       // For a shell command more chars need to be escaped.
+       if (usefilter || ea.cmdidx == CMD_bang || ea.cmdidx == CMD_terminal)
+       {
+ #ifndef BACKSLASH_IN_FILENAME
+           xp->xp_shell = TRUE;
+ #endif
+           // When still after the command name expand executables.
+           if (xp->xp_pattern == skipwhite(arg))
+               xp->xp_context = EXPAND_SHELLCMD;
+       }
+ 
+       // Check for environment variable
+       if (*xp->xp_pattern == '$'
+ #if defined(MSWIN)
+               || *xp->xp_pattern == '%'
+ #endif
+               )
+       {
+           for (p = xp->xp_pattern + 1; *p != NUL; ++p)
+               if (!vim_isIDc(*p))
+                   break;
+           if (*p == NUL)
+           {
+               xp->xp_context = EXPAND_ENV_VARS;
+               ++xp->xp_pattern;
+               // Avoid that the assignment uses EXPAND_FILES again.
+               if (compl != EXPAND_USER_DEFINED && compl != EXPAND_USER_LIST)
+                   compl = EXPAND_ENV_VARS;
+           }
+       }
+       // Check for user names
+       if (*xp->xp_pattern == '~')
+       {
+           for (p = xp->xp_pattern + 1; *p != NUL && *p != '/'; ++p)
+               ;
+           // Complete ~user only if it partially matches a user name.
+           // A full match ~user<Tab> will be replaced by user's home
+           // directory i.e. something like ~user<Tab> -> /home/user/
+           if (*p == NUL && p > xp->xp_pattern + 1
+                                      && match_user(xp->xp_pattern + 1) >= 1)
+           {
+               xp->xp_context = EXPAND_USER;
+               ++xp->xp_pattern;
+           }
+       }
+     }
+ 
+     // 6. Switch on command name.
+     switch (ea.cmdidx)
+     {
+       case CMD_find:
+       case CMD_sfind:
+       case CMD_tabfind:
+           if (xp->xp_context == EXPAND_FILES)
+               xp->xp_context = EXPAND_FILES_IN_PATH;
+           break;
+       case CMD_cd:
+       case CMD_chdir:
+       case CMD_tcd:
+       case CMD_tchdir:
+       case CMD_lcd:
+       case CMD_lchdir:
+           if (xp->xp_context == EXPAND_FILES)
+               xp->xp_context = EXPAND_DIRECTORIES;
+           break;
+       case CMD_help:
+           xp->xp_context = EXPAND_HELP;
+           xp->xp_pattern = arg;
+           break;
+ 
+       // Command modifiers: return the argument.
+       // Also for commands with an argument that is a command.
+       case CMD_aboveleft:
+       case CMD_argdo:
+       case CMD_belowright:
+       case CMD_botright:
+       case CMD_browse:
+       case CMD_bufdo:
+       case CMD_cdo:
+       case CMD_cfdo:
+       case CMD_confirm:
+       case CMD_debug:
+       case CMD_folddoclosed:
+       case CMD_folddoopen:
+       case CMD_hide:
+       case CMD_keepalt:
+       case CMD_keepjumps:
+       case CMD_keepmarks:
+       case CMD_keeppatterns:
+       case CMD_ldo:
+       case CMD_leftabove:
+       case CMD_lfdo:
+       case CMD_lockmarks:
+       case CMD_noautocmd:
+       case CMD_noswapfile:
+       case CMD_rightbelow:
+       case CMD_sandbox:
+       case CMD_silent:
+       case CMD_tab:
+       case CMD_tabdo:
+       case CMD_topleft:
+       case CMD_verbose:
+       case CMD_vertical:
+       case CMD_windo:
+           return arg;
+ 
+       case CMD_filter:
+           if (*arg != NUL)
+               arg = skip_vimgrep_pat(arg, NULL, NULL);
+           if (arg == NULL || *arg == NUL)
+           {
+               xp->xp_context = EXPAND_NOTHING;
+               return NULL;
+           }
+           return skipwhite(arg);
+ 
+ #ifdef FEAT_SEARCH_EXTRA
+       case CMD_match:
+           if (*arg == NUL || !ends_excmd(*arg))
+           {
+               // also complete "None"
+               set_context_in_echohl_cmd(xp, arg);
+               arg = skipwhite(skiptowhite(arg));
+               if (*arg != NUL)
+               {
+                   xp->xp_context = EXPAND_NOTHING;
+                   arg = skip_regexp(arg + 1, *arg, p_magic, NULL);
+               }
+           }
+           return find_nextcmd(arg);
+ #endif
+ 
+       // All completion for the +cmdline_compl feature goes here.
+ 
+       case CMD_command:
+           return set_context_in_user_cmd(xp, arg);
+ 
+       case CMD_delcommand:
+           xp->xp_context = EXPAND_USER_COMMANDS;
+           xp->xp_pattern = arg;
+           break;
+ 
+       case CMD_global:
+       case CMD_vglobal:
+           delim = *arg;           // get the delimiter
+           if (delim)
+               ++arg;              // skip delimiter if there is one
+ 
+           while (arg[0] != NUL && arg[0] != delim)
+           {
+               if (arg[0] == '\\' && arg[1] != NUL)
+                   ++arg;
+               ++arg;
+           }
+           if (arg[0] != NUL)
+               return arg + 1;
+           break;
+       case CMD_and:
+       case CMD_substitute:
+           delim = *arg;
+           if (delim)
+           {
+               // skip "from" part
+               ++arg;
+               arg = skip_regexp(arg, delim, p_magic, NULL);
+           }
+           // skip "to" part
+           while (arg[0] != NUL && arg[0] != delim)
+           {
+               if (arg[0] == '\\' && arg[1] != NUL)
+                   ++arg;
+               ++arg;
+           }
+           if (arg[0] != NUL)  // skip delimiter
+               ++arg;
+           while (arg[0] && vim_strchr((char_u *)"|\"#", arg[0]) == NULL)
+               ++arg;
+           if (arg[0] != NUL)
+               return arg;
+           break;
+       case CMD_isearch:
+       case CMD_dsearch:
+       case CMD_ilist:
+       case CMD_dlist:
+       case CMD_ijump:
+       case CMD_psearch:
+       case CMD_djump:
+       case CMD_isplit:
+       case CMD_dsplit:
+           arg = skipwhite(skipdigits(arg));       // skip count
+           if (*arg == '/')    // Match regexp, not just whole words
+           {
+               for (++arg; *arg && *arg != '/'; arg++)
+                   if (*arg == '\\' && arg[1] != NUL)
+                       arg++;
+               if (*arg)
+               {
+                   arg = skipwhite(arg + 1);
+ 
+                   // Check for trailing illegal characters
+                   if (*arg && vim_strchr((char_u *)"|\"\n", *arg) == NULL)
+                       xp->xp_context = EXPAND_NOTHING;
+                   else
+                       return arg;
+               }
+           }
+           break;
+ 
+       case CMD_autocmd:
+           return set_context_in_autocmd(xp, arg, FALSE);
+       case CMD_doautocmd:
+       case CMD_doautoall:
+           return set_context_in_autocmd(xp, arg, TRUE);
+       case CMD_set:
+           set_context_in_set_cmd(xp, arg, 0);
+           break;
+       case CMD_setglobal:
+           set_context_in_set_cmd(xp, arg, OPT_GLOBAL);
+           break;
+       case CMD_setlocal:
+           set_context_in_set_cmd(xp, arg, OPT_LOCAL);
+           break;
+       case CMD_tag:
+       case CMD_stag:
+       case CMD_ptag:
+       case CMD_ltag:
+       case CMD_tselect:
+       case CMD_stselect:
+       case CMD_ptselect:
+       case CMD_tjump:
+       case CMD_stjump:
+       case CMD_ptjump:
+           if (*p_wop != NUL)
+               xp->xp_context = EXPAND_TAGS_LISTFILES;
+           else
+               xp->xp_context = EXPAND_TAGS;
+           xp->xp_pattern = arg;
+           break;
+       case CMD_augroup:
+           xp->xp_context = EXPAND_AUGROUP;
+           xp->xp_pattern = arg;
+           break;
+ #ifdef FEAT_SYN_HL
+       case CMD_syntax:
+           set_context_in_syntax_cmd(xp, arg);
+           break;
+ #endif
+ #ifdef FEAT_EVAL
+       case CMD_let:
+       case CMD_if:
+       case CMD_elseif:
+       case CMD_while:
+       case CMD_for:
+       case CMD_echo:
+       case CMD_echon:
+       case CMD_execute:
+       case CMD_echomsg:
+       case CMD_echoerr:
+       case CMD_call:
+       case CMD_return:
+       case CMD_cexpr:
+       case CMD_caddexpr:
+       case CMD_cgetexpr:
+       case CMD_lexpr:
+       case CMD_laddexpr:
+       case CMD_lgetexpr:
+           set_context_for_expression(xp, arg, ea.cmdidx);
+           break;
+ 
+       case CMD_unlet:
+           while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL)
+               arg = xp->xp_pattern + 1;
+ 
+           xp->xp_context = EXPAND_USER_VARS;
+           xp->xp_pattern = arg;
+ 
+           if (*xp->xp_pattern == '$')
+           {
+               xp->xp_context = EXPAND_ENV_VARS;
+               ++xp->xp_pattern;
+           }
+ 
+           break;
+ 
+       case CMD_function:
+       case CMD_delfunction:
+           xp->xp_context = EXPAND_USER_FUNC;
+           xp->xp_pattern = arg;
+           break;
+ 
+       case CMD_echohl:
+           set_context_in_echohl_cmd(xp, arg);
+           break;
+ #endif
+       case CMD_highlight:
+           set_context_in_highlight_cmd(xp, arg);
+           break;
+ #ifdef FEAT_CSCOPE
+       case CMD_cscope:
+       case CMD_lcscope:
+       case CMD_scscope:
+           set_context_in_cscope_cmd(xp, arg, ea.cmdidx);
+           break;
+ #endif
+ #ifdef FEAT_SIGNS
+       case CMD_sign:
+           set_context_in_sign_cmd(xp, arg);
+           break;
+ #endif
+       case CMD_bdelete:
+       case CMD_bwipeout:
+       case CMD_bunload:
+           while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL)
+               arg = xp->xp_pattern + 1;
+           // FALLTHROUGH
+       case CMD_buffer:
+       case CMD_sbuffer:
+       case CMD_checktime:
+           xp->xp_context = EXPAND_BUFFERS;
+           xp->xp_pattern = arg;
+           break;
+ 
+       case CMD_USER:
+       case CMD_USER_BUF:
+           if (compl != EXPAND_NOTHING)
+           {
+               // EX_XFILE: file names are handled above
+               if (!(ea.argt & EX_XFILE))
+               {
+ #ifdef FEAT_MENU
+                   if (compl == EXPAND_MENUS)
+                       return set_context_in_menu_cmd(xp, cmd, arg, forceit);
+ #endif
+                   if (compl == EXPAND_COMMANDS)
+                       return arg;
+                   if (compl == EXPAND_MAPPINGS)
+                       return set_context_in_map_cmd(xp, (char_u *)"map",
+                                        arg, forceit, FALSE, FALSE, CMD_map);
+                   // Find start of last argument.
+                   p = arg;
+                   while (*p)
+                   {
+                       if (*p == ' ')
+                           // argument starts after a space
+                           arg = p + 1;
+                       else if (*p == '\\' && *(p + 1) != NUL)
+                           ++p; // skip over escaped character
+                       MB_PTR_ADV(p);
+                   }
+                   xp->xp_pattern = arg;
+               }
+               xp->xp_context = compl;
+           }
+           break;
+ 
+       case CMD_map:       case CMD_noremap:
+       case CMD_nmap:      case CMD_nnoremap:
+       case CMD_vmap:      case CMD_vnoremap:
+       case CMD_omap:      case CMD_onoremap:
+       case CMD_imap:      case CMD_inoremap:
+       case CMD_cmap:      case CMD_cnoremap:
+       case CMD_lmap:      case CMD_lnoremap:
+       case CMD_smap:      case CMD_snoremap:
+       case CMD_tmap:      case CMD_tnoremap:
+       case CMD_xmap:      case CMD_xnoremap:
+           return set_context_in_map_cmd(xp, cmd, arg, forceit,
+                                                    FALSE, FALSE, ea.cmdidx);
+       case CMD_unmap:
+       case CMD_nunmap:
+       case CMD_vunmap:
+       case CMD_ounmap:
+       case CMD_iunmap:
+       case CMD_cunmap:
+       case CMD_lunmap:
+       case CMD_sunmap:
+       case CMD_tunmap:
+       case CMD_xunmap:
+           return set_context_in_map_cmd(xp, cmd, arg, forceit,
+                                                     FALSE, TRUE, ea.cmdidx);
+       case CMD_mapclear:
+       case CMD_nmapclear:
+       case CMD_vmapclear:
+       case CMD_omapclear:
+       case CMD_imapclear:
+       case CMD_cmapclear:
+       case CMD_lmapclear:
+       case CMD_smapclear:
+       case CMD_tmapclear:
+       case CMD_xmapclear:
+           xp->xp_context = EXPAND_MAPCLEAR;
+           xp->xp_pattern = arg;
+           break;
+ 
+       case CMD_abbreviate:    case CMD_noreabbrev:
+       case CMD_cabbrev:       case CMD_cnoreabbrev:
+       case CMD_iabbrev:       case CMD_inoreabbrev:
+           return set_context_in_map_cmd(xp, cmd, arg, forceit,
+                                                     TRUE, FALSE, ea.cmdidx);
+       case CMD_unabbreviate:
+       case CMD_cunabbrev:
+       case CMD_iunabbrev:
+           return set_context_in_map_cmd(xp, cmd, arg, forceit,
+                                                      TRUE, TRUE, ea.cmdidx);
+ #ifdef FEAT_MENU
+       case CMD_menu:      case CMD_noremenu:      case CMD_unmenu:
+       case CMD_amenu:     case CMD_anoremenu:     case CMD_aunmenu:
+       case CMD_nmenu:     case CMD_nnoremenu:     case CMD_nunmenu:
+       case CMD_vmenu:     case CMD_vnoremenu:     case CMD_vunmenu:
+       case CMD_omenu:     case CMD_onoremenu:     case CMD_ounmenu:
+       case CMD_imenu:     case CMD_inoremenu:     case CMD_iunmenu:
+       case CMD_cmenu:     case CMD_cnoremenu:     case CMD_cunmenu:
+       case CMD_tlmenu:    case CMD_tlnoremenu:    case CMD_tlunmenu:
+       case CMD_tmenu:                             case CMD_tunmenu:
+       case CMD_popup:     case CMD_tearoff:       case CMD_emenu:
+           return set_context_in_menu_cmd(xp, cmd, arg, forceit);
+ #endif
+ 
+       case CMD_colorscheme:
+           xp->xp_context = EXPAND_COLORS;
+           xp->xp_pattern = arg;
+           break;
+ 
+       case CMD_compiler:
+           xp->xp_context = EXPAND_COMPILER;
+           xp->xp_pattern = arg;
+           break;
+ 
+       case CMD_ownsyntax:
+           xp->xp_context = EXPAND_OWNSYNTAX;
+           xp->xp_pattern = arg;
+           break;
+ 
+       case CMD_setfiletype:
+           xp->xp_context = EXPAND_FILETYPE;
+           xp->xp_pattern = arg;
+           break;
+ 
+       case CMD_packadd:
+           xp->xp_context = EXPAND_PACKADD;
+           xp->xp_pattern = arg;
+           break;
+ 
+ #if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+       case CMD_language:
+           p = skiptowhite(arg);
+           if (*p == NUL)
+           {
+               xp->xp_context = EXPAND_LANGUAGE;
+               xp->xp_pattern = arg;
+           }
+           else
+           {
+               if ( STRNCMP(arg, "messages", p - arg) == 0
+                 || STRNCMP(arg, "ctype", p - arg) == 0
+                 || STRNCMP(arg, "time", p - arg) == 0)
+               {
+                   xp->xp_context = EXPAND_LOCALES;
+                   xp->xp_pattern = skipwhite(p);
+               }
+               else
+                   xp->xp_context = EXPAND_NOTHING;
+           }
+           break;
+ #endif
+ #if defined(FEAT_PROFILE)
+       case CMD_profile:
+           set_context_in_profile_cmd(xp, arg);
+           break;
+ #endif
+       case CMD_behave:
+           xp->xp_context = EXPAND_BEHAVE;
+           xp->xp_pattern = arg;
+           break;
+ 
+       case CMD_messages:
+           xp->xp_context = EXPAND_MESSAGES;
+           xp->xp_pattern = arg;
+           break;
+ 
+       case CMD_history:
+           xp->xp_context = EXPAND_HISTORY;
+           xp->xp_pattern = arg;
+           break;
+ #if defined(FEAT_PROFILE)
+       case CMD_syntime:
+           xp->xp_context = EXPAND_SYNTIME;
+           xp->xp_pattern = arg;
+           break;
+ #endif
+ 
+       case CMD_argdelete:
+           while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL)
+               arg = xp->xp_pattern + 1;
+           xp->xp_context = EXPAND_ARGLIST;
+           xp->xp_pattern = arg;
+           break;
+ 
+       default:
+           break;
+     }
+     return NULL;
+ }
+ 
      void
  set_cmd_context(
      expand_T  *xp,
***************
*** 1115,1120 ****
--- 1921,1960 ----
  #endif
  
  /*
+  * Function given to ExpandGeneric() to obtain the possible arguments of the
+  * ":behave {mswin,xterm}" command.
+  */
+     static char_u *
+ get_behave_arg(expand_T *xp UNUSED, int idx)
+ {
+     if (idx == 0)
+       return (char_u *)"mswin";
+     if (idx == 1)
+       return (char_u *)"xterm";
+     return NULL;
+ }
+ 
+ /*
+  * Function given to ExpandGeneric() to obtain the possible arguments of the
+  * ":messages {clear}" command.
+  */
+     static char_u *
+ get_messages_arg(expand_T *xp UNUSED, int idx)
+ {
+     if (idx == 0)
+       return (char_u *)"clear";
+     return NULL;
+ }
+ 
+     static char_u *
+ get_mapclear_arg(expand_T *xp UNUSED, int idx)
+ {
+     if (idx == 0)
+       return (char_u *)"<buffer>";
+     return NULL;
+ }
+ 
+ /*
   * Do the expansion based on xp->xp_context and "pat".
   */
      static int
*** ../vim-8.1.1913/src/ex_docmd.c      2019-08-21 22:25:26.034016761 +0200
--- src/ex_docmd.c      2019-08-23 21:11:35.196716430 +0200
***************
*** 44,50 ****
  static void   ex_brewind(exarg_T *eap);
  static void   ex_blast(exarg_T *eap);
  static char_u *getargcmd(char_u **);
- static char_u *skip_cmd_arg(char_u *p, int rembs);
  static int    getargopt(exarg_T *eap);
  #ifndef FEAT_QUICKFIX
  # define ex_make              ex_ni
--- 44,49 ----
***************
*** 3307,4139 ****
  }
  #endif
  
! /*
!  * This is all pretty much copied from do_one_cmd(), with all the extra stuff
!  * we don't need/want deleted.        Maybe this could be done better if we 
didn't
!  * repeat all this stuff.  The only problem is that they may not stay
!  * perfectly compatible with each other, but then the command line syntax
!  * probably won't change that much -- webb.
!  */
!     char_u *
! set_one_cmd_context(
!     expand_T  *xp,
!     char_u    *buff)      /* buffer for command string */
  {
!     char_u            *p;
!     char_u            *cmd, *arg;
!     int                       len = 0;
!     exarg_T           ea;
!     int                       compl = EXPAND_NOTHING;
!     int                       delim;
!     int                       forceit = FALSE;
!     int                       usefilter = FALSE;  /* filter instead of file 
name */
! 
!     ExpandInit(xp);
!     xp->xp_pattern = buff;
!     xp->xp_context = EXPAND_COMMANDS; /* Default until we get past command */
!     ea.argt = 0;
! 
! /*
!  * 1. skip comment lines and leading space, colons or bars
!  */
!     for (cmd = buff; vim_strchr((char_u *)" \t:|", *cmd) != NULL; cmd++)
!       ;
!     xp->xp_pattern = cmd;
! 
!     if (*cmd == NUL)
!       return NULL;
!     if (*cmd == '"')      /* ignore comment lines */
!     {
!       xp->xp_context = EXPAND_NOTHING;
!       return NULL;
!     }
! 
! /*
!  * 3. Skip over the range to find the command.
!  */
!     cmd = skip_range(cmd, &xp->xp_context);
!     xp->xp_pattern = cmd;
!     if (*cmd == NUL)
!       return NULL;
!     if (*cmd == '"')
!     {
!       xp->xp_context = EXPAND_NOTHING;
!       return NULL;
!     }
! 
!     if (*cmd == '|' || *cmd == '\n')
!       return cmd + 1;                 /* There's another command */
! 
!     /*
!      * Isolate the command and search for it in the command table.
!      * Exceptions:
!      * - the 'k' command can directly be followed by any character, but
!      *   do accept "keepmarks", "keepalt" and "keepjumps".
!      * - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r'
!      */
!     if (*cmd == 'k' && cmd[1] != 'e')
!     {
!       ea.cmdidx = CMD_k;
!       p = cmd + 1;
!     }
!     else
!     {
!       p = cmd;
!       while (ASCII_ISALPHA(*p) || *p == '*')    /* Allow * wild card */
!           ++p;
!       /* a user command may contain digits */
!       if (ASCII_ISUPPER(cmd[0]))
!           while (ASCII_ISALNUM(*p) || *p == '*')
!               ++p;
!       /* for python 3.x: ":py3*" commands completion */
!       if (cmd[0] == 'p' && cmd[1] == 'y' && p == cmd + 2 && *p == '3')
!       {
!           ++p;
!           while (ASCII_ISALPHA(*p) || *p == '*')
!               ++p;
!       }
!       /* check for non-alpha command */
!       if (p == cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL)
!           ++p;
!       len = (int)(p - cmd);
! 
!       if (len == 0)
!       {
!           xp->xp_context = EXPAND_UNSUCCESSFUL;
!           return NULL;
!       }
!       for (ea.cmdidx = (cmdidx_T)0; (int)ea.cmdidx < (int)CMD_SIZE;
!                                  ea.cmdidx = (cmdidx_T)((int)ea.cmdidx + 1))
!           if (STRNCMP(cmdnames[(int)ea.cmdidx].cmd_name, cmd,
!                                                           (size_t)len) == 0)
!               break;
! 
!       if (cmd[0] >= 'A' && cmd[0] <= 'Z')
!           while (ASCII_ISALNUM(*p) || *p == '*')      // Allow * wild card
!               ++p;
!     }
! 
!     /*
!      * If the cursor is touching the command, and it ends in an alpha-numeric
!      * character, complete the command name.
!      */
!     if (*p == NUL && ASCII_ISALNUM(p[-1]))
!       return NULL;
! 
!     if (ea.cmdidx == CMD_SIZE)
!     {
!       if (*cmd == 's' && vim_strchr((char_u *)"cgriI", cmd[1]) != NULL)
!       {
!           ea.cmdidx = CMD_substitute;
!           p = cmd + 1;
!       }
!       else if (cmd[0] >= 'A' && cmd[0] <= 'Z')
!       {
!           ea.cmd = cmd;
!           p = find_ucmd(&ea, p, NULL, xp, &compl);
!           if (p == NULL)
!               ea.cmdidx = CMD_SIZE;   // ambiguous user command
!       }
!     }
!     if (ea.cmdidx == CMD_SIZE)
!     {
!       /* Not still touching the command and it was an illegal one */
!       xp->xp_context = EXPAND_UNSUCCESSFUL;
!       return NULL;
!     }
! 
!     xp->xp_context = EXPAND_NOTHING; /* Default now that we're past command */
! 
!     if (*p == '!')                /* forced commands */
!     {
!       forceit = TRUE;
!       ++p;
!     }
! 
! /*
!  * 6. parse arguments
!  */
!     if (!IS_USER_CMDIDX(ea.cmdidx))
!       ea.argt = (long)cmdnames[(int)ea.cmdidx].cmd_argt;
! 
!     arg = skipwhite(p);
! 
!     if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update)
!     {
!       if (*arg == '>')                        /* append */
!       {
!           if (*++arg == '>')
!               ++arg;
!           arg = skipwhite(arg);
!       }
!       else if (*arg == '!' && ea.cmdidx == CMD_write) /* :w !filter */
!       {
!           ++arg;
!           usefilter = TRUE;
!       }
!     }
! 
!     if (ea.cmdidx == CMD_read)
!     {
!       usefilter = forceit;                    /* :r! filter if forced */
!       if (*arg == '!')                        /* :r !filter */
!       {
!           ++arg;
!           usefilter = TRUE;
!       }
!     }
! 
!     if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift)
!     {
!       while (*arg == *cmd)        /* allow any number of '>' or '<' */
!           ++arg;
!       arg = skipwhite(arg);
!     }
! 
!     /* Does command allow "+command"? */
!     if ((ea.argt & EX_CMDARG) && !usefilter && *arg == '+')
!     {
!       /* Check if we're in the +command */
!       p = arg + 1;
!       arg = skip_cmd_arg(arg, FALSE);
! 
!       /* Still touching the command after '+'? */
!       if (*arg == NUL)
!           return p;
! 
!       /* Skip space(s) after +command to get to the real argument */
!       arg = skipwhite(arg);
!     }
! 
!     /*
!      * Check for '|' to separate commands and '"' to start comments.
!      * Don't do this for ":read !cmd" and ":write !cmd".
!      */
!     if ((ea.argt & EX_TRLBAR) && !usefilter)
!     {
!       p = arg;
!       /* ":redir @" is not the start of a comment */
!       if (ea.cmdidx == CMD_redir && p[0] == '@' && p[1] == '"')
!           p += 2;
!       while (*p)
!       {
!           if (*p == Ctrl_V)
!           {
!               if (p[1] != NUL)
!                   ++p;
!           }
!           else if ( (*p == '"' && !(ea.argt & EX_NOTRLCOM))
!                   || *p == '|' || *p == '\n')
!           {
!               if (*(p - 1) != '\\')
!               {
!                   if (*p == '|' || *p == '\n')
!                       return p + 1;
!                   return NULL;    /* It's a comment */
!               }
!           }
!           MB_PTR_ADV(p);
!       }
!     }
! 
!     if (!(ea.argt & EX_EXTRA) && *arg != NUL
!                                 && vim_strchr((char_u *)"|\"", *arg) == NULL)
!       // no arguments allowed but there is something
!       return NULL;
! 
!     /* Find start of last argument (argument just before cursor): */
!     p = buff;
!     xp->xp_pattern = p;
!     len = (int)STRLEN(buff);
!     while (*p && p < buff + len)
!     {
!       if (*p == ' ' || *p == TAB)
!       {
!           /* argument starts after a space */
!           xp->xp_pattern = ++p;
!       }
!       else
!       {
!           if (*p == '\\' && *(p + 1) != NUL)
!               ++p; /* skip over escaped character */
!           MB_PTR_ADV(p);
!       }
!     }
! 
!     if (ea.argt & EX_XFILE)
!     {
!       int     c;
!       int     in_quote = FALSE;
!       char_u  *bow = NULL;    /* Beginning of word */
! 
!       /*
!        * Allow spaces within back-quotes to count as part of the argument
!        * being expanded.
!        */
!       xp->xp_pattern = skipwhite(arg);
!       p = xp->xp_pattern;
!       while (*p != NUL)
!       {
!           if (has_mbyte)
!               c = mb_ptr2char(p);
!           else
!               c = *p;
!           if (c == '\\' && p[1] != NUL)
!               ++p;
!           else if (c == '`')
!           {
!               if (!in_quote)
!               {
!                   xp->xp_pattern = p;
!                   bow = p + 1;
!               }
!               in_quote = !in_quote;
!           }
!           /* An argument can contain just about everything, except
!            * characters that end the command and white space. */
!           else if (c == '|' || c == '\n' || c == '"' || (VIM_ISWHITE(c)
! #ifdef SPACE_IN_FILENAME
!                                       && (!(ea.argt & EX_NOSPC) || usefilter)
! #endif
!                   ))
!           {
!               len = 0;  /* avoid getting stuck when space is in 'isfname' */
!               while (*p != NUL)
!               {
!                   if (has_mbyte)
!                       c = mb_ptr2char(p);
!                   else
!                       c = *p;
!                   if (c == '`' || vim_isfilec_or_wc(c))
!                       break;
!                   if (has_mbyte)
!                       len = (*mb_ptr2len)(p);
!                   else
!                       len = 1;
!                   MB_PTR_ADV(p);
!               }
!               if (in_quote)
!                   bow = p;
!               else
!                   xp->xp_pattern = p;
!               p -= len;
!           }
!           MB_PTR_ADV(p);
!       }
! 
!       /*
!        * If we are still inside the quotes, and we passed a space, just
!        * expand from there.
!        */
!       if (bow != NULL && in_quote)
!           xp->xp_pattern = bow;
!       xp->xp_context = EXPAND_FILES;
! 
!       /* For a shell command more chars need to be escaped. */
!       if (usefilter || ea.cmdidx == CMD_bang || ea.cmdidx == CMD_terminal)
!       {
! #ifndef BACKSLASH_IN_FILENAME
!           xp->xp_shell = TRUE;
! #endif
!           /* When still after the command name expand executables. */
!           if (xp->xp_pattern == skipwhite(arg))
!               xp->xp_context = EXPAND_SHELLCMD;
!       }
! 
!       /* Check for environment variable */
!       if (*xp->xp_pattern == '$'
! #if defined(MSWIN)
!               || *xp->xp_pattern == '%'
! #endif
!               )
!       {
!           for (p = xp->xp_pattern + 1; *p != NUL; ++p)
!               if (!vim_isIDc(*p))
!                   break;
!           if (*p == NUL)
!           {
!               xp->xp_context = EXPAND_ENV_VARS;
!               ++xp->xp_pattern;
!               /* Avoid that the assignment uses EXPAND_FILES again. */
!               if (compl != EXPAND_USER_DEFINED && compl != EXPAND_USER_LIST)
!                   compl = EXPAND_ENV_VARS;
!           }
!       }
!       /* Check for user names */
!       if (*xp->xp_pattern == '~')
!       {
!           for (p = xp->xp_pattern + 1; *p != NUL && *p != '/'; ++p)
!               ;
!           /* Complete ~user only if it partially matches a user name.
!            * A full match ~user<Tab> will be replaced by user's home
!            * directory i.e. something like ~user<Tab> -> /home/user/ */
!           if (*p == NUL && p > xp->xp_pattern + 1
!                                      && match_user(xp->xp_pattern + 1) >= 1)
!           {
!               xp->xp_context = EXPAND_USER;
!               ++xp->xp_pattern;
!           }
!       }
!     }
! 
! /*
!  * 6. Switch on command name.
!  */
!     switch (ea.cmdidx)
!     {
!       case CMD_find:
!       case CMD_sfind:
!       case CMD_tabfind:
!           if (xp->xp_context == EXPAND_FILES)
!               xp->xp_context = EXPAND_FILES_IN_PATH;
!           break;
!       case CMD_cd:
!       case CMD_chdir:
!       case CMD_tcd:
!       case CMD_tchdir:
!       case CMD_lcd:
!       case CMD_lchdir:
!           if (xp->xp_context == EXPAND_FILES)
!               xp->xp_context = EXPAND_DIRECTORIES;
!           break;
!       case CMD_help:
!           xp->xp_context = EXPAND_HELP;
!           xp->xp_pattern = arg;
!           break;
! 
!       /* Command modifiers: return the argument.
!        * Also for commands with an argument that is a command. */
!       case CMD_aboveleft:
!       case CMD_argdo:
!       case CMD_belowright:
!       case CMD_botright:
!       case CMD_browse:
!       case CMD_bufdo:
!       case CMD_cdo:
!       case CMD_cfdo:
!       case CMD_confirm:
!       case CMD_debug:
!       case CMD_folddoclosed:
!       case CMD_folddoopen:
!       case CMD_hide:
!       case CMD_keepalt:
!       case CMD_keepjumps:
!       case CMD_keepmarks:
!       case CMD_keeppatterns:
!       case CMD_ldo:
!       case CMD_leftabove:
!       case CMD_lfdo:
!       case CMD_lockmarks:
!       case CMD_noautocmd:
!       case CMD_noswapfile:
!       case CMD_rightbelow:
!       case CMD_sandbox:
!       case CMD_silent:
!       case CMD_tab:
!       case CMD_tabdo:
!       case CMD_topleft:
!       case CMD_verbose:
!       case CMD_vertical:
!       case CMD_windo:
!           return arg;
! 
!       case CMD_filter:
!           if (*arg != NUL)
!               arg = skip_vimgrep_pat(arg, NULL, NULL);
!           if (arg == NULL || *arg == NUL)
!           {
!               xp->xp_context = EXPAND_NOTHING;
!               return NULL;
!           }
!           return skipwhite(arg);
! 
! #ifdef FEAT_SEARCH_EXTRA
!       case CMD_match:
!           if (*arg == NUL || !ends_excmd(*arg))
!           {
!               /* also complete "None" */
!               set_context_in_echohl_cmd(xp, arg);
!               arg = skipwhite(skiptowhite(arg));
!               if (*arg != NUL)
!               {
!                   xp->xp_context = EXPAND_NOTHING;
!                   arg = skip_regexp(arg + 1, *arg, p_magic, NULL);
!               }
!           }
!           return find_nextcmd(arg);
! #endif
! 
! /*
!  * All completion for the +cmdline_compl feature goes here.
!  */
! 
!       case CMD_command:
!           return set_context_in_user_cmd(xp, arg);
! 
!       case CMD_delcommand:
!           xp->xp_context = EXPAND_USER_COMMANDS;
!           xp->xp_pattern = arg;
!           break;
! 
!       case CMD_global:
!       case CMD_vglobal:
!           delim = *arg;           /* get the delimiter */
!           if (delim)
!               ++arg;              /* skip delimiter if there is one */
! 
!           while (arg[0] != NUL && arg[0] != delim)
!           {
!               if (arg[0] == '\\' && arg[1] != NUL)
!                   ++arg;
!               ++arg;
!           }
!           if (arg[0] != NUL)
!               return arg + 1;
!           break;
!       case CMD_and:
!       case CMD_substitute:
!           delim = *arg;
!           if (delim)
!           {
!               /* skip "from" part */
!               ++arg;
!               arg = skip_regexp(arg, delim, p_magic, NULL);
!           }
!           /* skip "to" part */
!           while (arg[0] != NUL && arg[0] != delim)
!           {
!               if (arg[0] == '\\' && arg[1] != NUL)
!                   ++arg;
!               ++arg;
!           }
!           if (arg[0] != NUL)  /* skip delimiter */
!               ++arg;
!           while (arg[0] && vim_strchr((char_u *)"|\"#", arg[0]) == NULL)
!               ++arg;
!           if (arg[0] != NUL)
!               return arg;
!           break;
!       case CMD_isearch:
!       case CMD_dsearch:
!       case CMD_ilist:
!       case CMD_dlist:
!       case CMD_ijump:
!       case CMD_psearch:
!       case CMD_djump:
!       case CMD_isplit:
!       case CMD_dsplit:
!           arg = skipwhite(skipdigits(arg));       /* skip count */
!           if (*arg == '/')    /* Match regexp, not just whole words */
!           {
!               for (++arg; *arg && *arg != '/'; arg++)
!                   if (*arg == '\\' && arg[1] != NUL)
!                       arg++;
!               if (*arg)
!               {
!                   arg = skipwhite(arg + 1);
! 
!                   /* Check for trailing illegal characters */
!                   if (*arg && vim_strchr((char_u *)"|\"\n", *arg) == NULL)
!                       xp->xp_context = EXPAND_NOTHING;
!                   else
!                       return arg;
!               }
!           }
!           break;
! 
!       case CMD_autocmd:
!           return set_context_in_autocmd(xp, arg, FALSE);
!       case CMD_doautocmd:
!       case CMD_doautoall:
!           return set_context_in_autocmd(xp, arg, TRUE);
!       case CMD_set:
!           set_context_in_set_cmd(xp, arg, 0);
!           break;
!       case CMD_setglobal:
!           set_context_in_set_cmd(xp, arg, OPT_GLOBAL);
!           break;
!       case CMD_setlocal:
!           set_context_in_set_cmd(xp, arg, OPT_LOCAL);
!           break;
!       case CMD_tag:
!       case CMD_stag:
!       case CMD_ptag:
!       case CMD_ltag:
!       case CMD_tselect:
!       case CMD_stselect:
!       case CMD_ptselect:
!       case CMD_tjump:
!       case CMD_stjump:
!       case CMD_ptjump:
!           if (*p_wop != NUL)
!               xp->xp_context = EXPAND_TAGS_LISTFILES;
!           else
!               xp->xp_context = EXPAND_TAGS;
!           xp->xp_pattern = arg;
!           break;
!       case CMD_augroup:
!           xp->xp_context = EXPAND_AUGROUP;
!           xp->xp_pattern = arg;
!           break;
! #ifdef FEAT_SYN_HL
!       case CMD_syntax:
!           set_context_in_syntax_cmd(xp, arg);
!           break;
! #endif
! #ifdef FEAT_EVAL
!       case CMD_let:
!       case CMD_if:
!       case CMD_elseif:
!       case CMD_while:
!       case CMD_for:
!       case CMD_echo:
!       case CMD_echon:
!       case CMD_execute:
!       case CMD_echomsg:
!       case CMD_echoerr:
!       case CMD_call:
!       case CMD_return:
!       case CMD_cexpr:
!       case CMD_caddexpr:
!       case CMD_cgetexpr:
!       case CMD_lexpr:
!       case CMD_laddexpr:
!       case CMD_lgetexpr:
!           set_context_for_expression(xp, arg, ea.cmdidx);
!           break;
! 
!       case CMD_unlet:
!           while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL)
!               arg = xp->xp_pattern + 1;
! 
!           xp->xp_context = EXPAND_USER_VARS;
!           xp->xp_pattern = arg;
! 
!           if (*xp->xp_pattern == '$')
!           {
!               xp->xp_context = EXPAND_ENV_VARS;
!               ++xp->xp_pattern;
!           }
  
            break;
  
!       case CMD_function:
!       case CMD_delfunction:
!           xp->xp_context = EXPAND_USER_FUNC;
!           xp->xp_pattern = arg;
!           break;
! 
!       case CMD_echohl:
!           set_context_in_echohl_cmd(xp, arg);
!           break;
! #endif
!       case CMD_highlight:
!           set_context_in_highlight_cmd(xp, arg);
!           break;
! #ifdef FEAT_CSCOPE
!       case CMD_cscope:
!       case CMD_lcscope:
!       case CMD_scscope:
!           set_context_in_cscope_cmd(xp, arg, ea.cmdidx);
!           break;
! #endif
! #ifdef FEAT_SIGNS
!       case CMD_sign:
!           set_context_in_sign_cmd(xp, arg);
!           break;
! #endif
!       case CMD_bdelete:
!       case CMD_bwipeout:
!       case CMD_bunload:
!           while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL)
!               arg = xp->xp_pattern + 1;
!           /* FALLTHROUGH */
!       case CMD_buffer:
!       case CMD_sbuffer:
!       case CMD_checktime:
!           xp->xp_context = EXPAND_BUFFERS;
!           xp->xp_pattern = arg;
!           break;
! 
!       case CMD_USER:
!       case CMD_USER_BUF:
!           if (compl != EXPAND_NOTHING)
!           {
!               // EX_XFILE: file names are handled above
!               if (!(ea.argt & EX_XFILE))
!               {
! #ifdef FEAT_MENU
!                   if (compl == EXPAND_MENUS)
!                       return set_context_in_menu_cmd(xp, cmd, arg, forceit);
! #endif
!                   if (compl == EXPAND_COMMANDS)
!                       return arg;
!                   if (compl == EXPAND_MAPPINGS)
!                       return set_context_in_map_cmd(xp, (char_u *)"map",
!                                        arg, forceit, FALSE, FALSE, CMD_map);
!                   // Find start of last argument.
!                   p = arg;
!                   while (*p)
!                   {
!                       if (*p == ' ')
!                           // argument starts after a space
!                           arg = p + 1;
!                       else if (*p == '\\' && *(p + 1) != NUL)
!                           ++p; // skip over escaped character
!                       MB_PTR_ADV(p);
!                   }
!                   xp->xp_pattern = arg;
!               }
!               xp->xp_context = compl;
!           }
!           break;
! 
!       case CMD_map:       case CMD_noremap:
!       case CMD_nmap:      case CMD_nnoremap:
!       case CMD_vmap:      case CMD_vnoremap:
!       case CMD_omap:      case CMD_onoremap:
!       case CMD_imap:      case CMD_inoremap:
!       case CMD_cmap:      case CMD_cnoremap:
!       case CMD_lmap:      case CMD_lnoremap:
!       case CMD_smap:      case CMD_snoremap:
!       case CMD_tmap:      case CMD_tnoremap:
!       case CMD_xmap:      case CMD_xnoremap:
!           return set_context_in_map_cmd(xp, cmd, arg, forceit,
!                                                    FALSE, FALSE, ea.cmdidx);
!       case CMD_unmap:
!       case CMD_nunmap:
!       case CMD_vunmap:
!       case CMD_ounmap:
!       case CMD_iunmap:
!       case CMD_cunmap:
!       case CMD_lunmap:
!       case CMD_sunmap:
!       case CMD_tunmap:
!       case CMD_xunmap:
!           return set_context_in_map_cmd(xp, cmd, arg, forceit,
!                                                     FALSE, TRUE, ea.cmdidx);
!       case CMD_mapclear:
!       case CMD_nmapclear:
!       case CMD_vmapclear:
!       case CMD_omapclear:
!       case CMD_imapclear:
!       case CMD_cmapclear:
!       case CMD_lmapclear:
!       case CMD_smapclear:
!       case CMD_tmapclear:
!       case CMD_xmapclear:
!           xp->xp_context = EXPAND_MAPCLEAR;
!           xp->xp_pattern = arg;
!           break;
! 
!       case CMD_abbreviate:    case CMD_noreabbrev:
!       case CMD_cabbrev:       case CMD_cnoreabbrev:
!       case CMD_iabbrev:       case CMD_inoreabbrev:
!           return set_context_in_map_cmd(xp, cmd, arg, forceit,
!                                                     TRUE, FALSE, ea.cmdidx);
!       case CMD_unabbreviate:
!       case CMD_cunabbrev:
!       case CMD_iunabbrev:
!           return set_context_in_map_cmd(xp, cmd, arg, forceit,
!                                                      TRUE, TRUE, ea.cmdidx);
! #ifdef FEAT_MENU
!       case CMD_menu:      case CMD_noremenu:      case CMD_unmenu:
!       case CMD_amenu:     case CMD_anoremenu:     case CMD_aunmenu:
!       case CMD_nmenu:     case CMD_nnoremenu:     case CMD_nunmenu:
!       case CMD_vmenu:     case CMD_vnoremenu:     case CMD_vunmenu:
!       case CMD_omenu:     case CMD_onoremenu:     case CMD_ounmenu:
!       case CMD_imenu:     case CMD_inoremenu:     case CMD_iunmenu:
!       case CMD_cmenu:     case CMD_cnoremenu:     case CMD_cunmenu:
!       case CMD_tlmenu:    case CMD_tlnoremenu:    case CMD_tlunmenu:
!       case CMD_tmenu:                             case CMD_tunmenu:
!       case CMD_popup:     case CMD_tearoff:       case CMD_emenu:
!           return set_context_in_menu_cmd(xp, cmd, arg, forceit);
! #endif
! 
!       case CMD_colorscheme:
!           xp->xp_context = EXPAND_COLORS;
!           xp->xp_pattern = arg;
!           break;
! 
!       case CMD_compiler:
!           xp->xp_context = EXPAND_COMPILER;
!           xp->xp_pattern = arg;
!           break;
! 
!       case CMD_ownsyntax:
!           xp->xp_context = EXPAND_OWNSYNTAX;
!           xp->xp_pattern = arg;
!           break;
! 
!       case CMD_setfiletype:
!           xp->xp_context = EXPAND_FILETYPE;
!           xp->xp_pattern = arg;
!           break;
! 
!       case CMD_packadd:
!           xp->xp_context = EXPAND_PACKADD;
!           xp->xp_pattern = arg;
!           break;
! 
! #if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
!       case CMD_language:
!           p = skiptowhite(arg);
!           if (*p == NUL)
!           {
!               xp->xp_context = EXPAND_LANGUAGE;
!               xp->xp_pattern = arg;
!           }
!           else
!           {
!               if ( STRNCMP(arg, "messages", p - arg) == 0
!                 || STRNCMP(arg, "ctype", p - arg) == 0
!                 || STRNCMP(arg, "time", p - arg) == 0)
!               {
!                   xp->xp_context = EXPAND_LOCALES;
!                   xp->xp_pattern = skipwhite(p);
!               }
!               else
!                   xp->xp_context = EXPAND_NOTHING;
!           }
!           break;
! #endif
! #if defined(FEAT_PROFILE)
!       case CMD_profile:
!           set_context_in_profile_cmd(xp, arg);
!           break;
! #endif
!       case CMD_behave:
!           xp->xp_context = EXPAND_BEHAVE;
!           xp->xp_pattern = arg;
!           break;
! 
!       case CMD_messages:
!           xp->xp_context = EXPAND_MESSAGES;
!           xp->xp_pattern = arg;
!           break;
! 
!       case CMD_history:
!           xp->xp_context = EXPAND_HISTORY;
!           xp->xp_pattern = arg;
!           break;
! #if defined(FEAT_PROFILE)
!       case CMD_syntime:
!           xp->xp_context = EXPAND_SYNTIME;
!           xp->xp_pattern = arg;
!           break;
! #endif
! 
!       case CMD_argdelete:
!           while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL)
!               arg = xp->xp_pattern + 1;
!           xp->xp_context = EXPAND_ARGLIST;
!           xp->xp_pattern = arg;
!           break;
  
!       default:
!           break;
!     }
!     return NULL;
  }
  
  /*
--- 3306,3328 ----
  }
  #endif
  
!     cmdidx_T
! excmd_get_cmdidx(char_u *cmd, int len)
  {
!     cmdidx_T idx;
  
+     for (idx = (cmdidx_T)0; (int)idx < (int)CMD_SIZE;
+           idx = (cmdidx_T)((int)idx + 1))
+       if (STRNCMP(cmdnames[(int)idx].cmd_name, cmd, (size_t)len) == 0)
            break;
  
!     return idx;
! }
  
!     long
! excmd_get_argt(cmdidx_T idx)
! {
!     return (long)cmdnames[(int)idx].cmd_argt;
  }
  
  /*
***************
*** 5196,5202 ****
  /*
   * Find end of "+command" argument.  Skip over "\ " and "\\".
   */
!     static char_u *
  skip_cmd_arg(
      char_u *p,
      int          rembs)       /* TRUE to halve the number of backslashes */
--- 4385,4391 ----
  /*
   * Find end of "+command" argument.  Skip over "\ " and "\\".
   */
!     char_u *
  skip_cmd_arg(
      char_u *p,
      int          rembs)       /* TRUE to halve the number of backslashes */
***************
*** 9162,9201 ****
        semsg(_(e_invarg2), eap->arg);
  }
  
- /*
-  * Function given to ExpandGeneric() to obtain the possible arguments of the
-  * ":behave {mswin,xterm}" command.
-  */
-     char_u *
- get_behave_arg(expand_T *xp UNUSED, int idx)
- {
-     if (idx == 0)
-       return (char_u *)"mswin";
-     if (idx == 1)
-       return (char_u *)"xterm";
-     return NULL;
- }
- 
- /*
-  * Function given to ExpandGeneric() to obtain the possible arguments of the
-  * ":messages {clear}" command.
-  */
-     char_u *
- get_messages_arg(expand_T *xp UNUSED, int idx)
- {
-     if (idx == 0)
-       return (char_u *)"clear";
-     return NULL;
- }
- 
-     char_u *
- get_mapclear_arg(expand_T *xp UNUSED, int idx)
- {
-     if (idx == 0)
-       return (char_u *)"<buffer>";
-     return NULL;
- }
- 
  static int filetype_detect = FALSE;
  static int filetype_plugin = FALSE;
  static int filetype_indent = FALSE;
--- 8351,8356 ----
*** ../vim-8.1.1913/src/proto/ex_docmd.pro      2019-08-17 14:38:35.647786228 
+0200
--- src/proto/ex_docmd.pro      2019-08-23 21:11:35.196716430 +0200
***************
*** 9,19 ****
  int checkforcmd(char_u **pp, char *cmd, int len);
  int modifier_len(char_u *cmd);
  int cmd_exists(char_u *name);
! char_u *set_one_cmd_context(expand_T *xp, char_u *buff);
  char_u *skip_range(char_u *cmd, int *ctx);
  void ex_ni(exarg_T *eap);
  int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp);
  void separate_nextcmd(exarg_T *eap);
  int get_bad_opt(char_u *p, exarg_T *eap);
  int ends_excmd(int c);
  char_u *find_nextcmd(char_u *p);
--- 9,21 ----
  int checkforcmd(char_u **pp, char *cmd, int len);
  int modifier_len(char_u *cmd);
  int cmd_exists(char_u *name);
! cmdidx_T excmd_get_cmdidx(char_u *cmd, int len);
! long excmd_get_argt(cmdidx_T idx);
  char_u *skip_range(char_u *cmd, int *ctx);
  void ex_ni(exarg_T *eap);
  int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp);
  void separate_nextcmd(exarg_T *eap);
+ char_u *skip_cmd_arg( char_u *p, int rembs);
  int get_bad_opt(char_u *p, exarg_T *eap);
  int ends_excmd(int c);
  char_u *find_nextcmd(char_u *p);
***************
*** 48,56 ****
  int put_eol(FILE *fd);
  int put_line(FILE *fd, char *s);
  void dialog_msg(char_u *buff, char *format, char_u *fname);
- char_u *get_behave_arg(expand_T *xp, int idx);
- char_u *get_messages_arg(expand_T *xp, int idx);
- char_u *get_mapclear_arg(expand_T *xp, int idx);
  void set_no_hlsearch(int flag);
  int is_loclist_cmd(int cmdidx);
  int get_pressedreturn(void);
--- 50,55 ----
*** ../vim-8.1.1913/src/version.c       2019-08-23 20:58:42.024375479 +0200
--- src/version.c       2019-08-23 21:12:57.300332771 +0200
***************
*** 763,764 ****
--- 763,766 ----
  {   /* Add new patch number below this line */
+ /**/
+     1914,
  /**/

-- 
A meeting is an event at which the minutes are kept and the hours are lost.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/201908231918.x7NJI3Na007857%40masaka.moolenaar.net.

Raspunde prin e-mail lui