refactor: move some functions to winfloat.c (#26020)

This commit is contained in:
Raphael
2023-11-16 09:54:47 +08:00
committed by GitHub
parent 405bad5e08
commit 326d46f690
10 changed files with 297 additions and 262 deletions

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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;

View File

@ -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");

View File

@ -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

View File

@ -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"

View File

@ -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);
}

279
src/nvim/winfloat.c Normal file
View File

@ -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;
}

7
src/nvim/winfloat.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include "nvim/buffer_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "winfloat.h.generated.h"
#endif