aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/winfloat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/winfloat.c')
-rw-r--r--src/nvim/winfloat.c108
1 files changed, 104 insertions, 4 deletions
diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c
index 8fe0315230..e3ca0ff139 100644
--- a/src/nvim/winfloat.c
+++ b/src/nvim/winfloat.c
@@ -6,7 +6,9 @@
#include "klib/kvec.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/api/vim.h"
#include "nvim/ascii_defs.h"
+#include "nvim/autocmd.h"
#include "nvim/buffer_defs.h"
#include "nvim/drawscreen.h"
#include "nvim/globals.h"
@@ -17,6 +19,7 @@
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/option.h"
+#include "nvim/option_defs.h"
#include "nvim/optionstr.h"
#include "nvim/pos_defs.h"
#include "nvim/strings.h"
@@ -41,7 +44,24 @@
win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err)
{
if (wp == NULL) {
- wp = win_alloc(last ? lastwin : lastwin_nofloating(), false);
+ tabpage_T *tp = NULL;
+ win_T *tp_last = last ? lastwin : lastwin_nofloating();
+ if (fconfig.window != 0) {
+ assert(!last);
+ win_T *parent_wp = find_window_by_handle(fconfig.window, err);
+ if (!parent_wp) {
+ return NULL;
+ }
+ tp = win_find_tabpage(parent_wp);
+ if (!tp) {
+ return NULL;
+ }
+ tp_last = tp->tp_lastwin;
+ while (tp_last->w_floating && tp_last->w_prev) {
+ tp_last = tp_last->w_prev;
+ }
+ }
+ wp = win_alloc(tp_last, false);
win_init(wp, curwin, 0);
} else {
assert(!last);
@@ -55,13 +75,26 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err)
api_set_error(err, kErrorTypeException,
"Cannot change window from different tabpage into float");
return NULL;
+ } else if (cmdwin_win != NULL && !cmdwin_win->w_floating) {
+ // cmdwin can't become the only non-float. Check for others.
+ bool other_nonfloat = false;
+ for (win_T *wp2 = firstwin; wp2 != NULL && !wp2->w_floating; wp2 = wp2->w_next) {
+ if (wp2 != wp && wp2 != cmdwin_win) {
+ other_nonfloat = true;
+ break;
+ }
+ }
+ if (!other_nonfloat) {
+ api_set_error(err, kErrorTypeException, "%s", e_cmdwin);
+ return NULL;
+ }
}
int dir;
- winframe_remove(wp, &dir, NULL);
+ winframe_remove(wp, &dir, NULL, NULL);
XFREE_CLEAR(wp->w_frame);
win_comp_pos(); // recompute window positions
win_remove(wp, NULL);
- win_append(lastwin_nofloating(), wp);
+ win_append(lastwin_nofloating(), wp, NULL);
}
wp->w_floating = true;
wp->w_status_height = 0;
@@ -208,7 +241,7 @@ void win_config_float(win_T *wp, WinConfig fconfig)
row += row_off;
col += col_off;
if (wp->w_config.bufpos.lnum >= 0) {
- pos_T pos = { wp->w_config.bufpos.lnum + 1,
+ pos_T pos = { MIN(wp->w_config.bufpos.lnum + 1, parent->w_buffer->b_ml.ml_line_count),
wp->w_config.bufpos.col, 0 };
int trow, tcol, tcolc, tcole;
textpos2screenpos(parent, &pos, &trow, &tcol, &tcolc, &tcole, true);
@@ -306,3 +339,70 @@ win_T *win_float_find_preview(void)
}
return NULL;
}
+
+/// Select an alternative window to `win` (assumed floating) in tabpage `tp`.
+///
+/// Useful for finding a window to switch to if `win` is the current window, but is then closed or
+/// moved to a different tabpage.
+///
+/// @param tp `win`'s original tabpage, or NULL for current.
+win_T *win_float_find_altwin(const win_T *win, const tabpage_T *tp)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ if (tp == NULL) {
+ return (win_valid(prevwin) && prevwin != win) ? prevwin : firstwin;
+ }
+
+ assert(tp != curtab);
+ return (tabpage_win_valid(tp, tp->tp_prevwin) && tp->tp_prevwin != win) ? tp->tp_prevwin
+ : tp->tp_firstwin;
+}
+
+/// create a floating preview window.
+///
+/// @param[in] bool enter floating window.
+/// @param[in] bool create a new buffer for window.
+///
+/// @return win_T
+win_T *win_float_create(bool enter, bool new_buf)
+{
+ WinConfig config = WIN_CONFIG_INIT;
+ config.col = curwin->w_wcol;
+ config.row = curwin->w_wrow;
+ config.relative = kFloatRelativeEditor;
+ config.focusable = false;
+ config.anchor = 0; // NW
+ config.noautocmd = true;
+ config.hide = true;
+ config.style = kWinStyleMinimal;
+ Error err = ERROR_INIT;
+
+ block_autocmds();
+ win_T *wp = win_new_float(NULL, false, config, &err);
+ if (!wp) {
+ unblock_autocmds();
+ return NULL;
+ }
+
+ if (new_buf) {
+ Buffer b = nvim_create_buf(false, true, &err);
+ if (!b) {
+ win_remove(wp, NULL);
+ win_free(wp, NULL);
+ unblock_autocmds();
+ return NULL;
+ }
+ buf_T *buf = find_buffer_by_handle(b, &err);
+ buf->b_p_bl = false; // unlist
+ set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("wipe"), OPT_LOCAL, 0, kOptReqBuf,
+ buf);
+ win_set_buf(wp, buf, &err);
+ }
+ unblock_autocmds();
+ wp->w_p_diff = false;
+ wp->w_float_is_info = true;
+ if (enter) {
+ win_enter(wp, false);
+ }
+ return wp;
+}