aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphael <glephunter@gmail.com>2023-11-16 09:54:47 +0800
committerGitHub <noreply@github.com>2023-11-16 09:54:47 +0800
commit326d46f690b383846f136f2a25523cffe2882f27 (patch)
treeb72ea5874bc2e8e569276ce80e18ff4b21fe8b74
parent405bad5e085fb359879646b6fd6fbcddae83eac5 (diff)
downloadrneovim-326d46f690b383846f136f2a25523cffe2882f27.tar.gz
rneovim-326d46f690b383846f136f2a25523cffe2882f27.tar.bz2
rneovim-326d46f690b383846f136f2a25523cffe2882f27.zip
refactor: move some functions to winfloat.c (#26020)
-rw-r--r--src/nvim/api/win_config.c1
-rw-r--r--src/nvim/autocmd.c1
-rw-r--r--src/nvim/buffer.c1
-rw-r--r--src/nvim/eval/window.c3
-rw-r--r--src/nvim/ex_docmd.c1
-rw-r--r--src/nvim/move.c1
-rw-r--r--src/nvim/ui.c1
-rw-r--r--src/nvim/window.c264
-rw-r--r--src/nvim/winfloat.c279
-rw-r--r--src/nvim/winfloat.h7
10 files changed, 297 insertions, 262 deletions
diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c
index 83c8ba832c..0e6daf6b95 100644
--- a/src/nvim/api/win_config.c
+++ b/src/nvim/api/win_config.c
@@ -25,6 +25,7 @@
#include "nvim/syntax.h"
#include "nvim/ui.h"
#include "nvim/window.h"
+#include "nvim/winfloat.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/win_config.c.generated.h"
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 80573696d4..65e902ed4b 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -48,6 +48,7 @@
#include "nvim/ui_compositor.h"
#include "nvim/vim.h"
#include "nvim/window.h"
+#include "nvim/winfloat.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "auevents_name_map.generated.h"
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 230cd4cef7..262163f248 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -101,6 +101,7 @@
#include "nvim/version.h"
#include "nvim/vim.h"
#include "nvim/window.h"
+#include "nvim/winfloat.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "buffer.c.generated.h"
diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c
index c0607a4a34..bcc29dfeed 100644
--- a/src/nvim/eval/window.c
+++ b/src/nvim/eval/window.c
@@ -26,6 +26,7 @@
#include "nvim/types.h"
#include "nvim/vim.h"
#include "nvim/window.h"
+#include "nvim/winfloat.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/window.c.generated.h"
@@ -635,7 +636,7 @@ void f_win_splitmove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (wp == NULL || targetwin == NULL || wp == targetwin
|| !win_valid(wp) || !win_valid(targetwin)
- || win_valid_floating(wp) || win_valid_floating(targetwin)) {
+ || win_float_valid(wp) || win_float_valid(targetwin)) {
emsg(_(e_invalwindow));
rettv->vval.v_number = -1;
return;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 13043930b2..fee712bbed 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -83,6 +83,7 @@
#include "nvim/usercmd.h"
#include "nvim/vim.h"
#include "nvim/window.h"
+#include "nvim/winfloat.h"
static const char e_ambiguous_use_of_user_defined_command[]
= N_("E464: Ambiguous use of user-defined command");
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 7cc368a36b..bf5aba2f7b 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -45,6 +45,7 @@
#include "nvim/types.h"
#include "nvim/vim.h"
#include "nvim/window.h"
+#include "nvim/winfloat.h"
typedef struct {
linenr_T lnum; // line number
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 3e5bfba315..a2791be583 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -35,6 +35,7 @@
#include "nvim/ui_compositor.h"
#include "nvim/vim.h"
#include "nvim/window.h"
+#include "nvim/winfloat.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ui.c.generated.h"
diff --git a/src/nvim/window.c b/src/nvim/window.c
index a49dcd95bc..7742313e84 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -75,6 +75,7 @@
#include "nvim/undo.h"
#include "nvim/vim.h"
#include "nvim/window.h"
+#include "nvim/winfloat.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "window.c.generated.h"
@@ -734,204 +735,6 @@ void win_set_buf(win_T *win, buf_T *buf, bool noautocmd, Error *err)
RedrawingDisabled--;
}
-/// Create a new float.
-///
-/// @param wp if NULL, allocate a new window, otherwise turn existing window into a float.
-/// It must then already belong to the current tabpage!
-/// @param last make the window the last one in the window list.
-/// Only used when allocating the autocommand window.
-/// @param config must already have been validated!
-win_T *win_new_float(win_T *wp, bool last, FloatConfig fconfig, Error *err)
-{
- if (wp == NULL) {
- wp = win_alloc(last ? lastwin : lastwin_nofloating(), false);
- win_init(wp, curwin, 0);
- } else {
- assert(!last);
- 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_CLEAR(wp->w_frame);
- (void)win_comp_pos(); // recompute window positions
- win_remove(wp, NULL);
- win_append(lastwin_nofloating(), wp);
- }
- wp->w_floating = true;
- wp->w_status_height = 0;
- wp->w_winbar_height = 0;
- wp->w_hsep_height = 0;
- wp->w_vsep_width = 0;
-
- win_config_float(wp, fconfig);
- win_set_inner_size(wp, true);
- wp->w_pos_changed = true;
- redraw_later(wp, UPD_VALID);
- return wp;
-}
-
-void win_set_minimal_style(win_T *wp)
-{
- wp->w_p_nu = false;
- wp->w_p_rnu = false;
- wp->w_p_cul = false;
- wp->w_p_cuc = false;
- wp->w_p_spell = false;
- wp->w_p_list = false;
-
- // Hide EOB region: use " " fillchar and cleared highlighting
- if (wp->w_p_fcs_chars.eob != ' ') {
- char *old = wp->w_p_fcs;
- wp->w_p_fcs = ((*old == NUL)
- ? xstrdup("eob: ")
- : concat_str(old, ",eob: "));
- free_string_option(old);
- }
-
- // TODO(bfredl): this could use a highlight namespace directly,
- // and avoid peculiarities around window options
- char *old = wp->w_p_winhl;
- wp->w_p_winhl = ((*old == NUL)
- ? xstrdup("EndOfBuffer:")
- : concat_str(old, ",EndOfBuffer:"));
- free_string_option(old);
- parse_winhl_opt(wp);
-
- // signcolumn: use 'auto'
- if (wp->w_p_scl[0] != 'a' || strlen(wp->w_p_scl) >= 8) {
- free_string_option(wp->w_p_scl);
- wp->w_p_scl = xstrdup("auto");
- }
-
- // foldcolumn: use '0'
- if (wp->w_p_fdc[0] != '0') {
- free_string_option(wp->w_p_fdc);
- wp->w_p_fdc = xstrdup("0");
- }
-
- // colorcolumn: cleared
- if (wp->w_p_cc != NULL && *wp->w_p_cc != NUL) {
- free_string_option(wp->w_p_cc);
- wp->w_p_cc = xstrdup("");
- }
-
- // statuscolumn: cleared
- if (wp->w_p_stc != NULL && *wp->w_p_stc != NUL) {
- free_string_option(wp->w_p_stc);
- wp->w_p_stc = xstrdup("");
- }
-}
-
-void win_config_float(win_T *wp, FloatConfig fconfig)
-{
- wp->w_width = MAX(fconfig.width, 1);
- wp->w_height = MAX(fconfig.height, 1);
-
- if (fconfig.relative == kFloatRelativeCursor) {
- fconfig.relative = kFloatRelativeWindow;
- fconfig.row += curwin->w_wrow;
- fconfig.col += curwin->w_wcol;
- fconfig.window = curwin->handle;
- } else if (fconfig.relative == kFloatRelativeMouse) {
- int row = mouse_row, col = mouse_col, grid = mouse_grid;
- win_T *mouse_win = mouse_find_win(&grid, &row, &col);
- if (mouse_win != NULL) {
- fconfig.relative = kFloatRelativeWindow;
- fconfig.row += row;
- fconfig.col += col;
- fconfig.window = mouse_win->handle;
- }
- }
-
- bool change_external = fconfig.external != wp->w_float_config.external;
- bool change_border = (fconfig.border != wp->w_float_config.border
- || memcmp(fconfig.border_hl_ids,
- wp->w_float_config.border_hl_ids,
- sizeof fconfig.border_hl_ids) != 0);
-
- wp->w_float_config = fconfig;
-
- bool has_border = wp->w_floating && wp->w_float_config.border;
- for (int i = 0; i < 4; i++) {
- int new_adj = has_border && wp->w_float_config.border_chars[2 * i + 1][0];
- if (new_adj != wp->w_border_adj[i]) {
- change_border = true;
- wp->w_border_adj[i] = new_adj;
- }
- }
-
- if (!ui_has(kUIMultigrid)) {
- wp->w_height = MIN(wp->w_height, Rows - win_border_height(wp));
- wp->w_width = MIN(wp->w_width, Columns - win_border_width(wp));
- }
-
- win_set_inner_size(wp, true);
- must_redraw = MAX(must_redraw, UPD_VALID);
-
- wp->w_pos_changed = true;
- if (change_external || change_border) {
- wp->w_hl_needs_update = true;
- redraw_later(wp, UPD_NOT_VALID);
- }
-
- // compute initial position
- if (wp->w_float_config.relative == kFloatRelativeWindow) {
- int row = (int)wp->w_float_config.row;
- int col = (int)wp->w_float_config.col;
- Error dummy = ERROR_INIT;
- win_T *parent = find_window_by_handle(wp->w_float_config.window, &dummy);
- if (parent) {
- row += parent->w_winrow;
- col += parent->w_wincol;
- ScreenGrid *grid = &parent->w_grid;
- int row_off = 0, col_off = 0;
- grid_adjust(&grid, &row_off, &col_off);
- row += row_off;
- col += col_off;
- if (wp->w_float_config.bufpos.lnum >= 0) {
- pos_T pos = { wp->w_float_config.bufpos.lnum + 1,
- wp->w_float_config.bufpos.col, 0 };
- int trow, tcol, tcolc, tcole;
- textpos2screenpos(parent, &pos, &trow, &tcol, &tcolc, &tcole, true);
- row += trow - 1;
- col += tcol - 1;
- }
- }
- api_clear_error(&dummy);
- wp->w_winrow = row;
- wp->w_wincol = col;
- } else {
- wp->w_winrow = (int)fconfig.row;
- wp->w_wincol = (int)fconfig.col;
- }
-
- // changing border style while keeping border only requires redrawing border
- if (fconfig.border) {
- wp->w_redr_border = true;
- redraw_later(wp, UPD_VALID);
- }
-}
-
-void win_check_anchored_floats(win_T *win)
-{
- for (win_T *wp = lastwin; wp && wp->w_floating; wp = wp->w_prev) {
- // float might be anchored to moved window
- if (wp->w_float_config.relative == kFloatRelativeWindow
- && wp->w_float_config.window == win->handle) {
- wp->w_pos_changed = true;
- }
- }
-}
-
/// Return the number of fold columns to display
int win_fdccol_count(win_T *wp)
{
@@ -1659,7 +1462,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
// The windows will both edit the same buffer.
// WSP_NEWLOC may be specified in flags to prevent the location list from
// being copied.
-static void win_init(win_T *newp, win_T *oldp, int flags)
+void win_init(win_T *newp, win_T *oldp, int flags)
{
newp->w_buffer = oldp->w_buffer;
newp->w_s = &(oldp->w_buffer->b_s);
@@ -1736,24 +1539,6 @@ static void win_init_some(win_T *newp, win_T *oldp)
win_copy_options(oldp, newp);
}
-/// Return true if "win" is floating window in the current tab page.
-///
-/// @param win window to check
-bool win_valid_floating(const win_T *win)
- FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
-{
- if (win == NULL) {
- return false;
- }
-
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp == win) {
- return wp->w_floating;
- }
- }
- return false;
-}
-
/// Check if "win" is a pointer to an existing window in the current tabpage.
///
/// @param win window to check
@@ -5112,7 +4897,7 @@ win_T *buf_jump_open_tab(buf_T *buf)
/// @param hidden allocate a window structure and link it in the window if
// false.
-static win_T *win_alloc(win_T *after, bool hidden)
+win_T *win_alloc(win_T *after, bool hidden)
{
static int last_win_id = LOWEST_WIN_ID - 1;
@@ -5790,13 +5575,6 @@ int win_comp_pos(void)
return row + global_stl_height();
}
-void win_reconfig_floats(void)
-{
- for (win_T *wp = lastwin; wp && wp->w_floating; wp = wp->w_prev) {
- win_config_float(wp, wp->w_float_config);
- }
-}
-
// Update the position of the windows in frame "topfrp", using the width and
// height of the frames.
// "*row" and "*col" are the top-left position of the frame. They are updated
@@ -6754,16 +6532,6 @@ void win_set_inner_size(win_T *wp, bool valid_cursor)
wp->w_redr_status = true;
}
-static int win_border_height(win_T *wp)
-{
- return wp->w_border_adj[0] + wp->w_border_adj[2];
-}
-
-static int win_border_width(win_T *wp)
-{
- return wp->w_border_adj[1] + wp->w_border_adj[3];
-}
-
/// Set the width of a window.
void win_new_width(win_T *wp, int width)
{
@@ -7654,29 +7422,3 @@ win_T *lastwin_nofloating(void)
}
return res;
}
-
-static int float_zindex_cmp(const void *a, const void *b)
-{
- return (*(win_T **)b)->w_float_config.zindex - (*(win_T **)a)->w_float_config.zindex;
-}
-
-void win_float_remove(bool bang, int count)
-{
- kvec_t(win_T *) float_win_arr = KV_INITIAL_VALUE;
- for (win_T *wp = lastwin; wp && wp->w_floating; wp = wp->w_prev) {
- kv_push(float_win_arr, wp);
- }
- qsort(float_win_arr.items, float_win_arr.size, sizeof(win_T *), float_zindex_cmp);
- for (size_t i = 0; i < float_win_arr.size; i++) {
- if (win_close(float_win_arr.items[i], false, false) == FAIL) {
- break;
- }
- if (!bang) {
- count--;
- if (count == 0) {
- break;
- }
- }
- }
- kv_destroy(float_win_arr);
-}
diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c
new file mode 100644
index 0000000000..d502056699
--- /dev/null
+++ b/src/nvim/winfloat.c
@@ -0,0 +1,279 @@
+#include <stdbool.h>
+
+#include "klib/kvec.h"
+#include "nvim/api/private/helpers.h"
+#include "nvim/buffer_defs.h"
+#include "nvim/drawscreen.h"
+#include "nvim/globals.h"
+#include "nvim/grid.h"
+#include "nvim/mouse.h"
+#include "nvim/move.h"
+#include "nvim/option.h"
+#include "nvim/optionstr.h"
+#include "nvim/ui.h"
+#include "nvim/vim.h"
+#include "nvim/window.h"
+#include "nvim/winfloat.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "winfloat.c.generated.h"
+#endif
+
+/// Create a new float.
+///
+/// @param wp if NULL, allocate a new window, otherwise turn existing window into a float.
+/// It must then already belong to the current tabpage!
+/// @param last make the window the last one in the window list.
+/// Only used when allocating the autocommand window.
+/// @param config must already have been validated!
+win_T *win_new_float(win_T *wp, bool last, FloatConfig fconfig, Error *err)
+{
+ if (wp == NULL) {
+ wp = win_alloc(last ? lastwin : lastwin_nofloating(), false);
+ win_init(wp, curwin, 0);
+ } else {
+ assert(!last);
+ 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_CLEAR(wp->w_frame);
+ (void)win_comp_pos(); // recompute window positions
+ win_remove(wp, NULL);
+ win_append(lastwin_nofloating(), wp);
+ }
+ wp->w_floating = true;
+ wp->w_status_height = 0;
+ wp->w_winbar_height = 0;
+ wp->w_hsep_height = 0;
+ wp->w_vsep_width = 0;
+
+ win_config_float(wp, fconfig);
+ win_set_inner_size(wp, true);
+ wp->w_pos_changed = true;
+ redraw_later(wp, UPD_VALID);
+ return wp;
+}
+
+void win_set_minimal_style(win_T *wp)
+{
+ wp->w_p_nu = false;
+ wp->w_p_rnu = false;
+ wp->w_p_cul = false;
+ wp->w_p_cuc = false;
+ wp->w_p_spell = false;
+ wp->w_p_list = false;
+
+ // Hide EOB region: use " " fillchar and cleared highlighting
+ if (wp->w_p_fcs_chars.eob != ' ') {
+ char *old = wp->w_p_fcs;
+ wp->w_p_fcs = ((*old == NUL)
+ ? xstrdup("eob: ")
+ : concat_str(old, ",eob: "));
+ free_string_option(old);
+ }
+
+ // TODO(bfredl): this could use a highlight namespace directly,
+ // and avoid peculiarities around window options
+ char *old = wp->w_p_winhl;
+ wp->w_p_winhl = ((*old == NUL)
+ ? xstrdup("EndOfBuffer:")
+ : concat_str(old, ",EndOfBuffer:"));
+ free_string_option(old);
+ parse_winhl_opt(wp);
+
+ // signcolumn: use 'auto'
+ if (wp->w_p_scl[0] != 'a' || strlen(wp->w_p_scl) >= 8) {
+ free_string_option(wp->w_p_scl);
+ wp->w_p_scl = xstrdup("auto");
+ }
+
+ // foldcolumn: use '0'
+ if (wp->w_p_fdc[0] != '0') {
+ free_string_option(wp->w_p_fdc);
+ wp->w_p_fdc = xstrdup("0");
+ }
+
+ // colorcolumn: cleared
+ if (wp->w_p_cc != NULL && *wp->w_p_cc != NUL) {
+ free_string_option(wp->w_p_cc);
+ wp->w_p_cc = xstrdup("");
+ }
+
+ // statuscolumn: cleared
+ if (wp->w_p_stc != NULL && *wp->w_p_stc != NUL) {
+ free_string_option(wp->w_p_stc);
+ wp->w_p_stc = xstrdup("");
+ }
+}
+
+int win_border_height(win_T *wp)
+{
+ return wp->w_border_adj[0] + wp->w_border_adj[2];
+}
+
+int win_border_width(win_T *wp)
+{
+ return wp->w_border_adj[1] + wp->w_border_adj[3];
+}
+
+void win_config_float(win_T *wp, FloatConfig fconfig)
+{
+ wp->w_width = MAX(fconfig.width, 1);
+ wp->w_height = MAX(fconfig.height, 1);
+
+ if (fconfig.relative == kFloatRelativeCursor) {
+ fconfig.relative = kFloatRelativeWindow;
+ fconfig.row += curwin->w_wrow;
+ fconfig.col += curwin->w_wcol;
+ fconfig.window = curwin->handle;
+ } else if (fconfig.relative == kFloatRelativeMouse) {
+ int row = mouse_row, col = mouse_col, grid = mouse_grid;
+ win_T *mouse_win = mouse_find_win(&grid, &row, &col);
+ if (mouse_win != NULL) {
+ fconfig.relative = kFloatRelativeWindow;
+ fconfig.row += row;
+ fconfig.col += col;
+ fconfig.window = mouse_win->handle;
+ }
+ }
+
+ bool change_external = fconfig.external != wp->w_float_config.external;
+ bool change_border = (fconfig.border != wp->w_float_config.border
+ || memcmp(fconfig.border_hl_ids,
+ wp->w_float_config.border_hl_ids,
+ sizeof fconfig.border_hl_ids) != 0);
+
+ wp->w_float_config = fconfig;
+
+ bool has_border = wp->w_floating && wp->w_float_config.border;
+ for (int i = 0; i < 4; i++) {
+ int new_adj = has_border && wp->w_float_config.border_chars[2 * i + 1][0];
+ if (new_adj != wp->w_border_adj[i]) {
+ change_border = true;
+ wp->w_border_adj[i] = new_adj;
+ }
+ }
+
+ if (!ui_has(kUIMultigrid)) {
+ wp->w_height = MIN(wp->w_height, Rows - win_border_height(wp));
+ wp->w_width = MIN(wp->w_width, Columns - win_border_width(wp));
+ }
+
+ win_set_inner_size(wp, true);
+ must_redraw = MAX(must_redraw, UPD_VALID);
+
+ wp->w_pos_changed = true;
+ if (change_external || change_border) {
+ wp->w_hl_needs_update = true;
+ redraw_later(wp, UPD_NOT_VALID);
+ }
+
+ // compute initial position
+ if (wp->w_float_config.relative == kFloatRelativeWindow) {
+ int row = (int)wp->w_float_config.row;
+ int col = (int)wp->w_float_config.col;
+ Error dummy = ERROR_INIT;
+ win_T *parent = find_window_by_handle(wp->w_float_config.window, &dummy);
+ if (parent) {
+ row += parent->w_winrow;
+ col += parent->w_wincol;
+ ScreenGrid *grid = &parent->w_grid;
+ int row_off = 0, col_off = 0;
+ grid_adjust(&grid, &row_off, &col_off);
+ row += row_off;
+ col += col_off;
+ if (wp->w_float_config.bufpos.lnum >= 0) {
+ pos_T pos = { wp->w_float_config.bufpos.lnum + 1,
+ wp->w_float_config.bufpos.col, 0 };
+ int trow, tcol, tcolc, tcole;
+ textpos2screenpos(parent, &pos, &trow, &tcol, &tcolc, &tcole, true);
+ row += trow - 1;
+ col += tcol - 1;
+ }
+ }
+ api_clear_error(&dummy);
+ wp->w_winrow = row;
+ wp->w_wincol = col;
+ } else {
+ wp->w_winrow = (int)fconfig.row;
+ wp->w_wincol = (int)fconfig.col;
+ }
+
+ // changing border style while keeping border only requires redrawing border
+ if (fconfig.border) {
+ wp->w_redr_border = true;
+ redraw_later(wp, UPD_VALID);
+ }
+}
+
+static int float_zindex_cmp(const void *a, const void *b)
+{
+ return (*(win_T **)b)->w_float_config.zindex - (*(win_T **)a)->w_float_config.zindex;
+}
+
+void win_float_remove(bool bang, int count)
+{
+ kvec_t(win_T *) float_win_arr = KV_INITIAL_VALUE;
+ for (win_T *wp = lastwin; wp && wp->w_floating; wp = wp->w_prev) {
+ kv_push(float_win_arr, wp);
+ }
+ qsort(float_win_arr.items, float_win_arr.size, sizeof(win_T *), float_zindex_cmp);
+ for (size_t i = 0; i < float_win_arr.size; i++) {
+ if (win_close(float_win_arr.items[i], false, false) == FAIL) {
+ break;
+ }
+ if (!bang) {
+ count--;
+ if (count == 0) {
+ break;
+ }
+ }
+ }
+ kv_destroy(float_win_arr);
+}
+
+void win_check_anchored_floats(win_T *win)
+{
+ for (win_T *wp = lastwin; wp && wp->w_floating; wp = wp->w_prev) {
+ // float might be anchored to moved window
+ if (wp->w_float_config.relative == kFloatRelativeWindow
+ && wp->w_float_config.window == win->handle) {
+ wp->w_pos_changed = true;
+ }
+ }
+}
+
+void win_reconfig_floats(void)
+{
+ for (win_T *wp = lastwin; wp && wp->w_floating; wp = wp->w_prev) {
+ win_config_float(wp, wp->w_float_config);
+ }
+}
+
+/// Return true if "win" is floating window in the current tab page.
+///
+/// @param win window to check
+bool win_float_valid(const win_T *win)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (win == NULL) {
+ return false;
+ }
+
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if (wp == win) {
+ return wp->w_floating;
+ }
+ }
+ return false;
+}
diff --git a/src/nvim/winfloat.h b/src/nvim/winfloat.h
new file mode 100644
index 0000000000..ba13c39551
--- /dev/null
+++ b/src/nvim/winfloat.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "nvim/buffer_defs.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "winfloat.h.generated.h"
+#endif