📄 buffer.c
字号:
}
/* in non-help buffer, try to skip help buffers, and vv */
if (buf->b_ml.ml_mfp != NULL && buf->b_help == curbuf->b_help)
break;
if (forward)
buf = buf->b_next;
else
buf = buf->b_prev;
}
if (buf == NULL) /* No loaded buffers, just take one */
{
if (curbuf->b_next != NULL)
buf = curbuf->b_next;
else
buf = curbuf->b_prev;
}
}
/*
* make buf current buffer
*/
if (action == DOBUF_SPLIT) /* split window first */
{
if (win_split(0, FALSE, FALSE) == FAIL)
return FAIL;
}
/* go to current buffer - nothing to do */
if (buf == curbuf)
return OK;
/*
* Check if the current buffer may be abandoned.
*/
if (action == DOBUF_GOTO && !can_abandon(curbuf, forceit))
{
EMSG(e_nowrtmsg);
return FAIL;
}
setpcmark();
curwin->w_alt_fnum = curbuf->b_fnum; /* remember alternate file */
buflist_altfpos(); /* remember curpos */
/* close_windows() or apply_autocmds() may change curbuf */
delbuf = curbuf;
#ifdef AUTOCMD
apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
if (buf_valid(delbuf))
#endif
{
if (action == DOBUF_UNLOAD || action == DOBUF_DEL)
close_windows(delbuf);
if (buf_valid(delbuf))
close_buffer(delbuf == curwin->w_buffer ? curwin : NULL, delbuf,
(action == DOBUF_GOTO && !p_hid && !buf_changed(delbuf))
|| action == DOBUF_UNLOAD || action == DOBUF_DEL,
action == DOBUF_DEL);
}
#ifdef AUTOCMD
if (buf_valid(buf)) /* an autocommand may have deleted buf! */
#endif
enter_buffer(buf);
return OK;
}
/*
* enter a new current buffer.
* (old curbuf must have been freed already)
*/
static void
enter_buffer(buf)
BUF *buf;
{
buf_copy_options(curbuf, buf, BCO_ENTER | BCO_NOHELP);
curwin->w_buffer = buf;
curbuf = buf;
++curbuf->b_nwindows;
if (curbuf->b_ml.ml_mfp == NULL) /* need to load the file */
open_buffer(FALSE);
else
{
need_fileinfo = TRUE; /* display file info after redraw */
buf_check_timestamp(curbuf); /* check if file has changed */
#ifdef AUTOCMD
apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
#endif
}
buflist_getfpos(); /* restore curpos.lnum and possibly
* curpos.col */
check_arg_idx(); /* check for valid arg_idx */
maketitle();
scroll_cursor_halfway(FALSE); /* redisplay at correct position */
update_screen(NOT_VALID);
}
/*
* functions for dealing with the buffer list
*/
/*
* Add a file name to the buffer list. Return a pointer to the buffer.
* If the same file name already exists return a pointer to that buffer.
* If it does not exist, or if fname == NULL, a new entry is created.
* If use_curbuf is TRUE, may use current buffer.
* This is the ONLY way to create a new buffer.
*/
static int top_file_num = 1; /* highest file number */
BUF *
buflist_new(ffname, sfname, lnum, use_curbuf)
char_u *ffname;
char_u *sfname;
linenr_t lnum;
int use_curbuf;
{
BUF *buf;
fname_expand(&ffname, &sfname); /* will allocate ffname */
/*
* If file name already exists in the list, update the entry.
*/
if (ffname != NULL && (buf = buflist_findname(ffname)) != NULL)
{
vim_free(ffname);
if (lnum != 0)
buflist_setfpos(buf, lnum, (colnr_t)0);
/* copy the options now, if 'cpo' doesn't have 's' and not done
* already */
buf_copy_options(curbuf, buf, 0);
return buf;
}
/*
* If the current buffer has no name and no contents, use the current
* buffer. Otherwise: Need to allocate a new buffer structure.
*
* This is the ONLY place where a new buffer structure is allocated!
*/
if (use_curbuf && curbuf != NULL && curbuf->b_ffname == NULL &&
curbuf->b_nwindows <= 1 &&
(curbuf->b_ml.ml_mfp == NULL || bufempty()))
{
buf = curbuf;
#ifdef AUTOCMD
/* It's like this buffer is deleted. */
apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
#endif
}
else
{
buf = (BUF *)alloc_clear((unsigned)sizeof(BUF));
if (buf == NULL)
{
vim_free(ffname);
return NULL;
}
}
if (ffname != NULL)
{
buf->b_ffname = ffname;
buf->b_sfname = vim_strsave(sfname);
}
if (buf->b_winfpos == NULL)
buf->b_winfpos = (WINFPOS *)alloc((unsigned)sizeof(WINFPOS));
if ((ffname != NULL && (buf->b_ffname == NULL ||
buf->b_sfname == NULL)) || buf->b_winfpos == NULL)
{
vim_free(buf->b_ffname);
buf->b_ffname = NULL;
vim_free(buf->b_sfname);
buf->b_sfname = NULL;
if (buf != curbuf)
free_buffer(buf);
return NULL;
}
if (buf == curbuf)
{
buf_freeall(buf, FALSE); /* free all things allocated for this buffer */
buf->b_nwindows = 0;
}
else
{
/*
* put new buffer at the end of the buffer list
*/
buf->b_next = NULL;
if (firstbuf == NULL) /* buffer list is empty */
{
buf->b_prev = NULL;
firstbuf = buf;
}
else /* append new buffer at end of list */
{
lastbuf->b_next = buf;
buf->b_prev = lastbuf;
}
lastbuf = buf;
buf->b_fnum = top_file_num++;
if (top_file_num < 0) /* wrap around (may cause duplicates) */
{
EMSG("Warning: List of file names overflow");
ui_delay(3000L, TRUE); /* make sure it is noticed */
top_file_num = 1;
}
buf->b_winfpos->wl_fpos.lnum = lnum;
buf->b_winfpos->wl_fpos.col = 0;
buf->b_winfpos->wl_next = NULL;
buf->b_winfpos->wl_prev = NULL;
buf->b_winfpos->wl_win = curwin;
#ifdef WANT_EVAL
var_init(&buf->b_vars); /* init internal variables */
#endif
/*
* Always copy the options from the current buffer.
*/
buf_copy_options(curbuf, buf, BCO_ALWAYS);
}
buf->b_fname = buf->b_sfname;
buf->b_u_synced = TRUE;
buf->b_flags |= BF_CHECK_RO | BF_NEVERLOADED;
buf_clear(buf);
clrallmarks(buf); /* clear marks */
fmarks_check_names(buf); /* check file marks for this file */
return buf;
}
/*
* Get the highest buffer number. Note that some buffers may have been
* deleted.
*/
int
buflist_maxbufnr()
{
return (top_file_num - 1);
}
/*
* Free the memory for the options of a buffer.
*/
void
free_buf_options(buf, free_p_ff)
BUF *buf;
int free_p_ff; /* also free 'fileformat'? */
{
if (free_p_ff)
{
free_string_option(buf->b_p_ff);
#ifdef MULTI_BYTE
free_string_option(buf->b_p_fe);
#endif
}
free_string_option(buf->b_p_mps);
free_string_option(buf->b_p_fo);
free_string_option(buf->b_p_isk);
free_string_option(buf->b_p_com);
free_string_option(buf->b_p_nf);
#ifdef SYNTAX_HL
free_string_option(buf->b_p_syn);
#endif
#ifdef CINDENT
free_string_option(buf->b_p_cink);
free_string_option(buf->b_p_cino);
#endif
#if defined(CINDENT) || defined(SMARTINDENT)
free_string_option(buf->b_p_cinw);
#endif
#ifdef INSERT_EXPAND
free_string_option(buf->b_p_cpt);
#endif
}
/*
* get alternate file n
* set linenr to lnum or altfpos.lnum if lnum == 0
* also set cursor column to altfpos.col if 'startofline' is not set.
* if (options & GETF_SETMARK) call setpcmark()
* if (options & GETF_ALT) we are jumping to an alternate file.
*
* return FAIL for failure, OK for success
*/
int
buflist_getfile(n, lnum, options, forceit)
int n;
linenr_t lnum;
int options;
int forceit;
{
BUF *buf;
FPOS *fpos;
colnr_t col;
buf = buflist_findnr(n);
if (buf == NULL)
{
if ((options & GETF_ALT) && n == 0)
emsg(e_noalt);
else
EMSGN("buffer %ld not found", n);
return FAIL;
}
/* if alternate file is the current buffer, nothing to do */
if (buf == curbuf)
return OK;
/* altfpos may be changed by getfile(), get it now */
if (lnum == 0)
{
fpos = buflist_findfpos(buf);
lnum = fpos->lnum;
col = fpos->col;
}
else
col = 0;
++RedrawingDisabled;
if (getfile(buf->b_fnum, NULL, NULL, (options & GETF_SETMARK),
lnum, forceit) <= 0)
{
--RedrawingDisabled;
/* cursor is at to BOL and w_cursor.lnum is checked due to getfile() */
if (!p_sol && col != 0)
{
curwin->w_cursor.col = col;
check_cursor_col();
}
return OK;
}
--RedrawingDisabled;
return FAIL;
}
/*
* go to the last know line number for the current buffer
*/
void
buflist_getfpos()
{
FPOS *fpos;
fpos = buflist_findfpos(curbuf);
curwin->w_cursor.lnum = fpos->lnum;
check_cursor_lnum();
if (p_sol)
curwin->w_cursor.col = 0;
else
{
curwin->w_cursor.col = fpos->col;
check_cursor_col();
}
}
/*
* find file in buffer list by name (it has to be for the current window)
* 'ffname' must have a full path.
*/
BUF *
buflist_findname(ffname)
char_u *ffname;
{
BUF *buf;
for (buf = firstbuf; buf != NULL; buf = buf->b_next)
if (buf->b_ffname != NULL && fnamecmp(ffname, buf->b_ffname) == 0)
return (buf);
return NULL;
}
/*
* Find file in buffer list by a regexppattern.
* Return fnum of the found buffer, < 0 for error.
*/
int
buflist_findpat(pattern, pattern_end)
char_u *pattern;
char_u *pattern_end; /* pointer to first char after pattern */
{
BUF *buf;
vim_regexp *prog;
int fnum = -1;
char_u *pat;
char_u *match;
int attempt;
char_u *p;
if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#'))
{
if (*pattern == '%')
fnum = curbuf->b_fnum;
else
fnum = curwin->w_alt_fnum;
}
/*
* Try four ways of matching:
* attempt == 0: without '^' or '$' (at any position)
* attempt == 1: with '^' at start (only at postion 0)
* attempt == 2: with '$' at end (only match at end)
* attempt == 3: with '^' at start and '$' at end (only full match)
*/
else for (attempt = 0; attempt <= 3; ++attempt)
{
/* may add '^' and '$' */
pat = file_pat_to_reg_pat(pattern, pattern_end, NULL);
if (pat == NULL)
return -1;
if (attempt < 2)
{
p = pat + STRLEN(pat) - 1;
if (p > pat && *p == '$') /* remove '$' */
*p = NUL;
}
p = pat;
if (*p == '^' && !(attempt & 1)) /* remove '^' */
++p;
prog = vim_regcomp(p, (int)p_magic);
vim_free(pat);
if (prog == NULL)
return -1;
for (buf = firstbuf; buf != NULL; buf = buf->b_next)
{
match = buflist_match(prog, buf);
if (match != NULL)
{
if (fnum >= 0) /* already found a match */
{
fnum = -2;
break;
}
fnum = buf->b_fnum; /* remember first match */
}
}
vim_free(prog);
if (fnum >= 0) /* found one match */
break;
}
if (fnum == -2)
EMSG2("More than one match for %s", pattern);
else if (fnum < 1)
EMSG2("No matching buffer for %s", pattern);
return fnum;
}
/*
* Find all buffer names that match.
* For command line expansion of ":buf" and ":sbuf".
* Return OK if matches found, FAIL otherwise.
*/
int
ExpandBufnames(pat, num_file, file, options)
char_u *pat;
int *num_file;
char_u ***file;
int options;
{
int count = 0;
BUF *buf;
int round;
char_u *p;
int attempt;
vim_regexp *prog;
*num_file = 0; /* return values in case of FAIL */
*file = NULL;
/*
* attempt == 1: try match with '^', match at start
* attempt == 2: try match without '^', match anywhere
*/
for (attempt = 1; attempt <= 2; ++attempt)
{
if (attempt == 2)
{
if (*pat != '^') /* there's no '^', no need to try again */
break;
++pat; /* skip the '^' */
}
prog = vim_regcomp(pat, (int)p_magic);
if (prog == NULL)
return FAIL;
/*
* round == 1: Count the matches.
* round == 2: Build the array to keep the matches.
*/
for (round = 1; round <= 2; ++round)
{
count = 0;
for (buf = firstbuf; buf != NULL; buf = buf->b_next)
{
p = buflist_match(prog, buf);
if (p != NULL)
{
if (round == 1)
++count;
else
{
if (options & WILD_HOME_REPLACE)
p = home_replace_save(buf, p);
else
p = vim_strsave(p);
(*file)[count++] = p;
}
}
}
if (count == 0) /* no match found, break here */
break;
if (round == 1)
{
*file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
if (*file == NULL)
{
vim_free(prog);
return FAIL;
}
}
}
vim_free(prog);
if (count) /* match(es) found, break here */
break;
}
*num_file = count;
return (count == 0 ? FAIL : OK);
}
/*
* Check for a match on the file name for buffer "buf" with regex prog "prog".
*/
static char_u *
buflist_match(prog, buf)
vim_regexp *prog;
BUF *buf;
{
char_u *match;
#ifdef CASE_INSENSITIVE_FILENAME
int save_reg_ic = reg_ic;
reg_ic = TRUE; /* Always ignore case */
#endif
/* First try the short file name, then the long file name. */
match = buflist_match_try(prog, buf->b_sfname);
if (match == NULL)
match = buflist_match_try(prog, buf->b_ffname);
#ifdef CASE_INSENSITIVE_FILENAME
reg_ic = save_reg_ic;
#endif
return match;
}
static char_u *
buflist_match_try(prog, name)
vim_regexp *prog;
char_u *name;
{
char_u *match = NULL;
char_u *p;
if (name != NULL)
{
if (vim_regexec(prog, name, TRUE) != 0)
match = name;
else
{
/* Replace $(HOME) with '~' and try matching again. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -