diff options
Diffstat (limited to 'src/nvim/window.c')
-rw-r--r-- | src/nvim/window.c | 325 |
1 files changed, 77 insertions, 248 deletions
diff --git a/src/nvim/window.c b/src/nvim/window.c index 1a6c3f7263..d3280a3478 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -22,6 +22,7 @@ #include "nvim/diff.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -72,6 +73,7 @@ #include "nvim/statusline.h" #include "nvim/strings.h" #include "nvim/syntax.h" +#include "nvim/tag.h" #include "nvim/terminal.h" #include "nvim/types_defs.h" #include "nvim/ui.h" @@ -357,13 +359,13 @@ newwindow: wp = lastwin; // wrap around } while (wp != NULL && wp->w_floating - && !wp->w_config.focusable) { + && (wp->w_config.hide || !wp->w_config.focusable)) { wp = wp->w_prev; } } else { // go to next window wp = curwin->w_next; while (wp != NULL && wp->w_floating - && !wp->w_config.focusable) { + && (wp->w_config.hide || !wp->w_config.focusable)) { wp = wp->w_next; } if (wp == NULL) { @@ -796,6 +798,19 @@ int win_fdccol_count(win_T *wp) return fdc[0] - '0'; } +/// Merges two window configs, freeing replaced fields if necessary. +void merge_win_config(WinConfig *dst, const WinConfig src) + FUNC_ATTR_NONNULL_ALL +{ + if (dst->title_chunks.items != src.title_chunks.items) { + clear_virttext(&dst->title_chunks); + } + if (dst->footer_chunks.items != src.footer_chunks.items) { + clear_virttext(&dst->footer_chunks); + } + *dst = src; +} + void ui_ext_win_position(win_T *wp, bool validate) { wp->w_pos_changed = false; @@ -1111,12 +1126,7 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir, frame_T *to_fl if (new_size == 0) { new_size = oldwin->w_width / 2; } - if (new_size > available - minwidth - 1) { - new_size = available - minwidth - 1; - } - if (new_size < wmw1) { - new_size = wmw1; - } + new_size = MAX(MIN(new_size, available - minwidth - 1), wmw1); // if it doesn't fit in the current window, need win_equal() if (oldwin->w_width - new_size - 1 < p_wmw) { @@ -1197,12 +1207,7 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir, frame_T *to_fl new_size = oldwin_height / 2; } - if (new_size > available - minheight - STATUS_HEIGHT) { - new_size = available - minheight - STATUS_HEIGHT; - } - if (new_size < wmh1) { - new_size = wmh1; - } + new_size = MAX(MIN(new_size, available - minheight - STATUS_HEIGHT), wmh1); // if it doesn't fit in the current window, need win_equal() if (oldwin_height - new_size - STATUS_HEIGHT < p_wmh) { @@ -1296,7 +1301,7 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir, frame_T *to_fl new_frame(wp); // non-floating window doesn't store float config or have a border. - wp->w_config = WIN_CONFIG_INIT; + merge_win_config(&wp->w_config, WIN_CONFIG_INIT); CLEAR_FIELD(wp->w_border_adj); } @@ -1729,12 +1734,8 @@ int make_windows(int count, bool vertical) - (p_wh - p_wmh)) / ((int)p_wmh + STATUS_HEIGHT + global_winbar_height()); } - if (maxcount < 2) { - maxcount = 2; - } - if (count > maxcount) { - count = maxcount; - } + maxcount = MAX(maxcount, 2); + count = MIN(count, maxcount); // add status line now, otherwise first window will be too big if (count > 1) { @@ -2188,9 +2189,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int if (frame_has_win(fr, next_curwin)) { room += (int)p_wiw - (int)p_wmw; next_curwin_size = 0; - if (new_size < p_wiw) { - new_size = (int)p_wiw; - } + new_size = MAX(new_size, (int)p_wiw); } else { // These windows don't use up room. totwincount -= (n + (fr->fr_next == NULL ? extra_sep : 0)) / ((int)p_wmw + 1); @@ -2253,9 +2252,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int } if (hnc) { // add next_curwin size next_curwin_size -= (int)p_wiw - (m - n); - if (next_curwin_size < 0) { - next_curwin_size = 0; - } + next_curwin_size = MAX(next_curwin_size, 0); new_size += next_curwin_size; room -= new_size - next_curwin_size; } else { @@ -2318,9 +2315,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int if (frame_has_win(fr, next_curwin)) { room += (int)p_wh - (int)p_wmh; next_curwin_size = 0; - if (new_size < p_wh) { - new_size = (int)p_wh; - } + new_size = MAX(new_size, (int)p_wh); } else { // These windows don't use up room. totwincount -= get_maximum_wincount(fr, (n + (fr->fr_next == NULL ? extra_sep : 0))); @@ -2489,7 +2484,7 @@ void close_windows(buf_T *buf, bool keep_curwin) // When the autocommand window is involved win_close() may need to print an error message. for (win_T *wp = lastwin; wp != NULL && (is_aucmd_win(lastwin) || !one_window(wp));) { if (wp->w_buffer == buf && (!keep_curwin || wp != curwin) - && !(wp->w_closing || wp->w_buffer->b_locked > 0)) { + && !(win_locked(wp) || wp->w_buffer->b_locked > 0)) { if (win_close(wp, false, false) == FAIL) { // If closing the window fails give up, to avoid looping forever. break; @@ -2511,7 +2506,7 @@ void close_windows(buf_T *buf, bool keep_curwin) // Start from tp_lastwin to close floating windows with the same buffer first. for (win_T *wp = tp->tp_lastwin; wp != NULL; wp = wp->w_prev) { if (wp->w_buffer == buf - && !(wp->w_closing || wp->w_buffer->b_locked > 0)) { + && !(win_locked(wp) || wp->w_buffer->b_locked > 0)) { win_close_othertab(wp, false, tp); // Start all over, the tab page may be closed and @@ -2648,10 +2643,10 @@ static void win_close_buffer(win_T *win, int action, bool abort_if_last) if (win->w_buffer != NULL) { bufref_T bufref; set_bufref(&bufref, curbuf); - win->w_closing = true; + win->w_locked = true; close_buffer(win, win->w_buffer, action, abort_if_last, true); if (win_valid_any_tab(win)) { - win->w_closing = false; + win->w_locked = false; } // Make sure curbuf is valid. It can become invalid if 'bufhidden' is @@ -2679,7 +2674,7 @@ int win_close(win_T *win, bool free_buf, bool force) return FAIL; } - if (win->w_closing + if (win_locked(win) || (win->w_buffer != NULL && win->w_buffer->b_locked > 0)) { return FAIL; // window is already being closed } @@ -2754,22 +2749,22 @@ int win_close(win_T *win, bool free_buf, bool force) if (!win_valid(win)) { return FAIL; } - win->w_closing = true; + win->w_locked = true; apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, false, curbuf); if (!win_valid(win)) { return FAIL; } - win->w_closing = false; + win->w_locked = false; if (last_window(win)) { return FAIL; } } - win->w_closing = true; + win->w_locked = true; apply_autocmds(EVENT_WINLEAVE, NULL, NULL, false, curbuf); if (!win_valid(win)) { return FAIL; } - win->w_closing = false; + win->w_locked = false; if (last_window(win)) { return FAIL; } @@ -2816,9 +2811,6 @@ int win_close(win_T *win, bool free_buf, bool force) // to split a window to avoid trouble. split_disallowed++; - // let terminal buffers know that this window dimensions may be ignored - win->w_closing = true; - bool was_floating = win->w_floating; if (ui_has(kUIMultigrid)) { ui_call_win_close(win->w_grid_alloc.handle); @@ -2872,7 +2864,7 @@ int win_close(win_T *win, bool free_buf, bool force) break; } if (!wp->w_p_pvw && !bt_quickfix(wp->w_buffer) - && !(wp->w_floating && !wp->w_config.focusable)) { + && !(wp->w_floating && (wp->w_config.hide || !wp->w_config.focusable))) { curwin = wp; break; } @@ -2967,7 +2959,7 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) { // Get here with win->w_buffer == NULL when win_close() detects the tab page // changed. - if (win->w_closing + if (win_locked(win) || (win->w_buffer != NULL && win->w_buffer->b_locked > 0)) { return; // window is already being closed } @@ -3455,14 +3447,23 @@ static frame_T *win_altframe(win_T *win, tabpage_T *tp) // Return the tabpage that will be used if the current one is closed. static tabpage_T *alt_tabpage(void) { - // Use the next tab page if possible. - if (curtab->tp_next != NULL) { - return curtab->tp_next; + // Use the last accessed tab page, if possible. + if ((tcl_flags & TCL_USELAST) && valid_tabpage(lastused_tabpage)) { + return lastused_tabpage; } - // Find the last but one tab page. + // Use the next tab page, if possible. + bool forward = curtab->tp_next != NULL + && ((tcl_flags & TCL_LEFT) == 0 || curtab == first_tabpage); + tabpage_T *tp; - for (tp = first_tabpage; tp->tp_next != curtab; tp = tp->tp_next) {} + if (forward) { + tp = curtab->tp_next; + } else { + // Use the previous tab page. + for (tp = first_tabpage; tp->tp_next != curtab; tp = tp->tp_next) {} + } + return tp; } @@ -3921,9 +3922,7 @@ static int frame_minwidth(frame_T *topfrp, win_T *next_curwin) frame_T *frp; FOR_ALL_FRAMES(frp, topfrp->fr_child) { int n = frame_minwidth(frp, next_curwin); - if (n > m) { - m = n; - } + m = MAX(m, n); } } else { // Add up the minimal widths for all frames in this row. @@ -4256,9 +4255,7 @@ int make_tabpages(int maxcount) int count = maxcount; // Limit to 'tabpagemax' tabs. - if (count > p_tpm) { - count = (int)p_tpm; - } + count = MIN(count, (int)p_tpm); // Don't execute autocommands while creating the tab pages. Must do that // when putting the buffers in the windows. @@ -5219,8 +5216,7 @@ void win_free(win_T *wp, tabpage_T *tp) xfree(wp->w_lines); for (int i = 0; i < wp->w_tagstacklen; i++) { - xfree(wp->w_tagstack[i].tagname); - xfree(wp->w_tagstack[i].user_data); + tagstack_clear_entry(&wp->w_tagstack[i]); } xfree(wp->w_localdir); @@ -5418,14 +5414,10 @@ void win_new_screensize(void) /// This only does the current tab page, others must be done when made active. void win_new_screen_rows(void) { - int h = (int)ROWS_AVAIL; - if (firstwin == NULL) { // not initialized yet return; } - if (h < frame_minheight(topframe, NULL)) { - h = frame_minheight(topframe, NULL); - } + int h = MAX((int)ROWS_AVAIL, frame_minheight(topframe, NULL)); // First try setting the heights of windows with 'winfixheight'. If // that doesn't result in the right height, forget about that option. @@ -5922,9 +5914,7 @@ static void frame_setheight(frame_T *curfrp, int height) // Row of frames: Also need to resize frames left and right of this // one. First check for the minimal height of these. int h = frame_minheight(curfrp->fr_parent, NULL); - if (height < h) { - height = h; - } + height = MAX(height, h); frame_setheight(curfrp->fr_parent, height); } else { // Column of frames: try to change only frames in this column. @@ -5959,9 +5949,7 @@ static void frame_setheight(frame_T *curfrp, int height) win_T *wp = lastwin_nofloating(); room_cmdline = Rows - (int)p_ch - global_stl_height() - (wp->w_winrow + wp->w_height + wp->w_hsep_height + wp->w_status_height); - if (room_cmdline < 0) { - room_cmdline = 0; - } + room_cmdline = MAX(room_cmdline, 0); } if (height <= room + room_cmdline) { @@ -5993,9 +5981,7 @@ static void frame_setheight(frame_T *curfrp, int height) if (take > 0 && room_cmdline > 0) { // use lines from cmdline first - if (take < room_cmdline) { - room_cmdline = take; - } + room_cmdline = MIN(room_cmdline, take), take -= room_cmdline; topframe->fr_height += room_cmdline; } @@ -6057,12 +6043,7 @@ void win_setwidth_win(int width, win_T *wp) // Always keep current window at least one column wide, even when // 'winminwidth' is zero. if (wp == curwin) { - if (width < p_wmw) { - width = (int)p_wmw; - } - if (width == 0) { - width = 1; - } + width = MAX(MAX(width, (int)p_wmw), 1); } else if (width < 0) { width = 0; } @@ -6100,9 +6081,7 @@ static void frame_setwidth(frame_T *curfrp, int width) // Column of frames: Also need to resize frames above and below of // this one. First check for the minimal width of these. int w = frame_minwidth(curfrp->fr_parent, NULL); - if (width < w) { - width = w; - } + width = MAX(width, w); frame_setwidth(curfrp->fr_parent, width); } else { // Row of frames: try to change only frames in this row. @@ -6299,9 +6278,7 @@ void win_drag_status_line(win_T *dragwin, int offset) } else if (!p_ch_was_zero) { room--; } - if (room < 0) { - room = 0; - } + room = MAX(room, 0); // sum up the room of frames below of the current one FOR_ALL_FRAMES(fr, curfr->fr_next) { room += fr->fr_height - frame_minheight(fr, NULL); @@ -6309,9 +6286,8 @@ void win_drag_status_line(win_T *dragwin, int offset) fr = curfr; // put fr at window that grows } - if (room < offset) { // Not enough room - offset = room; // Move as far as we can - } + // If not enough room then move as far as we can + offset = MIN(offset, room); if (offset <= 0) { return; } @@ -6413,10 +6389,8 @@ void win_drag_vsep_line(win_T *dragwin, int offset) fr = curfr; // put fr at window that grows } - // Not enough room - if (room < offset) { - offset = room; // Move as far as we can - } + // If not enough room thn move as far as we can + offset = MIN(offset, room); // No room at all, quit. if (offset <= 0) { @@ -6587,9 +6561,7 @@ void win_new_height(win_T *wp, int height) { // Don't want a negative height. Happens when splitting a tiny window. // Will equalize heights soon to fix it. - if (height < 0) { - height = 0; - } + height = MAX(height, 0); if (wp->w_height == height) { return; // nothing to do } @@ -6615,9 +6587,8 @@ void scroll_to_fraction(win_T *wp, int prev_height) // Find a value for w_topline that shows the cursor at the same // relative position in the window as before (more or less). linenr_T lnum = wp->w_cursor.lnum; - if (lnum < 1) { // can happen when starting up - lnum = 1; - } + // can happen when starting up + lnum = MAX(lnum, 1); wp->w_wrow = (wp->w_fraction * height - 1) / FRACTION_MULT; int line_size = plines_win_col(wp, lnum, wp->w_cursor.col) - 1; int sline = wp->w_wrow - line_size; @@ -6833,9 +6804,7 @@ void command_height(void) break; } int h = frp->fr_height - frame_minheight(frp, NULL); - if (h > p_ch - old_p_ch) { - h = (int)p_ch - old_p_ch; - } + h = MIN(h, (int)p_ch - old_p_ch); old_p_ch += h; frame_add_height(frp, -h); frp = frp->fr_prev; @@ -6853,9 +6822,7 @@ void command_height(void) return; } - if (msg_row < cmdline_row) { - msg_row = cmdline_row; - } + msg_row = MAX(msg_row, cmdline_row); redraw_cmdline = true; } frame_add_height(frp, (int)(old_p_ch - p_ch)); @@ -6880,142 +6847,6 @@ static void frame_add_height(frame_T *frp, int n) } } -// Get the file name at the cursor. -// If Visual mode is active, use the selected text if it's in one line. -// Returns the name in allocated memory, NULL for failure. -char *grab_file_name(int count, linenr_T *file_lnum) -{ - int options = FNAME_MESS | FNAME_EXP | FNAME_REL | FNAME_UNESC; - if (VIsual_active) { - size_t len; - char *ptr; - if (get_visual_text(NULL, &ptr, &len) == FAIL) { - return NULL; - } - // Only recognize ":123" here - if (file_lnum != NULL && ptr[len] == ':' && isdigit((uint8_t)ptr[len + 1])) { - char *p = ptr + len + 1; - - *file_lnum = getdigits_int32(&p, false, 0); - } - return find_file_name_in_path(ptr, len, options, count, curbuf->b_ffname); - } - return file_name_at_cursor(options | FNAME_HYP, count, file_lnum); -} - -// Return the file name under or after the cursor. -// -// The 'path' option is searched if the file name is not absolute. -// 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 -// FNAME_INCL apply "includeexpr" -char *file_name_at_cursor(int options, int count, linenr_T *file_lnum) -{ - return file_name_in_line(get_cursor_line_ptr(), - curwin->w_cursor.col, options, count, curbuf->b_ffname, - file_lnum); -} - -/// @param rel_fname file we are searching relative to -/// @param file_lnum line number after the file name -/// -/// @return the name of the file under or after ptr[col]. Otherwise like file_name_at_cursor(). -char *file_name_in_line(char *line, int col, int options, int count, char *rel_fname, - linenr_T *file_lnum) -{ - // search forward for what could be the start of a file name - char *ptr = line + col; - while (*ptr != NUL && !vim_isfilec((uint8_t)(*ptr))) { - MB_PTR_ADV(ptr); - } - if (*ptr == NUL) { // nothing found - if (options & FNAME_MESS) { - emsg(_("E446: No file name under cursor")); - } - return NULL; - } - - size_t len; - bool in_type = true; - bool is_url = false; - - // Search backward for first char of the file name. - // Go one char back to ":" before "//", or to the drive letter before ":\" (even if ":" - // is not in 'isfname'). - while (ptr > line) { - if ((len = (size_t)(utf_head_off(line, ptr - 1))) > 0) { - ptr -= len + 1; - } else if (vim_isfilec((uint8_t)ptr[-1]) || ((options & FNAME_HYP) && path_is_url(ptr - 1))) { - ptr--; - } else { - break; - } - } - - // Search forward for the last char of the file name. - // Also allow ":/" when ':' is not in 'isfname'. - len = path_has_drive_letter(ptr) ? 2 : 0; - while (vim_isfilec((uint8_t)ptr[len]) || (ptr[len] == '\\' && ptr[len + 1] == ' ') - || ((options & FNAME_HYP) && path_is_url(ptr + len)) - || (is_url && vim_strchr(":?&=", (uint8_t)ptr[len]) != NULL)) { - // After type:// we also include :, ?, & and = as valid characters, so that - // http://google.com:8080?q=this&that=ok works. - if ((ptr[len] >= 'A' && ptr[len] <= 'Z') || (ptr[len] >= 'a' && ptr[len] <= 'z')) { - if (in_type && path_is_url(ptr + len + 1)) { - is_url = true; - } - } else { - in_type = false; - } - - if (ptr[len] == '\\' && ptr[len + 1] == ' ') { - // Skip over the "\" in "\ ". - len++; - } - len += (size_t)(utfc_ptr2len(ptr + len)); - } - - // If there is trailing punctuation, remove it. - // But don't remove "..", could be a directory name. - if (len > 2 && vim_strchr(".,:;!", (uint8_t)ptr[len - 1]) != NULL - && ptr[len - 2] != '.') { - len--; - } - - if (file_lnum != NULL) { - const char *line_english = " line "; - const char *line_transl = _(line_msg); - - // Get the number after the file name and a separator character. - // Also accept " line 999" with and without the same translation as - // used in last_set_msg(). - char *p = ptr + len; - if (strncmp(p, line_english, strlen(line_english)) == 0) { - p += strlen(line_english); - } else if (strncmp(p, line_transl, strlen(line_transl)) == 0) { - p += strlen(line_transl); - } else { - p = skipwhite(p); - } - if (*p != NUL) { - if (!isdigit((uint8_t)(*p))) { - p++; // skip the separator - } - p = skipwhite(p); - if (isdigit((uint8_t)(*p))) { - *file_lnum = (linenr_T)getdigits_long(&p, false, 0); - } - } - } - - return find_file_name_in_path(ptr, len, options, count, rel_fname); -} - /// Add or remove a status line from window(s), according to the /// value of 'laststatus'. /// @@ -7241,9 +7072,7 @@ int min_rows(void) int total = 0; FOR_ALL_TABS(tp) { int n = frame_minheight(tp->tp_topframe, NULL); - if (total < n) { - total = n; - } + total = MAX(total, n); } total += tabline_height() + global_stl_height(); if (p_ch > 0) { @@ -7538,13 +7367,7 @@ static int int_cmp(const void *pa, const void *pb) { const int a = *(const int *)pa; const int b = *(const int *)pb; - if (a > b) { - return 1; - } - if (a < b) { - return -1; - } - return 0; + return a == b ? 0 : a < b ? -1 : 1; } /// Handle setting 'colorcolumn' or 'textwidth' in window "wp". @@ -7626,6 +7449,12 @@ int get_last_winid(void) return last_win_id; } +/// Don't let autocommands close the given window +int win_locked(win_T *wp) +{ + return wp->w_locked; +} + void win_get_tabwin(handle_T id, int *tabnr, int *winnr) { *tabnr = 0; |