From 372aa2eb3db375385cf19dc0a6571f790b858241 Mon Sep 17 00:00:00 2001 From: glepnir Date: Mon, 9 Oct 2023 18:47:10 +0800 Subject: [PATCH] feat(float): add fclose command --- runtime/doc/index.txt | 1 + runtime/doc/news.txt | 2 + runtime/doc/windows.txt | 5 + src/nvim/ex_cmds.lua | 6 + src/nvim/ex_docmd.c | 6 + src/nvim/window.c | 26 +++++ test/functional/ui/float_spec.lua | 180 ++++++++++++++++++++++++++++++ 7 files changed, 226 insertions(+) diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index b0ead51d0c..9e34cb5eab 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -1288,6 +1288,7 @@ tag command action ~ |:execute| :exe[cute] execute result of expressions |:exit| :exi[t] same as ":xit" |:exusage| :exu[sage] overview of Ex commands +|:fclose| :fc[lose] close floating window |:file| :f[ile] show or set the current file name |:files| :files list all files in the buffer list |:filetype| :filet[ype] switch file type detection on/off diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index b0f3b76587..ceacb2e5da 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -188,6 +188,8 @@ The following new APIs and features were added. • |$NVIM_APPNAME| can be set to a relative path instead of only a name. +• Added |:fclose| command. + ============================================================================== CHANGED FEATURES *news-changed* diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt index e0c0772f18..eb3c4df511 100644 --- a/runtime/doc/windows.txt +++ b/runtime/doc/windows.txt @@ -392,6 +392,11 @@ CTRL-W CTRL-O *CTRL-W_CTRL-O* *:on* *:only* given, then they become hidden. But modified buffers are never abandoned, so changes cannot get lost. + *:fc* *:fclose* +:[count]fc[lose][!] + Close [count]th floating window by zindex order. '!' to close + all floating windows. + ============================================================================== 4. Moving cursor to other windows *window-move-cursor* diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 88f3bc0b43..27f8535a1c 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -1044,6 +1044,12 @@ module.cmds = { addr_type='ADDR_NONE', func='ex_function', }, + { + command='fclose', + flags=bit.bor(BANG, RANGE), + addr_type='ADDR_OTHER', + func='ex_floatclose', + }, { command='global', flags=bit.bor(RANGE, WHOLEFOLD, BANG, EXTRA, DFLALL, SBOXOK, CMDWIN, LOCK_OK), diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index eb89e0fc9d..e18912c8a0 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -7357,6 +7357,12 @@ static void ex_terminal(exarg_T *eap) do_cmdline_cmd(ex_cmd); } +/// ":fclose" +static void ex_floatclose(exarg_T *eap) +{ + win_float_remove(eap->forceit, eap->line1); +} + void verify_command(char *cmd) { if (strcmp("smile", cmd) != 0) { diff --git a/src/nvim/window.c b/src/nvim/window.c index 04b5afe624..d688c58ff5 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -7658,3 +7658,29 @@ win_T *lastwin_nofloating(void) } return res; } + +static int floating_zindex_compare(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 *), floating_zindex_compare); + 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/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 18c8a7370f..ab02094beb 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -10927,6 +10927,186 @@ describe('float window', function() ]]) end end) + + it('fclose command #9663', function() + local bufA = meths.create_buf(false,false) + local bufB = meths.create_buf(false,false) + local bufC = meths.create_buf(false,false) + local bufD = meths.create_buf(false,false) + local config_A = {relative='editor', width=11, height=11, row=5, col=5, border ='single', zindex=50} + local config_B = {relative='editor', width=8, height=8, row=7, col=7, border ='single', zindex=70} + local config_C = {relative='editor', width=4, height=4, row=9, col=9, border ='single',zindex=90} + local config_D = {relative='editor', width=2, height=2, row=10, col=10, border ='single',zindex=100} + meths.open_win(bufA, false, config_A) + meths.open_win(bufB, false, config_B) + meths.open_win(bufC, false, config_C) + meths.open_win(bufD, false, config_D) + --close window which have higher zindex value + command('fclose') + local expected_pos = { + [4]={{id=1001}, 'NW', 1, 5, 5, true, 50}, + [5]={{id=1002}, 'NW', 1, 7, 7, true, 70}, + [6]={{id=1003}, 'NW', 1, 9, 9, true, 90}, + } + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + + ## grid 4 + {5:┌───────────┐}| + {5:│}{1: }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└───────────┘}| + ## grid 5 + {5:┌────────┐}| + {5:│}{1: }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└────────┘}| + ## grid 6 + {5:┌────┐}| + {5:│}{1: }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└────┘}| + ]],float_pos= expected_pos} + else + screen:expect([[ + ^ {5:┌─┌─┌────┐─┐┐} | + {0:~ }{5:│}{1: }{5:│}{1: }{5:│}{1: }{5:│}{1: }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~}{5:│}{2:~ }{5:│}{2: }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~}{5:│}{2:~ }{5:│}{2: }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~}{5:│}{2:~ }{5:│}{2: }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~}{5:└────┘}{2: }{5:││}{0: }| + | + ]]) + end + -- with range + command('1fclose') + expected_pos[6]=nil + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + + ## grid 4 + {5:┌───────────┐}| + {5:│}{1: }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└───────────┘}| + ## grid 5 + {5:┌────────┐}| + {5:│}{1: }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└────────┘}| + ]],float_pos= expected_pos} + else + screen:expect([[ + ^ {5:┌─┌────────┐┐} | + {0:~ }{5:│}{1: }{5:│}{1: }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~ }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~ }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~ }{5:││}{0: }| + {0:~ }{5:│}{2:~}{5:│}{2:~ }{5:││}{0: }| + | + ]]) + end + --with bang + command('fclose!') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + + ]],float_pos= {}} + else + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end + end) end describe('with ext_multigrid', function()