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

📄 ex_getln.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
 *  char_u *expand_pattern  The start of the pattern to be expanded within
 *				the command line (ends at the cursor).
 *  int expand_context	    The type of thing to expand.  Will be one of:
 *
 *  EXPAND_UNSUCCESSFUL	    Used sometimes when there is something illegal on
 *			    the command line, like an unknown command.	Caller
 *			    should beep.
 *  EXPAND_NOTHING	    Unrecognised context for completion, use char like
 *			    a normal char, rather than for completion.	eg
 *			    :s/^I/
 *  EXPAND_COMMANDS	    Cursor is still touching the command, so complete
 *			    it.
 *  EXPAND_BUFFERS	    Complete file names for :buf and :sbuf commands.
 *  EXPAND_FILES	    After command with XFILE set, or after setting
 *			    with P_EXPAND set.	eg :e ^I, :w>>^I
 *  EXPAND_DIRECTORIES	    In some cases this is used instead of the latter
 *			    when we know only directories are of interest.  eg
 *			    :set dir=^I
 *  EXPAND_SETTINGS	    Complete variable names.  eg :set d^I
 *  EXPAND_BOOL_SETTINGS    Complete boolean variables only,  eg :set no^I
 *  EXPAND_TAGS		    Complete tags from the files in p_tags.  eg :ta a^I
 *  EXPAND_HELP		    Complete tags from the file 'helpfile'/tags
 *  EXPAND_EVENTS	    Complete event names
 *  EXPAND_SYNTAX	    Complete :syntax command arguments
 *  EXPAND_HIGHLIGHT	    Complete highlight (syntax) group names
 *  EXPAND_AUGROUP	    Complete autocommand group names
 *  EXPAND_USER_VARS	    Complete user defined variable names, eg :unlet a^I
 *
 * -- webb.
 */
    static void
set_expand_context()
{
    char_u	*nextcomm;
    int		old_char = NUL;

    if (ccline.cmdfirstc != ':')	/* only expansion for ':' commands */
    {
	expand_context = EXPAND_NOTHING;
	return;
    }

    /*
     * Avoid a UMR warning from Purify, only save the character if it has been
     * written before.
     */
    if (ccline.cmdpos < ccline.cmdlen)
	old_char = ccline.cmdbuff[ccline.cmdpos];
    ccline.cmdbuff[ccline.cmdpos] = NUL;
    nextcomm = ccline.cmdbuff;
    while (nextcomm != NULL)
	nextcomm = set_one_cmd_context(nextcomm);
    ccline.cmdbuff[ccline.cmdpos] = old_char;
}

/*
 * Do the expansion based on the global variables expand_context and
 * expand_pattern -- webb.
 */
    static int
ExpandFromContext(pat, num_file, file, files_only, options)
    char_u  *pat;
    int	    *num_file;
    char_u  ***file;
    int	    files_only;
    int	    options;
{
    vim_regexp	*prog;
    int		ret;
    int		flags;
    flags = 0;
    if (!files_only)
	flags |= EW_DIR;
    if (options & WILD_LIST_NOTFOUND)
	flags |= EW_NOTFOUND;

    if (!expand_interactively || expand_context == EXPAND_FILES)
    {
	/*
	 * Expand file names.
	 */
	return expand_wildcards(1, &pat, num_file, file, flags|EW_FILE);
    }
    else if (expand_context == EXPAND_DIRECTORIES)
    {
	/*
	 * Expand directory names.
	 */
	int	free_pat = FALSE;
	int	i;

	/* for ":set path=" we need to remove backslashes for escaped space */
	if (expand_set_path)
	{
	    free_pat = TRUE;
	    pat = vim_strsave(pat);
	    for (i = 0; pat[i]; ++i)
		if (pat[i] == '\\' && pat[i + 1] == '\\' &&
				      pat[i + 2] == '\\' && pat[i + 3] == ' ')
		    STRCPY(pat + i, pat + i + 3);
	}

	ret = expand_wildcards(1, &pat, num_file, file,
						 (flags | EW_DIR) & ~EW_FILE);
	if (free_pat)
	    vim_free(pat);
	return ret;
    }

    *file = (char_u **)"";
    *num_file = 0;
    if (expand_context == EXPAND_OLD_SETTING)
	return ExpandOldSetting(num_file, file);

    if (expand_context == EXPAND_HELP)
	return find_help_tags(pat, num_file, file);

    set_reg_ic(pat);	    /* set reg_ic according to p_ic, p_scs and pat */

    if (expand_context == EXPAND_BUFFERS)
	return ExpandBufnames(pat, num_file, file, options);
    else if (expand_context == EXPAND_TAGS)
    {
	if (pat[0] == '^' && pat[1] == '/')
	    return find_tags(pat + 2, num_file, file,
				TAG_REGEXP | TAG_NAMES | TAG_VERBOSE, MAXCOL);
	return find_tags(pat, num_file, file,
		     TAG_REGEXP | TAG_NAMES | TAG_VERBOSE | TAG_NOIC, MAXCOL);
    }

    prog = vim_regcomp(pat, (int)p_magic);
    if (prog == NULL)
	return FAIL;

    if (expand_context == EXPAND_COMMANDS)
	ret = ExpandGeneric(prog, num_file, file, get_command_name);
    else if (expand_context == EXPAND_SETTINGS ||
				       expand_context == EXPAND_BOOL_SETTINGS)
	ret = ExpandSettings(prog, num_file, file);
#ifdef WANT_EVAL
    else if (expand_context == EXPAND_USER_VARS)
	ret = ExpandGeneric(prog, num_file, file, get_user_var_name);
#endif
#ifdef USE_GUI
    else if (expand_context == EXPAND_MENUS)
	ret = ExpandGeneric(prog, num_file, file, get_menu_name);
#endif
#ifdef SYNTAX_HL
    else if (expand_context == EXPAND_SYNTAX)
    {
	reg_ic = TRUE;
	ret = ExpandGeneric(prog, num_file, file, get_syntax_name);
    }
#endif
    else if (expand_context == EXPAND_HIGHLIGHT)
    {
	reg_ic = TRUE;
	ret = ExpandGeneric(prog, num_file, file, get_highlight_name);
    }
#ifdef AUTOCMD
    else if (expand_context == EXPAND_EVENTS)
    {
	reg_ic = TRUE;
	ret = ExpandGeneric(prog, num_file, file, get_event_name);
    }
    else if (expand_context == EXPAND_AUGROUP)
    {
	reg_ic = TRUE;
	ret = ExpandGeneric(prog, num_file, file, get_augroup_name);
    }
#endif
    else
	ret = FAIL;

    vim_free(prog);
    return ret;
}

/*
 * Expand a list of names.
 *
 * Generic function for command line completion.  It calls a function to
 * obtain strings, one by one.	The strings are matched against a regexp
 * program.  Matching strings are copied into an array, which is returned.
 *
 * Returns OK when no problems encountered, FAIL for error (out of memory).
 */
    int
ExpandGeneric(prog, num_file, file, func)
    vim_regexp	*prog;
    int		*num_file;
    char_u	***file;
    char_u	*((*func)__ARGS((int))); /* returns a string from the list */
{
    int i;
    int count = 0;
    int	loop;
    char_u  *str;

    /* do this loop twice:
     * loop == 0: count the number of matching names
     * loop == 1: copy the matching names into allocated memory
     */
    for (loop = 0; loop <= 1; ++loop)
    {
	for (i = 0; ; ++i)
	{
	    str = (*func)(i);
	    if (str == NULL)	    /* end of list */
		break;
	    if (*str == NUL)	    /* skip empty strings */
		continue;

	    if (vim_regexec(prog, str, TRUE))
	    {
		if (loop)
		    (*file)[count] = vim_strsave_escaped(str,
							  (char_u *)" \t\\.");
		++count;
	    }
	}
	if (loop == 0)
	{
	    if (count == 0)
		return OK;
	    *num_file = count;
	    *file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
	    if (*file == NULL)
	    {
		*file = (char_u **)"";
		return FAIL;
	    }
	    count = 0;
	}
    }
    return OK;
}

/*********************************
 *  Command line history stuff	 *
 *********************************/

/*
 * Translate a history character to the associated type number.
 */
    static int
hist_char2type(c)
    int	    c;
{
    if (c == ':')
	return HIST_CMD;
    if (c == '=')
	return HIST_EXPR;
    if (c == '@')
	return HIST_INPUT;
    return HIST_SEARCH;	    /* must be '?' or '/' */
}

/*
 * init_history() - Initialize the command line history.
 * Also used to re-allocate the history when the size changes.
 */
    static void
init_history()
{
    int	    newlen;	    /* new length of history table */
    char_u  **temp;
    int	    i;
    int	    j;
    int	    type;

    /*
     * If size of history table changed, reallocate it
     */
    newlen = (int)p_hi;
    if (newlen != hislen)			/* history length changed */
    {
	for (type = 0; type < HIST_COUNT; ++type)   /* adjust the tables */
	{
	    if (newlen)
	    {
		temp = (char_u **)lalloc((long_u)(newlen * sizeof(char_u *)),
									TRUE);
		if (temp == NULL)   /* out of memory! */
		{
		    if (type == 0)  /* first one: just keep the old length */
		    {
			newlen = hislen;
			break;
		    }
		    /* Already changed one table, now we can only have zero
		     * length for all tables. */
		    newlen = 0;
		    type = -1;
		    continue;
		}
	    }
	    else
		temp = NULL;
	    if (newlen == 0 || temp != NULL)
	    {
		if (hisidx[type] < 0)		/* there are no entries yet */
		{
		    for (i = 0; i < newlen; ++i)
			temp[i] = NULL;
		}
		else if (newlen > hislen)	/* array becomes bigger */
		{
		    for (i = 0; i <= hisidx[type]; ++i)
			temp[i] = history[type][i];
		    j = i;
		    for ( ; i <= newlen - (hislen - hisidx[type]); ++i)
			temp[i] = NULL;
		    for ( ; j < hislen; ++i, ++j)
			temp[i] = history[type][j];
		}
		else				/* array becomes smaller or 0 */
		{
		    j = hisidx[type];
		    for (i = newlen - 1; ; --i)
		    {
			if (i >= 0)		/* copy newest entries */
			    temp[i] = history[type][j];
			else			/* remove older entries */
			    vim_free(history[type][j]);
			if (--j < 0)
			    j = hislen - 1;
			if (j == hisidx[type])
			    break;
		    }
		    hisidx[type] = newlen - 1;
		}
		vim_free(history[type]);
		history[type] = temp;
	    }
	}
	hislen = newlen;
    }
}

/*
 * Check if command line 'str' is already in history.
 * If 'move_to_front' is TRUE, matching entry is moved to end of history.
 */
    static int
in_history(type, str, move_to_front)
    int	    type;
    char_u  *str;
    int	    move_to_front;	/* Move the entry to the front if it exists */
{
    int	    i;
    int	    last_i = -1;

    if (hisidx[type] < 0)
	return FALSE;
    i = hisidx[type];
    do
    {
	if (history[type][i] == NULL)
	    return FALSE;
	if (STRCMP(str, history[type][i]) == 0)
	{
	    if (!move_to_front)
		return TRUE;
	    last_i = i;
	    break;
	}
	if (--i < 0)
	    i = hislen - 1;
    } while (i != hisidx[type]);

    if (last_i >= 0)
    {
	str = history[type][i];
	while (i != hisidx[type])
	{
	    if (++i >= hislen)
		i = 0;
	    history[type][last_i] = history[type][i];
	    last_i = i;
	}
	history[type][i] = str;
	return TRUE;
    }
    return FALSE;
}

/*
 * Add the given string to the given history.  If the string is already in the
 * history then it is moved to the front.  "histype" may be HIST_CMD,
 * HIST_SEARCH, HIST_EXPR or HIST_INPUT.
 */
    void
add_to_history(histype, new_entry)
    int		histype;
    char_u	*new_entry;
{
    static int	last_maptick = -1;	/* last seen maptick */

    if (hislen == 0)		/* no history */
	return;

    /*
     * Searches inside the same mapping overwrite each other, so that only
     * the last line is kept.  Be careful not to remove a line that was moved
     * down, only lines that were added.
     */
    if (histype == HIST_SEARCH)
    {
	if (maptick == last_maptick)
	{
	    /* Current line is from the same mapping, remove it */
	    vim_free(history[HIST_SEARCH][hisidx[HIST_SEARCH]]);
	    history[HIST_SEARCH][hisidx[HIST_SEARCH]] = NULL;
	    if (--hisidx[HIST_SEARCH] < 0)
		hisidx[HIST_SEARCH] = hislen - 1;
	}
	last_maptick = -1;
    }
    if (!in_history(histype, new_entry, TRUE))
    {
	if (++hisidx[histype] == hislen)
	    hisidx[histype] = 0;
	vim_free(history[histype][hisidx[histype]]);
	history[histype][hisidx[histype]] = vim_strsave(new_entry);
	if (histype == HIST_SEARCH)
	    last_maptick = maptick;
    }
}

#ifdef VIMINFO
static char_u **viminfo_history[HIST_COUNT] = {NULL, NULL, NULL, NULL};
static int	viminfo_hisidx[HIST_COUNT] = {0, 0, 0, 0};
static int	viminfo_hislen[HIST_COUNT] = {0, 0, 0, 0};
static int	viminfo_add_at_front = FALSE;

static int	hist_type2char __ARGS((int type, int use_question));

/*
 * Translate a history type number to the associated character.
 */
    static int
hist_type2char(type, use_question)
    int	    type;
    int	    use_question;	    /* use '?' instead of '/' */
{
    if (type == HIST_CMD)
	return ':';
    if (type == HIST_SEARCH)
    {
	if (use_question)
	    return '?';
	else
	    return '/';
    }
    if (type == HIST_EXPR)
	return '=';
    return '@';
}

/*
 * Prepare for reading the history from the viminfo file.
 * This allocates history arrays to store the read history lines.
 */
    void
prepare_viminfo_history(asklen)
    int	    asklen;
{
    int	    i;
    int	    num;
    int	    type;
    int	    len;

    init_history();
    viminfo_add_at_front = (asklen != 0);
    if (asklen > hislen)
	asklen = hislen;

    for (type = 0; type < HIST_COUNT; ++type)
    {
	/*
	 * Count the number of empty spaces in the history list.  If there are
	 * more spaces available than we request, then fill them up.
	 */
	for (i = 0, num = 0; i < hislen; i++)
	    if (history[type][i] == NULL)
		num++;
	len = asklen;
	if (num > len)
	    len = num;
	if (len <= 0)
	    viminfo_history[type] = NULL;
	else
	    viminfo_history[type] =
		   (char_u **)lalloc((long_u)(len * sizeof(char_u *)), FALSE);
	if (viminfo_history[type] == NULL)
	    len = 0;
	viminfo_hislen[type] = len;
	viminfo_hisidx[type] = 0;
    }
}

/*
 * Accept a line from the viminfo, store it in the history array when it's
 * new.
 */
    int
read_viminfo_history(line, fp)
    char_u  *line;
    FILE    *fp;
{
    int	    type;

    

⌨️ 快捷键说明

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