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

📄 ex_getln.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
    int	    options;
    int	    mode;
{
    char_u	*ss = NULL;
    static char_u **cmd_files = NULL;	/* list of input files */
    static int	findex;
    static char_u *orig_save = NULL;	/* kept value of orig */
    int		i;
    int		non_suf_match;		/* number without matching suffix */
    long_u	len;
    char_u	*p;

/*
 * first handle the case of using an old match
 */
    if (mode == WILD_NEXT || mode == WILD_PREV)
    {
	if (cmd_numfiles > 0)
	{
	    if (mode == WILD_PREV)
	    {
		if (findex == -1)
		    findex = cmd_numfiles;
		--findex;
	    }
	    else    /* mode == WILD_NEXT */
		++findex;

	    /*
	     * When wrapping around, return the original string, set findex to
	     * -1.
	     */
	    if (findex < 0)
	    {
		if (orig_save == NULL)
		    findex = cmd_numfiles - 1;
		else
		    findex = -1;
	    }
	    if (findex >= cmd_numfiles)
	    {
		if (orig_save == NULL)
		    findex = 0;
		else
		    findex = -1;
	    }
	    if (findex == -1)
		return vim_strsave(orig_save);
	    return vim_strsave(cmd_files[findex]);
	}
	else
	    return NULL;
    }

/* free old names */
    if (cmd_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST)
    {
	FreeWild(cmd_numfiles, cmd_files);
	cmd_numfiles = -1;
	vim_free(orig_save);
	orig_save = NULL;
    }
    findex = 0;

    if (mode == WILD_FREE)	/* only release file name */
	return NULL;

    if (cmd_numfiles == -1)
    {
	vim_free(orig_save);
	orig_save = orig;

	/*
	 * Do the expansion.
	 */
	if (ExpandFromContext(str, &cmd_numfiles, &cmd_files, FALSE,
							     options) == FAIL)
	    /* error: do nothing */;
	else if (cmd_numfiles == 0)
	{
	    if (!expand_interactively)
		emsg2(e_nomatch2, str);
	}
	else
	{
	    /*
	     * May change home directory back to "~"
	     */
	    if (options & WILD_HOME_REPLACE)
		tilde_replace(str, cmd_numfiles, cmd_files);

	    /*
	     * Insert backslashes into a file name before a space, \, %, # and
	     * wildmatch characters, except '~'.
	     */
	    if (expand_interactively &&
		    (expand_context == EXPAND_FILES ||
		     expand_context == EXPAND_BUFFERS ||
		     expand_context == EXPAND_DIRECTORIES))
	    {
		for (i = 0; i < cmd_numfiles; ++i)
		{
		    /* for ":set path=" we need to escape spaces twice */
		    if (expand_set_path)
		    {
			p = vim_strsave_escaped(cmd_files[i], (char_u *)" ");
			if (p != NULL)
			{
			    vim_free(cmd_files[i]);
			    cmd_files[i] = p;
#if defined(BACKSLASH_IN_FILENAME) || defined(COLON_AS_PATHSEP)
			    p = vim_strsave_escaped(cmd_files[i],
							       (char_u *)" ");
			    if (p != NULL)
			    {
				vim_free(cmd_files[i]);
				cmd_files[i] = p;
			    }
#endif
			}
		    }
		    p = vim_strsave_escaped(cmd_files[i],
#ifdef BACKSLASH_IN_FILENAME
						    (char_u *)" *?[{`$%#"
#else
# ifdef COLON_AS_PATHSEP
						    (char_u *)" *?[{`$%#/"
# else
						    (char_u *)" *?[{`$\\%#"
# endif
#endif
									    );
		    if (p != NULL)
		    {
			vim_free(cmd_files[i]);
			cmd_files[i] = p;
		    }
		}
		expand_set_path = FALSE;
	    }

	    /*
	     * Check for matching suffixes in file names.
	     */
	    if (mode != WILD_ALL && mode != WILD_LONGEST)
	    {
		if (cmd_numfiles)
		    non_suf_match = cmd_numfiles;
		else
		    non_suf_match = 1;
		if ((!expand_interactively
			    || expand_context == EXPAND_FILES
			    || expand_context == EXPAND_DIRECTORIES)
			&& cmd_numfiles > 1)	/* more than one match; check suffix */
		{
		    /*
		     * The files will have been sorted on matching suffix in
		     * expand_wildcards, only need to check the first two.
		     */
		    non_suf_match = 0;
		    for (i = 0; i < 2; ++i)
			if (match_suffix(cmd_files[i]))
			    ++non_suf_match;
		}
		if (non_suf_match != 1)
		{
		    /* Can we ever get here unless it's while expanding
		     * interactively?  If not, we can get rid of this all
		     * together. Don't really want to wait for this message
		     * (and possibly have to hit return to continue!).
		     */
		    if (!expand_interactively)
			emsg(e_toomany);
		    else if (!(options & WILD_NO_BEEP))
			beep_flush();
		}
		if (!(non_suf_match != 1 && mode == WILD_EXPAND_FREE))
		    ss = vim_strsave(cmd_files[0]);
	    }
	}
    }

    /* Find longest common part */
    if (mode == WILD_LONGEST && cmd_numfiles > 0)
    {
	for (len = 0; cmd_files[0][len]; ++len)
	{
	    for (i = 0; i < cmd_numfiles; ++i)
	    {
#ifdef CASE_INSENSITIVE_FILENAME
		if (expand_context == EXPAND_DIRECTORIES
			|| expand_context == EXPAND_FILES
			|| expand_context == EXPAND_BUFFERS)
		{
		    if (TO_LOWER(cmd_files[i][len]) !=
						   TO_LOWER(cmd_files[0][len]))
			break;
		}
		else
#endif
		     if (cmd_files[i][len] != cmd_files[0][len])
		    break;
	    }
	    if (i < cmd_numfiles)
	    {
		if (!(options & WILD_NO_BEEP))
		    vim_beep();
		break;
	    }
	}
	ss = alloc((unsigned)len + 1);
	if (ss)
	{
	    STRNCPY(ss, cmd_files[0], len);
	    ss[len] = NUL;
	}
	findex = -1;			    /* next p_wc gets first one */
    }

    /* Concatenate all matching names */
    if (mode == WILD_ALL && cmd_numfiles > 0)
    {
	len = 0;
	for (i = 0; i < cmd_numfiles; ++i)
	    len += STRLEN(cmd_files[i]) + 1;
	ss = lalloc(len, TRUE);
	if (ss != NULL)
	{
	    *ss = NUL;
	    for (i = 0; i < cmd_numfiles; ++i)
	    {
		STRCAT(ss, cmd_files[i]);
		if (i != cmd_numfiles - 1)
		    STRCAT(ss, (options & WILD_USE_NL) ? "\n" : " ");
	    }
	}
    }

    if (mode == WILD_EXPAND_FREE || mode == WILD_ALL)
    {
	FreeWild(cmd_numfiles, cmd_files);
	cmd_numfiles = -1;
    }

    return ss;
}

/*
 * For each file name in files[num_files]:
 * If 'orig_pat' starts with "~/", replace the home directory with "~".
 */
    void
tilde_replace(orig_pat, num_files, files)
    char_u  *orig_pat;
    int	    num_files;
    char_u  **files;
{
    int	    i;
    char_u  *p;

    if (orig_pat[0] == '~' && vim_ispathsep(orig_pat[1]))
    {
	for (i = 0; i < num_files; ++i)
	{
	    p = home_replace_save(NULL, files[i]);
	    if (p != NULL)
	    {
		vim_free(files[i]);
		files[i] = p;
	    }
	}
    }
}

/*
 * show all matches for completion on the command line
 */
    static int
showmatches()
{
    char_u	*file_str;
    int		num_files;
    char_u	**files_found;
    int		i, j, k;
    int		maxlen;
    int		lines;
    int		columns;
    char_u	*p;
    int		lastlen;
    int		attr;

    set_expand_context();
    if (expand_context == EXPAND_UNSUCCESSFUL)
    {
	beep_flush();
	return OK;  /* Something illegal on command line */
    }
    if (expand_context == EXPAND_NOTHING)
    {
	/* Caller can use the character as a normal char instead */
	return FAIL;
    }
    expand_interactively = TRUE;

    /* add star to file name, or convert to regexp if not expanding files! */
    file_str = addstar(expand_pattern,
		      (int)(ccline.cmdbuff + ccline.cmdpos - expand_pattern));
    if (file_str == NULL)
    {
	expand_interactively = FALSE;
	return OK;
    }

    msg_didany = FALSE;			/* lines_left will be set */
    msg_start();			/* prepare for paging */
    msg_putchar('\n');
    out_flush();
    cmdline_row = msg_row;
    msg_didany = FALSE;			/* lines_left will be set again */
    msg_start();			/* prepare for paging */

    /* find all files that match the description */
    if (ExpandFromContext(file_str, &num_files, &files_found, FALSE, 0) == FAIL)
    {
	num_files = 0;
	files_found = (char_u **)"";
    }

    /* find the length of the longest file name */
    maxlen = 0;
    for (i = 0; i < num_files; ++i)
    {
	if (expand_context == EXPAND_FILES || expand_context == EXPAND_BUFFERS)
	{
	    home_replace(NULL, files_found[i], NameBuff, MAXPATHL, TRUE);
	    j = vim_strsize(NameBuff);
	}
	else
	    j = vim_strsize(files_found[i]);
	if (j > maxlen)
	    maxlen = j;
    }

    /* compute the number of columns and lines for the listing */
    maxlen += 2;    /* two spaces between file names */
    columns = ((int)Columns + 2) / maxlen;
    if (columns < 1)
	columns = 1;
    lines = (num_files + columns - 1) / columns;

    attr = hl_attr(HLF_D);	/* find out highlighting for directories */

    /* list the files line by line */
    for (i = 0; i < lines; ++i)
    {
	lastlen = 999;
	for (k = i; k < num_files; k += lines)
	{
	    for (j = maxlen - lastlen; --j >= 0; )
		msg_putchar(' ');
	    if (expand_context == EXPAND_FILES ||
					     expand_context == EXPAND_BUFFERS)
	    {
			/* highlight directories */
		j = (mch_isdir(files_found[k]));
		home_replace(NULL, files_found[k], NameBuff, MAXPATHL, TRUE);
		p = NameBuff;
	    }
	    else
	    {
		j = FALSE;
		p = files_found[k];
	    }
	    lastlen = msg_outtrans_attr(p, j ? attr : 0);
	}
	msg_clr_eos();
	msg_putchar('\n');
	out_flush();		    /* show one line at a time */
	if (got_int)
	{
	    got_int = FALSE;
	    break;
	}
    }
    vim_free(file_str);
    FreeWild(num_files, files_found);

/*
 * we redraw the command below the lines that we have just listed
 * This is a bit tricky, but it saves a lot of screen updating.
 */
    cmdline_row = msg_row;	/* will put it back later */

    expand_interactively = FALSE;
    return OK;
}

/*
 * Prepare a string for expansion.
 * When expanding file names:  The string will be used with expand_wildcards().
 * Copy the file name into allocated memory and add a '*' at the end.
 * When expanding other names:	The string will be used with regcomp().  Copy
 * the name into allocated memory and add ".*" at the end.
 */
    char_u *
addstar(fname, len)
    char_u  *fname;
    int	    len;
{
    char_u  *retval;
    int	    i, j;
    int	    new_len;
    char_u  *tail;

    if (expand_interactively && expand_context != EXPAND_FILES &&
					 expand_context != EXPAND_DIRECTORIES)
    {
	/*
	 * Matching will be done internally (on something other than files).
	 * So we convert the file-matching-type wildcards into our kind for
	 * use with vim_regcomp().  First work out how long it will be:
	 */

	/* for help tags the translation is done in find_help_tags() */
	if (expand_context == EXPAND_HELP)
	    retval = vim_strnsave(fname, len);
	else
	{
	    new_len = len + 2;		/* +2 for '^' at start, NUL at end */
	    for (i = 0; i < len; i++)
	    {
		if (fname[i] == '*' || fname[i] == '~')
		    new_len++;		/* '*' needs to be replaced by ".*"
					   '~' needs to be replaced by "\~" */

		/* Buffer names are like file names.  "." should be literal */
		if (expand_context == EXPAND_BUFFERS && fname[i] == '.')
		    new_len++;		/* "." becomes "\." */
	    }
	    retval = alloc(new_len);
	    if (retval != NULL)
	    {
		retval[0] = '^';
		j = 1;
		for (i = 0; i < len; i++, j++)
		{
		    if (fname[i] == '\\' && ++i == len)	/* skip backslash */
			break;

		    switch (fname[i])
		    {
			case '*':   retval[j++] = '.';
				    break;
			case '~':   retval[j++] = '\\';
				    break;
			case '?':   retval[j] = '.';
				    continue;
			case '.':   if (expand_context == EXPAND_BUFFERS)
					retval[j++] = '\\';
				    break;
		    }
		    retval[j] = fname[i];
		}
		retval[j] = NUL;
	    }
	}
    }
    else
    {
	retval = alloc(len + 4);
	if (retval != NULL)
	{
	    STRNCPY(retval, fname, len);
	    retval[len] = NUL;
#ifndef macintosh
	    if (!expand_set_path)
		backslash_halve(retval, TRUE);	/* remove some backslashes */
#endif
	    len = STRLEN(retval);

	    /*
	     * Don't add a star to ~, ~user, $var or `cmd`.
	     * ~ would be at the start of the tail.
	     * $ could be anywhere in the tail.
	     * ` could be anywhere in the file name.
	     */
	    tail = gettail(retval);
	    if (*tail != '~' && vim_strchr(tail, '$') == NULL
					   && vim_strchr(retval, '`') == NULL)
	    {
#ifdef MSDOS
		/*
		 * if there is no dot in the file name, add "*.*" instead of
		 * "*".
		 */
		for (i = len - 1; i >= 0; --i)
		    if (vim_strchr((char_u *)".\\/:", retval[i]) != NULL)
			break;
		if (i < 0 || retval[i] != '.')
		{
		    retval[len++] = '*';
		    retval[len++] = '.';
		}
#endif
		retval[len++] = '*';
	    }
	    retval[len] = NUL;
	}
    }
    return retval;
}

/*
 * Must parse the command line so far to work out what context we are in.
 * Completion can then be done based on that context.
 * This routine sets two global variables:

⌨️ 快捷键说明

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