diff options
-rw-r--r-- | src/nvim/api/vim.c | 5 | ||||
-rw-r--r-- | src/nvim/api/window.c | 31 | ||||
-rw-r--r-- | src/nvim/screen.c | 2 | ||||
-rw-r--r-- | src/nvim/window.c | 61 | ||||
-rw-r--r-- | test/functional/ui/float_spec.lua | 160 |
5 files changed, 198 insertions, 61 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index f56d37af90..d0327b241c 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1003,7 +1003,8 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err) /// /// For a general overview of floats, see |api-floatwin|. /// -/// Exactly one of `external` and `relative` must be specified. +/// Exactly one of `external` and `relative` must be specified. The `width` and +/// `height` of the new window must be specified. /// /// With editor positioning row=0, col=0 refers to the top-left corner of the /// screen-grid and row=Lines-1, Columns-1 refers to the bottom-right corner. @@ -1035,7 +1036,7 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err) /// - "SW" south-west /// - "SE" south-east /// - `height`: window height (in character cells). Minimum of 1. -/// - `width`: window width (in character cells). Minimum of 2. +/// - `width`: window width (in character cells). Minimum of 1. /// - `row`: row position. Screen cell height are used as unit. Can be /// floating point. /// - `col`: column position. Screen cell width is used as unit. Can be diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 01cb9a6847..e1c50cb89d 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -466,8 +466,6 @@ void nvim_win_set_config(Window window, Dictionary config, Error *err) if (!parse_float_config(config, &fconfig, !new_float, err)) { return; } - fconfig.height = fconfig.height > 0 ? fconfig.height : win->w_height; - fconfig.width = fconfig.width > 0 ? fconfig.width : win->w_width; if (new_float) { if (!win_new_float(win, fconfig, err)) { return; @@ -499,26 +497,25 @@ Dictionary nvim_win_get_config(Window window, Error *err) return rv; } - PUT(rv, "width", INTEGER_OBJ(wp->w_float_config.width)); - PUT(rv, "height", INTEGER_OBJ(wp->w_float_config.height)); PUT(rv, "focusable", BOOLEAN_OBJ(wp->w_float_config.focusable)); PUT(rv, "external", BOOLEAN_OBJ(wp->w_float_config.external)); - PUT(rv, "anchor", STRING_OBJ(cstr_to_string( - float_anchor_str[wp->w_float_config.anchor]))); - if (wp->w_float_config.relative == kFloatRelativeWindow) { - PUT(rv, "win", INTEGER_OBJ(wp->w_float_config.window)); - } - - if (wp->w_float_config.external) { - return rv; + if (wp->w_floating) { + PUT(rv, "width", INTEGER_OBJ(wp->w_float_config.width)); + PUT(rv, "height", INTEGER_OBJ(wp->w_float_config.height)); + if (!wp->w_float_config.external) { + if (wp->w_float_config.relative == kFloatRelativeWindow) { + PUT(rv, "win", INTEGER_OBJ(wp->w_float_config.window)); + } + PUT(rv, "anchor", STRING_OBJ(cstr_to_string( + float_anchor_str[wp->w_float_config.anchor]))); + PUT(rv, "row", FLOAT_OBJ(wp->w_float_config.row)); + PUT(rv, "col", FLOAT_OBJ(wp->w_float_config.col)); + } } - PUT(rv, "row", FLOAT_OBJ(wp->w_float_config.row)); - PUT(rv, "col", FLOAT_OBJ(wp->w_float_config.col)); - - const char *rel = - wp->w_floating ? float_relative_str[wp->w_float_config.relative] : ""; + const char *rel = (wp->w_floating && !wp->w_float_config.external + ? float_relative_str[wp->w_float_config.relative] : ""); PUT(rv, "relative", STRING_OBJ(cstr_to_string(rel))); return rv; diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 55f3417bb9..b4ebf2ece5 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -363,7 +363,7 @@ void update_screen(int type) need_wait_return = FALSE; } - if (type >= NOT_VALID) { + if (type >= CLEAR || !default_grid.valid) { ui_comp_set_screen_valid(false); } win_ui_flush_positions(); diff --git a/src/nvim/window.c b/src/nvim/window.c index 9555c88138..9d8cd21dba 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -579,7 +579,7 @@ win_T *win_new_float(win_T *wp, FloatConfig fconfig, Error *err) void win_config_float(win_T *wp, FloatConfig fconfig) { - wp->w_width = MAX(fconfig.width, 2); + wp->w_width = MAX(fconfig.width, 1); wp->w_height = MAX(fconfig.height, 1); if (fconfig.relative == kFloatRelativeCursor) { @@ -617,13 +617,16 @@ static void ui_ext_win_position(win_T *wp) FloatConfig c = wp->w_float_config; if (!c.external) { ScreenGrid *grid = &default_grid; - int row = c.row, col = c.col; + float 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); + int row_off = 0, col_off = 0; + screen_adjust_grid(&grid, &row_off, &col_off); + row += row_off; + col += col_off; } api_clear_error(&dummy); } @@ -637,16 +640,16 @@ static void ui_ext_win_position(win_T *wp) 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; + int comp_row = (int)row - (south ? wp->w_height : 0); + int comp_col = (int)col - (east ? wp->w_width : 0); + comp_row = MAX(MIN(comp_row, Rows-wp->w_height-1), 0); + comp_col = MAX(MIN(comp_col, Columns-wp->w_width), 0); + wp->w_winrow = comp_row; + 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, row, col, wp->w_height, wp->w_width, - valid, on_top); + ui_comp_put_grid(&wp->w_grid, comp_row, comp_col, wp->w_height, + wp->w_width, valid, on_top); if (!valid) { wp->w_grid.valid = false; redraw_win_later(wp, NOT_VALID); @@ -681,9 +684,6 @@ static bool parse_float_anchor(String anchor, FloatAnchor *out) static bool parse_float_relative(String relative, FloatRelative *out) { - if (relative.size == 0) { - *out = (FloatRelative)0; - } char *str = relative.data; if (striequal(str, "editor")) { *out = kFloatRelativeEditor; @@ -700,8 +700,11 @@ static bool parse_float_relative(String relative, FloatRelative *out) 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; for (size_t i = 0; i < config.size; i++) { char *key = config.items[i].key.data; @@ -729,7 +732,8 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf, return false; } } else if (strequal(key, "width")) { - if (val.type == kObjectTypeInteger && val.data.integer >= 0) { + has_width = true; + if (val.type == kObjectTypeInteger && val.data.integer > 0) { fconfig->width = val.data.integer; } else { api_set_error(err, kErrorTypeValidation, @@ -737,7 +741,8 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf, return false; } } else if (strequal(key, "height")) { - if (val.type == kObjectTypeInteger && val.data.integer >= 0) { + has_height = true; + if (val.type == kObjectTypeInteger && val.data.integer > 0) { fconfig->height= val.data.integer; } else { api_set_error(err, kErrorTypeValidation, @@ -756,16 +761,19 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf, return false; } } else if (!strcmp(key, "relative")) { - has_relative = true; if (val.type != kObjectTypeString) { api_set_error(err, kErrorTypeValidation, "'relative' key must be String"); return false; } - if (!parse_float_relative(val.data.string, &fconfig->relative)) { - api_set_error(err, kErrorTypeValidation, - "Invalid value of 'relative' key"); - 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; @@ -828,6 +836,12 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf, 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"); @@ -1135,6 +1149,8 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) } else if (wp->w_floating) { new_frame(wp); wp->w_floating = false; + // non-floating window doesn't store float config. + wp->w_float_config = FLOAT_CONFIG_INIT; } /* @@ -4421,6 +4437,7 @@ static win_T *win_alloc(win_T *after, int hidden) new_wp->w_cursor.lnum = 1; new_wp->w_scbind_pos = 1; new_wp->w_floating = 0; + new_wp->w_float_config = FLOAT_CONFIG_INIT; /* We won't calculate w_fraction until resizing the window */ new_wp->w_fraction = 0; @@ -4717,8 +4734,6 @@ int win_comp_pos(void) // 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) { - wp->w_float_config.width = wp->w_width; - wp->w_float_config.height = wp->w_height; win_config_float(wp, wp->w_float_config); } diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index aa304c11bb..a567fbb941 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -173,6 +173,13 @@ describe('floating windows', function() local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=3, col=5}) local expected = {anchor='NW', col=5, external=false, focusable=true, height=2, relative='editor', row=3, width=20} eq(expected, meths.win_get_config(win)) + + eq({relative='', external=false, focusable=true}, meths.win_get_config(0)) + + if multigrid then + meths.win_set_config(win, {external=true, width=10, height=1}) + eq({external=true,focusable=true,width=10,height=1,relative=''}, meths.win_get_config(win)) + end end) it('defaults to nonumber and NormalFloat highlight', function() @@ -253,6 +260,112 @@ describe('floating windows', function() end end) + it('can have minimum size', function() + insert("the background text") + local buf = meths.create_buf(false, true) + meths.buf_set_lines(buf, 0, -1, true, {'x'}) + local win = meths.open_win(buf, false, {relative='win', width=1, height=1, row=0, col=4, focusable=false}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + the background tex^t | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 4 + {1:x}| + ]], float_pos={ + [4] = {{id = 1002}, "NW", 2, 0, 4, false} + }} + else + screen:expect([[ + the {1:x}ackground tex^t | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end + + meths.win_set_config(win, {relative='win', row=0, col=15}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + the background tex^t | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 4 + {1:x}| + ]], float_pos={ + [4] = {{id = 1002}, "NW", 2, 0, 15, false} + }} + else + screen:expect([[ + the background {1:x}ex^t | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end + + meths.win_close(win,false) + if multigrid then + screen:expect([[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + the background tex^t | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ]]) + else + screen:expect([[ + the background tex^t | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end + end) + it('API has proper error messages', function() local buf = meths.create_buf(false,false) eq({false, "Invalid key 'bork'"}, @@ -271,6 +384,10 @@ describe('floating windows', function() meth_pcall(meths.open_win,buf, false, {width=-1,height=2,relative='editor'})) eq({false, "'height' key must be a positive Integer"}, meth_pcall(meths.open_win,buf, false, {width=20,height=-1,relative='editor'})) + eq({false, "'height' key must be a positive Integer"}, + meth_pcall(meths.open_win,buf, false, {width=20,height=0,relative='editor'})) + eq({false, "Must specify 'width' and 'height'"}, + meth_pcall(meths.open_win,buf, false, {relative='editor'})) end) it('can be placed relative window or cursor', function() @@ -836,15 +953,15 @@ describe('floating windows', function() screen:expect([[ | {0:~ }| + {0:~ }{1:such }{0: }| {0:~ }{1:very }{0: }| {0:~ }{1:^float }{0: }| - {0:~ }| - {0:~ }| + {0:~ }{2:~ }{0: }| | ]]) end - meths.win_set_config(win, {width=0, height=3}) + meths.win_set_config(win, {height=3}) feed('gg') if multigrid then screen:expect{grid=[[ @@ -1173,9 +1290,9 @@ describe('floating windows', function() screen:expect([[ | {0:~ }| - {0:~ }{1:^such }{0: }| - {0:~ }| - {0:~ }| + {0:~ }{1:^such }{0: }| + {0:~ }{1:very }{0: }| + {0:~ }{1:float }{0: }| {0:~ }| | ]]) @@ -3256,7 +3373,7 @@ describe('floating windows', function() end if multigrid then - meths.win_set_config(0, {external=true}) + meths.win_set_config(0, {external=true, width=30, height=2}) expected_pos = {[3]={external=true}} screen:expect{grid=[[ ## grid 1 @@ -3274,12 +3391,12 @@ describe('floating windows', function() {0:~ }| {0:~ }| ## grid 3 - ^y | - {0:~ }| + ^y | + {0:~ }| ]], float_pos=expected_pos} else eq({false, "UI doesn't support external windows"}, - meth_pcall(meths.win_set_config, 0, {external=true})) + meth_pcall(meths.win_set_config, 0, {external=true, width=30, height=2})) return end @@ -3547,7 +3664,8 @@ describe('floating windows', function() it(":tabnew and :tabnext (external)", function() if multigrid then - meths.win_set_config(win, {external=true}) + -- also test external window wider than main screen + meths.win_set_config(win, {external=true, width=65, height=4}) expected_pos = {[3]={external=true}} feed(":tabnew<cr>") screen:expect{grid=[[ @@ -3567,8 +3685,10 @@ describe('floating windows', function() {0:~ }| {0:~ }| ## grid 3 - y | - {0:~ }| + y | + {0:~ }| + {0:~ }| + {0:~ }| ## grid 4 ^ | {0:~ }| @@ -3578,7 +3698,7 @@ describe('floating windows', function() ]], float_pos=expected_pos} else eq({false, "UI doesn't support external windows"}, - meth_pcall(meths.win_set_config, 0, {external=true})) + meth_pcall(meths.win_set_config, 0, {external=true, width=65, height=4})) end feed(":tabnext<cr>") @@ -3599,8 +3719,10 @@ describe('floating windows', function() {0:~ }| {0:~ }| ## grid 3 - y | - {0:~ }| + y | + {0:~ }| + {0:~ }| + {0:~ }| ## grid 4 | {0:~ }| @@ -3628,8 +3750,10 @@ describe('floating windows', function() {0:~ }| {0:~ }| ## grid 3 - y | - {0:~ }| + y | + {0:~ }| + {0:~ }| + {0:~ }| ## grid 4 ^ | {0:~ }| |