📄 edit.c
字号:
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 + -