aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/window.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/window.c')
-rw-r--r--src/nvim/window.c1138
1 files changed, 788 insertions, 350 deletions
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 1298248f1e..3cadfe612a 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -1,3 +1,6 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+
#include <assert.h>
#include <inttypes.h>
#include <stdbool.h>
@@ -28,7 +31,6 @@
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/misc2.h"
#include "nvim/file_search.h"
#include "nvim/garray.h"
#include "nvim/move.h"
@@ -41,10 +43,12 @@
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/search.h"
+#include "nvim/state.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/terminal.h"
#include "nvim/undo.h"
+#include "nvim/ui.h"
#include "nvim/os/os.h"
@@ -129,9 +133,10 @@ newwindow:
vim_snprintf(cbuf, sizeof(cbuf) - 5, "%" PRId64, (int64_t)Prenum);
else
cbuf[0] = NUL;
- if (nchar == 'v' || nchar == Ctrl_V)
- strcat(cbuf, "v");
- strcat(cbuf, "new");
+ if (nchar == 'v' || nchar == Ctrl_V) {
+ xstrlcat(cbuf, "v", sizeof(cbuf));
+ }
+ xstrlcat(cbuf, "new", sizeof(cbuf));
do_cmdline_cmd(cbuf);
break;
@@ -160,13 +165,18 @@ newwindow:
/* cursor to preview window */
case 'P':
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- if (wp->w_p_pvw)
+ wp = NULL;
+ FOR_ALL_WINDOWS_IN_TAB(wp2, curtab) {
+ if (wp2->w_p_pvw) {
+ wp = wp2;
break;
- if (wp == NULL)
+ }
+ }
+ if (wp == NULL) {
EMSG(_("E441: There is no preview window"));
- else
+ } else {
win_goto(wp);
+ }
break;
/* close all but current window */
@@ -183,7 +193,7 @@ newwindow:
/* cursor to previous window with wrap around */
case 'W':
CHECK_CMDWIN
- if (firstwin == lastwin && Prenum != 1) /* just one window */
+ if (ONE_WINDOW && Prenum != 1) /* just one window */
beep_flush();
else {
if (Prenum) { /* go to specified window */
@@ -278,10 +288,11 @@ newwindow:
/* cursor to last accessed (previous) window */
case 'p':
case Ctrl_P:
- if (prevwin == NULL)
+ if (!win_valid(prevwin)) {
beep_flush();
- else
+ } else {
win_goto(prevwin);
+ }
break;
/* exchange current and next window */
@@ -356,7 +367,7 @@ newwindow:
g_do_tagpreview = Prenum;
else
g_do_tagpreview = p_pvh;
- /*FALLTHROUGH*/
+ FALLTHROUGH;
case ']':
case Ctrl_RSB:
CHECK_CMDWIN
@@ -384,12 +395,16 @@ wingotofile:
ptr = grab_file_name(Prenum1, &lnum);
if (ptr != NULL) {
+ tabpage_T *oldtab = curtab;
+ win_T *oldwin = curwin;
setpcmark();
if (win_split(0, 0) == OK) {
RESET_BINDING(curwin);
- (void)do_ecmd(0, ptr, NULL, NULL, ECMD_LASTL,
- ECMD_HIDE, NULL);
- if (nchar == 'F' && lnum >= 0) {
+ if (do_ecmd(0, ptr, NULL, NULL, ECMD_LASTL, ECMD_HIDE, NULL) == FAIL) {
+ // Failed to open the file, close the window opened for it.
+ win_close(curwin, false);
+ goto_tabpage_win(oldtab, oldwin);
+ } else if (nchar == 'F' && lnum >= 0) {
curwin->w_cursor.lnum = lnum;
check_cursor_lnum();
beginline(BL_SOL | BL_FIX);
@@ -405,8 +420,8 @@ wingotofile:
case 'i': /* Go to any match */
case Ctrl_I:
type = FIND_ANY;
- /* FALLTHROUGH */
- case 'd': /* Go to definition, using 'define' */
+ FALLTHROUGH;
+ case 'd': // Go to definition, using 'define'
case Ctrl_D:
CHECK_CMDWIN
if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
@@ -436,13 +451,12 @@ wingotofile:
case 'g':
case Ctrl_G:
CHECK_CMDWIN
- ++ no_mapping;
- ++allow_keys; /* no mapping for xchar, but allow key codes */
- if (xchar == NUL)
+ no_mapping++;
+ if (xchar == NUL) {
xchar = plain_vgetc();
- LANGMAP_ADJUST(xchar, TRUE);
- --no_mapping;
- --allow_keys;
+ }
+ LANGMAP_ADJUST(xchar, true);
+ no_mapping--;
(void)add_to_showcmd(xchar);
switch (xchar) {
case '}':
@@ -451,7 +465,7 @@ wingotofile:
g_do_tagpreview = Prenum;
else
g_do_tagpreview = p_pvh;
- /*FALLTHROUGH*/
+ FALLTHROUGH;
case ']':
case Ctrl_RSB:
// Keep visual mode, can select words to use as a tag.
@@ -482,7 +496,7 @@ wingotofile:
}
static void cmd_with_count(char *cmd, char_u *bufp, size_t bufsize,
- long Prenum)
+ int64_t Prenum)
{
size_t len = xstrlcpy((char *)bufp, cmd, bufsize);
@@ -551,6 +565,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
int before;
int minheight;
int wmh1;
+ bool did_set_fraction = false;
if (flags & WSP_TOP)
oldwin = firstwin;
@@ -560,7 +575,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
oldwin = curwin;
/* add a status line when p_ls == 1 and splitting the first window */
- if (lastwin == firstwin && p_ls == 1 && oldwin->w_status_height == 0) {
+ if (ONE_WINDOW && p_ls == 1 && oldwin->w_status_height == 0) {
if (oldwin->w_height <= p_wmh && new_wp == NULL) {
EMSG(_(e_noroom));
return FAIL;
@@ -627,11 +642,12 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
if (oldwin->w_width - new_size - 1 < p_wmw)
do_equal = TRUE;
- /* We don't like to take lines for the new window from a
- * 'winfixwidth' window. Take them from a window to the left or right
- * instead, if possible. */
- if (oldwin->w_p_wfw)
- win_setwidth_win(oldwin->w_width + new_size, oldwin);
+ // We don't like to take lines for the new window from a
+ // 'winfixwidth' window. Take them from a window to the left or right
+ // instead, if possible. Add one for the separator.
+ if (oldwin->w_p_wfw) {
+ win_setwidth_win(oldwin->w_width + new_size + 1, oldwin);
+ }
/* Only make all windows the same width if one of them (except oldwin)
* is wider than one of the split windows. */
@@ -714,6 +730,11 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
* 'winfixheight' window. Take them from a window above or below
* instead, if possible. */
if (oldwin->w_p_wfh) {
+ // Set w_fraction now so that the cursor keeps the same relative
+ // vertical position using the old height.
+ set_fraction(oldwin);
+ did_set_fraction = true;
+
win_setheight_win(oldwin->w_height + new_size + STATUS_HEIGHT,
oldwin);
oldwin_height = oldwin->w_height;
@@ -828,8 +849,9 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
/* Set w_fraction now so that the cursor keeps the same relative
* vertical position. */
- if (oldwin->w_height > 0)
+ if (!did_set_fraction) {
set_fraction(oldwin);
+ }
wp->w_fraction = oldwin->w_fraction;
if (flags & WSP_VERT) {
@@ -893,31 +915,31 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
/* "new_size" of the current window goes to the new window, use
* one row for the status line */
win_new_height(wp, new_size);
- if (flags & (WSP_TOP | WSP_BOT))
- frame_new_height(curfrp, curfrp->fr_height
- - (new_size + STATUS_HEIGHT), flags & WSP_TOP, FALSE);
- else
+ if (flags & (WSP_TOP | WSP_BOT)) {
+ int new_fr_height = curfrp->fr_height - new_size;
+
+ if (!((flags & WSP_BOT) && p_ls == 0)) {
+ new_fr_height -= STATUS_HEIGHT;
+ }
+ frame_new_height(curfrp, new_fr_height, flags & WSP_TOP, false);
+ } else {
win_new_height(oldwin, oldwin_height - (new_size + STATUS_HEIGHT));
- if (before) { /* new window above current one */
+ }
+ if (before) { // new window above current one
wp->w_winrow = oldwin->w_winrow;
wp->w_status_height = STATUS_HEIGHT;
oldwin->w_winrow += wp->w_height + STATUS_HEIGHT;
} else { /* new window below current one */
wp->w_winrow = oldwin->w_winrow + oldwin->w_height + STATUS_HEIGHT;
wp->w_status_height = oldwin->w_status_height;
- // Don't set the status_height for oldwin yet, this might break
- // frame_fix_height(oldwin), therefore will be set below.
+ if (!(flags & WSP_BOT)) {
+ oldwin->w_status_height = STATUS_HEIGHT;
+ }
}
if (flags & WSP_BOT)
frame_add_statusline(curfrp);
frame_fix_height(wp);
frame_fix_height(oldwin);
-
- if (!before) {
- // New window above current one, set the status_height after
- // frame_fix_height(oldwin)
- oldwin->w_status_height = STATUS_HEIGHT;
- }
}
if (flags & (WSP_TOP | WSP_BOT))
@@ -968,11 +990,15 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
/*
* make the new window the current window
*/
- win_enter(wp, false);
- if (flags & WSP_VERT)
+ win_enter_ext(wp, false, false, true, true, true);
+ if (flags & WSP_VERT) {
p_wiw = i;
- else
+ } else {
p_wh = i;
+ }
+
+ // Send the window positions to the UI
+ oldwin->w_pos_changed = true;
return OK;
}
@@ -1028,7 +1054,7 @@ static void win_init(win_T *newp, win_T *oldp, int flags)
win_init_some(newp, oldp);
- check_colorcolumn(newp);
+ didset_window_options(newp);
}
/*
@@ -1064,6 +1090,23 @@ bool win_valid(win_T *win) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
return false;
}
+/// Check if "win" is a pointer to an existing window in any tabpage.
+///
+/// @param win window to check
+bool win_valid_any_tab(win_T *win) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (win == NULL) {
+ return false;
+ }
+
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp == win) {
+ return true;
+ }
+ }
+ return false;
+}
+
/*
* Return the number of windows.
*/
@@ -1150,7 +1193,7 @@ static void win_exchange(long Prenum)
win_T *wp2;
int temp;
- if (lastwin == firstwin) { /* just one window */
+ if (ONE_WINDOW) { /* just one window */
beep_flush();
return;
}
@@ -1225,7 +1268,8 @@ static void win_exchange(long Prenum)
(void)win_comp_pos(); /* recompute window positions */
win_enter(wp, true);
- redraw_later(CLEAR);
+ redraw_later(NOT_VALID);
+ redraw_win_later(wp, NOT_VALID);
}
/*
@@ -1239,7 +1283,7 @@ static void win_rotate(int upwards, int count)
frame_T *frp;
int n;
- if (firstwin == lastwin) { /* nothing to do */
+ if (ONE_WINDOW) { /* nothing to do */
beep_flush();
return;
}
@@ -1300,7 +1344,10 @@ static void win_rotate(int upwards, int count)
(void)win_comp_pos();
}
- redraw_later(CLEAR);
+ wp1->w_pos_changed = true;
+ wp2->w_pos_changed = true;
+
+ redraw_all_later(NOT_VALID);
}
/*
@@ -1311,7 +1358,7 @@ static void win_totop(int size, int flags)
int dir;
int height = curwin->w_height;
- if (lastwin == firstwin) {
+ if (ONE_WINDOW) {
beep_flush();
return;
}
@@ -1382,6 +1429,9 @@ void win_move_after(win_T *win1, win_T *win2)
redraw_later(NOT_VALID);
}
win_enter(win1, false);
+
+ win1->w_pos_changed = true;
+ win2->w_pos_changed = true;
}
/*
@@ -1437,10 +1487,10 @@ static void win_equal_rec(
|| topfr->fr_width != width || topfr->fr_win->w_wincol != col
) {
topfr->fr_win->w_winrow = row;
- frame_new_height(topfr, height, FALSE, FALSE);
+ frame_new_height(topfr, height, false, false);
topfr->fr_win->w_wincol = col;
- frame_new_width(topfr, width, FALSE, FALSE);
- redraw_all_later(CLEAR);
+ frame_new_width(topfr, width, false, false);
+ redraw_all_later(NOT_VALID);
}
} else if (topfr->fr_layout == FR_ROW) {
topfr->fr_width = width;
@@ -1685,25 +1735,23 @@ static void win_equal_rec(
}
}
-/*
- * close all windows for buffer 'buf'
- */
-void
-close_windows (
- buf_T *buf,
- int keep_curwin /* don't close "curwin" */
-)
+/// Closes all windows for buffer `buf`.
+///
+/// @param keep_curwin don't close `curwin`
+void close_windows(buf_T *buf, int keep_curwin)
{
tabpage_T *tp, *nexttp;
int h = tabline_height();
++RedrawingDisabled;
- for (win_T *wp = firstwin; wp != NULL && lastwin != firstwin; ) {
+ for (win_T *wp = firstwin; wp != NULL && !ONE_WINDOW; ) {
if (wp->w_buffer == buf && (!keep_curwin || wp != curwin)
- && !(wp->w_closing || wp->w_buffer->b_closing)
- ) {
- win_close(wp, FALSE);
+ && !(wp->w_closing || wp->w_buffer->b_locked > 0)) {
+ if (win_close(wp, false) == FAIL) {
+ // If closing the window fails give up, to avoid looping forever.
+ break;
+ }
/* Start all over, autocommands may change the window layout. */
wp = firstwin;
@@ -1717,9 +1765,8 @@ close_windows (
if (tp != curtab) {
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
if (wp->w_buffer == buf
- && !(wp->w_closing || wp->w_buffer->b_closing)
- ) {
- win_close_othertab(wp, FALSE, tp);
+ && !(wp->w_closing || wp->w_buffer->b_locked > 0)) {
+ win_close_othertab(wp, false, tp);
/* Start all over, the tab page may be closed and
* autocommands may change the window layout. */
@@ -1732,9 +1779,10 @@ close_windows (
--RedrawingDisabled;
- redraw_tabline = TRUE;
- if (h != tabline_height())
+ redraw_tabline = true;
+ if (h != tabline_height()) {
shell_new_rows();
+ }
}
/// Check that current window is the last one.
@@ -1775,7 +1823,7 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf,
tabpage_T *prev_curtab)
FUNC_ATTR_NONNULL_ARG(1)
{
- if (firstwin != lastwin) {
+ if (!ONE_WINDOW) {
return false;
}
buf_T *old_curbuf = curbuf;
@@ -1811,15 +1859,8 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf,
shell_new_rows();
}
- if (term) {
- // When a window containing a terminal buffer is closed, recalculate its
- // size
- terminal_resize(term, 0, 0);
- }
-
// Since goto_tabpage_tp above did not trigger *Enter autocommands, do
// that now.
- apply_autocmds(EVENT_TABCLOSED, prev_idx, prev_idx, false, curbuf);
apply_autocmds(EVENT_WINENTER, NULL, NULL, false, curbuf);
apply_autocmds(EVENT_TABENTER, NULL, NULL, false, curbuf);
if (old_curbuf != curbuf) {
@@ -1828,29 +1869,30 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf,
return true;
}
-/*
- * Close window "win". Only works for the current tab page.
- * If "free_buf" is TRUE related buffer may be unloaded.
- *
- * Called by :quit, :close, :xit, :wq and findtag().
- * Returns FAIL when the window was not closed.
- */
-int win_close(win_T *win, int free_buf)
+// Close window "win". Only works for the current tab page.
+// If "free_buf" is true related buffer may be unloaded.
+//
+// Called by :quit, :close, :xit, :wq and findtag().
+// Returns FAIL when the window was not closed.
+int win_close(win_T *win, bool free_buf)
{
win_T *wp;
int other_buffer = FALSE;
int close_curwin = FALSE;
int dir;
- int help_window = FALSE;
+ bool help_window = false;
tabpage_T *prev_curtab = curtab;
+ frame_T *win_frame = win->w_frame->fr_parent;
if (last_window()) {
EMSG(_("E444: Cannot close last window"));
return FAIL;
}
- if (win->w_closing || (win->w_buffer != NULL && win->w_buffer->b_closing))
- return FAIL; /* window is already being closed */
+ if (win->w_closing
+ || (win->w_buffer != NULL && win->w_buffer->b_locked > 0)) {
+ return FAIL; // window is already being closed
+ }
if (win == aucmd_win) {
EMSG(_("E813: Cannot close autocmd window"));
return FAIL;
@@ -1868,10 +1910,11 @@ int win_close(win_T *win, int free_buf)
/* When closing the help window, try restoring a snapshot after closing
* the window. Otherwise clear the snapshot, it's now invalid. */
- if (win->w_buffer != NULL && win->w_buffer->b_help)
- help_window = TRUE;
- else
+ if (bt_help(win->w_buffer)) {
+ help_window = true;
+ } else {
clear_snapshot(curtab, SNAP_HELP_IDX);
+ }
if (win == curwin) {
/*
@@ -1915,15 +1958,17 @@ int win_close(win_T *win, int free_buf)
* Close the link to the buffer.
*/
if (win->w_buffer != NULL) {
+ bufref_T bufref;
+ set_bufref(&bufref, curbuf);
win->w_closing = true;
close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, true);
- if (win_valid(win)) {
+ if (win_valid_any_tab(win)) {
win->w_closing = false;
}
// Make sure curbuf is valid. It can become invalid if 'bufhidden' is
// "wipe".
- if (!buf_valid(curbuf)) {
+ if (!bufref_valid(&bufref)) {
curbuf = firstbuf;
}
}
@@ -1931,17 +1976,26 @@ int win_close(win_T *win, int free_buf)
if (only_one_window() && win_valid(win) && win->w_buffer == NULL
&& (last_window() || curtab != prev_curtab
|| close_last_window_tabpage(win, free_buf, prev_curtab))) {
- /* Autocommands have close all windows, quit now. Restore
- * curwin->w_buffer, otherwise writing ShaDa file may fail. */
- if (curwin->w_buffer == NULL)
+ // Autocommands have closed all windows, quit now. Restore
+ // curwin->w_buffer, otherwise writing ShaDa file may fail.
+ if (curwin->w_buffer == NULL) {
curwin->w_buffer = curbuf;
+ }
getout(0);
}
- /* Autocommands may have closed the window already, or closed the only
- * other window or moved to another tab page. */
- else if (!win_valid(win) || last_window() || curtab != prev_curtab
- || close_last_window_tabpage(win, free_buf, prev_curtab))
+ // Autocommands may have moved to another tab page.
+ if (curtab != prev_curtab && win_valid_any_tab(win)
+ && win->w_buffer == NULL) {
+ // Need to close the window anyway, since the buffer is NULL.
+ win_close_othertab(win, false, prev_curtab);
+ return FAIL;
+ }
+ // Autocommands may have closed the window already, or closed the only
+ // other window or moved to another tab page.
+ if (!win_valid(win) || last_window()
+ || close_last_window_tabpage(win, free_buf, prev_curtab)) {
return FAIL;
+ }
// let terminal buffers know that this window dimensions may be ignored
win->w_closing = true;
@@ -1949,6 +2003,14 @@ int win_close(win_T *win, int free_buf)
* the screen space. */
wp = win_free_mem(win, &dir, NULL);
+ if (help_window) {
+ // Closing the help window moves the cursor back to the original window.
+ win_T *tmpwp = get_snapshot_focus(SNAP_HELP_IDX);
+ if (tmpwp != NULL) {
+ wp = tmpwp;
+ }
+ }
+
/* Make sure curwin isn't invalid. It can cause severe trouble when
* printing an error message. For win_equal() curbuf needs to be valid
* too. */
@@ -1974,20 +2036,25 @@ int win_close(win_T *win, int free_buf)
}
curbuf = curwin->w_buffer;
close_curwin = TRUE;
+
+ // The cursor position may be invalid if the buffer changed after last
+ // using the window.
+ check_cursor();
}
- if (p_ea
- && (*p_ead == 'b' || *p_ead == dir)
- ) {
- win_equal(curwin, true, dir);
+ if (p_ea && (*p_ead == 'b' || *p_ead == dir)) {
+ // If the frame of the closed window contains the new current window,
+ // only resize that frame. Otherwise resize all windows.
+ win_equal(curwin, curwin->w_frame->fr_parent == win_frame, dir);
} else {
win_comp_pos();
}
if (close_curwin) {
- win_enter_ext(wp, false, TRUE, TRUE, TRUE);
- if (other_buffer)
- /* careful: after this wp and win may be invalid! */
- apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
+ win_enter_ext(wp, false, true, false, true, true);
+ if (other_buffer) {
+ // careful: after this wp and win may be invalid!
+ apply_autocmds(EVENT_BUFENTER, NULL, NULL, false, curbuf);
+ }
}
/*
@@ -2001,6 +2068,7 @@ int win_close(win_T *win, int free_buf)
if (help_window)
restore_snapshot(SNAP_HELP_IDX, close_curwin);
+ curwin->w_pos_changed = true;
redraw_all_later(NOT_VALID);
return OK;
}
@@ -2018,12 +2086,17 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
tabpage_T *ptp = NULL;
int free_tp = FALSE;
- assert(win->w_buffer); // to avoid np dereference warning in next line
- if (win->w_closing || win->w_buffer->b_closing)
- return; /* window is already being closed */
+ // Get here with win->w_buffer == NULL when win_close() detects the tab page
+ // changed.
+ if (win->w_closing
+ || (win->w_buffer != NULL && win->w_buffer->b_locked > 0)) {
+ return; // window is already being closed
+ }
- /* Close the link to the buffer. */
- close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, FALSE);
+ if (win->w_buffer != NULL) {
+ // Close the link to the buffer.
+ close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, false);
+ }
/* Careful: Autocommands may have closed the tab page or made it the
* current tab page. */
@@ -2048,19 +2121,29 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
/* When closing the last window in a tab page remove the tab page. */
if (tp->tp_firstwin == tp->tp_lastwin) {
- if (tp == first_tabpage)
+ char_u prev_idx[NUMBUFLEN];
+ if (has_event(EVENT_TABCLOSED)) {
+ vim_snprintf((char *)prev_idx, NUMBUFLEN, "%i", tabpage_index(tp));
+ }
+
+ if (tp == first_tabpage) {
first_tabpage = tp->tp_next;
- else {
+ } else {
for (ptp = first_tabpage; ptp != NULL && ptp->tp_next != tp;
- ptp = ptp->tp_next)
- ;
+ ptp = ptp->tp_next) {
+ // loop
+ }
if (ptp == NULL) {
- EMSG2(_(e_intern2), "win_close_othertab()");
+ internal_error("win_close_othertab()");
return;
}
ptp->tp_next = tp->tp_next;
}
- free_tp = TRUE;
+ free_tp = true;
+
+ if (has_event(EVENT_TABCLOSED)) {
+ apply_autocmds(EVENT_TABCLOSED, prev_idx, prev_idx, false, win->w_buffer);
+ }
}
/* Free the memory used for the window. */
@@ -2139,7 +2222,7 @@ winframe_remove (
/*
* If there is only one window there is nothing to remove.
*/
- if (tp == NULL ? firstwin == lastwin : tp->tp_firstwin == tp->tp_lastwin)
+ if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin)
return NULL;
/*
@@ -2231,6 +2314,9 @@ winframe_remove (
if (frp2->fr_win != NULL)
frp2->fr_win->w_frame = frp2->fr_parent;
frp = frp2->fr_parent;
+ if (topframe->fr_child == frp2) {
+ topframe->fr_child = frp;
+ }
xfree(frp2);
frp2 = frp->fr_parent;
@@ -2252,6 +2338,9 @@ winframe_remove (
break;
}
}
+ if (topframe->fr_child == frp) {
+ topframe->fr_child = frp2;
+ }
xfree(frp);
}
}
@@ -2259,14 +2348,14 @@ winframe_remove (
return wp;
}
-/*
- * Find out which frame is going to get the freed up space when "win" is
- * closed.
- * if 'splitbelow'/'splitleft' the space goes to the window above/left.
- * if 'nosplitbelow'/'nosplitleft' the space goes to the window below/right.
- * This makes opening a window and closing it immediately keep the same window
- * layout.
- */
+// Return a pointer to the frame that will receive the empty screen space that
+// is left over after "win" is closed.
+//
+// If 'splitbelow' or 'splitright' is set, the space goes above or to the left
+// by default. Otherwise, the free space goes below or to the right. The
+// result is that opening a window and then immediately closing it will
+// preserve the initial window layout. The 'wfh' and 'wfw' settings are
+// respected when possible.
static frame_T *
win_altframe (
win_T *win,
@@ -2274,20 +2363,40 @@ win_altframe (
)
{
frame_T *frp;
- int b;
- if (tp == NULL ? firstwin == lastwin : tp->tp_firstwin == tp->tp_lastwin)
- /* Last window in this tab page, will go to next tab page. */
+ if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin) {
return alt_tabpage()->tp_curwin->w_frame;
+ }
frp = win->w_frame;
- if (frp->fr_parent != NULL && frp->fr_parent->fr_layout == FR_ROW)
- b = p_spr;
- else
- b = p_sb;
- if ((!b && frp->fr_next != NULL) || frp->fr_prev == NULL)
+
+ if (frp->fr_prev == NULL) {
return frp->fr_next;
- return frp->fr_prev;
+ }
+ if (frp->fr_next == NULL) {
+ return frp->fr_prev;
+ }
+
+ frame_T *target_fr = frp->fr_next;
+ frame_T *other_fr = frp->fr_prev;
+ if (p_spr || p_sb) {
+ target_fr = frp->fr_prev;
+ other_fr = frp->fr_next;
+ }
+
+ // If 'wfh' or 'wfw' is set for the target and not for the alternate
+ // window, reverse the selection.
+ if (frp->fr_parent != NULL && frp->fr_parent->fr_layout == FR_ROW) {
+ if (frame_fixed_width(target_fr) && !frame_fixed_width(other_fr)) {
+ target_fr = other_fr;
+ }
+ } else {
+ if (frame_fixed_height(target_fr) && !frame_fixed_height(other_fr)) {
+ target_fr = other_fr;
+ }
+ }
+
+ return target_fr;
}
/*
@@ -2784,8 +2893,8 @@ close_others (
}
if (!r) {
if (message && (p_confirm || cmdmod.confirm) && p_write) {
- dialog_changed(wp->w_buffer, FALSE);
- if (!win_valid(wp)) { /* autocommands messed wp up */
+ dialog_changed(wp->w_buffer, false);
+ if (!win_valid(wp)) { // autocommands messed wp up
nextwp = firstwin;
continue;
}
@@ -2793,10 +2902,10 @@ close_others (
if (bufIsChanged(wp->w_buffer))
continue;
}
- win_close(wp, !P_HID(wp->w_buffer) && !bufIsChanged(wp->w_buffer));
+ win_close(wp, !buf_hide(wp->w_buffer) && !bufIsChanged(wp->w_buffer));
}
- if (message && lastwin != firstwin)
+ if (message && !ONE_WINDOW)
EMSG(_("E445: Other window contains changes"));
}
@@ -2874,8 +2983,9 @@ static int win_alloc_firstwin(win_T *oldwin)
/* Very first window, need to create an empty buffer for it and
* initialize from scratch. */
curbuf = buflist_new(NULL, NULL, 1L, BLN_LISTED);
- if (curbuf == NULL)
+ if (curbuf == NULL) {
return FAIL;
+ }
curwin->w_buffer = curbuf;
curwin->w_s = &(curbuf->b_s);
curbuf->b_nwindows = 1; /* there is one window */
@@ -2893,7 +3003,6 @@ static int win_alloc_firstwin(win_T *oldwin)
topframe = curwin->w_frame;
topframe->fr_width = Columns;
topframe->fr_height = Rows - p_ch;
- topframe->fr_win = curwin;
return OK;
}
@@ -2926,11 +3035,13 @@ void win_init_size(void)
*/
static tabpage_T *alloc_tabpage(void)
{
+ static int last_tp_handle = 0;
tabpage_T *tp = xcalloc(1, sizeof(tabpage_T));
+ tp->handle = ++last_tp_handle;
handle_register_tabpage(tp);
- /* init t: variables */
- tp->tp_vars = dict_alloc();
+ // Init t: variables.
+ tp->tp_vars = tv_dict_alloc();
init_var_dict(tp->tp_vars, &tp->tp_winvar, VAR_SCOPE);
tp->tp_diff_invalid = TRUE;
tp->tp_ch_used = p_ch;
@@ -2950,8 +3061,7 @@ void free_tabpage(tabpage_T *tp)
hash_init(&tp->tp_vars->dv_hashtab);
unref_var_dict(tp->tp_vars);
-
- xfree(tp->localdir); // Free tab-local working directory
+ xfree(tp->tp_localdir);
xfree(tp);
}
@@ -2976,6 +3086,9 @@ int win_new_tabpage(int after, char_u *filename)
xfree(newtp);
return FAIL;
}
+
+ newtp->tp_localdir = tp->tp_localdir ? vim_strsave(tp->tp_localdir) : NULL;
+
curtab = newtp;
/* Create a new empty window. */
@@ -3003,10 +3116,15 @@ int win_new_tabpage(int after, char_u *filename)
newtp->tp_topframe = topframe;
last_status(FALSE);
- redraw_all_later(CLEAR);
+ redraw_all_later(NOT_VALID);
- apply_autocmds(EVENT_TABNEW, filename, filename, false, curbuf);
+ if (ui_is_external(kUIMultigrid)) {
+ tabpage_check_windows(tp);
+ }
+
+ apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf);
apply_autocmds(EVENT_WINENTER, NULL, NULL, false, curbuf);
+ apply_autocmds(EVENT_TABNEW, filename, filename, false, curbuf);
apply_autocmds(EVENT_TABENTER, NULL, NULL, false, curbuf);
return OK;
@@ -3078,6 +3196,45 @@ bool valid_tabpage(tabpage_T *tpc) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
return false;
}
+/// Returns true when `tpc` is valid and at least one window is valid.
+int valid_tabpage_win(tabpage_T *tpc)
+{
+ FOR_ALL_TABS(tp) {
+ if (tp == tpc) {
+ FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
+ if (win_valid_any_tab(wp)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ // shouldn't happen
+ return false;
+}
+
+/// Close tabpage `tab`, assuming it has no windows in it.
+/// There must be another tabpage or this will crash.
+void close_tabpage(tabpage_T *tab)
+{
+ tabpage_T *ptp;
+
+ if (tab == first_tabpage) {
+ first_tabpage = tab->tp_next;
+ ptp = first_tabpage;
+ } else {
+ for (ptp = first_tabpage; ptp != NULL && ptp->tp_next != tab;
+ ptp = ptp->tp_next) {
+ // do nothing
+ }
+ assert(ptp != NULL);
+ ptp->tp_next = tab->tp_next;
+ }
+
+ goto_tabpage_tp(ptp, false, false);
+ free_tabpage(tab);
+}
+
/*
* Find tab page "n" (first one is 1). Returns NULL when not found.
*/
@@ -3156,22 +3313,26 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_au
int old_off = tp->tp_firstwin->w_winrow;
win_T *next_prevwin = tp->tp_prevwin;
+ tabpage_T *old_curtab = curtab;
curtab = tp;
firstwin = tp->tp_firstwin;
lastwin = tp->tp_lastwin;
topframe = tp->tp_topframe;
+ if (old_curtab != curtab && ui_is_external(kUIMultigrid)) {
+ tabpage_check_windows(old_curtab);
+ }
+
/* We would like doing the TabEnter event first, but we don't have a
* valid current window yet, which may break some commands.
* This triggers autocommands, thus may make "tp" invalid. */
- win_enter_ext(tp->tp_curwin, false, TRUE,
- trigger_enter_autocmds, trigger_leave_autocmds);
+ win_enter_ext(tp->tp_curwin, false, true, false,
+ trigger_enter_autocmds, trigger_leave_autocmds);
prevwin = next_prevwin;
- last_status(FALSE); /* status line may appear or disappear */
- (void)win_comp_pos(); /* recompute w_winrow for all windows */
- must_redraw = CLEAR; /* need to redraw everything */
- diff_need_scrollbind = TRUE;
+ last_status(false); // status line may appear or disappear
+ (void)win_comp_pos(); // recompute w_winrow for all windows
+ diff_need_scrollbind = true;
/* The tabpage line may have appeared or disappeared, may need to resize
* the frames for that. When the Vim window was resized need to update
@@ -3193,7 +3354,21 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_au
apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
}
- redraw_all_later(CLEAR);
+ redraw_all_later(NOT_VALID);
+}
+
+/// called when changing current tabpage from old_curtab to curtab
+static void tabpage_check_windows(tabpage_T *old_curtab)
+{
+ win_T *next_wp;
+ for (win_T *wp = old_curtab->tp_firstwin; wp; wp = next_wp) {
+ next_wp = wp->w_next;
+ wp->w_pos_changed = true;
+ }
+
+ for (win_T *wp = firstwin; wp; wp = wp->w_next) {
+ wp->w_pos_changed = true;
+ }
}
/*
@@ -3207,11 +3382,8 @@ void goto_tabpage(int n)
int i;
if (text_locked()) {
- /* Not allowed when editing the command line. */
- if (cmdwin_type != 0)
- EMSG(_(e_cmdwin));
- else
- EMSG(_(e_secure));
+ // Not allowed when editing the command line.
+ text_locked_msg();
return;
}
@@ -3296,8 +3468,11 @@ void tabpage_move(int nr)
tabpage_T *tp;
tabpage_T *tp_dst;
- if (first_tabpage->tp_next == NULL)
+ assert(curtab != NULL);
+
+ if (first_tabpage->tp_next == NULL) {
return;
+ }
for (tp = first_tabpage; tp->tp_next != NULL && n < nr; tp = tp->tp_next) {
++n;
@@ -3310,15 +3485,20 @@ void tabpage_move(int nr)
tp_dst = tp;
- /* Remove the current tab page from the list of tab pages. */
- if (curtab == first_tabpage)
+ // Remove the current tab page from the list of tab pages.
+ if (curtab == first_tabpage) {
first_tabpage = curtab->tp_next;
- else {
- for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
- if (tp->tp_next == curtab)
+ } else {
+ tp = NULL;
+ FOR_ALL_TABS(tp2) {
+ if (tp2->tp_next == curtab) {
+ tp = tp2;
break;
- if (tp == NULL) /* "cannot happen" */
+ }
+ }
+ if (tp == NULL) { // "cannot happen"
return;
+ }
tp->tp_next = curtab->tp_next;
}
@@ -3362,11 +3542,13 @@ void win_goto(win_T *wp)
win_enter(wp, true);
- /* Conceal cursor line in previous window, unconceal in current window. */
- if (win_valid(owp) && owp->w_p_cole > 0 && !msg_scrolled)
- update_single_line(owp, owp->w_cursor.lnum);
- if (curwin->w_p_cole > 0 && !msg_scrolled)
- need_cursor_line_redraw = TRUE;
+ // Conceal cursor line in previous window, unconceal in current window.
+ if (win_valid(owp) && owp->w_p_cole > 0 && !msg_scrolled) {
+ redrawWinline(owp, owp->w_cursor.lnum);
+ }
+ if (curwin->w_p_cole > 0 && !msg_scrolled) {
+ redrawWinline(curwin, curwin->w_cursor.lnum);
+ }
}
@@ -3506,7 +3688,7 @@ end:
*/
void win_enter(win_T *wp, bool undo_sync)
{
- win_enter_ext(wp, undo_sync, FALSE, TRUE, TRUE);
+ win_enter_ext(wp, undo_sync, false, false, true, true);
}
/*
@@ -3514,7 +3696,9 @@ void win_enter(win_T *wp, bool undo_sync)
* Can be called with "curwin_invalid" TRUE, which means that curwin has just
* been closed and isn't valid.
*/
-static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, int trigger_enter_autocmds, int trigger_leave_autocmds)
+static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid,
+ int trigger_new_autocmds, int trigger_enter_autocmds,
+ int trigger_leave_autocmds)
{
int other_buffer = FALSE;
@@ -3563,33 +3747,46 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, int tri
curwin->w_cursor.coladd = 0;
changed_line_abv_curs(); /* assume cursor position needs updating */
- // The new directory is either the local directory of the window, of the tab
- // or NULL.
- char_u *new_dir = curwin->w_localdir ? curwin->w_localdir : curtab->localdir;
+ // New directory is either the local directory of the window, tab or NULL.
+ char *new_dir = (char *)(curwin->w_localdir
+ ? curwin->w_localdir : curtab->tp_localdir);
+
+ char cwd[MAXPATHL];
+ if (os_dirname((char_u *)cwd, MAXPATHL) != OK) {
+ cwd[0] = NUL;
+ }
if (new_dir) {
// Window/tab has a local directory: Save current directory as global
- // directory (unless that was done already) and change to the local
- // directory.
+ // (unless that was done already) and change to the local directory.
if (globaldir == NULL) {
- char_u cwd[MAXPATHL];
-
- if (os_dirname(cwd, MAXPATHL) == OK) {
- globaldir = vim_strsave(cwd);
+ if (cwd[0] != NUL) {
+ globaldir = (char_u *)xstrdup(cwd);
}
}
- if (os_chdir((char *)new_dir) == 0) {
+ if (os_chdir(new_dir) == 0) {
+ if (!p_acd && !strequal(new_dir, cwd)) {
+ do_autocmd_dirchanged(new_dir, curwin->w_localdir
+ ? kCdScopeWindow : kCdScopeTab);
+ }
shorten_fnames(true);
}
} else if (globaldir != NULL) {
- /* Window doesn't have a local directory and we are not in the global
- * directory: Change to the global directory. */
- ignored = os_chdir((char *)globaldir);
+ // Window doesn't have a local directory and we are not in the global
+ // directory: Change to the global directory.
+ if (os_chdir((char *)globaldir) == 0) {
+ if (!p_acd && !strequal((char *)globaldir, cwd)) {
+ do_autocmd_dirchanged((char *)globaldir, kCdScopeGlobal);
+ }
+ }
xfree(globaldir);
globaldir = NULL;
shorten_fnames(TRUE);
}
+ if (trigger_new_autocmds) {
+ apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf);
+ }
if (trigger_enter_autocmds) {
apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
if (other_buffer)
@@ -3602,6 +3799,12 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, int tri
if (restart_edit)
redraw_later(VALID); /* causes status line redraw */
+ if (HL_ATTR(HLF_INACTIVE)
+ || (prevwin && prevwin->w_hl_ids[HLF_INACTIVE])
+ || curwin->w_hl_ids[HLF_INACTIVE]) {
+ redraw_all_later(NOT_VALID);
+ }
+
/* set window height to desired minimal value */
if (curwin->w_height < p_wh && !curwin->w_p_wfh)
win_setheight((int)p_wh);
@@ -3616,10 +3819,6 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, int tri
/* Change directories when the 'acd' option is set. */
do_autochdir();
-
- if (curbuf->terminal) {
- terminal_resize(curbuf->terminal, curwin->w_width, curwin->w_height);
- }
}
@@ -3686,15 +3885,19 @@ win_T *buf_jump_open_tab(buf_T *buf)
*/
static win_T *win_alloc(win_T *after, int hidden)
{
- /*
- * allocate window structure and linesizes arrays
- */
+ static int last_win_id = LOWEST_WIN_ID - 1;
+
+ // allocate window structure and linesizes arrays
win_T *new_wp = xcalloc(1, sizeof(win_T));
- handle_register_window(new_wp);
win_alloc_lines(new_wp);
- /* init w: variables */
- new_wp->w_vars = dict_alloc();
+ new_wp->handle = ++last_win_id;
+ handle_register_window(new_wp);
+
+ grid_assign_handle(&new_wp->w_grid);
+
+ // Init w: variables.
+ new_wp->w_vars = tv_dict_alloc();
init_var_dict(new_wp->w_vars, &new_wp->w_winvar, VAR_SCOPE);
/* Don't execute autocommands while the window is not properly
@@ -3758,8 +3961,15 @@ win_free (
hash_init(&wp->w_vars->dv_hashtab);
unref_var_dict(wp->w_vars);
- if (prevwin == wp)
+ if (prevwin == wp) {
prevwin = NULL;
+ }
+ FOR_ALL_TABS(ttp) {
+ if (ttp->tp_prevwin == wp) {
+ ttp->tp_prevwin = NULL;
+ }
+ }
+
win_free_lsize(wp);
for (i = 0; i < wp->w_tagstacklen; ++i)
@@ -3784,6 +3994,8 @@ win_free (
xfree(wp->w_p_cc_cols);
+ win_free_grid(wp, false);
+
if (wp != aucmd_win)
win_remove(wp, tp);
if (autocmd_busy) {
@@ -3796,6 +4008,20 @@ win_free (
unblock_autocmds();
}
+void win_free_grid(win_T *wp, bool reinit)
+{
+ if (wp->w_grid.handle != 0 && ui_is_external(kUIMultigrid)) {
+ ui_call_grid_destroy(wp->w_grid.handle);
+ wp->w_grid.handle = 0;
+ }
+ grid_free(&wp->w_grid);
+ if (reinit) {
+ // if a float is turned into a split and back into a float, the grid
+ // data structure will be reused
+ memset(&wp->w_grid, 0, sizeof(wp->w_grid));
+ }
+}
+
/*
* Append window "wp" in the window list after window "after".
*/
@@ -3829,18 +4055,20 @@ win_remove (
tabpage_T *tp /* tab page "win" is in, NULL for current */
)
{
- if (wp->w_prev != NULL)
+ if (wp->w_prev != NULL) {
wp->w_prev->w_next = wp->w_next;
- else if (tp == NULL)
- firstwin = wp->w_next;
- else
+ } else if (tp == NULL) {
+ firstwin = curtab->tp_firstwin = wp->w_next;
+ } else {
tp->tp_firstwin = wp->w_next;
- if (wp->w_next != NULL)
+ }
+ if (wp->w_next != NULL) {
wp->w_next->w_prev = wp->w_prev;
- else if (tp == NULL)
- lastwin = wp->w_prev;
- else
+ } else if (tp == NULL) {
+ lastwin = curtab->tp_lastwin = wp->w_prev;
+ } else {
tp->tp_lastwin = wp->w_prev;
+ }
}
/*
@@ -3874,12 +4102,18 @@ static void frame_insert(frame_T *before, frame_T *frp)
*/
static void frame_remove(frame_T *frp)
{
- if (frp->fr_prev != NULL)
+ if (frp->fr_prev != NULL) {
frp->fr_prev->fr_next = frp->fr_next;
- else
+ } else {
frp->fr_parent->fr_child = frp->fr_next;
- if (frp->fr_next != NULL)
+ // special case: topframe->fr_child == frp
+ if (topframe->fr_child == frp) {
+ topframe->fr_child = frp->fr_next;
+ }
+ }
+ if (frp->fr_next != NULL) {
frp->fr_next->fr_prev = frp->fr_prev;
+ }
}
@@ -3889,8 +4123,8 @@ static void frame_remove(frame_T *frp)
void win_alloc_lines(win_T *wp)
{
wp->w_lines_valid = 0;
- assert(Rows >= 0);
- wp->w_lines = xcalloc(Rows, sizeof(wline_T));
+ assert(wp->w_grid.Rows >= 0);
+ wp->w_lines = xcalloc(MAX(wp->w_grid.Rows + 1, Rows), sizeof(wline_T));
}
/*
@@ -4020,7 +4254,8 @@ static void frame_comp_pos(frame_T *topfrp, int *row, int *col)
wp->w_winrow = *row;
wp->w_wincol = *col;
redraw_win_later(wp, NOT_VALID);
- wp->w_redr_status = TRUE;
+ wp->w_redr_status = true;
+ wp->w_pos_changed = true;
}
*row += wp->w_height + wp->w_status_height;
*col += wp->w_width + wp->w_vsep_width;
@@ -4073,8 +4308,9 @@ void win_setheight_win(int height, win_T *win)
* If there is extra space created between the last window and the command
* line, clear it.
*/
- if (full_screen && msg_scrolled == 0 && row < cmdline_row)
- screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
+ if (full_screen && msg_scrolled == 0 && row < cmdline_row) {
+ grid_fill(&default_grid, row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
+ }
cmdline_row = row;
msg_row = row;
msg_col = 0;
@@ -4157,11 +4393,11 @@ static void frame_setheight(frame_T *curfrp, int height)
room_cmdline = 0;
}
- if (height <= room + room_cmdline)
+ if (height <= room + room_cmdline) {
break;
+ }
if (run == 2 || curfrp->fr_width == Columns) {
- if (height > room + room_cmdline)
- height = room + room_cmdline;
+ height = room + room_cmdline;
break;
}
frame_setheight(curfrp->fr_parent, height
@@ -4325,8 +4561,7 @@ static void frame_setwidth(frame_T *curfrp, int width)
if (width <= room)
break;
if (run == 2 || curfrp->fr_height >= ROWS_AVAIL) {
- if (width > room)
- width = room;
+ width = room;
break;
}
frame_setwidth(curfrp->fr_parent, width
@@ -4525,7 +4760,7 @@ void win_drag_status_line(win_T *dragwin, int offset)
fr = fr->fr_next;
}
row = win_comp_pos();
- screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
+ grid_fill(&default_grid, row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
cmdline_row = row;
p_ch = Rows - cmdline_row;
if (p_ch < 1)
@@ -4638,10 +4873,13 @@ void win_drag_vsep_line(win_T *dragwin, int offset)
#define FRACTION_MULT 16384L
// Set wp->w_fraction for the current w_wrow and w_height.
+// Has no effect when the window is less than two lines.
void set_fraction(win_T *wp)
{
- wp->w_fraction = ((long)wp->w_wrow * FRACTION_MULT + wp->w_height / 2)
+ if (wp->w_height > 1) {
+ wp->w_fraction = ((long)wp->w_wrow * FRACTION_MULT + wp->w_height / 2)
/ (long)wp->w_height;
+ }
}
/*
@@ -4651,8 +4889,6 @@ void set_fraction(win_T *wp)
*/
void win_new_height(win_T *wp, int height)
{
- linenr_T lnum;
- int sline, line_size;
int prev_height = wp->w_height;
/* Don't want a negative height. Happens when splitting a tiny window.
@@ -4668,7 +4904,7 @@ void win_new_height(win_T *wp, int height)
// call win_new_height() recursively.
validate_cursor();
}
- if (wp->w_height != prev_height) {
+ if (wp->w_height != prev_height) { // -V547
return; // Recursive call already changed the size, bail out.
}
if (wp->w_wrow != wp->w_prev_fraction_row) {
@@ -4679,6 +4915,21 @@ void win_new_height(win_T *wp, int height)
wp->w_height = height;
wp->w_skipcol = 0;
+ // There is no point in adjusting the scroll position when exiting. Some
+ // values might be invalid.
+ if (!exiting) {
+ scroll_to_fraction(wp, prev_height);
+ }
+
+ wp->w_pos_changed = true;
+}
+
+void scroll_to_fraction(win_T *wp, int prev_height)
+{
+ linenr_T lnum;
+ int sline, line_size;
+ int height = wp->w_height;
+
/* Don't change w_topline when height is zero. Don't set w_topline when
* 'scrollbind' is set and this isn't the current window. */
if (height > 0
@@ -4697,8 +4948,8 @@ void win_new_height(win_T *wp, int height)
sline = wp->w_wrow - line_size;
if (sline >= 0) {
- /* Make sure the whole cursor line is visible, if possible. */
- int rows = plines_win(wp, lnum, FALSE);
+ // Make sure the whole cursor line is visible, if possible.
+ const int rows = plines_win(wp, lnum, false);
if (sline > wp->w_height - rows) {
sline = wp->w_height - rows;
@@ -4733,12 +4984,13 @@ void win_new_height(win_T *wp, int height)
--sline;
break;
}
- --lnum;
- if (lnum == wp->w_topline)
- line_size = plines_win_nofill(wp, lnum, TRUE)
+ lnum--;
+ if (lnum == wp->w_topline) {
+ line_size = plines_win_nofill(wp, lnum, true)
+ wp->w_topfill;
- else
- line_size = plines_win(wp, lnum, TRUE);
+ } else {
+ line_size = plines_win(wp, lnum, true);
+ }
sline -= line_size;
}
@@ -4775,13 +5027,11 @@ void win_new_height(win_T *wp, int height)
if (wp->w_buffer->terminal) {
terminal_resize(wp->w_buffer->terminal, 0, wp->w_height);
- redraw_win_later(wp, CLEAR);
+ redraw_win_later(wp, NOT_VALID);
}
}
-/*
- * Set the width of a window.
- */
+/// Set the width of a window.
void win_new_width(win_T *wp, int width)
{
wp->w_width = width;
@@ -4797,10 +5047,12 @@ void win_new_width(win_T *wp, int width)
if (wp->w_buffer->terminal) {
if (wp->w_height != 0) {
- terminal_resize(wp->w_buffer->terminal, wp->w_width, 0);
+ terminal_resize(wp->w_buffer->terminal,
+ (uint16_t)(MAX(0, wp->w_width - win_col_off(wp))),
+ 0);
}
- redraw_win_later(wp, CLEAR);
}
+ wp->w_pos_changed = true;
}
void win_comp_scroll(win_T *wp)
@@ -4857,10 +5109,11 @@ void command_height(void)
/* Recompute window positions. */
(void)win_comp_pos();
- /* clear the lines added to cmdline */
- if (full_screen)
- screen_fill(cmdline_row, (int)Rows, 0,
- (int)Columns, ' ', ' ', 0);
+ // clear the lines added to cmdline
+ if (full_screen) {
+ grid_fill(&default_grid, cmdline_row, (int)Rows, 0, (int)Columns, ' ',
+ ' ', 0);
+ }
msg_row = cmdline_row;
redraw_cmdline = TRUE;
return;
@@ -4946,16 +5199,20 @@ file_name_in_line (
{
char_u *ptr;
size_t len;
+ bool in_type = true;
+ bool is_url = false;
/*
* search forward for what could be the start of a file name
*/
ptr = line + col;
- while (*ptr != NUL && !vim_isfilec(*ptr))
- mb_ptr_adv(ptr);
- if (*ptr == NUL) { /* nothing found */
- if (options & FNAME_MESS)
+ while (*ptr != NUL && !vim_isfilec(*ptr)) {
+ MB_PTR_ADV(ptr);
+ }
+ if (*ptr == NUL) { // nothing found
+ if (options & FNAME_MESS) {
EMSG(_("E446: No file name under cursor"));
+ }
return NULL;
}
@@ -4964,13 +5221,14 @@ file_name_in_line (
* Go one char back to ":" before "//" even when ':' is not in 'isfname'.
*/
while (ptr > line) {
- if (has_mbyte && (len = (size_t)((*mb_head_off)(line, ptr - 1))) > 0)
+ if ((len = (size_t)(utf_head_off(line, ptr - 1))) > 0) {
ptr -= len + 1;
- else if (vim_isfilec(ptr[-1])
- || ((options & FNAME_HYP) && path_is_url((char *)ptr - 1)))
- --ptr;
- else
+ } else if (vim_isfilec(ptr[-1])
+ || ((options & FNAME_HYP) && path_is_url((char *)ptr - 1))) {
+ ptr--;
+ } else {
break;
+ }
}
/*
@@ -4979,7 +5237,19 @@ file_name_in_line (
*/
len = 0;
while (vim_isfilec(ptr[len]) || (ptr[len] == '\\' && ptr[len + 1] == ' ')
- || ((options & FNAME_HYP) && path_is_url((char *)ptr + len))) {
+ || ((options & FNAME_HYP) && path_is_url((char *)ptr + len))
+ || (is_url && vim_strchr((char_u *)"?&=", ptr[len]) != NULL)) {
+ // After type:// we also include ?, & and = as valid characters, so that
+ // http://google.com?q=this&that=ok works.
+ if ((ptr[len] >= 'A' && ptr[len] <= 'Z')
+ || (ptr[len] >= 'a' && ptr[len] <= 'z')) {
+ if (in_type && path_is_url((char *)ptr + len + 1)) {
+ is_url = true;
+ }
+ } else {
+ in_type = false;
+ }
+
if (ptr[len] == '\\' && ptr[len + 1] == ' ') {
// Skip over the "\" in "\ ".
++len;
@@ -5028,7 +5298,7 @@ last_status (
{
/* Don't make a difference between horizontal or vertical split. */
last_status_rec(topframe, (p_ls == 2
- || (p_ls == 1 && (morewin || lastwin != firstwin))));
+ || (p_ls == 1 && (morewin || !ONE_WINDOW))));
}
static void last_status_rec(frame_T *fr, int statusline)
@@ -5085,6 +5355,9 @@ static void last_status_rec(frame_T *fr, int statusline)
*/
int tabline_height(void)
{
+ if (ui_is_external(kUITabline)) {
+ return 0;
+ }
assert(first_tabpage);
switch (p_stal) {
case 0: return 0;
@@ -5127,7 +5400,7 @@ bool only_one_window(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
int count = 0;
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_buffer != NULL
- && (!((wp->w_buffer->b_help && !curbuf->b_help)
+ && (!((bt_help(wp->w_buffer) && !bt_help(curbuf))
|| wp->w_p_pvw) || wp == curwin) && wp != aucmd_win) {
count++;
}
@@ -5229,15 +5502,13 @@ restore_snapshot (
win_comp_pos();
if (wp != NULL && close_curwin)
win_goto(wp);
- redraw_all_later(CLEAR);
+ redraw_all_later(NOT_VALID);
}
clear_snapshot(curtab, idx);
}
-/*
- * Check if frames "sn" and "fr" have the same layout, same following frames
- * and same children.
- */
+/// Check if frames "sn" and "fr" have the same layout, same following frames
+/// and same children. And the window pointer is valid.
static int check_snapshot_rec(frame_T *sn, frame_T *fr)
{
if (sn->fr_layout != fr->fr_layout
@@ -5246,7 +5517,8 @@ static int check_snapshot_rec(frame_T *sn, frame_T *fr)
|| (sn->fr_next != NULL
&& check_snapshot_rec(sn->fr_next, fr->fr_next) == FAIL)
|| (sn->fr_child != NULL
- && check_snapshot_rec(sn->fr_child, fr->fr_child) == FAIL))
+ && check_snapshot_rec(sn->fr_child, fr->fr_child) == FAIL)
+ || (sn->fr_win != NULL && !win_valid(sn->fr_win)))
return FAIL;
return OK;
}
@@ -5281,6 +5553,27 @@ static win_T *restore_snapshot_rec(frame_T *sn, frame_T *fr)
return wp;
}
+/// Gets the focused window (the one holding the cursor) of the snapshot.
+static win_T *get_snapshot_focus(int idx)
+{
+ if (curtab->tp_snapshot[idx] == NULL) {
+ return NULL;
+ }
+
+ frame_T *sn = curtab->tp_snapshot[idx];
+ // This should be equivalent to the recursive algorithm found in
+ // restore_snapshot as far as traveling nodes go.
+ while (sn->fr_child != NULL || sn->fr_next != NULL) {
+ while (sn->fr_child != NULL) {
+ sn = sn->fr_child;
+ }
+ if (sn->fr_next != NULL) {
+ sn = sn->fr_next;
+ }
+ }
+
+ return sn->fr_win;
+}
/*
* Set "win" to be the curwin and "tp" to be the current tab page.
@@ -5313,12 +5606,10 @@ int switch_win(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage
return OK;
}
-/*
- * Restore current tabpage and window saved by switch_win(), if still valid.
- * When "no_display" is TRUE the display won't be affected, no redraw is
- * triggered.
- */
-void restore_win(win_T *save_curwin, tabpage_T *save_curtab, int no_display)
+// Restore current tabpage and window saved by switch_win(), if still valid.
+// When "no_display" is true the display won't be affected, no redraw is
+// triggered.
+void restore_win(win_T *save_curwin, tabpage_T *save_curtab, bool no_display)
{
if (save_curtab != NULL && valid_tabpage(save_curtab)) {
if (no_display) {
@@ -5337,44 +5628,45 @@ void restore_win(win_T *save_curwin, tabpage_T *save_curtab, int no_display)
unblock_autocmds();
}
-/*
- * Make "buf" the current buffer. restore_buffer() MUST be called to undo.
- * No autocommands will be executed. Use aucmd_prepbuf() if there are any.
- */
-void switch_buffer(buf_T **save_curbuf, buf_T *buf)
+/// Make "buf" the current buffer.
+///
+/// restore_buffer() MUST be called to undo.
+/// No autocommands will be executed. Use aucmd_prepbuf() if there are any.
+void switch_buffer(bufref_T *save_curbuf, buf_T *buf)
{
block_autocmds();
- *save_curbuf = curbuf;
- --curbuf->b_nwindows;
+ set_bufref(save_curbuf, curbuf);
+ curbuf->b_nwindows--;
curbuf = buf;
curwin->w_buffer = buf;
- ++curbuf->b_nwindows;
+ curbuf->b_nwindows++;
}
-/*
- * Restore the current buffer after using switch_buffer().
- */
-void restore_buffer(buf_T *save_curbuf)
+/// Restore the current buffer after using switch_buffer().
+void restore_buffer(bufref_T *save_curbuf)
{
unblock_autocmds();
- /* Check for valid buffer, just in case. */
- if (buf_valid(save_curbuf)) {
- --curbuf->b_nwindows;
- curwin->w_buffer = save_curbuf;
- curbuf = save_curbuf;
- ++curbuf->b_nwindows;
+ // Check for valid buffer, just in case.
+ if (bufref_valid(save_curbuf)) {
+ curbuf->b_nwindows--;
+ curwin->w_buffer = save_curbuf->br_buf;
+ curbuf = save_curbuf->br_buf;
+ curbuf->b_nwindows++;
}
}
-// Add match to the match list of window 'wp'. The pattern 'pat' will be
-// highlighted with the group 'grp' with priority 'prio'.
-// Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
-// If no particular ID is desired, -1 must be specified for 'id'.
-// Return ID of added match, -1 on failure.
-int match_add(win_T *wp, char_u *grp, char_u *pat,
+/// Add match to the match list of window 'wp'. The pattern 'pat' will be
+/// highlighted with the group 'grp' with priority 'prio'.
+/// Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
+///
+/// @param[in] id a desired ID 'id' can be specified
+/// (greater than or equal to 1). -1 must be specified if no
+/// particular ID is desired
+/// @return ID of added match, -1 on failure.
+int match_add(win_T *wp, const char *const grp, const char *const pat,
int prio, int id, list_T *pos_list,
- char_u *conceal_char)
+ const char *const conceal_char)
{
matchitem_T *cur;
matchitem_T *prev;
@@ -5387,8 +5679,8 @@ int match_add(win_T *wp, char_u *grp, char_u *pat,
return -1;
}
if (id < -1 || id == 0) {
- EMSGN("E799: Invalid ID: %" PRId64
- " (must be greater than or equal to 1)",
+ EMSGN(_("E799: Invalid ID: %" PRId64
+ " (must be greater than or equal to 1)"),
id);
return -1;
}
@@ -5396,17 +5688,17 @@ int match_add(win_T *wp, char_u *grp, char_u *pat,
cur = wp->w_match_head;
while (cur != NULL) {
if (cur->id == id) {
- EMSGN("E801: ID already taken: %" PRId64, id);
+ EMSGN(_("E801: ID already taken: %" PRId64), id);
return -1;
}
cur = cur->next;
}
}
- if ((hlg_id = syn_namen2id(grp, (int)STRLEN(grp))) == 0) {
+ if ((hlg_id = syn_name2id((const char_u *)grp)) == 0) {
EMSG2(_(e_nogroup), grp);
return -1;
}
- if (pat != NULL && (regprog = vim_regcomp(pat, RE_MAGIC)) == NULL) {
+ if (pat != NULL && (regprog = vim_regcomp((char_u *)pat, RE_MAGIC)) == NULL) {
EMSG2(_(e_invarg2), pat);
return -1;
}
@@ -5425,76 +5717,76 @@ int match_add(win_T *wp, char_u *grp, char_u *pat,
m = xcalloc(1, sizeof(matchitem_T));
m->id = id;
m->priority = prio;
- m->pattern = pat == NULL ? NULL: vim_strsave(pat);
+ m->pattern = pat == NULL ? NULL: (char_u *)xstrdup(pat);
m->hlg_id = hlg_id;
m->match.regprog = regprog;
m->match.rmm_ic = FALSE;
m->match.rmm_maxcol = 0;
m->conceal_char = 0;
if (conceal_char != NULL) {
- m->conceal_char = (*mb_ptr2char)(conceal_char);
+ m->conceal_char = utf_ptr2char((const char_u *)conceal_char);
}
// Set up position matches
- if (pos_list != NULL)
- {
- linenr_T toplnum = 0;
- linenr_T botlnum = 0;
- listitem_T *li;
- int i;
-
- for (i = 0, li = pos_list->lv_first; li != NULL && i < MAXPOSMATCH;
- i++, li = li->li_next) {
- linenr_T lnum = 0;
- colnr_T col = 0;
- int len = 1;
- list_T *subl;
- listitem_T *subli;
- int error = false;
-
- if (li->li_tv.v_type == VAR_LIST) {
- subl = li->li_tv.vval.v_list;
- if (subl == NULL) {
- goto fail;
- }
- subli = subl->lv_first;
+ if (pos_list != NULL) {
+ linenr_T toplnum = 0;
+ linenr_T botlnum = 0;
+
+ int i = 0;
+ TV_LIST_ITER(pos_list, li, {
+ linenr_T lnum = 0;
+ colnr_T col = 0;
+ int len = 1;
+ bool error = false;
+
+ if (TV_LIST_ITEM_TV(li)->v_type == VAR_LIST) {
+ const list_T *const subl = TV_LIST_ITEM_TV(li)->vval.v_list;
+ const listitem_T *subli = tv_list_first(subl);
if (subli == NULL) {
+ emsgf(_("E5030: Empty list at position %d"),
+ (int)tv_list_idx_of_item(pos_list, li));
goto fail;
}
- lnum = get_tv_number_chk(&subli->li_tv, &error);
- if (error == true) {
+ lnum = tv_get_number_chk(TV_LIST_ITEM_TV(subli), &error);
+ if (error) {
goto fail;
}
- if (lnum == 0) {
- --i;
+ if (lnum <= 0) {
continue;
}
m->pos.pos[i].lnum = lnum;
- subli = subli->li_next;
+ subli = TV_LIST_ITEM_NEXT(subl, subli);
if (subli != NULL) {
- col = get_tv_number_chk(&subli->li_tv, &error);
- if (error == true)
+ col = tv_get_number_chk(TV_LIST_ITEM_TV(subli), &error);
+ if (error) {
goto fail;
- subli = subli->li_next;
+ }
+ if (col < 0) {
+ continue;
+ }
+ subli = TV_LIST_ITEM_NEXT(subl, subli);
if (subli != NULL) {
- len = get_tv_number_chk(&subli->li_tv, &error);
- if (error == true) {
+ len = tv_get_number_chk(TV_LIST_ITEM_TV(subli), &error);
+ if (len < 0) {
+ continue;
+ }
+ if (error) {
goto fail;
}
}
}
m->pos.pos[i].col = col;
m->pos.pos[i].len = len;
- } else if (li->li_tv.v_type == VAR_NUMBER) {
- if (li->li_tv.vval.v_number == 0) {
- --i;
+ } else if (TV_LIST_ITEM_TV(li)->v_type == VAR_NUMBER) {
+ if (TV_LIST_ITEM_TV(li)->vval.v_number <= 0) {
continue;
}
- m->pos.pos[i].lnum = li->li_tv.vval.v_number;
+ m->pos.pos[i].lnum = TV_LIST_ITEM_TV(li)->vval.v_number;
m->pos.pos[i].col = 0;
m->pos.pos[i].len = 0;
} else {
- EMSG(_("List or number required"));
+ emsgf(_("E5031: List or number required at position %d"),
+ (int)tv_list_idx_of_item(pos_list, li));
goto fail;
}
if (toplnum == 0 || lnum < toplnum) {
@@ -5503,7 +5795,11 @@ int match_add(win_T *wp, char_u *grp, char_u *pat,
if (botlnum == 0 || lnum >= botlnum) {
botlnum = lnum + 1;
}
- }
+ i++;
+ if (i >= MAXPOSMATCH) {
+ break;
+ }
+ });
// Calculate top and bottom lines for redrawing area
if (toplnum != 0){
@@ -5548,10 +5844,9 @@ fail:
return -1;
}
-/*
- * Delete match with ID 'id' in the match list of window 'wp'.
- * Print error messages if 'perr' is TRUE.
- */
+
+/// Delete match with ID 'id' in the match list of window 'wp'.
+/// Print error messages if 'perr' is TRUE.
int match_delete(win_T *wp, int id, int perr)
{
matchitem_T *cur = wp->w_match_head;
@@ -5559,10 +5854,11 @@ int match_delete(win_T *wp, int id, int perr)
int rtype = SOME_VALID;
if (id < 1) {
- if (perr == TRUE)
- EMSGN("E802: Invalid ID: %" PRId64
- " (must be greater than or equal to 1)",
+ if (perr) {
+ EMSGN(_("E802: Invalid ID: %" PRId64
+ " (must be greater than or equal to 1)"),
id);
+ }
return -1;
}
while (cur != NULL && cur->id != id) {
@@ -5570,8 +5866,9 @@ int match_delete(win_T *wp, int id, int perr)
cur = cur->next;
}
if (cur == NULL) {
- if (perr == TRUE)
- EMSGN("E803: ID not found: %" PRId64, id);
+ if (perr) {
+ EMSGN(_("E803: ID not found: %" PRId64), id);
+ }
return -1;
}
if (cur == prev)
@@ -5671,3 +5968,144 @@ static bool frame_check_width(frame_T *topfrp, int width)
}
return true;
}
+
+int win_getid(typval_T *argvars)
+{
+ if (argvars[0].v_type == VAR_UNKNOWN) {
+ return curwin->handle;
+ }
+ int winnr = tv_get_number(&argvars[0]);
+ win_T *wp;
+ if (winnr > 0) {
+ if (argvars[1].v_type == VAR_UNKNOWN) {
+ wp = firstwin;
+ } else {
+ tabpage_T *tp = NULL;
+ int tabnr = tv_get_number(&argvars[1]);
+ FOR_ALL_TABS(tp2) {
+ if (--tabnr == 0) {
+ tp = tp2;
+ break;
+ }
+ }
+ if (tp == NULL) {
+ return -1;
+ }
+ if (tp == curtab) {
+ wp = firstwin;
+ } else {
+ wp = tp->tp_firstwin;
+ }
+ }
+ for ( ; wp != NULL; wp = wp->w_next) {
+ if (--winnr == 0) {
+ return wp->handle;
+ }
+ }
+ }
+ return 0;
+}
+
+int win_gotoid(typval_T *argvars)
+{
+ int id = tv_get_number(&argvars[0]);
+
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->handle == id) {
+ goto_tabpage_win(tp, wp);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void win_get_tabwin(handle_T id, int *tabnr, int *winnr)
+{
+ *tabnr = 0;
+ *winnr = 0;
+
+ int tnum = 1, wnum = 1;
+ FOR_ALL_TABS(tp) {
+ FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
+ if (wp->handle == id) {
+ *winnr = wnum;
+ *tabnr = tnum;
+ return;
+ }
+ wnum++;
+ }
+ tnum++;
+ wnum = 1;
+ }
+}
+
+void win_id2tabwin(typval_T *const argvars, typval_T *const rettv)
+{
+ int winnr = 1;
+ int tabnr = 1;
+ handle_T id = (handle_T)tv_get_number(&argvars[0]);
+
+ win_get_tabwin(id, &tabnr, &winnr);
+
+ list_T *const list = tv_list_alloc_ret(rettv, 2);
+ tv_list_append_number(list, tabnr);
+ tv_list_append_number(list, winnr);
+}
+
+win_T * win_id2wp(typval_T *argvars)
+{
+ int id = tv_get_number(&argvars[0]);
+
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->handle == id) {
+ return wp;
+ }
+ }
+
+ return NULL;
+}
+
+int win_id2win(typval_T *argvars)
+{
+ int nr = 1;
+ int id = tv_get_number(&argvars[0]);
+
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if (wp->handle == id) {
+ return nr;
+ }
+ nr++;
+ }
+ return 0;
+}
+
+void win_findbuf(typval_T *argvars, list_T *list)
+{
+ int bufnr = tv_get_number(&argvars[0]);
+
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer->b_fnum == bufnr) {
+ tv_list_append_number(list, wp->handle);
+ }
+ }
+}
+
+void win_ui_flush(void)
+{
+ if (!ui_is_external(kUIMultigrid)) {
+ return;
+ }
+
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_pos_changed && wp->w_grid.chars != NULL) {
+ if (tp == curtab) {
+ ui_call_win_pos(wp->w_grid.handle, wp->handle, wp->w_winrow,
+ wp->w_wincol, wp->w_width, wp->w_height);
+ } else {
+ ui_call_win_hide(wp->w_grid.handle);
+ }
+ wp->w_pos_changed = false;
+ }
+ }
+
+}