diff options
author | Björn Linse <bjorn.linse@gmail.com> | 2021-03-22 23:27:59 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-22 23:27:59 +0100 |
commit | 1df1098b0c54258a41c4f97c9d3131d061a5b206 (patch) | |
tree | 315d116677afd7dfbfbc6858949e66e574c81aee /src | |
parent | 6fef28da58a217a45d2d6e5b68ecfddd1eb84c29 (diff) | |
parent | 243820ebd0d9df7664311c8bf79d879bf23eb742 (diff) | |
download | rneovim-1df1098b0c54258a41c4f97c9d3131d061a5b206.tar.gz rneovim-1df1098b0c54258a41c4f97c9d3131d061a5b206.tar.bz2 rneovim-1df1098b0c54258a41c4f97c9d3131d061a5b206.zip |
Merge pull request #13998 from bfredl/border
floats: add MS-DOS mode (borders)
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/private/helpers.c | 352 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 23 | ||||
-rw-r--r-- | src/nvim/autocmd.c | 8 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 13 | ||||
-rw-r--r-- | src/nvim/edit.c | 2 | ||||
-rw-r--r-- | src/nvim/eval.c | 2 | ||||
-rw-r--r-- | src/nvim/grid_defs.h | 17 | ||||
-rw-r--r-- | src/nvim/highlight.c | 15 | ||||
-rw-r--r-- | src/nvim/highlight_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/mbyte.c | 3 | ||||
-rw-r--r-- | src/nvim/message.c | 2 | ||||
-rw-r--r-- | src/nvim/mouse.c | 14 | ||||
-rw-r--r-- | src/nvim/option.c | 4 | ||||
-rw-r--r-- | src/nvim/popupmnu.c | 2 | ||||
-rw-r--r-- | src/nvim/screen.c | 138 | ||||
-rw-r--r-- | src/nvim/syntax.c | 1 | ||||
-rw-r--r-- | src/nvim/window.c | 311 |
17 files changed, 577 insertions, 332 deletions
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 7cee569989..d2b787a6f5 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1645,6 +1645,20 @@ bool api_object_to_bool(Object obj, const char *what, } } +int object_to_hl_id(Object obj, const char *what, Error *err) +{ + if (obj.type == kObjectTypeString) { + String str = obj.data.string; + return str.size ? syn_check_group((char_u *)str.data, (int)str.size) : 0; + } else if (obj.type == kObjectTypeInteger) { + return (int)obj.data.integer; + } else { + api_set_error(err, kErrorTypeValidation, + "%s is not a valid highlight", what); + return 0; + } +} + HlMessage parse_hl_msg(Array chunks, Error *err) { HlMessage hl_msg = KV_INITIAL_VALUE; @@ -1720,3 +1734,341 @@ DecorProvider *get_provider(NS ns_id, bool force) return item; } + +static bool parse_float_anchor(String anchor, FloatAnchor *out) +{ + if (anchor.size == 0) { + *out = (FloatAnchor)0; + } + char *str = anchor.data; + if (striequal(str, "NW")) { + *out = 0; // NW is the default + } else if (striequal(str, "NE")) { + *out = kFloatAnchorEast; + } else if (striequal(str, "SW")) { + *out = kFloatAnchorSouth; + } else if (striequal(str, "SE")) { + *out = kFloatAnchorSouth | kFloatAnchorEast; + } else { + return false; + } + return true; +} + +static bool parse_float_relative(String relative, FloatRelative *out) +{ + char *str = relative.data; + if (striequal(str, "editor")) { + *out = kFloatRelativeEditor; + } else if (striequal(str, "win")) { + *out = kFloatRelativeWindow; + } else if (striequal(str, "cursor")) { + *out = kFloatRelativeCursor; + } else { + return false; + } + return true; +} + +static bool parse_float_bufpos(Array bufpos, lpos_T *out) +{ + if (bufpos.size != 2 + || bufpos.items[0].type != kObjectTypeInteger + || bufpos.items[1].type != kObjectTypeInteger) { + return false; + } + out->lnum = bufpos.items[0].data.integer; + out->col = (colnr_T)bufpos.items[1].data.integer; + return true; +} + +static void parse_border_style(Object style, FloatConfig *fconfig, Error *err) +{ + struct { + const char *name; + schar_T chars[8]; + } defaults[] = { + { "double", { "╔", "═", "╗", "║", "╝", "═", "╚", "║" } }, + { "single", { "┌", "─", "┐", "│", "┘", "─", "└", "│" } }, + { NULL, { { NUL } } }, + }; + + schar_T *chars = fconfig->border_chars; + int *hl_ids = fconfig->border_hl_ids; + + fconfig->border = true; + + if (style.type == kObjectTypeArray) { + Array arr = style.data.array; + size_t size = arr.size; + if (!size || size > 8 || (size & (size-1))) { + api_set_error(err, kErrorTypeValidation, + "invalid number of border chars"); + return; + } + for (size_t i = 0; i < size; i++) { + Object iytem = arr.items[i]; + String string = NULL_STRING; + int hl_id = 0; + if (iytem.type == kObjectTypeArray) { + Array iarr = iytem.data.array; + if (!iarr.size || iarr.size > 2) { + api_set_error(err, kErrorTypeValidation, "invalid border char"); + return; + } + if (iarr.items[0].type != kObjectTypeString) { + api_set_error(err, kErrorTypeValidation, "invalid border char"); + return; + } + string = iarr.items[0].data.string; + if (iarr.size == 2) { + hl_id = object_to_hl_id(iarr.items[1], "border char highlight", err); + if (ERROR_SET(err)) { + return; + } + } + + } else if (iytem.type == kObjectTypeString) { + string = iytem.data.string; + } else { + api_set_error(err, kErrorTypeValidation, "invalid border char"); + return; + } + if (!string.size + || mb_string2cells_len((char_u *)string.data, string.size) != 1) { + api_set_error(err, kErrorTypeValidation, + "border chars must be one cell"); + } + size_t len = MIN(string.size, sizeof(*chars)-1); + memcpy(chars[i], string.data, len); + chars[i][len] = NUL; + hl_ids[i] = hl_id; + } + while (size < 8) { + memcpy(chars+size, chars, sizeof(*chars) * size); + memcpy(hl_ids+size, hl_ids, sizeof(*hl_ids) * size); + size <<= 1; + } + } else if (style.type == kObjectTypeString) { + String str = style.data.string; + if (str.size == 0 || strequal(str.data, "none")) { + fconfig->border = false; + return; + } + for (size_t i = 0; defaults[i].name; i++) { + if (strequal(str.data, defaults[i].name)) { + memcpy(chars, defaults[i].chars, sizeof(defaults[i].chars)); + memset(hl_ids, 0, 8 * sizeof(*hl_ids)); + return; + } + } + api_set_error(err, kErrorTypeValidation, + "invalid border style \"%s\"", str.data); + } +} + +bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf, + Error *err) +{ + // TODO(bfredl): use a get/has_key interface instead and get rid of extra + // flags + bool has_row = false, has_col = false, has_relative = false; + bool has_external = false, has_window = false; + bool has_width = false, has_height = false; + bool has_bufpos = 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) { + fconfig->row = (double)val.data.integer; + } else if (val.type == kObjectTypeFloat) { + fconfig->row = val.data.floating; + } else { + api_set_error(err, kErrorTypeValidation, + "'row' key must be Integer or Float"); + return false; + } + } else if (!strcmp(key, "col")) { + has_col = true; + if (val.type == kObjectTypeInteger) { + fconfig->col = (double)val.data.integer; + } else if (val.type == kObjectTypeFloat) { + fconfig->col = val.data.floating; + } else { + api_set_error(err, kErrorTypeValidation, + "'col' key must be Integer or Float"); + return false; + } + } else if (strequal(key, "width")) { + has_width = true; + if (val.type == kObjectTypeInteger && val.data.integer > 0) { + fconfig->width = (int)val.data.integer; + } else { + api_set_error(err, kErrorTypeValidation, + "'width' key must be a positive Integer"); + return false; + } + } else if (strequal(key, "height")) { + has_height = true; + if (val.type == kObjectTypeInteger && val.data.integer > 0) { + fconfig->height= (int)val.data.integer; + } else { + api_set_error(err, kErrorTypeValidation, + "'height' key must be a positive Integer"); + return false; + } + } else if (!strcmp(key, "anchor")) { + if (val.type != kObjectTypeString) { + api_set_error(err, kErrorTypeValidation, + "'anchor' key must be String"); + return false; + } + if (!parse_float_anchor(val.data.string, &fconfig->anchor)) { + api_set_error(err, kErrorTypeValidation, + "Invalid value of 'anchor' key"); + return false; + } + } else if (!strcmp(key, "relative")) { + if (val.type != kObjectTypeString) { + api_set_error(err, kErrorTypeValidation, + "'relative' key must be String"); + return false; + } + // ignore empty string, to match nvim_win_get_config + if (val.data.string.size > 0) { + has_relative = true; + if (!parse_float_relative(val.data.string, &fconfig->relative)) { + api_set_error(err, kErrorTypeValidation, + "Invalid value of 'relative' key"); + return false; + } + } + } else if (!strcmp(key, "win")) { + has_window = true; + if (val.type != kObjectTypeInteger + && val.type != kObjectTypeWindow) { + api_set_error(err, kErrorTypeValidation, + "'win' key must be Integer or Window"); + return false; + } + fconfig->window = (Window)val.data.integer; + } else if (!strcmp(key, "bufpos")) { + if (val.type != kObjectTypeArray) { + api_set_error(err, kErrorTypeValidation, + "'bufpos' key must be Array"); + return false; + } + if (!parse_float_bufpos(val.data.array, &fconfig->bufpos)) { + api_set_error(err, kErrorTypeValidation, + "Invalid value of 'bufpos' key"); + return false; + } + has_bufpos = true; + } else if (!strcmp(key, "external")) { + if (val.type == kObjectTypeInteger) { + fconfig->external = val.data.integer; + } else if (val.type == kObjectTypeBoolean) { + fconfig->external = val.data.boolean; + } else { + api_set_error(err, kErrorTypeValidation, + "'external' key must be Boolean"); + return false; + } + has_external = fconfig->external; + } else if (!strcmp(key, "focusable")) { + if (val.type == kObjectTypeInteger) { + fconfig->focusable = val.data.integer; + } else if (val.type == kObjectTypeBoolean) { + fconfig->focusable = val.data.boolean; + } else { + api_set_error(err, kErrorTypeValidation, + "'focusable' key must be Boolean"); + return false; + } + } else if (!strcmp(key, "border")) { + parse_border_style(val, fconfig, err); + if (ERROR_SET(err)) { + return false; + } + } else if (!strcmp(key, "style")) { + if (val.type != kObjectTypeString) { + api_set_error(err, kErrorTypeValidation, + "'style' key must be String"); + return false; + } + if (val.data.string.data[0] == NUL) { + fconfig->style = kWinStyleUnused; + } else if (striequal(val.data.string.data, "minimal")) { + fconfig->style = kWinStyleMinimal; + } else { + api_set_error(err, kErrorTypeValidation, + "Invalid value of 'style' key"); + } + } else { + api_set_error(err, kErrorTypeValidation, + "Invalid key '%s'", key); + return false; + } + } + + if (has_window && !(has_relative + && fconfig->relative == kFloatRelativeWindow)) { + api_set_error(err, kErrorTypeValidation, + "'win' key is only valid with relative='win'"); + return false; + } + + if ((has_relative && fconfig->relative == kFloatRelativeWindow) + && (!has_window || fconfig->window == 0)) { + fconfig->window = curwin->handle; + } + + if (has_window && !has_bufpos) { + fconfig->bufpos.lnum = -1; + } + + if (has_bufpos) { + if (!has_row) { + fconfig->row = (fconfig->anchor & kFloatAnchorSouth) ? 0 : 1; + has_row = true; + } + if (!has_col) { + fconfig->col = 0; + has_col = true; + } + } + + if (has_relative && has_external) { + api_set_error(err, kErrorTypeValidation, + "Only one of 'relative' and 'external' must be used"); + return false; + } else if (!reconf && !has_relative && !has_external) { + api_set_error(err, kErrorTypeValidation, + "One of 'relative' and 'external' must be used"); + return false; + } else if (has_relative) { + fconfig->external = false; + } + + if (!reconf && !(has_height && has_width)) { + api_set_error(err, kErrorTypeValidation, + "Must specify 'width' and 'height'"); + return false; + } + + if (fconfig->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, + "'relative' requires 'row'/'col' or 'bufpos'"); + return false; + } + return true; +} diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 6358f35d0a..9dde62f0ee 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1416,6 +1416,25 @@ void nvim_chan_send(Integer chan, String data, Error *err) /// end-of-buffer region is hidden by setting `eob` flag of /// 'fillchars' to a space char, and clearing the /// |EndOfBuffer| region in 'winhighlight'. +/// - `border`: style of (optional) window border. This can either be a string +/// or an array. the string values are: +/// - "none" No border. This is the default +/// - "single" a single line box +/// - "double" a double line box +/// If it is an array it should be an array of eight items or any divisor of +/// eight. The array will specifify the eight chars building up the border +/// in a clockwise fashion starting with the top-left corner. As, an +/// example, the double box style could be specified as: +/// [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ] +/// if the number of chars are less than eight, they will be repeated. Thus +/// an ASCII border could be specified as: +/// [ "/", "-", "\\", "|" ] +/// or all chars the same as: +/// [ "x" ] +/// By default `FloatBorder` highlight is used which links to `VertSplit` +/// when not defined. It could also be specified by character: +/// [ {"+", "MyCorner"}, {"x", "MyBorder"} ] +/// /// @param[out] err Error details, if any /// /// @return Window handle, or 0 on error @@ -2831,8 +2850,8 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Error *err) g = &pum_grid; } else if (grid > 1) { win_T *wp = get_win_by_grid_handle((handle_T)grid); - if (wp != NULL && wp->w_grid.chars != NULL) { - g = &wp->w_grid; + if (wp != NULL && wp->w_grid_alloc.chars != NULL) { + g = &wp->w_grid_alloc; } else { api_set_error(err, kErrorTypeValidation, "No grid with the given handle"); diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 2ddb925d40..f71075ae74 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -1192,10 +1192,10 @@ void aucmd_restbuf(aco_save_T *aco) win_remove(curwin, NULL); handle_unregister_window(curwin); - if (curwin->w_grid.chars != NULL) { - ui_comp_remove_grid(&curwin->w_grid); - ui_call_win_hide(curwin->w_grid.handle); - grid_free(&curwin->w_grid); + if (curwin->w_grid_alloc.chars != NULL) { + ui_comp_remove_grid(&curwin->w_grid_alloc); + ui_call_win_hide(curwin->w_grid_alloc.handle); + grid_free(&curwin->w_grid_alloc); } aucmd_win_used = false; diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index a05bd6fcc7..e8038e7281 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -1079,6 +1079,10 @@ typedef struct { bool external; bool focusable; WinStyle style; + bool border; + schar_T border_chars[8]; + int border_hl_ids[8]; + int border_attr[8]; } FloatConfig; #define FLOAT_CONFIG_INIT ((FloatConfig){ .height = 0, .width = 0, \ @@ -1256,6 +1260,11 @@ struct window_S { int w_height_request; int w_width_request; + int w_border_adj; + // outer size of window grid, including border + int w_height_outer; + int w_width_outer; + /* * === start of cached values ==== */ @@ -1331,7 +1340,8 @@ struct window_S { // w_redr_type is REDRAW_TOP linenr_T w_redraw_top; // when != 0: first line needing redraw linenr_T w_redraw_bot; // when != 0: last line needing redraw - int w_redr_status; // if TRUE status line must be redrawn + bool w_redr_status; // if true status line must be redrawn + bool w_redr_border; // if true border must be redrawn // remember what is shown in the ruler for this window (if 'ruler' set) pos_T w_ru_cursor; // cursor position shown in ruler @@ -1409,6 +1419,7 @@ struct window_S { int w_tagstacklen; // number of tags on stack ScreenGrid w_grid; // the grid specific to the window + ScreenGrid w_grid_alloc; // the grid specific to the window bool w_pos_changed; // true if window position changed bool w_floating; ///< whether the window is floating FloatConfig w_float_config; diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 68c7438ea3..cffa46fa77 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1565,7 +1565,7 @@ void edit_putchar(int c, bool highlight) { int attr; - if (curwin->w_grid.chars != NULL || default_grid.chars != NULL) { + if (curwin->w_grid_alloc.chars != NULL || default_grid.chars != NULL) { update_topline(curwin); // just in case w_topline isn't valid validate_cursor(); if (highlight) { diff --git a/src/nvim/eval.c b/src/nvim/eval.c index f190ef14c4..e1fcbdce25 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -8501,7 +8501,7 @@ static bool tv_is_luafunc(typval_T *tv) int check_luafunc_name(const char *str, bool paren) { const char *p = str; - while (ASCII_ISALNUM(*p) || *p == '_' || *p == '.') { + while (ASCII_ISALNUM(*p) || *p == '_' || *p == '.' || *p == '\'') { p++; } if (*p != (paren ? '(' : NUL)) { diff --git a/src/nvim/grid_defs.h b/src/nvim/grid_defs.h index 752be4f5a8..3b34af46e4 100644 --- a/src/nvim/grid_defs.h +++ b/src/nvim/grid_defs.h @@ -7,7 +7,7 @@ #include "nvim/types.h" -#define MAX_MCO 6 // maximum value for 'maxcombine' +#define MAX_MCO 6 // fixed value for 'maxcombine' // The characters and attributes drawn on grids. typedef char_u schar_T[(MAX_MCO+1) * 4 + 1]; @@ -35,7 +35,8 @@ typedef int sattr_T; /// line_wraps[] is an array of boolean flags indicating if the screen line /// wraps to the next line. It can only be true if a window occupies the entire /// screen width. -typedef struct { +typedef struct ScreenGrid ScreenGrid; +struct ScreenGrid { handle_T handle; schar_T *chars; @@ -58,10 +59,13 @@ typedef struct { // external UI. bool throttled; - // offsets for the grid relative to the global screen. Used by screen.c - // for windows that don't have w_grid->chars etc allocated + // TODO(bfredl): maybe physical grids and "views" (i e drawing + // specifications) should be two separate types? + // offsets for the grid relative to another grid. Used for grids + // that are views into another, actually allocated grid 'target' int row_offset; int col_offset; + ScreenGrid *target; // whether the compositor should blend the grid with the background grid bool blending; @@ -89,9 +93,10 @@ typedef struct { // compositor should momentarily ignore the grid. Used internally when // moving around grids etc. bool comp_disabled; -} ScreenGrid; +}; #define SCREEN_GRID_INIT { 0, NULL, NULL, NULL, NULL, NULL, 0, 0, false, \ - false, 0, 0, false, true, 0, 0, 0, 0, 0, false } + false, 0, 0, NULL, false, true, \ + 0, 0, 0, 0, 0, false } #endif // NVIM_GRID_DEFS_H diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index b01cdde236..f03382bea7 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -341,6 +341,17 @@ void update_window_hl(win_T *wp, bool invalid) } wp->w_hl_attrs[hlf] = attr; } + + if (wp->w_floating && wp->w_float_config.border) { + for (int i = 0; i < 8; i++) { + int attr = wp->w_hl_attrs[HLF_BORDER]; + if (wp->w_float_config.border_hl_ids[i]) { + attr = hl_get_ui_attr(HLF_BORDER, wp->w_float_config.border_hl_ids[i], + false); + } + wp->w_float_config.border_attr[i] = attr; + } + } } /// Gets HL_UNDERLINE highlight. @@ -517,6 +528,10 @@ static HlAttrs get_colors_force(int attr) /// @return the resulting attributes. int hl_blend_attrs(int back_attr, int front_attr, bool *through) { + if (front_attr < 0 || back_attr < 0) { + return -1; + } + HlAttrs fattrs = get_colors_force(front_attr); int ratio = fattrs.hl_blend; if (ratio <= 0) { diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h index 2bda094d8e..ed4aefb577 100644 --- a/src/nvim/highlight_defs.h +++ b/src/nvim/highlight_defs.h @@ -101,6 +101,7 @@ typedef enum { , HLF_MSGSEP // message separator line , HLF_NFLOAT // Floating window , HLF_MSG // Message area + , HLF_BORDER // Floating window border , HLF_COUNT // MUST be the last one } hlf_T; @@ -155,6 +156,7 @@ EXTERN const char *hlf_names[] INIT(= { [HLF_MSGSEP] = "MsgSeparator", [HLF_NFLOAT] = "NormalFloat", [HLF_MSG] = "MsgArea", + [HLF_BORDER] = "FloatBorder", }); diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index ec4f4cbc21..73e3ba53a5 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -571,11 +571,12 @@ size_t mb_string2cells(const char_u *str) /// @param size maximum length of string. It will terminate on earlier NUL. /// @return The number of cells occupied by string `str` size_t mb_string2cells_len(const char_u *str, size_t size) + FUNC_ATTR_NONNULL_ARG(1) { size_t clen = 0; for (const char_u *p = str; *p != NUL && p < str+size; - p += utf_ptr2len_len(p, size+(p-str))) { + p += utfc_ptr2len_len(p, size+(p-str))) { clen += utf_ptr2cells(p); } diff --git a/src/nvim/message.c b/src/nvim/message.c index ba7a667a60..71cb345878 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -178,6 +178,7 @@ void msg_grid_validate(void) msg_grid.throttled = false; // don't throttle in 'cmdheight' area msg_scrolled_at_flush = msg_scrolled; msg_grid.focusable = false; + msg_grid_adj.target = &msg_grid; if (!msg_scrolled) { msg_grid_set_pos(Rows - p_ch, false); } @@ -188,6 +189,7 @@ void msg_grid_validate(void) ui_call_grid_destroy(msg_grid.handle); msg_grid.throttled = false; msg_grid_adj.row_offset = 0; + msg_grid_adj.target = &default_grid; redraw_cmdline = true; } else if (msg_grid.chars && !msg_scrolled && msg_grid_pos != Rows - p_ch) { msg_grid_set_pos(Rows - p_ch, false); diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 9dc85797b4..fa9787a3ac 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -470,21 +470,21 @@ static win_T *mouse_find_grid_win(int *gridp, int *rowp, int *colp) *gridp = DEFAULT_GRID_HANDLE; } else if (*gridp > 1) { win_T *wp = get_win_by_grid_handle(*gridp); - if (wp && wp->w_grid.chars + if (wp && wp->w_grid_alloc.chars && !(wp->w_floating && !wp->w_float_config.focusable)) { - *rowp = MIN(*rowp, wp->w_grid.Rows-1); - *colp = MIN(*colp, wp->w_grid.Columns-1); + *rowp = MIN(*rowp-wp->w_grid.row_offset, wp->w_grid.Rows-1); + *colp = MIN(*colp-wp->w_grid.col_offset, wp->w_grid.Columns-1); return wp; } } else if (*gridp == 0) { ScreenGrid *grid = ui_comp_mouse_focus(*rowp, *colp); FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (&wp->w_grid != grid) { + if (&wp->w_grid_alloc != grid) { continue; } *gridp = grid->handle; - *rowp -= grid->comp_row; - *colp -= grid->comp_col; + *rowp -= grid->comp_row+wp->w_grid.row_offset; + *colp -= grid->comp_col+wp->w_grid.col_offset; return wp; } @@ -729,7 +729,7 @@ int mouse_check_fold(void) if (wp && mouse_row >= 0 && mouse_row < Rows && mouse_col >= 0 && mouse_col <= Columns) { int multigrid = ui_has(kUIMultigrid); - ScreenGrid *gp = multigrid ? &wp->w_grid : &default_grid; + ScreenGrid *gp = multigrid ? &wp->w_grid_alloc : &default_grid; int fdc = win_fdccol_count(wp); int row = multigrid && mouse_grid == 0 ? click_row : mouse_row; int col = multigrid && mouse_grid == 0 ? click_col : mouse_col; diff --git a/src/nvim/option.c b/src/nvim/option.c index dbd8ceb55c..d04329e104 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -4287,7 +4287,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, // 'floatblend' curwin->w_p_winbl = MAX(MIN(curwin->w_p_winbl, 100), 0); curwin->w_hl_needs_update = true; - curwin->w_grid.blending = curwin->w_p_winbl > 0; + curwin->w_grid_alloc.blending = curwin->w_p_winbl > 0; } @@ -5800,7 +5800,7 @@ void didset_window_options(win_T *wp) set_chars_option(wp, &wp->w_p_fcs, true); set_chars_option(wp, &wp->w_p_lcs, true); parse_winhl_opt(wp); // sets w_hl_needs_update also for w_p_winbl - wp->w_grid.blending = wp->w_p_winbl > 0; + wp->w_grid_alloc.blending = wp->w_p_winbl > 0; } diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c index aef7ffa397..69c614fff9 100644 --- a/src/nvim/popupmnu.c +++ b/src/nvim/popupmnu.c @@ -139,7 +139,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, cursor_col = curwin->w_wcol; } - pum_anchor_grid = (int)curwin->w_grid.handle; + pum_anchor_grid = (int)curwin->w_grid.target->handle; if (!ui_has(kUIMultigrid)) { pum_anchor_grid = (int)default_grid.handle; pum_win_row += curwin->w_winrow; diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 467cac4f27..d50520f49e 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -232,7 +232,7 @@ void screen_invalidate_highlights(void) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { redraw_later(wp, NOT_VALID); - wp->w_grid.valid = false; + wp->w_grid_alloc.valid = false; } } @@ -582,11 +582,18 @@ int update_screen(int type) FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_redr_type == CLEAR && wp->w_floating && wp->w_grid.chars) { - grid_invalidate(&wp->w_grid); + if (wp->w_redr_type == CLEAR && wp->w_floating && wp->w_grid_alloc.chars) { + grid_invalidate(&wp->w_grid_alloc); wp->w_redr_type = NOT_VALID; } + // reallocate grid if needed. + win_grid_alloc(wp); + + if (wp->w_redr_border || wp->w_redr_type >= NOT_VALID) { + win_redr_border(wp); + } + if (wp->w_redr_type != 0) { if (!did_one) { did_one = TRUE; @@ -774,8 +781,6 @@ static void win_update(win_T *wp, Providers *providers) type = wp->w_redr_type; - win_grid_alloc(wp); - if (type >= NOT_VALID) { wp->w_redr_status = true; wp->w_lines_valid = 0; @@ -4404,14 +4409,10 @@ void draw_virt_text(buf_T *buf, int *end_col, int max_col) /// screen positions. void screen_adjust_grid(ScreenGrid **grid, int *row_off, int *col_off) { - if (!(*grid)->chars && *grid != &default_grid) { - *row_off += (*grid)->row_offset; - *col_off += (*grid)->col_offset; - if (*grid == &msg_grid_adj && msg_grid.chars) { - *grid = &msg_grid; - } else { - *grid = &default_grid; - } + if ((*grid)->target) { + *row_off += (*grid)->row_offset; + *col_off += (*grid)->col_offset; + *grid = (*grid)->target; } } @@ -5415,6 +5416,46 @@ theend: entered = FALSE; } +static void win_redr_border(win_T *wp) +{ + wp->w_redr_border = false; + if (!(wp->w_floating && wp->w_float_config.border)) { + return; + } + + ScreenGrid *grid = &wp->w_grid_alloc; + + schar_T *chars = wp->w_float_config.border_chars; + int *attrs = wp->w_float_config.border_attr; + + int endrow = grid->Rows-1, endcol = grid->Columns-1; + + grid_puts_line_start(grid, 0); + grid_put_schar(grid, 0, 0, chars[0], attrs[0]); + for (int i = 1; i < endcol; i++) { + grid_put_schar(grid, 0, i, chars[1], attrs[1]); + } + grid_put_schar(grid, 0, endcol, chars[2], attrs[2]); + grid_puts_line_flush(false); + + for (int i = 1; i < endrow; i++) { + grid_puts_line_start(grid, i); + grid_put_schar(grid, i, 0, chars[7], attrs[7]); + grid_puts_line_flush(false); + grid_puts_line_start(grid, i); + grid_put_schar(grid, i, endcol, chars[3], attrs[3]); + grid_puts_line_flush(false); + } + + grid_puts_line_start(grid, endrow); + grid_put_schar(grid, endrow, 0, chars[6], attrs[6]); + for (int i = 1; i < endcol; i++) { + grid_put_schar(grid, endrow, i, chars[5], attrs[5]); + } + grid_put_schar(grid, endrow, endcol, chars[4], attrs[4]); + grid_puts_line_flush(false); +} + // Low-level functions to manipulate invidual character cells on the // screen grid. @@ -5552,6 +5593,20 @@ void grid_puts_line_start(ScreenGrid *grid, int row) put_dirty_grid = grid; } +void grid_put_schar(ScreenGrid *grid, int row, int col, char_u *schar, int attr) +{ + assert(put_dirty_row == row); + unsigned int off = grid->line_offset[row] + col; + if (grid->attrs[off] != attr || schar_cmp(grid->chars[off], schar)) { + schar_copy(grid->chars[off], schar); + grid->attrs[off] = attr; + + put_dirty_first = MIN(put_dirty_first, col); + // TODO(bfredl): Y U NO DOUBLEWIDTH? + put_dirty_last = MAX(put_dirty_last, col+1); + } +} + /// like grid_puts(), but output "text[len]". When "len" is -1 output up to /// a NUL. void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, @@ -6143,12 +6198,15 @@ void check_for_delay(int check_msg_scroll) void win_grid_alloc(win_T *wp) { ScreenGrid *grid = &wp->w_grid; + ScreenGrid *grid_allocated = &wp->w_grid_alloc; int rows = wp->w_height_inner; int cols = wp->w_width_inner; + int total_rows = wp->w_height_outer; + int total_cols = wp->w_width_outer; bool want_allocation = ui_has(kUIMultigrid) || wp->w_floating; - bool has_allocation = (grid->chars != NULL); + bool has_allocation = (grid_allocated->chars != NULL); if (grid->Rows != rows) { wp->w_lines_valid = 0; @@ -6157,35 +6215,47 @@ void win_grid_alloc(win_T *wp) } int was_resized = false; - if ((has_allocation != want_allocation) - || grid->Rows != rows - || grid->Columns != cols) { - if (want_allocation) { - grid_alloc(grid, rows, cols, wp->w_grid.valid, false); - grid->valid = true; - } else { - // Single grid mode, all rendering will be redirected to default_grid. - // Only keep track of the size and offset of the window. - grid_free(grid); - grid->Rows = rows; - grid->Columns = cols; - grid->valid = false; + if (want_allocation && (!has_allocation + || grid_allocated->Rows != total_rows + || grid_allocated->Columns != total_cols)) { + grid_alloc(grid_allocated, total_rows, total_cols, + wp->w_grid_alloc.valid, false); + grid_allocated->valid = true; + if (wp->w_border_adj) { + wp->w_redr_border = true; } was_resized = true; - } else if (want_allocation && has_allocation && !wp->w_grid.valid) { - grid_invalidate(grid); - grid->valid = true; + } else if (!want_allocation && has_allocation) { + // Single grid mode, all rendering will be redirected to default_grid. + // Only keep track of the size and offset of the window. + grid_free(grid_allocated); + grid_allocated->valid = false; + was_resized = true; + } else if (want_allocation && has_allocation && !wp->w_grid_alloc.valid) { + grid_invalidate(grid_allocated); + grid_allocated->valid = true; } - grid->row_offset = wp->w_winrow; - grid->col_offset = wp->w_wincol; + grid->Rows = rows; + grid->Columns = cols; + + if (want_allocation) { + grid->target = grid_allocated; + grid->row_offset = wp->w_border_adj; + grid->col_offset = wp->w_border_adj; + } else { + grid->target = &default_grid; + grid->row_offset = wp->w_winrow; + grid->col_offset = wp->w_wincol; + } // send grid resize event if: // - a grid was just resized // - screen_resize was called and all grid sizes must be sent // - the UI wants multigrid event (necessary) if ((send_grid_resize || was_resized) && want_allocation) { - ui_call_grid_resize(grid->handle, grid->Columns, grid->Rows); + ui_call_grid_resize(grid_allocated->handle, + grid_allocated->Columns, grid_allocated->Rows); } } @@ -7531,7 +7601,7 @@ void win_new_shellsize(void) win_T *get_win_by_grid_handle(handle_T handle) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_grid.handle == handle) { + if (wp->w_grid_alloc.handle == handle) { return wp; } } diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index d204968c0f..f1eb7879b0 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -6046,6 +6046,7 @@ static const char *highlight_init_both[] = { "default link Whitespace NonText", "default link MsgSeparator StatusLine", "default link NormalFloat Pmenu", + "default link FloatBorder VertSplit", "RedrawDebugNormal cterm=reverse gui=reverse", "RedrawDebugClear ctermbg=Yellow guibg=Yellow", "RedrawDebugComposed ctermbg=Green guibg=Green", diff --git a/src/nvim/window.c b/src/nvim/window.c index eef75b10bd..fd7af108b7 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -605,6 +605,7 @@ win_T *win_new_float(win_T *wp, FloatConfig fconfig, Error *err) wp->w_vsep_width = 0; win_config_float(wp, fconfig); + win_set_inner_size(wp); wp->w_pos_changed = true; redraw_later(wp, VALID); return wp; @@ -667,6 +668,8 @@ void win_config_float(win_T *wp, FloatConfig fconfig) } bool change_external = fconfig.external != wp->w_float_config.external; + bool change_border = fconfig.border != wp->w_float_config.border; + wp->w_float_config = fconfig; if (!ui_has(kUIMultigrid)) { @@ -676,11 +679,18 @@ void win_config_float(win_T *wp, FloatConfig fconfig) win_set_inner_size(wp); must_redraw = MAX(must_redraw, VALID); + wp->w_pos_changed = true; - if (change_external) { + if (change_external || change_border) { wp->w_hl_needs_update = true; redraw_later(wp, NOT_VALID); } + + // changing border style while keeping border only requires redrawing border + if (fconfig.border) { + wp->w_redr_border = true; + redraw_later(wp, VALID); + } } void win_check_anchored_floats(win_T *win) @@ -713,7 +723,7 @@ int win_fdccol_count(win_T *wp) 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, + ui_call_win_pos(wp->w_grid_alloc.handle, wp->handle, wp->w_winrow, wp->w_wincol, wp->w_width, wp->w_height); return; } @@ -743,8 +753,8 @@ void ui_ext_win_position(win_T *wp) } if (ui_has(kUIMultigrid)) { String anchor = cstr_to_string(float_anchor_str[c.anchor]); - ui_call_win_float_pos(wp->w_grid.handle, wp->handle, anchor, grid->handle, - row, col, c.focusable); + ui_call_win_float_pos(wp->w_grid_alloc.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. @@ -759,17 +769,17 @@ void ui_ext_win_position(win_T *wp) wp->w_wincol = comp_col; bool valid = (wp->w_redr_type == 0); bool on_top = (curwin == wp) || !curwin->w_floating; - ui_comp_put_grid(&wp->w_grid, comp_row, comp_col, wp->w_height, - wp->w_width, valid, on_top); - ui_check_cursor_grid(wp->w_grid.handle); - wp->w_grid.focusable = wp->w_float_config.focusable; + ui_comp_put_grid(&wp->w_grid_alloc, comp_row, comp_col, + wp->w_height_outer, wp->w_width_outer, valid, on_top); + ui_check_cursor_grid(wp->w_grid_alloc.handle); + wp->w_grid_alloc.focusable = wp->w_float_config.focusable; if (!valid) { - wp->w_grid.valid = false; + wp->w_grid_alloc.valid = false; redraw_later(wp, NOT_VALID); } } } else { - ui_call_win_external_pos(wp->w_grid.handle, wp->handle); + ui_call_win_external_pos(wp->w_grid_alloc.handle, wp->handle); } } @@ -784,260 +794,12 @@ void ui_ext_win_viewport(win_T *wp) // interact with incomplete final line? Diff filler lines? botline = wp->w_buffer->b_ml.ml_line_count; } - ui_call_win_viewport(wp->w_grid.handle, wp->handle, wp->w_topline-1, + ui_call_win_viewport(wp->w_grid_alloc.handle, wp->handle, wp->w_topline-1, botline, wp->w_cursor.lnum-1, wp->w_cursor.col); wp->w_viewport_invalid = false; } } -static bool parse_float_anchor(String anchor, FloatAnchor *out) -{ - if (anchor.size == 0) { - *out = (FloatAnchor)0; - } - char *str = anchor.data; - if (striequal(str, "NW")) { - *out = 0; // NW is the default - } else if (striequal(str, "NE")) { - *out = kFloatAnchorEast; - } else if (striequal(str, "SW")) { - *out = kFloatAnchorSouth; - } else if (striequal(str, "SE")) { - *out = kFloatAnchorSouth | kFloatAnchorEast; - } else { - return false; - } - return true; -} - -static bool parse_float_relative(String relative, FloatRelative *out) -{ - char *str = relative.data; - if (striequal(str, "editor")) { - *out = kFloatRelativeEditor; - } else if (striequal(str, "win")) { - *out = kFloatRelativeWindow; - } else if (striequal(str, "cursor")) { - *out = kFloatRelativeCursor; - } else { - return false; - } - return true; -} - -static bool parse_float_bufpos(Array bufpos, lpos_T *out) -{ - if (bufpos.size != 2 - || bufpos.items[0].type != kObjectTypeInteger - || bufpos.items[1].type != kObjectTypeInteger) { - return false; - } - out->lnum = bufpos.items[0].data.integer; - out->col = bufpos.items[1].data.integer; - return true; -} - -bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf, - Error *err) -{ - // TODO(bfredl): use a get/has_key interface instead and get rid of extra - // flags - bool has_row = false, has_col = false, has_relative = false; - bool has_external = false, has_window = false; - bool has_width = false, has_height = false; - bool has_bufpos = 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) { - fconfig->row = val.data.integer; - } else if (val.type == kObjectTypeFloat) { - fconfig->row = val.data.floating; - } else { - api_set_error(err, kErrorTypeValidation, - "'row' key must be Integer or Float"); - return false; - } - } else if (!strcmp(key, "col")) { - has_col = true; - if (val.type == kObjectTypeInteger) { - fconfig->col = val.data.integer; - } else if (val.type == kObjectTypeFloat) { - fconfig->col = val.data.floating; - } else { - api_set_error(err, kErrorTypeValidation, - "'col' key must be Integer or Float"); - return false; - } - } else if (strequal(key, "width")) { - has_width = true; - if (val.type == kObjectTypeInteger && val.data.integer > 0) { - fconfig->width = val.data.integer; - } else { - api_set_error(err, kErrorTypeValidation, - "'width' key must be a positive Integer"); - return false; - } - } else if (strequal(key, "height")) { - has_height = true; - if (val.type == kObjectTypeInteger && val.data.integer > 0) { - fconfig->height= val.data.integer; - } else { - api_set_error(err, kErrorTypeValidation, - "'height' key must be a positive Integer"); - return false; - } - } else if (!strcmp(key, "anchor")) { - if (val.type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, - "'anchor' key must be String"); - return false; - } - if (!parse_float_anchor(val.data.string, &fconfig->anchor)) { - api_set_error(err, kErrorTypeValidation, - "Invalid value of 'anchor' key"); - return false; - } - } else if (!strcmp(key, "relative")) { - if (val.type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, - "'relative' key must be String"); - return false; - } - // ignore empty string, to match nvim_win_get_config - if (val.data.string.size > 0) { - has_relative = true; - if (!parse_float_relative(val.data.string, &fconfig->relative)) { - api_set_error(err, kErrorTypeValidation, - "Invalid value of 'relative' key"); - return false; - } - } - } else if (!strcmp(key, "win")) { - has_window = true; - if (val.type != kObjectTypeInteger - && val.type != kObjectTypeWindow) { - api_set_error(err, kErrorTypeValidation, - "'win' key must be Integer or Window"); - return false; - } - fconfig->window = val.data.integer; - } else if (!strcmp(key, "bufpos")) { - if (val.type != kObjectTypeArray) { - api_set_error(err, kErrorTypeValidation, - "'bufpos' key must be Array"); - return false; - } - if (!parse_float_bufpos(val.data.array, &fconfig->bufpos)) { - api_set_error(err, kErrorTypeValidation, - "Invalid value of 'bufpos' key"); - return false; - } - has_bufpos = true; - } else if (!strcmp(key, "external")) { - if (val.type == kObjectTypeInteger) { - fconfig->external = val.data.integer; - } else if (val.type == kObjectTypeBoolean) { - fconfig->external = val.data.boolean; - } else { - api_set_error(err, kErrorTypeValidation, - "'external' key must be Boolean"); - return false; - } - has_external = fconfig->external; - } else if (!strcmp(key, "focusable")) { - if (val.type == kObjectTypeInteger) { - fconfig->focusable = val.data.integer; - } else if (val.type == kObjectTypeBoolean) { - fconfig->focusable = val.data.boolean; - } else { - api_set_error(err, kErrorTypeValidation, - "'focusable' key must be Boolean"); - return false; - } - } else if (!strcmp(key, "style")) { - if (val.type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, - "'style' key must be String"); - return false; - } - if (val.data.string.data[0] == NUL) { - fconfig->style = kWinStyleUnused; - } else if (striequal(val.data.string.data, "minimal")) { - fconfig->style = kWinStyleMinimal; - } else { - api_set_error(err, kErrorTypeValidation, - "Invalid value of 'style' key"); - } - } else { - api_set_error(err, kErrorTypeValidation, - "Invalid key '%s'", key); - return false; - } - } - - if (has_window && !(has_relative - && fconfig->relative == kFloatRelativeWindow)) { - api_set_error(err, kErrorTypeValidation, - "'win' key is only valid with relative='win'"); - return false; - } - - if ((has_relative && fconfig->relative == kFloatRelativeWindow) - && (!has_window || fconfig->window == 0)) { - fconfig->window = curwin->handle; - } - - if (has_window && !has_bufpos) { - fconfig->bufpos.lnum = -1; - } - - if (has_bufpos) { - if (!has_row) { - fconfig->row = (fconfig->anchor & kFloatAnchorSouth) ? 0 : 1; - has_row = true; - } - if (!has_col) { - fconfig->col = 0; - has_col = true; - } - } - - if (has_relative && has_external) { - api_set_error(err, kErrorTypeValidation, - "Only one of 'relative' and 'external' must be used"); - return false; - } else if (!reconf && !has_relative && !has_external) { - api_set_error(err, kErrorTypeValidation, - "One of 'relative' and 'external' must be used"); - return false; - } else if (has_relative) { - fconfig->external = false; - } - - if (!reconf && !(has_height && has_width)) { - api_set_error(err, kErrorTypeValidation, - "Must specify 'width' and 'height'"); - return false; - } - - if (fconfig->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, - "'relative' requires 'row'/'col' or 'bufpos'"); - return false; - } - return true; -} - /* * split the current window, implements CTRL-W s and :split * @@ -1953,12 +1715,12 @@ static void win_totop(int size, int flags) } if (curwin->w_floating) { - ui_comp_remove_grid(&curwin->w_grid); + ui_comp_remove_grid(&curwin->w_grid_alloc); 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); + ui_call_win_hide(curwin->w_grid_alloc.handle); win_free_grid(curwin, false); } } else { @@ -2581,11 +2343,11 @@ int win_close(win_T *win, bool free_buf) bool was_floating = win->w_floating; if (ui_has(kUIMultigrid)) { - ui_call_win_close(win->w_grid.handle); + ui_call_win_close(win->w_grid_alloc.handle); } if (win->w_floating) { - ui_comp_remove_grid(&win->w_grid); + ui_comp_remove_grid(&win->w_grid_alloc); if (win->w_float_config.external) { for (tabpage_T *tp = first_tabpage; tp != NULL; tp = tp->tp_next) { if (tp == curtab) { @@ -3763,9 +3525,11 @@ void win_init_size(void) { firstwin->w_height = ROWS_AVAIL; firstwin->w_height_inner = firstwin->w_height; + firstwin->w_height_outer = firstwin->w_height; topframe->fr_height = ROWS_AVAIL; firstwin->w_width = Columns; firstwin->w_width_inner = firstwin->w_width; + firstwin->w_width_outer = firstwin->w_width; topframe->fr_width = Columns; } @@ -4131,7 +3895,7 @@ static void tabpage_check_windows(tabpage_T *old_curtab) win_remove(wp, old_curtab); win_append(lastwin_nofloating(), wp); } else { - ui_comp_remove_grid(&wp->w_grid); + ui_comp_remove_grid(&wp->w_grid_alloc); } } wp->w_pos_changed = true; @@ -4726,7 +4490,7 @@ static win_T *win_alloc(win_T *after, int hidden) new_wp->handle = ++last_win_id; handle_register_window(new_wp); - grid_assign_handle(&new_wp->w_grid); + grid_assign_handle(&new_wp->w_grid_alloc); // Init w: variables. new_wp->w_vars = tv_dict_alloc(); @@ -4850,15 +4614,14 @@ win_free ( void win_free_grid(win_T *wp, bool reinit) { - if (wp->w_grid.handle != 0 && ui_has(kUIMultigrid)) { - ui_call_grid_destroy(wp->w_grid.handle); - wp->w_grid.handle = 0; + if (wp->w_grid_alloc.handle != 0 && ui_has(kUIMultigrid)) { + ui_call_grid_destroy(wp->w_grid_alloc.handle); } - grid_free(&wp->w_grid); + grid_free(&wp->w_grid_alloc); 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)); + memset(&wp->w_grid_alloc, 0, sizeof(wp->w_grid_alloc)); } } @@ -5963,6 +5726,10 @@ void win_set_inner_size(win_T *wp) if (wp->w_buffer->terminal) { terminal_check_size(wp->w_buffer->terminal); } + + wp->w_border_adj = wp->w_floating && wp->w_float_config.border ? 1 : 0; + wp->w_height_outer = wp->w_height_inner + 2 * wp->w_border_adj; + wp->w_width_outer = wp->w_width_inner + 2 * wp->w_border_adj; } /// Set the width of a window. @@ -7099,11 +6866,11 @@ void get_framelayout(const frame_T *fr, list_T *l, bool outer) void win_ui_flush(void) { FOR_ALL_TAB_WINDOWS(tp, wp) { - if (wp->w_pos_changed && wp->w_grid.chars != NULL) { + if (wp->w_pos_changed && wp->w_grid_alloc.chars != NULL) { if (tp == curtab) { ui_ext_win_position(wp); } else { - ui_call_win_hide(wp->w_grid.handle); + ui_call_win_hide(wp->w_grid_alloc.handle); } wp->w_pos_changed = false; } |