📄 buffer.c
字号:
}
resettitle();
}
/*
* Append (file 2 of 8) to 'buf', if editing more than one file.
* Return TRUE if it was appended.
*/
static int
append_arg_number(buf, add_file, maxlen)
char_u *buf;
int add_file; /* Add "file" before the arg number */
int maxlen; /* maximum nr of chars in buf */
{
char_u *p;
if (arg_file_count <= 1) /* nothing to do */
return FALSE;
p = buf + STRLEN(buf); /* go to the end of the buffer */
if (p - buf + 35 >= maxlen) /* getting too long */
return FALSE;
*p++ = ' ';
*p++ = '(';
if (add_file)
{
STRCPY(p, "file ");
p += 5;
}
sprintf((char *)p, curwin->w_arg_idx_invalid ? "(%d) of %d)" :
"%d of %d)", curwin->w_arg_idx + 1, arg_file_count);
return TRUE;
}
/*
* Put current window title back (used after calling a shell)
*/
void
resettitle()
{
mch_settitle(lasttitle, lasticon);
}
/*
* If fname is not a full path, make it a full path.
* Returns pointer to allocated memory (NULL for failure).
*/
char_u *
fix_fname(fname)
char_u *fname;
{
/*
* Force expanding the path always for Unix, because symbolic links may
* mess up the full path name, even though it starts with a '/'.
*/
#ifdef UNIX
return FullName_save(fname, TRUE);
#else
if (!mch_isFullName(fname))
return FullName_save(fname, FALSE);
fname = vim_strsave(fname);
#ifdef USE_FNAME_CASE
# ifdef USE_LONG_FNAME
if (USE_LONG_FNAME)
# endif
{
if (fname != NULL)
fname_case(fname); /* set correct case for file name */
}
#endif
return fname;
#endif
}
/*
* make ffname a full file name, set sfname to ffname if not NULL
* ffname becomes a pointer to allocated memory (or NULL).
*/
void
fname_expand(ffname, sfname)
char_u **ffname;
char_u **sfname;
{
if (*ffname == NULL) /* if no file name given, nothing to do */
return;
if (*sfname == NULL) /* if no short file name given, use ffname */
*sfname = *ffname;
*ffname = fix_fname(*ffname); /* expand to full path */
}
/*
* do_arg_all(): Open up to 'count' windows, one for each argument.
*/
void
do_arg_all(count, forceit)
int count;
int forceit; /* hide buffers in current windows */
{
int i;
WIN *wp, *wpnext;
char_u *opened; /* array of flags for which args are open */
int opened_len; /* lenght of opened[] */
int use_firstwin = FALSE; /* use first window for arglist */
int split_ret = OK;
int p_sb_save;
int p_ea_save;
if (arg_file_count <= 0)
{
/* Don't give an error message. We don't want it when the ":all"
* command is in the .vimrc. */
return;
}
setpcmark();
opened_len = arg_file_count;
opened = alloc_clear((unsigned)opened_len);
if (opened == NULL)
return;
#ifdef USE_GUI
need_mouse_correct = TRUE;
#endif
/*
* Try closing all windows that are not in the argument list.
* When 'hidden' or "forceit" set the buffer becomes hidden.
* Windows that have a changed buffer and can't be hidden won't be closed.
*/
for (wp = firstwin; wp != NULL; wp = wpnext)
{
wpnext = wp->w_next;
if (wp->w_buffer->b_ffname == NULL || wp->w_buffer->b_nwindows > 1)
i = arg_file_count;
else
{
/* check if the buffer in this window is in the arglist */
for (i = 0; i < arg_file_count; ++i)
{
if (fullpathcmp(arg_files[i],
wp->w_buffer->b_ffname, TRUE) & FPC_SAME)
{
if (i < opened_len)
opened[i] = TRUE;
break;
}
}
}
wp->w_arg_idx = i;
if (i == arg_file_count) /* close this window */
{
if (p_hid || forceit || wp->w_buffer->b_nwindows > 1
|| !buf_changed(wp->w_buffer))
{
/* If the buffer was changed, and we would like to hide it,
* try autowriting. */
if (!p_hid && wp->w_buffer->b_nwindows <= 1
&& buf_changed(wp->w_buffer))
{
autowrite(wp->w_buffer, FALSE);
#ifdef AUTOCMD
/* check if autocommands removed the window */
if (!win_valid(wp))
{
wpnext = firstwin; /* start all over... */
continue;
}
#endif
}
if (firstwin == lastwin) /* can't close last window */
use_firstwin = TRUE;
else
{
close_window(wp, !p_hid && !buf_changed(wp->w_buffer));
#ifdef AUTOCMD
/* check if autocommands removed the next window */
if (!win_valid(wpnext))
wpnext = firstwin; /* start all over... */
#endif
}
}
}
}
/*
* Open a window for files in the argument list that don't have one.
* arg_file_count may change while doing this, because of autocommands.
*/
if (count > arg_file_count || count <= 0)
count = arg_file_count;
#ifdef AUTOCMD
/* Don't execute Win/Buf Enter/Leave autocommands here. */
++autocmd_no_enter;
++autocmd_no_leave;
#endif
win_enter(lastwin, FALSE);
for (i = 0; i < count && i < arg_file_count && !got_int; ++i)
{
if (i == arg_file_count - 1)
arg_had_last = TRUE;
if (i < opened_len && opened[i])
{
/* Move the already present window to below the current window */
if (curwin->w_arg_idx != i)
{
for (wpnext = firstwin; wpnext != NULL; wpnext = wpnext->w_next)
{
if (wpnext->w_arg_idx == i)
{
win_move_after(wpnext, curwin);
break;
}
}
}
}
else if (split_ret == OK)
{
if (!use_firstwin) /* split current window */
{
p_sb_save = p_sb;
p_ea_save = p_ea;
p_sb = TRUE; /* put windows in order of arglist */
p_ea = TRUE; /* use space from all windows */
split_ret = win_split(0, FALSE, TRUE);
p_sb = p_sb_save;
p_ea = p_ea_save;
if (split_ret == FAIL)
continue;
}
#ifdef AUTOCMD
else /* first window: do autocmd for leaving this buffer */
--autocmd_no_leave;
#endif
curwin->w_arg_idx = i;
/* edit file i */
(void)do_ecmd(0, arg_files[i], NULL, NULL, (linenr_t)1,
((p_hid || buf_changed(curwin->w_buffer)) ? ECMD_HIDE : 0)
+ ECMD_OLDBUF);
#ifdef AUTOCMD
if (use_firstwin)
++autocmd_no_leave;
#endif
use_firstwin = FALSE;
}
ui_breakcheck();
}
#ifdef AUTOCMD
--autocmd_no_enter;
#endif
win_enter(firstwin, FALSE); /* back to first window */
#ifdef AUTOCMD
--autocmd_no_leave;
#endif
}
/*
* do_buffer_all: Open a window for each buffer.
*
* 'count' is the maximum number of windows to open.
* When 'all' is TRUE, also load inactive buffers.
*/
void
do_buffer_all(count, all)
int count;
int all;
{
BUF *buf;
WIN *wp, *wpnext;
int split_ret = OK;
int p_sb_save;
int p_ea_save;
int open_wins = 0;
setpcmark();
#ifdef USE_GUI
need_mouse_correct = TRUE;
#endif
/*
* Close superfluous windows (two windows for the same buffer).
*/
for (wp = firstwin; wp != NULL; wp = wpnext)
{
wpnext = wp->w_next;
if (wp->w_buffer->b_nwindows > 1)
{
close_window(wp, FALSE);
#ifdef AUTOCMD
wpnext = firstwin; /* just in case an autocommand does
something strange with windows */
open_wins = 0;
#endif
}
else
++open_wins;
}
/*
* Go through the buffer list. When a buffer doesn't have a window yet,
* open one. Otherwise move the window to the right position.
* Watch out for autocommands that delete buffers or windows!
*/
#ifdef AUTOCMD
/* Don't execute Win/Buf Enter/Leave autocommands here. */
++autocmd_no_enter;
#endif
win_enter(lastwin, FALSE);
#ifdef AUTOCMD
++autocmd_no_leave;
#endif
for (buf = firstbuf; buf != NULL && open_wins < count; buf = buf->b_next)
{
/* Check if this buffer needs a window */
if (!all && buf->b_ml.ml_mfp == NULL)
continue;
/* Check if this buffer already has a window */
for (wp = firstwin; wp != NULL; wp = wp->w_next)
if (wp->w_buffer == buf)
break;
/* If the buffer already has a window, move it */
if (wp != NULL)
win_move_after(wp, curwin);
else if (split_ret == OK)
{
/* Split the window and put the buffer in it */
p_sb_save = p_sb;
p_ea_save = p_ea;
p_sb = TRUE; /* put windows in order of arglist */
p_ea = TRUE; /* use space from all windows */
split_ret = win_split(0, FALSE, TRUE);
++open_wins;
p_sb = p_sb_save;
p_ea = p_ea_save;
if (split_ret == FAIL)
continue;
(void)do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD,
(int)buf->b_fnum, 0);
#ifdef AUTOCMD
if (!buf_valid(buf)) /* autocommands deleted the buffer!!! */
break;
#endif
}
ui_breakcheck();
if (got_int)
{
(void)vgetc(); /* only break the file loading, not the rest */
break;
}
}
#ifdef AUTOCMD
--autocmd_no_enter;
#endif
win_enter(firstwin, FALSE); /* back to first window */
#ifdef AUTOCMD
--autocmd_no_leave;
#endif
/*
* Close superfluous windows.
*/
for (wp = lastwin; open_wins > count; )
{
if (p_hid || !buf_changed(wp->w_buffer)
|| autowrite(wp->w_buffer, FALSE) == OK)
{
close_window(wp, !p_hid);
--open_wins;
wp = lastwin;
}
else
{
wp = wp->w_prev;
if (wp == NULL)
break;
}
}
}
/*
* do_modelines() - process mode lines for the current file
*
* Returns immediately if the "ml" option isn't set.
*/
static int chk_modeline __ARGS((linenr_t));
void
do_modelines()
{
linenr_t lnum;
int nmlines;
if (!curbuf->b_p_ml || (nmlines = (int)p_mls) == 0)
return;
for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count && lnum <= nmlines;
++lnum)
if (chk_modeline(lnum) == FAIL)
nmlines = 0;
for (lnum = curbuf->b_ml.ml_line_count; lnum > 0 && lnum > nmlines &&
lnum > curbuf->b_ml.ml_line_count - nmlines; --lnum)
if (chk_modeline(lnum) == FAIL)
nmlines = 0;
}
/*
* chk_modeline() - check a single line for a mode string
* Return FAIL if an error encountered.
*/
static int
chk_modeline(lnum)
linenr_t lnum;
{
char_u *s;
char_u *e;
char_u *linecopy; /* local copy of any modeline found */
int prev;
int end;
int retval = OK;
char_u *save_sourcing_name;
prev = -1;
for (s = ml_get(lnum); *s != NUL; ++s)
{
if (prev == -1 || vim_isspace(prev))
{
if ((prev != -1 && STRNCMP(s, "ex:", (size_t)3) == 0) ||
STRNCMP(s, "vi:", (size_t)3) == 0 ||
STRNCMP(s, "vim:", (size_t)4) == 0)
break;
}
prev = *s;
}
if (*s)
{
do /* skip over "ex:", "vi:" or "vim:" */
++s;
while (s[-1] != ':');
s = linecopy = vim_strsave(s); /* copy the line, it will change */
if (linecopy == NULL)
return FAIL;
sourcing_lnum = lnum; /* prepare for emsg() */
save_sourcing_name = sourcing_name;
sourcing_name = (char_u *)"modelines";
end = FALSE;
while (end == FALSE)
{
s = skipwhite(s);
if (*s == NUL)
break;
/*
* Find end of set command: ':' or end of line.
*/
for (e = s; (*e != ':' || *(e - 1) == '\\') && *e != NUL; ++e)
;
if (*e == NUL)
end = TRUE;
/*
* If there is a "set" command, require a terminating ':' and
* ignore the stuff after the ':'.
* "vi:set opt opt opt: foo" -- foo not interpreted
* "vi:opt opt opt: foo" -- foo interpreted
*/
if (STRNCMP(s, "set ", (size_t)4) == 0)
{
if (*e != ':') /* no terminating ':'? */
break;
end = TRUE;
s += 4;
}
*e = NUL; /* truncate the set command */
if (do_set(s) == FAIL) /* stop if error found */
{
retval = FAIL;
break;
}
s = e + 1; /* advance to next part */
}
sourcing_lnum = 0;
sourcing_name = save_sourcing_name;
vim_free(linecopy);
}
return retval;
}
#ifdef VIMINFO
int
read_viminfo_bufferlist(line, fp, writing)
char_u *line;
FILE *fp;
int writing;
{
char_u *tab;
linenr_t lnum;
colnr_t col;
BUF *buf;
char_u *sfname;
/* don't read in if there are files on the command-line or if writing: */
if (!writing && arg_file_count == 0 && find_viminfo_parameter('%') != NULL)
{
tab = vim_strchr(line + 1, '\t');
lnum = 0;
col = 0;
if (tab != NULL)
{
*tab++ = '\0';
lnum = atol((char *)tab);
tab = vim_strchr(tab, '\t');
if (tab != NULL)
col = atoi((char *)tab + 1);
}
/* Expand "~/" in the file name at "line + 1" to a full path.
* Then try shortening it by comparing with the current directory */
expand_env(line + 1, NameBuff, MAXPATHL);
mch_dirname(IObuff, IOSIZE);
sfname = shorten_fname(NameBuff, IObuff);
if (sfname == NULL)
sfname = NameBuff;
buf = buflist_new(NameBuff, sfname, (linenr_t)0, FALSE);
if (buf != NULL) /* just in case... */
{
buf->b_last_cursor.lnum = lnum;
buf->b_last_cursor.col = col;
buflist_setfpos(buf, lnum, col);
}
}
return vim_fgets(line, LSIZE, fp);
}
void
write_viminfo_bufferlist(fp)
FILE *fp;
{
BUF *buf;
WIN *win;
if (find_viminfo_parameter('%') == NULL)
return;
for (win = firstwin; win != NULL; win = win->w_next)
set_last_cursor(win);
fprintf(fp, "\n# Buffer list:\n");
for (buf = firstbuf; buf != NULL ; buf = buf->b_next)
{
if (buf->b_fname == NULL || buf->b_help || removable(buf->b_ffname))
continue;
home_replace(NULL, buf->b_ffname, NameBuff, MAXPATHL, TRUE);
fprintf(fp, "%%%s\t%ld\t%d\n", NameBuff,
(long)buf->b_last_cursor.lnum,
buf->b_last_cursor.col);
}
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -