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

📄 edit.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
	return RET_ERROR;
    if (reuse & ORIGINAL_TEXT)
	match->str = original_text;
    else if ((match->str = vim_strnsave(str, len)) == NULL)
    {
	vim_free(match);
	return RET_ERROR;
    }
    /* match-fname is:
     * - curr_match->fname if it is a string equal to fname.
     * - a copy of fname, FREE_FNAME is set to free later THE allocated mem.
     * - NULL otherwise.	--Acevedo */
    if (fname && curr_match && curr_match->fname
	      && STRCMP(fname, curr_match->fname) == 0)
	match->fname = curr_match->fname;
    else if (fname && (match->fname = vim_strsave(fname)) != NULL)
	reuse |= FREE_FNAME;
    else
	match->fname = NULL;
    match->original = reuse;

    /*
     * Link the new match structure in the list of matches.
     */
    if (first_match == NULL)
	match->next = match->prev = NULL;
    else if (dir == FORWARD)
    {
	match->next = curr_match->next;
	match->prev = curr_match;
    }
    else	/* BACKWARD */
    {
	match->next = curr_match;
	match->prev = curr_match->prev;
    }
    if (match->next)
	match->next->prev = match;
    if (match->prev)
	match->prev->next = match;
    else	/* if there's nothing before, it is the first match */
	first_match = match;
    curr_match = match;

    return OK;
}

/* Make the completion list cyclic.
 * Return the number of matches (excluding the original).
 */
    static int
make_cyclic()
{
    struct Completion *match;
    int	    count = 0;

    if (first_match != NULL)
    {
	/*
	 * Find the end of the list.
	 */
	match = first_match;
	/* there's always an entry for the original_text, it doesn't count. */
	while (match->next != NULL && match->next != first_match)
	{
	    match = match->next;
	    ++count;
	}
	match->next = first_match;
	first_match->prev = match;
    }
    return count;
}

#define DICT_FIRST	(1)	/* use just first element in "dict" */
#define DICT_EXACT	(2)	/* "dict" is the exact name of a file */
/*
 * Add any identifiers that match the given pattern to the list of
 * completions.
 */
    static void
complete_dictionaries(dict, pat, dir, flags)
    char_u  *dict;
    char_u  *pat;
    int	     dir;
    int	     flags;
{
    char_u	*ptr;
    char_u	*buf;
    int		at_start;
    FILE	*fp;
    vim_regexp	*prog;
    int		add_r;
    char_u	**files;
    int		count;
    int		i;

    buf = alloc(LSIZE);
    set_reg_ic(pat);	/* set reg_ic according to p_ic, p_scs and pat */
    prog = vim_regcomp(pat, (int)p_magic);
    expand_interactively = TRUE;
    while (buf && prog && *dict != NUL && !got_int)
    {
	/* copy one dictionary file name into buf */
	if (flags == DICT_EXACT)
	{
	    count = 1;
	    files = &dict;
	}
	else
	{
	    copy_option_part(&dict, buf, LSIZE, ",");
	    if (expand_wildcards(1, &buf, &count, &files, EW_FILE|EW_DIR) != OK)
		count = 0;
	}

	for (i = 0; i < count && !got_int; i++)
	{
	    fp = fopen((char *)files[i], "r");	/* open dictionary file */
	    if (flags != DICT_EXACT)
	    {
		sprintf((char*)IObuff, "Scanning dictionary: %s",
							    (char *)files[i]);
		msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
	    }

	    if (fp != NULL)
	    {
		/*
		 * Read dictionary file line by line.
		 * Check each line for a match.
		 */
		while (!got_int && !vim_fgets(buf, LSIZE, fp))
		{
		    ptr = buf;
		    at_start = TRUE;
		    while (vim_regexec(prog, ptr, at_start))
		    {
			at_start = FALSE;
			ptr = prog->startp[0];
			while (vim_iswordc(*ptr))
			    ++ptr;
			add_r = add_completion_and_infercase(prog->startp[0],
				(int)(ptr - prog->startp[0]), files[i], dir, 0);
			if (add_r == OK)
			    /* if dir was BACKWARD then honor it just once */
			    dir = FORWARD;
			else if (add_r == RET_ERROR)
			    break;
		    }
		    line_breakcheck();
		}
		fclose(fp);
	    }
	}
	if (flags != DICT_EXACT && count > 0)
	    FreeWild(count, files);
	if (flags)
	    break;
    }
    expand_interactively = FALSE;
    vim_free(prog);
    vim_free(buf);
}

/*
 * Free the list of completions
 */
    static void
free_completions()
{
    struct Completion *match;

    if (first_match == NULL)
	return;
    curr_match = first_match;
    do
    {
	match = curr_match;
	curr_match = curr_match->next;
	vim_free(match->str);
	/* several entries may use the same fname, free it just once. */
	if (match->original & FREE_FNAME)
	    vim_free(match->fname);
	vim_free(match);
    } while (curr_match != NULL && curr_match != first_match);
    first_match = curr_match = NULL;
}

    static void
clear_insexp()
{
    continue_status = 0;
    started_completion = FALSE;
    complete_pat = NULL;
    save_sm = -1;
}

/*
 * Prepare for insert-expand, or stop it.
 */
    static int
ins_expand_pre(c)
    int	    c;
{
    char_u	*ptr;
    char_u	*tmp_ptr;
    int		temp;
    linenr_t	lnum;
    int		need_redraw = FALSE;

    if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET)
    {
	/*
	 * We have just entered ctrl-x mode and aren't quite sure which
	 * ctrl-x mode it will be yet.	Now we decide -- webb
	 */
	switch (c)
	{
	    case Ctrl('E'):
	    case Ctrl('Y'):
		ctrl_x_mode = CTRL_X_SCROLL;
		if (State == INSERT)
		    edit_submode = (char_u *)" (insert) Scroll (^E/^Y)";
		else
		    edit_submode = (char_u *)" (replace) Scroll (^E/^Y)";
		showmode();
		break;
	    case Ctrl('L'):
		ctrl_x_mode = CTRL_X_WHOLE_LINE;
		break;
	    case Ctrl('F'):
		ctrl_x_mode = CTRL_X_FILES;
		break;
	    case Ctrl('K'):
		ctrl_x_mode = CTRL_X_DICTIONARY;
		break;
	    case Ctrl(']'):
		ctrl_x_mode = CTRL_X_TAGS;
		break;
#ifdef FIND_IN_PATH
	    case Ctrl('I'):
	    case K_S_TAB:
		ctrl_x_mode = CTRL_X_PATH_PATTERNS;
		break;
	    case Ctrl('D'):
		ctrl_x_mode = CTRL_X_PATH_DEFINES;
		break;
#endif
	    case Ctrl('P'):
	    case Ctrl('N'):
		/* ^X^P means LOCAL expansion if nothing interrupted (eg we
		 * just started ^X mode, or there were enough ^X's to cancel
		 * the previous mode, say ^X^F^X^X^P or ^P^X^X^X^P, see below)
		 * do normal expansion when interrupting a different mode (say
		 * ^X^F^X^P or ^P^X^X^P, see below)
		 * nothing changes if interrupting mode 0, (eg, the flag
		 * doesn't change when going to ADDING mode  -- Acevedo */
		if (!(continue_status & CONT_INTRPT))
		    continue_status |= CONT_LOCAL;
		else if (continue_mode)
		    continue_status &=~CONT_LOCAL;
		/* FALLTHROUGH */
	    default:
		/* if we have typed at least 2 ^X's... for modes != 0, we set
		 * continue_status = 0 (eg, as if we had just started ^X mode)
		 * for mode 0, we set continue_mode to an impossible value, in
		 * both cases ^X^X can be used to restart the same mode
		 * (avoiding ADDING mode).   Undocumented feature:
		 * In a mode != 0 ^X^P and ^X^X^P start 'complete' and local
		 * ^P expansions respectively.	In mode 0 an extra ^X is
		 * needed since ^X^P goes to ADDING mode  -- Acevedo */
		if (c == Ctrl('X'))
		{
		    if (continue_mode)
			continue_status = 0;
		    else
			continue_mode = CTRL_X_NOT_DEFINED_YET;
		}
		ctrl_x_mode = 0;
		edit_submode = NULL;
		showmode();
		break;
	}
    }
    else if (ctrl_x_mode)
    {
	/* We we're already in ctrl-x mode, do we stay in it? */
	if (!vim_is_ctrl_x_key(c))
	{
	    if (ctrl_x_mode == CTRL_X_SCROLL)
		ctrl_x_mode = 0;
	    else
		ctrl_x_mode = CTRL_X_FINISHED;
	    edit_submode = NULL;
	}
	showmode();
    }
    if (started_completion || ctrl_x_mode == CTRL_X_FINISHED)
    {
	/* Show error message from attempted keyword completion (probably
	 * 'Pattern not found') until another key is hit, then go back to
	 * showing what mode we are in.
	 */
	showmode();
	if ((ctrl_x_mode == 0 && c != Ctrl('N') && c != Ctrl('P')) ||
					    ctrl_x_mode == CTRL_X_FINISHED)
	{
	    /* Get here when we have finished typing a sequence of ^N and
	     * ^P or other completion characters in CTRL-X mode. Free up
	     * memory that was used, and make sure we can redo the insert
	     * -- webb.
	     */
	    if (curr_match != NULL)
	    {
		/*
		 * If any of the original typed text has been changed,
		 * eg when ignorecase is set, we must add back-spaces to
		 * the redo buffer.  We add as few as necessary to delete
		 * just the part of the original text that has changed
		 * -- webb
		 */
		ptr = curr_match->str;
		tmp_ptr = original_text;
		while (*tmp_ptr && *tmp_ptr == *ptr)
		{
		    ++tmp_ptr;
		    ++ptr;
		}
		for (temp = 0; tmp_ptr[temp]; ++temp)
		    AppendCharToRedobuff(K_BS);
		while (*ptr)
		{
		    /* Put a string of normal characters in the redo buffer */
		    tmp_ptr = ptr;
		    while (*ptr >= ' ' && *ptr < DEL)
			++ptr;
		    /* Don't put '0' or '^' as last character, just in case a
		     * CTRL-D is typed next */
		    if (*ptr == NUL && (ptr[-1] == '0' || ptr[-1] == '^'))
			--ptr;
		    if (ptr > tmp_ptr)
		    {
			temp = *ptr;
			*ptr = NUL;
			AppendToRedobuff(tmp_ptr);
			*ptr = temp;
		    }
		    if (*ptr)
		    {
			/* quote special chars with a CTRL-V */
			AppendCharToRedobuff(Ctrl('V'));
			AppendCharToRedobuff(*ptr);
			/* CTRL-V '0' must be inserted as CTRL-V 048 */
			if (*ptr++ == '0')
			    AppendToRedobuff((char_u *)"48");
		    }
		}
	    }

	    /*
	     * When completing whole lines: fix indent for 'cindent'.
	     * Otherwise, break line if it's too long.
	     */
	    lnum = curwin->w_cursor.lnum;
	    if (continue_mode == CTRL_X_WHOLE_LINE)
	    {
#ifdef CINDENT
		/* re-indent the current line */
		if (curbuf->b_p_cin)
		    fixthisline(get_c_indent);
#endif
	    }
	    else
	    {
		/* put the cursor on the last char, for 'tw' formatting */
		curwin->w_cursor.col--;
		insertchar(NUL, FALSE, -1, FALSE);
		curwin->w_cursor.col++;
	    }
	    if (lnum != curwin->w_cursor.lnum)
	    {
		update_topline();
		update_screen(NOT_VALID);
	    }
	    else
		need_redraw = TRUE;

	    vim_free(complete_pat);
	    complete_pat = NULL;
	    free_completions();
	    started_completion = FALSE;
	    ctrl_x_mode = 0;
	    p_sm = save_sm;
	    if (edit_submode != NULL)
	    {
		edit_submode = NULL;
		showmode();
	    }
	}
    }

    /* reset continue_* if we left expansion-mode, if we stay they'll be
     * (re)set properly in ins_complete */
    if (!ctrl_x_mode && c != Ctrl('P') && c != Ctrl('N') && c != Ctrl('X'))
	continue_status = continue_mode = 0;

    return need_redraw;
}

/*
 * Loops through the list of windows, loaded-buffers or non-loaded-buffers
 * (depending on flag) starting from buf and looking for a non-scanned
 * buffer (other than curbuf).	curbuf is special, if it is called with
 * buf=curbuf then it has to be the first call for a given flag/expansion.
 *
 * Returns the buffer to scan, if any, otherwise returns curbuf -- Acevedo
 */
    static BUF*
next_buf(buf, flag)
    BUF		*buf;
    int		flag;
{
    static WIN	*w;

    if (flag == 'w')		/* just windows */
    {
	if (buf == curbuf)	/* first call for this flag/expansion */
	    w = curwin;
	while ((w = w->w_next ? w->w_next : firstwin) != curwin
		&& w->w_buffer->b_scanned)
	    ;
	buf = w->w_buffer;
    }
    else	/* 'b' (just loaded buffers) or 'u' (just non-loaded buffers) */
	while ((buf = buf->b_next ? buf->b_next : firstbuf) != curbuf
		&& ((buf->b_ml.ml_mfp == NULL) != (flag == 'u')
		    || buf->b_scanned))
	    ;
    return buf;
}

/*
 * Get the next expansion(s) for the text starting at the initial curbuf
 * position "ini" and in the direction dir.
 * Return the total of matches or -1 if still unknown -- Acevedo
 */
    static int
get_expansion(ini, dir)
    FPOS	*ini;
    int		dir;
{
    static FPOS		first_match_pos;
    static FPOS		last_match_pos;
    static char_u	*e_cpt = (char_u *)"";	/* curr. entry in 'complete' */
    static int		done_info = 0;	/* Found all matches in this dir. */
    static BUF		*ins_buf = NULL;

    FPOS		*pos;
    char_u		**matches;
    int			save_p_scs;
    int			save_p_ws;
    int			i;
    int			temp;
    int			type = ctrl_x_mode;
    char_u		*ptr;
    char_u		*tmp_ptr;
    char_u		*dict = NULL;
    int			dict_f = 0;
    struct Completion	*old_match;

    if (!started_completion)
    {
	for (ins_buf = firstbuf; ins_buf; ins_buf = ins_buf->b_next)
	    ins_buf->b_scanned = 0;
	done_info = 0;
	ins_buf = curbuf;
	e_cpt = continue_status & CONT_LOCAL ? (char_u *)"." : curbuf->b_p_cpt;
	last_match_pos = first_match_pos = *ini;
    }

    old_match = curr_match;		/* remember the last current match */
    pos = (dir == FORWARD) ? &last_match_pos : &first_match_pos;
    /* For ^N/^P loop over all the flags/windows/buffers in 'complete' */
    for (;;)
    {
	temp = FAIL;
	/* in mode 0 pick a new entry from e_cpt if started_completion is off,
	 * or if done_info says this entry is done  -- Acevedo */
	if (!ctrl_x_mode && (!started_completion || done_info == 6))

⌨️ 快捷键说明

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