📄 window.c
字号:
{
wp->w_p_scroll = ((unsigned)wp->w_height >> 1);
if (wp->w_p_scroll == 0)
wp->w_p_scroll = 1;
}
/*
* command_height: called whenever p_ch has been changed
*/
void
command_height(old_p_ch)
long old_p_ch;
{
WIN *wp;
int h;
if (!starting)
{
cmdline_row = Rows - p_ch;
if (p_ch > old_p_ch) /* p_ch got bigger */
{
for (wp = lastwin; p_ch > old_p_ch; wp = wp->w_prev)
{
if (wp == NULL)
{
emsg(e_noroom);
p_ch = old_p_ch;
break;
}
h = wp->w_height - (p_ch - old_p_ch);
if (p_wmh == 0)
{
/* don't make current window zero lines */
if (wp == curwin && h < 1)
h = 1;
}
else if (h < p_wmh)
h = p_wmh;
old_p_ch += wp->w_height - h;
win_new_height(wp, h);
}
win_comp_pos();
/* clear the lines added to cmdline */
if (full_screen)
screen_fill((int)(cmdline_row), (int)Rows, 0,
(int)Columns, ' ', ' ', 0);
msg_row = cmdline_row;
redraw_cmdline = TRUE;
return;
}
if (msg_row < cmdline_row)
msg_row = cmdline_row;
redraw_cmdline = TRUE;
}
win_new_height(lastwin, (int)(lastwin->w_height + old_p_ch - p_ch));
}
void
last_status()
{
WIN *wp;
if (lastwin->w_status_height)
{
/* remove status line */
if (p_ls == 0 || (p_ls == 1 && firstwin == lastwin))
{
win_new_height(lastwin, lastwin->w_height + 1);
lastwin->w_status_height = 0;
comp_col();
}
}
else if (p_ls == 2 || (p_ls == 1 && firstwin != lastwin))
{
/* go to first window with enough room for a win_new_height(-1) */
for (wp = lastwin; wp->w_height <= p_wmh; wp = wp->w_prev)
if (wp == NULL)
{
emsg(e_noroom);
return;
}
win_new_height(wp, wp->w_height - 1);
win_comp_pos();
lastwin->w_status_height = 1;
comp_col();
update_screen(CLEAR);
}
}
#ifdef FILE_IN_PATH
/*
* file_name_at_cursor()
*
* Return the name of the file under (or to the right of) the cursor.
*
* get_file_name_in_path()
*
* Return the name of the file at (or to the right of) ptr[col].
*
* The p_path variable is searched if the file name does not start with '/'.
* The string returned has been alloc'ed and should be freed by the caller.
* NULL is returned if the file name or file is not found.
*
* options:
* FNAME_MESS give error messages
* FNAME_EXP expand to path
* FNAME_HYP check for hypertext link
*/
char_u *
file_name_at_cursor(options, count)
int options;
long count;
{
return get_file_name_in_path(ml_get_curline(),
curwin->w_cursor.col, options, count);
}
char_u *
get_file_name_in_path(line, col, options, count)
char_u *line;
int col;
int options;
long count;
{
char_u *ptr;
char_u *file_name;
int len;
/*
* search forward for what could be the start of a file name
*/
ptr = line + col;
while (*ptr != NUL && !vim_isfilec(*ptr))
++ptr;
if (*ptr == NUL) /* nothing found */
{
if (options & FNAME_MESS)
EMSG("No file name under cursor");
return NULL;
}
/*
* search backward for first char of the file name
*/
while (ptr > line && vim_isfilec(ptr[-1]))
--ptr;
/*
* Go one char back to ":" before "//" even when ':' is not in 'isfname'.
*/
if ((options & FNAME_HYP) && ptr > line && path_is_url(ptr - 1))
--ptr;
/*
* Search forward for the last char of the file name.
* Also allow "://" when ':' is not in 'isfname'.
*/
len = 0;
while (vim_isfilec(ptr[len])
|| ((options & FNAME_HYP) && path_is_url(ptr + len)))
++len;
if (options & FNAME_HYP)
{
/* For hypertext links, ignore the name of the machine.
* Such a link looks like "type://machine/path". Only "/path" is used.
* First search for the string "://", then for the extra '/'
*/
if ((file_name = vim_strchr(ptr, ':')) != NULL &&
((path_is_url(file_name) == URL_SLASH &&
(file_name = vim_strchr(file_name + 3, '/')) != NULL) ||
(path_is_url(file_name) == URL_BACKSLASH &&
(file_name = vim_strchr(file_name + 3, '\\')) != NULL)) &&
file_name < ptr + len)
{
len -= file_name - ptr;
ptr = file_name;
if (ptr[1] == '~') /* skip '/' for /~user/path */
{
++ptr;
--len;
}
}
}
if (!(options & FNAME_EXP))
return vim_strnsave(ptr, len);
return find_file_in_path(ptr, len, options, count);
}
/*
* Find the file name "ptr[len]" in the path.
*
* options:
* FNAME_MESS give error message when not found
*
* Uses NameBuff[]!
*
* Returns an allocated string for the file name. NULL for error.
*/
static char_u *
find_file_in_path(ptr, len, options, count)
char_u *ptr; /* file name */
int len; /* length of file name */
int options;
long count; /* use count'th matching file name */
{
char_u save_char;
char_u *file_name;
char_u *curr_path = NULL;
char_u *dir;
int curr_path_len;
char_u *p;
char_u *head;
/* copy file name into NameBuff, expanding environment variables */
save_char = ptr[len];
ptr[len] = NUL;
expand_env(ptr, NameBuff, MAXPATHL);
ptr[len] = save_char;
if (mch_isFullName(NameBuff))
{
/*
* Absolute path, no need to use 'path'.
*/
if ((file_name = vim_strsave(NameBuff)) == NULL)
return NULL;
if (mch_getperm(file_name) >= 0)
return file_name;
if (options & FNAME_MESS)
EMSG2("Can't find file \"%s\"", NameBuff);
}
else
{
/*
* Relative path, use 'path' option.
*/
if (curbuf->b_fname != NULL)
{
curr_path = curbuf->b_fname;
ptr = gettail(curr_path);
curr_path_len = ptr - curr_path;
}
else
curr_path_len = 0;
if ((file_name = alloc((int)(curr_path_len + STRLEN(p_path) +
STRLEN(NameBuff) + 3))) == NULL)
return NULL;
for (dir = p_path; *dir && !got_int; )
{
len = copy_option_part(&dir, file_name, 31000, " ,");
/* len == 0 means: use current directory */
if (len != 0)
{
/* Look for file relative to current file */
if (file_name[0] == '.' && curr_path_len > 0
&& (len == 1 || vim_ispathsep(file_name[1])))
{
if (len == 1) /* just a "." */
len = 0;
else /* "./path": move "path" */
{
len -= 2;
mch_memmove(file_name + curr_path_len, file_name + 2,
(size_t)len);
}
STRNCPY(file_name, curr_path, curr_path_len);
len += curr_path_len;
}
if (!vim_ispathsep(file_name[len - 1]))
file_name[len++] = PATHSEP;
file_name[len] = '\0';
/*
* Handle "**" in the path: 'wildcard in path'.
*/
if (mch_has_wildcard(file_name))
{
p = get_past_head(file_name);
if (p == file_name) /* no absolute file name */
p = find_file_in_wildcard_path((char_u *)"",
file_name, 0, &count);
else /* absolute file name, separate head */
{
head = vim_strnsave(file_name,
(unsigned)(p - file_name));
if (head != NULL)
{
p = find_file_in_wildcard_path(head, p, 0, &count);
vim_free(head);
}
}
if (p != NULL)
{
vim_free(file_name);
return p;
}
continue;
}
}
STRCPY(file_name + len, NameBuff);
/*
* Translate names like "src/a/../b/file.c" into "src/b/file.c".
*/
simplify_filename(file_name);
if (mch_getperm(file_name) >= 0 && --count == 0)
return file_name;
}
if (options & FNAME_MESS)
EMSG2("Can't find file \"%s\" in path", NameBuff);
}
/* get here when file doesn't exist */
vim_free(file_name);
return NULL;
}
/*
* find_file_in_wildcard_path(): expand path recursively while searching
* files in path
*
* The syntax '**' means the whole subtree.
* To avoid endless recursion, a counter restricts the depth to 100 levels.
* In the following pseudo code '+/' will mean '*' followed by '/'
*
* in the case of 'set path=,/foo/bar/+/+/,'
* the function call hierarchy will be
* find_file_in_wildcard_path("/", "foo/bar/+/+/", NameBuff, 0);
* find_file_in_wildcard_path("/foo/", "bar/+/+/", NameBuff, 0);
* find_file_in_wildcard_path("/foo/bar/", "+/+/", NameBuff, 0);
* which in turn will call
* find_file_in_wildcard_path("/foo/bar/dir/", "+/", NameBuff, 1);
* for each directory 'dir' in '/foo/bar/+'. It's the next call,
* find_file_in_wildcard_path("/foo/bar/dir/dir2/", "", NameBuff, 2);
* that will try to find the file 'NameBuff' in the given directory.
*
* pseudo code:
*
* find_file_in_wildcard_path(path_so_far, wildcards, level)
* {
* if (level > 100)
* return NULL;
*
* file_name = path_so_far + first_segment(wildcards);
* rest_of_wildcards = all_but_first_segment(wildcards);
*
* result = expand(file_name);
*
* if (!rest_of_wildcards) {
* foreach_path_in(result) {
* if (exists&readable(path + NameBuff))
* return path+NameBuff;
* }
* } else {
* foreach_path_in(result) {
* c = find_file_in_wildcard_path(path, rest_of_wildcards, level+1);
* if (c)
* return c;
* }
* }
* if (infinite_recursion(wildcards)) {
* foreach_path_in(result) {
* c = find_file_in_wildcard_path(path, wildcards, level+1);
* if (c)
* return c;
* }
* }
* return NULL;
* }
*/
static char_u *
find_file_in_wildcard_path(path_so_far, wildcards, level, countptr)
char_u *path_so_far;
char_u *wildcards;
int level;
long *countptr;
{
char_u *file_name;
int len;
char_u *rest_of_wildcards;
int nFiles = 0;
char_u **ppFiles;
int i;
char_u *c;
ui_breakcheck();
if (level > 100 || got_int)
return NULL;
if ((file_name = alloc((int)MAXPATHL)) == NULL)
return NULL;
STRCPY(file_name, path_so_far);
len = STRLEN(file_name);
if (!vim_ispathsep(file_name[len-1]))
{
file_name[len++] = PATHSEP;
file_name[len] = '\0';
}
rest_of_wildcards = wildcards;
if (rest_of_wildcards)
{
if (STRNCMP(rest_of_wildcards, "**", 2) == 0)
rest_of_wildcards++;
while (*rest_of_wildcards && !vim_ispathsep(*rest_of_wildcards))
file_name[len++] = *rest_of_wildcards++;
/* file_name[len++] = *rest_of_wildcards++; */
rest_of_wildcards++;
file_name[len] = '\0';
}
++expand_interactively;
expand_wildcards(1, &file_name, &nFiles, &ppFiles, EW_FILE|EW_DIR);
--expand_interactively;
if (!*rest_of_wildcards)
{
for (i = 0; i < nFiles; ++i)
{
if (!mch_isdir(ppFiles[i]))
continue; /* not a directory */
STRCPY(file_name, ppFiles[i]);
if (!vim_ispathsep(file_name[STRLEN(file_name)-1]))
STRCAT(file_name, PATHSEPSTR);
STRCAT(file_name, NameBuff);
if (mch_getperm(file_name) >= 0 && --*countptr == 0)
{
FreeWild(nFiles, ppFiles);
return file_name;
}
}
}
else
{
for (i = 0; i < nFiles; ++i)
{
if (!mch_isdir(ppFiles[i]))
continue; /* not a directory */
c = find_file_in_wildcard_path(ppFiles[i],
rest_of_wildcards, level+1, countptr);
if (c)
{
FreeWild(nFiles, ppFiles);
vim_free(file_name);
return c;
}
}
}
if (STRNCMP(wildcards, "**", 2) == 0)
{
for (i = 0; i < nFiles; ++i)
{
if (!mch_isdir(ppFiles[i]))
continue; /* not a directory */
c = find_file_in_wildcard_path(ppFiles[i],
wildcards, level+1, countptr);
if (c)
{
FreeWild(nFiles, ppFiles);
vim_free(file_name);
return c;
}
}
}
FreeWild(nFiles, ppFiles);
vim_free(file_name);
return NULL;
}
/*
* Check if the "://" of a URL is at the pointer, return URL_SLASH.
* Also check for ":\\", which MS Internet Explorer accepts, return
* URL_BACKSLASH.
*/
static int
path_is_url(p)
char_u *p;
{
if (STRNCMP(p, "://", (size_t)3) == 0)
return URL_SLASH;
else if (STRNCMP(p, ":\\\\", (size_t)3) == 0)
return URL_BACKSLASH;
return 0;
}
#endif /* FILE_IN_PATH */
/*
* Return the minimal number of rows that is needed on the screen to display
* the current number of windows.
*/
int
min_rows()
{
WIN *wp;
int total;
if (firstwin == NULL) /* not initialized yet */
return MIN_LINES;
total = p_ch; /* count the room for the status line */
for (wp = firstwin; wp != NULL; wp = wp->w_next)
total += p_wmh + wp->w_status_height;
if (p_wmh == 0)
total += 1; /* at least one window should have a line! */
return total;
}
/*
* Return TRUE if there is only one window, not counting a help window, unless
* it is the current window.
*/
int
only_one_window()
{
int count = 0;
WIN *wp;
for (wp = firstwin; wp != NULL; wp = wp->w_next)
if (!wp->w_buffer->b_help || wp == curwin)
++count;
return (count <= 1);
}
/*
* Correct the cursor line number in other windows. Used after changing the
* current buffer, and before applying autocommands.
* When "do_curwin" is TRUE, also check current window.
*/
void
check_lnums(do_curwin)
int do_curwin;
{
WIN *wp;
for (wp = firstwin; wp != NULL; wp = wp->w_next)
if ((do_curwin || wp != curwin) && wp->w_buffer == curbuf)
{
if (wp->w_cursor.lnum > curbuf->b_ml.ml_line_count)
wp->w_cursor.lnum = curbuf->b_ml.ml_line_count;
if (wp->w_topline > curbuf->b_ml.ml_line_count)
wp->w_topline = curbuf->b_ml.ml_line_count;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -