diff options
Diffstat (limited to 'src/nvim/window.c')
-rw-r--r-- | src/nvim/window.c | 652 |
1 files changed, 567 insertions, 85 deletions
diff --git a/src/nvim/window.c b/src/nvim/window.c index bb71b12aed..18fad76a95 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -6,6 +6,7 @@ #include <stdbool.h> #include "nvim/api/private/handle.h" +#include "nvim/api/private/helpers.h" #include "nvim/vim.h" #include "nvim/ascii.h" #include "nvim/window.h" @@ -48,6 +49,7 @@ #include "nvim/terminal.h" #include "nvim/undo.h" #include "nvim/ui.h" +#include "nvim/ui_compositor.h" #include "nvim/os/os.h" @@ -203,14 +205,24 @@ newwindow: wp = wp->w_next; } } else { - if (nchar == 'W') { /* go to previous window */ + if (nchar == 'W') { // go to previous window wp = curwin->w_prev; - if (wp == NULL) - wp = lastwin; /* wrap around */ - } else { /* go to next window */ + if (wp == NULL) { + wp = lastwin; // wrap around + } + while (wp != NULL && wp->w_floating + && !wp->w_float_config.focusable) { + wp = wp->w_prev; + } + } else { // go to next window wp = curwin->w_next; - if (wp == NULL) - wp = firstwin; /* wrap around */ + while (wp != NULL && wp->w_floating + && !wp->w_float_config.focusable) { + wp = wp->w_next; + } + if (wp == NULL) { + wp = firstwin; // wrap around + } } } win_goto(wp); @@ -281,7 +293,7 @@ newwindow: /* cursor to bottom-right window */ case 'b': case Ctrl_B: - win_goto(lastwin); + win_goto(lastwin_nofloating()); break; /* cursor to last accessed (previous) window */ @@ -483,6 +495,22 @@ wingotofile: cmdmod.tab = tabpage_index(curtab) + 1; nchar = xchar; goto wingotofile; + + case 'e': + if (curwin->w_floating || !ui_has(kUIMultigrid)) { + beep_flush(); + break; + } + FloatConfig config = FLOAT_CONFIG_INIT; + config.external = true; + Error err = ERROR_INIT; + if (!win_new_float(curwin, curwin->w_width, curwin->w_height, config, + &err)) { + EMSG(err.msg); + api_clear_error(&err); + beep_flush(); + } + break; default: beep_flush(); break; @@ -504,6 +532,302 @@ static void cmd_with_count(char *cmd, char_u *bufp, size_t bufsize, } } +/// Create a new float. +/// +/// if wp == NULL allocate a new window, otherwise turn existing window into a +/// float. It must then already belong to the current tabpage! +/// +/// config must already have been validated! +win_T *win_new_float(win_T *wp, int width, int height, FloatConfig config, + Error *err) +{ + bool new = false; + if (wp == NULL) { + new = true; + wp = win_alloc(lastwin_nofloating(), false); + win_init(wp, curwin, 0); + } else { + assert(!wp->w_floating); + if (firstwin == wp && lastwin_nofloating() == wp) { + // last non-float + api_set_error(err, kErrorTypeException, + "Cannot change last window into float"); + return NULL; + } else if (!win_valid(wp)) { + api_set_error(err, kErrorTypeException, + "Cannot change window from different tabpage into float"); + return NULL; + } + int dir; + winframe_remove(wp, &dir, NULL); + xfree(wp->w_frame); + wp->w_frame = NULL; + (void)win_comp_pos(); // recompute window positions + win_remove(wp, NULL); + win_append(lastwin_nofloating(), wp); + } + wp->w_floating = 1; + wp->w_status_height = 0; + wp->w_vsep_width = 0; + win_config_float(wp, width, height, config); + wp->w_pos_changed = true; + redraw_win_later(wp, VALID); + if (new) { + win_enter(wp, false); + } + return wp; +} + +void win_config_float(win_T *wp, int width, int height, + FloatConfig config) +{ + wp->w_height = MAX(height, 1); + wp->w_width = MAX(width, 2); + + if (config.relative == kFloatRelativeCursor) { + config.relative = kFloatRelativeWindow; + config.row += curwin->w_wrow; + config.col += curwin->w_wcol; + config.window = curwin->handle; + } + + wp->w_float_config = config; + + if (!ui_has(kUIMultigrid)) { + wp->w_height = MIN(wp->w_height, Rows-1); + wp->w_width = MIN(wp->w_width, Columns); + } + + win_set_inner_size(wp); + must_redraw = MAX(must_redraw, VALID); + wp->w_pos_changed = true; +} + +static void ui_ext_win_position(win_T *wp) +{ + if (!wp->w_floating) { + ui_call_win_pos(wp->w_grid.handle, wp->handle, wp->w_winrow, + wp->w_wincol, wp->w_width, wp->w_height); + return; + } + const char *const anchor_str[] = { + "NW", + "NE", + "SW", + "SE" + }; + + FloatConfig c = wp->w_float_config; + if (!c.external) { + ScreenGrid *grid = &default_grid; + int row = c.row, col = c.col; + if (c.relative == kFloatRelativeWindow) { + Error dummy = ERROR_INIT; + win_T *win = find_window_by_handle(c.window, &dummy); + if (win) { + grid = &win->w_grid; + screen_adjust_grid(&grid, &row, &col); + } + api_clear_error(&dummy); + } + if (ui_has(kUIMultigrid)) { + String anchor = cstr_to_string(anchor_str[c.anchor]); + ui_call_win_float_pos(wp->w_grid.handle, wp->handle, anchor, grid->handle, + row, col, c.focusable); + } else { + // TODO(bfredl): ideally, compositor should work like any multigrid UI + // and use standard win_pos events. + bool east = c.anchor & kFloatAnchorEast; + bool south = c.anchor & kFloatAnchorSouth; + + row -= (south ? wp->w_height : 0); + col -= (east ? wp->w_width : 0); + row = MAX(MIN(row, Rows-wp->w_height-1), 0); + col = MAX(MIN(col, Columns-wp->w_width), 0); + wp->w_winrow = row; + wp->w_wincol = col; + bool valid = (wp->w_redr_type == 0); + bool on_top = (curwin == wp) || !curwin->w_floating; + ui_comp_put_grid(&wp->w_grid, row, col, wp->w_height, wp->w_width, + valid, on_top); + if (!valid) { + wp->w_grid.valid = false; + redraw_win_later(wp, NOT_VALID); + } + } + } else { + ui_call_win_external_pos(wp->w_grid.handle, wp->handle); + } + +} + + +static bool parse_float_anchor(String anchor, FloatAnchor *out) +{ + if (anchor.size == 0) { + *out = (FloatAnchor)0; + } + char *str = anchor.data; + if (!STRICMP(str, "NW")) { + *out = kFloatAnchorNW; + } else if (!STRICMP(str, "NE")) { + *out = kFloatAnchorNE; + } else if (!STRICMP(str, "SW")) { + *out = kFloatAnchorSW; + } else if (!STRICMP(str, "SE")) { + *out = kFloatAnchorSE; + } else { + return false; + } + return true; +} + +static bool parse_float_relative(String relative, FloatRelative *out) +{ + if (relative.size == 0) { + *out = (FloatRelative)0; + } + char *str = relative.data; + if (!STRICMP(str, "editor")) { + *out = kFloatRelativeEditor; + } else if (!STRICMP(str, "win")) { + *out = kFloatRelativeWindow; + } else if (!STRICMP(str, "cursor")) { + *out = kFloatRelativeCursor; + } else { + return false; + } + return true; +} + +bool parse_float_config(Dictionary config, FloatConfig *out, bool reconf, + Error *err) +{ + bool has_row = false, has_col = false, has_relative = false; + bool has_external = false, has_window = false; + + for (size_t i = 0; i < config.size; i++) { + char *key = config.items[i].key.data; + Object val = config.items[i].value; + if (!strcmp(key, "row")) { + has_row = true; + if (val.type == kObjectTypeInteger) { + out->row = val.data.integer; + } else if (val.type == kObjectTypeFloat) { + out->row = val.data.floating; + } else { + api_set_error(err, kErrorTypeValidation, + "'row' option has to be Integer or Float"); + return false; + } + } else if (!strcmp(key, "col")) { + has_col = true; + if (val.type == kObjectTypeInteger) { + out->col = val.data.integer; + } else if (val.type == kObjectTypeFloat) { + out->col = val.data.floating; + } else { + api_set_error(err, kErrorTypeValidation, + "'col' option has to be Integer or Float"); + return false; + } + } else if (!strcmp(key, "anchor")) { + if (val.type != kObjectTypeString) { + api_set_error(err, kErrorTypeValidation, + "'anchor' option has to be String"); + return false; + } + if (!parse_float_anchor(val.data.string, &out->anchor)) { + api_set_error(err, kErrorTypeValidation, + "Invalid value of 'anchor' option"); + return false; + } + } else if (!strcmp(key, "relative")) { + has_relative = true; + if (val.type != kObjectTypeString) { + api_set_error(err, kErrorTypeValidation, + "'relative' option has to be String"); + return false; + } + if (!parse_float_relative(val.data.string, &out->relative)) { + api_set_error(err, kErrorTypeValidation, + "Invalid value of 'relative' option"); + return false; + } + } else if (!strcmp(key, "win")) { + has_window = true; + if (val.type != kObjectTypeInteger + && val.type != kObjectTypeWindow) { + api_set_error(err, kErrorTypeValidation, + "'win' option has to be Integer or Window"); + return false; + } + out->window = val.data.integer; + } else if (!strcmp(key, "external")) { + if (val.type == kObjectTypeInteger) { + out->external = val.data.integer; + } else if (val.type == kObjectTypeBoolean) { + out->external = val.data.boolean; + } else { + api_set_error(err, kErrorTypeValidation, + "'external' option has to be Boolean"); + return false; + } + has_external = out->external; + } else if (!strcmp(key, "focusable")) { + if (val.type == kObjectTypeInteger) { + out->focusable = val.data.integer; + } else if (val.type == kObjectTypeBoolean) { + out->focusable = val.data.boolean; + } else { + api_set_error(err, kErrorTypeValidation, + "'focusable' option has to be Boolean"); + return false; + } + } else { + api_set_error(err, kErrorTypeValidation, + "Invalid options key '%s'", key); + return false; + } + } + + if (has_window && !(has_relative && out->relative == kFloatRelativeWindow)) { + api_set_error(err, kErrorTypeValidation, + "'win' option is only valid with relative='win'"); + return false; + } + + if ((has_relative && out->relative == kFloatRelativeWindow) + && (!has_window || out->window == 0)) { + out->window = curwin->handle; + } + + if (has_relative && has_external) { + api_set_error(err, kErrorTypeValidation, + "Only one of 'relative' and 'external' should be used"); + return false; + } else if (has_relative) { + out->external = false; + } else if (!reconf && !has_relative && !has_external) { + api_set_error(err, kErrorTypeValidation, + "One of 'relative' and 'external' must be used"); + return false; + } + + if (out->external && !ui_has(kUIMultigrid)) { + api_set_error(err, kErrorTypeValidation, + "UI doesn't support external windows"); + return false; + } + + if (has_relative != has_row || has_row != has_col) { + api_set_error(err, kErrorTypeValidation, "All of 'relative', 'row', and " + "'col' has to be specified at once"); + return false; + } + return true; +} + /* * split the current window, implements CTRL-W s and :split * @@ -566,16 +890,20 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) int wmh1; bool did_set_fraction = false; - if (flags & WSP_TOP) + if (flags & WSP_TOP) { oldwin = firstwin; - else if (flags & WSP_BOT) - oldwin = lastwin; - else + } else if (flags & WSP_BOT || curwin->w_floating) { + // can't split float, use last nonfloating window instead + oldwin = lastwin_nofloating(); + } else { oldwin = curwin; + } - /* add a status line when p_ls == 1 and splitting the first window */ - if (ONE_WINDOW && p_ls == 1 && oldwin->w_status_height == 0) { - if (oldwin->w_height <= p_wmh && new_wp == NULL) { + bool new_in_layout = (new_wp == NULL || new_wp->w_floating); + + // add a status line when p_ls == 1 and splitting the first window + if (one_nonfloat() && p_ls == 1 && oldwin->w_status_height == 0) { + if (oldwin->w_height <= p_wmh && new_in_layout) { EMSG(_(e_noroom)); return FAIL; } @@ -624,7 +952,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) available = oldwin->w_frame->fr_width; needed += minwidth; } - if (available < needed && new_wp == NULL) { + if (available < needed && new_in_layout) { EMSG(_(e_noroom)); return FAIL; } @@ -702,7 +1030,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) available = oldwin->w_frame->fr_height; needed += minheight; } - if (available < needed && new_wp == NULL) { + if (available < needed && new_in_layout) { EMSG(_(e_noroom)); return FAIL; } @@ -790,6 +1118,9 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) /* make the contents of the new window the same as the current one */ win_init(wp, curwin, flags); + } else if (wp->w_floating) { + new_frame(wp); + wp->w_floating = false; } /* @@ -1192,7 +1523,13 @@ static void win_exchange(long Prenum) win_T *wp2; int temp; - if (ONE_WINDOW) { /* just one window */ + if (curwin->w_floating) { + EMSG(e_floatexchange); + return; + } + + if (firstwin == curwin && lastwin_nofloating() == curwin) { + // just one window beep_flush(); return; } @@ -1282,7 +1619,13 @@ static void win_rotate(int upwards, int count) frame_T *frp; int n; - if (ONE_WINDOW) { /* nothing to do */ + if (curwin->w_floating) { + EMSG(e_floatexchange); + return; + } + + if (firstwin == curwin && lastwin_nofloating() == curwin) { + // nothing to do beep_flush(); return; } @@ -1355,16 +1698,27 @@ static void win_rotate(int upwards, int count) */ static void win_totop(int size, int flags) { - int dir; + int dir = 0; int height = curwin->w_height; - if (ONE_WINDOW) { + if (firstwin == curwin && lastwin_nofloating() == curwin) { beep_flush(); return; } - /* Remove the window and frame from the tree of frames. */ - (void)winframe_remove(curwin, &dir, NULL); + if (curwin->w_floating) { + ui_comp_remove_grid(&curwin->w_grid); + if (ui_has(kUIMultigrid)) { + curwin->w_pos_changed = true; + } else { + // No longer a float, a non-multigrid UI shouldn't draw it as such + ui_call_win_hide(curwin->w_grid.handle); + win_free_grid(curwin, false); + } + } else { + // Remove the window and frame from the tree of frames. + (void)winframe_remove(curwin, &dir, NULL); + } win_remove(curwin, NULL); last_status(FALSE); /* may need to remove last status line */ (void)win_comp_pos(); /* recompute window positions */ @@ -1795,13 +2149,13 @@ static bool last_window(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT } /// Check that current tab page contains no more then one window other than -/// "aucmd_win". +/// "aucmd_win". Only counts floating window if it is current. bool one_window(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { bool seen_one = false; FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp != aucmd_win) { + if (wp != aucmd_win && (!wp->w_floating || wp == curwin)) { if (seen_one) { return false; } @@ -1811,6 +2165,20 @@ bool one_window(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT return true; } +/// Like ONE_WINDOW but only considers non-floating windows +bool one_nonfloat(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + return firstwin->w_next == NULL || firstwin->w_next->w_floating; +} + +/// if wp is the last non-floating window +/// +/// always false for a floating window +bool last_nonfloat(win_T *wp) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + return firstwin == wp && !(wp->w_next && !wp->w_floating); +} + /// Close the possibly last window in a tab page. /// /// @param win window to close @@ -1882,9 +2250,9 @@ int win_close(win_T *win, bool free_buf) int dir; bool help_window = false; tabpage_T *prev_curtab = curtab; - frame_T *win_frame = win->w_frame->fr_parent; + frame_T *win_frame = win->w_floating ? NULL : win->w_frame->fr_parent; - if (last_window()) { + if (last_window() && !win->w_floating) { EMSG(_("E444: Cannot close last window")); return FAIL; } @@ -1897,10 +2265,17 @@ int win_close(win_T *win, bool free_buf) EMSG(_("E813: Cannot close autocmd window")); return FAIL; } - if ((firstwin == aucmd_win || lastwin == aucmd_win) && one_window()) { + if ((firstwin == aucmd_win || lastwin_nofloating() == aucmd_win) + && one_window()) { EMSG(_("E814: Cannot close window, only autocmd window would remain")); return FAIL; } + if ((firstwin == win && lastwin_nofloating() == win) + && lastwin->w_floating) { + // TODO(bfredl): we might close the float also instead + EMSG(e_floatonly); + return FAIL; + } /* When closing the last window in a tab page first go to another tab page * and then close the window and the tab page to avoid that curwin and @@ -1921,7 +2296,15 @@ int win_close(win_T *win, bool free_buf) * Guess which window is going to be the new current window. * This may change because of the autocommands (sigh). */ - wp = frame2win(win_altframe(win, NULL)); + if (!win->w_floating) { + wp = frame2win(win_altframe(win, NULL)); + } else { + if (win_valid(prevwin)) { + wp = prevwin; + } else { + wp = curtab->tp_firstwin; + } + } /* * Be careful: If autocommands delete the window or cause this window @@ -1949,6 +2332,27 @@ int win_close(win_T *win, bool free_buf) return FAIL; } + bool was_floating = win->w_floating; + if (ui_has(kUIMultigrid)) { + ui_call_win_close(win->w_grid.handle); + } + + if (win->w_floating) { + ui_comp_remove_grid(&win->w_grid); + if (win->w_float_config.external) { + for (tabpage_T *tp = first_tabpage; tp != NULL; tp = tp->tp_next) { + if (tp == curtab) { + continue; + } + if (tp->tp_curwin == win) { + // NB: an autocmd can still abort the closing of this window, + // bur carring out this change anyway shouldn't be a catastrophe. + tp->tp_curwin = tp->tp_firstwin; + } + } + } + } + /* Free independent synblock before the buffer is freed. */ if (win->w_buffer != NULL) @@ -1975,7 +2379,8 @@ int win_close(win_T *win, bool 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))) { + || close_last_window_tabpage(win, free_buf, prev_curtab)) + && !win->w_floating) { // Autocommands have closed all windows, quit now. Restore // curwin->w_buffer, otherwise writing ShaDa file may fail. if (curwin->w_buffer == NULL) { @@ -1992,7 +2397,7 @@ int win_close(win_T *win, bool free_buf) } // 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() + if (!win_valid(win) || (!win->w_floating && last_window()) || close_last_window_tabpage(win, free_buf, prev_curtab)) { return FAIL; } @@ -2041,12 +2446,15 @@ int win_close(win_T *win, bool free_buf) // using the window. check_cursor(); } - 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 (!was_floating) { + 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) { @@ -2167,10 +2575,18 @@ win_free_mem ( frame_T *frp; win_T *wp; - /* Remove the window and its frame from the tree of frames. */ - frp = win->w_frame; - wp = winframe_remove(win, dirp, tp); - xfree(frp); + if (!win->w_floating) { + // Remove the window and its frame from the tree of frames. + frp = win->w_frame; + wp = winframe_remove(win, dirp, tp); + xfree(frp); + } else { + if (win_valid(prevwin)) { + wp = prevwin; + } else { + wp = curtab->tp_firstwin; + } + } win_free(win, tp); /* When deleting the current window of another tab page select a new @@ -2189,6 +2605,12 @@ void win_free_all(void) while (first_tabpage->tp_next != NULL) tabpage_close(TRUE); + while (lastwin != NULL && lastwin->w_floating) { + win_T *wp = lastwin; + win_remove(lastwin, NULL); + (void)win_free_mem(wp, &dummy, NULL); + } + if (aucmd_win != NULL) { (void)win_free_mem(aucmd_win, &dummy, NULL); aucmd_win = NULL; @@ -2870,11 +3292,19 @@ close_others ( win_T *nextwp; int r; - if (one_window()) { + if (curwin->w_floating) { + if (message && !autocmd_busy) { + EMSG(e_floatonly); + } + return; + } + + if (one_window() && !lastwin->w_floating) { if (message && !autocmd_busy - ) + ) { MSG(_(m_onlyone)); + } return; } @@ -3116,9 +3546,7 @@ int win_new_tabpage(int after, char_u *filename) redraw_all_later(NOT_VALID); - if (ui_has(kUIMultigrid)) { - tabpage_check_windows(tp); - } + tabpage_check_windows(tp); apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf); apply_autocmds(EVENT_WINENTER, NULL, NULL, false, curbuf); @@ -3317,7 +3745,7 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_au lastwin = tp->tp_lastwin; topframe = tp->tp_topframe; - if (old_curtab != curtab && ui_has(kUIMultigrid)) { + if (old_curtab != curtab) { tabpage_check_windows(old_curtab); } @@ -3355,16 +3783,31 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_au redraw_all_later(NOT_VALID); } -/// called when changing current tabpage from old_curtab to curtab +/// tells external UI that windows and inline floats in old_curtab are invisible +/// and that floats in curtab is now visible. +/// +/// External floats are considered independent of tabpages. This is +/// implemented by always moving them 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; + if (wp->w_floating) { + if (wp->w_float_config.external) { + win_remove(wp, old_curtab); + win_append(lastwin_nofloating(), wp); + } else { + ui_comp_remove_grid(&wp->w_grid); + } + } wp->w_pos_changed = true; } for (win_T *wp = firstwin; wp; wp = wp->w_next) { + if (wp->w_floating && !wp->w_float_config.external) { + win_config_float(wp, wp->w_width, wp->w_height, wp->w_float_config); + } wp->w_pos_changed = true; } } @@ -3577,6 +4020,12 @@ win_goto_ver ( frame_T *foundfr; foundfr = curwin->w_frame; + + if (curwin->w_floating) { + win_goto(prevwin); + return; + } + while (count--) { /* * First go upwards in the tree of frames until we find an upwards or @@ -3636,6 +4085,12 @@ win_goto_hor ( frame_T *foundfr; foundfr = curwin->w_frame; + + if (curwin->w_floating) { + win_goto(prevwin); + return; + } + while (count--) { /* * First go upwards in the tree of frames until we find a left or @@ -3740,6 +4195,7 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, } curwin = wp; curbuf = wp->w_buffer; + check_cursor(); if (!virtual_active()) curwin->w_cursor.coladd = 0; @@ -3809,9 +4265,10 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, else if (curwin->w_height == 0) win_setheight(1); - /* set window width to desired minimal value */ - if (curwin->w_width < p_wiw && !curwin->w_p_wfw) + // set window width to desired minimal value + if (curwin->w_width < p_wiw && !curwin->w_p_wfw && !wp->w_floating) { win_setwidth((int)p_wiw); + } setmouse(); /* in case jumped to/from help buffer */ @@ -3916,6 +4373,7 @@ static win_T *win_alloc(win_T *after, int hidden) new_wp->w_botline = 2; new_wp->w_cursor.lnum = 1; new_wp->w_scbind_pos = 1; + new_wp->w_floating = 0; /* We won't calculate w_fraction until resizing the window */ new_wp->w_fraction = 0; @@ -4204,6 +4662,13 @@ int win_comp_pos(void) int col = 0; frame_comp_pos(topframe, &row, &col); + + // Too often, but when we support anchoring floats to split windows, + // this will be needed + for (win_T *wp = lastwin; wp && wp->w_floating; wp = wp->w_prev) { + win_config_float(wp, wp->w_width, wp->w_height, wp->w_float_config); + } + return row; } @@ -4263,8 +4728,6 @@ void win_setheight(int height) */ void win_setheight_win(int height, win_T *win) { - int row; - if (win == curwin) { /* Always keep current window at least one line high, even when * 'winminheight' is zero. */ @@ -4274,21 +4737,28 @@ void win_setheight_win(int height, win_T *win) height = 1; } - frame_setheight(win->w_frame, height + win->w_status_height); + if (win->w_floating) { + if (win->w_float_config.external) { + win_config_float(win, win->w_width, height, win->w_float_config); + } else { + beep_flush(); + return; + } + } else { + frame_setheight(win->w_frame, height + win->w_status_height); - /* recompute the window positions */ - row = win_comp_pos(); + // recompute the window positions + int row = win_comp_pos(); - /* - * 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) { - grid_fill(&default_grid, row, cmdline_row, 0, (int)Columns, ' ', ' ', 0); + // 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) { + grid_fill(&default_grid, row, cmdline_row, 0, (int)Columns, ' ', ' ', 0); + } + cmdline_row = row; + msg_row = row; + msg_col = 0; } - cmdline_row = row; - msg_row = row; - msg_col = 0; redraw_all_later(NOT_VALID); } @@ -4358,14 +4828,16 @@ static void frame_setheight(frame_T *curfrp, int height) if (frp != curfrp) room -= frame_minheight(frp, NULL); } - if (curfrp->fr_width != Columns) + if (curfrp->fr_width != Columns) { room_cmdline = 0; - else { - room_cmdline = Rows - p_ch - (lastwin->w_winrow - + lastwin->w_height + - lastwin->w_status_height); - if (room_cmdline < 0) + } else { + win_T *wp = lastwin_nofloating(); + room_cmdline = Rows - p_ch - (wp->w_winrow + + wp->w_height + + wp->w_status_height); + if (room_cmdline < 0) { room_cmdline = 0; + } } if (height <= room + room_cmdline) { @@ -4470,11 +4942,19 @@ void win_setwidth_win(int width, win_T *wp) if (width == 0) width = 1; } + if (wp->w_floating) { + if (wp->w_float_config.external) { + win_config_float(wp, width, wp->w_height, wp->w_float_config); + } else { + beep_flush(); + return; + } + } else { + frame_setwidth(wp->w_frame, width + wp->w_vsep_width); - frame_setwidth(wp->w_frame, width + wp->w_vsep_width); - - /* recompute the window positions */ - (void)win_comp_pos(); + // recompute the window positions + (void)win_comp_pos(); + } redraw_all_later(NOT_VALID); } @@ -5015,6 +5495,7 @@ void win_set_inner_size(win_T *wp) if (!exiting) { scroll_to_fraction(wp, prev_height); } + redraw_win_later(wp, NOT_VALID); // SOME_VALID?? } if (width != wp->w_width_inner) { @@ -5026,6 +5507,7 @@ void win_set_inner_size(win_T *wp) update_topline(); curs_columns(true); // validate w_wrow } + redraw_win_later(wp, NOT_VALID); } if (wp->w_buffer->terminal) { @@ -5039,9 +5521,7 @@ void win_new_width(win_T *wp, int width) wp->w_width = width; win_set_inner_size(wp); - redraw_win_later(wp, NOT_VALID); - wp->w_redr_status = TRUE; - + wp->w_redr_status = true; wp->w_pos_changed = true; } @@ -5379,7 +5859,7 @@ int min_rows(void) /// Check that there is only one window (and only one tab page), not counting a /// help or preview window, unless it is the current window. Does not count -/// "aucmd_win". +/// "aucmd_win". Does not count floats unless it is current. bool only_one_window(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { // If there is another tab page there always is another window. @@ -5390,7 +5870,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 - && (!((bt_help(wp->w_buffer) && !bt_help(curbuf)) + && (!((bt_help(wp->w_buffer) && !bt_help(curbuf)) || wp->w_floating || wp->w_p_pvw) || wp == curwin) && wp != aucmd_win) { count++; } @@ -6080,22 +6560,24 @@ void win_findbuf(typval_T *argvars, list_T *list) } } -void win_ui_flush(void) +void win_ui_flush_positions(void) { - if (!ui_has(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); + ui_ext_win_position(wp); } else { ui_call_win_hide(wp->w_grid.handle); } wp->w_pos_changed = false; } } +} +win_T *lastwin_nofloating(void) { + win_T *res = lastwin; + while (res->w_floating) { + res = res->w_prev; + } + return res; } |