From b03e790cddd19b57fa91f4fbfcc30c28f3c173bf Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 17 Dec 2024 11:34:30 +0800 Subject: [PATCH] vim-patch:9.1.0934: hard to view an existing buffer in the preview window (#31605) Problem: hard to view an existing buffer in the preview window Solution: add the :pbuffer command (Yinzuo Jiang) Similar as `:pedit` and `:buffer` command. `:pbuffer` edits buffer [N] from the buffer list in the preview window. `:pbuffer` can also open special buffer, for example terminal buffer. closes: vim/vim#16222 https://github.com/vim/vim/commit/a2a2fe841ed2efdbb1f8055f752a3a4d0988ae9d Cherry-pick Test_popup_and_previewwindow_dump() changes from patch 9.0.0625. Cherry-pick Run_noroom_for_newwindow_test() changes from patches 8.2.0432 and 9.0.0363. Co-authored-by: Yinzuo Jiang --- runtime/doc/index.txt | 1 + runtime/doc/windows.txt | 7 +++ src/nvim/ex_cmds.lua | 6 +++ src/nvim/ex_docmd.c | 35 +++++++++++-- test/functional/ui/popupmenu_spec.lua | 75 +++++++++++++++++++++++++++ test/old/testdir/test_popup.vim | 33 ++++++++---- test/old/testdir/test_preview.vim | 49 ++++++++++++++--- test/old/testdir/test_statusline.vim | 4 ++ test/old/testdir/test_window_cmd.vim | 31 +++++------ test/old/testdir/test_winfixbuf.vim | 12 +++++ 10 files changed, 216 insertions(+), 37 deletions(-) diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index d81d59c56f..0182123a12 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -1472,6 +1472,7 @@ tag command action ~ |:ownsyntax| :ow[nsyntax] set new local syntax highlight for this window |:packadd| :pa[ckadd] add a plugin from 'packpath' |:packloadall| :packl[oadall] load all packages under 'packpath' +|:pbuffer| :pb[uffer] edit buffer in the preview window |:pclose| :pc[lose] close preview window |:pedit| :ped[it] edit file in the preview window |:perl| :pe[rl] execute perl command diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt index a6e5984c82..d3c58a28a4 100644 --- a/runtime/doc/windows.txt +++ b/runtime/doc/windows.txt @@ -978,6 +978,13 @@ CTRL-W g } *CTRL-W_g}* it. Make the new Preview window (if required) N high. If N is not given, 'previewheight' is used. + *:pb* *:pbuffer* +:[N]pb[uffer][!] [+cmd] [N] + Edit buffer [N] from the buffer list in the preview window. + If [N] is not given, the current buffer remains being edited. + See |:buffer-!| for [!]. This will also edit a buffer that is + not in the buffer list, without setting the 'buflisted' flag. + *:ped* *:pedit* :ped[it][!] [++opt] [+cmd] {file} Edit {file} in the preview window. The preview window is diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index c8574c805c..0cdc397e9c 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -1946,6 +1946,12 @@ M.cmds = { addr_type = 'ADDR_NONE', func = 'ex_packloadall', }, + { + command = 'pbuffer', + flags = bit.bor(BANG, RANGE, BUFNAME, BUFUNL, COUNT, EXTRA, CMDARG, TRLBAR), + addr_type = 'ADDR_BUFFERS', + func = 'ex_pbuffer', + }, { command = 'pclose', flags = bit.bor(BANG, TRLBAR), diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index b32a8b867f..052bf3b9f7 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4501,6 +4501,12 @@ static void ex_bunload(exarg_T *eap) /// :[N]buffer [N] to buffer N /// :[N]sbuffer [N] to buffer N static void ex_buffer(exarg_T *eap) +{ + do_exbuffer(eap); +} + +/// ":buffer" command and alike. +static void do_exbuffer(exarg_T *eap) { if (*eap->arg) { eap->errmsg = ex_errmsg(e_trailing_arg, eap->arg); @@ -7002,14 +7008,35 @@ static void ex_ptag(exarg_T *eap) static void ex_pedit(exarg_T *eap) { win_T *curwin_save = curwin; - - // Open the preview window or popup and make it the current window. - g_do_tagpreview = (int)p_pvh; - prepare_tagpreview(true); + prepare_preview_window(); // Edit the file. do_exedit(eap, NULL); + back_to_current_window(curwin_save); +} + +/// ":pbuffer" +static void ex_pbuffer(exarg_T *eap) +{ + win_T *curwin_save = curwin; + prepare_preview_window(); + + // Go to the buffer. + do_exbuffer(eap); + + back_to_current_window(curwin_save); +} + +static void prepare_preview_window(void) +{ + // Open the preview window or popup and make it the current window. + g_do_tagpreview = (int)p_pvh; + prepare_tagpreview(true); +} + +static void back_to_current_window(win_T *curwin_save) +{ if (curwin != curwin_save && win_valid(curwin_save)) { // Return cursor to where we were validate_cursor(curwin); diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index a4bf602e57..beb3ae385c 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -1542,6 +1542,81 @@ describe('builtin popupmenu', function() end) if not multigrid then + describe('popup and preview window do not overlap', function() + before_each(function() + screen:try_resize(53, 20) + end) + + -- oldtest: Test_popup_and_previewwindow_dump_pedit() + it('with :pedit', function() + exec([[ + set previewheight=9 + silent! pedit + call setline(1, map(repeat(["ab"], 10), "v:val .. v:key")) + exec "norm! G\\" + ]]) + feed('o') + n.poke_eventloop() + feed('') + screen:expect([[ + ab0 | + ab1 | + ab2 | + ab3 | + ab4 | + ab5 | + ab6 | + ab7 | + ab8 | + {s:ab0 }{c: }{3:ew][+] }| + {n:ab1 }{c: } | + {n:ab2 }{c: } | + {n:ab3 }{c: } | + {n:ab4 }{s: } | + {n:ab5 }{s: } | + {n:ab6 }{s: } | + ab0^ | + {1:~ }| + {4:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 10} | + ]]) + end) + + -- oldtest: Test_popup_and_previewwindow_dump_pbuffer() + it('with :pbuffer', function() + exec([[ + set previewheight=9 + silent! pbuffer + call setline(1, map(repeat(["ab"], 10), "v:val .. v:key")) + exec "norm! G\\\" + ]]) + feed('o') + n.poke_eventloop() + feed('') + screen:expect([[ + ab0 | + ab1 | + ab2 | + ab3 | + ab4 | + ab5 | + ab6 | + ab7 | + ab8 | + {s:ab0 }{c: }{3:ew][+] }| + {n:ab1 }{c: } | + {n:ab2 }{c: } | + {n:ab3 }{s: } | + {n:ab4 }{s: } | + {n:ab5 }{s: } | + ab0^ | + {1:~ }|*2 + {4:[No Name] [+] }| + {2:-- Keyword Local completion (^N^P) }{5:match 1 of 10} | + ]]) + end) + end) + -- oldtest: Test_pum_with_preview_win() it('preview window opened during completion', function() exec([[ diff --git a/test/old/testdir/test_popup.vim b/test/old/testdir/test_popup.vim index 33e86678c8..a24e133ce6 100644 --- a/test/old/testdir/test_popup.vim +++ b/test/old/testdir/test_popup.vim @@ -748,17 +748,11 @@ func Test_popup_and_preview_autocommand() bw! endfunc -func Test_popup_and_previewwindow_dump() +func s:run_popup_and_previewwindow_dump(lines, dumpfile) CheckScreendump CheckFeature quickfix - let lines =<< trim END - set previewheight=9 - silent! pedit - call setline(1, map(repeat(["ab"], 10), "v:val .. v:key")) - exec "norm! G\\" - END - call writefile(lines, 'Xscript') + call writefile(a:lines, 'Xscript', 'D') let buf = RunVimInTerminal('-S Xscript', {}) " wait for the script to finish @@ -768,11 +762,30 @@ func Test_popup_and_previewwindow_dump() call term_sendkeys(buf, "o") call TermWait(buf, 50) call term_sendkeys(buf, "\\") - call VerifyScreenDump(buf, 'Test_popup_and_previewwindow_01', {}) + call VerifyScreenDump(buf, a:dumpfile, {}) call term_sendkeys(buf, "\u") call StopVimInTerminal(buf) - call delete('Xscript') +endfunc + +func Test_popup_and_previewwindow_dump_pedit() + let lines =<< trim END + set previewheight=9 + silent! pedit + call setline(1, map(repeat(["ab"], 10), "v:val .. v:key")) + exec "norm! G\\" + END + call s:run_popup_and_previewwindow_dump(lines, 'Test_popup_and_previewwindow_pedit') +endfunc + +func Test_popup_and_previewwindow_dump_pbuffer() + let lines =<< trim END + set previewheight=9 + silent! pbuffer + call setline(1, map(repeat(["ab"], 10), "v:val .. v:key")) + exec "norm! G\\\" + END + call s:run_popup_and_previewwindow_dump(lines, 'Test_popup_and_previewwindow_pbuffer') endfunc func Test_balloon_split() diff --git a/test/old/testdir/test_preview.vim b/test/old/testdir/test_preview.vim index b7b908e761..d24b09b7d2 100644 --- a/test/old/testdir/test_preview.vim +++ b/test/old/testdir/test_preview.vim @@ -15,14 +15,7 @@ func Test_Psearch() bwipe endfunc -func Test_window_preview() - CheckFeature quickfix - - " Open a preview window - pedit Xa - call assert_equal(2, winnr('$')) - call assert_equal(0, &previewwindow) - +func s:goto_preview_and_close() " Go to the preview window wincmd P call assert_equal(1, &previewwindow) @@ -36,6 +29,46 @@ func Test_window_preview() call assert_fails('wincmd P', 'E441:') endfunc +func Test_window_preview() + CheckFeature quickfix + + " Open a preview window + pedit Xa + call assert_equal(2, winnr('$')) + call assert_equal(0, &previewwindow) + + call s:goto_preview_and_close() +endfunc + +func Test_window_preview_from_pbuffer() + CheckFeature quickfix + + call writefile(['/* some C code */'], 'Xpreview.c', 'D') + edit Xpreview.c + const buf_num = bufnr('%') + enew + call assert_equal(1, winnr('$')) + exe 'pbuffer ' . buf_num + call assert_equal(2, winnr('$')) + call assert_equal(0, &previewwindow) + + call s:goto_preview_and_close() +endfunc + +func Test_window_preview_terminal() + CheckFeature quickfix + " CheckFeature terminal + + term " ++curwin + const buf_num = bufnr('$') + call assert_equal(1, winnr('$')) + exe 'pbuffer' . buf_num + call assert_equal(2, winnr('$')) + call assert_equal(0, &previewwindow) + + call s:goto_preview_and_close() +endfunc + func Test_window_preview_from_help() CheckFeature quickfix diff --git a/test/old/testdir/test_statusline.vim b/test/old/testdir/test_statusline.vim index c8162ced07..c9f79dfef7 100644 --- a/test/old/testdir/test_statusline.vim +++ b/test/old/testdir/test_statusline.vim @@ -220,6 +220,10 @@ func Test_statusline() wincmd j call assert_match('^\[Preview\],PRV\s*$', s:get_statusline()) pclose + pbuffer + wincmd j + call assert_match('^\[Preview\],PRV\s*$', s:get_statusline()) + pclose " %y: Type of file in the buffer, e.g., "[vim]". See 'filetype'. " %Y: Type of file in the buffer, e.g., ",VIM". See 'filetype'. diff --git a/test/old/testdir/test_window_cmd.vim b/test/old/testdir/test_window_cmd.vim index e173aa1e73..343bc9fd83 100644 --- a/test/old/testdir/test_window_cmd.vim +++ b/test/old/testdir/test_window_cmd.vim @@ -1185,20 +1185,20 @@ func Run_noroom_for_newwindow_test(dir_arg) let dir = (a:dir_arg == 'v') ? 'vert ' : '' " Open as many windows as possible - for i in range(500) + while v:true try exe dir . 'new' catch /E36:/ break endtry - endfor + endwhile - call writefile(['first', 'second', 'third'], 'Xfile1') - call writefile([], 'Xfile2') - call writefile([], 'Xfile3') + call writefile(['first', 'second', 'third'], 'Xnorfile1') + call writefile([], 'Xnorfile2') + call writefile([], 'Xnorfile3') " Argument list related commands - args Xfile1 Xfile2 Xfile3 + args Xnorfile1 Xnorfile2 Xnorfile3 next for cmd in ['sargument 2', 'snext', 'sprevious', 'sNext', 'srewind', \ 'sfirst', 'slast'] @@ -1209,13 +1209,13 @@ func Run_noroom_for_newwindow_test(dir_arg) " Buffer related commands set modified hide enew - for cmd in ['sbuffer Xfile1', 'sbnext', 'sbprevious', 'sbNext', 'sbrewind', + for cmd in ['sbuffer Xnorfile1', 'sbnext', 'sbprevious', 'sbNext', 'sbrewind', \ 'sbfirst', 'sblast', 'sball', 'sbmodified', 'sunhide'] call assert_fails(dir .. cmd, 'E36:') endfor " Window related commands - for cmd in ['split', 'split Xfile2', 'new', 'new Xfile3', 'sview Xfile1', + for cmd in ['split', 'split Xnorfile2', 'new', 'new Xnorfile3', 'sview Xnorfile1', \ 'sfind runtest.vim'] call assert_fails(dir .. cmd, 'E36:') endfor @@ -1238,7 +1238,8 @@ func Run_noroom_for_newwindow_test(dir_arg) call assert_fails(dir .. 'lopen', 'E36:') " Preview window - call assert_fails(dir .. 'pedit Xfile2', 'E36:') + call assert_fails(dir .. 'pedit Xnorfile2', 'E36:') + call assert_fails(dir .. 'pbuffer', 'E36:') call setline(1, 'abc') call assert_fails(dir .. 'psearch abc', 'E36:') endif @@ -1246,15 +1247,15 @@ func Run_noroom_for_newwindow_test(dir_arg) " Window commands (CTRL-W ^ and CTRL-W f) if a:dir_arg == 'h' call assert_fails('call feedkeys("\^", "xt")', 'E36:') - call setline(1, 'Xfile1') + call setline(1, 'Xnorfile1') call assert_fails('call feedkeys("gg\f", "xt")', 'E36:') endif enew! " Tag commands (:stag, :stselect and :stjump) call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//", - \ "second\tXfile1\t2", - \ "third\tXfile1\t3",], + \ "second\tXnorfile1\t2", + \ "third\tXnorfile1\t3",], \ 'Xtags') set tags=Xtags call assert_fails(dir .. 'stag second', 'E36:') @@ -1276,9 +1277,9 @@ func Run_noroom_for_newwindow_test(dir_arg) endif %bwipe! - call delete('Xfile1') - call delete('Xfile2') - call delete('Xfile3') + call delete('Xnorfile1') + call delete('Xnorfile2') + call delete('Xnorfile3') only endfunc diff --git a/test/old/testdir/test_winfixbuf.vim b/test/old/testdir/test_winfixbuf.vim index cc8ff86fa1..f7986fdda3 100644 --- a/test/old/testdir/test_winfixbuf.vim +++ b/test/old/testdir/test_winfixbuf.vim @@ -2545,6 +2545,18 @@ func Test_pedit() call assert_equal(l:other, bufnr()) endfunc +" Allow :pbuffer because, unlike :buffer, it uses a separate window +func Test_pbuffer() + call s:reset_all_buffers() + + let l:other = s:make_buffer_pairs() + + exe 'pbuffer ' . l:other + + execute "normal \w" + call assert_equal(l:other, bufnr()) +endfunc + " Fail :pop but :pop! is allowed func Test_pop() call s:reset_all_buffers()