⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ex_docmd.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
	return NULL;
    if (*cmd == '"')	    /* ignore comment lines */
    {
	expand_context = EXPAND_NOTHING;
	return NULL;
    }

/*
 * 3. parse a range specifier of the form: addr [,addr] [;addr] ..
 */
    /*
     * Backslashed delimiters after / or ? will be skipped, and commands will
     * not be expanded between /'s and ?'s or after "'". -- webb
     */
    while (*cmd != NUL && (vim_isspace(*cmd) || isdigit(*cmd) ||
			    vim_strchr((char_u *)".$%'/?-+,;", *cmd) != NULL))
    {
	if (*cmd == '\'')
	{
	    if (*++cmd == NUL)
		expand_context = EXPAND_NOTHING;
	}
	else if (*cmd == '/' || *cmd == '?')
	{
	    delim = *cmd++;
	    while (*cmd != NUL && *cmd != delim)
		if (*cmd++ == '\\' && *cmd != NUL)
		    ++cmd;
	    if (*cmd == NUL)
		expand_context = EXPAND_NOTHING;
	}
	if (*cmd != NUL)
	    ++cmd;
    }

/*
 * 4. parse command
 */

    cmd = skipwhite(cmd);
    expand_pattern = cmd;
    if (*cmd == NUL)
	return NULL;
    if (*cmd == '"')
    {
	expand_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.
     * - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r'
     */
    if (*cmd == 'k')
    {
	cmdidx = CMD_k;
	p = cmd + 1;
    }
    else
    {
	p = cmd;
	while (isalpha(*p) || *p == '*')    /* Allow * wild card */
	    ++p;
	    /* check for non-alpha command */
	if (p == cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL)
	    ++p;
	i = (int)(p - cmd);

	if (i == 0)
	{
	    expand_context = EXPAND_UNSUCCESSFUL;
	    return NULL;
	}
	for (cmdidx = (CMDIDX)0; (int)cmdidx < (int)CMD_SIZE;
					   cmdidx = (CMDIDX)((int)cmdidx + 1))
	    if (STRNCMP(cmdnames[(int)cmdidx].cmd_name, cmd, (size_t)i) == 0)
		break;
    }

    /*
     * If the cursor is touching the command, and it ends in an alphabetic
     * character, complete the command name.
     */
    if (*p == NUL && isalpha(p[-1]))
	return NULL;

    if (cmdidx == CMD_SIZE)
    {
	if (*cmd == 's' && vim_strchr((char_u *)"cgriI", cmd[1]) != NULL)
	{
	    cmdidx = CMD_substitute;
	    p = cmd + 1;
	}
	else
	{
#ifdef USER_COMMANDS
	    /* Look for a user defined command as a last resort */
	    UCMD *c = USER_CMD(0);
	    int j;
	    int found = FALSE;

	    for (j = 0; j < ucmds.ga_len; ++j, ++c)
	    {
		if (STRNCMP(c->uc_name, cmd, (size_t)i) == 0)
		{
		    if (found)
		    {
			/* Ambiguous abbreviation */
			expand_context = EXPAND_UNSUCCESSFUL;
			return NULL;
		    }
		    found = TRUE;
		    cmdidx = CMD_USER;
		    argt = c->uc_argt;
		    compl = c->uc_compl;

		    /* Do not search for further abbreviations
		     * if this is an exact match
		     */
		    if ((size_t)i == STRLEN(c->uc_name))
			break;
		}
	    }

	    if (!found)
#endif
	    {
		/* Not still touching the command and it was an illegal one */
		expand_context = EXPAND_UNSUCCESSFUL;
		return NULL;
	    }
	}
    }

    expand_context = EXPAND_NOTHING; /* Default now that we're past command */

    if (*p == '!')		    /* forced commands */
    {
	forceit = TRUE;
	++p;
    }

/*
 * 5. parse arguments
 */
#ifdef USER_COMMANDS
    if (cmdidx != CMD_USER)
#endif
	argt = cmdnames[(int)cmdidx].cmd_argt;

    arg = skipwhite(p);

    if (cmdidx == CMD_write || cmdidx == CMD_update)
    {
	if (*arg == '>')			/* append */
	{
	    if (*++arg == '>')
		++arg;
	    arg = skipwhite(arg);
	}
	else if (*arg == '!' && cmdidx == CMD_write)	/* :w !filter */
	{
	    ++arg;
	    usefilter = TRUE;
	}
    }

    if (cmdidx == CMD_read)
    {
	usefilter = forceit;			/* :r! filter if forced */
	if (*arg == '!')			/* :r !filter */
	{
	    ++arg;
	    usefilter = TRUE;
	}
    }

    if (cmdidx == CMD_lshift || cmdidx == CMD_rshift)
    {
	while (*arg == *cmd)	    /* allow any number of '>' or '<' */
	    ++arg;
	arg = skipwhite(arg);
    }

    /* Does command allow "+command"? */
    if ((argt & EDITCMD) && !usefilter && *arg == '+')
    {
	/* Check if we're in the +command */
	p = arg + 1;
	arg = skip_cmd_arg(arg);

	/* 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 ((argt & TRLBAR) && !usefilter)
    {
	p = arg;
	while (*p)
	{
	    if (*p == Ctrl('V'))
	    {
		if (p[1] != NUL)
		    ++p;
	    }
	    else if ( (*p == '"' && !(argt & NOTRLCOM))
		    || *p == '|' || *p == '\n')
	    {
		if (*(p - 1) != '\\')
		{
		    if (*p == '|' || *p == '\n')
			return p + 1;
		    return NULL;    /* It's a comment */
		}
	    }
	    ++p;
	}
    }

						/* no arguments allowed */
    if (!(argt & EXTRA) && *arg != NUL &&
				    vim_strchr((char_u *)"|\"", *arg) == NULL)
	return NULL;

    /* Find start of last argument (argument just before cursor): */
    p = buff + STRLEN(buff);
    while (p != arg && *p != ' ' && *p != TAB)
	p--;
    if (*p == ' ' || *p == TAB)
	p++;
    expand_pattern = p;

    if (argt & XFILE)
    {
	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.
	 */
	expand_pattern = skipwhite(arg);
	for (p = expand_pattern; *p; ++p)
	{
	    if (*p == '\\' && p[1])
		++p;
#ifdef SPACE_IN_FILENAME
	    else if (vim_iswhite(*p) && (!(argt & NOSPC) || usefilter))
#else
	    else if (vim_iswhite(*p))
#endif
	    {
		p = skipwhite(p);
		if (in_quote)
		    bow = p;
		else
		    expand_pattern = p;
		--p;
	    }
	    else if (*p == '`')
	    {
		if (!in_quote)
		{
		    expand_pattern = p;
		    bow = p + 1;
		}
		in_quote = !in_quote;
	    }
	}

	/*
	 * If we are still inside the quotes, and we passed a space, just
	 * expand from there.
	 */
	if (bow != NULL && in_quote)
	    expand_pattern = bow;
	expand_context = EXPAND_FILES;
    }

/*
 * 6. switch on command name
 */
    switch (cmdidx)
    {
	case CMD_cd:
	case CMD_chdir:
	    expand_context = EXPAND_DIRECTORIES;
	    break;
#ifdef USE_BROWSE
	case CMD_browse:
#endif
	case CMD_confirm:
	    return arg;

	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)
		++arg;
	    for (i = 0; i < 2; i++)
	    {
		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_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)
			expand_context = EXPAND_NOTHING;
		    else
			return arg;
		}
	    }
	    break;
#ifdef AUTOCMD
	case CMD_autocmd:
	    return set_context_in_autocmd(arg, FALSE);

	case CMD_doautocmd:
	    return set_context_in_autocmd(arg, TRUE);
#endif
	case CMD_set:
	    set_context_in_set_cmd(arg);
	    break;
	case CMD_tag:
	case CMD_stag:
	case CMD_tselect:
	case CMD_stselect:
	case CMD_tjump:
	case CMD_stjump:
	    expand_context = EXPAND_TAGS;
	    expand_pattern = arg;
	    break;
	case CMD_help:
	    expand_context = EXPAND_HELP;
	    expand_pattern = arg;
	    break;
	case CMD_augroup:
	    expand_context = EXPAND_AUGROUP;
	    expand_pattern = arg;
	    break;
#ifdef SYNTAX_HL
	case CMD_syntax:
	    set_context_in_syntax_cmd(arg);
	    break;
#endif
#ifdef WANT_EVAL
	case CMD_unlet:
	    while ((expand_pattern = vim_strchr(arg, ' ')) != NULL)
		arg = expand_pattern + 1;
	    expand_context = EXPAND_USER_VARS;
	    expand_pattern = arg;
	    break;

	case CMD_echohl:
	    expand_context = EXPAND_HIGHLIGHT;
	    expand_pattern = arg;
	    break;
#endif
	case CMD_highlight:
	    set_context_in_highlight_cmd(arg);
	    break;
	case CMD_bdelete:
	case CMD_bunload:
	    while ((expand_pattern = vim_strchr(arg, ' ')) != NULL)
		arg = expand_pattern + 1;
	case CMD_buffer:
	case CMD_sbuffer:
	    expand_context = EXPAND_BUFFERS;
	    expand_pattern = arg;
	    break;
#ifdef USER_COMMANDS
	case CMD_USER:
	    if (compl != EXPAND_NOTHING)
	    {
#ifdef USE_GUI
		if (compl == EXPAND_MENUS)
		    return gui_set_context_in_menu_cmd(cmd, arg, forceit);
#endif
		if (compl == EXPAND_COMMANDS)
		    return arg;
		while ((expand_pattern = vim_strchr(arg, ' ')) != NULL)
		    arg = expand_pattern + 1;
		expand_context = compl;
		expand_pattern = arg;
	    }
	    break;
#endif

#ifdef USE_GUI
	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_tmenu:				    case CMD_tunmenu:
	case CMD_tearoff:
	    return gui_set_context_in_menu_cmd(cmd, arg, forceit);
#endif
	default:
	    break;
    }
    return NULL;
}

/*
 * get a single EX address
 *
 * Set ptr to the next character after the part that was interpreted.
 * Set ptr to NULL when an error is encountered.
 *
 * Return MAXLNUM when no Ex address was found.
 */
    static linenr_t
get_address(ptr, skip)
    char_u	**ptr;
    int		skip;	    /* only skip the address, don't use it */
{
    int		c;
    int		i;
    long	n;
    char_u	*cmd;
    FPOS	pos;
    FPOS	*fp;
    linenr_t	lnum;

    cmd = skipwhite(*ptr);
    lnum = MAXLNUM;
    do
    {
	switch (*cmd)
	{
	    case '.':			    /* '.' - Cursor position */
			++cmd;
			lnum = curwin->w_cursor.lnum;
			break;

	    case '$':			    /* '$' - last line */
			++cmd;
			lnum = curbuf->b_ml.ml_line_count;
			break;

	    case '\'':			    /* ''' - mark */
			if (*++cmd == NUL)
			{
			    cmd = NULL;
			    goto error;
			}
			if (!skip)
			{
			    fp = getmark(*cmd, FALSE);
			    ++cmd;
			    if (check_mark(fp) == FAIL)
			    {
				cmd = NULL;
				goto error;
			    }
			    lnum = fp->lnum;
			}
			break;

	    case '/':
	    case '?':			/* '/' or '?' - search */
			c = *cmd++;
			if (skip)	/* skip "/pat/" */
			{
			    cmd = skip_regexp(cmd, c, (int)p_magic);
			    if (*cmd == c)
				++cmd;
			}
			else
			{
			    pos = curwin->w_cursor; /* save curwin->w_cursor */
			    /*
			     * When '/' or '?' follows another address, start
			     * from there.
			     */
			    if (lnum != MAXLNUM)
				curwin->w_cursor.lnum = lnum;
			    /*
			     * Start a forward search at the end of the line.
			     * Start a backward search at the start of the line.
			     * This makes sure we never match in the current
			     * line, and can match anywhere in the
			     * next/previous line.
			     */
			    if (c == '/')
				curwin->w_cursor.col = MAXCOL;
			    else
				curwin->w_cursor.col = 0;
			    searchcmdlen = 0;
			    if (!do_search(NULL, c, cmd, 1L,
				      SEARCH_HIS + SEARCH_MSG + SEARCH_START))
			    {
				curwin->w_cursor = pos;
				cmd = NULL;
				goto error;
			    }
			    lnum = curwin->w_cursor.l

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -