From 39b431b3ed5d5e7c9236655a874863489567174a Mon Sep 17 00:00:00 2001 From: ckelsel Date: Fri, 30 Jun 2017 20:18:41 +0800 Subject: fix hostname_spec.lua test failed --- test/functional/eval/hostname_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/eval/hostname_spec.lua b/test/functional/eval/hostname_spec.lua index f1867846c4..6d5b64b929 100644 --- a/test/functional/eval/hostname_spec.lua +++ b/test/functional/eval/hostname_spec.lua @@ -8,7 +8,7 @@ describe('hostname()', function() it('returns hostname string', function() local actual = call('hostname') - ok(string.len(actual) > 1) + ok(string.len(actual) > 0) if call('executable', 'hostname') == 1 then local expected = string.gsub(call('system', 'hostname'), '[\n\r]', '') helpers.eq(expected, actual) -- cgit From 3965449d05d02c619b44c2b939b9ff88ba542aa0 Mon Sep 17 00:00:00 2001 From: ckelsel Date: Sat, 1 Jul 2017 10:55:55 +0800 Subject: test --- travis_ci | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 travis_ci diff --git a/travis_ci b/travis_ci new file mode 100644 index 0000000000..e69de29bb2 -- cgit From b96f43f2b86cbac3f34691fd97bce4cdb9d6aed9 Mon Sep 17 00:00:00 2001 From: ckelsel Date: Sat, 1 Jul 2017 10:56:46 +0800 Subject: rm test --- travis_ci | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 travis_ci diff --git a/travis_ci b/travis_ci deleted file mode 100644 index e69de29bb2..0000000000 -- cgit From 8cc49f9f1ad4edface62284c32f05ef1140d8220 Mon Sep 17 00:00:00 2001 From: ckelsel Date: Wed, 12 Jul 2017 11:34:22 +0800 Subject: ignore patch-2367,2364 --- src/nvim/version.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nvim/version.c b/src/nvim/version.c index 094ca29b01..9d57da4caa 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -77,10 +77,10 @@ static char *features[] = { // clang-format off static const int included_patches[] = { - // 2367,NA + // 2367 NA // 2366 NA // 2365 NA - // 2364,NA + // 2364 NA // 2363 NA 2362, // 2361 NA -- cgit From 5e66c429e33db1c9a272c273cb3ad95c9bf64627 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 29 Jul 2017 01:51:08 +0200 Subject: vim-patch:8.0.0090 fix breakindent bug (original Vim commit-message is bogus) https://github.com/vim/vim/commit/6c896867c4f5d759616028ef7cbfce2a9ed32600 --- src/nvim/screen.c | 8 +- src/nvim/testdir/test_breakindent.vim | 241 ++++++++++++++++++++++++++++++++++ src/nvim/version.c | 2 +- 3 files changed, 247 insertions(+), 4 deletions(-) create mode 100644 src/nvim/testdir/test_breakindent.vim diff --git a/src/nvim/screen.c b/src/nvim/screen.c index cd4f4de40f..e3a2c1ffec 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2195,7 +2195,7 @@ win_line ( int change_start = MAXCOL; /* first col of changed area */ int change_end = -1; /* last col of changed area */ colnr_T trailcol = MAXCOL; /* start of trailing spaces */ - int need_showbreak = FALSE; + int need_showbreak = false; // overlong line, skip first x chars int line_attr = 0; /* attribute for the whole line */ matchitem_T *cur; /* points to the match list */ match_T *shl; /* points to search_hl or a match */ @@ -2805,8 +2805,10 @@ win_line ( // draw 'breakindent': indent wrapped text accodringly if (draw_state == WL_BRI - 1 && n_extra == 0) { draw_state = WL_BRI; - if (wp->w_p_bri && row != startrow && filler_lines == 0) { - char_attr = wp->w_hl_attr_normal; // was: hl_attr(HLF_AT); + // if need_showbreak is set, breakindent also applies + if (wp->w_p_bri && (row != startrow || need_showbreak) + && filler_lines == 0) { + char_attr = wp->w_hl_attr_normal; if (diff_hlf != (hlf_T)0) { char_attr = win_hl_attr(wp, diff_hlf); diff --git a/src/nvim/testdir/test_breakindent.vim b/src/nvim/testdir/test_breakindent.vim new file mode 100644 index 0000000000..bf363dcf8c --- /dev/null +++ b/src/nvim/testdir/test_breakindent.vim @@ -0,0 +1,241 @@ +" Test for breakindent +" +" Note: if you get strange failures when adding new tests, it might be that +" while the test is run, the breakindent cacheing gets in its way. +" It helps to change the tabastop setting and force a redraw (e.g. see +" Test_breakindent08()) +if !exists('+breakindent') + finish +endif + +let s:input ="\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP" + +function s:screenline(lnum, width) abort + " always get 4 screen lines + redraw! + let line = [] + for j in range(3) + for c in range(1, a:width) + call add(line, nr2char(screenchar(a:lnum+j, c))) + endfor + call add(line, "\n") + endfor + return join(line, '') +endfunction + +function s:testwindows(...) + 10new + vsp + vert resize 20 + setl ts=4 sw=4 sts=4 breakindent + put =s:input + if a:0 + exe a:1 + endif +endfunction + +function s:close_windows(...) + bw! + if a:0 + exe a:1 + endif + unlet! g:line g:expect +endfunction + +function Test_breakindent01() + " simple breakindent test + call s:testwindows('setl briopt=min:0') + let g:line=s:screenline(line('.'),8) + let g:expect=" abcd\n qrst\n GHIJ\n" + call assert_equal(g:expect, g:line) + call s:close_windows() +endfunction + +function Test_breakindent02() + " simple breakindent test with showbreak set + call s:testwindows('setl briopt=min:0 sbr=>>') + let g:line=s:screenline(line('.'),8) + let g:expect=" abcd\n >>qr\n >>EF\n" + call assert_equal(g:expect, g:line) + call s:close_windows('set sbr=') +endfunction + +function Test_breakindent03() + " simple breakindent test with showbreak set and briopt including sbr + call s:testwindows('setl briopt=sbr,min:0 sbr=++') + let g:line=s:screenline(line('.'),8) + let g:expect=" abcd\n++ qrst\n++ GHIJ\n" + call assert_equal(g:expect, g:line) + " clean up + call s:close_windows('set sbr=') +endfunction + +function Test_breakindent04() + " breakindent set with min width 18 + call s:testwindows('setl sbr= briopt=min:18') + let g:line=s:screenline(line('.'),8) + let g:expect=" abcd\n qrstuv\n IJKLMN\n" + call assert_equal(g:expect, g:line) + " clean up + call s:close_windows('set sbr=') +endfunction + +function Test_breakindent05() + " breakindent set and shift by 2 + call s:testwindows('setl briopt=shift:2,min:0') + let g:line=s:screenline(line('.'),8) + let g:expect=" abcd\n qr\n EF\n" + call assert_equal(g:expect, g:line) + call s:close_windows() +endfunction + +function Test_breakindent06() + " breakindent set and shift by -1 + call s:testwindows('setl briopt=shift:-1,min:0') + let g:line=s:screenline(line('.'),8) + let g:expect=" abcd\n qrstu\n HIJKL\n" + call assert_equal(g:expect, g:line) + call s:close_windows() +endfunction + +function Test_breakindent07() + " breakindent set and shift by 1, Number set sbr=? and briopt:sbr + call s:testwindows('setl briopt=shift:1,sbr,min:0 nu sbr=? nuw=4 cpo+=n') + let g:line=s:screenline(line('.'),10) + let g:expect=" 2 ab\n? m\n? x\n" + call assert_equal(g:expect, g:line) + " clean up + call s:close_windows('set sbr= cpo-=n') +endfunction + +function Test_breakindent07a() + " breakindent set and shift by 1, Number set sbr=? and briopt:sbr + call s:testwindows('setl briopt=shift:1,sbr,min:0 nu sbr=? nuw=4') + let g:line=s:screenline(line('.'),10) + let g:expect=" 2 ab\n ? m\n ? x\n" + call assert_equal(g:expect, g:line) + " clean up + call s:close_windows('set sbr=') +endfunction + +function Test_breakindent08() + " breakindent set and shift by 1, Number and list set sbr=# and briopt:sbr + call s:testwindows('setl briopt=shift:1,sbr,min:0 nu nuw=4 sbr=# list cpo+=n ts=4') + " make sure, cache is invalidated! + set ts=8 + redraw! + set ts=4 + redraw! + let g:line=s:screenline(line('.'),10) + let g:expect=" 2 ^Iabcd\n# opq\n# BCD\n" + call assert_equal(g:expect, g:line) + call s:close_windows('set sbr= cpo-=n') +endfunction + +function Test_breakindent08a() + " breakindent set and shift by 1, Number and list set sbr=# and briopt:sbr + call s:testwindows('setl briopt=shift:1,sbr,min:0 nu nuw=4 sbr=# list') + let g:line=s:screenline(line('.'),10) + let g:expect=" 2 ^Iabcd\n # opq\n # BCD\n" + call assert_equal(g:expect, g:line) + call s:close_windows('set sbr=') +endfunction + +function Test_breakindent09() + " breakindent set and shift by 1, Number and list set sbr=# + call s:testwindows('setl briopt=shift:1,min:0 nu nuw=4 sbr=# list') + let g:line=s:screenline(line('.'),10) + let g:expect=" 2 ^Iabcd\n #op\n #AB\n" + call assert_equal(g:expect, g:line) + call s:close_windows('set sbr=') +endfunction + +function Test_breakindent10() + " breakindent set, Number set sbr=~ + call s:testwindows('setl cpo+=n sbr=~ nu nuw=4 nolist briopt=sbr,min:0') + " make sure, cache is invalidated! + set ts=8 + redraw! + set ts=4 + redraw! + let g:line=s:screenline(line('.'),10) + let g:expect=" 2 ab\n~ mn\n~ yz\n" + call assert_equal(g:expect, g:line) + call s:close_windows('set sbr= cpo-=n') +endfunction + +function Test_breakindent11() + " test strdisplaywidth() + call s:testwindows('setl cpo-=n sbr=>> nu nuw=4 nolist briopt= ts=4') + let text=getline(2) + let width = strlen(text[1:])+indent(2)+strlen(&sbr)*3 " text wraps 3 times + call assert_equal(width, strdisplaywidth(text)) + call s:close_windows('set sbr=') +endfunction + +function Test_breakindent12() + " test breakindent with long indent + let s:input="\t\t\t\t\t{" + call s:testwindows('setl breakindent linebreak briopt=min:10 nu numberwidth=3 ts=4 list listchars=tab:>-') + let g:line=s:screenline(2,16) + let g:expect=" 2 >--->--->--->\n ---{ \n~ \n" + call assert_equal(g:expect, g:line) + call s:close_windows('set nuw=4 listchars=') +endfunction + +function Test_breakindent13() + let s:input="" + call s:testwindows('setl breakindent briopt=min:10 ts=8') + vert resize 20 + call setline(1, [" a\tb\tc\td\te", " z y x w v"]) + 1 + norm! fbgj"ayl + 2 + norm! fygj"byl + call assert_equal('d', @a) + call assert_equal('w', @b) + call s:close_windows() +endfunction + +function Test_breakindent14() + let s:input="" + call s:testwindows('setl breakindent briopt= ts=8') + vert resize 30 + norm! 3a1234567890 + norm! a abcde + exec "norm! 0\tex" + let g:line=s:screenline(line('.'),8) + let g:expect="e \n~ \n~ \n" + call assert_equal(g:expect, g:line) + call s:close_windows() +endfunction + +function Test_breakindent15() + let s:input="" + call s:testwindows('setl breakindent briopt= ts=8 sw=8') + vert resize 30 + norm! 4a1234567890 + exe "normal! >>\3f0x" + let g:line=s:screenline(line('.'),20) + let g:expect=" 1234567890 \n~ \n~ \n" + call assert_equal(g:expect, g:line) + call s:close_windows() +endfunction + +function Test_breakindent16() + " Check that overlong lines are indented correctly. + " TODO: currently it does not fail even when the bug is not fixed. + let s:input="" + call s:testwindows('setl breakindent briopt=min:0 ts=4') + call setline(1, "\t".repeat("1234567890", 10)) + resize 6 + norm! 1gg$ + redraw! + let g:line=s:screenline(1,10) + let g:expect=" 123456\n 789012\n 345678\n" + call assert_equal(g:expect, g:line) + let g:line=s:screenline(4,10) + let g:expect=" 901234\n 567890\n 123456\n" + call assert_equal(g:expect, g:line) + call s:close_windows() +endfunction diff --git a/src/nvim/version.c b/src/nvim/version.c index 72af7dbafd..69d5cb8e8d 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -862,7 +862,7 @@ static const int included_patches[] = { // 93 NA // 92, // 91, - // 90, + 90, // 89 NA 88, // 87 NA -- cgit From dfd45f26f14179c6a4c75f06814c0ff6c0792349 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 29 Jul 2017 02:26:21 +0200 Subject: vim-patch:8.0.0126 Problem: Display problem with 'foldcolumn' and a wide character. (esiegerman) Solution: Don't use "extra" but an allocated buffer. (Christian Brabandt, closes vim/vim#1310) https://github.com/vim/vim/commit/6270660611a151c5d0f614a5f0248ccdc80ed971 --- src/nvim/screen.c | 19 ++++++++++++------- src/nvim/testdir/test_display.vim | 37 +++++++++++++++++++++++++++++++++++++ src/nvim/version.c | 2 +- 3 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 src/nvim/testdir/test_display.vim diff --git a/src/nvim/screen.c b/src/nvim/screen.c index e3a2c1ffec..3d558bdbdd 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2705,13 +2705,18 @@ win_line ( draw_state = WL_FOLD; if (fdc > 0) { - // Draw the 'foldcolumn'. - fill_foldcolumn(extra, wp, false, lnum); - n_extra = fdc; - p_extra = extra; - p_extra[n_extra] = NUL; - c_extra = NUL; - char_attr = win_hl_attr(wp, HLF_FC); + // Draw the 'foldcolumn'. Allocate a buffer, "extra" may + // already be in used. + p_extra_free = xmalloc(12 + 1); + + if (p_extra_free != NULL) { + fill_foldcolumn(p_extra_free, wp, false, lnum); + n_extra = fdc; + p_extra_free[n_extra] = NUL; + p_extra = p_extra_free; + c_extra = NUL; + char_attr = win_hl_attr(wp, HLF_FC); + } } } diff --git a/src/nvim/testdir/test_display.vim b/src/nvim/testdir/test_display.vim new file mode 100644 index 0000000000..ba7b7d7626 --- /dev/null +++ b/src/nvim/testdir/test_display.vim @@ -0,0 +1,37 @@ +" Test for displaying stuff +if !has('gui_running') && has('unix') + set term=ansi +endif + +function! s:screenline(lnum, nr) abort + let line = [] + for j in range(a:nr) + for c in range(1, winwidth(0)) + call add(line, nr2char(screenchar(a:lnum+j, c))) + endfor + call add(line, "\n") + endfor + return join(line, '') +endfunction + +function! Test_display_foldcolumn() + new + vnew + vert resize 25 + + 1put='e more noise blah blah‚ more stuff here' + + let expect = "e more noise blah blah<82\n> more stuff here \n" + + call cursor(2, 1) + norm! zt + redraw! + call assert_equal(expect, s:screenline(1,2)) + set fdc=2 + redraw! + let expect = " e more noise blah blah<\n 82> more stuff here \n" + call assert_equal(expect, s:screenline(1,2)) + + quit! + quit! +endfunction diff --git a/src/nvim/version.c b/src/nvim/version.c index 69d5cb8e8d..ca1d64ac56 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -826,7 +826,7 @@ static const int included_patches[] = { // 129 NA // 128, 127, - // 126, + 126, // 125, 124, // 123 NA -- cgit From 247c3385178383b7a4451210cbef22fe83427f92 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 29 Jul 2017 02:30:54 +0200 Subject: vim-patch:8.0.0128 Problem: Display test fails on MS-Windows. Solution: Set 'isprint' to "@". https://github.com/vim/vim/commit/7089237885218eb8a19805bc2b75481c4efcd6ba --- src/nvim/testdir/test_display.vim | 2 ++ src/nvim/version.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nvim/testdir/test_display.vim b/src/nvim/testdir/test_display.vim index ba7b7d7626..609e16c737 100644 --- a/src/nvim/testdir/test_display.vim +++ b/src/nvim/testdir/test_display.vim @@ -18,6 +18,8 @@ function! Test_display_foldcolumn() new vnew vert resize 25 + call assert_equal(25, winwidth(winnr())) + set isprint=@ 1put='e more noise blah blah‚ more stuff here' diff --git a/src/nvim/version.c b/src/nvim/version.c index ca1d64ac56..dfee84c1b2 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -824,7 +824,7 @@ static const int included_patches[] = { // 131, // 130 NA // 129 NA - // 128, + 128, 127, 126, // 125, -- cgit From f5e55e93aa4b390e455d825a076cc0c29ba0e933 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 29 Jul 2017 01:46:43 +0200 Subject: vim-patch:8.0.0311 Problem: Linebreak tests are old style. Solution: Turn the tests into new style. Share utility functions. (Ozaki Kiichi, closes vim/vim#1444) https://github.com/vim/vim/commit/544d3bc9f0e494cb712a33b61558b8e8e12b1e0b --- src/nvim/testdir/test_breakindent.vim | 250 ++++++++++++++++++++------------- src/nvim/testdir/test_listlbr.vim | 219 +++++++++++++++++++++++++++++ src/nvim/testdir/test_listlbr_utf8.vim | 195 +++++++++++++++++++++++++ src/nvim/testdir/view_util.vim | 30 ++++ src/nvim/version.c | 2 +- 5 files changed, 599 insertions(+), 97 deletions(-) create mode 100644 src/nvim/testdir/test_listlbr.vim create mode 100644 src/nvim/testdir/test_listlbr_utf8.vim create mode 100644 src/nvim/testdir/view_util.vim diff --git a/src/nvim/testdir/test_breakindent.vim b/src/nvim/testdir/test_breakindent.vim index bf363dcf8c..8721b35cdf 100644 --- a/src/nvim/testdir/test_breakindent.vim +++ b/src/nvim/testdir/test_breakindent.vim @@ -2,171 +2,209 @@ " " Note: if you get strange failures when adding new tests, it might be that " while the test is run, the breakindent cacheing gets in its way. -" It helps to change the tabastop setting and force a redraw (e.g. see +" It helps to change the tabstop setting and force a redraw (e.g. see " Test_breakindent08()) if !exists('+breakindent') finish endif +source view_util.vim + let s:input ="\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP" -function s:screenline(lnum, width) abort - " always get 4 screen lines - redraw! - let line = [] - for j in range(3) - for c in range(1, a:width) - call add(line, nr2char(screenchar(a:lnum+j, c))) - endfor - call add(line, "\n") - endfor - return join(line, '') -endfunction - -function s:testwindows(...) - 10new - vsp - vert resize 20 - setl ts=4 sw=4 sts=4 breakindent +function s:screen_lines(lnum, width) abort + return ScreenLines([a:lnum, a:lnum + 2], a:width) +endfunction + +function! s:compare_lines(expect, actual) + call assert_equal(join(a:expect, "\n"), join(a:actual, "\n")) +endfunction + +function s:test_windows(...) + call NewWindow(10, 20) + setl ts=4 sw=4 sts=4 breakindent put =s:input - if a:0 - exe a:1 - endif + exe get(a:000, 0, '') endfunction function s:close_windows(...) - bw! - if a:0 - exe a:1 - endif - unlet! g:line g:expect + call CloseWindow() + exe get(a:000, 0, '') endfunction function Test_breakindent01() " simple breakindent test - call s:testwindows('setl briopt=min:0') - let g:line=s:screenline(line('.'),8) - let g:expect=" abcd\n qrst\n GHIJ\n" - call assert_equal(g:expect, g:line) + call s:test_windows('setl briopt=min:0') + let lines=s:screen_lines(line('.'),8) + let expect=[ +\ " abcd", +\ " qrst", +\ " GHIJ", +\ ] + call s:compare_lines(expect, lines) call s:close_windows() endfunction function Test_breakindent02() " simple breakindent test with showbreak set - call s:testwindows('setl briopt=min:0 sbr=>>') - let g:line=s:screenline(line('.'),8) - let g:expect=" abcd\n >>qr\n >>EF\n" - call assert_equal(g:expect, g:line) + call s:test_windows('setl briopt=min:0 sbr=>>') + let lines=s:screen_lines(line('.'),8) + let expect=[ +\ " abcd", +\ " >>qr", +\ " >>EF", +\ ] + call s:compare_lines(expect, lines) call s:close_windows('set sbr=') endfunction function Test_breakindent03() " simple breakindent test with showbreak set and briopt including sbr - call s:testwindows('setl briopt=sbr,min:0 sbr=++') - let g:line=s:screenline(line('.'),8) - let g:expect=" abcd\n++ qrst\n++ GHIJ\n" - call assert_equal(g:expect, g:line) + call s:test_windows('setl briopt=sbr,min:0 sbr=++') + let lines=s:screen_lines(line('.'),8) + let expect=[ +\ " abcd", +\ "++ qrst", +\ "++ GHIJ", +\ ] + call s:compare_lines(expect, lines) " clean up call s:close_windows('set sbr=') endfunction function Test_breakindent04() " breakindent set with min width 18 - call s:testwindows('setl sbr= briopt=min:18') - let g:line=s:screenline(line('.'),8) - let g:expect=" abcd\n qrstuv\n IJKLMN\n" - call assert_equal(g:expect, g:line) + call s:test_windows('setl sbr= briopt=min:18') + let lines=s:screen_lines(line('.'),8) + let expect=[ +\ " abcd", +\ " qrstuv", +\ " IJKLMN", +\ ] + call s:compare_lines(expect, lines) " clean up call s:close_windows('set sbr=') endfunction function Test_breakindent05() " breakindent set and shift by 2 - call s:testwindows('setl briopt=shift:2,min:0') - let g:line=s:screenline(line('.'),8) - let g:expect=" abcd\n qr\n EF\n" - call assert_equal(g:expect, g:line) + call s:test_windows('setl briopt=shift:2,min:0') + let lines=s:screen_lines(line('.'),8) + let expect=[ +\ " abcd", +\ " qr", +\ " EF", +\ ] + call s:compare_lines(expect, lines) call s:close_windows() endfunction function Test_breakindent06() " breakindent set and shift by -1 - call s:testwindows('setl briopt=shift:-1,min:0') - let g:line=s:screenline(line('.'),8) - let g:expect=" abcd\n qrstu\n HIJKL\n" - call assert_equal(g:expect, g:line) + call s:test_windows('setl briopt=shift:-1,min:0') + let lines=s:screen_lines(line('.'),8) + let expect=[ +\ " abcd", +\ " qrstu", +\ " HIJKL", +\ ] + call s:compare_lines(expect, lines) call s:close_windows() endfunction function Test_breakindent07() " breakindent set and shift by 1, Number set sbr=? and briopt:sbr - call s:testwindows('setl briopt=shift:1,sbr,min:0 nu sbr=? nuw=4 cpo+=n') - let g:line=s:screenline(line('.'),10) - let g:expect=" 2 ab\n? m\n? x\n" - call assert_equal(g:expect, g:line) + call s:test_windows('setl briopt=shift:1,sbr,min:0 nu sbr=? nuw=4 cpo+=n') + let lines=s:screen_lines(line('.'),10) + let expect=[ +\ " 2 ab", +\ "? m", +\ "? x", +\ ] + call s:compare_lines(expect, lines) " clean up call s:close_windows('set sbr= cpo-=n') endfunction function Test_breakindent07a() " breakindent set and shift by 1, Number set sbr=? and briopt:sbr - call s:testwindows('setl briopt=shift:1,sbr,min:0 nu sbr=? nuw=4') - let g:line=s:screenline(line('.'),10) - let g:expect=" 2 ab\n ? m\n ? x\n" - call assert_equal(g:expect, g:line) + call s:test_windows('setl briopt=shift:1,sbr,min:0 nu sbr=? nuw=4') + let lines=s:screen_lines(line('.'),10) + let expect=[ +\ " 2 ab", +\ " ? m", +\ " ? x", +\ ] + call s:compare_lines(expect, lines) " clean up call s:close_windows('set sbr=') endfunction function Test_breakindent08() " breakindent set and shift by 1, Number and list set sbr=# and briopt:sbr - call s:testwindows('setl briopt=shift:1,sbr,min:0 nu nuw=4 sbr=# list cpo+=n ts=4') + call s:test_windows('setl briopt=shift:1,sbr,min:0 nu nuw=4 sbr=# list cpo+=n ts=4') " make sure, cache is invalidated! set ts=8 redraw! set ts=4 redraw! - let g:line=s:screenline(line('.'),10) - let g:expect=" 2 ^Iabcd\n# opq\n# BCD\n" - call assert_equal(g:expect, g:line) + let lines=s:screen_lines(line('.'),10) + let expect=[ +\ " 2 ^Iabcd", +\ "# opq", +\ "# BCD", +\ ] + call s:compare_lines(expect, lines) call s:close_windows('set sbr= cpo-=n') endfunction function Test_breakindent08a() " breakindent set and shift by 1, Number and list set sbr=# and briopt:sbr - call s:testwindows('setl briopt=shift:1,sbr,min:0 nu nuw=4 sbr=# list') - let g:line=s:screenline(line('.'),10) - let g:expect=" 2 ^Iabcd\n # opq\n # BCD\n" - call assert_equal(g:expect, g:line) + call s:test_windows('setl briopt=shift:1,sbr,min:0 nu nuw=4 sbr=# list') + let lines=s:screen_lines(line('.'),10) + let expect=[ +\ " 2 ^Iabcd", +\ " # opq", +\ " # BCD", +\ ] + call s:compare_lines(expect, lines) call s:close_windows('set sbr=') endfunction function Test_breakindent09() " breakindent set and shift by 1, Number and list set sbr=# - call s:testwindows('setl briopt=shift:1,min:0 nu nuw=4 sbr=# list') - let g:line=s:screenline(line('.'),10) - let g:expect=" 2 ^Iabcd\n #op\n #AB\n" - call assert_equal(g:expect, g:line) + call s:test_windows('setl briopt=shift:1,min:0 nu nuw=4 sbr=# list') + let lines=s:screen_lines(line('.'),10) + let expect=[ +\ " 2 ^Iabcd", +\ " #op", +\ " #AB", +\ ] + call s:compare_lines(expect, lines) call s:close_windows('set sbr=') endfunction function Test_breakindent10() " breakindent set, Number set sbr=~ - call s:testwindows('setl cpo+=n sbr=~ nu nuw=4 nolist briopt=sbr,min:0') + call s:test_windows('setl cpo+=n sbr=~ nu nuw=4 nolist briopt=sbr,min:0') " make sure, cache is invalidated! set ts=8 redraw! set ts=4 redraw! - let g:line=s:screenline(line('.'),10) - let g:expect=" 2 ab\n~ mn\n~ yz\n" - call assert_equal(g:expect, g:line) + let lines=s:screen_lines(line('.'),10) + let expect=[ +\ " 2 ab", +\ "~ mn", +\ "~ yz", +\ ] + call s:compare_lines(expect, lines) call s:close_windows('set sbr= cpo-=n') endfunction function Test_breakindent11() " test strdisplaywidth() - call s:testwindows('setl cpo-=n sbr=>> nu nuw=4 nolist briopt= ts=4') + call s:test_windows('setl cpo-=n sbr=>> nu nuw=4 nolist briopt= ts=4') let text=getline(2) let width = strlen(text[1:])+indent(2)+strlen(&sbr)*3 " text wraps 3 times call assert_equal(width, strdisplaywidth(text)) @@ -176,16 +214,20 @@ endfunction function Test_breakindent12() " test breakindent with long indent let s:input="\t\t\t\t\t{" - call s:testwindows('setl breakindent linebreak briopt=min:10 nu numberwidth=3 ts=4 list listchars=tab:>-') - let g:line=s:screenline(2,16) - let g:expect=" 2 >--->--->--->\n ---{ \n~ \n" - call assert_equal(g:expect, g:line) + call s:test_windows('setl breakindent linebreak briopt=min:10 nu numberwidth=3 ts=4 list listchars=tab:>-') + let lines=s:screen_lines(2,16) + let expect=[ +\ " 2 >--->--->--->", +\ " ---{ ", +\ "~ ", +\ ] + call s:compare_lines(expect, lines) call s:close_windows('set nuw=4 listchars=') endfunction function Test_breakindent13() let s:input="" - call s:testwindows('setl breakindent briopt=min:10 ts=8') + call s:test_windows('setl breakindent briopt=min:10 ts=8') vert resize 20 call setline(1, [" a\tb\tc\td\te", " z y x w v"]) 1 @@ -199,26 +241,34 @@ endfunction function Test_breakindent14() let s:input="" - call s:testwindows('setl breakindent briopt= ts=8') + call s:test_windows('setl breakindent briopt= ts=8') vert resize 30 norm! 3a1234567890 norm! a abcde exec "norm! 0\tex" - let g:line=s:screenline(line('.'),8) - let g:expect="e \n~ \n~ \n" - call assert_equal(g:expect, g:line) + let lines=s:screen_lines(line('.'),8) + let expect=[ +\ "e ", +\ "~ ", +\ "~ ", +\ ] + call s:compare_lines(expect, lines) call s:close_windows() endfunction function Test_breakindent15() let s:input="" - call s:testwindows('setl breakindent briopt= ts=8 sw=8') + call s:test_windows('setl breakindent briopt= ts=8 sw=8') vert resize 30 norm! 4a1234567890 exe "normal! >>\3f0x" - let g:line=s:screenline(line('.'),20) - let g:expect=" 1234567890 \n~ \n~ \n" - call assert_equal(g:expect, g:line) + let lines=s:screen_lines(line('.'),20) + let expect=[ +\ " 1234567890 ", +\ "~ ", +\ "~ ", +\ ] + call s:compare_lines(expect, lines) call s:close_windows() endfunction @@ -226,16 +276,24 @@ function Test_breakindent16() " Check that overlong lines are indented correctly. " TODO: currently it does not fail even when the bug is not fixed. let s:input="" - call s:testwindows('setl breakindent briopt=min:0 ts=4') + call s:test_windows('setl breakindent briopt=min:0 ts=4') call setline(1, "\t".repeat("1234567890", 10)) resize 6 norm! 1gg$ redraw! - let g:line=s:screenline(1,10) - let g:expect=" 123456\n 789012\n 345678\n" - call assert_equal(g:expect, g:line) - let g:line=s:screenline(4,10) - let g:expect=" 901234\n 567890\n 123456\n" - call assert_equal(g:expect, g:line) + let lines=s:screen_lines(1,10) + let expect=[ +\ " 123456", +\ " 789012", +\ " 345678", +\ ] + call s:compare_lines(expect, lines) + let lines=s:screen_lines(4,10) + let expect=[ +\ " 901234", +\ " 567890", +\ " 123456", +\ ] + call s:compare_lines(expect, lines) call s:close_windows() endfunction diff --git a/src/nvim/testdir/test_listlbr.vim b/src/nvim/testdir/test_listlbr.vim new file mode 100644 index 0000000000..71366a161e --- /dev/null +++ b/src/nvim/testdir/test_listlbr.vim @@ -0,0 +1,219 @@ +" Test for linebreak and list option (non-utf8) + +set encoding=latin1 +scriptencoding latin1 + +if !exists("+linebreak") || !has("conceal") + finish +endif + +source view_util.vim + +function s:screen_lines(lnum, width) abort + return ScreenLines(a:lnum, a:width) +endfunction + +function! s:compare_lines(expect, actual) + call assert_equal(join(a:expect, "\n"), join(a:actual, "\n")) +endfunction + +function s:test_windows(...) + call NewWindow(10, 20) + setl ts=8 sw=4 sts=4 linebreak sbr= wrap + exe get(a:000, 0, '') +endfunction + +function s:close_windows(...) + call CloseWindow() + exe get(a:000, 0, '') +endfunction + +func Test_set_linebreak() + call s:test_windows('setl ts=4 sbr=+') + call setline(1, "\tabcdef hijklmn\tpqrstuvwxyz_1060ABCDEFGHIJKLMNOP ") + let lines = s:screen_lines([1, 4], winwidth(0)) + let expect = [ +\ " abcdef ", +\ "+hijklmn ", +\ "+pqrstuvwxyz_1060ABC", +\ "+DEFGHIJKLMNOP ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc + +func Test_linebreak_with_list() + call s:test_windows('setl ts=4 sbr=+ list listchars=') + call setline(1, "\tabcdef hijklmn\tpqrstuvwxyz_1060ABCDEFGHIJKLMNOP ") + let lines = s:screen_lines([1, 4], winwidth(0)) + let expect = [ +\ "^Iabcdef hijklmn^I ", +\ "+pqrstuvwxyz_1060ABC", +\ "+DEFGHIJKLMNOP ", +\ "~ ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc + +func Test_linebreak_with_nolist() + call s:test_windows('setl ts=4 sbr=+ nolist') + call setline(1, "\tabcdef hijklmn\tpqrstuvwxyz_1060ABCDEFGHIJKLMNOP ") + let lines = s:screen_lines([1, 4], winwidth(0)) + let expect = [ +\ " abcdef ", +\ "+hijklmn ", +\ "+pqrstuvwxyz_1060ABC", +\ "+DEFGHIJKLMNOP ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc + +func Test_should_break() + call s:test_windows('setl sbr=+ nolist') + call setline(1, "1\t" . repeat('a', winwidth(0)-2)) + let lines = s:screen_lines([1, 4], winwidth(0)) + let expect = [ +\ "1 ", +\ "+aaaaaaaaaaaaaaaaaa ", +\ "~ ", +\ "~ ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc + +func Test_linebreak_with_conceal() + call s:test_windows('setl cpo&vim sbr=+ list conceallevel=2 concealcursor=nv listchars=tab:ab') + call setline(1, "_S_\t bla") + syn match ConcealVar contained /_/ conceal + syn match All /.*/ contains=ConcealVar + let lines = s:screen_lines([1, 4], winwidth(0)) + let expect = [ +\ "Sabbbbbb bla ", +\ "~ ", +\ "~ ", +\ "~ ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc + +func Test_virtual_block() + call s:test_windows('setl sbr=+') + call setline(1, [ +\ "REMOVE: this not", +\ "REMOVE: aaaaaaaaaaaaa", +\ ]) + exe "norm! 1/^REMOVE:" + exe "norm! 0\jf x" + $put + let lines = s:screen_lines([1, 4], winwidth(0)) + let expect = [ +\ "this not ", +\ "aaaaaaaaaaaaa ", +\ "REMOVE: ", +\ "REMOVE: ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc + +func Test_virtual_block_and_vbA() + call s:test_windows() + call setline(1, "long line: " . repeat("foobar ", 40) . "TARGET at end") + exe "norm! $3B\eAx\" + let lines = s:screen_lines([1, 10], winwidth(0)) + let expect = [ +\ "foobar foobar ", +\ "foobar foobar ", +\ "foobar foobar ", +\ "foobar foobar ", +\ "foobar foobar ", +\ "foobar foobar ", +\ "foobar foobar ", +\ "foobar foobar ", +\ "foobar foobar ", +\ "foobar TARGETx at ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc + +func Test_virtual_char_and_block() + call s:test_windows() + call setline(1, "1111-1111-1111-11-1111-1111-1111") + exe "norm! 0f-lv3lc2222\bgj." + let lines = s:screen_lines([1, 2], winwidth(0)) + let expect = [ +\ "1111-2222-1111-11- ", +\ "1111-2222-1111 ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc + +func Test_undo_after_block_visual() + call s:test_windows() + call setline(1, ["aaa", "aaa", "a"]) + exe "norm! gg\2j~e." + let lines = s:screen_lines([1, 3], winwidth(0)) + let expect = [ +\ "AaA ", +\ "AaA ", +\ "A ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc + +func Test_norm_after_block_visual() + call s:test_windows() + call setline(1, ["abcd{ef", "ghijklm", "no}pgrs"]) + exe "norm! ggf{\\c%" + let lines = s:screen_lines([1, 3], winwidth(0)) + let expect = [ +\ "abcdpgrs ", +\ "~ ", +\ "~ ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc + +func Test_block_replace_after_wrapping() + call s:test_windows() + call setline(1, repeat("a", 150)) + exe "norm! 0yypk147|\jr0" + call assert_equal(repeat("a", 146) . "0aaa", getline(1)) + call assert_equal(repeat("a", 146) . "0aaa", getline(2)) + let lines = s:screen_lines([1, 10], winwidth(0)) + let expect = [ +\ "aaaaaaaaaaaaaaaaaaaa", +\ "aaaaaaaaaaaaaaaaaaaa", +\ "aaaaaaaaaaaaaaaaaaaa", +\ "aaaaaaaaaaaaaaaaaaaa", +\ "aaaaaaaaaaaaaaaaaaaa", +\ "aaaaaaaaaaaaaaaaaaaa", +\ "aaaaaaaaaaaaaaaaaaaa", +\ "aaaaaa0aaa ", +\ "@ ", +\ "@ ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc + +func Test_list_with_listchars() + call s:test_windows('setl list listchars=space:_,trail:-,tab:>-,eol:$') + call setline(1, "a aaaaaaaaaaaaaaaaaaaaaa\ta ") + let lines = s:screen_lines([1, 3], winwidth(0)) + let expect = [ +\ "a_ ", +\ "aaaaaaaaaaaaaaaaaaaa", +\ "aa>-----a-$ ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc diff --git a/src/nvim/testdir/test_listlbr_utf8.vim b/src/nvim/testdir/test_listlbr_utf8.vim new file mode 100644 index 0000000000..807b6ad31a --- /dev/null +++ b/src/nvim/testdir/test_listlbr_utf8.vim @@ -0,0 +1,195 @@ +" Test for linebreak and list option in utf-8 mode + +set encoding=utf-8 +scriptencoding utf-8 + +if !exists("+linebreak") || !has("conceal") || !has("signs") + finish +endif + +source view_util.vim + +function s:screen_lines(lnum, width) abort + return ScreenLines(a:lnum, a:width) +endfunction + +function! s:compare_lines(expect, actual) + call assert_equal(a:expect, a:actual) +endfunction + +function s:screen_attr(lnum, chars, ...) abort + let line = getline(a:lnum) + let attr = [] + let prefix = get(a:000, 0, 0) + for i in range(a:chars[0], a:chars[1]) + let scol = strdisplaywidth(strcharpart(line, 0, i-1)) + 1 + let attr += [screenattr(a:lnum, scol + prefix)] + endfor + return attr +endfunction + +function s:test_windows(...) + call NewWindow(10, 20) + setl ts=4 sw=4 sts=4 linebreak sbr=+ wrap + exe get(a:000, 0, '') +endfunction + +function s:close_windows(...) + call CloseWindow() + exe get(a:000, 0, '') +endfunction + +func Test_linebreak_with_fancy_listchars() + call s:test_windows("setl list listchars=nbsp:\u2423,tab:\u2595\u2014,trail:\u02d1,eol:\ub6") + call setline(1, "\tabcdef hijklmn\tpqrstuvwxyz\u00a01060ABCDEFGHIJKLMNOP ") + redraw! + let lines = s:screen_lines([1, 4], winwidth(0)) + let expect = [ +\ "▕———abcdef ", +\ "+hijklmn▕——— ", +\ "+pqrstuvwxyz␣1060ABC", +\ "+DEFGHIJKLMNOPˑ¶ ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc + +func Test_nolinebreak_with_list() + call s:test_windows("setl nolinebreak list listchars=nbsp:\u2423,tab:\u2595\u2014,trail:\u02d1,eol:\ub6") + call setline(1, "\tabcdef hijklmn\tpqrstuvwxyz\u00a01060ABCDEFGHIJKLMNOP ") + redraw! + let lines = s:screen_lines([1, 4], winwidth(0)) + let expect = [ +\ "▕———abcdef hijklmn▕—", +\ "+pqrstuvwxyz␣1060ABC", +\ "+DEFGHIJKLMNOPˑ¶ ", +\ "~ ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc + +func Test_linebreak_with_nolist() + call s:test_windows('setl nolist') + call setline(1, "\t*mask = nil;") + redraw! + let lines = s:screen_lines([1, 4], winwidth(0)) + let expect = [ +\ " *mask = nil; ", +\ "~ ", +\ "~ ", +\ "~ ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc + +func Test_list_and_concealing1() + call s:test_windows('setl list listchars=tab:>- cole=1') + call setline(1, [ +\ "#define ABCDE\t\t1", +\ "#define ABCDEF\t\t1", +\ "#define ABCDEFG\t\t1", +\ "#define ABCDEFGH\t1", +\ "#define MSG_MODE_FILE\t\t\t1", +\ "#define MSG_MODE_CONSOLE\t\t2", +\ "#define MSG_MODE_FILE_AND_CONSOLE\t3", +\ "#define MSG_MODE_FILE_THEN_CONSOLE\t4", +\ ]) + vert resize 40 + syn match Conceal conceal cchar=>'AB\|MSG_MODE' + redraw! + let lines = s:screen_lines([1, 7], winwidth(0)) + let expect = [ +\ "#define ABCDE>-->---1 ", +\ "#define >CDEF>-->---1 ", +\ "#define >CDEFG>->---1 ", +\ "#define >CDEFGH>----1 ", +\ "#define >_FILE>--------->--->---1 ", +\ "#define >_CONSOLE>---------->---2 ", +\ "#define >_FILE_AND_CONSOLE>---------3 ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc + +func Test_list_and_concealing2() + call s:test_windows('setl nowrap ts=2 list listchars=tab:>- cole=2 concealcursor=n') + call setline(1, "bbeeeeee\t\t;\tsome text") + vert resize 40 + syn clear + syn match meaning /;\s*\zs.*/ + syn match hasword /^\x\{8}/ contains=word + syn match word /\<\x\{8}\>/ contains=beginword,endword contained + syn match beginword /\<\x\x/ contained conceal + syn match endword /\x\{6}\>/ contained + hi meaning guibg=blue + hi beginword guibg=green + hi endword guibg=red + redraw! + let lines = s:screen_lines([1, 1], winwidth(0)) + let expect = [ +\ "eeeeee>--->-;>some text ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc + +func Test_screenattr_for_comment() + call s:test_windows("setl ft=c ts=7 list listchars=nbsp:\u2423,tab:\u2595\u2014,trail:\u02d1,eol:\ub6") + call setline(1, " /*\t\t and some more */") + norm! gg0 + syntax on + hi SpecialKey term=underline ctermfg=red guifg=red + redraw! + let line = getline(1) + let attr = s:screen_attr(1, [1, 6]) + call assert_notequal(attr[0], attr[1]) + call assert_notequal(attr[1], attr[3]) + call assert_notequal(attr[3], attr[5]) + call s:close_windows() +endfunc + +func Test_visual_block_and_selection_exclusive() + call s:test_windows('setl selection=exclusive') + call setline(1, "long line: " . repeat("foobar ", 40) . "TARGETÃ' at end") + exe "norm! $3B\eAx\" + let lines = s:screen_lines([1, 10], winwidth(0)) + let expect = [ +\ "+foobar foobar ", +\ "+foobar foobar ", +\ "+foobar foobar ", +\ "+foobar foobar ", +\ "+foobar foobar ", +\ "+foobar foobar ", +\ "+foobar foobar ", +\ "+foobar foobar ", +\ "+foobar foobar ", +\ "+foobar TARGETÃx' ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc + +func Test_multibyte_sign_and_colorcolumn() + call s:test_windows("setl nolinebreak cc=3 list listchars=nbsp:\u2423,tab:\u2595\u2014,trail:\u02d1,eol:\ub6") + call setline(1, ["", "a b c", "a b c"]) + exe "sign define foo text=\uff0b" + exe "sign place 1 name=foo line=2 buffer=" . bufnr('%') + redraw! + norm! ggj0 + let signwidth = strdisplaywidth("\uff0b") + let attr1 = s:screen_attr(2, [1, 3], signwidth) + let attr2 = s:screen_attr(3, [1, 3], signwidth) + call assert_equal(attr1[0], attr2[0]) + call assert_equal(attr1[1], attr2[1]) + call assert_equal(attr1[2], attr2[2]) + let lines = s:screen_lines([1, 3], winwidth(0)) + let expect = [ +\ " ¶ ", +\ "+a b c¶ ", +\ " a b c¶ ", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfunc diff --git a/src/nvim/testdir/view_util.vim b/src/nvim/testdir/view_util.vim new file mode 100644 index 0000000000..eb92630761 --- /dev/null +++ b/src/nvim/testdir/view_util.vim @@ -0,0 +1,30 @@ +" Functions about view shared by several tests + +" ScreenLines(lnum, width) or +" ScreenLines([start, end], width) +function! ScreenLines(lnum, width) abort + redraw! + if type(a:lnum) == v:t_list + let start = a:lnum[0] + let end = a:lnum[1] + else + let start = a:lnum + let end = a:lnum + endif + let lines = [] + for l in range(start, end) + let lines += [join(map(range(1, a:width), 'nr2char(screenchar(l, v:val))'), '')] + endfor + return lines +endfunction + +function! NewWindow(height, width) abort + exe a:height . 'new' + exe a:width . 'vsp' + redraw! +endfunction + +function! CloseWindow() abort + bw! + redraw! +endfunction diff --git a/src/nvim/version.c b/src/nvim/version.c index dfee84c1b2..7fca8aee82 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -641,7 +641,7 @@ static const int included_patches[] = { // 314, // 313, // 312, - // 311, + 311, // 310, // 309, // 308, -- cgit From a7b98246b3385d3cacfe5c0691c83f7558c2143e Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 29 Jul 2017 02:11:31 +0200 Subject: vim-patch:8.0.0290 vim-patch:8.0.0394 vim-patch:8.0.0290: cursor positioning wrong if wide character wraps Problem: If a wide character doesn't fit at the end of the screen line, and the line doesn't fit on the screen, then the cursor position may be wrong. (anliting) Solution: Don't skip over wide character. (Christian Brabandt, closes vim/1408) vim-patch:8.0.0394 Problem: Tabs are not aligned when scrolling horizontally and a Tab doesn't fit. (Axel Bender) Solution: Handle a Tab as a not fitting character. (Christian Brabandt) Also fix that ":redraw" does not scroll horizontally to show the cursor. And fix the test that depended on the old behavior. https://github.com/vim/vim/commit/abc39ab642791ae3d22a524516eeedb673a95d9d --- src/nvim/ex_docmd.c | 1 + src/nvim/screen.c | 24 ++++++++++++++---------- src/nvim/testdir/test_breakindent.vim | 5 ++--- src/nvim/testdir/test_listlbr.vim | 16 ++++++++++++++++ src/nvim/testdir/test_listlbr_utf8.vim | 34 ++++++++++++++++++++++++++++++++++ src/nvim/version.c | 4 ++-- 6 files changed, 69 insertions(+), 15 deletions(-) diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 29788a9865..6e7938046a 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -7690,6 +7690,7 @@ static void ex_redraw(exarg_T *eap) RedrawingDisabled = 0; p_lz = FALSE; + validate_cursor(); update_topline(); update_screen(eap->forceit ? CLEAR : VIsual_active ? INVERTED : diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 3d558bdbdd..27701c4643 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2112,16 +2112,16 @@ win_line ( bool nochange /* not updating for changed text */ ) { - int col; /* visual column on screen */ - unsigned off; /* offset in ScreenLines/ScreenAttrs */ - int c = 0; /* init for GCC */ - long vcol = 0; /* virtual column (for tabs) */ + int col = 0; // visual column on screen + unsigned off; // offset in ScreenLines/ScreenAttrs + int c = 0; // init for GCC + long vcol = 0; // virtual column (for tabs) long vcol_sbr = -1; // virtual column after showbreak - long vcol_prev = -1; /* "vcol" of previous character */ - char_u *line; /* current line */ - char_u *ptr; /* current position in "line" */ - int row; /* row in the window, excl w_winrow */ - int screen_row; /* row on the screen, incl w_winrow */ + long vcol_prev = -1; // "vcol" of previous character + char_u *line; // current line + char_u *ptr; // current position in "line" + int row; // row in the window, excl w_winrow + int screen_row; // row on the screen, incl w_winrow char_u extra[18]; /* line number and 'fdc' must fit in here */ int n_extra = 0; /* number of extra chars */ @@ -2522,7 +2522,11 @@ win_line ( if (vcol > v) { vcol -= c; ptr = prev_ptr; - n_skip = v - vcol; + // If the character fits on the screen, don't need to skip it. + // Except for a TAB. + if (((*mb_ptr2cells)(ptr) >= c || *ptr == TAB) && col == 0) { + n_skip = v - vcol; + } } /* diff --git a/src/nvim/testdir/test_breakindent.vim b/src/nvim/testdir/test_breakindent.vim index 8721b35cdf..7deffbe452 100644 --- a/src/nvim/testdir/test_breakindent.vim +++ b/src/nvim/testdir/test_breakindent.vim @@ -274,7 +274,6 @@ endfunction function Test_breakindent16() " Check that overlong lines are indented correctly. - " TODO: currently it does not fail even when the bug is not fixed. let s:input="" call s:test_windows('setl breakindent briopt=min:0 ts=4') call setline(1, "\t".repeat("1234567890", 10)) @@ -283,16 +282,16 @@ function Test_breakindent16() redraw! let lines=s:screen_lines(1,10) let expect=[ -\ " 123456", \ " 789012", \ " 345678", +\ " 901234", \ ] call s:compare_lines(expect, lines) let lines=s:screen_lines(4,10) let expect=[ -\ " 901234", \ " 567890", \ " 123456", +\ " 7890 ", \ ] call s:compare_lines(expect, lines) call s:close_windows() diff --git a/src/nvim/testdir/test_listlbr.vim b/src/nvim/testdir/test_listlbr.vim index 71366a161e..7856ee82ab 100644 --- a/src/nvim/testdir/test_listlbr.vim +++ b/src/nvim/testdir/test_listlbr.vim @@ -217,3 +217,19 @@ func Test_list_with_listchars() call s:compare_lines(expect, lines) call s:close_windows() endfunc + +func Test_list_with_tab_and_skipping_first_chars() + call s:test_windows('setl list listchars=tab:>- ts=70 nowrap') + call setline(1, ["iiiiiiiiiiiiiiii\taaaaaaaaaaaaaaaaaa", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\taaaaaaaaaaaaaaaaaa", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\taaaaaaaaaaaaaaaaaa", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\taaaaaaaaaaaaaaaaaa"]) + call cursor(4,64) + norm! 2zl + let lines = s:screen_lines([1, 4], winwidth(0)) + let expect = [ +\ "---------------aaaaa", +\ "---------------aaaaa", +\ "---------------aaaaa", +\ "iiiiiiiii>-----aaaaa", +\ ] + call s:compare_lines(expect, lines) + call s:close_windows() +endfu diff --git a/src/nvim/testdir/test_listlbr_utf8.vim b/src/nvim/testdir/test_listlbr_utf8.vim index 807b6ad31a..980d67d49d 100644 --- a/src/nvim/testdir/test_listlbr_utf8.vim +++ b/src/nvim/testdir/test_listlbr_utf8.vim @@ -193,3 +193,37 @@ func Test_multibyte_sign_and_colorcolumn() call s:compare_lines(expect, lines) call s:close_windows() endfunc + +func Test_chinese_char_on_wrap_column() + call s:test_windows("setl nolbr wrap sbr=") + syntax off + call setline(1, [ +\ 'aaaaaaaaaaaaaaaaaaa中'. +\ 'aaaaaaaaaaaaaaaaa中'. +\ 'aaaaaaaaaaaaaaaaa中'. +\ 'aaaaaaaaaaaaaaaaa中'. +\ 'aaaaaaaaaaaaaaaaa中'. +\ 'aaaaaaaaaaaaaaaaa中'. +\ 'aaaaaaaaaaaaaaaaa中'. +\ 'aaaaaaaaaaaaaaaaa中'. +\ 'aaaaaaaaaaaaaaaaa中'. +\ 'aaaaaaaaaaaaaaaaa中'. +\ 'hello']) + call cursor(1,1) + norm! $ + redraw! + let expect=[ +\ '中aaaaaaaaaaaaaaaaa>', +\ '中aaaaaaaaaaaaaaaaa>', +\ '中aaaaaaaaaaaaaaaaa>', +\ '中aaaaaaaaaaaaaaaaa>', +\ '中aaaaaaaaaaaaaaaaa>', +\ '中aaaaaaaaaaaaaaaaa>', +\ '中aaaaaaaaaaaaaaaaa>', +\ '中aaaaaaaaaaaaaaaaa>', +\ '中aaaaaaaaaaaaaaaaa>', +\ '中hello '] + let lines = s:screen_lines([1, 10], winwidth(0)) + call s:compare_lines(expect, lines) + call s:close_windows() +endfu diff --git a/src/nvim/version.c b/src/nvim/version.c index 7fca8aee82..a7479c6b18 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -558,7 +558,7 @@ static const int included_patches[] = { // 397, // 396, // 395, - // 394, + 394, 393, // 392, // 391, @@ -662,7 +662,7 @@ static const int included_patches[] = { // 293, // 292, // 291, - // 290, + 290, // 289, // 288 NA // 287, -- cgit From 9b4cbd5cdcc807a69da649b96f52e8a3d56c1ff4 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 29 Jul 2017 01:44:58 +0200 Subject: vim-patch:8.0.0518 Closes #7086 Problem: Storing a zero byte from a multi-byte character causes fold text to show up wrong. Solution: Avoid putting zero in ScreenLines. (Christian Brabandt, closes vim/vim#1567) https://github.com/vim/vim/commit/c6cd8409c2993b1476e123fba11cb4b8d743b896 --- src/nvim/screen.c | 8 ++++-- src/nvim/testdir/test_display.vim | 56 ++++++++++++++++++++++++++------------- src/nvim/version.c | 2 +- 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 27701c4643..c302ac695e 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -1924,10 +1924,14 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T if (fill_fold >= 0x80) { ScreenLinesUC[off + col] = fill_fold; ScreenLinesC[0][off + col] = 0; - } else + ScreenLines[off + col] = 0x80; // avoid storing zero + } else { ScreenLinesUC[off + col] = 0; + } + col++; + } else { + ScreenLines[off + col++] = fill_fold; } - ScreenLines[off + col++] = fill_fold; } if (text != buf) diff --git a/src/nvim/testdir/test_display.vim b/src/nvim/testdir/test_display.vim index 609e16c737..4253b56933 100644 --- a/src/nvim/testdir/test_display.vim +++ b/src/nvim/testdir/test_display.vim @@ -3,18 +3,12 @@ if !has('gui_running') && has('unix') set term=ansi endif -function! s:screenline(lnum, nr) abort - let line = [] - for j in range(a:nr) - for c in range(1, winwidth(0)) - call add(line, nr2char(screenchar(a:lnum+j, c))) - endfor - call add(line, "\n") - endfor - return join(line, '') -endfunction +source view_util.vim -function! Test_display_foldcolumn() +func! Test_display_foldcolumn() + if !has("folding") + return + endif new vnew vert resize 25 @@ -23,17 +17,43 @@ function! Test_display_foldcolumn() 1put='e more noise blah blah‚ more stuff here' - let expect = "e more noise blah blah<82\n> more stuff here \n" + let expect = [ + \ "e more noise blah blah<82", + \ "> more stuff here " + \ ] call cursor(2, 1) norm! zt - redraw! - call assert_equal(expect, s:screenline(1,2)) + let lines=ScreenLines([1,2], winwidth(0)) + call assert_equal(expect, lines) set fdc=2 - redraw! - let expect = " e more noise blah blah<\n 82> more stuff here \n" - call assert_equal(expect, s:screenline(1,2)) + let lines=ScreenLines([1,2], winwidth(0)) + let expect = [ + \ " e more noise blah blah<", + \ " 82> more stuff here " + \ ] + call assert_equal(expect, lines) quit! quit! -endfunction +endfunc + +func! Test_display_foldtext_mbyte() + if !has("folding") || !has("multi_byte") + return + endif + call NewWindow(10, 40) + call append(0, range(1,20)) + exe "set foldmethod=manual foldtext=foldtext() fillchars=fold:\u2500,vert:\u2502 fdc=2" + call cursor(2, 1) + norm! zf13G + let lines=ScreenLines([1,3], winwidth(0)+1) + let expect=[ + \ " 1 \u2502", + \ "+ +-- 12 lines: 2". repeat("\u2500", 23). "\u2502", + \ " 14 \u2502", + \ ] + call assert_equal(expect, lines) + set foldtext& fillchars& foldmethod& fdc& + bw! +endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index a7479c6b18..b6386049bf 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -434,7 +434,7 @@ static const int included_patches[] = { // 521, // 520, // 519, - // 518, + 518, // 517, // 516, // 515, -- cgit From 5ed2ab6d5327ed7c54edc9fa5eb1cfa447edbf2a Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 29 Jul 2017 02:40:25 +0200 Subject: vim-patch:8.0.0524 Problem: Folds are messed up when 'encodin' is "utf-8". Solution: Also set the fold character when it's not multi-byte. https://github.com/vim/vim/commit/8da1e6cedf839902e15987a98733ebd31b5f1b81 --- src/nvim/screen.c | 1 + src/nvim/testdir/test_display.vim | 10 ++++++++++ src/nvim/version.c | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/nvim/screen.c b/src/nvim/screen.c index c302ac695e..dd958eec80 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -1927,6 +1927,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T ScreenLines[off + col] = 0x80; // avoid storing zero } else { ScreenLinesUC[off + col] = 0; + ScreenLines[off + col] = fill_fold; } col++; } else { diff --git a/src/nvim/testdir/test_display.vim b/src/nvim/testdir/test_display.vim index 4253b56933..48b7a2318e 100644 --- a/src/nvim/testdir/test_display.vim +++ b/src/nvim/testdir/test_display.vim @@ -54,6 +54,16 @@ func! Test_display_foldtext_mbyte() \ " 14 \u2502", \ ] call assert_equal(expect, lines) + + set fillchars=fold:-,vert:\| + let lines=ScreenLines([1,3], winwidth(0)+1) + let expect=[ + \ " 1 |", + \ "+ +-- 12 lines: 2". repeat("-", 23). "|", + \ " 14 |", + \ ] + call assert_equal(expect, lines) + set foldtext& fillchars& foldmethod& fdc& bw! endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index b6386049bf..a1655f1caa 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -428,7 +428,7 @@ static const int included_patches[] = { // 527, // 526, // 525, - // 524, + 524, // 523, // 522, // 521, -- cgit From e214cc2cdc5bd262ef0c4b20f1daf7647c490063 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 10 Aug 2017 04:11:35 +0200 Subject: oldtest: cannot `:set term` in Nvim --- src/nvim/testdir/test_display.vim | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/nvim/testdir/test_display.vim b/src/nvim/testdir/test_display.vim index 48b7a2318e..0ed672d577 100644 --- a/src/nvim/testdir/test_display.vim +++ b/src/nvim/testdir/test_display.vim @@ -1,7 +1,9 @@ " Test for displaying stuff -if !has('gui_running') && has('unix') - set term=ansi -endif + +" Nvim: `:set term` is not supported. +" if !has('gui_running') && has('unix') +" set term=ansi +" endif source view_util.vim -- cgit From cd5f9d638eb61dd364689f2f2fa645efe4e1b6a5 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 12 Aug 2017 18:22:47 +0200 Subject: vim-patch:8.0.0235 Problem: Memory leak detected when running tests for diff mode. Solution: Free p_extra_free. https://github.com/vim/vim/commit/b031c4ea04eb1e37a873fbb85e90d835aa1e2b1c --- src/nvim/screen.c | 21 +++++++++++---------- src/nvim/version.c | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/nvim/screen.c b/src/nvim/screen.c index dd958eec80..f8d519ab36 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2715,17 +2715,15 @@ win_line ( draw_state = WL_FOLD; if (fdc > 0) { // Draw the 'foldcolumn'. Allocate a buffer, "extra" may - // already be in used. + // already be in use. + xfree(p_extra_free); p_extra_free = xmalloc(12 + 1); - - if (p_extra_free != NULL) { - fill_foldcolumn(p_extra_free, wp, false, lnum); - n_extra = fdc; - p_extra_free[n_extra] = NUL; - p_extra = p_extra_free; - c_extra = NUL; - char_attr = win_hl_attr(wp, HLF_FC); - } + fill_foldcolumn(p_extra_free, wp, false, lnum); + n_extra = fdc; + p_extra_free[n_extra] = NUL; + p_extra = p_extra_free; + c_extra = NUL; + char_attr = win_hl_attr(wp, HLF_FC); } } @@ -3526,6 +3524,7 @@ win_line ( p = xmalloc(len + 1); memset(p, ' ', len); p[len] = NUL; + xfree(p_extra_free); p_extra_free = p; for (i = 0; i < tab_len; i++) { mb_char2bytes(lcs_tab2, p); @@ -3641,6 +3640,7 @@ win_line ( memset(p, ' ', n_extra); STRNCPY(p, p_extra + 1, STRLEN(p_extra) - 1); p[n_extra] = NUL; + xfree(p_extra_free); p_extra_free = p_extra = p; } else { n_extra = byte2cells(c) - 1; @@ -4314,6 +4314,7 @@ win_line ( cap_col = 0; } + xfree(p_extra_free); return row; } diff --git a/src/nvim/version.c b/src/nvim/version.c index a1655f1caa..f4984864f3 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -717,7 +717,7 @@ static const int included_patches[] = { // 238, // 237, // 236, - // 235, + 235, // 234, // 233, // 232 NA -- cgit From 809420233c591c81aede48679a42fce90e75bb6f Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Mon, 10 Jul 2017 09:37:54 +0200 Subject: tui: fix DECSCUSR logic #6997 Fix linuxvt cursor shape codes Fix konsole cursor_shapes (even when inside tmux) Do not trust old VTE terminal lies Closes #6978 Closes #7002 Closes #7049 --- src/nvim/tui/tui.c | 90 +++++++++++++++++++++++++----------------------------- 1 file changed, 42 insertions(+), 48 deletions(-) diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 97a0398c80..b5af5b0333 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1256,7 +1256,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, bool teraterm = terminfo_is_term_family(term, "teraterm"); bool putty = terminfo_is_term_family(term, "putty"); bool screen = terminfo_is_term_family(term, "screen"); - bool tmux = terminfo_is_term_family(term, "tmux"); + bool tmux = terminfo_is_term_family(term, "tmux") || !!os_getenv("TMUX"); bool st = terminfo_is_term_family(term, "st"); bool gnome = terminfo_is_term_family(term, "gnome") || terminfo_is_term_family(term, "vte"); @@ -1270,7 +1270,6 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, bool mate_pretending_xterm = xterm && colorterm && strstr(colorterm, "mate-terminal"); bool true_xterm = xterm && !!xterm_version; - bool tmux_pretending_screen = screen && !!os_getenv("TMUX"); char *fix_normal = (char *)unibi_get_str(ut, unibi_cursor_normal); if (fix_normal) { @@ -1347,7 +1346,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, // per the screen manual; 2017-04 terminfo.src lacks these. unibi_set_if_empty(ut, unibi_to_status_line, "\x1b_"); unibi_set_if_empty(ut, unibi_from_status_line, "\x1b\\"); - } else if (terminfo_is_term_family(term, "tmux")) { + } else if (tmux) { unibi_set_if_empty(ut, unibi_to_status_line, "\x1b_"); unibi_set_if_empty(ut, unibi_from_status_line, "\x1b\\"); } else if (terminfo_is_term_family(term, "interix")) { @@ -1408,12 +1407,11 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, unibi_set_str(ut, unibi_set_a_foreground, XTERM_SETAF_256_COLON); unibi_set_str(ut, unibi_set_a_background, XTERM_SETAB_256_COLON); } else if (konsole || xterm || gnome || rxvt || st || putty - || linuxvt // Linux 4.8+ supports 256-colour SGR. - || mate_pretending_xterm || gnome_pretending_xterm - || tmux || tmux_pretending_screen - || (colorterm && strstr(colorterm, "256")) - || (term && strstr(term, "256")) - ) { + || linuxvt // Linux 4.8+ supports 256-colour SGR. + || mate_pretending_xterm || gnome_pretending_xterm + || tmux + || (colorterm && strstr(colorterm, "256")) + || (term && strstr(term, "256"))) { unibi_set_num(ut, unibi_max_colors, 256); unibi_set_str(ut, unibi_set_a_foreground, XTERM_SETAF_256); unibi_set_str(ut, unibi_set_a_background, XTERM_SETAB_256); @@ -1429,12 +1427,17 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, } } - // Dickey ncurses terminfo has included the Ss and Se capabilities, pioneered - // by tmux, since 2011-07-14. So adding them to terminal types, that do - // actually have such control sequences but lack the correct definitions in - // terminfo, is a fixup, not an augmentation. - data->unibi_ext.reset_cursor_style = unibi_find_ext_str(ut, "Se"); - data->unibi_ext.set_cursor_style = unibi_find_ext_str(ut, "Ss"); + // Some terminals can not currently be trusted to report if they support + // DECSCUSR or not. So we need to have a blacklist for when we should not + // trust the reported features. + if (!((vte_version != 0 && vte_version < 3900) || konsole)) { + // Dickey ncurses terminfo has included the Ss and Se capabilities, + // pioneered by tmux, since 2011-07-14. So adding them to terminal types, + // that do actually have such control sequences but lack the correct + // definitions in terminfo, is a fixup, not an augmentation. + data->unibi_ext.reset_cursor_style = unibi_find_ext_str(ut, "Se"); + data->unibi_ext.set_cursor_style = unibi_find_ext_str(ut, "Ss"); + } if (-1 == data->unibi_ext.set_cursor_style) { // The DECSCUSR sequence to change the cursor shape is widely // supported by several terminal types and should be in many @@ -1442,6 +1445,13 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, // https://github.com/gnachman/iTerm2/pull/92 for more. // xterm even has an extended version that has a vertical bar. if (true_xterm // per xterm ctlseqs doco (since version 282) + // per MinTTY 0.4.3-1 release notes from 2009 + || putty + // per https://bugzilla.gnome.org/show_bug.cgi?id=720821 + || (vte_version >= 3900) + || tmux // per tmux manual page + // https://lists.gnu.org/archive/html/screen-devel/2013-03/msg00000.html + || screen || rxvt // per command.C // per analysis of VT100Terminal.m || iterm || iterm_pretending_xterm @@ -1454,50 +1464,34 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, (int)unibi_add_ext_str(ut, "Ss", "\x1b[%p1%d q"); if (-1 == data->unibi_ext.reset_cursor_style) { data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se", - ""); + ""); } unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style, "\x1b[ q"); - } else if ( - // per MinTTY 0.4.3-1 release notes from 2009 - putty - // per https://bugzilla.gnome.org/show_bug.cgi?id=720821 - || (vte_version >= 3900) - // per tmux manual page and per - // https://lists.gnu.org/archive/html/screen-devel/2013-03/msg00000.html - || screen) { - // Since we use the xterm extension, we must map it to the unextended form - data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss", - "\x1b[%?" - "%p1%{4}%>" "%t%p1%{2}%-" // a bit of a bodge for extension values - "%e%p1" // the conventional codes are just passed through - "%;%d q"); - if (-1 == data->unibi_ext.reset_cursor_style) { - data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se", - ""); - } - unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style, - "\x1b[ q"); } else if (linuxvt) { // Linux uses an idiosyncratic escape code to set the cursor shape and // does not support DECSCUSR. + // See http://linuxgazette.net/137/anonymous.html for more info data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss", "\x1b[?" "%?" // The parameter passed to Ss is the DECSCUSR parameter, so the // terminal capability has to translate into the Linux idiosyncratic // parameter. - "%p1%{2}%<" "%t%{8}" // blink block - "%p1%{2}%=" "%t%{24}" // steady block - "%p1%{3}%=" "%t%{1}" // blink underline - "%p1%{4}%=" "%t%{17}" // steady underline - "%p1%{5}%=" "%t%{1}" // blink bar - "%p1%{6}%=" "%t%{17}" // steady bar - "%e%{0}" // anything else + // + // linuxvt only supports block and underline. It is also only + // possible to have a steady block (no steady underline) + "%p1%{2}%<" "%t%{8}" // blink block + "%e%p1%{2}%=" "%t%{112}" // steady block + "%e%p1%{3}%=" "%t%{4}" // blink underline (set to half block) + "%e%p1%{4}%=" "%t%{4}" // steady underline + "%e%p1%{5}%=" "%t%{2}" // blink bar (set to underline) + "%e%p1%{6}%=" "%t%{2}" // steady bar + "%e%{0}" // anything else "%;" "%dc"); if (-1 == data->unibi_ext.reset_cursor_style) { data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se", - ""); + ""); } unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style, "\x1b[?c"); @@ -1507,17 +1501,17 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, // nonce profile, which has side-effects on temporary font resizing. // In an ideal world, Konsole would just support DECSCUSR. data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss", - "\x1b]50;CursorShape=%?" + TMUX_WRAP(tmux, "\x1b]50;CursorShape=%?" "%p1%{3}%<" "%t%{0}" // block - "%e%p1%{4}%<" "%t%{2}" // underline + "%e%p1%{5}%<" "%t%{2}" // underline "%e%{1}" // everything else is bar "%;%d;BlinkingCursorEnabled=%?" "%p1%{1}%<" "%t%{1}" // Fortunately if we exclude zero as special, "%e%p1%{1}%&" // in all other cases we can treat bit #0 as a flag. - "%;%d\x07"); + "%;%d\x07")); if (-1 == data->unibi_ext.reset_cursor_style) { data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se", - ""); + ""); } unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style, "\x1b]50;\x07"); -- cgit From e6c528d9fc527d555a85ae12dc6cc8b74ab09e38 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 13 Aug 2017 10:01:39 -0400 Subject: travis: Move TSAN to last stage and allow failure TSAN build has been much less reliable lately, so it shouldn't hold up the other tests. --- .travis.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 45c2dcb832..2bab1635ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -57,9 +57,6 @@ jobs: env: > CLANG_SANITIZER=ASAN_UBSAN CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON" - - os: linux - compiler: clang-4.0 - env: CLANG_SANITIZER=TSAN - stage: normal builds os: linux compiler: gcc-5 @@ -79,12 +76,16 @@ jobs: - stage: lint os: linux env: CI_TARGET=lint - - stage: coverage + - stage: Flaky builds os: linux compiler: gcc-5 env: GCOV=gcov-5 CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON" + - os: linux + compiler: clang-4.0 + env: CLANG_SANITIZER=TSAN allow_failures: - env: GCOV=gcov-5 CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON" + - env: CLANG_SANITIZER=TSAN fast_finish: true before_install: ci/before_install.sh -- cgit From d0cb175cab56da47fbd08e4b65ca02832a93bc38 Mon Sep 17 00:00:00 2001 From: Nikolai Aleksandrovich Pavlov Date: Sun, 13 Aug 2017 18:37:35 +0300 Subject: lua/executor: Fix crash when printing empty string (#7157) --- src/nvim/lua/executor.c | 2 +- test/functional/lua/overrides_spec.lua | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 9ec5bfb8ad..eb821f7831 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -519,7 +519,7 @@ static int nlua_print(lua_State *const lstate) } msg((char_u *)str + start); } - if (str[len - 1] == NUL) { // Last was newline + if (len && str[len - 1] == NUL) { // Last was newline msg((char_u *)""); } } diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index 6e1d50071d..8ca5fe57ba 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -69,6 +69,13 @@ describe('print', function() eq('\nT^@', redir_exec([[lua print("T\0")]])) eq('\nT\n', redir_exec([[lua print("T\n")]])) end) + it('prints empty strings correctly', function() + -- Regression: first test used to crash + eq('', redir_exec('lua print("")')) + eq('\n def', redir_exec('lua print("", "def")')) + eq('\nabc ', redir_exec('lua print("abc", "")')) + eq('\nabc def', redir_exec('lua print("abc", "", "def")')) + end) end) describe('debug.debug', function() -- cgit From c4e214a99cf0dfc53c1e903178c08fad9cb05354 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 13 Aug 2017 18:46:09 +0200 Subject: io: more guards against NULL filename (#7159) References ac055d677aa9 References #4370 --- src/nvim/main.c | 1 + src/nvim/memfile.c | 1 + src/nvim/memline.c | 2 ++ src/nvim/os/fs.c | 5 ++++- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/nvim/main.c b/src/nvim/main.c index a46c1a58f8..3f828d7be9 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1825,6 +1825,7 @@ static int process_env(char *env, bool is_viminit) /// os_fileinfo_link() respectively for extra security. static bool file_owned(const char *fname) { + assert(fname != NULL); uid_t uid = getuid(); FileInfo file_info; bool file_owned = os_fileinfo(fname, &file_info) diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index 9429703620..4428dd42aa 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -895,6 +895,7 @@ static bool mf_do_open(memfile_T *mfp, char_u *fname, int flags) { // fname cannot be NameBuff, because it must have been allocated. mf_set_fnames(mfp, fname); + assert(mfp->mf_fname != NULL); /// Extra security check: When creating a swap file it really shouldn't /// exist yet. If there is a symbolic link, this is most likely an attack. diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 55e7e01825..f28a9e60f4 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -1460,6 +1460,7 @@ static int process_still_running; */ static time_t swapfile_info(char_u *fname) { + assert(fname != NULL); int fd; struct block0 b0; time_t x = (time_t)0; @@ -3135,6 +3136,7 @@ attention_message ( char_u *fname /* swap file name */ ) { + assert(buf->b_fname != NULL); time_t x, sx; char *p; diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 6ac9d682d7..78627f8703 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -859,8 +859,11 @@ bool os_fileinfo(const char *path, FileInfo *file_info) /// @param[out] file_info Pointer to a FileInfo to put the information in. /// @return `true` on success, `false` for failure. bool os_fileinfo_link(const char *path, FileInfo *file_info) - FUNC_ATTR_NONNULL_ALL + FUNC_ATTR_NONNULL_ARG(2) { + if (path == NULL) { + return false; + } uv_fs_t request; int result = uv_fs_lstat(&fs_loop, &request, path, NULL); file_info->stat = request.statbuf; -- cgit From ef6641ba6952fd868d3efafb2a23234ac9bd0d3f Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 15 Aug 2017 16:30:32 +0300 Subject: lua/executor: Make stricmp function work with strings with NULs --- src/nvim/lua/executor.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index eb821f7831..4ed477ea36 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -124,9 +124,36 @@ static void nlua_error(lua_State *const lstate, const char *const msg) /// omitted. static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL { - const char *s1 = luaL_checklstring(lstate, 1, NULL); - const char *s2 = luaL_checklstring(lstate, 2, NULL); - const int ret = STRICMP(s1, s2); + size_t s1_len; + size_t s2_len; + const char *s1 = luaL_checklstring(lstate, 1, &s1_len); + const char *s2 = luaL_checklstring(lstate, 2, &s2_len); + char *nul1; + char *nul2; + int ret = 0; + assert(s1[s1_len] == NUL); + assert(s2[s2_len] == NUL); + do { + nul1 = memchr(s1, NUL, s1_len); + nul2 = memchr(s2, NUL, s2_len); + ret = STRICMP(s1, s2); + // Compare "a\0" greater then "a". + if (ret == 0 && (nul1 == NULL) != (nul2 == NULL)) { + ret = ((nul1 != NULL) - (nul2 != NULL)); + break; + } + if (nul1 != NULL) { + assert(nul2 != NULL); + // Due to lowercase letter having possibly different byte length then + // uppercase letter can’t shift both strings by the same amount of bytes. + s1_len -= (size_t)(nul1 - s1) + 1; + s2_len -= (size_t)(nul2 - s2) + 1; + s1 = nul1 + 1; + s2 = nul2 + 1; + } else { + break; + } + } while (ret == 0); lua_pop(lstate, 2); lua_pushnumber(lstate, (lua_Number)((ret > 0) - (ret < 0))); return 1; -- cgit From 96b1600bc822d72f5a1defa1dafda562ff208b7e Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 15 Aug 2017 16:31:11 +0300 Subject: functests: Add test for stricmp --- test/functional/lua/utility_functions_spec.lua | 102 +++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 test/functional/lua/utility_functions_spec.lua diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua new file mode 100644 index 0000000000..c89a21a968 --- /dev/null +++ b/test/functional/lua/utility_functions_spec.lua @@ -0,0 +1,102 @@ +-- Test suite for testing interactions with API bindings +local helpers = require('test.functional.helpers')(after_each) + +local funcs = helpers.funcs +local clear = helpers.clear +local eq = helpers.eq + +before_each(clear) + +describe('stricmp', function() + -- İ: `tolower("İ")` is `i` which has length 1 while `İ` itself has + -- length 2 (in bytes). + -- Ⱥ: `tolower("Ⱥ")` is `ⱥ` which has length 2 while `Ⱥ` itself has + -- length 3 (in bytes). + -- For some reason 'i' !=? 'İ' and 'ⱥ' !=? 'Ⱥ' on some systems. Also built-in + -- Neovim comparison (i.e. when there is no strcasecmp) works only on ASCII + -- characters. + it('works', function() + eq(0, funcs.luaeval('stricmp("a", "A")')) + eq(0, funcs.luaeval('stricmp("A", "a")')) + eq(0, funcs.luaeval('stricmp("a", "a")')) + eq(0, funcs.luaeval('stricmp("A", "A")')) + + eq(0, funcs.luaeval('stricmp("", "")')) + eq(0, funcs.luaeval('stricmp("\\0", "\\0")')) + eq(0, funcs.luaeval('stricmp("\\0\\0", "\\0\\0")')) + eq(0, funcs.luaeval('stricmp("\\0\\0\\0", "\\0\\0\\0")')) + eq(0, funcs.luaeval('stricmp("\\0\\0\\0A", "\\0\\0\\0a")')) + eq(0, funcs.luaeval('stricmp("\\0\\0\\0a", "\\0\\0\\0A")')) + eq(0, funcs.luaeval('stricmp("\\0\\0\\0a", "\\0\\0\\0a")')) + + eq(0, funcs.luaeval('stricmp("a\\0", "A\\0")')) + eq(0, funcs.luaeval('stricmp("A\\0", "a\\0")')) + eq(0, funcs.luaeval('stricmp("a\\0", "a\\0")')) + eq(0, funcs.luaeval('stricmp("A\\0", "A\\0")')) + + eq(0, funcs.luaeval('stricmp("\\0a", "\\0A")')) + eq(0, funcs.luaeval('stricmp("\\0A", "\\0a")')) + eq(0, funcs.luaeval('stricmp("\\0a", "\\0a")')) + eq(0, funcs.luaeval('stricmp("\\0A", "\\0A")')) + + eq(0, funcs.luaeval('stricmp("\\0a\\0", "\\0A\\0")')) + eq(0, funcs.luaeval('stricmp("\\0A\\0", "\\0a\\0")')) + eq(0, funcs.luaeval('stricmp("\\0a\\0", "\\0a\\0")')) + eq(0, funcs.luaeval('stricmp("\\0A\\0", "\\0A\\0")')) + + eq(-1, funcs.luaeval('stricmp("a", "B")')) + eq(-1, funcs.luaeval('stricmp("A", "b")')) + eq(-1, funcs.luaeval('stricmp("a", "b")')) + eq(-1, funcs.luaeval('stricmp("A", "B")')) + + eq(-1, funcs.luaeval('stricmp("", "\\0")')) + eq(-1, funcs.luaeval('stricmp("\\0", "\\0\\0")')) + eq(-1, funcs.luaeval('stricmp("\\0\\0", "\\0\\0\\0")')) + eq(-1, funcs.luaeval('stricmp("\\0\\0\\0A", "\\0\\0\\0b")')) + eq(-1, funcs.luaeval('stricmp("\\0\\0\\0a", "\\0\\0\\0B")')) + eq(-1, funcs.luaeval('stricmp("\\0\\0\\0a", "\\0\\0\\0b")')) + + eq(-1, funcs.luaeval('stricmp("a\\0", "B\\0")')) + eq(-1, funcs.luaeval('stricmp("A\\0", "b\\0")')) + eq(-1, funcs.luaeval('stricmp("a\\0", "b\\0")')) + eq(-1, funcs.luaeval('stricmp("A\\0", "B\\0")')) + + eq(-1, funcs.luaeval('stricmp("\\0a", "\\0B")')) + eq(-1, funcs.luaeval('stricmp("\\0A", "\\0b")')) + eq(-1, funcs.luaeval('stricmp("\\0a", "\\0b")')) + eq(-1, funcs.luaeval('stricmp("\\0A", "\\0B")')) + + eq(-1, funcs.luaeval('stricmp("\\0a\\0", "\\0B\\0")')) + eq(-1, funcs.luaeval('stricmp("\\0A\\0", "\\0b\\0")')) + eq(-1, funcs.luaeval('stricmp("\\0a\\0", "\\0b\\0")')) + eq(-1, funcs.luaeval('stricmp("\\0A\\0", "\\0B\\0")')) + + eq(1, funcs.luaeval('stricmp("c", "B")')) + eq(1, funcs.luaeval('stricmp("C", "b")')) + eq(1, funcs.luaeval('stricmp("c", "b")')) + eq(1, funcs.luaeval('stricmp("C", "B")')) + + eq(1, funcs.luaeval('stricmp("\\0", "")')) + eq(1, funcs.luaeval('stricmp("\\0\\0", "\\0")')) + eq(1, funcs.luaeval('stricmp("\\0\\0\\0", "\\0\\0")')) + eq(1, funcs.luaeval('stricmp("\\0\\0\\0\\0", "\\0\\0\\0")')) + eq(1, funcs.luaeval('stricmp("\\0\\0\\0C", "\\0\\0\\0b")')) + eq(1, funcs.luaeval('stricmp("\\0\\0\\0c", "\\0\\0\\0B")')) + eq(1, funcs.luaeval('stricmp("\\0\\0\\0c", "\\0\\0\\0b")')) + + eq(1, funcs.luaeval('stricmp("c\\0", "B\\0")')) + eq(1, funcs.luaeval('stricmp("C\\0", "b\\0")')) + eq(1, funcs.luaeval('stricmp("c\\0", "b\\0")')) + eq(1, funcs.luaeval('stricmp("C\\0", "B\\0")')) + + eq(1, funcs.luaeval('stricmp("\\0c", "\\0B")')) + eq(1, funcs.luaeval('stricmp("\\0C", "\\0b")')) + eq(1, funcs.luaeval('stricmp("\\0c", "\\0b")')) + eq(1, funcs.luaeval('stricmp("\\0C", "\\0B")')) + + eq(1, funcs.luaeval('stricmp("\\0c\\0", "\\0B\\0")')) + eq(1, funcs.luaeval('stricmp("\\0C\\0", "\\0b\\0")')) + eq(1, funcs.luaeval('stricmp("\\0c\\0", "\\0b\\0")')) + eq(1, funcs.luaeval('stricmp("\\0C\\0", "\\0B\\0")')) + end) +end) -- cgit From 93ef823f5e5347e685b4a69fff487278d0b4ed87 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 15 Aug 2017 16:32:06 +0300 Subject: lua/executor: Move stricmp to vim “module” and document it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- runtime/doc/if_lua.txt | 5 + src/nvim/lua/executor.c | 8 +- test/functional/lua/utility_functions_spec.lua | 166 ++++++++++++------------- 3 files changed, 92 insertions(+), 87 deletions(-) diff --git a/runtime/doc/if_lua.txt b/runtime/doc/if_lua.txt index c4efd57b45..515864555b 100644 --- a/runtime/doc/if_lua.txt +++ b/runtime/doc/if_lua.txt @@ -246,6 +246,11 @@ Lua interfaces Vim through the "vim" module. Currently it only has `api` submodule which is a table with all API functions. Descriptions of these functions may be found in |api.txt|. +vim.stricmp(a, b) *lua-vim.stricmp* + Function used for case-insensitive string comparison. Takes two + string arguments and returns 0, 1 or -1 if strings are equal, a is + greater then b or a is lesser then b respectively. + ============================================================================== 3. The luaeval function *lua-luaeval* *lua-eval* *luaeval()* diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 4ed477ea36..90333be541 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -281,10 +281,6 @@ static int nlua_exec_lua_file(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL /// Called by lua interpreter itself to initialize state. static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL { - // stricmp - lua_pushcfunction(lstate, &nlua_stricmp); - lua_setglobal(lstate, "stricmp"); - // print lua_pushcfunction(lstate, &nlua_print); lua_setglobal(lstate, "print"); @@ -304,6 +300,10 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL nlua_add_api_functions(lstate); // vim.types, vim.type_idx, vim.val_idx nlua_init_types(lstate); + // stricmp + lua_pushcfunction(lstate, &nlua_stricmp); + lua_setfield(lstate, -2, "stricmp"); + lua_setglobal(lstate, "vim"); return 0; } diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua index c89a21a968..c2c61299b1 100644 --- a/test/functional/lua/utility_functions_spec.lua +++ b/test/functional/lua/utility_functions_spec.lua @@ -7,7 +7,7 @@ local eq = helpers.eq before_each(clear) -describe('stricmp', function() +describe('vim.stricmp', function() -- İ: `tolower("İ")` is `i` which has length 1 while `İ` itself has -- length 2 (in bytes). -- Ⱥ: `tolower("Ⱥ")` is `ⱥ` which has length 2 while `Ⱥ` itself has @@ -16,87 +16,87 @@ describe('stricmp', function() -- Neovim comparison (i.e. when there is no strcasecmp) works only on ASCII -- characters. it('works', function() - eq(0, funcs.luaeval('stricmp("a", "A")')) - eq(0, funcs.luaeval('stricmp("A", "a")')) - eq(0, funcs.luaeval('stricmp("a", "a")')) - eq(0, funcs.luaeval('stricmp("A", "A")')) - - eq(0, funcs.luaeval('stricmp("", "")')) - eq(0, funcs.luaeval('stricmp("\\0", "\\0")')) - eq(0, funcs.luaeval('stricmp("\\0\\0", "\\0\\0")')) - eq(0, funcs.luaeval('stricmp("\\0\\0\\0", "\\0\\0\\0")')) - eq(0, funcs.luaeval('stricmp("\\0\\0\\0A", "\\0\\0\\0a")')) - eq(0, funcs.luaeval('stricmp("\\0\\0\\0a", "\\0\\0\\0A")')) - eq(0, funcs.luaeval('stricmp("\\0\\0\\0a", "\\0\\0\\0a")')) - - eq(0, funcs.luaeval('stricmp("a\\0", "A\\0")')) - eq(0, funcs.luaeval('stricmp("A\\0", "a\\0")')) - eq(0, funcs.luaeval('stricmp("a\\0", "a\\0")')) - eq(0, funcs.luaeval('stricmp("A\\0", "A\\0")')) - - eq(0, funcs.luaeval('stricmp("\\0a", "\\0A")')) - eq(0, funcs.luaeval('stricmp("\\0A", "\\0a")')) - eq(0, funcs.luaeval('stricmp("\\0a", "\\0a")')) - eq(0, funcs.luaeval('stricmp("\\0A", "\\0A")')) - - eq(0, funcs.luaeval('stricmp("\\0a\\0", "\\0A\\0")')) - eq(0, funcs.luaeval('stricmp("\\0A\\0", "\\0a\\0")')) - eq(0, funcs.luaeval('stricmp("\\0a\\0", "\\0a\\0")')) - eq(0, funcs.luaeval('stricmp("\\0A\\0", "\\0A\\0")')) - - eq(-1, funcs.luaeval('stricmp("a", "B")')) - eq(-1, funcs.luaeval('stricmp("A", "b")')) - eq(-1, funcs.luaeval('stricmp("a", "b")')) - eq(-1, funcs.luaeval('stricmp("A", "B")')) - - eq(-1, funcs.luaeval('stricmp("", "\\0")')) - eq(-1, funcs.luaeval('stricmp("\\0", "\\0\\0")')) - eq(-1, funcs.luaeval('stricmp("\\0\\0", "\\0\\0\\0")')) - eq(-1, funcs.luaeval('stricmp("\\0\\0\\0A", "\\0\\0\\0b")')) - eq(-1, funcs.luaeval('stricmp("\\0\\0\\0a", "\\0\\0\\0B")')) - eq(-1, funcs.luaeval('stricmp("\\0\\0\\0a", "\\0\\0\\0b")')) - - eq(-1, funcs.luaeval('stricmp("a\\0", "B\\0")')) - eq(-1, funcs.luaeval('stricmp("A\\0", "b\\0")')) - eq(-1, funcs.luaeval('stricmp("a\\0", "b\\0")')) - eq(-1, funcs.luaeval('stricmp("A\\0", "B\\0")')) - - eq(-1, funcs.luaeval('stricmp("\\0a", "\\0B")')) - eq(-1, funcs.luaeval('stricmp("\\0A", "\\0b")')) - eq(-1, funcs.luaeval('stricmp("\\0a", "\\0b")')) - eq(-1, funcs.luaeval('stricmp("\\0A", "\\0B")')) - - eq(-1, funcs.luaeval('stricmp("\\0a\\0", "\\0B\\0")')) - eq(-1, funcs.luaeval('stricmp("\\0A\\0", "\\0b\\0")')) - eq(-1, funcs.luaeval('stricmp("\\0a\\0", "\\0b\\0")')) - eq(-1, funcs.luaeval('stricmp("\\0A\\0", "\\0B\\0")')) - - eq(1, funcs.luaeval('stricmp("c", "B")')) - eq(1, funcs.luaeval('stricmp("C", "b")')) - eq(1, funcs.luaeval('stricmp("c", "b")')) - eq(1, funcs.luaeval('stricmp("C", "B")')) - - eq(1, funcs.luaeval('stricmp("\\0", "")')) - eq(1, funcs.luaeval('stricmp("\\0\\0", "\\0")')) - eq(1, funcs.luaeval('stricmp("\\0\\0\\0", "\\0\\0")')) - eq(1, funcs.luaeval('stricmp("\\0\\0\\0\\0", "\\0\\0\\0")')) - eq(1, funcs.luaeval('stricmp("\\0\\0\\0C", "\\0\\0\\0b")')) - eq(1, funcs.luaeval('stricmp("\\0\\0\\0c", "\\0\\0\\0B")')) - eq(1, funcs.luaeval('stricmp("\\0\\0\\0c", "\\0\\0\\0b")')) - - eq(1, funcs.luaeval('stricmp("c\\0", "B\\0")')) - eq(1, funcs.luaeval('stricmp("C\\0", "b\\0")')) - eq(1, funcs.luaeval('stricmp("c\\0", "b\\0")')) - eq(1, funcs.luaeval('stricmp("C\\0", "B\\0")')) - - eq(1, funcs.luaeval('stricmp("\\0c", "\\0B")')) - eq(1, funcs.luaeval('stricmp("\\0C", "\\0b")')) - eq(1, funcs.luaeval('stricmp("\\0c", "\\0b")')) - eq(1, funcs.luaeval('stricmp("\\0C", "\\0B")')) - - eq(1, funcs.luaeval('stricmp("\\0c\\0", "\\0B\\0")')) - eq(1, funcs.luaeval('stricmp("\\0C\\0", "\\0b\\0")')) - eq(1, funcs.luaeval('stricmp("\\0c\\0", "\\0b\\0")')) - eq(1, funcs.luaeval('stricmp("\\0C\\0", "\\0B\\0")')) + eq(0, funcs.luaeval('vim.stricmp("a", "A")')) + eq(0, funcs.luaeval('vim.stricmp("A", "a")')) + eq(0, funcs.luaeval('vim.stricmp("a", "a")')) + eq(0, funcs.luaeval('vim.stricmp("A", "A")')) + + eq(0, funcs.luaeval('vim.stricmp("", "")')) + eq(0, funcs.luaeval('vim.stricmp("\\0", "\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0\\0", "\\0\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0a")')) + eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0A")')) + eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0a")')) + + eq(0, funcs.luaeval('vim.stricmp("a\\0", "A\\0")')) + eq(0, funcs.luaeval('vim.stricmp("A\\0", "a\\0")')) + eq(0, funcs.luaeval('vim.stricmp("a\\0", "a\\0")')) + eq(0, funcs.luaeval('vim.stricmp("A\\0", "A\\0")')) + + eq(0, funcs.luaeval('vim.stricmp("\\0a", "\\0A")')) + eq(0, funcs.luaeval('vim.stricmp("\\0A", "\\0a")')) + eq(0, funcs.luaeval('vim.stricmp("\\0a", "\\0a")')) + eq(0, funcs.luaeval('vim.stricmp("\\0A", "\\0A")')) + + eq(0, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0A\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0a\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0a\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0A\\0")')) + + eq(-1, funcs.luaeval('vim.stricmp("a", "B")')) + eq(-1, funcs.luaeval('vim.stricmp("A", "b")')) + eq(-1, funcs.luaeval('vim.stricmp("a", "b")')) + eq(-1, funcs.luaeval('vim.stricmp("A", "B")')) + + eq(-1, funcs.luaeval('vim.stricmp("", "\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0", "\\0\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0\\0", "\\0\\0\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0b")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0B")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0b")')) + + eq(-1, funcs.luaeval('vim.stricmp("a\\0", "B\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("A\\0", "b\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("a\\0", "b\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("A\\0", "B\\0")')) + + eq(-1, funcs.luaeval('vim.stricmp("\\0a", "\\0B")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0A", "\\0b")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0a", "\\0b")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0A", "\\0B")')) + + eq(-1, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0B\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0b\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0b\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0B\\0")')) + + eq(1, funcs.luaeval('vim.stricmp("c", "B")')) + eq(1, funcs.luaeval('vim.stricmp("C", "b")')) + eq(1, funcs.luaeval('vim.stricmp("c", "b")')) + eq(1, funcs.luaeval('vim.stricmp("C", "B")')) + + eq(1, funcs.luaeval('vim.stricmp("\\0", "")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0", "\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0\\0", "\\0\\0\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0C", "\\0\\0\\0b")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0B")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0b")')) + + eq(1, funcs.luaeval('vim.stricmp("c\\0", "B\\0")')) + eq(1, funcs.luaeval('vim.stricmp("C\\0", "b\\0")')) + eq(1, funcs.luaeval('vim.stricmp("c\\0", "b\\0")')) + eq(1, funcs.luaeval('vim.stricmp("C\\0", "B\\0")')) + + eq(1, funcs.luaeval('vim.stricmp("\\0c", "\\0B")')) + eq(1, funcs.luaeval('vim.stricmp("\\0C", "\\0b")')) + eq(1, funcs.luaeval('vim.stricmp("\\0c", "\\0b")')) + eq(1, funcs.luaeval('vim.stricmp("\\0C", "\\0B")')) + + eq(1, funcs.luaeval('vim.stricmp("\\0c\\0", "\\0B\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0b\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0c\\0", "\\0b\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0B\\0")')) end) end) -- cgit From b1a8dcefeee0bb999a350de2cc38fc08df679bf6 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 15 Aug 2017 16:41:43 +0300 Subject: lua/executor: Fix crash when first string contains NUL and second not --- src/nvim/lua/executor.c | 33 +++++++++++++++----------- test/functional/lua/utility_functions_spec.lua | 5 ++++ 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 90333be541..54973a6e94 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -137,23 +137,28 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL nul1 = memchr(s1, NUL, s1_len); nul2 = memchr(s2, NUL, s2_len); ret = STRICMP(s1, s2); - // Compare "a\0" greater then "a". - if (ret == 0 && (nul1 == NULL) != (nul2 == NULL)) { - ret = ((nul1 != NULL) - (nul2 != NULL)); - break; - } - if (nul1 != NULL) { - assert(nul2 != NULL); - // Due to lowercase letter having possibly different byte length then - // uppercase letter can’t shift both strings by the same amount of bytes. - s1_len -= (size_t)(nul1 - s1) + 1; - s2_len -= (size_t)(nul2 - s2) + 1; - s1 = nul1 + 1; - s2 = nul2 + 1; + if (ret == 0) { + // Compare "a\0" greater then "a". + if ((nul1 == NULL) != (nul2 == NULL)) { + ret = ((nul1 != NULL) - (nul2 != NULL)); + break; + } + if (nul1 != NULL) { + assert(nul2 != NULL); + // Due to lowercase letter having possibly different byte length then + // uppercase letter can’t shift both strings by the same amount of + // bytes. + s1_len -= (size_t)(nul1 - s1) + 1; + s2_len -= (size_t)(nul2 - s2) + 1; + s1 = nul1 + 1; + s2 = nul2 + 1; + } else { + break; + } } else { break; } - } while (ret == 0); + } while (true); lua_pop(lstate, 2); lua_pushnumber(lstate, (lua_Number)((ret > 0) - (ret < 0))); return 1; diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua index c2c61299b1..9855a05e8c 100644 --- a/test/functional/lua/utility_functions_spec.lua +++ b/test/functional/lua/utility_functions_spec.lua @@ -89,6 +89,11 @@ describe('vim.stricmp', function() eq(1, funcs.luaeval('vim.stricmp("c\\0", "b\\0")')) eq(1, funcs.luaeval('vim.stricmp("C\\0", "B\\0")')) + eq(1, funcs.luaeval('vim.stricmp("c\\0", "B")')) + eq(1, funcs.luaeval('vim.stricmp("C\\0", "b")')) + eq(1, funcs.luaeval('vim.stricmp("c\\0", "b")')) + eq(1, funcs.luaeval('vim.stricmp("C\\0", "B")')) + eq(1, funcs.luaeval('vim.stricmp("\\0c", "\\0B")')) eq(1, funcs.luaeval('vim.stricmp("\\0C", "\\0b")')) eq(1, funcs.luaeval('vim.stricmp("\\0c", "\\0b")')) -- cgit From dd1943a3a77793d3c1b8488ca70a09fefed6fb42 Mon Sep 17 00:00:00 2001 From: ZyX Date: Wed, 16 Aug 2017 00:44:52 +0300 Subject: doc: Describe everything what is in `vim` lua “module” MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ci skip] --- runtime/doc/if_lua.txt | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/runtime/doc/if_lua.txt b/runtime/doc/if_lua.txt index 515864555b..49b4c6dce1 100644 --- a/runtime/doc/if_lua.txt +++ b/runtime/doc/if_lua.txt @@ -243,14 +243,50 @@ position are restricted when the command is executed in the |sandbox|. 2. The vim module *lua-vim* Lua interfaces Vim through the "vim" module. Currently it only has `api` -submodule which is a table with all API functions. Descriptions of these -functions may be found in |api.txt|. +submodule and some Neovim-specific utility values which is a table with all +API functions. Descriptions of the API functions may be found in |api.txt|. +Description of other utilities is below: vim.stricmp(a, b) *lua-vim.stricmp* Function used for case-insensitive string comparison. Takes two string arguments and returns 0, 1 or -1 if strings are equal, a is greater then b or a is lesser then b respectively. +vim.type_idx *lua-vim.type_idx* + Type index for use in |lua-special-tables|. Specifying one of the + values from |lua-vim.types| allows typing the empty table (it is + unclear whether empty lua table represents empty list or empty array) + and forcing integral numbers to be |Float|. See |lua-special-tbl| for + more details. + +vim.val_idx *lua-vim.val_idx* + Value index for tables representing |Float|s. A table representing + floating-point value 1.0 looks like this: > + { + [vim.type_idx] = vim.types.float, + [vim.val_idx] = 1.0, + } +< See also |lua-vim.type_idx| and |lua-special-tbl|. + +vim.types *lua-vim.types* + Table with possible values for |lua-vim.type_idx|. Contains two sets + of key-value pairs: first maps possible values for |lua-vim.type_idx| + to human-readable strings, second maps human-readable type names to + values for |lua-vim.type_idx|. Currently contains pairs for `float`, + `array` and `dictionary` types. + + Note: one must expect that values corresponding to `vim.types.float`, + `vim.types.array` and `vim.types.dictionary` fall under only two + following assumptions: + 1. Value may serve both as a key and as a value in a table. Given the + properties of lua tables this basically means “value is not `nil`”. + 2. For each value in `vim.types` table `vim.types[vim.types[value]]` + is the same as `value`. + No other restrictions are put on types, and it is not guaranteed that + values corresponding to `vim.types.float`, `vim.types.array` and + `vim.types.dictionary` will not change or that `vim.types` table will + only contain values for these three types. + ============================================================================== 3. The luaeval function *lua-luaeval* *lua-eval* *luaeval()* @@ -283,6 +319,7 @@ between these cases there is the following agreement: 3. Table with string keys, at least one of which contains NUL byte, is also considered to be a dictionary, but this time it is converted to a |msgpack-special-map|. + *lua-special-tbl* 4. Table with `vim.type_idx` key may be a dictionary, a list or floating-point value: - `{[vim.type_idx]=vim.types.float, [vim.val_idx]=1}` is converted to -- cgit From 583b68f5a94f362c44ff29c62909969e6908438b Mon Sep 17 00:00:00 2001 From: ckelsel Date: Sun, 24 Sep 2017 11:06:16 +0800 Subject: vim-patch:8.0.0101 Problem: Some options are not strictly checked. Solution: Add flags for strickter checks. https://github.com/vim/vim/commit/031cb743ae154cfb727a9b7787bdcb61202ff1c8 --- src/nvim/option.c | 13 +++++++------ src/nvim/options.lua | 2 ++ src/nvim/version.c | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/nvim/option.c b/src/nvim/option.c index 74250e83e6..ae1a2b1b24 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -3172,17 +3172,18 @@ did_set_string_option ( } else { // Options that are a list of flags. p = NULL; - if (varp == &p_ww) + if (varp == &p_ww) { // 'whichwrap' p = (char_u *)WW_ALL; - if (varp == &p_shm) + } + if (varp == &p_shm) { // 'shortmess' p = (char_u *)SHM_ALL; - else if (varp == &(p_cpo)) + } else if (varp == &(p_cpo)) { // 'cpoptions' p = (char_u *)CPO_VI; - else if (varp == &(curbuf->b_p_fo)) + } else if (varp == &(curbuf->b_p_fo)) { // 'formatoptions' p = (char_u *)FO_ALL; - else if (varp == &curwin->w_p_cocu) + } else if (varp == &curwin->w_p_cocu) { // 'concealcursor' p = (char_u *)COCU_ALL; - else if (varp == &p_mouse) { + } else if (varp == &p_mouse) { // 'mouse' p = (char_u *)MOUSE_ALL; } if (p != NULL) { diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 103227f6b5..757fac9465 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -575,6 +575,7 @@ return { full_name='dictionary', abbreviation='dict', type='string', list='onecomma', scope={'global', 'buffer'}, deny_duplicates=true, + normal_fname_chars=true, vi_def=true, expand=true, varname='p_dict', @@ -1750,6 +1751,7 @@ return { { full_name='printexpr', abbreviation='pexpr', type='string', scope={'global'}, + secure=true, vi_def=true, varname='p_pexpr', defaults={if_true={vi=""}} diff --git a/src/nvim/version.c b/src/nvim/version.c index d4f9c0232f..feb69cae52 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -851,7 +851,7 @@ static const int included_patches[] = { // 104, // 103 NA // 102, - // 101, + 101, 100, 99, // 98 NA -- cgit From d2eba872fb80ec9ace3a244aa706e55c82a48e83 Mon Sep 17 00:00:00 2001 From: ckelsel Date: Sun, 24 Sep 2017 11:06:16 +0800 Subject: vim-patch:8.0.0101 Problem: Some options are not strictly checked. Solution: Add flags for strickter checks. https://github.com/vim/vim/commit/031cb743ae154cfb727a9b7787bdcb61202ff1c8 --- src/nvim/option.c | 13 +++++++------ src/nvim/options.lua | 2 ++ src/nvim/version.c | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/nvim/option.c b/src/nvim/option.c index 74250e83e6..ae1a2b1b24 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -3172,17 +3172,18 @@ did_set_string_option ( } else { // Options that are a list of flags. p = NULL; - if (varp == &p_ww) + if (varp == &p_ww) { // 'whichwrap' p = (char_u *)WW_ALL; - if (varp == &p_shm) + } + if (varp == &p_shm) { // 'shortmess' p = (char_u *)SHM_ALL; - else if (varp == &(p_cpo)) + } else if (varp == &(p_cpo)) { // 'cpoptions' p = (char_u *)CPO_VI; - else if (varp == &(curbuf->b_p_fo)) + } else if (varp == &(curbuf->b_p_fo)) { // 'formatoptions' p = (char_u *)FO_ALL; - else if (varp == &curwin->w_p_cocu) + } else if (varp == &curwin->w_p_cocu) { // 'concealcursor' p = (char_u *)COCU_ALL; - else if (varp == &p_mouse) { + } else if (varp == &p_mouse) { // 'mouse' p = (char_u *)MOUSE_ALL; } if (p != NULL) { diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 103227f6b5..757fac9465 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -575,6 +575,7 @@ return { full_name='dictionary', abbreviation='dict', type='string', list='onecomma', scope={'global', 'buffer'}, deny_duplicates=true, + normal_fname_chars=true, vi_def=true, expand=true, varname='p_dict', @@ -1750,6 +1751,7 @@ return { { full_name='printexpr', abbreviation='pexpr', type='string', scope={'global'}, + secure=true, vi_def=true, varname='p_pexpr', defaults={if_true={vi=""}} diff --git a/src/nvim/version.c b/src/nvim/version.c index d4f9c0232f..feb69cae52 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -851,7 +851,7 @@ static const int included_patches[] = { // 104, // 103 NA // 102, - // 101, + 101, 100, 99, // 98 NA -- cgit From cd13c24427a3191c7383b76a0bf9467bee2736e3 Mon Sep 17 00:00:00 2001 From: ckelsel Date: Sun, 24 Sep 2017 11:54:40 +0800 Subject: vim-patch:8.0.0102 Problem: Cannot set 'dictionary' to a path. Solution: Allow for slash and backslash. Add a test (partly by Daisuke Suzuki, closes vim/vim#1279, closes vim/vim#1284) https://github.com/vim/vim/commit/7554da4033498c4da0af3cde542c3e87e9097b73 --- src/nvim/generators/gen_options.lua | 1 + src/nvim/option.c | 13 ++++++++----- src/nvim/options.lua | 4 ++-- src/nvim/testdir/test_options.vim | 15 +++++++++++++++ src/nvim/version.c | 2 +- 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index ca0134043c..36562c0be9 100644 --- a/src/nvim/generators/gen_options.lua +++ b/src/nvim/generators/gen_options.lua @@ -74,6 +74,7 @@ local get_flags = function(o) {'gettext'}, {'noglob'}, {'normal_fname_chars', 'P_NFNAME'}, + {'normal_dname_chars', 'P_NDNAME'}, {'pri_mkrc'}, {'deny_in_modelines', 'P_NO_ML'}, {'deny_duplicates', 'P_NODUP'}, diff --git a/src/nvim/option.c b/src/nvim/option.c index ae1a2b1b24..6ed4989a4c 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -242,6 +242,7 @@ typedef struct vimoption { #define P_NO_DEF_EXP 0x8000000U ///< Do not expand default value. #define P_RWINONLY 0x10000000U ///< only redraw current window +#define P_NDNAME 0x20000000U ///< only normal dir name chars allowed #define HIGHLIGHT_INIT \ "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText," \ @@ -2454,11 +2455,13 @@ did_set_string_option ( if ((secure || sandbox != 0) && (options[opt_idx].flags & P_SECURE)) { errmsg = e_secure; - } else if ((options[opt_idx].flags & P_NFNAME) - && vim_strpbrk(*varp, (char_u *)"/\\*?[|;&<>\r\n") != NULL) { - // Check for a "normal" file name in some options. Disallow a path - // separator (slash and/or backslash), wildcards and characters that are - // often illegal in a file name. + } else if ((((options[opt_idx].flags & P_NFNAME) + && vim_strpbrk(*varp, (char_u *)"/\\*?[|;&<>\r\n") != NULL)) + || ((options[opt_idx].flags & P_NDNAME) + && vim_strpbrk(*varp, (char_u *)"*?[|;&<>\r\n") != NULL)) { + // Check for a "normal" directory or file name in some options. Disallow a + // path separator (slash and/or backslash), wildcards and characters that + // are often illegal in a file name. errmsg = e_invarg; } /* 'backupcopy' */ diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 757fac9465..cce9e10409 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -7,7 +7,7 @@ -- enable_if=nil, -- defaults={condition=nil, if_true={vi=224, vim=0}, if_false=nil}, -- secure=nil, gettext=nil, noglob=nil, normal_fname_chars=nil, --- pri_mkrc=nil, deny_in_modelines=nil, +-- pri_mkrc=nil, deny_in_modelines=nil, normal_dname_chars=nil, -- expand=nil, nodefault=nil, no_mkrc=nil, vi_def=true, vim=true, -- alloced=nil, -- save_pv_indir=nil, @@ -575,7 +575,7 @@ return { full_name='dictionary', abbreviation='dict', type='string', list='onecomma', scope={'global', 'buffer'}, deny_duplicates=true, - normal_fname_chars=true, + normal_dname_chars=true, vi_def=true, expand=true, varname='p_dict', diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index 2ffe63787b..ea020d9ca0 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -103,3 +103,18 @@ func Test_keymap_valid() call assert_fails(":set kmp=trunc\x00name", "E544:") call assert_fails(":set kmp=trunc\x00name", "trunc") endfunc + +func Test_dictionary() + " Check that it's possible to set the option. + set dictionary=/usr/share/dict/words + call assert_equal('/usr/share/dict/words', &dictionary) + set dictionary=/usr/share/dict/words,/and/there + call assert_equal('/usr/share/dict/words,/and/there', &dictionary) + set dictionary=/usr/share/dict\ words + call assert_equal('/usr/share/dict words', &dictionary) + + " Check rejecting weird characters. + call assert_fails("set dictionary=/not&there", "E474:") + call assert_fails("set dictionary=/not>there", "E474:") + call assert_fails("set dictionary=/not.*there", "E474:") +endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index feb69cae52..890587b307 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -850,7 +850,7 @@ static const int included_patches[] = { // 105 NA // 104, // 103 NA - // 102, + 102, 101, 100, 99, -- cgit From 25a3f77f614260c945c32a56607b36a603b914be Mon Sep 17 00:00:00 2001 From: ckelsel Date: Sun, 24 Sep 2017 13:21:07 +0800 Subject: vim-patch:8.0.0106 Problem: Cannot use a semicolon in 'backupext'. (Jeff) Solution: Allow for a few more characters when "secure" isn't set. https://github.com/vim/vim/commit/0945eaface83e78138fbd40f95cc590bab0e8c86 --- src/nvim/option.c | 7 ++++--- src/nvim/version.c | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/nvim/option.c b/src/nvim/option.c index 6ed4989a4c..e989f700ae 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2455,13 +2455,14 @@ did_set_string_option ( if ((secure || sandbox != 0) && (options[opt_idx].flags & P_SECURE)) { errmsg = e_secure; - } else if ((((options[opt_idx].flags & P_NFNAME) - && vim_strpbrk(*varp, (char_u *)"/\\*?[|;&<>\r\n") != NULL)) + } else if (((options[opt_idx].flags & P_NFNAME) + && vim_strpbrk(*varp, (char_u *)(secure + ? "/\\*?[|;&<>\r\n" : "/\\*?[<>\r\n")) != NULL) || ((options[opt_idx].flags & P_NDNAME) && vim_strpbrk(*varp, (char_u *)"*?[|;&<>\r\n") != NULL)) { // Check for a "normal" directory or file name in some options. Disallow a // path separator (slash and/or backslash), wildcards and characters that - // are often illegal in a file name. + // are often illegal in a file name. Be more permissive if "secure" is off. errmsg = e_invarg; } /* 'backupcopy' */ diff --git a/src/nvim/version.c b/src/nvim/version.c index 06482bf490..f6a9418dbf 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -846,7 +846,7 @@ static const int included_patches[] = { // 109 NA // 108 NA // 107 NA - // 106, + 106, // 105 NA 104, // 103 NA -- cgit From 3a1c33a6c3ad5074bfc442507282a438726f1b58 Mon Sep 17 00:00:00 2001 From: ckelsel Date: Sun, 24 Sep 2017 13:21:07 +0800 Subject: vim-patch:8.0.0106 Problem: Cannot use a semicolon in 'backupext'. (Jeff) Solution: Allow for a few more characters when "secure" isn't set. https://github.com/vim/vim/commit/0945eaface83e78138fbd40f95cc590bab0e8c86 --- src/nvim/option.c | 7 ++++--- src/nvim/version.c | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/nvim/option.c b/src/nvim/option.c index 6ed4989a4c..e989f700ae 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2455,13 +2455,14 @@ did_set_string_option ( if ((secure || sandbox != 0) && (options[opt_idx].flags & P_SECURE)) { errmsg = e_secure; - } else if ((((options[opt_idx].flags & P_NFNAME) - && vim_strpbrk(*varp, (char_u *)"/\\*?[|;&<>\r\n") != NULL)) + } else if (((options[opt_idx].flags & P_NFNAME) + && vim_strpbrk(*varp, (char_u *)(secure + ? "/\\*?[|;&<>\r\n" : "/\\*?[<>\r\n")) != NULL) || ((options[opt_idx].flags & P_NDNAME) && vim_strpbrk(*varp, (char_u *)"*?[|;&<>\r\n") != NULL)) { // Check for a "normal" directory or file name in some options. Disallow a // path separator (slash and/or backslash), wildcards and characters that - // are often illegal in a file name. + // are often illegal in a file name. Be more permissive if "secure" is off. errmsg = e_invarg; } /* 'backupcopy' */ diff --git a/src/nvim/version.c b/src/nvim/version.c index 06482bf490..f6a9418dbf 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -846,7 +846,7 @@ static const int included_patches[] = { // 109 NA // 108 NA // 107 NA - // 106, + 106, // 105 NA 104, // 103 NA -- cgit From 4543fc1612183da659a9ca10f826ae59e2186f22 Mon Sep 17 00:00:00 2001 From: KillTheMule Date: Sat, 30 Sep 2017 22:20:47 +0200 Subject: menu_get: prettyprint special chars --- src/nvim/menu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nvim/menu.c b/src/nvim/menu.c index 0db250d111..69700e34fd 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -698,7 +698,9 @@ static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes) if (*menu->strings[bit] == NUL) { tv_dict_add_str(impl, S_LEN("rhs"), (char *)""); } else { - tv_dict_add_str(impl, S_LEN("rhs"), (char *)menu->strings[bit]); + tv_dict_add_allocated_str(impl, S_LEN("rhs"), + str2special_save((char *)menu->strings[bit], + false, false)); } tv_dict_add_nr(impl, S_LEN("silent"), menu->silent[bit]); tv_dict_add_nr(impl, S_LEN("enabled"), -- cgit From 9fb8b47ad845b0dc95da64705276c9f163e97f6c Mon Sep 17 00:00:00 2001 From: KillTheMule Date: Sat, 30 Sep 2017 22:21:06 +0200 Subject: menu_get: adjust tests for prettyprinting ... and add a bit of new testing --- test/functional/ex_cmds/menu_spec.lua | 102 +++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 2 deletions(-) diff --git a/test/functional/ex_cmds/menu_spec.lua b/test/functional/ex_cmds/menu_spec.lua index 55da8da8dc..5238752af4 100644 --- a/test/functional/ex_cmds/menu_spec.lua +++ b/test/functional/ex_cmds/menu_spec.lua @@ -107,7 +107,7 @@ describe('menu_get', function() sid = 1, noremap = 1, enabled = 1, - rhs = "inormal\27", + rhs = "inormal", silent = 0 }, v = { @@ -242,7 +242,7 @@ describe('menu_get', function() sid = 1, noremap = 1, enabled = 1, - rhs = "\18\"", + rhs = "\"", silent = 0 }, n = { @@ -380,4 +380,102 @@ describe('menu_get', function() eq(expected, m) end) + it('prettyprints special chars', function() + clear() + command('nnoremenu &Test.Test inormal') + command('inoremenu &Test.Test2 ') + command('vnoremenu &Test.Test3 yA0xyz') + command('inoremenu &Test.Test4 *') + command('inoremenu &Test.Test5 +') + local m = funcs.menu_get("","a"); + local expected = { + { + shortcut = "T", + hidden = 0, + submenus = { + { + priority = 500, + mappings = { + n = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "inormal", + silent = 0 + } + }, + name = "Test", + hidden = 0 + }, + { + priority = 500, + mappings = { + i = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "", + silent = 0 + } + }, + name = "Test2", + hidden = 0 + }, + { + priority = 500, + mappings = { + s = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "yA0xyz", + silent = 0 + }, + v = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "yA0xyz", + silent = 0 + } + }, + name = "Test3", + hidden = 0 + }, + { + priority = 500, + mappings = { + i = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "*", + silent = 0 + } + }, + name = "Test4", + hidden = 0 + }, + { + priority = 500, + mappings = { + i = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "+", + silent = 0 + } + }, + name = "Test5", + hidden = 0 + } + }, + priority = 500, + name = "Test" + } + } + + eq(m, expected) + end) end) -- cgit From 41f624a85b95d54ce038637cbe53530ad1b99f53 Mon Sep 17 00:00:00 2001 From: KillTheMule Date: Mon, 2 Oct 2017 14:55:19 +0200 Subject: Deal with NOP, add actext to output --- src/nvim/menu.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/nvim/menu.c b/src/nvim/menu.c index 69700e34fd..88d968704b 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -682,6 +682,10 @@ static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes) tv_dict_add_str(dict, S_LEN("shortcut"), buf); } + if (menu->actext) { + tv_dict_add_str(dict, S_LEN("actext"), (char *)menu->actext); + } + if (menu->modes & MENU_TIP_MODE && menu->strings[MENU_INDEX_TIP]) { tv_dict_add_str(dict, S_LEN("tooltip"), (char *)menu->strings[MENU_INDEX_TIP]); @@ -695,13 +699,9 @@ static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes) for (int bit = 0; bit < MENU_MODES; bit++) { if ((menu->modes & modes & (1 << bit)) != 0) { dict_T *impl = tv_dict_alloc(); - if (*menu->strings[bit] == NUL) { - tv_dict_add_str(impl, S_LEN("rhs"), (char *)""); - } else { - tv_dict_add_allocated_str(impl, S_LEN("rhs"), - str2special_save((char *)menu->strings[bit], - false, false)); - } + tv_dict_add_allocated_str(impl, S_LEN("rhs"), + str2special_save((char *)menu->strings[bit], + false, false)); tv_dict_add_nr(impl, S_LEN("silent"), menu->silent[bit]); tv_dict_add_nr(impl, S_LEN("enabled"), (menu->enabled & (1 << bit)) ? 1 : 0); -- cgit From 1f6138702c5413bd870fb14e2237c5b42f061cd2 Mon Sep 17 00:00:00 2001 From: KillTheMule Date: Mon, 2 Oct 2017 14:55:25 +0200 Subject: More tests --- test/functional/ex_cmds/menu_spec.lua | 310 +++++++++++++++++++++++++--------- 1 file changed, 230 insertions(+), 80 deletions(-) diff --git a/test/functional/ex_cmds/menu_spec.lua b/test/functional/ex_cmds/menu_spec.lua index 5238752af4..2bc73d811b 100644 --- a/test/functional/ex_cmds/menu_spec.lua +++ b/test/functional/ex_cmds/menu_spec.lua @@ -379,6 +379,13 @@ describe('menu_get', function() } eq(expected, m) end) +end) + +describe('menu_get', function() + + before_each(function() + clear() + end) it('prettyprints special chars', function() clear() @@ -387,94 +394,237 @@ describe('menu_get', function() command('vnoremenu &Test.Test3 yA0xyz') command('inoremenu &Test.Test4 *') command('inoremenu &Test.Test5 +') - local m = funcs.menu_get("","a"); + command('nnoremenu &Test.Test6 ') + command('nnoremenu &Test.Test7 ') + command('nnoremenu &Test.Test8 ') + command('nnoremenu &Test.Test9 ""') + + local m = funcs.menu_get(""); local expected = { - { - shortcut = "T", - hidden = 0, - submenus = { - { - priority = 500, - mappings = { - n = { - sid = 1, - noremap = 1, - enabled = 1, - rhs = "inormal", - silent = 0 - } - }, - name = "Test", - hidden = 0 + { + shortcut = "T", + hidden = 0, + submenus = { + { + priority = 500, + mappings = { + n = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "inormal", + silent = 0 + } }, - { - priority = 500, - mappings = { - i = { - sid = 1, - noremap = 1, - enabled = 1, - rhs = "", - silent = 0 - } - }, - name = "Test2", - hidden = 0 + name = "Test", + hidden = 0 + }, + { + priority = 500, + mappings = { + i = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "", + silent = 0 + } }, - { - priority = 500, - mappings = { - s = { - sid = 1, - noremap = 1, - enabled = 1, - rhs = "yA0xyz", - silent = 0 - }, - v = { - sid = 1, - noremap = 1, - enabled = 1, - rhs = "yA0xyz", - silent = 0 - } + name = "Test2", + hidden = 0 + }, + { + priority = 500, + mappings = { + s = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "yA0xyz", + silent = 0 }, - name = "Test3", - hidden = 0 + v = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "yA0xyz", + silent = 0 + } }, - { - priority = 500, - mappings = { - i = { - sid = 1, - noremap = 1, - enabled = 1, - rhs = "*", - silent = 0 - } - }, - name = "Test4", - hidden = 0 + name = "Test3", + hidden = 0 + }, + { + priority = 500, + mappings = { + i = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "*", + silent = 0 + } }, - { - priority = 500, - mappings = { - i = { - sid = 1, - noremap = 1, - enabled = 1, - rhs = "+", - silent = 0 - } - }, - name = "Test5", - hidden = 0 - } + name = "Test4", + hidden = 0 }, - priority = 500, - name = "Test" - } + { + priority = 500, + mappings = { + i = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "+", + silent = 0 + } + }, + name = "Test5", + hidden = 0 + }, + { + priority = 500, + mappings = { + n = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "", + silent = 0 + } + }, + name = "Test6", + hidden = 0 + }, + { + priority = 500, + mappings = { + n = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "", + silent = 0 + } + }, + name = "Test7", + hidden = 0 + }, + { + priority = 500, + mappings = { + n = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "", + silent = 0 + } + }, + name = "Test8", + hidden = 0 + }, + { + priority = 500, + mappings = { + n = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "\"\"", + silent = 0 + } + }, + name = "Test9", + hidden = 0 + } + }, + priority = 500, + name = "Test" + } + } + + eq(m, expected) + end) + + it('works with right-aligned text and spaces', function() + clear() + command('nnoremenu &TestY.TestX\\ x inormal') + command('nnoremenu &Test\\ 1.Test\\ 2 Wargl') + command('nnoremenu &Test4.Test3 i space') + + local m = funcs.menu_get(""); + local expected = { + { + shortcut = "T", + hidden = 0, + actext = "Y", + submenus = { + { + mappings = { + n = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "inormal", + silent = 0 + } + }, + hidden = 0, + actext = "X x", + priority = 500, + name = "Test" + } + }, + priority = 500, + name = "Test" + }, + { + shortcut = "T", + hidden = 0, + submenus = { + { + priority = 500, + mappings = { + n = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "Wargl", + silent = 0 + } + }, + name = "Test 2", + hidden = 0 + } + }, + priority = 500, + name = "Test 1" + }, + { + shortcut = "T", + hidden = 0, + submenus = { + { + mappings = { + n = { + sid = 1, + noremap = 1, + enabled = 1, + rhs = "i space", + silent = 0 + } + }, + hidden = 0, + actext = "3", + priority = 500, + name = "Test" + } + }, + priority = 500, + name = "Test4" } + } eq(m, expected) end) -- cgit From 97dc1350f0d4f8509ebad2beb7da8847b81bbf4b Mon Sep 17 00:00:00 2001 From: ckelsel Date: Tue, 10 Oct 2017 14:53:27 +0800 Subject: vim-patch:8.0.0183 NA Problem: Ubsan warns for using a pointer that is not aligned. Solution: First copy the address. (Yegappan Lakshmanan) https://github.com/vim/vim/commit/7173b47958a238bb07f80b8f26fb232b0ea69b4a --- src/nvim/version.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/version.c b/src/nvim/version.c index 7e59f3327a..cb66dcd6fe 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -920,7 +920,7 @@ static const int included_patches[] = { 186, // 185, // 184, - // 183, + // 183 NA 182, 181, // 180, -- cgit From 56eda2aa17c80ba380b606f9466f288fb8162dd3 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 16 Oct 2017 08:18:03 +0200 Subject: syntax: 'cursorline': revert priority change (#7400) ref #7383 reverts d1874ab2821d076397290cc154d87ec2dc352c79 ref #6380 --- runtime/doc/vim_diff.txt | 4 ++-- src/nvim/screen.c | 37 ++++++++++++++++++----------------- test/functional/ui/highlight_spec.lua | 6 +++--- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index 861fa65c3a..5df3852d8e 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -281,8 +281,8 @@ other arguments if used). |input()| and |inputdialog()| support user-defined cmdline highlighting. Highlight groups: - |hl-ColorColumn|, |hl-CursorColumn|, |hl-CursorLine| are lower priority than - (overridden by) most other highlight groups. + |hl-ColorColumn|, |hl-CursorColumn| are lower priority than most other + groups ============================================================================== 5. Missing legacy features *nvim-features-missing* diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 5659f30f64..f5730cf70a 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2202,7 +2202,6 @@ win_line ( colnr_T trailcol = MAXCOL; /* start of trailing spaces */ int need_showbreak = false; // overlong line, skip first x chars int line_attr = 0; // attribute for the whole line - int line_attr_low_priority = 0; // current line, lowest priority matchitem_T *cur; // points to the match list match_T *shl; // points to search_hl or a match int shl_flag; // flag to indicate whether search_hl @@ -2428,13 +2427,7 @@ win_line ( filler_lines = wp->w_topfill; filler_todo = filler_lines; - // 'cursorline' highlighting for the current window. Not when Visual mode is - // active, because it's not clear what is selected then. - if (wp->w_p_cul && lnum == wp->w_cursor.lnum - && !(wp == curwin && VIsual_active)) { - line_attr_low_priority = win_hl_attr(wp, HLF_CUL); - } - + // If this line has a sign with line highlighting set line_attr. v = buf_getsigntype(wp->w_buffer, lnum, SIGN_LINEHL); if (v != 0) { line_attr = sign_get_attr((int)v, true); @@ -2449,7 +2442,7 @@ win_line ( line_attr = hl_combine_attr(wp->w_hl_attr_normal, line_attr); } - if (line_attr_low_priority || line_attr) { + if (line_attr != 0) { area_highlighting = true; } @@ -2671,6 +2664,20 @@ win_line ( cur = cur->next; } + // Cursor line highlighting for 'cursorline' in the current window. Not + // when Visual mode is active, because it's not clear what is selected + // then. + if (wp->w_p_cul && lnum == wp->w_cursor.lnum + && !(wp == curwin && VIsual_active)) { + if (line_attr != 0 && !(State & INSERT) && bt_quickfix(wp->w_buffer) + && qf_current_entry(wp) == lnum) { + line_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUL), line_attr); + } else { + line_attr = win_hl_attr(wp, HLF_CUL); + } + area_highlighting = true; + } + off = (unsigned)(current_ScreenLine - ScreenLines); col = 0; if (wp->w_p_rl) { @@ -3589,9 +3596,7 @@ win_line ( // Display a '$' after the line or highlight an extra // character if the line break is included. // For a diff line the highlighting continues after the "$". - if (diff_hlf == (hlf_T)0 - && line_attr == 0 - && line_attr_low_priority == 0) { + if (diff_hlf == (hlf_T)0 && line_attr == 0) { // In virtualedit, visual selections may extend beyond end of line. if (area_highlighting && virtual_active() && tocol != MAXCOL && vcol < tocol) { @@ -3655,7 +3660,7 @@ win_line ( (col < wp->w_width))) { c = ' '; ptr--; // put it back at the NUL - } else if ((diff_hlf != (hlf_T)0 || line_attr_low_priority || line_attr) + } else if ((diff_hlf != (hlf_T)0 || line_attr != 0) && (wp->w_p_rl ? (col >= 0) : (col - boguscols < wp->w_width))) { @@ -3667,8 +3672,7 @@ win_line ( did_line_attr++; // don't do search HL for the rest of the line - if ((line_attr_low_priority || line_attr) - && char_attr == search_attr && col > 0) { + if (line_attr != 0 && char_attr == search_attr && col > 0) { char_attr = line_attr; } if (diff_hlf == HLF_TXD) { @@ -4037,9 +4041,6 @@ win_line ( } } - // Apply `line_attr_low_priority` now, so that everthing can override it. - char_attr = hl_combine_attr(line_attr_low_priority, char_attr); - /* * Store character to be displayed. * Skip characters that are left of the screen for 'nowrap'. diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 077b0ec14c..d1357ea525 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -518,7 +518,7 @@ describe("'listchars' highlight", function() ]]) feed_command('set cursorline') screen:expect([[ - {2:^>-------.}{1:abcd}{2:.}{1:Lorem}{3:>}| + {2:^>-------.}{1:abcd}{2:.}{1:Lorem}{4:>}| {5:>-------.}abcd{5:*}{4:¬} | {4:¬} | {4:~ }| @@ -526,7 +526,7 @@ describe("'listchars' highlight", function() ]]) feed('$') screen:expect([[ - {3:<}{1:r}{2:.}{1:sit}{2:.}{1:ame^t}{3:¬}{1: }| + {4:<}{1:r}{2:.}{1:sit}{2:.}{1:ame^t}{3:¬}{1: }| {4:<} | {4:<} | {4:~ }| @@ -607,7 +607,7 @@ describe("'listchars' highlight", function() feed('$') screen:expect([[ {4:<} | - {3:<}{1:r}{2:.}{1:sit}{2:.}{1:ame^t}{3:¬}{1: }| + {4:<}{1:r}{2:.}{1:sit}{2:.}{1:ame^t}{3:¬}{1: }| {4:<} | {4:~ }| | -- cgit From 2f4647e77b7e8271aad1b45eb07fbabed78d9fe6 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 16 Oct 2017 21:59:13 +0200 Subject: test: avoid redundant clear() #7340 --- test/functional/ex_cmds/menu_spec.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/functional/ex_cmds/menu_spec.lua b/test/functional/ex_cmds/menu_spec.lua index 2bc73d811b..2c0535acda 100644 --- a/test/functional/ex_cmds/menu_spec.lua +++ b/test/functional/ex_cmds/menu_spec.lua @@ -387,8 +387,7 @@ describe('menu_get', function() clear() end) - it('prettyprints special chars', function() - clear() + it('returns representation of special keys', function() command('nnoremenu &Test.Test inormal') command('inoremenu &Test.Test2 ') command('vnoremenu &Test.Test3 yA0xyz') @@ -548,7 +547,6 @@ describe('menu_get', function() end) it('works with right-aligned text and spaces', function() - clear() command('nnoremenu &TestY.TestX\\ x inormal') command('nnoremenu &Test\\ 1.Test\\ 2 Wargl') command('nnoremenu &Test4.Test3 i space') -- cgit From 5baeb4a49c061472a125f98af798c522d8504fbe Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 15 Oct 2017 18:29:53 +0200 Subject: ex-cmds: :checkhealth Built-in `:checkhealth` checks for valid $VIMRUNTIME by attempting to autoload `health#check()`. closes #2977 closes #3159 --- src/nvim/eval.c | 29 +++++++++++++++++++++++++++++ src/nvim/ex_cmds.lua | 6 ++++++ test/functional/plugin/health_spec.lua | 26 ++++++++++++++++++++++++-- 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index b2a0d9a767..986c4a9a17 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -22850,3 +22850,32 @@ void eval_format_source_name_line(char *buf, size_t bufsize) (sourcing_name ? sourcing_name : (char_u *)"?"), (sourcing_name ? sourcing_lnum : 0)); } + +/// ":checkhealth [plugins]" +void ex_checkhealth(exarg_T *eap) +{ + bool found = !!find_func((char_u *)"health#check"); + if (!found + && script_autoload("health#check", sizeof("health#check") - 1, false)) { + found = !!find_func((char_u *)"health#check"); + } + if (!found) { + const char *vimruntime_env = os_getenv("VIMRUNTIME"); + if (vimruntime_env == NULL) { + EMSG(_("E5009: $VIMRUNTIME is empty or unset")); + return; + } else { + EMSG2(_("E5009: Invalid $VIMRUNTIME: %s"), os_getenv("VIMRUNTIME")); + return; + } + } + + size_t bufsize = STRLEN(eap->arg) + strlen("CheckHealth ") + 1; + char *buf = xmalloc(bufsize); + snprintf(buf, bufsize, "CheckHealth %s", eap->arg); + + do_cmdline_cmd(buf); + + xfree(buf); +} + diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 5a578cd088..f99954db7a 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -450,6 +450,12 @@ return { addr_type=ADDR_LINES, func='ex_changes', }, + { + command='checkhealth', + flags=bit.bor(EXTRA, TRLBAR), + addr_type=ADDR_LINES, + func='ex_checkhealth', + }, { command='checkpath', flags=bit.bor(TRLBAR, BANG, CMDWIN), diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua index 8646ec98bf..a85a3ce495 100644 --- a/test/functional/plugin/health_spec.lua +++ b/test/functional/plugin/health_spec.lua @@ -2,7 +2,29 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local plugin_helpers = require('test.functional.plugin.helpers') +local clear = helpers.clear local command = helpers.command +local eq = helpers.eq + +describe(':checkhealth', function() + it("detects invalid $VIMRUNTIME", function() + clear({ + env={ VIMRUNTIME='bogus', }, + }) + local status, err = pcall(command, 'checkhealth') + eq(false, status) + eq('Invalid $VIMRUNTIME: bogus', string.match(err, 'Invalid.*')) + end) + it("detects invalid $VIM", function() + clear({ + env={ VIM='bogus', }, + }) + local status, err = pcall(command, 'checkhealth') + eq(false, status) + -- Invalid $VIM causes $VIMRUNTIME to be broken. + eq('Invalid $VIMRUNTIME: bogus', string.match(err, 'Invalid.*')) + end) +end) describe('health.vim', function() before_each(function() @@ -14,7 +36,7 @@ describe('health.vim', function() command("set runtimepath+=test/functional/fixtures") end) - it("reports", function() + it("health#report_*()", function() helpers.source([[ let g:health_report = execute([ \ "call health#report_start('Check Bar')", @@ -44,7 +66,7 @@ describe('health.vim', function() end) - describe(":CheckHealth", function() + describe(":checkhealth", function() it("concatenates multiple reports", function() command("CheckHealth success1 success2") helpers.expect([[ -- cgit From d214df4e9b23b5f2d9f7e6c78624881a7d298cdb Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 15 Oct 2017 20:31:12 +0200 Subject: doc: replace ":CheckHealth" with ":checkhealth" --- runtime/autoload/health.vim | 2 +- runtime/autoload/provider/ruby.vim | 2 +- runtime/doc/pi_health.txt | 92 +++++++++------------- runtime/doc/provider.txt | 4 +- runtime/doc/vim_diff.txt | 2 +- src/nvim/ops.c | 2 +- src/nvim/version.c | 2 +- .../clipboard/clipboard_provider_spec.lua | 6 +- test/functional/plugin/health_spec.lua | 8 +- test/functional/provider/ruby_spec.lua | 2 +- 10 files changed, 53 insertions(+), 69 deletions(-) diff --git a/runtime/autoload/health.vim b/runtime/autoload/health.vim index d0ad7729ab..028b6cca8e 100644 --- a/runtime/autoload/health.vim +++ b/runtime/autoload/health.vim @@ -18,7 +18,7 @@ function! s:enhance_syntax() abort syntax match healthBar "|" contained conceal highlight link healthHelp Identifier - " We do not care about markdown syntax errors in :CheckHealth output. + " We do not care about markdown syntax errors in :checkhealth output. highlight! link markdownError Normal endfunction diff --git a/runtime/autoload/provider/ruby.vim b/runtime/autoload/provider/ruby.vim index 91b7fb9f2c..7df3500267 100644 --- a/runtime/autoload/provider/ruby.vim +++ b/runtime/autoload/provider/ruby.vim @@ -75,7 +75,7 @@ let s:prog = provider#ruby#Detect() let s:plugin_path = expand(':p:h') . '/script_host.rb' if empty(s:prog) - let s:err = 'Cannot find the neovim RubyGem. Try :CheckHealth' + let s:err = 'Cannot find the neovim RubyGem. Try :checkhealth' endif call remote#host#RegisterClone('legacy-ruby-provider', 'ruby') diff --git a/runtime/doc/pi_health.txt b/runtime/doc/pi_health.txt index f77267288c..3fd649f1f8 100644 --- a/runtime/doc/pi_health.txt +++ b/runtime/doc/pi_health.txt @@ -5,50 +5,36 @@ Author: TJ DeVries Type to see the table of contents. ============================================================================== -Introduction *healthcheck* *health.vim-intro* +Introduction *health* -Troubleshooting user configuration problems is a time-consuming task that -developers want to minimize. health.vim provides a simple framework for plugin -authors to hook into, and for users to invoke, to check and report the user's -configuration and environment. Type this command to try it: > +health.vim is a minimal framework to help with troubleshooting user +configuration. Nvim ships with healthchecks for configuration, performance, +python support, ruby support, clipboard support, and more. - :CheckHealth -< -For example, some users have broken or unusual Python setups, which breaks the -|:python| command. |:CheckHealth| detects several common Python configuration -problems and reports them. If the Neovim Python module is not installed, it -shows a warning: > +To run the healthchecks, use this command: > - You have not installed the Neovim Python module - You might want to try `pip install Neovim` -< -Plugin authors are encouraged to add healthchecks, see |health.vim-dev|. + :checkhealth +< +Plugin authors are encouraged to write new healthchecks. |health-dev| ============================================================================== -Commands and functions *health.vim-manual* - -Commands ------------------------------------------------------------------------------- - *:CheckHealth* -:CheckHealth Run all healthchecks and show the output in a new - tabpage. These healthchecks are included by default: - - python2 - - python3 - - ruby - - remote plugin - -:CheckHealth {plugins} - Run healthchecks for one or more plugins. E.g. to run +Commands *health-commands* + + *:checkhealth* *:CheckHealth* +:checkhealth Run all healthchecks. + +:checkhealth {plugins} + Run healthcheck(s) for one or more plugins. E.g. to run only the standard Nvim healthcheck: > - :CheckHealth nvim + :checkhealth nvim < To run the healthchecks for the "foo" and "bar" plugins (assuming these plugins are on your 'runtimepath' and they have implemented health#foo#check() and health#bar#check(), respectively): > - :CheckHealth foo bar + :checkhealth foo bar < -Functions ------------------------------------------------------------------------------- +============================================================================== +Functions *health-functions* health.vim functions are for creating new healthchecks. They mostly just do some layout and formatting, to give users a consistent presentation. @@ -59,51 +45,49 @@ health#report_start({name}) *health#report_start* per section. health#report_info({msg}) *health#report_info* - Displays an informational message. + Reports an informational message. health#report_ok({msg}) *health#report_ok* - Displays a "success" message. + Reports a "success" message. health#report_warn({msg}, [{advice}]) *health#report_warn* - Displays a warning. {advice} is an optional List of suggestions. + Reports a warning. {advice} is an optional List of suggestions. health#report_error({msg}, [{advice}]) *health#report_error* - Displays an error. {advice} is an optional List of suggestions. + Reports an error. {advice} is an optional List of suggestions. health#{plugin}#check() *health.user_checker* - This is the form of a healthcheck definition. Call the above functions - from this function, then |:CheckHealth| does the rest. Example: > + Healthcheck function for {plugin}. Called by |:checkhealth| + automatically. Example: > function! health#my_plug#check() abort silent call s:check_environment_vars() silent call s:check_python_configuration() endfunction < - The function will be found and called automatically when the user - invokes |:CheckHealth|. - All output will be captured from the healthcheck. Use the health#report_* functions so that your healthcheck has a format consistent with the standard healthchecks. ============================================================================== -Create a healthcheck *health.vim-dev* +Create a healthcheck *health-dev* -Healthchecks are functions that check the health of the system. Neovim has -built-in checkers, found in $VIMRUNTIME/autoload/health/. +Healthchecks are functions that check the user environment, configuration, +etc. Nvim has built-in healthchecks in $VIMRUNTIME/autoload/health/. -To add a new checker for your own plugin, simply define a +To add a new healthcheck for your own plugin, simply define a health#{plugin}#check() function in autoload/health/{plugin}.vim. -|:CheckHealth| automatically finds and invokes such functions. +|:checkhealth| automatically finds and invokes such functions. -If your plugin is named "jslint", then its healthcheck function must be > - health#jslint#check() +If your plugin is named "foo", then its healthcheck function must be > + health#foo#check() defined in this file on 'runtimepath': > - autoload/health/jslint.vim + autoload/health/foo.vim -Here's a sample to get started: > - function! health#jslint#check() abort +Copy this sample code into autoload/health/foo.vim and replace "foo" with your +plugin name: > + function! health#foo#check() abort call health#report_start('sanity checks') " perform arbitrary checks " ... @@ -111,8 +95,8 @@ Here's a sample to get started: > if looks_good call health#report_ok('found required dependencies') else - call health#report_error('cannot find jslint', - \ ['npm install --save jslint']) + call health#report_error('cannot find foo', + \ ['npm install --save foo']) endif endfunction diff --git a/runtime/doc/provider.txt b/runtime/doc/provider.txt index 50307ccbf3..60d0414edd 100644 --- a/runtime/doc/provider.txt +++ b/runtime/doc/provider.txt @@ -20,7 +20,7 @@ Note: Only the Vim 7.3 API is supported; bindeval (Vim 7.4) is not. PYTHON QUICKSTART ~ If you used a package manager to install Nvim, you might already have the -required `neovim` Python package. Run |:CheckHealth| to see if your system is +required `neovim` Python package. Run |:checkhealth| to see if your system is up-to-date. Following are steps to install the package with Python's `pip` tool. @@ -88,7 +88,7 @@ Ruby integration *provider-ruby* Nvim supports the Vim legacy |ruby-vim| interface via external Ruby interpreters connected via |RPC|. -Run |:CheckHealth| to see if your system is up-to-date. +Run |:checkhealth| to see if your system is up-to-date. RUBY QUICKSTART ~ diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index 5df3852d8e..16a63a2df4 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -127,7 +127,7 @@ Variables: |v:windowid| is always available (for use by external UIs) Commands: - |:CheckHealth| + |:checkhealth| |:drop| is available on all platforms |:Man| is available by default, with many improvements such as completion diff --git a/src/nvim/ops.c b/src/nvim/ops.c index e7bc20698b..c6df71ea46 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -5535,7 +5535,7 @@ int get_default_register_name(void) static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing) { #define MSG_NO_CLIP "clipboard: No provider. " \ - "Try \":CheckHealth\" or \":h clipboard\"." + "Try \":checkhealth\" or \":h clipboard\"." yankreg_T *target = NULL; bool explicit_cb_reg = (*name == '*' || *name == '+'); diff --git a/src/nvim/version.c b/src/nvim/version.c index 7e59f3327a..c2a8dcac07 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -1365,7 +1365,7 @@ void intro_message(int colon) N_("https://neovim.io/community"), "", N_("type :help nvim if you are new! "), - N_("type :CheckHealth to optimize Nvim"), + N_("type :checkhealth to optimize Nvim"), N_("type :q to exit "), N_("type :help for help "), "", diff --git a/test/functional/clipboard/clipboard_provider_spec.lua b/test/functional/clipboard/clipboard_provider_spec.lua index b90335e70a..a3ea3b568f 100644 --- a/test/functional/clipboard/clipboard_provider_spec.lua +++ b/test/functional/clipboard/clipboard_provider_spec.lua @@ -100,7 +100,7 @@ describe('clipboard', function() ^ | ~ | ~ | - clipboard: No provider. Try ":CheckHealth" or ":h clipboard". | + clipboard: No provider. Try ":checkhealth" or ":h clipboard". | ]], nil, {{bold = true, foreground = Screen.colors.Blue}}) end) @@ -112,7 +112,7 @@ describe('clipboard', function() feed_command('redir @+> | bogus_cmd | redir END') screen:expect([[ ~ | - clipboard: No provider. Try ":CheckHealth" or ":h clipboard". | + clipboard: No provider. Try ":checkhealth" or ":h clipboard". | E492: Not an editor command: bogus_cmd | redir END | Press ENTER or type command to continue^ | ]], nil, {{bold = true, foreground = Screen.colors.Blue}}) @@ -132,7 +132,7 @@ describe('clipboard', function() ^ | ~ | ~ | - clipboard: No provider. Try ":CheckHealth" or ":h clipboard". | + clipboard: No provider. Try ":checkhealth" or ":h clipboard". | ]], nil, {{bold = true, foreground = Screen.colors.Blue}}) end) diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua index a85a3ce495..a91c0b401b 100644 --- a/test/functional/plugin/health_spec.lua +++ b/test/functional/plugin/health_spec.lua @@ -68,7 +68,7 @@ describe('health.vim', function() describe(":checkhealth", function() it("concatenates multiple reports", function() - command("CheckHealth success1 success2") + command("checkhealth success1 success2") helpers.expect([[ health#success1#check @@ -87,7 +87,7 @@ describe('health.vim', function() end) it("gracefully handles broken healthcheck", function() - command("CheckHealth broken") + command("checkhealth broken") helpers.expect([[ health#broken#check @@ -111,7 +111,7 @@ describe('health.vim', function() Bar = { foreground=Screen.colors.Purple }, Bullet = { bold=true, foreground=Screen.colors.Brown }, }) - command("CheckHealth foo success1") + command("checkhealth foo success1") command("1tabclose") command("set laststatus=0") screen:expect([[ @@ -129,7 +129,7 @@ describe('health.vim', function() end) it("gracefully handles invalid healthcheck", function() - command("CheckHealth non_existent_healthcheck") + command("checkhealth non_existent_healthcheck") helpers.expect([[ health#non_existent_healthcheck#check diff --git a/test/functional/provider/ruby_spec.lua b/test/functional/provider/ruby_spec.lua index 9f5ef3b3fc..c70f90da1c 100644 --- a/test/functional/provider/ruby_spec.lua +++ b/test/functional/provider/ruby_spec.lua @@ -16,7 +16,7 @@ do clear() if missing_provider('ruby') then pending( - "Cannot find the neovim RubyGem. Try :CheckHealth", + "Cannot find the neovim RubyGem. Try :checkhealth", function() end) return end -- cgit From d5d7a9928da8d670e94a9e5e08d6814759b702b6 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 15 Oct 2017 23:23:17 +0200 Subject: doc: E5009 "Invalid $VIMRUNTIME" --- runtime/doc/pi_health.txt | 6 +++++ runtime/doc/starting.txt | 68 +++++++++++++++++++---------------------------- 2 files changed, 33 insertions(+), 41 deletions(-) diff --git a/runtime/doc/pi_health.txt b/runtime/doc/pi_health.txt index 3fd649f1f8..aee3a0f6e6 100644 --- a/runtime/doc/pi_health.txt +++ b/runtime/doc/pi_health.txt @@ -22,6 +22,12 @@ Commands *health-commands* *:checkhealth* *:CheckHealth* :checkhealth Run all healthchecks. + *E5009* + Nvim depends on the |$VIMRUNTIME| environment variable + to find the standard "runtime files" for syntax + highlighting, filetype-specific behavior, and standard + plugins such as :checkhealth. If $VIMRUNTIME is invalid + then those features will not work. :checkhealth {plugins} Run healthcheck(s) for one or more plugins. E.g. to run diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index 4cfc98d5b6..aa55c80d4d 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -633,54 +633,40 @@ though. ============================================================================== 3. $VIM and $VIMRUNTIME *$VIM* -The environment variable "$VIM" is used to locate various user files for Vim, +The environment variable "$VIM" is used to locate various user files for Nvim, such as the user startup script |init.vim|. This depends on the system, see |startup|. -To avoid the need for every user to set the $VIM environment variable, Vim -will try to get the value for $VIM in this order: -1. The value defined by the $VIM environment variable. You can use this to - make Vim look in a specific directory for its support files. Example: > - setenv VIM /home/paul/vim -2. The path from 'helpfile' is used, unless it contains some environment - variable too (the default is "$VIMRUNTIME/doc/help.txt": chicken-egg - problem). The file name ("help.txt" or any other) is removed. Then - trailing directory names are removed, in this order: "doc", "runtime" and - "vim{version}" (e.g., "vim54"). -3. For MSDOS and Win32 Vim tries to use the directory name of the - executable. If it ends in "/src", this is removed. This is useful if you - unpacked the .zip file in some directory, and adjusted the search path to - find the vim executable. Trailing directory names are removed, in this - order: "runtime" and "vim{version}" (e.g., "vim54"). -4. For Unix the compile-time defined installation directory is used (see the - output of ":version"). - -Once Vim has done this once, it will set the $VIM environment variable. To -change it later, use a ":let" command like this: > - :let $VIM = "/home/paul/vim/" -< +Nvim will try to get the value for $VIM in this order: + +1. Environment variable $VIM, if it is set. +2. Path derived from the 'helpfile' option, unless it contains some + environment variable too (default is "$VIMRUNTIME/doc/help.txt"). File + name ("help.txt", etc.) is removed. Trailing directory names are removed, + in this order: "doc", "runtime". +3. Path derived from the location of the `nvim` executable. +4. Compile-time defined installation directory (see output of ":version"). + +After doing this once, Nvim sets the $VIM environment variable. + *$VIMRUNTIME* The environment variable "$VIMRUNTIME" is used to locate various support -files, such as the on-line documentation and files used for syntax -highlighting. For example, the main help file is normally -"$VIMRUNTIME/doc/help.txt". -You don't normally set $VIMRUNTIME yourself, but let Vim figure it out. This -is the order used to find the value of $VIMRUNTIME: -1. If the environment variable $VIMRUNTIME is set, it is used. You can use - this when the runtime files are in an unusual location. -2. If "$VIM/vim{version}" exists, it is used. {version} is the version - number of Vim, without any '-' or '.'. For example: "$VIM/vim54". This is - the normal value for $VIMRUNTIME. -3. If "$VIM/runtime" exists, it is used. -4. The value of $VIM is used. This is for backwards compatibility with older - versions. +files, such as the documentation and syntax-highlighting files. For example, +the main help file is normally "$VIMRUNTIME/doc/help.txt". + +Nvim will try to get the value for $VIMRUNTIME in this order: + +1. Environment variable $VIMRUNTIME, if it is set. +2. Directory path "$VIM/vim{version}", if it exists, where {version} is the + Vim version number without '-' or '.'. For example: "$VIM/vim54". +3. Directory path "$VIM/runtime", if it exists. +4. Value of $VIM environment variable. This is for backwards compatibility + with older Vim versions. 5. If "../share/nvim/runtime" exists relative to |v:progpath|, it is used. -6. When the 'helpfile' option is set and doesn't contain a '$', its value is - used, with "doc/help.txt" removed from the end. +6. Path derived from the 'helpfile' option (if it doesn't contain '$') with + "doc/help.txt" removed from the end. -Once Vim has done this once, it will set the $VIMRUNTIME environment variable. -To change it later, use a ":let" command like this: > - :let $VIMRUNTIME = "/home/piet/vim/vim54" +After doing this once, Nvim sets the $VIMRUNTIME environment variable. In case you need the value of $VIMRUNTIME in a shell (e.g., for a script that greps in the help files) you might be able to use this: > -- cgit From 014bd59957beb3f94cfb014a7acde3d2544bdfd9 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 16 Oct 2017 00:05:35 +0200 Subject: ex_checkhealth: call health#check() directly This allows us to remove :CheckHealth later (avoids wildmenu noise). --- runtime/autoload/health.vim | 5 ++++- src/nvim/eval.c | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/runtime/autoload/health.vim b/runtime/autoload/health.vim index 028b6cca8e..b076f2456b 100644 --- a/runtime/autoload/health.vim +++ b/runtime/autoload/health.vim @@ -159,7 +159,10 @@ endfunction " Translates a list of plugin names to healthcheck function names. function! s:to_fn_names(plugin_names) abort let healthchecks = [] - for p in a:plugin_names + let plugin_names = type('') ==# type(a:plugin_names) + \ ? split(a:plugin_names, '', v:false) + \ : a:plugin_names + for p in plugin_names call add(healthchecks, 'health#'.p.'#check') endfor return healthchecks diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 986c4a9a17..aab777955c 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -22870,9 +22870,9 @@ void ex_checkhealth(exarg_T *eap) } } - size_t bufsize = STRLEN(eap->arg) + strlen("CheckHealth ") + 1; + size_t bufsize = STRLEN(eap->arg) + sizeof("call health#check('')"); char *buf = xmalloc(bufsize); - snprintf(buf, bufsize, "CheckHealth %s", eap->arg); + snprintf(buf, bufsize, "call health#check('%s')", eap->arg); do_cmdline_cmd(buf); -- cgit From 3bcee71cc8ef782fc89de7d72cb784cfb6d984d3 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 17 Oct 2017 00:10:52 +0200 Subject: :checkhealth : validate $VIM --- runtime/autoload/health/nvim.vim | 7 +++++++ test/functional/plugin/health_spec.lua | 14 +++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/runtime/autoload/health/nvim.vim b/runtime/autoload/health/nvim.vim index 6c6a5e8543..7f6e943dc9 100644 --- a/runtime/autoload/health/nvim.vim +++ b/runtime/autoload/health/nvim.vim @@ -4,12 +4,19 @@ function! s:check_config() abort let ok = v:true call health#report_start('Configuration') + " If $VIM is empty we don't care. Else make sure it is valid. + if !empty($VIM) && !filereadable($VIM.'/runtime/doc/nvim.txt') + let ok = v:false + call health#report_error("$VIM is invalid: ".$VIM) + endif + if exists('$NVIM_TUI_ENABLE_CURSOR_SHAPE') let ok = v:false call health#report_warn("$NVIM_TUI_ENABLE_CURSOR_SHAPE is ignored in Nvim 0.2+", \ [ "Use the 'guicursor' option to configure cursor shape. :help 'guicursor'", \ 'https://github.com/neovim/neovim/wiki/Following-HEAD#20170402' ]) endif + if &paste let ok = v:false call health#report_error("'paste' is enabled. This option is only for pasting text.\nIt should not be set in your config.", diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua index a91c0b401b..b5374210e6 100644 --- a/test/functional/plugin/health_spec.lua +++ b/test/functional/plugin/health_spec.lua @@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen') local plugin_helpers = require('test.functional.plugin.helpers') local clear = helpers.clear +local curbuf_contents = helpers.curbuf_contents local command = helpers.command local eq = helpers.eq @@ -16,13 +17,12 @@ describe(':checkhealth', function() eq('Invalid $VIMRUNTIME: bogus', string.match(err, 'Invalid.*')) end) it("detects invalid $VIM", function() - clear({ - env={ VIM='bogus', }, - }) - local status, err = pcall(command, 'checkhealth') - eq(false, status) - -- Invalid $VIM causes $VIMRUNTIME to be broken. - eq('Invalid $VIMRUNTIME: bogus', string.match(err, 'Invalid.*')) + clear() + -- Do this after startup, otherwise it just breaks $VIMRUNTIME. + command("let $VIM='zub'") + command("checkhealth nvim") + eq("ERROR: $VIM is invalid: zub", + string.match(curbuf_contents(), "ERROR: $VIM .* zub")) end) end) -- cgit From 70b574dab36a99e676b1845bdfe0fef4bfa63584 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 17 Oct 2017 12:55:12 -0400 Subject: vim-patch:8.0.0118 Runtime updates that were bundled into the otherwise NA commit: Problem: "make proto" adds extra function prototype. Solution: Add vim/vim#ifdef. https://github.com/vim/vim/commit/5162822914372fc916a93f85848c0c82209e7cec --- runtime/doc/change.txt | 1 + runtime/doc/editing.txt | 5 +++-- runtime/doc/motion.txt | 1 + runtime/doc/options.txt | 6 +++++- runtime/doc/windows.txt | 2 ++ runtime/syntax/c.vim | 18 +++++++++--------- src/nvim/version.c | 2 +- 7 files changed, 22 insertions(+), 13 deletions(-) diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index f82d61370c..5384bbfc6f 100644 --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -648,6 +648,7 @@ g& Synonym for `:%s//~/&` (repeat last substitute with *:s_flags* The flags that you can use for the substitute commands: + *:&&* [&] Must be the first one: Keep the flags from the previous substitute command. Examples: > :&& diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt index 8974a5c64e..29ccd48b7b 100644 --- a/runtime/doc/editing.txt +++ b/runtime/doc/editing.txt @@ -901,11 +901,12 @@ WRITING WITH MULTIPLE BUFFERS *buffer-write* *:wa* *:wall* :wa[ll] Write all changed buffers. Buffers without a file - name or which are readonly are not written. + name cause an error message. Buffers which are + readonly are not written. :wa[ll]! Write all changed buffers, even the ones that are readonly. Buffers without a file name are not - written. + written and cause an error message. Vim will warn you if you try to overwrite a file that has been changed diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt index 99aa76bfe5..fd156702f5 100644 --- a/runtime/doc/motion.txt +++ b/runtime/doc/motion.txt @@ -886,6 +886,7 @@ was made yet in the current file. then the position can be near the end of what the command changed. For example when inserting a word, the position will be on the last character. + To jump to older changes use |g;|. *'(* *`(* '( `( To the start of the current sentence, like the |(| diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index d55eb7405c..f421d4022c 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -187,7 +187,7 @@ opt+=val" the expansion is done before the adding or removing. Handling of local options *local-options* Some of the options only apply to a window or buffer. Each window or buffer -has its own copy of this option, thus can each have their own value. This +has its own copy of this option, thus each can have its own value. This allows you to set 'list' in one window but not in another. And set 'shiftwidth' to 3 in one buffer and 4 in another. @@ -3017,6 +3017,8 @@ A jump table for the options with a short description can be found at |Q_op|. The format of this option is like that of 'statusline'. 'guitabtooltip' is used for the tooltip, see below. + The expression will be evaluated in the |sandbox| when set from a + modeline, see |sandbox-option|. Only used when the GUI tab pages line is displayed. 'e' must be present in 'guioptions'. For the non-GUI tab pages line 'tabline' is @@ -4482,6 +4484,8 @@ A jump table for the options with a short description can be found at |Q_op|. and |+postscript| features} Expression used to print the PostScript produced with |:hardcopy|. See |pexpr-option|. + This option cannot be set from a |modeline| or in the |sandbox|, for + security reasons. *'printfont'* *'pfn'* 'printfont' 'pfn' string (default "courier") diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt index f5d5321a5e..ceb7a7f003 100644 --- a/runtime/doc/windows.txt +++ b/runtime/doc/windows.txt @@ -677,6 +677,8 @@ can also get to them with the buffer list commands, like ":bnext". - If the file is not open in a window edit the file in the current window. If the current buffer can't be |abandon|ed, the window is split first. + - Windows that are not in the argument list or are not full + width will be closed if possible. The |argument-list| is set, like with the |:next| command. The purpose of this command is that it can be used from a program that wants Vim to edit another file, e.g., a debugger. diff --git a/runtime/syntax/c.vim b/runtime/syntax/c.vim index cc99f674a1..16c7ce4d92 100644 --- a/runtime/syntax/c.vim +++ b/runtime/syntax/c.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: C " Maintainer: Bram Moolenaar -" Last Change: 2016 Nov 17 +" Last Change: 2016 Nov 18 " Quit when a (custom) syntax file was already loaded if exists("b:current_syntax") @@ -363,23 +363,23 @@ syn match cPreConditMatch display "^\s*\zs\(%:\|#\)\s*\(else\|endif\)\>" if !exists("c_no_if0") syn cluster cCppOutInGroup contains=cCppInIf,cCppInElse,cCppInElse2,cCppOutIf,cCppOutIf2,cCppOutElse,cCppInSkip,cCppOutSkip syn region cCppOutWrapper start="^\s*\zs\(%:\|#\)\s*if\s\+0\+\s*\($\|//\|/\*\|&\)" end=".\@=\|$" contains=cCppOutIf,cCppOutElse,@NoSpell fold - syn region cCppOutIf contained start="0\+" matchgroup=cCppOutWrapper end="^\s*\zs\(%:\|#\)\s*endif\>" contains=cCppOutIf2,cCppOutElse + syn region cCppOutIf contained start="0\+" matchgroup=cCppOutWrapper end="^\s*\(%:\|#\)\s*endif\>" contains=cCppOutIf2,cCppOutElse if !exists("c_no_if0_fold") syn region cCppOutIf2 contained matchgroup=cCppOutWrapper start="0\+" end="^\s*\(%:\|#\)\s*\(else\>\|elif\s\+\(0\+\s*\($\|//\|/\*\|&\)\)\@!\|endif\>\)"me=s-1 contains=cSpaceError,cCppOutSkip,@Spell fold else syn region cCppOutIf2 contained matchgroup=cCppOutWrapper start="0\+" end="^\s*\(%:\|#\)\s*\(else\>\|elif\s\+\(0\+\s*\($\|//\|/\*\|&\)\)\@!\|endif\>\)"me=s-1 contains=cSpaceError,cCppOutSkip,@Spell endif - syn region cCppOutElse contained matchgroup=cCppOutWrapper start="^\s*\zs\(%:\|#\)\s*\(else\|elif\)" end="^\s*\zs\(%:\|#\)\s*endif\>"me=s-1 contains=TOP,cPreCondit + syn region cCppOutElse contained matchgroup=cCppOutWrapper start="^\s*\(%:\|#\)\s*\(else\|elif\)" end="^\s*\(%:\|#\)\s*endif\>"me=s-1 contains=TOP,cPreCondit syn region cCppInWrapper start="^\s*\zs\(%:\|#\)\s*if\s\+0*[1-9]\d*\s*\($\|//\|/\*\||\)" end=".\@=\|$" contains=cCppInIf,cCppInElse fold - syn region cCppInIf contained matchgroup=cCppInWrapper start="\d\+" end="^\s*\zs\(%:\|#\)\s*endif\>" contains=TOP,cPreCondit + syn region cCppInIf contained matchgroup=cCppInWrapper start="\d\+" end="^\s*\(%:\|#\)\s*endif\>" contains=TOP,cPreCondit if !exists("c_no_if0_fold") - syn region cCppInElse contained start="^\s*\zs\(%:\|#\)\s*\(else\>\|elif\s\+\(0*[1-9]\d*\s*\($\|//\|/\*\||\)\)\@!\)" end=".\@=\|$" containedin=cCppInIf contains=cCppInElse2 fold + syn region cCppInElse contained start="^\s*\(%:\|#\)\s*\(else\>\|elif\s\+\(0*[1-9]\d*\s*\($\|//\|/\*\||\)\)\@!\)" end=".\@=\|$" containedin=cCppInIf contains=cCppInElse2 fold else - syn region cCppInElse contained start="^\s*\zs\(%:\|#\)\s*\(else\>\|elif\s\+\(0*[1-9]\d*\s*\($\|//\|/\*\||\)\)\@!\)" end=".\@=\|$" containedin=cCppInIf contains=cCppInElse2 + syn region cCppInElse contained start="^\s*\(%:\|#\)\s*\(else\>\|elif\s\+\(0*[1-9]\d*\s*\($\|//\|/\*\||\)\)\@!\)" end=".\@=\|$" containedin=cCppInIf contains=cCppInElse2 endif - syn region cCppInElse2 contained matchgroup=cCppInWrapper start="^\s*\zs\(%:\|#\)\s*\(else\|elif\)\([^/]\|/[^/*]\)*" end="^\s*\zs\(%:\|#\)\s*endif\>"me=s-1 contains=cSpaceError,cCppOutSkip,@Spell - syn region cCppOutSkip contained start="^\s*\zs\(%:\|#\)\s*\(if\>\|ifdef\>\|ifndef\>\)" skip="\\$" end="^\s*\zs\(%:\|#\)\s*endif\>" contains=cSpaceError,cCppOutSkip - syn region cCppInSkip contained matchgroup=cCppInWrapper start="^\s*\zs\(%:\|#\)\s*\(if\s\+\(\d\+\s*\($\|//\|/\*\||\|&\)\)\@!\|ifdef\>\|ifndef\>\)" skip="\\$" end="^\s*\zs\(%:\|#\)\s*endif\>" containedin=cCppOutElse,cCppInIf,cCppInSkip contains=TOP,cPreProc + syn region cCppInElse2 contained matchgroup=cCppInWrapper start="^\s*\(%:\|#\)\s*\(else\|elif\)\([^/]\|/[^/*]\)*" end="^\s*\(%:\|#\)\s*endif\>"me=s-1 contains=cSpaceError,cCppOutSkip,@Spell + syn region cCppOutSkip contained start="^\s*\(%:\|#\)\s*\(if\>\|ifdef\>\|ifndef\>\)" skip="\\$" end="^\s*\(%:\|#\)\s*endif\>" contains=cSpaceError,cCppOutSkip + syn region cCppInSkip contained matchgroup=cCppInWrapper start="^\s*\(%:\|#\)\s*\(if\s\+\(\d\+\s*\($\|//\|/\*\||\|&\)\)\@!\|ifdef\>\|ifndef\>\)" skip="\\$" end="^\s*\(%:\|#\)\s*endif\>" containedin=cCppOutElse,cCppInIf,cCppInSkip contains=TOP,cPreProc endif syn region cIncluded display contained start=+"+ skip=+\\\\\|\\"+ end=+"+ syn match cIncluded display contained "<[^>]*>" diff --git a/src/nvim/version.c b/src/nvim/version.c index 7f1a219322..60066ec8d3 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -985,7 +985,7 @@ static const int included_patches[] = { 121, // 120 NA 119, - // 118, + 118, // 117 NA 116, // 115 NA -- cgit From 295c90989d10bf221eff7babc1cf9484ec0f4560 Mon Sep 17 00:00:00 2001 From: relnod Date: Sat, 15 Jul 2017 14:27:59 +0200 Subject: refactor/single-include: terminal.h --- src/nvim/CMakeLists.txt | 1 - src/nvim/terminal.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index e2f1f16635..da8ec354d9 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -543,7 +543,6 @@ set(NO_SINGLE_CHECK_HEADERS os/pty_process_win.h regexp_defs.h syntax_defs.h - terminal.h undo.h undo_defs.h ) diff --git a/src/nvim/terminal.h b/src/nvim/terminal.h index 25e609fb68..f2b0e232c3 100644 --- a/src/nvim/terminal.h +++ b/src/nvim/terminal.h @@ -10,6 +10,8 @@ typedef void (*terminal_write_cb)(char *buffer, size_t size, void *data); typedef void (*terminal_resize_cb)(uint16_t width, uint16_t height, void *data); typedef void (*terminal_close_cb)(void *data); +#include "nvim/buffer_defs.h" + typedef struct { void *data; uint16_t width, height; -- cgit From 69199958b7ed9ec87a83b2ac0fd37a0c3e41a506 Mon Sep 17 00:00:00 2001 From: relnod Date: Sat, 15 Jul 2017 16:44:06 +0200 Subject: refactor/single-include: regexp_defs.h --- src/nvim/CMakeLists.txt | 1 - src/nvim/regexp_defs.h | 46 ++++++++++++++++++++++++++-------------------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index da8ec354d9..7bd121050e 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -541,7 +541,6 @@ endfunction() set(NO_SINGLE_CHECK_HEADERS os/win_defs.h os/pty_process_win.h - regexp_defs.h syntax_defs.h undo.h undo_defs.h diff --git a/src/nvim/regexp_defs.h b/src/nvim/regexp_defs.h index 6426ee441b..7492a86697 100644 --- a/src/nvim/regexp_defs.h +++ b/src/nvim/regexp_defs.h @@ -15,6 +15,8 @@ #include #include "nvim/pos.h" +#include "nvim/types.h" +#include "nvim/profile.h" /* * The number of sub-matches is limited to 10. @@ -41,18 +43,38 @@ #define NFA_ENGINE 2 typedef struct regengine regengine_T; +typedef struct regprog regprog_T; +typedef struct reg_extmatch reg_extmatch_T; + +/* + * Structure to be used for multi-line matching. + * Sub-match "no" starts in line "startpos[no].lnum" column "startpos[no].col" + * and ends in line "endpos[no].lnum" just before column "endpos[no].col". + * The line numbers are relative to the first line, thus startpos[0].lnum is + * always 0. + * When there is no match, the line number is -1. + */ +typedef struct { + regprog_T *regprog; + lpos_T startpos[NSUBEXP]; + lpos_T endpos[NSUBEXP]; + int rmm_ic; + colnr_T rmm_maxcol; /* when not zero: maximum column */ +} regmmatch_T; + +#include "nvim/buffer_defs.h" /* * Structure returned by vim_regcomp() to pass on to vim_regexec(). * This is the general structure. For the actual matcher, two specific * structures are used. See code below. */ -typedef struct regprog { +struct regprog { regengine_T *engine; unsigned regflags; unsigned re_engine; ///< Automatic, backtracking or NFA engine. unsigned re_flags; ///< Second argument for vim_regcomp(). -} regprog_T; +}; /* * Structure used by the back track matcher. @@ -125,31 +147,15 @@ typedef struct { bool rm_ic; } regmatch_T; -/* - * Structure to be used for multi-line matching. - * Sub-match "no" starts in line "startpos[no].lnum" column "startpos[no].col" - * and ends in line "endpos[no].lnum" just before column "endpos[no].col". - * The line numbers are relative to the first line, thus startpos[0].lnum is - * always 0. - * When there is no match, the line number is -1. - */ -typedef struct { - regprog_T *regprog; - lpos_T startpos[NSUBEXP]; - lpos_T endpos[NSUBEXP]; - int rmm_ic; - colnr_T rmm_maxcol; /* when not zero: maximum column */ -} regmmatch_T; - /* * Structure used to store external references: "\z\(\)" to "\z\1". * Use a reference count to avoid the need to copy this around. When it goes * from 1 to zero the matches need to be freed. */ -typedef struct { +struct reg_extmatch { short refcnt; char_u *matches[NSUBEXP]; -} reg_extmatch_T; +}; struct regengine { regprog_T *(*regcomp)(char_u*, int); -- cgit From 4b0a086d165013ff5726b987b353d88a863491a9 Mon Sep 17 00:00:00 2001 From: relnod Date: Sat, 15 Jul 2017 16:47:12 +0200 Subject: refactor/single-include: syntax_defs.h --- src/nvim/CMakeLists.txt | 1 - src/nvim/syntax_defs.h | 8 +++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 7bd121050e..2cc236101c 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -541,7 +541,6 @@ endfunction() set(NO_SINGLE_CHECK_HEADERS os/win_defs.h os/pty_process_win.h - syntax_defs.h undo.h undo_defs.h ) diff --git a/src/nvim/syntax_defs.h b/src/nvim/syntax_defs.h index 56fadbe7f6..7260853703 100644 --- a/src/nvim/syntax_defs.h +++ b/src/nvim/syntax_defs.h @@ -2,7 +2,6 @@ #define NVIM_SYNTAX_DEFS_H #include "nvim/highlight_defs.h" -#include "nvim/regexp_defs.h" # define SST_MIN_ENTRIES 150 /* minimal size for state stack array */ # define SST_MAX_ENTRIES 1000 /* maximal size for state stack array */ @@ -10,6 +9,11 @@ # define SST_DIST 16 /* normal distance between entries */ # define SST_INVALID (synstate_T *)-1 /* invalid syn_state pointer */ +typedef struct syn_state synstate_T; + +#include "nvim/buffer_defs.h" +#include "nvim/regexp_defs.h" + typedef unsigned short disptick_T; /* display tick type */ /* struct passed to in_id_list() */ @@ -48,8 +52,6 @@ typedef struct buf_state { * syn_state contains the syntax state stack for the start of one line. * Used by b_sst_array[]. */ -typedef struct syn_state synstate_T; - struct syn_state { synstate_T *sst_next; /* next entry in used or free list */ linenr_T sst_lnum; /* line number for this state */ -- cgit From 14e63271cc216ef60036891f7f79d8509c8f52c1 Mon Sep 17 00:00:00 2001 From: relnod Date: Sat, 15 Jul 2017 16:50:22 +0200 Subject: refactor/single-include: undo_defs.h --- src/nvim/CMakeLists.txt | 1 - src/nvim/undo_defs.h | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 2cc236101c..09d50f0f00 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -542,7 +542,6 @@ set(NO_SINGLE_CHECK_HEADERS os/win_defs.h os/pty_process_win.h undo.h - undo_defs.h ) foreach(hfile ${NVIM_HEADERS}) get_test_target(test-includes "${hfile}" relative_path texe) diff --git a/src/nvim/undo_defs.h b/src/nvim/undo_defs.h index d841210815..6c7e2bba41 100644 --- a/src/nvim/undo_defs.h +++ b/src/nvim/undo_defs.h @@ -4,9 +4,10 @@ #include // for time_t #include "nvim/pos.h" -#include "nvim/buffer_defs.h" #include "nvim/mark_defs.h" +typedef struct u_header u_header_T; + /* Structure to store info about the Visual area. */ typedef struct { pos_T vi_start; /* start pos of last VIsual */ @@ -15,8 +16,9 @@ typedef struct { colnr_T vi_curswant; /* MAXCOL from w_curswant */ } visualinfo_T; +#include "nvim/buffer_defs.h" + typedef struct u_entry u_entry_T; -typedef struct u_header u_header_T; struct u_entry { u_entry_T *ue_next; /* pointer to next entry in list */ linenr_T ue_top; /* number of line above undo block */ -- cgit From 0f74b7afeb3a4b85302268e7cb04f0faefda397d Mon Sep 17 00:00:00 2001 From: relnod Date: Sat, 15 Jul 2017 16:52:32 +0200 Subject: refactor/single-include: undo.h --- src/nvim/CMakeLists.txt | 1 - src/nvim/undo.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 09d50f0f00..eb3b60f0b5 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -541,7 +541,6 @@ endfunction() set(NO_SINGLE_CHECK_HEADERS os/win_defs.h os/pty_process_win.h - undo.h ) foreach(hfile ${NVIM_HEADERS}) get_test_target(test-includes "${hfile}" relative_path texe) diff --git a/src/nvim/undo.h b/src/nvim/undo.h index ab8584fbb2..802cdc5583 100644 --- a/src/nvim/undo.h +++ b/src/nvim/undo.h @@ -2,6 +2,7 @@ #define NVIM_UNDO_H #include "nvim/undo_defs.h" +#include "nvim/ex_cmds_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "undo.h.generated.h" -- cgit From dde3ece10ed4ee62744009fa1fd347be740fc845 Mon Sep 17 00:00:00 2001 From: relnod Date: Sat, 15 Jul 2017 17:52:06 +0200 Subject: lint --- src/nvim/regexp_defs.h | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/nvim/regexp_defs.h b/src/nvim/regexp_defs.h index 7492a86697..b5d56e07fc 100644 --- a/src/nvim/regexp_defs.h +++ b/src/nvim/regexp_defs.h @@ -46,20 +46,18 @@ typedef struct regengine regengine_T; typedef struct regprog regprog_T; typedef struct reg_extmatch reg_extmatch_T; -/* - * Structure to be used for multi-line matching. - * Sub-match "no" starts in line "startpos[no].lnum" column "startpos[no].col" - * and ends in line "endpos[no].lnum" just before column "endpos[no].col". - * The line numbers are relative to the first line, thus startpos[0].lnum is - * always 0. - * When there is no match, the line number is -1. - */ +/// Structure to be used for multi-line matching. +/// Sub-match "no" starts in line "startpos[no].lnum" column "startpos[no].col" +/// and ends in line "endpos[no].lnum" just before column "endpos[no].col". +/// The line numbers are relative to the first line, thus startpos[0].lnum is +/// always 0. +/// When there is no match, the line number is -1. typedef struct { regprog_T *regprog; lpos_T startpos[NSUBEXP]; lpos_T endpos[NSUBEXP]; int rmm_ic; - colnr_T rmm_maxcol; /* when not zero: maximum column */ + colnr_T rmm_maxcol; /// when not zero: maximum column } regmmatch_T; #include "nvim/buffer_defs.h" @@ -153,7 +151,7 @@ typedef struct { * from 1 to zero the matches need to be freed. */ struct reg_extmatch { - short refcnt; + int16_t refcnt; char_u *matches[NSUBEXP]; }; -- cgit From dfe806ea8b90ace9ef2ee63aafbf10ebea2df7ef Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Thu, 19 Oct 2017 11:46:07 +0200 Subject: bufhl: support creating new groups --- src/nvim/api/buffer.c | 6 +++++- test/functional/ui/bufhl_spec.lua | 31 ++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 82de8fd4a2..c381e92dc7 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -793,7 +793,11 @@ Integer nvim_buf_add_highlight(Buffer buffer, col_end = MAXCOL; } - int hlg_id = syn_name2id((char_u *)(hl_group.data ? hl_group.data : "")); + int hlg_id = 0; + if (hl_group.size > 0) { + hlg_id = syn_check_group((char_u *)hl_group.data, (int)hl_group.size); + } + src_id = bufhl_add_hl(buf, (int)src_id, hlg_id, (linenr_T)line+1, (colnr_T)col_start+1, (colnr_T)col_end); return src_id; diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index e1e11203e0..2143c01139 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -24,7 +24,8 @@ describe('Buffer highlighting', function() [6] = {foreground = Screen.colors.DarkCyan}, -- Identifier [7] = {bold = true}, [8] = {underline = true, bold = true, foreground = Screen.colors.SlateBlue}, - [9] = {foreground = Screen.colors.SlateBlue, underline = true} + [9] = {foreground = Screen.colors.SlateBlue, underline = true}, + [10] = {foreground = Screen.colors.Red} }) curbuf = request('nvim_get_current_buf') end) @@ -255,4 +256,32 @@ describe('Buffer highlighting', function() | ]]) end) + + it('works with new syntax groups', function() + insert([[ + fancy code in a new fancy language]]) + add_hl(-1, "FancyLangItem", 0, 0, 5) + screen:expect([[ + fancy code in a new fancy languag^e | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + + command('hi FancyLangItem guifg=red') + screen:expect([[ + {10:fancy} code in a new fancy languag^e | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end) end) -- cgit From 82b8382abe6c533fbdd01529cfc93a8d1c5231e2 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 21 Oct 2017 02:04:35 +0200 Subject: vim-patch:8.0.0962 closes #6726 Problem: Crash with virtualedit and joining lines. (Joshua T Corbin, Neovim #6726) Solution: When using a mark check that coladd is valid. https://github.com/vim/vim/commit/9aa156912867c05e0a6480925afe11c590378f09 --- src/nvim/cursor.c | 26 ++++++++++++++++++-------- src/nvim/normal.c | 13 +++++++++---- src/nvim/testdir/test_alot.vim | 1 + src/nvim/testdir/test_virtualedit.vim | 31 +++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 12 deletions(-) create mode 100644 src/nvim/testdir/test_virtualedit.vim diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c index 60002f3cea..e575143af0 100644 --- a/src/nvim/cursor.c +++ b/src/nvim/cursor.c @@ -375,17 +375,27 @@ void check_cursor_col_win(win_T *win) win->w_cursor.col = 0; } - /* If virtual editing is on, we can leave the cursor on the old position, - * only we must set it to virtual. But don't do it when at the end of the - * line. */ - if (oldcol == MAXCOL) + // If virtual editing is on, we can leave the cursor on the old position, + // only we must set it to virtual. But don't do it when at the end of the + // line. + if (oldcol == MAXCOL) { win->w_cursor.coladd = 0; - else if (ve_flags == VE_ALL) { - if (oldcoladd > win->w_cursor.col) + } else if (ve_flags == VE_ALL) { + if (oldcoladd > win->w_cursor.col) { win->w_cursor.coladd = oldcoladd - win->w_cursor.col; - else - /* avoid weird number when there is a miscalculation or overflow */ + if (win->w_cursor.col < len && win->w_cursor.coladd > 0) { + int cs, ce; + + // check that coladd is not more than the char width + getvcol(win, &win->w_cursor, &cs, NULL, &ce); + if (win->w_cursor.coladd > ce - cs) { + win->w_cursor.coladd = ce - cs; + } + } + } else { + // avoid weird number when there is a miscalculation or overflow win->w_cursor.coladd = 0; + } } } diff --git a/src/nvim/normal.c b/src/nvim/normal.c index c40ed58550..1103fe15d2 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -1548,8 +1548,10 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) } oap->start = VIsual; - if (VIsual_mode == 'V') + if (VIsual_mode == 'V') { oap->start.col = 0; + oap->start.coladd = 0; + } } /* @@ -6260,15 +6262,18 @@ static void nv_gomark(cmdarg_T *cap) } else nv_cursormark(cap, cap->arg, pos); - /* May need to clear the coladd that a mark includes. */ - if (!virtual_active()) + // May need to clear the coladd that a mark includes. + if (!virtual_active()) { curwin->w_cursor.coladd = 0; + } + check_cursor_col(); if (cap->oap->op_type == OP_NOP && pos != NULL && (pos == (pos_T *)-1 || !equalpos(old_cursor, *pos)) && (fdo_flags & FDO_MARK) - && old_KeyTyped) + && old_KeyTyped) { foldOpenCursor(); + } } /* diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim index d55170c27c..535e290a34 100644 --- a/src/nvim/testdir/test_alot.vim +++ b/src/nvim/testdir/test_alot.vim @@ -34,4 +34,5 @@ source test_taglist.vim source test_true_false.vim source test_unlet.vim source test_utf8.vim +source test_virtualedit.vim source test_window_cmd.vim diff --git a/src/nvim/testdir/test_virtualedit.vim b/src/nvim/testdir/test_virtualedit.vim new file mode 100644 index 0000000000..da143c518f --- /dev/null +++ b/src/nvim/testdir/test_virtualedit.vim @@ -0,0 +1,31 @@ +" Tests for 'virtualedit'. + +func Test_yank_move_change() + split + call setline(1, [ + \ "func foo() error {", + \ "\tif n, err := bar();", + \ "\terr != nil {", + \ "\t\treturn err", + \ "\t}", + \ "\tn = n * n", + \ ]) + set virtualedit=all + set ts=4 + function! MoveSelectionDown(count) abort + normal! m` + silent! exe "'<,'>move'>+".a:count + norm! `` + endfunction + + xmap ]e :call MoveSelectionDown(v:count1) + 2 + normal 2gg + normal J + normal jVj + normal ]e + normal ce + bwipe! + set virtualedit= + set ts=8 +endfunc -- cgit From b5b8966760773421b285ee8b63015fc767bca18d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 21 Oct 2017 02:20:17 +0200 Subject: vim-patch:8.0.1019 Problem: Pasting in virtual edit happens in the wrong place. Solution: Do not adjust coladd when after the end of the line (closes vim/vim#2015) https://github.com/vim/vim/commit/d41babef89a50cdf165f15bc1834c0a4e89ffff8 --- src/nvim/cursor.c | 7 +++++-- src/nvim/testdir/test_virtualedit.vim | 14 +++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c index e575143af0..0e97e2203f 100644 --- a/src/nvim/cursor.c +++ b/src/nvim/cursor.c @@ -383,10 +383,13 @@ void check_cursor_col_win(win_T *win) } else if (ve_flags == VE_ALL) { if (oldcoladd > win->w_cursor.col) { win->w_cursor.coladd = oldcoladd - win->w_cursor.col; - if (win->w_cursor.col < len && win->w_cursor.coladd > 0) { + + // Make sure that coladd is not more than the char width. + // Not for the last character, coladd is then used when the cursor + // is actually after the last character. + if (win->w_cursor.col + 1 < len && win->w_cursor.coladd > 0) { int cs, ce; - // check that coladd is not more than the char width getvcol(win, &win->w_cursor, &cs, NULL, &ce); if (win->w_cursor.coladd > ce - cs) { win->w_cursor.coladd = ce - cs; diff --git a/src/nvim/testdir/test_virtualedit.vim b/src/nvim/testdir/test_virtualedit.vim index da143c518f..2b8849f488 100644 --- a/src/nvim/testdir/test_virtualedit.vim +++ b/src/nvim/testdir/test_virtualedit.vim @@ -1,7 +1,7 @@ " Tests for 'virtualedit'. func Test_yank_move_change() - split + new call setline(1, [ \ "func foo() error {", \ "\tif n, err := bar();", @@ -29,3 +29,15 @@ func Test_yank_move_change() set virtualedit= set ts=8 endfunc + +func Test_paste_end_of_line() + new + set virtualedit=all + call setline(1, ['456', '123']) + normal! gg0"ay$ + exe "normal! 2G$lllA\:normal! \"agP\r" + call assert_equal('123456', getline(2)) + + bwipe! + set virtualedit= +endfunc -- cgit From 37420ef942085bf5e9344842a57c796b4d4c9684 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 21 Oct 2017 02:30:21 +0200 Subject: build: set MIN_LOG_LEVEL correctly (#7419) closes #7283 regression by 42d892913daa215c27e41b2255e96c1ce09ea56c - Don't need to explicitly put "-O2 -g" in RelWithDebInfo; CMake does that already. That was left-over from 42d892913daa2 which removed the "Dev" custom build-type, but repurposed the logic for RelWithDebInfo. - `if(DEFINED MIN_LOG_LEVEL)` doesn't work. - `if(${MIN_LOG_LEVEL} MATCHES "^$")` doesn't work if -DMIN_LOG_LEVEL is omitted. - `if(MIN_LOG_LEVEL)` also isn't what we want: it would be true if MIN_LOG_LEVEL=0. --- CMakeLists.txt | 24 +++++++++++------------- src/nvim/CMakeLists.txt | 2 +- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index df29774d45..e0daea5969 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,15 +113,14 @@ else() set(HAS_OG_FLAG 0) endif() -# Set custom build flags for RelWithDebInfo. -# -DNDEBUG purposely omitted because we want assertions. +# +# Build-type: RelWithDebInfo +# if(HAS_OG_FLAG) - set(CMAKE_C_FLAGS_RELWITHDEBINFO "-Og -g" - CACHE STRING "Flags used by the compiler during release-with-debug builds." FORCE) -elseif(NOT MSVC) - set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g" - CACHE STRING "Flags used by the compiler during release-with-debug builds." FORCE) -elseif(CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES DNDEBUG) + set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -Og -g") +endif() +# We _want_ assertions in RelWithDebInfo build-type. +if(CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES DNDEBUG) string(REPLACE "-DNDEBUG" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") endif() @@ -479,20 +478,19 @@ install_helper( DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) # MIN_LOG_LEVEL for log.h -if(DEFINED MIN_LOG_LEVEL) +if("${MIN_LOG_LEVEL}" MATCHES "^$") + message(STATUS "MIN_LOG_LEVEL not specified") +else() if(NOT MIN_LOG_LEVEL MATCHES "^[0-3]$") message(FATAL_ERROR "invalid MIN_LOG_LEVEL: " ${MIN_LOG_LEVEL}) endif() message(STATUS "MIN_LOG_LEVEL set to ${MIN_LOG_LEVEL}") -else() - message(STATUS "MIN_LOG_LEVEL not specified, defaulting to 1 (INFO)") endif() # Go down the tree. add_subdirectory(src/nvim) -# Read compilation flags from src/nvim, -# used in config subdirectory below. +# Read compilation flags from src/nvim, used in config subdirectory below. include(GetCompileFlags) get_compile_flags(NVIM_VERSION_CFLAGS) diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index e2f1f16635..bcbbc76cbc 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -164,7 +164,7 @@ if(NOT MSVC) endif() endif() -if(DEFINED MIN_LOG_LEVEL) +if(NOT "${MIN_LOG_LEVEL}" MATCHES "^$") add_definitions(-DMIN_LOG_LEVEL=${MIN_LOG_LEVEL}) endif() -- cgit From 70683705603e8e0e225574f01bc8b6824d5320eb Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 21 Oct 2017 02:33:58 +0200 Subject: help, man.vim: change "outline" map to gO (#7405) --- runtime/doc/api.txt | 2 +- runtime/doc/autocmd.txt | 2 +- runtime/doc/change.txt | 2 +- runtime/doc/cmdline.txt | 2 +- runtime/doc/debug.txt | 2 +- runtime/doc/develop.txt | 2 +- runtime/doc/diff.txt | 2 +- runtime/doc/digraph.txt | 2 +- runtime/doc/editing.txt | 2 +- runtime/doc/eval.txt | 2 +- runtime/doc/filetype.txt | 4 ++-- runtime/doc/fold.txt | 2 +- runtime/doc/gui.txt | 2 +- runtime/doc/helphelp.txt | 4 ++-- runtime/doc/if_cscop.txt | 2 +- runtime/doc/if_lua.txt | 2 +- runtime/doc/if_pyth.txt | 2 +- runtime/doc/if_ruby.txt | 2 +- runtime/doc/indent.txt | 2 +- runtime/doc/index.txt | 2 +- runtime/doc/insert.txt | 2 +- runtime/doc/intro.txt | 2 +- runtime/doc/job_control.txt | 2 +- runtime/doc/map.txt | 2 +- runtime/doc/mbyte.txt | 2 +- runtime/doc/message.txt | 2 +- runtime/doc/mlang.txt | 2 +- runtime/doc/motion.txt | 2 +- runtime/doc/msgpack_rpc.txt | 2 +- runtime/doc/nvim.txt | 2 +- runtime/doc/nvim_terminal_emulator.txt | 2 +- runtime/doc/options.txt | 2 +- runtime/doc/pattern.txt | 2 +- runtime/doc/pi_health.txt | 2 +- runtime/doc/print.txt | 2 +- runtime/doc/provider.txt | 2 +- runtime/doc/quickfix.txt | 2 +- runtime/doc/recover.txt | 2 +- runtime/doc/remote.txt | 2 +- runtime/doc/remote_plugin.txt | 2 +- runtime/doc/repeat.txt | 2 +- runtime/doc/russian.txt | 2 +- runtime/doc/scroll.txt | 2 +- runtime/doc/sign.txt | 2 +- runtime/doc/spell.txt | 2 +- runtime/doc/starting.txt | 2 +- runtime/doc/syntax.txt | 2 +- runtime/doc/tabpage.txt | 2 +- runtime/doc/tagsrch.txt | 2 +- runtime/doc/term.txt | 2 +- runtime/doc/tips.txt | 2 +- runtime/doc/undo.txt | 2 +- runtime/doc/various.txt | 11 +++++++++-- runtime/doc/vi_diff.txt | 2 +- runtime/doc/vim_diff.txt | 4 ++-- runtime/doc/visual.txt | 2 +- runtime/doc/windows.txt | 2 +- runtime/ftplugin/help.vim | 2 +- runtime/ftplugin/man.vim | 2 +- 59 files changed, 70 insertions(+), 63 deletions(-) diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index e12cd1cfa9..8aead087db 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -11,7 +11,7 @@ via |msgpack-rpc|, Lua and VimL (|eval-api|). Applications can also embed libnvim to work with the C API directly. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== API Types *api-types* diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index fd2a7c2641..2850c8058f 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -8,7 +8,7 @@ Automatic commands *autocommand* For a basic explanation, see section |40.3| in the user manual. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Introduction *autocmd-intro* diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index 5384bbfc6f..9610d7359f 100644 --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -11,7 +11,7 @@ commands with the "." command. For inserting text see |insert.txt|. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Deleting text *deleting* *E470* diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt index 652487d8ab..4222a5b6f7 100644 --- a/runtime/doc/cmdline.txt +++ b/runtime/doc/cmdline.txt @@ -13,7 +13,7 @@ Command-line mode is used to enter Ex commands (":"), search patterns Basic command line editing is explained in chapter 20 of the user manual |usr_20.txt|. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Command-line editing *cmdline-editing* diff --git a/runtime/doc/debug.txt b/runtime/doc/debug.txt index fd2c4fa54e..422255fa02 100644 --- a/runtime/doc/debug.txt +++ b/runtime/doc/debug.txt @@ -9,7 +9,7 @@ Debugging Vim *debug-vim* This is for debugging Vim itself, when it doesn't work properly. For debugging Vim scripts, functions, etc. see |debug-scripts| - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt index 5d5523e73f..298f64bbee 100644 --- a/runtime/doc/develop.txt +++ b/runtime/doc/develop.txt @@ -11,7 +11,7 @@ Nvim is open source software. Everybody is encouraged to contribute. See src/nvim/README.md for an overview of the source code. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== Design goals *design-goals* diff --git a/runtime/doc/diff.txt b/runtime/doc/diff.txt index 74a3d183a3..8cb049584a 100644 --- a/runtime/doc/diff.txt +++ b/runtime/doc/diff.txt @@ -10,7 +10,7 @@ eight versions of the same file. The basics are explained in section |08.7| of the user manual. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Starting diff mode diff --git a/runtime/doc/digraph.txt b/runtime/doc/digraph.txt index 43f8ccab06..d3b03c6ef6 100644 --- a/runtime/doc/digraph.txt +++ b/runtime/doc/digraph.txt @@ -14,7 +14,7 @@ with CTRL-V (see |i_CTRL-V|). There is a brief introduction on digraphs in the user manual: |24.9| An alternative is using the 'keymap' option. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Defining digraphs *digraphs-define* diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt index 29ccd48b7b..a747058991 100644 --- a/runtime/doc/editing.txt +++ b/runtime/doc/editing.txt @@ -6,7 +6,7 @@ Editing files *edit-files* - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Introduction *edit-intro* diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index b37b0e8836..300bdd061e 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -12,7 +12,7 @@ Note: Expression evaluation can be disabled at compile time. If this has been done, the features in this document are not available. See |+eval| and |no-eval-feature|. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Variables *variables* diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt index 64d9c6daa9..7f1e98fed4 100644 --- a/runtime/doc/filetype.txt +++ b/runtime/doc/filetype.txt @@ -8,7 +8,7 @@ Filetypes *filetype* *file-type* Also see |autocmd.txt|. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Filetypes *filetypes* *file-types* @@ -540,7 +540,7 @@ K or CTRL-] Jump to the manpage for the under the cursor. Takes a count for the section. CTRL-T Jump back to the location that the manpage was opened from. -META-] Show the manpage outline in the |location-list|. +gO Show the manpage outline. |gO| q :quit if invoked as $MANPAGER, otherwise :close. Variables: diff --git a/runtime/doc/fold.txt b/runtime/doc/fold.txt index 88dde9f61d..42efb04d7a 100644 --- a/runtime/doc/fold.txt +++ b/runtime/doc/fold.txt @@ -9,7 +9,7 @@ Folding *Folding* *folding* *folds* You can find an introduction on folding in chapter 28 of the user manual. |usr_28.txt| - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Fold methods *fold-methods* diff --git a/runtime/doc/gui.txt b/runtime/doc/gui.txt index b66a60c860..fb05f178ad 100644 --- a/runtime/doc/gui.txt +++ b/runtime/doc/gui.txt @@ -6,7 +6,7 @@ Vim's Graphical User Interface *gui* *GUI* - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Starting the GUI *gui-start* *E229* *E233* diff --git a/runtime/doc/helphelp.txt b/runtime/doc/helphelp.txt index 5948b24667..d86a95e854 100644 --- a/runtime/doc/helphelp.txt +++ b/runtime/doc/helphelp.txt @@ -6,7 +6,7 @@ Help on help files *helphelp* - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Help commands *online-help* @@ -23,7 +23,7 @@ Help on help files *helphelp* The 'helplang' option is used to select a language, if the main help file is available in several languages. - Type to see the table of contents. + Type |gO| to see the table of contents. *{subject}* *E149* *E661* :h[elp] {subject} Like ":help", additionally jump to the tag {subject}. diff --git a/runtime/doc/if_cscop.txt b/runtime/doc/if_cscop.txt index 831b2c9840..e359f2144c 100644 --- a/runtime/doc/if_cscop.txt +++ b/runtime/doc/if_cscop.txt @@ -12,7 +12,7 @@ a cscope query is just like jumping to any tag; it is saved on the tag stack so that with the right keyboard mappings, you can jump back and forth between functions as you normally would with |tags|. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Cscope introduction *cscope-intro* diff --git a/runtime/doc/if_lua.txt b/runtime/doc/if_lua.txt index c4efd57b45..d1b8cd4856 100644 --- a/runtime/doc/if_lua.txt +++ b/runtime/doc/if_lua.txt @@ -6,7 +6,7 @@ Lua Interface to Nvim *lua* *Lua* - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Importing modules *lua-require* diff --git a/runtime/doc/if_pyth.txt b/runtime/doc/if_pyth.txt index 8baa2d309b..8940e69092 100644 --- a/runtime/doc/if_pyth.txt +++ b/runtime/doc/if_pyth.txt @@ -8,7 +8,7 @@ The Python Interface to Vim *python* *Python* See |provider-python| for more information. {Nvim} - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Commands *python-commands* diff --git a/runtime/doc/if_ruby.txt b/runtime/doc/if_ruby.txt index 54d81a958d..a657d88a44 100644 --- a/runtime/doc/if_ruby.txt +++ b/runtime/doc/if_ruby.txt @@ -10,7 +10,7 @@ The Ruby Interface to Vim *ruby* *Ruby* The home page for ruby is http://www.ruby-lang.org/. You can find links for downloading Ruby there. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Commands *ruby-commands* diff --git a/runtime/doc/indent.txt b/runtime/doc/indent.txt index 8e17de3fb0..cf45ec4f38 100644 --- a/runtime/doc/indent.txt +++ b/runtime/doc/indent.txt @@ -6,7 +6,7 @@ This file is about indenting C programs and other files. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Indenting C style programs *C-indenting* diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index c15587cffd..ad93dcb000 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -15,7 +15,7 @@ For an overview of built-in functions see |functions|. For a list of Vim variables see |vim-variable|. For a complete listing of all help items see |help-tags|. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Insert mode *insert-index* diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt index 9219f45c83..9ef58fa54c 100644 --- a/runtime/doc/insert.txt +++ b/runtime/doc/insert.txt @@ -16,7 +16,7 @@ user manual |usr_24.txt|. Also see 'virtualedit', for moving the cursor to positions where there is no character. Useful for editing a table. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Special keys *ins-special-keys* diff --git a/runtime/doc/intro.txt b/runtime/doc/intro.txt index b9cc94ce5f..90b0ff7da3 100644 --- a/runtime/doc/intro.txt +++ b/runtime/doc/intro.txt @@ -6,7 +6,7 @@ Introduction to Vim *ref* *reference* - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Introduction *intro* diff --git a/runtime/doc/job_control.txt b/runtime/doc/job_control.txt index edbc1bca81..2cf48f0f4f 100644 --- a/runtime/doc/job_control.txt +++ b/runtime/doc/job_control.txt @@ -6,7 +6,7 @@ Nvim's facilities for job control *job-control* - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Introduction *job-control-intro* diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt index 944f7474be..e78b4cc942 100644 --- a/runtime/doc/map.txt +++ b/runtime/doc/map.txt @@ -9,7 +9,7 @@ Key mapping, abbreviations and user-defined commands. This subject is introduced in sections |05.3|, |24.7| and |40.1| of the user manual. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Key mapping *key-mapping* *mapping* *macro* diff --git a/runtime/doc/mbyte.txt b/runtime/doc/mbyte.txt index 2e2ca92656..531629fddc 100644 --- a/runtime/doc/mbyte.txt +++ b/runtime/doc/mbyte.txt @@ -14,7 +14,7 @@ For an introduction to the most common features, see |usr_45.txt| in the user manual. For changing the language of messages and menus see |mlang.txt|. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== Getting started *mbyte-first* diff --git a/runtime/doc/message.txt b/runtime/doc/message.txt index 58ababf229..904b9dfce4 100644 --- a/runtime/doc/message.txt +++ b/runtime/doc/message.txt @@ -8,7 +8,7 @@ This file contains an alphabetical list of messages and error messages that Vim produces. You can use this if you don't understand what the message means. It is not complete though. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Old messages *:messages* *:mes* *message-history* diff --git a/runtime/doc/mlang.txt b/runtime/doc/mlang.txt index 717ec9530c..6453a96877 100644 --- a/runtime/doc/mlang.txt +++ b/runtime/doc/mlang.txt @@ -11,7 +11,7 @@ multi-byte text see |multibyte|. The basics are explained in the user manual: |usr_45.txt|. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Messages *multilang-messages* diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt index fd156702f5..81137b6069 100644 --- a/runtime/doc/motion.txt +++ b/runtime/doc/motion.txt @@ -26,7 +26,7 @@ The 'virtualedit' option can be set to make it possible to move the cursor to positions where there is no character or within a multi-column character (like a tab). - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Motions and operators *operator* diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index 856476c6ae..98a74ccfd6 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -6,7 +6,7 @@ RPC API for Nvim *RPC* *rpc* *msgpack-rpc* - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Introduction *rpc-intro* diff --git a/runtime/doc/nvim.txt b/runtime/doc/nvim.txt index f3f4305ad5..2420227f6c 100644 --- a/runtime/doc/nvim.txt +++ b/runtime/doc/nvim.txt @@ -15,7 +15,7 @@ Nvim is emphatically a fork of Vim, not a clone: compatibility with Vim is maintained where possible. See |vim_diff.txt| for the complete reference of differences from Vim. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== Transitioning from Vim *nvim-from-vim* diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt index 4527a14710..9dae69ae26 100644 --- a/runtime/doc/nvim_terminal_emulator.txt +++ b/runtime/doc/nvim_terminal_emulator.txt @@ -18,7 +18,7 @@ Terminal buffers behave like normal buffers, except: closing the terminal buffer. - 'bufhidden' defaults to "hide". - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== Start *terminal-start* diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index f421d4022c..4df08ca5fb 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -14,7 +14,7 @@ achieve special effects. These options come in three forms: number has a numeric value string has a string value - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Setting options *set-option* *E764* diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt index f7f561dfa5..8243a3ca7d 100644 --- a/runtime/doc/pattern.txt +++ b/runtime/doc/pattern.txt @@ -9,7 +9,7 @@ Patterns and search commands *pattern-searches* The very basics can be found in section |03.9| of the user manual. A few more explanations are in chapter 27 |usr_27.txt|. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Search commands *search-commands* diff --git a/runtime/doc/pi_health.txt b/runtime/doc/pi_health.txt index aee3a0f6e6..99ff519bb9 100644 --- a/runtime/doc/pi_health.txt +++ b/runtime/doc/pi_health.txt @@ -2,7 +2,7 @@ Author: TJ DeVries - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== Introduction *health* diff --git a/runtime/doc/print.txt b/runtime/doc/print.txt index 01de3a5290..72625a450a 100644 --- a/runtime/doc/print.txt +++ b/runtime/doc/print.txt @@ -6,7 +6,7 @@ Printing *printing* - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Introduction *print-intro* diff --git a/runtime/doc/provider.txt b/runtime/doc/provider.txt index 60d0414edd..02f3fcab6c 100644 --- a/runtime/doc/provider.txt +++ b/runtime/doc/provider.txt @@ -8,7 +8,7 @@ Providers *provider* Nvim delegates some features to dynamic "providers". - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== Python integration *provider-python* diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt index cad5bf98b5..46ddaefbf4 100644 --- a/runtime/doc/quickfix.txt +++ b/runtime/doc/quickfix.txt @@ -6,7 +6,7 @@ This subject is introduced in section |30.1| of the user manual. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================= 1. Using QuickFix commands *quickfix* *Quickfix* *E42* diff --git a/runtime/doc/recover.txt b/runtime/doc/recover.txt index 2b49af1c96..0533157072 100644 --- a/runtime/doc/recover.txt +++ b/runtime/doc/recover.txt @@ -15,7 +15,7 @@ You can recover most of your changes from the files that Vim uses to store the contents of the file. Mostly you can recover your work with one command: vim -r filename - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. The swap file *swap-file* diff --git a/runtime/doc/remote.txt b/runtime/doc/remote.txt index bdc763b85f..67bfb0b48e 100644 --- a/runtime/doc/remote.txt +++ b/runtime/doc/remote.txt @@ -6,7 +6,7 @@ Vim client-server communication *client-server* - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Common functionality *clientserver* diff --git a/runtime/doc/remote_plugin.txt b/runtime/doc/remote_plugin.txt index cc2efd3d1f..eeb9cf8150 100644 --- a/runtime/doc/remote_plugin.txt +++ b/runtime/doc/remote_plugin.txt @@ -6,7 +6,7 @@ Nvim support for remote plugins *remote-plugin* - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Introduction *remote-plugin-intro* diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt index 0b3edc9bba..421ebab100 100644 --- a/runtime/doc/repeat.txt +++ b/runtime/doc/repeat.txt @@ -8,7 +8,7 @@ Repeating commands, Vim scripts and debugging *repeating* Chapter 26 of the user manual introduces repeating |usr_26.txt|. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Single repeats *single-repeat* diff --git a/runtime/doc/russian.txt b/runtime/doc/russian.txt index e2c44ce54f..8c6076146c 100644 --- a/runtime/doc/russian.txt +++ b/runtime/doc/russian.txt @@ -6,7 +6,7 @@ Russian language localization and support in Vim *russian* *Russian* - Type to see the table of contents. + Type |gO| to see the table of contents. =============================================================================== 1. Introduction *russian-intro* diff --git a/runtime/doc/scroll.txt b/runtime/doc/scroll.txt index 52e5cc9f0c..56af9ab75e 100644 --- a/runtime/doc/scroll.txt +++ b/runtime/doc/scroll.txt @@ -16,7 +16,7 @@ upwards in the buffer, the text in the window moves downwards on your screen. See section |03.7| of the user manual for an introduction. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Scrolling downwards *scroll-down* diff --git a/runtime/doc/sign.txt b/runtime/doc/sign.txt index ced0608e8a..977d73b7b2 100644 --- a/runtime/doc/sign.txt +++ b/runtime/doc/sign.txt @@ -7,7 +7,7 @@ Sign Support Features *sign-support* - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Introduction *sign-intro* *signs* diff --git a/runtime/doc/spell.txt b/runtime/doc/spell.txt index 5c99db42ba..f2be25097c 100644 --- a/runtime/doc/spell.txt +++ b/runtime/doc/spell.txt @@ -6,7 +6,7 @@ Spell checking *spell* - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Quick start *spell-quickstart* *E756* diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index aa55c80d4d..7aba84b454 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -6,7 +6,7 @@ Starting Vim *starting* - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Vim arguments *vim-arguments* diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index 73841edb09..cbaa2916e6 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -20,7 +20,7 @@ In the User Manual: |usr_06.txt| introduces syntax highlighting. |usr_44.txt| introduces writing a syntax file. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Quick start *:syn-qstart* diff --git a/runtime/doc/tabpage.txt b/runtime/doc/tabpage.txt index 8f1eb9d8cd..6be7cf9746 100644 --- a/runtime/doc/tabpage.txt +++ b/runtime/doc/tabpage.txt @@ -10,7 +10,7 @@ The commands which have been added to use multiple tab pages are explained here. Additionally, there are explanations for commands that work differently when used in combination with more than one tab page. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Introduction *tab-page-intro* diff --git a/runtime/doc/tagsrch.txt b/runtime/doc/tagsrch.txt index d5a4f4e627..1ceb602512 100644 --- a/runtime/doc/tagsrch.txt +++ b/runtime/doc/tagsrch.txt @@ -8,7 +8,7 @@ Tags and special searches *tags-and-searches* See section |29.1| of the user manual for an introduction. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Jump to a tag *tag-commands* diff --git a/runtime/doc/term.txt b/runtime/doc/term.txt index 39eb0673c4..a694185fc9 100644 --- a/runtime/doc/term.txt +++ b/runtime/doc/term.txt @@ -10,7 +10,7 @@ Nvim (except in |--headless| mode) uses information about the terminal you are using to present a built-in UI. If that information is not correct, the screen may be messed up or keys may not be recognized. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== Startup *startup-terminal* diff --git a/runtime/doc/tips.txt b/runtime/doc/tips.txt index 0ac9a8303d..011e0f0565 100644 --- a/runtime/doc/tips.txt +++ b/runtime/doc/tips.txt @@ -13,7 +13,7 @@ http://www.vim.org Don't forget to browse the user manual, it also contains lots of useful tips |usr_toc.txt|. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== Editing C programs *C-editing* diff --git a/runtime/doc/undo.txt b/runtime/doc/undo.txt index cbce868cec..f8f6049119 100644 --- a/runtime/doc/undo.txt +++ b/runtime/doc/undo.txt @@ -8,7 +8,7 @@ Undo and redo *undo-redo* The basics are explained in section |02.5| of the user manual. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Undo and redo commands *undo-commands* diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt index 223a0135b2..9150f3a809 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -6,7 +6,7 @@ Various commands *various* - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Various commands *various-cmds* @@ -608,6 +608,13 @@ which it was defined is reported. the keyword. Only works when the highlighted text is not more than one line. + *gO* +gO Show a filetype-specific, navigable "outline" of the + current buffer. For example, in a |help| buffer this + shows the table of contents. + + Currently works in |help| and |:Man| buffers. + [N]gs *gs* *:sl* *:sleep* :[N]sl[eep] [N] [m] Do nothing for [N] seconds. When [m] is included, sleep for [N] milliseconds. The count for "gs" always @@ -646,4 +653,4 @@ LessInitFunc in your vimrc, for example: > endfunc < - vim:tw=78:ts=8:ft=help:norl: + vim:noet:tw=78:ts=8:ft=help:norl: diff --git a/runtime/doc/vi_diff.txt b/runtime/doc/vi_diff.txt index b8bfcaa586..917e0e6f80 100644 --- a/runtime/doc/vi_diff.txt +++ b/runtime/doc/vi_diff.txt @@ -6,7 +6,7 @@ Differences between Vim and Vi *vi-differences* - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Limits *limits* diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index 16a63a2df4..c92fcd8994 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -9,7 +9,7 @@ Differences between Nvim and Vim *vim-differences* Nvim differs from Vim in many ways, big and small. This document is a complete and centralized reference of those differences. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Configuration *nvim-configuration* @@ -100,7 +100,7 @@ by Nvim developers. FEATURES ~ -"Outline": Type in |:Man| and |:help| pages to see a document outline. +"Outline": Type |gO| in |:Man| and |:help| pages to see a document outline. |META| (ALT) chords are recognized, even in the terminal. Any |, , , , , , diff --git a/runtime/doc/visual.txt b/runtime/doc/visual.txt index cf804444e5..6c4d44edb6 100644 --- a/runtime/doc/visual.txt +++ b/runtime/doc/visual.txt @@ -11,7 +11,7 @@ operator. It is the only way to select a block of text. This is introduced in section |04.4| of the user manual. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Using Visual mode *visual-use* diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt index ceb7a7f003..c37362a497 100644 --- a/runtime/doc/windows.txt +++ b/runtime/doc/windows.txt @@ -13,7 +13,7 @@ differently when used in combination with more than one window. The basics are explained in chapter 7 and 8 of the user manual |usr_07.txt| |usr_08.txt|. - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== 1. Introduction *windows-intro* *window* diff --git a/runtime/ftplugin/help.vim b/runtime/ftplugin/help.vim index 9d2361b413..e6d48454d9 100644 --- a/runtime/ftplugin/help.vim +++ b/runtime/ftplugin/help.vim @@ -90,7 +90,7 @@ if !exists('g:no_plugin_maps') let w:qf_toc = bufname endfunction - nnoremap :call show_toc() + nnoremap gO :call show_toc() endif let &cpo = s:cpo_save diff --git a/runtime/ftplugin/man.vim b/runtime/ftplugin/man.vim index 27c8b88e44..e36dfc5a90 100644 --- a/runtime/ftplugin/man.vim +++ b/runtime/ftplugin/man.vim @@ -31,7 +31,7 @@ setlocal nolist setlocal nofoldenable if !exists('g:no_plugin_maps') && !exists('g:no_man_maps') - nnoremap :call man#show_toc() + nnoremap gO :call man#show_toc() nnoremap :Man nnoremap K :Man nnoremap :call man#pop_tag() -- cgit From 3ce97879d09c5cbeba6fdc5ebd7525b127df18e0 Mon Sep 17 00:00:00 2001 From: Franklin Mathieu Date: Sat, 21 Oct 2017 01:36:26 +0100 Subject: cmake,bsd: Fix mandir to saner defaults. (#7417) closes #7239 The old behaviour was to set CMAKE_INSTALL_MANDIR to /usr/local/man when MANPREFIX wasn't defined. This caused mismatching installation paths when the installation prefix wasn't /usr/local. This fix explicitely checks that the prefix is /usr/local to change the value of CMAKE_INSTALL_MANDIR, and uses the default behaviour otherwise, as /usr/local is the exception rather than the norm (as per man hier(7)). --- cmake/InstallHelpers.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/InstallHelpers.cmake b/cmake/InstallHelpers.cmake index ca20ddf354..bebc0d0d17 100644 --- a/cmake/InstallHelpers.cmake +++ b/cmake/InstallHelpers.cmake @@ -2,8 +2,8 @@ if(CMAKE_SYSTEM_NAME MATCHES "BSD" AND NOT DEFINED CMAKE_INSTALL_MANDIR) if(DEFINED ENV{MANPREFIX}) set(CMAKE_INSTALL_MANDIR "$ENV{MANPREFIX}/man") - else() - set(CMAKE_INSTALL_MANDIR "/usr/local/man") + elseif(CMAKE_INSTALL_PREFIX MATCHES "^/usr/local$") + set(CMAKE_INSTALL_MANDIR "man") endif() endif() -- cgit From bead15f10dbdd71c0091bbfa18ec0aab9b8b2e82 Mon Sep 17 00:00:00 2001 From: KunMing Xie Date: Sun, 22 Oct 2017 18:13:46 +0800 Subject: vim-patch:8.0.0140 (#7428) Problem: Pasting inserted text in Visual mode does not work properly. (Matthew Malcomson) Solution: Stop Visual mode before stuffing the inserted text. (Christian Brabandt, from neovim #5709) https://github.com/vim/vim/commit/f8eb9c51e5bbd10e59c9b1247f8f6c7f5b77ccd0 --- src/nvim/testdir/test_visual.vim | 18 +++++++++++++----- src/nvim/version.c | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim index 8cb59ca32a..1694adbd32 100644 --- a/src/nvim/testdir/test_visual.vim +++ b/src/nvim/testdir/test_visual.vim @@ -1,13 +1,13 @@ -" Tests for Visual mode -if !has('multi_byte') - finish -endif - +" Tests for various Visual mode. if !has('visual') finish endif func Test_block_shift_multibyte() + " Uses double-wide character. + if !has('multi_byte') + return + endif split call setline(1, ['xヹxxx', 'ヹxxx']) exe "normal 1G0l\jl>" @@ -35,3 +35,11 @@ func Test_Visual_vapo() normal vapo bwipe! endfunc + +func Test_dotregister_paste() + new + exe "norm! ihello world\" + norm! 0ve".p + call assert_equal('hello world world', getline(1)) + q! +endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index fb3eadac3d..30ebbb22bc 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -963,7 +963,7 @@ static const int included_patches[] = { 143, 142, // 141, - // 140, + 140, // 139 NA // 138 NA 137, -- cgit From 9db42d4ce99c5b5747e9d83045b37e93d55c4249 Mon Sep 17 00:00:00 2001 From: Josh Leeb-du Toit Date: Fri, 29 Sep 2017 01:12:56 +1000 Subject: :cquit : take an error code argument #7336 closes #2699 ex_cmds.lua: use flags consistent with similar commands such as `cnext`. upstream discussion: "[patch] :qcuit can take exit code" https://groups.google.com/d/msg/vim_dev/_PjyNbUKyRc/oPgr5_ZXc6AJ --- runtime/doc/quickfix.txt | 16 ++++++---- src/nvim/ex_cmds.lua | 2 +- src/nvim/ex_docmd.c | 3 +- test/functional/core/exit_spec.lua | 61 +++++++++++++++++++++++++++++++------- 4 files changed, 63 insertions(+), 19 deletions(-) diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt index 46ddaefbf4..a647318347 100644 --- a/runtime/doc/quickfix.txt +++ b/runtime/doc/quickfix.txt @@ -138,11 +138,15 @@ processing a quickfix or location list command, it will be aborted. current window is used instead of the quickfix list. *:cq* *:cquit* -:cq[uit][!] Quit Vim with an error code, so that the compiler - will not compile the same file again. - WARNING: All changes in files are lost! Also when the - [!] is not used. It works like ":qall!" |:qall|, - except that Vim returns a non-zero exit code. +:[count]cq[uit] Quit Nvim with an error code, or the code specified in + [count]. Useful when Nvim is called from another + program: e.g. `git commit` will abort the comitting + process, `fc` (built-in for shells like bash and zsh) + will not execute the command. + + WARNING: All changes in files are lost. It works like + ":qall!" |:qall|, except that Nvim exits non-zero or + [count]. *:cf* *:cfile* :cf[ile][!] [errorfile] Read the error file and jump to the first error. @@ -1534,4 +1538,4 @@ by Vim. - vim:tw=78:ts=8:ft=help:norl: + vim:noet:tw=78:ts=8:ft=help:norl: diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index f99954db7a..e57e662039 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -620,7 +620,7 @@ return { }, { command='cquit', - flags=bit.bor(TRLBAR, BANG), + flags=bit.bor(RANGE, NOTADR, COUNT, ZEROR, TRLBAR, BANG), addr_type=ADDR_LINES, func='ex_cquit', }, diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 3130747e08..f64c9fded8 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "nvim/vim.h" @@ -5995,7 +5996,7 @@ static void ex_quit(exarg_T *eap) */ static void ex_cquit(exarg_T *eap) { - getout(1); + getout(eap->addr_count > 0 ? (int)eap->line2 : EXIT_FAILURE); } /* diff --git a/test/functional/core/exit_spec.lua b/test/functional/core/exit_spec.lua index 3fb39f3e78..188a6a2c11 100644 --- a/test/functional/core/exit_spec.lua +++ b/test/functional/core/exit_spec.lua @@ -2,8 +2,12 @@ local helpers = require('test.functional.helpers')(after_each) local command = helpers.command local eval = helpers.eval -local eq, neq = helpers.eq, helpers.neq +local eq = helpers.eq local run = helpers.run +local funcs = helpers.funcs +local nvim_prog = helpers.nvim_prog +local redir_exec = helpers.redir_exec +local wait = helpers.wait describe('v:exiting', function() local cid @@ -29,18 +33,53 @@ describe('v:exiting', function() end run(on_request, nil, on_setup) end) +end) - it('is non-zero after :cquit', function() - local function on_setup() - command('autocmd VimLeavePre * call rpcrequest('..cid..', "")') - command('autocmd VimLeave * call rpcrequest('..cid..', "")') - command('cquit') - end - local function on_request() - neq(0, eval('v:exiting')) - return '' +describe(':cquit', function() + local function test_cq(cmdline, exit_code, redir_msg) + if redir_msg then + eq('\n' .. redir_msg, redir_exec(cmdline)) + wait() + eq(2, eval("1+1")) -- Still alive? + else + funcs.system({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless', '--cmd', cmdline}) + eq(exit_code, eval('v:shell_error')) end - run(on_request, nil, on_setup) + end + + before_each(function() + helpers.clear() + end) + + it('exits with non-zero after :cquit', function() + test_cq('cquit', 1, nil) end) + it('exits with non-zero after :cquit 123', function() + test_cq('cquit 123', 123, nil) + end) + + it('exits with non-zero after :123 cquit', function() + test_cq('123 cquit', 123, nil) + end) + + it('exits with 0 after :cquit 0', function() + test_cq('cquit 0', 0, nil) + end) + + it('exits with 0 after :0 cquit', function() + test_cq('0 cquit', 0, nil) + end) + + it('exits with redir msg for multiple exit codes after :cquit 1 2', function() + test_cq('cquit 1 2', nil, 'E488: Trailing characters: cquit 1 2') + end) + + it('exits with redir msg for non-number exit code after :cquit X', function() + test_cq('cquit X', nil, 'E488: Trailing characters: cquit X') + end) + + it('exits with redir msg for negative exit code after :cquit -1', function() + test_cq('cquit -1', nil, 'E488: Trailing characters: cquit -1') + end) end) -- cgit From e4a974c7cc6dea53b9457bbd29a4e48f221720cb Mon Sep 17 00:00:00 2001 From: Victor Adam Date: Wed, 17 Jun 2015 11:38:47 +0200 Subject: plines_win_nofold(): Ignore virtcols after 32000th computation #3527 Avoid crashing or hanging when editing a file than contains ludicrously long lines (more than 100,000,000 virtual columns). The change is in plines_win_nofold, which is called by wrapping and folding code. As a result, wrapping and folding may be done incorrectly when the UI is capable of rendering more than 32000 characters at a time (tiny font). fixes #2838 --- src/nvim/misc1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 5270687a4d..2f02985875 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -1273,7 +1273,7 @@ int plines_win_nofold(win_T *wp, linenr_T lnum) * Add column offset for 'number', 'relativenumber' and 'foldcolumn'. */ width = wp->w_width - win_col_off(wp); - if (width <= 0) { + if (width <= 0 || col > 32000) { return 32000; // bigger than the number of lines of the screen } if (col <= (unsigned int)width) { -- cgit From a3134bc4809dff52cc9a635103a48b48d7c2d148 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 22 Oct 2017 13:51:50 +0200 Subject: test: tabstop= #2838 --- src/nvim/misc1.c | 2 +- test/functional/options/tabstop_spec.lua | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 test/functional/options/tabstop_spec.lua diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 2f02985875..137de84953 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -1274,7 +1274,7 @@ int plines_win_nofold(win_T *wp, linenr_T lnum) */ width = wp->w_width - win_col_off(wp); if (width <= 0 || col > 32000) { - return 32000; // bigger than the number of lines of the screen + return 32000; // bigger than the number of screen columns } if (col <= (unsigned int)width) { return 1; diff --git a/test/functional/options/tabstop_spec.lua b/test/functional/options/tabstop_spec.lua new file mode 100644 index 0000000000..dc3ba38438 --- /dev/null +++ b/test/functional/options/tabstop_spec.lua @@ -0,0 +1,23 @@ +local helpers = require('test.functional.helpers')(after_each) + +local clear = helpers.clear +local feed = helpers.feed +local eq = helpers.eq +local eval = helpers.eval + +describe("'tabstop' option", function() + before_each(function() + clear() + end) + + -- NOTE: Setting 'tabstop' to a big number reproduces crash #2838. + -- Disallowing big 'tabstop' would not fix #2838, only hide it. + it("tabstop= does not crash #2838", function() + -- Insert a character for 'tabstop' to work with. + feed('i') + -- Set 'tabstop' to a very high value. + -- Use feed(), not command(), to provoke crash. + feed(':set tabstop=3000000000') + eq(2, eval("1+1")) -- Still alive? + end) +end) -- cgit From fdd9b1982ba2bce586e30a5a119273aa448bf049 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 24 Oct 2017 21:57:11 +0200 Subject: :version : show Lua[Jit] version (#7436) Also remove vestigial `extra_patches` code. --- src/nvim/version.c | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/src/nvim/version.c b/src/nvim/version.c index 30ebbb22bc..6f3ca12458 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -22,6 +22,7 @@ #include "nvim/message.h" #include "nvim/screen.h" #include "nvim/strings.h" +#include "nvim/lua/executor.h" // version info generated by the build system #include "auto/versiondef.h" @@ -1107,16 +1108,6 @@ static const int included_patches[] = { }; // clang-format on -/// Place to put a short description when adding a feature with a patch. -/// Keep it short, e.g.,: "relative numbers", "persistent undo". -/// Also add a comment marker to separate the lines. -/// See the official Vim patches for the diff format: It must use a context of -/// one line only. Create it by hand or use "diff -C2" and edit the patch. -static char *(extra_patches[]) = { - // Add your patch description below this line - NULL -}; - /// Compares a version string to the current Nvim version. /// /// @param version Version string like "1.3.42" @@ -1251,27 +1242,24 @@ static void list_features(void) MSG_PUTS("See \":help feature-compile\"\n\n"); } +void list_lua_version(void) +{ + typval_T luaver_tv; + typval_T arg = { .v_type = VAR_UNKNOWN }; // No args. + char *luaver_expr = "((jit and jit.version) and jit.version or _VERSION)"; + executor_eval_lua(cstr_as_string(luaver_expr), &arg, &luaver_tv); + assert(luaver_tv.v_type == VAR_STRING); + MSG(luaver_tv.vval.v_string); + xfree(luaver_tv.vval.v_string); +} + void list_version(void) { - // When adding features here, don't forget to update the list of - // internal variables in eval.c! MSG(longVersion); MSG(version_buildtype); + list_lua_version(); MSG(version_cflags); - // Print the list of extra patch descriptions if there is at least one. - char *s = ""; - if (extra_patches[0] != NULL) { - MSG_PUTS(_("\nExtra patches: ")); - s = ""; - - for (int i = 0; extra_patches[i] != NULL; ++i) { - MSG_PUTS(s); - s = ", "; - MSG_PUTS(extra_patches[i]); - } - } - #ifdef HAVE_PATHDEF if ((*compiled_user != NUL) || (*compiled_sys != NUL)) { @@ -1312,6 +1300,8 @@ void list_version(void) version_msg("\"\n"); } #endif // ifdef HAVE_PATHDEF + + version_msg("\nRun :checkhealth for more info"); } /// Output a string for the version message. If it's going to wrap, output a -- cgit From f1f7f3b5123edbd312ae92e9510c4c86cfe1171d Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 23 Oct 2017 19:52:23 -0400 Subject: inccommand: Ignore leading modifiers in the command --- src/nvim/ex_docmd.c | 8 ++++++- test/functional/ui/inccommand_spec.lua | 38 ++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index f64c9fded8..096187b162 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -9883,7 +9883,7 @@ static void ex_terminal(exarg_T *eap) /// Checks if `cmd` is "previewable" (i.e. supported by 'inccommand'). /// -/// @param[in] cmd Commandline to check. May start with a range. +/// @param[in] cmd Commandline to check. May start with a range or modifier. /// /// @return true if `cmd` is previewable bool cmd_can_preview(char_u *cmd) @@ -9892,6 +9892,12 @@ bool cmd_can_preview(char_u *cmd) return false; } + // Ignore any leading modifiers (:keeppatterns, :verbose, etc.) + for (int len = modifier_len(cmd); len != 0; len = modifier_len(cmd)) { + cmd += len; + cmd = skipwhite(cmd); + } + exarg_T ea; // parse the command line ea.cmd = skip_range(cmd, NULL); diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index c8fa2888d1..cc023ef10d 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -701,6 +701,25 @@ describe(":substitute, inccommand=split", function() eq(0, eval("&modified")) end) + it("shows preview when cmd modifiers are present", function() + -- one modifier + feed(':keeppatterns %s/tw/to') + screen:expect([[too lines]], nil, nil, nil, true) + feed('') + screen:expect([[two lines]], nil, nil, nil, true) + + -- multiple modifiers + feed(':keeppatterns silent %s/tw/to') + screen:expect([[too lines]], nil, nil, nil, true) + feed('') + screen:expect([[two lines]], nil, nil, nil, true) + + -- non-modifier prefix + feed(':silent tabedit %s/tw/to') + screen:expect([[two lines]], nil, nil, nil, true) + feed('') + end) + it('shows split window when typing the pattern', function() feed(":%s/tw") screen:expect([[ @@ -1140,6 +1159,25 @@ describe("inccommand=nosplit", function() ]]) end) + it("shows preview when cmd modifiers are present", function() + -- one modifier + feed(':keeppatterns %s/tw/to') + screen:expect([[too lines]], nil, nil, nil, true) + feed('') + screen:expect([[two lines]], nil, nil, nil, true) + + -- multiple modifiers + feed(':keeppatterns silent %s/tw/to') + screen:expect([[too lines]], nil, nil, nil, true) + feed('') + screen:expect([[two lines]], nil, nil, nil, true) + + -- non-modifier prefix + feed(':silent tabedit %s/tw/to') + screen:expect([[two lines]], nil, nil, nil, true) + feed('') + end) + it('never shows preview buffer', function() feed_command("set hlsearch") -- cgit From 439c39a2cfb0712eb68ad76354b1fd7e92bb71fe Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Thu, 23 Feb 2017 05:33:14 +0000 Subject: ext_cmdline: allow external ui to draw cmdline --- runtime/doc/msgpack_rpc.txt | 33 +++++++++++++++++++ src/nvim/ex_getln.c | 80 ++++++++++++++++++++++++++++++++++++++++----- src/nvim/ui.c | 2 ++ 3 files changed, 106 insertions(+), 9 deletions(-) diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index 98a74ccfd6..4a82b3a1bd 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -260,12 +260,23 @@ a dictionary with these (optional) keys: colors. Set to false to use terminal color codes (at most 256 different colors). + `ext_popupmenu` Externalize the popupmenu. |ui-ext-popupmenu| `ext_tabline` Externalize the tabline. |ui-ext-tabline| Externalized widgets will not be drawn by Nvim; only high-level data will be published in new UI event kinds. + `popupmenu_external`: Instead of drawing the completion popupmenu on + the grid, Nvim will send higher-level events to + the ui and let it draw the popupmenu. + Defaults to false. + cmdline_external: Instead of drawing the cmdline on + the grid, Nvim will send higher-level events to + the ui and let it draw the cmdline. + Defaults to false. + + Nvim will then send msgpack-rpc notifications, with the method name "redraw" and a single argument, an array of screen updates (described below). These should be processed in order. Preferably the user should only be able to see @@ -441,5 +452,27 @@ states might be represented as separate modes. curtab: Current Tabpage tabs: List of Dicts [{ "tab": Tabpage, "name": String }, ...] +["cmdline_enter"] + Enter the cmdline. + +["cmdline_leave"] + Leave the cmdline. + +["cmdline_firstc", firstc] + The first character of the command, which could be : / ? etc. With + the firstc, you know wheither it's a command or a search. + +["cmdline", content, pos] + When cmdline_external is set to true, nvim will not draw the cmdline + on the grad, instead nvim will send ui events of the cmdline content + and cursor position to the remote ui. The content is the full content + that should be displayed in the cmdline, and the pos is the position + of the cursor that in the cmdline. This event will be triggered when + you type in the cmdline. + +["cmdline_pos", pos] + When you move your cursor, nvim will send out this event which tells + you the current position of the cursor in the cmdline. + ============================================================================== vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 54e5bcb9ff..87bf46d4d0 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -185,6 +185,8 @@ static int cmd_showtail; /* Only show path tail in lists ? */ static int new_cmdpos; /* position set by set_cmdline_pos() */ +static bool cmdline_external = false; + /* * Type used by call_user_expand_func */ @@ -281,7 +283,9 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) if (!cmd_silent) { s->i = msg_scrolled; msg_scrolled = 0; // avoid wait_return message - gotocmdline(true); + if (!cmdline_external) { + gotocmdline(true); + } msg_scrolled += s->i; redrawcmdprompt(); // draw prompt or indent set_cmdspos(); @@ -1828,7 +1832,16 @@ getcmdline ( int indent // indent for inside conditionals ) { - return command_line_enter(firstc, count, indent); + if (cmdline_external) { + Array args = ARRAY_DICT_INIT; + ui_event("cmdline_enter", args); + } + char_u *p = command_line_enter(firstc, count, indent); + if (cmdline_external) { + Array args = ARRAY_DICT_INIT; + ui_event("cmdline_leave", args); + } + return p; } /// Get a command line with a prompt @@ -2589,6 +2602,14 @@ static void draw_cmdline(int start, int len) return; } + if (cmdline_external) { + Array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); + ADD(args, INTEGER_OBJ(ccline.cmdpos)); + ui_event("cmdline", args); + return; + } + if (cmdline_star > 0) { for (int i = 0; i < len; i++) { msg_putchar('*'); @@ -2713,11 +2734,28 @@ void putcmdline(int c, int shift) { if (cmd_silent) return; - msg_no_more = TRUE; - msg_putchar(c); - if (shift) - draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); - msg_no_more = FALSE; + if (!cmdline_external) { + msg_no_more = TRUE; + msg_putchar(c); + if (shift) + draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); + msg_no_more = FALSE; + } else { + char_u *p; + if (ccline.cmdpos == ccline.cmdlen || shift) { + p = vim_strnsave(ccline.cmdbuff, ccline.cmdlen + 1); + } else { + p = vim_strsave(ccline.cmdbuff); + } + p[ccline.cmdpos] = c; + if (shift) + STRCPY(p + ccline.cmdpos + 1, ccline.cmdbuff + ccline.cmdpos); + Array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstr_to_string((char *)(p)))); + ADD(args, INTEGER_OBJ(ccline.cmdpos)); + ui_event("cmdline", args); + xfree(p); + } cursorcmd(); ui_cursor_shape(); } @@ -3066,8 +3104,15 @@ static void redrawcmdprompt(void) if (cmd_silent) return; - if (ccline.cmdfirstc != NUL) - msg_putchar(ccline.cmdfirstc); + if (ccline.cmdfirstc != NUL) { + if (cmdline_external) { + Array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstr_to_string((char *)(&ccline.cmdfirstc)))); + ui_event("cmdline_firstc", args); + } else { + msg_putchar(ccline.cmdfirstc); + } + } if (ccline.cmdprompt != NULL) { msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr); ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns; @@ -3087,6 +3132,11 @@ void redrawcmd(void) if (cmd_silent) return; + if (cmdline_external) { + draw_cmdline(0, ccline.cmdlen); + return; + } + /* when 'incsearch' is set there may be no command line while redrawing */ if (ccline.cmdbuff == NULL) { ui_cursor_goto(cmdline_row, 0); @@ -3130,6 +3180,13 @@ static void cursorcmd(void) if (cmd_silent) return; + if (cmdline_external) { + Array args = ARRAY_DICT_INIT; + ADD(args, INTEGER_OBJ(ccline.cmdpos)); + ui_event("cmdline_pos", args); + return; + } + if (cmdmsg_rl) { msg_row = cmdline_row + (ccline.cmdspos / (int)(Columns - 1)); msg_col = (int)Columns - (ccline.cmdspos % (int)(Columns - 1)) - 1; @@ -5974,3 +6031,8 @@ static void set_search_match(pos_T *t) coladvance((colnr_T)MAXCOL); } } + +void cmdline_set_external(bool external) +{ + cmdline_external = external; +} diff --git a/src/nvim/ui.c b/src/nvim/ui.c index afe7a51d43..0fa4034ff6 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -30,6 +30,7 @@ #include "nvim/os/input.h" #include "nvim/os/signal.h" #include "nvim/popupmnu.h" +#include "nvim/ex_getln.h" #include "nvim/screen.h" #include "nvim/syntax.h" #include "nvim/window.h" @@ -280,6 +281,7 @@ void ui_refresh(void) int save_p_lz = p_lz; p_lz = false; // convince redrawing() to return true ... + cmdline_set_external(cmdline_external); screen_resize(width, height); p_lz = save_p_lz; -- cgit From 6e90bc7200c87f0af448a8cf0998715db9175f15 Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Thu, 23 Feb 2017 09:53:12 +0000 Subject: ext_cmdline: Added cmdline prompt --- runtime/doc/msgpack_rpc.txt | 3 +++ src/nvim/eval.c | 18 +++++++++++------- src/nvim/ex_getln.c | 21 ++++++++++++++++----- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index 4a82b3a1bd..b7c790bb64 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -462,6 +462,9 @@ states might be represented as separate modes. The first character of the command, which could be : / ? etc. With the firstc, you know wheither it's a command or a search. +["cmdline_prompt", prompt] + The prompt of the cmdline. + ["cmdline", content, pos] When cmdline_external is set to true, nvim will not draw the cmdline on the grad, instead nvim will send ui events of the cmdline content diff --git a/src/nvim/eval.c b/src/nvim/eval.c index aab777955c..72b97cbab9 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -11149,15 +11149,19 @@ void get_user_input(const typval_T *const argvars, // Only the part of the message after the last NL is considered as // prompt for the command line. const char *p = strrchr(prompt, '\n'); - if (p == NULL) { + if (ui_is_external(kUICmdline)) { p = prompt; } else { - p++; - msg_start(); - msg_clr_eos(); - msg_puts_attr_len(prompt, p - prompt, echo_attr); - msg_didout = false; - msg_starthere(); + if (p == NULL) { + p = prompt; + } else { + p++; + msg_start(); + msg_clr_eos(); + msg_puts_attr_len(prompt, p - prompt, echo_attr); + msg_didout = false; + msg_starthere(); + } } cmdline_row = msg_row; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 87bf46d4d0..a05331d13a 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -3114,11 +3114,17 @@ static void redrawcmdprompt(void) } } if (ccline.cmdprompt != NULL) { - msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr); - ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns; - /* do the reverse of set_cmdspos() */ - if (ccline.cmdfirstc != NUL) - --ccline.cmdindent; + if (cmdline_external) { + Array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdprompt)))); + ui_event("cmdline_prompt", args); + } else { + msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr); + ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns; + /* do the reverse of set_cmdspos() */ + if (ccline.cmdfirstc != NUL) + --ccline.cmdindent; + } } else for (i = ccline.cmdindent; i > 0; --i) msg_putchar(' '); @@ -6036,3 +6042,8 @@ void cmdline_set_external(bool external) { cmdline_external = external; } + +bool cmdline_get_external(void) +{ + return cmdline_external; +} -- cgit From 26fd70bd18283701a2ade11407694485cd0f7e35 Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Fri, 24 Feb 2017 07:26:39 +0000 Subject: ext_cmdline: add tests --- src/nvim/ex_getln.c | 11 ++-- test/functional/ui/cmdline_spec.lua | 128 ++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 4 deletions(-) create mode 100644 test/functional/ui/cmdline_spec.lua diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index a05331d13a..18d6b26595 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -283,9 +283,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) if (!cmd_silent) { s->i = msg_scrolled; msg_scrolled = 0; // avoid wait_return message - if (!cmdline_external) { - gotocmdline(true); - } + gotocmdline(true); msg_scrolled += s->i; redrawcmdprompt(); // draw prompt or indent set_cmdspos(); @@ -808,7 +806,9 @@ static int command_line_execute(VimState *state, int key) } if (!cmd_silent) { - ui_cursor_goto(msg_row, 0); + if (!cmdline_external) { + ui_cursor_goto(msg_row, 0); + } ui_flush(); } return 0; @@ -3210,6 +3210,9 @@ static void cursorcmd(void) void gotocmdline(int clr) { + if (cmdline_external) { + return; + } msg_start(); if (cmdmsg_rl) msg_col = Columns - 1; diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua new file mode 100644 index 0000000000..67eff9827c --- /dev/null +++ b/test/functional/ui/cmdline_spec.lua @@ -0,0 +1,128 @@ +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') +local clear, feed, execute, eq = helpers.clear, helpers.feed, helpers.execute, helpers.eq +local funcs = helpers.funcs + +if helpers.pending_win32(pending) then return end + +describe('External command line completion', function() + local screen + local shown = false + local firstc, prompt, content, pos + + before_each(function() + clear() + screen = Screen.new(25, 5) + screen:attach({rgb=true, cmdline_external=true}) + screen:set_on_event_handler(function(name, data) + if name == "cmdline_enter" then + shown = true + elseif name == "cmdline_leave" then + shown = false + elseif name == "cmdline_firstc" then + firstc = data[1] + elseif name == "cmdline_prompt" then + prompt = data[1] + elseif name == "cmdline" then + content, pos = unpack(data) + elseif name == "cmdline_pos" then + pos = data[1] + end + end) + end) + + after_each(function() + screen:detach() + end) + + describe("'cmdline'", function() + it(':sign', function() + feed(':') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(true, shown) + eq(':', firstc) + end) + + feed('sign') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq("sign", content) + eq(4, pos) + end) + + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq("sign", content) + eq(true, shown) + eq(3, pos) + end) + + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq("sin", content) + eq(true, shown) + eq(2, pos) + end) + + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(false, shown) + end) + + feed(':call input("input", "default")') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(true, shown) + eq("input", prompt) + eq("default", content) + end) + + feed('') + feed(':=1+2') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq("3", content) + end) + + end) + end) +end) -- cgit From b7a8a76f6e3b2de1cfdf32e3ccc66d87ab8e5cad Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Mon, 27 Feb 2017 02:56:38 +0000 Subject: ext_cmdline: lint --- src/nvim/ex_getln.c | 13 ++++++++----- test/functional/ui/cmdline_spec.lua | 3 +-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 18d6b26595..0fae6c9810 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -3121,13 +3121,16 @@ static void redrawcmdprompt(void) } else { msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr); ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns; - /* do the reverse of set_cmdspos() */ - if (ccline.cmdfirstc != NUL) - --ccline.cmdindent; + // do the reverse of set_cmdspos() + if (ccline.cmdfirstc != NUL) { + ccline.cmdindent--; + } } - } else - for (i = ccline.cmdindent; i > 0; --i) + } else { + for (i = ccline.cmdindent; i > 0; i--) { msg_putchar(' '); + } + } } /* diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 67eff9827c..d0726f5924 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -1,7 +1,6 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') -local clear, feed, execute, eq = helpers.clear, helpers.feed, helpers.execute, helpers.eq -local funcs = helpers.funcs +local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq if helpers.pending_win32(pending) then return end -- cgit From 550651c130c014e6c668644273db31dd96be475e Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Fri, 28 Apr 2017 06:51:16 +0100 Subject: ext_cmdline: use standard external ui functions --- runtime/doc/msgpack_rpc.txt | 22 ++------ src/nvim/eval.c | 15 +++--- src/nvim/ex_getln.c | 104 +++++++++++++++++------------------- src/nvim/ui.c | 1 - test/functional/ui/cmdline_spec.lua | 16 +++--- 5 files changed, 65 insertions(+), 93 deletions(-) diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index b7c790bb64..46fc6f19c2 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -260,23 +260,13 @@ a dictionary with these (optional) keys: colors. Set to false to use terminal color codes (at most 256 different colors). - `ext_popupmenu` Externalize the popupmenu. |ui-ext-popupmenu| `ext_tabline` Externalize the tabline. |ui-ext-tabline| + `ext_cmdline` Externalize the cmdline. |ui-ext-cmdline| Externalized widgets will not be drawn by Nvim; only high-level data will be published in new UI event kinds. - `popupmenu_external`: Instead of drawing the completion popupmenu on - the grid, Nvim will send higher-level events to - the ui and let it draw the popupmenu. - Defaults to false. - cmdline_external: Instead of drawing the cmdline on - the grid, Nvim will send higher-level events to - the ui and let it draw the cmdline. - Defaults to false. - - Nvim will then send msgpack-rpc notifications, with the method name "redraw" and a single argument, an array of screen updates (described below). These should be processed in order. Preferably the user should only be able to see @@ -452,20 +442,14 @@ states might be represented as separate modes. curtab: Current Tabpage tabs: List of Dicts [{ "tab": Tabpage, "name": String }, ...] + *ui-ext-cmdline* ["cmdline_enter"] Enter the cmdline. ["cmdline_leave"] Leave the cmdline. -["cmdline_firstc", firstc] - The first character of the command, which could be : / ? etc. With - the firstc, you know wheither it's a command or a search. - -["cmdline_prompt", prompt] - The prompt of the cmdline. - -["cmdline", content, pos] +["cmdline_show", content, pos, firstc, prompt] When cmdline_external is set to true, nvim will not draw the cmdline on the grad, instead nvim will send ui events of the cmdline content and cursor position to the remote ui. The content is the full content diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 72b97cbab9..3c9614dfcd 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -11147,15 +11147,12 @@ void get_user_input(const typval_T *const argvars, cmd_silent = false; // Want to see the prompt. // Only the part of the message after the last NL is considered as - // prompt for the command line. - const char *p = strrchr(prompt, '\n'); - if (ui_is_external(kUICmdline)) { - p = prompt; - } else { - if (p == NULL) { - p = prompt; - } else { - p++; + // prompt for the command line, unlsess cmdline is externalized + const char *p = prompt; + if (!ui_is_external(kUICmdline)) { + const char *lastnl = strrchr(prompt, '\n'); + if (lastnl != NULL) { + p = lastnl+1; msg_start(); msg_clr_eos(); msg_puts_attr_len(prompt, p - prompt, echo_attr); diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 0fae6c9810..8c9e081c89 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -185,8 +185,6 @@ static int cmd_showtail; /* Only show path tail in lists ? */ static int new_cmdpos; /* position set by set_cmdline_pos() */ -static bool cmdline_external = false; - /* * Type used by call_user_expand_func */ @@ -806,7 +804,7 @@ static int command_line_execute(VimState *state, int key) } if (!cmd_silent) { - if (!cmdline_external) { + if (!ui_is_external(kUICmdline)) { ui_cursor_goto(msg_row, 0); } ui_flush(); @@ -1832,12 +1830,12 @@ getcmdline ( int indent // indent for inside conditionals ) { - if (cmdline_external) { + if (ui_is_external(kUICmdline)) { Array args = ARRAY_DICT_INIT; ui_event("cmdline_enter", args); } char_u *p = command_line_enter(firstc, count, indent); - if (cmdline_external) { + if (ui_is_external(kUICmdline)) { Array args = ARRAY_DICT_INIT; ui_event("cmdline_leave", args); } @@ -2602,11 +2600,8 @@ static void draw_cmdline(int start, int len) return; } - if (cmdline_external) { - Array args = ARRAY_DICT_INIT; - ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); - ADD(args, INTEGER_OBJ(ccline.cmdpos)); - ui_event("cmdline", args); + if (ui_is_external(kUICmdline)) { + ui_ext_cmdline_show(); return; } @@ -2725,6 +2720,32 @@ draw_cmdline_no_arabicshape: } } +void ui_ext_cmdline_char(int c, int shift) +{ + Array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstr_to_string((char *)(&c)))); + ADD(args, INTEGER_OBJ(shift)); + ui_event("cmdline_char", args); +} + +void ui_ext_cmdline_show(void) +{ + Array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); + ADD(args, INTEGER_OBJ(ccline.cmdpos)); + if (ccline.cmdfirstc != NUL) { + ADD(args, STRING_OBJ(cstr_to_string((char *)(&ccline.cmdfirstc)))); + } else { + ADD(args, STRING_OBJ(cstr_to_string(""))); + } + if (ccline.cmdprompt != NULL) { + ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdprompt)))); + } else { + ADD(args, STRING_OBJ(cstr_to_string(""))); + } + ui_event("cmdline_show", args); +} + /* * Put a character on the command line. Shifts the following text to the * right when "shift" is TRUE. Used for CTRL-V, CTRL-K, etc. @@ -2732,29 +2753,17 @@ draw_cmdline_no_arabicshape: */ void putcmdline(int c, int shift) { - if (cmd_silent) + if (cmd_silent) { return; - if (!cmdline_external) { + } + if (!ui_is_external(kUICmdline)) { msg_no_more = TRUE; msg_putchar(c); if (shift) draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); msg_no_more = FALSE; } else { - char_u *p; - if (ccline.cmdpos == ccline.cmdlen || shift) { - p = vim_strnsave(ccline.cmdbuff, ccline.cmdlen + 1); - } else { - p = vim_strsave(ccline.cmdbuff); - } - p[ccline.cmdpos] = c; - if (shift) - STRCPY(p + ccline.cmdpos + 1, ccline.cmdbuff + ccline.cmdpos); - Array args = ARRAY_DICT_INIT; - ADD(args, STRING_OBJ(cstr_to_string((char *)(p)))); - ADD(args, INTEGER_OBJ(ccline.cmdpos)); - ui_event("cmdline", args); - xfree(p); + ui_ext_cmdline_char(c, shift); } cursorcmd(); ui_cursor_shape(); @@ -3104,27 +3113,19 @@ static void redrawcmdprompt(void) if (cmd_silent) return; + if (ui_is_external(kUICmdline)) { + ui_ext_cmdline_show(); + return; + } if (ccline.cmdfirstc != NUL) { - if (cmdline_external) { - Array args = ARRAY_DICT_INIT; - ADD(args, STRING_OBJ(cstr_to_string((char *)(&ccline.cmdfirstc)))); - ui_event("cmdline_firstc", args); - } else { - msg_putchar(ccline.cmdfirstc); - } + msg_putchar(ccline.cmdfirstc); } if (ccline.cmdprompt != NULL) { - if (cmdline_external) { - Array args = ARRAY_DICT_INIT; - ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdprompt)))); - ui_event("cmdline_prompt", args); - } else { - msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr); - ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns; - // do the reverse of set_cmdspos() - if (ccline.cmdfirstc != NUL) { - ccline.cmdindent--; - } + msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr); + ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns; + // do the reverse of set_cmdspos() + if (ccline.cmdfirstc != NUL) { + ccline.cmdindent--; } } else { for (i = ccline.cmdindent; i > 0; i--) { @@ -3141,7 +3142,7 @@ void redrawcmd(void) if (cmd_silent) return; - if (cmdline_external) { + if (ui_is_external(kUICmdline)) { draw_cmdline(0, ccline.cmdlen); return; } @@ -3189,7 +3190,7 @@ static void cursorcmd(void) if (cmd_silent) return; - if (cmdline_external) { + if (ui_is_external(kUICmdline)) { Array args = ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(ccline.cmdpos)); ui_event("cmdline_pos", args); @@ -3213,7 +3214,7 @@ static void cursorcmd(void) void gotocmdline(int clr) { - if (cmdline_external) { + if (ui_is_external(kUICmdline)) { return; } msg_start(); @@ -6044,12 +6045,3 @@ static void set_search_match(pos_T *t) } } -void cmdline_set_external(bool external) -{ - cmdline_external = external; -} - -bool cmdline_get_external(void) -{ - return cmdline_external; -} diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 0fa4034ff6..6b09f6e6db 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -281,7 +281,6 @@ void ui_refresh(void) int save_p_lz = p_lz; p_lz = false; // convince redrawing() to return true ... - cmdline_set_external(cmdline_external); screen_resize(width, height); p_lz = save_p_lz; diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index d0726f5924..35cacbf4d0 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -7,23 +7,21 @@ if helpers.pending_win32(pending) then return end describe('External command line completion', function() local screen local shown = false - local firstc, prompt, content, pos + local firstc, prompt, content, pos, char, shift before_each(function() clear() screen = Screen.new(25, 5) - screen:attach({rgb=true, cmdline_external=true}) + screen:attach({rgb=true, ext_cmdline=true}) screen:set_on_event_handler(function(name, data) if name == "cmdline_enter" then shown = true elseif name == "cmdline_leave" then shown = false - elseif name == "cmdline_firstc" then - firstc = data[1] - elseif name == "cmdline_prompt" then - prompt = data[1] - elseif name == "cmdline" then - content, pos = unpack(data) + elseif name == "cmdline_show" then + content, pos, firstc, prompt = unpack(data) + elseif name == "cmdline_char" then + char, shift = unpack(data) elseif name == "cmdline_pos" then pos = data[1] end @@ -120,6 +118,8 @@ describe('External command line completion', function() | ]], nil, nil, function() eq("3", content) + eq("\"", char) + eq(1, shift) end) end) -- cgit From daec81ab5179c7ce8e3813af556b1e2f05fc59c6 Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Fri, 28 Apr 2017 07:49:45 +0100 Subject: ext_cmdline: change the content format --- runtime/doc/msgpack_rpc.txt | 2 ++ src/nvim/ex_getln.c | 7 ++++++- test/functional/ui/cmdline_spec.lua | 10 +++++----- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index 46fc6f19c2..ef4a22db0b 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -450,6 +450,8 @@ states might be represented as separate modes. Leave the cmdline. ["cmdline_show", content, pos, firstc, prompt] + content: List of [highlight group, string] + [["Normal", "t"], ["Search", "est"], ...] When cmdline_external is set to true, nvim will not draw the cmdline on the grad, instead nvim will send ui events of the cmdline content and cursor position to the remote ui. The content is the full content diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 8c9e081c89..12f3f53c81 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2731,7 +2731,12 @@ void ui_ext_cmdline_char(int c, int shift) void ui_ext_cmdline_show(void) { Array args = ARRAY_DICT_INIT; - ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); + Array content = ARRAY_DICT_INIT; + Array text = ARRAY_DICT_INIT; + ADD(text, STRING_OBJ(cstr_to_string("Normal"))); + ADD(text, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); + ADD(content, ARRAY_OBJ(text)); + ADD(args, ARRAY_OBJ(content)); ADD(args, INTEGER_OBJ(ccline.cmdpos)); if (ccline.cmdfirstc != NUL) { ADD(args, STRING_OBJ(cstr_to_string((char *)(&ccline.cmdfirstc)))); diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 35cacbf4d0..523f7065d4 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -54,7 +54,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq("sign", content) + eq({{'Normal', 'sign'}}, content) eq(4, pos) end) @@ -66,7 +66,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq("sign", content) + eq({{'Normal', 'sign'}}, content) eq(true, shown) eq(3, pos) end) @@ -79,7 +79,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq("sin", content) + eq({{'Normal', 'sin'}}, content) eq(true, shown) eq(2, pos) end) @@ -105,7 +105,7 @@ describe('External command line completion', function() ]], nil, nil, function() eq(true, shown) eq("input", prompt) - eq("default", content) + eq({{'Normal', 'default'}}, content) end) feed('') @@ -117,7 +117,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq("3", content) + eq({{'Normal', '3'}}, content) eq("\"", char) eq(1, shift) end) -- cgit From e164ba41c8460d4e5b2e7e2b929d8479a0310738 Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Thu, 11 May 2017 04:48:59 +0100 Subject: ext_cmdline: fix firstc, change cmdline_leave to cmdline_hide --- runtime/doc/msgpack_rpc.txt | 4 ++-- src/nvim/ex_getln.c | 19 ++++++++----------- test/functional/ui/cmdline_spec.lua | 2 +- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index ef4a22db0b..77938fbd82 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -446,8 +446,8 @@ states might be represented as separate modes. ["cmdline_enter"] Enter the cmdline. -["cmdline_leave"] - Leave the cmdline. +["cmdline_hide"] + Hide the cmdline. ["cmdline_show", content, pos, firstc, prompt] content: List of [highlight group, string] diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 12f3f53c81..34547c59c9 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1837,7 +1837,7 @@ getcmdline ( char_u *p = command_line_enter(firstc, count, indent); if (ui_is_external(kUICmdline)) { Array args = ARRAY_DICT_INIT; - ui_event("cmdline_leave", args); + ui_event("cmdline_hide", args); } return p; } @@ -2738,16 +2738,13 @@ void ui_ext_cmdline_show(void) ADD(content, ARRAY_OBJ(text)); ADD(args, ARRAY_OBJ(content)); ADD(args, INTEGER_OBJ(ccline.cmdpos)); - if (ccline.cmdfirstc != NUL) { - ADD(args, STRING_OBJ(cstr_to_string((char *)(&ccline.cmdfirstc)))); - } else { - ADD(args, STRING_OBJ(cstr_to_string(""))); - } - if (ccline.cmdprompt != NULL) { - ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdprompt)))); - } else { - ADD(args, STRING_OBJ(cstr_to_string(""))); - } + char *firstc = (char []) { (char)ccline.cmdfirstc }; + String str = (String) { + .data = xmemdupz(firstc, 1), + .size = 1 + }; + ADD(args, STRING_OBJ(str)); + ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdprompt)))); ui_event("cmdline_show", args); } diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 523f7065d4..479f5c3b7d 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -16,7 +16,7 @@ describe('External command line completion', function() screen:set_on_event_handler(function(name, data) if name == "cmdline_enter" then shown = true - elseif name == "cmdline_leave" then + elseif name == "cmdline_hide" then shown = false elseif name == "cmdline_show" then content, pos, firstc, prompt = unpack(data) -- cgit From ab85999eb7c53e9d2b5bca5f8896ea11cb1df13e Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Thu, 11 May 2017 07:11:21 +0100 Subject: ext_cmdline: change to use ui_call --- src/nvim/api/ui_events.in.h | 11 +++++++++++ src/nvim/ex_getln.c | 27 +++++---------------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 1b5d17584f..093251bb00 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -68,4 +68,15 @@ void popupmenu_select(Integer selected) void tabline_update(Tabpage current, Array tabs) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_enter(void) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_show(Array content, Integer pos, String firstc, String prompt) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_pos(Integer pos) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_char(String c, Integer shift) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_hide(void) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + #endif // NVIM_API_UI_EVENTS_IN_H diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 34547c59c9..0223d9e936 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1831,13 +1831,11 @@ getcmdline ( ) { if (ui_is_external(kUICmdline)) { - Array args = ARRAY_DICT_INIT; - ui_event("cmdline_enter", args); + ui_call_cmdline_enter(); } char_u *p = command_line_enter(firstc, count, indent); if (ui_is_external(kUICmdline)) { - Array args = ARRAY_DICT_INIT; - ui_event("cmdline_hide", args); + ui_call_cmdline_hide(); } return p; } @@ -2720,32 +2718,19 @@ draw_cmdline_no_arabicshape: } } -void ui_ext_cmdline_char(int c, int shift) -{ - Array args = ARRAY_DICT_INIT; - ADD(args, STRING_OBJ(cstr_to_string((char *)(&c)))); - ADD(args, INTEGER_OBJ(shift)); - ui_event("cmdline_char", args); -} - void ui_ext_cmdline_show(void) { - Array args = ARRAY_DICT_INIT; Array content = ARRAY_DICT_INIT; Array text = ARRAY_DICT_INIT; ADD(text, STRING_OBJ(cstr_to_string("Normal"))); ADD(text, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); ADD(content, ARRAY_OBJ(text)); - ADD(args, ARRAY_OBJ(content)); - ADD(args, INTEGER_OBJ(ccline.cmdpos)); char *firstc = (char []) { (char)ccline.cmdfirstc }; String str = (String) { .data = xmemdupz(firstc, 1), .size = 1 }; - ADD(args, STRING_OBJ(str)); - ADD(args, STRING_OBJ(cstr_to_string((char *)(ccline.cmdprompt)))); - ui_event("cmdline_show", args); + ui_call_cmdline_show(content, ccline.cmdpos, str, cstr_to_string((char *)(ccline.cmdprompt))); } /* @@ -2765,7 +2750,7 @@ void putcmdline(int c, int shift) draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); msg_no_more = FALSE; } else { - ui_ext_cmdline_char(c, shift); + ui_call_cmdline_char(cstr_to_string((char *)(&c)), shift); } cursorcmd(); ui_cursor_shape(); @@ -3193,9 +3178,7 @@ static void cursorcmd(void) return; if (ui_is_external(kUICmdline)) { - Array args = ARRAY_DICT_INIT; - ADD(args, INTEGER_OBJ(ccline.cmdpos)); - ui_event("cmdline_pos", args); + ui_call_cmdline_pos(ccline.cmdpos); return; } -- cgit From 866dadaf753ba3733feb8c22d7da47af757bd35c Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Thu, 11 May 2017 07:51:10 +0100 Subject: ext_cmdline: added cmdline level add cchar_to_string --- src/nvim/api/private/helpers.c | 16 ++++++++++++ src/nvim/api/ui_events.in.h | 11 +++----- src/nvim/ex_getln.c | 40 +++++++++++++--------------- test/functional/ui/cmdline_spec.lua | 52 +++++++++++++++++++++++++++++++------ 4 files changed, 82 insertions(+), 37 deletions(-) diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index e736e29e2d..f00fbf69ea 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -667,6 +667,22 @@ tabpage_T *find_tab_by_handle(Tabpage tabpage, Error *err) return rv; } +/// Allocates a String consisting of a single char. Does not support multibyte +/// characters. The resulting string is also NUL-terminated, to facilitate +/// interoperating with code using C strings. +/// +/// @param char the char to convert +/// @return the resulting String, if the input char was NUL, an +/// empty String is returned +String cchar_to_string(char c) +{ + char buf[] = { c, NUL }; + return (String) { + .data = xmemdupz(buf, 1), + .size = (c != NUL) ? 1 : 0 + }; +} + /// Copies a C string into a String (binary safe string, characters + length). /// The resulting string is also NUL-terminated, to facilitate interoperating /// with code using C strings. diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 093251bb00..17eefbe1d6 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -66,17 +66,14 @@ void popupmenu_hide(void) void popupmenu_select(Integer selected) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void tabline_update(Tabpage current, Array tabs) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; - -void cmdline_enter(void) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_show(Array content, Integer pos, String firstc, String prompt) +void cmdline_show(Array content, Integer pos, String firstc, String prompt, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_pos(Integer pos) +void cmdline_pos(Integer pos, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_char(String c, Integer shift) +void cmdline_char(String c, Integer shift, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_hide(void) +void cmdline_hide(Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; #endif // NVIM_API_UI_EVENTS_IN_H diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 0223d9e936..548459a8ce 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -91,6 +91,7 @@ struct cmdline_info { int input_fn; // when TRUE Invoked for input() function unsigned prompt_id; ///< Prompt number, used to disable coloring on errors. Callback highlight_callback; ///< Callback used for coloring user input. + int level; // current cmdline level }; /// Last value of prompt_id, incremented when doing new prompt static unsigned last_prompt_id = 0; @@ -238,7 +239,9 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) cmd_hkmap = 0; } + // TODO(bfredl): can these be combined? ccline.prompt_id = last_prompt_id++; + ccline.level++; ccline.overstrike = false; // always start in insert mode clearpos(&s->match_end); s->save_cursor = curwin->w_cursor; // may be restored later @@ -414,6 +417,11 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) // Make ccline empty, getcmdline() may try to use it. ccline.cmdbuff = NULL; + + if (ui_is_external(kUICmdline)) { + ui_call_cmdline_hide(ccline.level); + } + ccline.level--; return p; } } @@ -1830,14 +1838,7 @@ getcmdline ( int indent // indent for inside conditionals ) { - if (ui_is_external(kUICmdline)) { - ui_call_cmdline_enter(); - } - char_u *p = command_line_enter(firstc, count, indent); - if (ui_is_external(kUICmdline)) { - ui_call_cmdline_hide(); - } - return p; + return command_line_enter(firstc, count, indent); } /// Get a command line with a prompt @@ -2720,17 +2721,12 @@ draw_cmdline_no_arabicshape: void ui_ext_cmdline_show(void) { - Array content = ARRAY_DICT_INIT; - Array text = ARRAY_DICT_INIT; - ADD(text, STRING_OBJ(cstr_to_string("Normal"))); - ADD(text, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); - ADD(content, ARRAY_OBJ(text)); - char *firstc = (char []) { (char)ccline.cmdfirstc }; - String str = (String) { - .data = xmemdupz(firstc, 1), - .size = 1 - }; - ui_call_cmdline_show(content, ccline.cmdpos, str, cstr_to_string((char *)(ccline.cmdprompt))); + Array content = ARRAY_DICT_INIT; + Array text = ARRAY_DICT_INIT; + ADD(text, STRING_OBJ(cstr_to_string("Normal"))); + ADD(text, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); + ADD(content, ARRAY_OBJ(text)); + ui_call_cmdline_show(content, ccline.cmdpos, cchar_to_string((char)ccline.cmdfirstc), cstr_to_string((char *)(ccline.cmdprompt)), ccline.level); } /* @@ -2750,7 +2746,7 @@ void putcmdline(int c, int shift) draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); msg_no_more = FALSE; } else { - ui_call_cmdline_char(cstr_to_string((char *)(&c)), shift); + ui_call_cmdline_char(cchar_to_string((char)(c)), shift, ccline.level); } cursorcmd(); ui_cursor_shape(); @@ -3178,7 +3174,7 @@ static void cursorcmd(void) return; if (ui_is_external(kUICmdline)) { - ui_call_cmdline_pos(ccline.cmdpos); + ui_call_cmdline_pos(ccline.cmdpos, ccline.level); return; } @@ -3200,7 +3196,7 @@ static void cursorcmd(void) void gotocmdline(int clr) { if (ui_is_external(kUICmdline)) { - return; + return; } msg_start(); if (cmdmsg_rl) diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 479f5c3b7d..479d40e959 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -7,19 +7,19 @@ if helpers.pending_win32(pending) then return end describe('External command line completion', function() local screen local shown = false - local firstc, prompt, content, pos, char, shift + local firstc, prompt, content, pos, char, shift, level, current_hide_level before_each(function() clear() screen = Screen.new(25, 5) screen:attach({rgb=true, ext_cmdline=true}) screen:set_on_event_handler(function(name, data) - if name == "cmdline_enter" then - shown = true - elseif name == "cmdline_hide" then + if name == "cmdline_hide" then shown = false + current_hide_level = data[1] elseif name == "cmdline_show" then - content, pos, firstc, prompt = unpack(data) + shown = true + content, pos, firstc, prompt, level = unpack(data) elseif name == "cmdline_char" then char, shift = unpack(data) elseif name == "cmdline_pos" then @@ -107,9 +107,9 @@ describe('External command line completion', function() eq("input", prompt) eq({{'Normal', 'default'}}, content) end) - feed('') - feed(':=1+2') + + feed(':') screen:expect([[ ^ | ~ | @@ -117,9 +117,45 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq({{'Normal', '3'}}, content) + eq(1, level) + end) + + feed('=1+2') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{'Normal', '1+2'}}, content) eq("\"", char) eq(1, shift) + eq(2, level) + end) + + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{'Normal', '3'}}, content) + eq(2, current_hide_level) + eq(1, level) + end) + + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(1, current_hide_level) end) end) -- cgit From 461ae698242458bffbf5fb68de89fe8b2a3defd2 Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Mon, 26 Jun 2017 11:19:40 +0100 Subject: ext_cmdline: Add function block support --- src/nvim/api/ui_events.in.h | 4 ++++ src/nvim/eval.c | 11 ++++++++++- test/functional/ui/cmdline_spec.lua | 39 ++++++++++++++++++++++++++++++++++++- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 17eefbe1d6..5602dc6df3 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -75,5 +75,9 @@ void cmdline_char(String c, Integer shift, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_hide(Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_function_show(void) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_function_hide(void) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; #endif // NVIM_API_UI_EVENTS_IN_H diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 3c9614dfcd..d5ff01e922 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -19816,6 +19816,10 @@ void ex_function(exarg_T *eap) goto errret_2; } + if (ui_is_external(kUICmdline)) { + ui_call_cmdline_function_show(); + } + // find extra arguments "range", "dict", "abort" and "closure" for (;; ) { p = skipwhite(p); @@ -19868,7 +19872,9 @@ void ex_function(exarg_T *eap) if (!eap->skip && did_emsg) goto erret; - msg_putchar('\n'); /* don't overwrite the function name */ + if (!ui_is_external(kUICmdline)) { + msg_putchar('\n'); /* don't overwrite the function name */ + } cmdline_row = msg_row; } @@ -20194,6 +20200,9 @@ ret_free: xfree(name); did_emsg |= saved_did_emsg; need_wait_return |= saved_wait_return; + if (ui_is_external(kUICmdline)) { + ui_call_cmdline_function_hide(); + } } /// Get a function name, translating "" and "". diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 479d40e959..9e2857bc95 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -7,7 +7,7 @@ if helpers.pending_win32(pending) then return end describe('External command line completion', function() local screen local shown = false - local firstc, prompt, content, pos, char, shift, level, current_hide_level + local firstc, prompt, content, pos, char, shift, level, current_hide_level, in_function before_each(function() clear() @@ -24,6 +24,10 @@ describe('External command line completion', function() char, shift = unpack(data) elseif name == "cmdline_pos" then pos = data[1] + elseif name == "cmdline_function_show" then + in_function = true + elseif name == "cmdline_function_hide" then + in_function = false end end) end) @@ -158,6 +162,39 @@ describe('External command line completion', function() eq(1, current_hide_level) end) + feed(':function Foo()') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(true, in_function) + end) + + feed('line1') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(true, in_function) + end) + + feed('endfunction') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(false, in_function) + end) + end) end) end) -- cgit From fb389a6b4b1e6fedb559dc2e5845dd138e8ff264 Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Mon, 26 Jun 2017 15:27:49 +0100 Subject: ext_cmdline: added indent --- src/nvim/api/ui_events.in.h | 2 +- src/nvim/ex_getln.c | 6 +++++- test/functional/ui/cmdline_spec.lua | 17 +++++++++++++++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 5602dc6df3..700d99dc6b 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -67,7 +67,7 @@ void popupmenu_select(Integer selected) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void tabline_update(Tabpage current, Array tabs) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_show(Array content, Integer pos, String firstc, String prompt, Integer level) +void cmdline_show(Array content, Integer pos, String firstc, String prompt, Integer indent, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_pos(Integer pos, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 548459a8ce..6f941e66ef 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2726,7 +2726,11 @@ void ui_ext_cmdline_show(void) ADD(text, STRING_OBJ(cstr_to_string("Normal"))); ADD(text, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); ADD(content, ARRAY_OBJ(text)); - ui_call_cmdline_show(content, ccline.cmdpos, cchar_to_string((char)ccline.cmdfirstc), cstr_to_string((char *)(ccline.cmdprompt)), ccline.level); + ui_call_cmdline_show(content, ccline.cmdpos, + cchar_to_string((char)ccline.cmdfirstc), + cstr_to_string((char *)(ccline.cmdprompt)), + ccline.cmdindent, + ccline.level); } /* diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 9e2857bc95..1e30ba1449 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -7,7 +7,7 @@ if helpers.pending_win32(pending) then return end describe('External command line completion', function() local screen local shown = false - local firstc, prompt, content, pos, char, shift, level, current_hide_level, in_function + local firstc, prompt, content, pos, char, shift, indent, level, current_hide_level, in_function before_each(function() clear() @@ -19,7 +19,7 @@ describe('External command line completion', function() current_hide_level = data[1] elseif name == "cmdline_show" then shown = true - content, pos, firstc, prompt, level = unpack(data) + content, pos, firstc, prompt, indent, level = unpack(data) elseif name == "cmdline_char" then char, shift = unpack(data) elseif name == "cmdline_pos" then @@ -171,6 +171,7 @@ describe('External command line completion', function() | ]], nil, nil, function() eq(true, in_function) + eq(2, indent) end) feed('line1') @@ -182,6 +183,7 @@ describe('External command line completion', function() | ]], nil, nil, function() eq(true, in_function) + eq(2, indent) end) feed('endfunction') @@ -195,6 +197,17 @@ describe('External command line completion', function() eq(false, in_function) end) + feed(':sign') + screen:expect([[ + | + [No Name] | + :sign^ | + [Command Line] | + | + ]], nil, nil, function() + eq(false, in_function) + end) + end) end) end) -- cgit From 5ad591ef2d0ef184f78c728b1774c2a55fe2e581 Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Tue, 27 Jun 2017 02:20:27 +0100 Subject: ext_cmdline: lint --- src/nvim/api/ui_events.in.h | 17 +++++++++-------- src/nvim/eval.c | 2 +- src/nvim/ex_getln.c | 7 ++++--- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 700d99dc6b..bb1084c838 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -66,18 +66,19 @@ void popupmenu_hide(void) void popupmenu_select(Integer selected) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void tabline_update(Tabpage current, Array tabs) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_show(Array content, Integer pos, String firstc, String prompt, Integer indent, Integer level) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_show(Array content, Integer pos, String firstc, String prompt, + Integer indent, Integer level) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_pos(Integer pos, Integer level) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_char(String c, Integer shift, Integer level) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_hide(Integer level) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_function_show(void) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_function_hide(void) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; #endif // NVIM_API_UI_EVENTS_IN_H diff --git a/src/nvim/eval.c b/src/nvim/eval.c index d5ff01e922..5f655cdc7b 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -19873,7 +19873,7 @@ void ex_function(exarg_T *eap) goto erret; if (!ui_is_external(kUICmdline)) { - msg_putchar('\n'); /* don't overwrite the function name */ + msg_putchar('\n'); // don't overwrite the function name } cmdline_row = msg_row; } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 6f941e66ef..93c060b4b7 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2744,11 +2744,12 @@ void putcmdline(int c, int shift) return; } if (!ui_is_external(kUICmdline)) { - msg_no_more = TRUE; + msg_no_more = true; msg_putchar(c); - if (shift) + if (shift) { draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); - msg_no_more = FALSE; + } + msg_no_more = false; } else { ui_call_cmdline_char(cchar_to_string((char)(c)), shift, ccline.level); } -- cgit From 22402fb99d05191cf140293cfb5f67902e78a8a8 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 16 Aug 2017 12:19:29 +0200 Subject: ext_cmdline: add support for highlighting --- src/nvim/api/private/helpers.c | 17 ++++++++ src/nvim/ex_getln.c | 31 ++++++++++++--- test/functional/ui/cmdline_spec.lua | 77 ++++++++++++++++++++++++++++++++++--- 3 files changed, 114 insertions(+), 11 deletions(-) diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index f00fbf69ea..2944925a9c 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -703,6 +703,23 @@ String cstr_to_string(const char *str) }; } +/// Copies buffer to an allocated String. +/// The resulting string is also NUL-terminated, to facilitate interoperating +/// with code using C strings. +/// +/// @param buf the buffer to copy +/// @param size length of the buffer +/// @return the resulting String, if the input string was NULL, an +/// empty String is returned +String cbuf_to_string(const char *buf, size_t size) + FUNC_ATTR_NONNULL_ALL +{ + return (String) { + .data = xmemdupz(buf, size), + .size = size + }; +} + /// Creates a String using the given C string. Unlike /// cstr_to_string this function DOES NOT copy the C string. /// diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 93c060b4b7..624a108bd4 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2372,6 +2372,7 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline, FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { bool printed_errmsg = false; + #define PRINT_ERRMSG(...) \ do { \ msg_putchar('\n'); \ @@ -2405,7 +2406,7 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline, static unsigned prev_prompt_id = UINT_MAX; static int prev_prompt_errors = 0; - Callback color_cb = { .type = kCallbackNone }; + Callback color_cb = CALLBACK_NONE; bool can_free_cb = false; TryState tstate; Error err = ERROR_INIT; @@ -2722,10 +2723,30 @@ draw_cmdline_no_arabicshape: void ui_ext_cmdline_show(void) { Array content = ARRAY_DICT_INIT; - Array text = ARRAY_DICT_INIT; - ADD(text, STRING_OBJ(cstr_to_string("Normal"))); - ADD(text, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); - ADD(content, ARRAY_OBJ(text)); + if (kv_size(last_ccline_colors.colors)) { + for (size_t i = 0; i < kv_size(last_ccline_colors.colors); i++) { + CmdlineColorChunk chunk = kv_A(last_ccline_colors.colors, i); + Array item = ARRAY_DICT_INIT; + + if (chunk.attr) { + attrentry_T *aep = syn_cterm_attr2entry(chunk.attr); + // TODO(bfredl): this desicion could be delayed by making attr_code a + // recognized type + HlAttrs rgb_attrs = attrentry2hlattrs(aep, true); + ADD(item, DICTIONARY_OBJ(hlattrs2dict(rgb_attrs))); + } else { + ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); + } + ADD(item, STRING_OBJ(cbuf_to_string((char *)ccline.cmdbuff + chunk.start, + chunk.end-chunk.start))); + ADD(content, ARRAY_OBJ(item)); + } + } else { + Array item = ARRAY_DICT_INIT; + ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); + ADD(item, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); + ADD(content, ARRAY_OBJ(item)); + } ui_call_cmdline_show(content, ccline.cmdpos, cchar_to_string((char)ccline.cmdfirstc), cstr_to_string((char *)(ccline.cmdprompt)), diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 1e30ba1449..8d694052ee 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -1,6 +1,7 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq +local source = helpers.source if helpers.pending_win32(pending) then return end @@ -36,6 +37,22 @@ describe('External command line completion', function() screen:detach() end) + function expect_cmdline(expected) + local attr_ids = screen._default_attr_ids + local attr_ignore = screen._default_attr_ignore + local actual = '' + for _, chunk in ipairs(content or {}) do + local attrs, text = chunk[1], chunk[2] + if screen:_equal_attrs(attrs, {}) then + actual = actual..text + else + local attr_id = screen:_get_attr_id(attr_ids, attr_ignore, attrs) + actual = actual..'{' .. attr_id .. ':' .. text .. '}' + end + end + eq(expected, actual) + end + describe("'cmdline'", function() it(':sign', function() feed(':') @@ -58,7 +75,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq({{'Normal', 'sign'}}, content) + eq({{{}, 'sign'}}, content) eq(4, pos) end) @@ -70,7 +87,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq({{'Normal', 'sign'}}, content) + eq({{{}, 'sign'}}, content) eq(true, shown) eq(3, pos) end) @@ -83,7 +100,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq({{'Normal', 'sin'}}, content) + eq({{{}, 'sin'}}, content) eq(true, shown) eq(2, pos) end) @@ -109,7 +126,7 @@ describe('External command line completion', function() ]], nil, nil, function() eq(true, shown) eq("input", prompt) - eq({{'Normal', 'default'}}, content) + eq({{{}, 'default'}}, content) end) feed('') @@ -132,7 +149,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq({{'Normal', '1+2'}}, content) + eq({{{}, '1+2'}}, content) eq("\"", char) eq(1, shift) eq(2, level) @@ -146,7 +163,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq({{'Normal', '3'}}, content) + eq({{{}, '3'}}, content) eq(2, current_hide_level) eq(1, level) end) @@ -210,4 +227,52 @@ describe('External command line completion', function() end) end) + + it('works with highlighted cmdline', function() + source([[ + highlight RBP1 guibg=Red + highlight RBP2 guibg=Yellow + highlight RBP3 guibg=Green + highlight RBP4 guibg=Blue + let g:NUM_LVLS = 4 + function RainBowParens(cmdline) + let ret = [] + let i = 0 + let lvl = 0 + while i < len(a:cmdline) + if a:cmdline[i] is# '(' + call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)]) + let lvl += 1 + elseif a:cmdline[i] is# ')' + let lvl -= 1 + call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)]) + endif + let i += 1 + endwhile + return ret + endfunction + map :let x = input({'prompt':'>','highlight':'RainBowParens'}) + "map :let x = input({'prompt':'>'}) + ]]) + screen:set_default_attr_ids({ + RBP1={background = Screen.colors.Red}, + RBP2={background = Screen.colors.Yellow}, + RBP3={background = Screen.colors.Green}, + RBP4={background = Screen.colors.Blue}, + EOB={bold = true, foreground = Screen.colors.Blue1}, + ERR={foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + SK={foreground = Screen.colors.Blue}, + PE={bold = true, foreground = Screen.colors.SeaGreen4} + }) + feed('(a(b)a)') + screen:expect([[ + ^ | + {EOB:~ }| + {EOB:~ }| + {EOB:~ }| + | + ]], nil, nil, function() + expect_cmdline('{RBP1:(}a{RBP2:(}b{RBP2:)}a{RBP1:)}') + end) + end) end) -- cgit From ddfc077da468450d1fab81fe3b3f594bb6ebf6dd Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 16 Aug 2017 13:36:02 +0200 Subject: ext_cmdline: disable some redraws --- src/nvim/ex_getln.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 624a108bd4..0e620e59d8 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1144,7 +1144,7 @@ static int command_line_handle_key(CommandLineState *s) xfree(ccline.cmdbuff); // no commandline to return ccline.cmdbuff = NULL; - if (!cmd_silent) { + if (!cmd_silent && !ui_is_external(kUICmdline)) { if (cmdmsg_rl) { msg_col = Columns; } else { @@ -1596,9 +1596,14 @@ static int command_line_handle_key(CommandLineState *s) s->do_abbr = false; // don't do abbreviation now // may need to remove ^ when composing char was typed if (enc_utf8 && utf_iscomposing(s->c) && !cmd_silent) { - draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); - msg_putchar(' '); - cursorcmd(); + if (ui_is_external(kUICmdline)) { + // TODO(bfredl): why not make unputcmdline also work with true? + unputcmdline(); + } else { + draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); + msg_putchar(' '); + cursorcmd(); + } } break; @@ -2778,22 +2783,19 @@ void putcmdline(int c, int shift) ui_cursor_shape(); } -/* - * Undo a putcmdline(c, FALSE). - */ +/// Undo a putcmdline(c, FALSE). void unputcmdline(void) { - if (cmd_silent) + if (cmd_silent) { return; - msg_no_more = TRUE; - if (ccline.cmdlen == ccline.cmdpos) + } + msg_no_more = true; + if (ccline.cmdlen == ccline.cmdpos && !ui_is_external(kUICmdline)) { msg_putchar(' '); - else if (has_mbyte) - draw_cmdline(ccline.cmdpos, - (*mb_ptr2len)(ccline.cmdbuff + ccline.cmdpos)); - else - draw_cmdline(ccline.cmdpos, 1); - msg_no_more = FALSE; + } else { + draw_cmdline(ccline.cmdpos, mb_ptr2len(ccline.cmdbuff + ccline.cmdpos)); + } + msg_no_more = false; cursorcmd(); ui_cursor_shape(); } -- cgit From a68817f56517a31943806bd0b5a0030cdd35e182 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 16 Aug 2017 13:57:58 +0200 Subject: ext_cmdline: extend "function" to generic "block" mechanism --- src/nvim/api/ui_events.in.h | 7 +++++-- src/nvim/eval.c | 13 +++++++++---- src/nvim/ex_getln.c | 28 ++++++++++++++++++++++++++++ test/functional/ui/cmdline_spec.lua | 18 +++++++++--------- 4 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index bb1084c838..764078c6bd 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -67,6 +67,7 @@ void popupmenu_select(Integer selected) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void tabline_update(Tabpage current, Array tabs) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + void cmdline_show(Array content, Integer pos, String firstc, String prompt, Integer indent, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; @@ -76,9 +77,11 @@ void cmdline_char(String c, Integer shift, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_hide(Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_function_show(void) +void cmdline_block_show(Array lines) + FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; +void cmdline_block_append(Array lines) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_function_hide(void) +void cmdline_block_hide(void) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; #endif // NVIM_API_UI_EVENTS_IN_H diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 5f655cdc7b..50044718b6 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -19643,6 +19643,7 @@ void ex_function(exarg_T *eap) int todo; hashitem_T *hi; int sourcing_lnum_off; + bool show_block = false; /* * ":function" without argument: list functions. @@ -19816,8 +19817,9 @@ void ex_function(exarg_T *eap) goto errret_2; } - if (ui_is_external(kUICmdline)) { - ui_call_cmdline_function_show(); + if (KeyTyped && ui_is_external(kUICmdline)) { + show_block = true; + ui_ext_cmdline_block_append(0, (const char *)eap->cmd); } // find extra arguments "range", "dict", "abort" and "closure" @@ -19908,6 +19910,9 @@ void ex_function(exarg_T *eap) EMSG(_("E126: Missing :endfunction")); goto erret; } + if (show_block) { + ui_ext_cmdline_block_append(indent, (const char *)theline); + } /* Detect line continuation: sourcing_lnum increased more than one. */ if (sourcing_lnum > sourcing_lnum_off + 1) @@ -20200,8 +20205,8 @@ ret_free: xfree(name); did_emsg |= saved_did_emsg; need_wait_return |= saved_wait_return; - if (ui_is_external(kUICmdline)) { - ui_call_cmdline_function_hide(); + if (show_block) { + ui_ext_cmdline_block_leave(); } } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 0e620e59d8..50cccc8d10 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -186,6 +186,8 @@ static int cmd_showtail; /* Only show path tail in lists ? */ static int new_cmdpos; /* position set by set_cmdline_pos() */ +static Array cmdline_block; ///< currently displayed block of context + /* * Type used by call_user_expand_func */ @@ -2759,6 +2761,32 @@ void ui_ext_cmdline_show(void) ccline.level); } +void ui_ext_cmdline_block_append(int indent, const char *line) +{ + char *buf = xmallocz(indent + strlen(line)); + memset(buf, ' ', indent); + memcpy(buf+indent, line, strlen(line)); + + Array item = ARRAY_DICT_INIT; + ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); + ADD(item, STRING_OBJ(cstr_as_string(buf))); + Array content = ARRAY_DICT_INIT; + ADD(content, ARRAY_OBJ(item)); + ADD(cmdline_block, ARRAY_OBJ(content)); + if (cmdline_block.size > 1) { + ui_call_cmdline_block_append(copy_array(content)); + } else { + ui_call_cmdline_block_show(copy_array(cmdline_block)); + } +} + +void ui_ext_cmdline_block_leave(void) +{ + api_free_array(cmdline_block); + ui_call_cmdline_block_hide(); +} + + /* * Put a character on the command line. Shifts the following text to the * right when "shift" is TRUE. Used for CTRL-V, CTRL-K, etc. diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 8d694052ee..3b63a3bd9e 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -8,7 +8,7 @@ if helpers.pending_win32(pending) then return end describe('External command line completion', function() local screen local shown = false - local firstc, prompt, content, pos, char, shift, indent, level, current_hide_level, in_function + local firstc, prompt, content, pos, char, shift, indent, level, current_hide_level, in_block before_each(function() clear() @@ -25,10 +25,10 @@ describe('External command line completion', function() char, shift = unpack(data) elseif name == "cmdline_pos" then pos = data[1] - elseif name == "cmdline_function_show" then - in_function = true - elseif name == "cmdline_function_hide" then - in_function = false + elseif name == "cmdline_block_show" then + in_block = true + elseif name == "cmdline_block_hide" then + in_block = false end end) end) @@ -187,7 +187,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq(true, in_function) + eq(true, in_block) eq(2, indent) end) @@ -199,7 +199,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq(true, in_function) + eq(true, in_block) eq(2, indent) end) @@ -211,7 +211,7 @@ describe('External command line completion', function() ~ | | ]], nil, nil, function() - eq(false, in_function) + eq(false, in_block) end) feed(':sign') @@ -222,7 +222,7 @@ describe('External command line completion', function() [Command Line] | | ]], nil, nil, function() - eq(false, in_function) + eq(false, in_block) end) end) -- cgit From f2aaa4ae8b84f74666b4379b391f333f34868a45 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 16 Aug 2017 15:38:12 +0200 Subject: ext_cmdline: rename cmdline_char to cmdline_special_char --- src/nvim/api/ui_events.in.h | 2 +- src/nvim/ex_getln.c | 3 ++- test/functional/ui/cmdline_spec.lua | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 764078c6bd..65357d008a 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -73,7 +73,7 @@ void cmdline_show(Array content, Integer pos, String firstc, String prompt, FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_pos(Integer pos, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; -void cmdline_char(String c, Integer shift, Integer level) +void cmdline_special_char(String c, Boolean shift, Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void cmdline_hide(Integer level) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 50cccc8d10..b9cf7b977c 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2805,7 +2805,8 @@ void putcmdline(int c, int shift) } msg_no_more = false; } else { - ui_call_cmdline_char(cchar_to_string((char)(c)), shift, ccline.level); + ui_call_cmdline_special_char(cchar_to_string((char)(c)), shift, + ccline.level); } cursorcmd(); ui_cursor_shape(); diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 3b63a3bd9e..33835dd9e4 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -21,7 +21,9 @@ describe('External command line completion', function() elseif name == "cmdline_show" then shown = true content, pos, firstc, prompt, indent, level = unpack(data) - elseif name == "cmdline_char" then + -- FIXME: + --char, shift = nil, nil + elseif name == "cmdline_special_char" then char, shift = unpack(data) elseif name == "cmdline_pos" then pos = data[1] -- cgit From 87a723963e720612d16c7cfb577d529f58a3d4d1 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 16 Aug 2017 15:38:23 +0200 Subject: ext_cmdline: documentation --- runtime/doc/msgpack_rpc.txt | 62 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index 77938fbd82..9601e239f2 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -302,6 +302,8 @@ kind. Set the default foreground, background and special colors respectively. + + *ui-event-highlight_set* ["highlight_set", attrs] Set the attributes that the next text put on the screen will have. `attrs` is a dict with the keys below. Any absent key is reset @@ -443,25 +445,57 @@ states might be represented as separate modes. tabs: List of Dicts [{ "tab": Tabpage, "name": String }, ...] *ui-ext-cmdline* -["cmdline_enter"] - Enter the cmdline. +["cmdline_show", content, pos, firstc, prompt, indent, level] + content: List of [attrs, string] + [[{}, "t"], [attrs, "est"], ...] + When cmdline_external is set to true, nvim will not draw the cmdline + on the grid, instead nvim will send ui events of the cmdline content + and cursor position to the remote ui. The `content` is the full content + that should be displayed in the cmdline, and the `pos` is the position + of the cursor that in the cmdline. This event will be triggered when + you type in the cmdline. The content is divided into chunks with + different highlight attributes represented as a dict, see + |ui-event-highlight_set|. + + `firstc` and `prompt` are text, that if non-empty should be + displayed in front of the command line. `firstc` always indicates + built in command lines such as `:` (ex command) and `/` `?` (search), + while `prompt` is an |input()| prompt. `indent` tells how many spaces + the content should be indented + + The command line in nvim can be invoked recursively, for instance by + typing `=` at the command line prompt. The `level` field is used + to distinguish different command lines active at the same time. The + first invoked command line will always have level 1, and the next + recursively invoked prompt will have level 2. Also, a command line + invoked while in command line window will have a higher level than + than the edited command line. + +["cmdline_pos", pos, level] + Change the cursor position in the cmdline. + +["cmdline_special_char", c, shift, level] + Display a special char in the cmdline at the cursor position. This is + typically used to indicate a pending state, like right after Ctrl-V. + if shift is true the text after the cursor should be shifted, + otherwise it should overshadow the char at the cursor. + Should be hidden at next cmdline_char + ["cmdline_hide"] Hide the cmdline. -["cmdline_show", content, pos, firstc, prompt] - content: List of [highlight group, string] - [["Normal", "t"], ["Search", "est"], ...] - When cmdline_external is set to true, nvim will not draw the cmdline - on the grad, instead nvim will send ui events of the cmdline content - and cursor position to the remote ui. The content is the full content - that should be displayed in the cmdline, and the pos is the position - of the cursor that in the cmdline. This event will be triggered when - you type in the cmdline. +["cmdline_block_show", lines] + Show a block of context to the current command line. This occurs for + instance if a function is interactively defined at the command line. + `lines` is a list of lines where each line is represented as a list of + highlighted chunks, just like `contents` of |ui-event-cmdline_show|. + +["cmdline_block_append", line] + Append a line at the end of the currently shown block. -["cmdline_pos", pos] - When you move your cursor, nvim will send out this event which tells - you the current position of the cursor in the cmdline. +["cmdline_block_hide"] + Hide the block. ============================================================================== vim:tw=78:ts=8:noet:ft=help:norl: -- cgit From 91f94bfef80c1f39a597dd47806e8dbe45a22578 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Thu, 17 Aug 2017 12:26:33 +0200 Subject: ext_cmdline: restructure and improve tests --- test/functional/ui/cmdline_spec.lua | 450 ++++++++++++++++++++++-------------- 1 file changed, 274 insertions(+), 176 deletions(-) diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 33835dd9e4..3f9ce8ad67 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -2,35 +2,42 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq local source = helpers.source +local ok = helpers.ok if helpers.pending_win32(pending) then return end -describe('External command line completion', function() +describe('external cmdline', function() local screen - local shown = false - local firstc, prompt, content, pos, char, shift, indent, level, current_hide_level, in_block + local last_level = 0 + local cmdline = {} + local block = nil before_each(function() clear() screen = Screen.new(25, 5) screen:attach({rgb=true, ext_cmdline=true}) screen:set_on_event_handler(function(name, data) - if name == "cmdline_hide" then - shown = false - current_hide_level = data[1] - elseif name == "cmdline_show" then - shown = true - content, pos, firstc, prompt, indent, level = unpack(data) - -- FIXME: - --char, shift = nil, nil + if name == "cmdline_show" then + local content, pos, firstc, prompt, indent, level = unpack(data) + ok(level > 0) + cmdline[level] = {content=content, pos=pos, firstc=firstc, + prompt=prompt, indent=indent} + last_level = level + elseif name == "cmdline_hide" then + local level = data[1] + cmdline[level] = nil elseif name == "cmdline_special_char" then - char, shift = unpack(data) + local char, shift, level = unpack(data) + cmdline[level].special = {char, shift} elseif name == "cmdline_pos" then - pos = data[1] + local pos, level = unpack(data) + cmdline[level].pos = pos elseif name == "cmdline_block_show" then - in_block = true + block = data[1] + elseif name == "cmdline_block_append" then + block[#block+1] = data[1] elseif name == "cmdline_block_hide" then - in_block = false + block = nil end end) end) @@ -39,11 +46,11 @@ describe('External command line completion', function() screen:detach() end) - function expect_cmdline(expected) + local function expect_cmdline(level, expected) local attr_ids = screen._default_attr_ids local attr_ignore = screen._default_attr_ignore local actual = '' - for _, chunk in ipairs(content or {}) do + for _, chunk in ipairs(cmdline[level] and cmdline[level].content or {}) do local attrs, text = chunk[1], chunk[2] if screen:_equal_attrs(attrs, {}) then actual = actual..text @@ -55,181 +62,272 @@ describe('External command line completion', function() eq(expected, actual) end - describe("'cmdline'", function() - it(':sign', function() - feed(':') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq(true, shown) - eq(':', firstc) - end) + it('works', function() + feed(':') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(1, last_level) + eq({{ + content = { { {}, "" } }, + firstc = ":", + indent = 0, + pos = 0, + prompt = "" + }}, cmdline) + end) - feed('sign') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq({{{}, 'sign'}}, content) - eq(4, pos) - end) + feed('sign') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "sign" } }, + firstc = ":", + indent = 0, + pos = 4, + prompt = "" + }}, cmdline) + end) - feed('') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq({{{}, 'sign'}}, content) - eq(true, shown) - eq(3, pos) - end) + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "sign" } }, + firstc = ":", + indent = 0, + pos = 3, + prompt = "" + }}, cmdline) + end) - feed('') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq({{{}, 'sin'}}, content) - eq(true, shown) - eq(2, pos) - end) + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "sin" } }, + firstc = ":", + indent = 0, + pos = 2, + prompt = "" + }}, cmdline) + end) - feed('') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq(false, shown) - end) + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({}, cmdline) + end) + end) - feed(':call input("input", "default")') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq(true, shown) - eq("input", prompt) - eq({{{}, 'default'}}, content) - end) - feed('') + it("works with input()", function() + feed(':call input("input", "default")') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "default" } }, + firstc = "", + indent = 0, + pos = 7, + prompt = "input" + }}, cmdline) + end) + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({}, cmdline) + end) - feed(':') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq(1, level) - end) + end) - feed('=1+2') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq({{{}, '1+2'}}, content) - eq("\"", char) - eq(1, shift) - eq(2, level) - end) + it("works with special chars and nested cmdline", function() + feed(':xx') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "xx" } }, + firstc = ":", + indent = 0, + pos = 2, + prompt = "", + special = {'"', true}, + }}, cmdline) + end) - feed('') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq({{{}, '3'}}, content) - eq(2, current_hide_level) - eq(1, level) - end) + feed('=') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "xx" } }, + firstc = ":", + indent = 0, + pos = 2, + prompt = "", + special = {'"', true}, + },{ + content = { { {}, "" } }, + firstc = "=", + indent = 0, + pos = 0, + prompt = "", + }}, cmdline) + end) - feed('') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq(1, current_hide_level) - end) + feed('1+2') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "xx" } }, + firstc = ":", + indent = 0, + pos = 2, + prompt = "", + special = {'"', true}, + },{ + content = { { {}, "1+2" } }, + firstc = "=", + indent = 0, + pos = 3, + prompt = "", + }}, cmdline) + end) - feed(':function Foo()') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq(true, in_block) - eq(2, indent) - end) + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "xx3" } }, + firstc = ":", + indent = 0, + pos = 3, + prompt = "", + }}, cmdline) + end) - feed('line1') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq(true, in_block) - eq(2, indent) - end) + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({}, cmdline) + end) + end) - feed('endfunction') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq(false, in_block) - end) + it("works with function definitions", function() + feed(':function Foo()') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "" } }, + firstc = ":", + indent = 2, + pos = 0, + prompt = "", + }}, cmdline) + eq({{{{}, 'function Foo()'}}}, block) + end) - feed(':sign') - screen:expect([[ - | - [No Name] | - :sign^ | - [Command Line] | - | - ]], nil, nil, function() - eq(false, in_block) - end) + feed('line1') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{{{}, 'function Foo()'}}, + {{{}, ' line1'}}}, block) + end) + feed('endfunction') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(nil, block) end) end) + pending("works with cmdline window", function() + feed(':sign') + screen:expect([[ + | + [No Name] | + :sign^ | + [Command Line] | + | + ]], nil, nil, function() + eq({}, cmdline) + end) + + feed(":blargh") + end) + it('works with highlighted cmdline', function() source([[ highlight RBP1 guibg=Red @@ -274,7 +372,7 @@ describe('External command line completion', function() {EOB:~ }| | ]], nil, nil, function() - expect_cmdline('{RBP1:(}a{RBP2:(}b{RBP2:)}a{RBP1:)}') + expect_cmdline(1, '{RBP1:(}a{RBP2:(}b{RBP2:)}a{RBP1:)}') end) end) end) -- cgit From 2050e6604632e190a04d52829f4469f1ef7f7018 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 20 Aug 2017 16:30:09 +0200 Subject: ext_cmdline: turn nested cmdlines into a linked list --- src/nvim/ex_getln.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index b9cf7b977c..2ac9ecdc2b 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -92,6 +92,7 @@ struct cmdline_info { unsigned prompt_id; ///< Prompt number, used to disable coloring on errors. Callback highlight_callback; ///< Callback used for coloring user input. int level; // current cmdline level + struct cmdline_info *prev_ccline; ///< pointer to saved cmdline state }; /// Last value of prompt_id, incremented when doing new prompt static unsigned last_prompt_id = 0; @@ -2958,9 +2959,6 @@ void put_on_cmdline(char_u *str, int len, int redraw) msg_check(); } -static struct cmdline_info prev_ccline; -static int prev_ccline_used = FALSE; - /* * Save ccline, because obtaining the "=" register may execute "normal :cmd" * and overwrite it. But get_cmdline_str() may need it, thus make it @@ -2968,12 +2966,8 @@ static int prev_ccline_used = FALSE; */ static void save_cmdline(struct cmdline_info *ccp) { - if (!prev_ccline_used) { - memset(&prev_ccline, 0, sizeof(struct cmdline_info)); - prev_ccline_used = TRUE; - } - *ccp = prev_ccline; - prev_ccline = ccline; + *ccp = ccline; + ccline.prev_ccline = ccp; ccline.cmdbuff = NULL; ccline.cmdprompt = NULL; ccline.xpc = NULL; @@ -2984,8 +2978,7 @@ static void save_cmdline(struct cmdline_info *ccp) */ static void restore_cmdline(struct cmdline_info *ccp) { - ccline = prev_ccline; - prev_ccline = *ccp; + ccline = *ccp; } /* @@ -5312,13 +5305,15 @@ int get_history_idx(int histype) */ static struct cmdline_info *get_ccline_ptr(void) { - if ((State & CMDLINE) == 0) + if ((State & CMDLINE) == 0) { return NULL; - if (ccline.cmdbuff != NULL) + } else if (ccline.cmdbuff != NULL) { return &ccline; - if (prev_ccline_used && prev_ccline.cmdbuff != NULL) - return &prev_ccline; - return NULL; + } else if (ccline.prev_ccline && ccline.prev_ccline->cmdbuff != NULL) { + return ccline.prev_ccline; + } else { + return NULL; + } } /* -- cgit From bed0a3a8428027af32602ccb169e81767c55e257 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 20 Aug 2017 17:47:42 +0200 Subject: ext_cmdline: implement redraw! --- src/nvim/ex_getln.c | 166 +++++++++++++++++++++--------------- src/nvim/screen.c | 5 +- test/functional/ui/cmdline_spec.lua | 54 +++++++++--- 3 files changed, 145 insertions(+), 80 deletions(-) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 2ac9ecdc2b..933aea7b93 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -67,6 +67,30 @@ #include "nvim/api/private/helpers.h" #include "nvim/highlight_defs.h" +/// Command-line colors: one chunk +/// +/// Defines a region which has the same highlighting. +typedef struct { + int start; ///< Colored chunk start. + int end; ///< Colored chunk end (exclusive, > start). + int attr; ///< Highlight attr. +} CmdlineColorChunk; + +/// Command-line colors +/// +/// Holds data about all colors. +typedef kvec_t(CmdlineColorChunk) CmdlineColors; + +/// Command-line coloring +/// +/// Holds both what are the colors and what have been colored. Latter is used to +/// suppress unnecessary calls to coloring callbacks. +typedef struct { + unsigned prompt_id; ///< ID of the prompt which was colored last. + char *cmdbuff; ///< What exactly was colored last time or NULL. + CmdlineColors colors; ///< Last colors. +} ColoredCmdline; + /* * Variables shared between getcmdline(), redrawcmdline() and others. * These need to be saved when using CTRL-R |, that's why they are in a @@ -91,8 +115,11 @@ struct cmdline_info { int input_fn; // when TRUE Invoked for input() function unsigned prompt_id; ///< Prompt number, used to disable coloring on errors. Callback highlight_callback; ///< Callback used for coloring user input. + ColoredCmdline last_colors; ///< Last cmdline colors int level; // current cmdline level struct cmdline_info *prev_ccline; ///< pointer to saved cmdline state + char special_char; ///< last putcmdline char (used for redraws) + bool special_shift; ///< shift of last putcmdline char }; /// Last value of prompt_id, incremented when doing new prompt static unsigned last_prompt_id = 0; @@ -145,36 +172,6 @@ typedef struct command_line_state { struct cmdline_info save_ccline; } CommandLineState; -/// Command-line colors: one chunk -/// -/// Defines a region which has the same highlighting. -typedef struct { - int start; ///< Colored chunk start. - int end; ///< Colored chunk end (exclusive, > start). - int attr; ///< Highlight attr. -} CmdlineColorChunk; - -/// Command-line colors -/// -/// Holds data about all colors. -typedef kvec_t(CmdlineColorChunk) CmdlineColors; - -/// Command-line coloring -/// -/// Holds both what are the colors and what have been colored. Latter is used to -/// suppress unnecessary calls to coloring callbacks. -typedef struct { - unsigned prompt_id; ///< ID of the prompt which was colored last. - char *cmdbuff; ///< What exactly was colored last time or NULL. - CmdlineColors colors; ///< Last colors. -} ColoredCmdline; - -/// Last command-line colors. -ColoredCmdline last_ccline_colors = { - .cmdbuff = NULL, - .colors = KV_INITIAL_VALUE -}; - typedef struct cmdline_info CmdlineInfo; /* The current cmdline_info. It is initialized in getcmdline() and after that @@ -242,7 +239,6 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) cmd_hkmap = 0; } - // TODO(bfredl): can these be combined? ccline.prompt_id = last_prompt_id++; ccline.level++; ccline.overstrike = false; // always start in insert mode @@ -264,6 +260,9 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) ccline.cmdlen = ccline.cmdpos = 0; ccline.cmdbuff[0] = NUL; + ccline.last_colors = (ColoredCmdline){ .cmdbuff = NULL, + .colors = KV_INITIAL_VALUE }; + // autoindent for :insert and :append if (s->firstc <= 0) { memset(ccline.cmdbuff, ' ', s->indent); @@ -414,6 +413,8 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) setmouse(); ui_cursor_shape(); // may show different cursor shape xfree(s->save_p_icm); + xfree(ccline.last_colors.cmdbuff); + kv_destroy(ccline.last_colors.colors); { char_u *p = ccline.cmdbuff; @@ -2364,8 +2365,7 @@ enum { MAX_CB_ERRORS = 1 }; /// Should use built-in command parser or user-specified one. Currently only the /// latter is supported. /// -/// @param[in] colored_ccline Command-line to color. -/// @param[out] ret_ccline_colors What should be colored. Also holds a cache: +/// @param[in,out] colored_ccline Command-line to color. Also holds a cache: /// if ->prompt_id and ->cmdbuff values happen /// to be equal to those from colored_cmdline it /// will just do nothing, assuming that ->colors @@ -2375,8 +2375,7 @@ enum { MAX_CB_ERRORS = 1 }; /// /// @return true if draw_cmdline may proceed, false if it does not need anything /// to do. -static bool color_cmdline(const CmdlineInfo *const colored_ccline, - ColoredCmdline *const ret_ccline_colors) +static bool color_cmdline(CmdlineInfo *colored_ccline) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { bool printed_errmsg = false; @@ -2389,19 +2388,21 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline, } while (0) bool ret = true; + ColoredCmdline *ccline_colors = &colored_ccline->last_colors; + // Check whether result of the previous call is still valid. - if (ret_ccline_colors->prompt_id == colored_ccline->prompt_id - && ret_ccline_colors->cmdbuff != NULL - && STRCMP(ret_ccline_colors->cmdbuff, colored_ccline->cmdbuff) == 0) { + if (ccline_colors->prompt_id == colored_ccline->prompt_id + && ccline_colors->cmdbuff != NULL + && STRCMP(ccline_colors->cmdbuff, colored_ccline->cmdbuff) == 0) { return ret; } - kv_size(ret_ccline_colors->colors) = 0; + kv_size(ccline_colors->colors) = 0; if (colored_ccline->cmdbuff == NULL || *colored_ccline->cmdbuff == NUL) { // Nothing to do, exiting. - xfree(ret_ccline_colors->cmdbuff); - ret_ccline_colors->cmdbuff = NULL; + xfree(ccline_colors->cmdbuff); + ccline_colors->cmdbuff = NULL; return ret; } @@ -2523,7 +2524,7 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline, goto color_cmdline_error; } if (start != prev_end) { - kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) { + kv_push(ccline_colors->colors, ((CmdlineColorChunk) { .start = prev_end, .end = start, .attr = 0, @@ -2552,14 +2553,14 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline, } const int id = syn_name2id((char_u *)group); const int attr = (id == 0 ? 0 : syn_id2attr(id)); - kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) { + kv_push(ccline_colors->colors, ((CmdlineColorChunk) { .start = start, .end = end, .attr = attr, })); } if (prev_end < colored_ccline->cmdlen) { - kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) { + kv_push(ccline_colors->colors, ((CmdlineColorChunk) { .start = prev_end, .end = colored_ccline->cmdlen, .attr = 0, @@ -2571,14 +2572,14 @@ color_cmdline_end: if (can_free_cb) { callback_free(&color_cb); } - xfree(ret_ccline_colors->cmdbuff); + xfree(ccline_colors->cmdbuff); // Note: errors “output” is cached just as well as regular results. - ret_ccline_colors->prompt_id = colored_ccline->prompt_id; + ccline_colors->prompt_id = colored_ccline->prompt_id; if (arg_allocated) { - ret_ccline_colors->cmdbuff = (char *)arg.vval.v_string; + ccline_colors->cmdbuff = (char *)arg.vval.v_string; } else { - ret_ccline_colors->cmdbuff = xmemdupz((const char *)colored_ccline->cmdbuff, - (size_t)colored_ccline->cmdlen); + ccline_colors->cmdbuff = xmemdupz((const char *)colored_ccline->cmdbuff, + (size_t)colored_ccline->cmdlen); } tv_clear(&tv); return ret; @@ -2591,7 +2592,7 @@ color_cmdline_error: (void)printed_errmsg; prev_prompt_errors++; - kv_size(ret_ccline_colors->colors) = 0; + kv_size(ccline_colors->colors) = 0; redrawcmdline(); ret = false; goto color_cmdline_end; @@ -2604,12 +2605,13 @@ color_cmdline_error: */ static void draw_cmdline(int start, int len) { - if (!color_cmdline(&ccline, &last_ccline_colors)) { + if (!color_cmdline(&ccline)) { return; } if (ui_is_external(kUICmdline)) { - ui_ext_cmdline_show(); + ccline.special_char = NUL; + ui_ext_cmdline_show(&ccline); return; } @@ -2711,9 +2713,9 @@ static void draw_cmdline(int start, int len) msg_outtrans_len(arshape_buf, newlen); } else { draw_cmdline_no_arabicshape: - if (kv_size(last_ccline_colors.colors)) { - for (size_t i = 0; i < kv_size(last_ccline_colors.colors); i++) { - CmdlineColorChunk chunk = kv_A(last_ccline_colors.colors, i); + if (kv_size(ccline.last_colors.colors)) { + for (size_t i = 0; i < kv_size(ccline.last_colors.colors); i++) { + CmdlineColorChunk chunk = kv_A(ccline.last_colors.colors, i); if (chunk.end <= start) { continue; } @@ -2728,12 +2730,12 @@ draw_cmdline_no_arabicshape: } } -void ui_ext_cmdline_show(void) +static void ui_ext_cmdline_show(CmdlineInfo *line) { Array content = ARRAY_DICT_INIT; - if (kv_size(last_ccline_colors.colors)) { - for (size_t i = 0; i < kv_size(last_ccline_colors.colors); i++) { - CmdlineColorChunk chunk = kv_A(last_ccline_colors.colors, i); + if (kv_size(line->last_colors.colors)) { + for (size_t i = 0; i < kv_size(line->last_colors.colors); i++) { + CmdlineColorChunk chunk = kv_A(line->last_colors.colors, i); Array item = ARRAY_DICT_INIT; if (chunk.attr) { @@ -2745,21 +2747,26 @@ void ui_ext_cmdline_show(void) } else { ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); } - ADD(item, STRING_OBJ(cbuf_to_string((char *)ccline.cmdbuff + chunk.start, + ADD(item, STRING_OBJ(cbuf_to_string((char *)line->cmdbuff + chunk.start, chunk.end-chunk.start))); ADD(content, ARRAY_OBJ(item)); } } else { Array item = ARRAY_DICT_INIT; ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); - ADD(item, STRING_OBJ(cstr_to_string((char *)(ccline.cmdbuff)))); + ADD(item, STRING_OBJ(cstr_to_string((char *)(line->cmdbuff)))); ADD(content, ARRAY_OBJ(item)); } - ui_call_cmdline_show(content, ccline.cmdpos, - cchar_to_string((char)ccline.cmdfirstc), - cstr_to_string((char *)(ccline.cmdprompt)), - ccline.cmdindent, - ccline.level); + ui_call_cmdline_show(content, line->cmdpos, + cchar_to_string((char)line->cmdfirstc), + cstr_to_string((char *)(line->cmdprompt)), + line->cmdindent, + line->level); + if (line->special_char) { + ui_call_cmdline_special_char(cchar_to_string((char)(line->special_char)), + line->special_shift, + line->level); + } } void ui_ext_cmdline_block_append(int indent, const char *line) @@ -2787,6 +2794,28 @@ void ui_ext_cmdline_block_leave(void) ui_call_cmdline_block_hide(); } +/// Extra redrawing needed for redraw! and on ui_attach +/// assumes "redrawcmdline()" will already be invoked +void cmdline_screen_cleared(void) +{ + if (!ui_is_external(kUICmdline)) { + return; + } + + if (cmdline_block.size) { + ui_call_cmdline_block_show(copy_array(cmdline_block)); + } + + int prev_level = ccline.level-1; + CmdlineInfo *prev_ccline = ccline.prev_ccline; + while (prev_level > 0 && prev_ccline) { + if (prev_ccline->level == prev_level) { + ui_ext_cmdline_show(prev_ccline); + prev_level--; + } + prev_ccline = prev_ccline->prev_ccline; + } +} /* * Put a character on the command line. Shifts the following text to the @@ -2806,6 +2835,8 @@ void putcmdline(int c, int shift) } msg_no_more = false; } else { + ccline.special_char = c; + ccline.special_shift = shift; ui_call_cmdline_special_char(cchar_to_string((char)(c)), shift, ccline.level); } @@ -2971,6 +3002,7 @@ static void save_cmdline(struct cmdline_info *ccp) ccline.cmdbuff = NULL; ccline.cmdprompt = NULL; ccline.xpc = NULL; + ccline.special_char = NUL; } /* @@ -3147,7 +3179,7 @@ static void redrawcmdprompt(void) if (cmd_silent) return; if (ui_is_external(kUICmdline)) { - ui_ext_cmdline_show(); + ui_ext_cmdline_show(&ccline); return; } if (ccline.cmdfirstc != NUL) { diff --git a/src/nvim/screen.c b/src/nvim/screen.c index f5730cf70a..0f47103a84 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -345,8 +345,9 @@ void update_screen(int type) if (need_highlight_changed) highlight_changed(); - if (type == CLEAR) { /* first clear screen */ - screenclear(); /* will reset clear_cmdline */ + if (type == CLEAR) { // first clear screen + screenclear(); // will reset clear_cmdline + cmdline_screen_cleared(); // clear external cmdline state type = NOT_VALID; } diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 3f9ce8ad67..e4d625df8e 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen') local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq local source = helpers.source local ok = helpers.ok +local command = helpers.command if helpers.pending_win32(pending) then return end @@ -218,14 +219,7 @@ describe('external cmdline', function() end) feed('1+2') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]], nil, nil, function() - eq({{ + local expectation = {{ content = { { {}, "xx" } }, firstc = ":", indent = 0, @@ -238,16 +232,40 @@ describe('external cmdline', function() indent = 0, pos = 3, prompt = "", - }}, cmdline) + }} + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq(expectation, cmdline) end) - feed('') + -- erase information, so we check if it is retransmitted + cmdline = {} + command("redraw!") + -- redraw! forgets cursor position. Be OK with that, as UI should indicate + -- focus is at external cmdline anyway. screen:expect([[ - ^ | + | ~ | ~ | ~ | + ^ | + ]], nil, nil, function() + eq(expectation, cmdline) + end) + + + feed('') + screen:expect([[ | + ~ | + ~ | + ~ | + ^ | ]], nil, nil, function() eq({{ content = { { {}, "xx3" } }, @@ -301,6 +319,20 @@ describe('external cmdline', function() {{{}, ' line1'}}}, block) end) + block = {} + command("redraw!") + screen:expect([[ + | + ~ | + ~ | + ~ | + ^ | + ]], nil, nil, function() + eq({{{{}, 'function Foo()'}}, + {{{}, ' line1'}}}, block) + end) + + feed('endfunction') screen:expect([[ ^ | -- cgit From 91d8e26bc7471378b8005b8843182dc1af90d81a Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 27 Aug 2017 09:57:30 +0200 Subject: ext_cmdline: interact with cmdline window --- src/nvim/ex_getln.c | 10 +++- src/nvim/globals.h | 7 ++- test/functional/ui/cmdline_spec.lua | 107 ++++++++++++++++++++++++++++++++++-- 3 files changed, 115 insertions(+), 9 deletions(-) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 933aea7b93..bcc8d598db 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2810,7 +2810,10 @@ void cmdline_screen_cleared(void) CmdlineInfo *prev_ccline = ccline.prev_ccline; while (prev_level > 0 && prev_ccline) { if (prev_ccline->level == prev_level) { - ui_ext_cmdline_show(prev_ccline); + // don't redraw a cmdline already shown in the cmdline window + if (prev_level != cmdwin_level) { + ui_ext_cmdline_show(prev_ccline); + } prev_level--; } prev_ccline = prev_ccline->prev_ccline; @@ -5781,6 +5784,7 @@ static int ex_window(void) return K_IGNORE; } cmdwin_type = get_cmdline_type(); + cmdwin_level = ccline.level; // Create empty command-line buffer. buf_open_scratch(0, "[Command Line]"); @@ -5833,6 +5837,9 @@ static int ex_window(void) curwin->w_cursor.col = ccline.cmdpos; changed_line_abv_curs(); invalidate_botline(); + if (ui_is_external(kUICmdline)) { + ui_call_cmdline_hide(ccline.level); + } redraw_later(SOME_VALID); // Save the command line info, can be used recursively. @@ -5875,6 +5882,7 @@ static int ex_window(void) // Restore the command line info. restore_cmdline(&save_ccline); cmdwin_type = 0; + cmdwin_level = 0; exmode_active = save_exmode; diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 300e506854..f24286360a 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -981,9 +981,10 @@ EXTERN int fill_diff INIT(= '-'); EXTERN int km_stopsel INIT(= FALSE); EXTERN int km_startsel INIT(= FALSE); -EXTERN int cedit_key INIT(= -1); /* key value of 'cedit' option */ -EXTERN int cmdwin_type INIT(= 0); /* type of cmdline window or 0 */ -EXTERN int cmdwin_result INIT(= 0); /* result of cmdline window or 0 */ +EXTERN int cedit_key INIT(= -1); ///< key value of 'cedit' option +EXTERN int cmdwin_type INIT(= 0); ///< type of cmdline window or 0 +EXTERN int cmdwin_result INIT(= 0); ///< result of cmdline window or 0 +EXTERN int cmdwin_level INIT(= 0); ///< cmdline level of cmdline window or 0 EXTERN char_u no_lines_msg[] INIT(= N_("--No lines in buffer--")); diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index e4d625df8e..b886596e00 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -232,7 +232,7 @@ describe('external cmdline', function() indent = 0, pos = 3, prompt = "", - }} + }} screen:expect([[ ^ | ~ | @@ -345,19 +345,116 @@ describe('external cmdline', function() end) end) - pending("works with cmdline window", function() - feed(':sign') + it("works with cmdline window", function() + feed(':make') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "make" } }, + firstc = ":", + indent = 0, + pos = 4, + prompt = "" + }}, cmdline) + end) + + feed('') + screen:expect([[ + | + [No Name] | + :make^ | + [Command Line] | + | + ]], nil, nil, function() + eq({}, cmdline) + end) + + -- nested cmdline + feed(':yank') + screen:expect([[ + | + [No Name] | + :make^ | + [Command Line] | + | + ]], nil, nil, function() + eq({nil, { + content = { { {}, "yank" } }, + firstc = ":", + indent = 0, + pos = 4, + prompt = "" + }}, cmdline) + end) + + cmdline = {} + command("redraw!") + screen:expect([[ + | + [No Name] | + :make | + [Command Line] | + ^ | + ]], nil, nil, function() + eq({nil, { + content = { { {}, "yank" } }, + firstc = ":", + indent = 0, + pos = 4, + prompt = "" + }}, cmdline) + end) + + feed("") screen:expect([[ | [No Name] | - :sign^ | + :make^ | [Command Line] | | ]], nil, nil, function() eq({}, cmdline) end) - feed(":blargh") + feed("") + screen:expect([[ + | + [No Name] | + :make^ | + [Command Line] | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "make" } }, + firstc = ":", + indent = 0, + pos = 4, + prompt = "" + }}, cmdline) + end) + + cmdline = {} + command("redraw!") + screen:expect([[ + | + ~ | + ~ | + ~ | + ^ | + ]], nil, nil, function() + eq({{ + content = { { {}, "make" } }, + firstc = ":", + indent = 0, + pos = 4, + prompt = "" + }}, cmdline) + end) end) it('works with highlighted cmdline', function() -- cgit From 445f25998c66ee7e4dc5bbfeed4108818e439b92 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 30 Aug 2017 08:51:39 +0200 Subject: ext_cmdline: fix inputsecret() --- src/nvim/ex_getln.c | 13 ++++++++++++- test/functional/ui/cmdline_spec.lua | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index bcc8d598db..e79476ab53 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2733,7 +2733,18 @@ draw_cmdline_no_arabicshape: static void ui_ext_cmdline_show(CmdlineInfo *line) { Array content = ARRAY_DICT_INIT; - if (kv_size(line->last_colors.colors)) { + if (cmdline_star) { + size_t len = 0; + for (char_u *p = ccline.cmdbuff; *p; mb_ptr_adv(p)) { + len++; + } + char *buf = xmallocz(len); + memset(buf, '*', len); + Array item = ARRAY_DICT_INIT; + ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); + ADD(item, STRING_OBJ(((String) { .data = buf, .size = len }))); + ADD(content, ARRAY_OBJ(item)); + } else if (kv_size(line->last_colors.colors)) { for (size_t i = 0; i < kv_size(line->last_colors.colors); i++) { CmdlineColorChunk chunk = kv_A(line->last_colors.colors, i); Array item = ARRAY_DICT_INIT; diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index b886596e00..6a9f4a22b4 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -15,6 +15,7 @@ describe('external cmdline', function() before_each(function() clear() + cmdline, block = {}, nil screen = Screen.new(25, 5) screen:attach({rgb=true, ext_cmdline=true}) screen:set_on_event_handler(function(name, data) @@ -457,6 +458,25 @@ describe('external cmdline', function() end) end) + it('works with inputsecret()', function() + feed(":call inputsecret('secret:')abc123") + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]], nil, nil, function() + eq({{ + content = { { {}, "******" } }, + firstc = "", + indent = 0, + pos = 6, + prompt = "secret:" + }}, cmdline) + end) + end) + it('works with highlighted cmdline', function() source([[ highlight RBP1 guibg=Red -- cgit From f640ae0d6e788bb3ca06508d216a397c1ff190d5 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 10 Sep 2017 10:01:18 +0200 Subject: docs: breakout ui.txt from msgpack_rpc.txt --- runtime/doc/api.txt | 2 +- runtime/doc/msgpack_rpc.txt | 255 --------------------------------------- runtime/doc/ui.txt | 284 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 285 insertions(+), 256 deletions(-) create mode 100644 runtime/doc/ui.txt diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 8aead087db..159dd93c5e 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -48,7 +48,7 @@ version.api_compatible API is backwards-compatible with this level version.api_prerelease Declares the current API level as unstable > (version.api_prerelease && fn.since == version.api_level) functions API function signatures -ui_events UI event signatures |rpc-remote-ui| +ui_events UI event signatures |ui| {fn}.since API level where function {fn} was introduced {fn}.deprecated_since API level where function {fn} was deprecated types Custom handle types defined by Nvim diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index 9601e239f2..7af6e401da 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -243,259 +243,4 @@ Even for statically compiled clients it is good practice to avoid hardcoding the type codes, because a client may be built against one Nvim version but connect to another with different type codes. -============================================================================== -6. Remote UIs *rpc-remote-ui* - -GUIs can be implemented as external processes communicating with Nvim over the -RPC API. The UI model consists of a terminal-like grid with a single, -monospace font size. Some elements (UI "widgets") can be drawn separately from -the grid ("externalized"). - -After connecting to Nvim (usually a spawned, embedded instance) use the -|nvim_ui_attach| API method to tell Nvim that your program wants to draw the -Nvim screen on a grid of width × height cells. `options` must be -a dictionary with these (optional) keys: - `rgb` Controls what color format to use. - Set to true (default) to use 24-bit rgb - colors. - Set to false to use terminal color codes (at - most 256 different colors). - `ext_popupmenu` Externalize the popupmenu. |ui-ext-popupmenu| - `ext_tabline` Externalize the tabline. |ui-ext-tabline| - `ext_cmdline` Externalize the cmdline. |ui-ext-cmdline| - Externalized widgets will not be drawn by - Nvim; only high-level data will be published - in new UI event kinds. - -Nvim will then send msgpack-rpc notifications, with the method name "redraw" -and a single argument, an array of screen updates (described below). These -should be processed in order. Preferably the user should only be able to see -the screen state after all updates in the same "redraw" event are processed -(not any intermediate state after processing only a part of the array). - -Future versions of Nvim may add new update kinds and may append new parameters -to existing update kinds. Clients must be prepared to ignore such extensions -to be forward-compatible. |api-contract| - -Screen updates are tuples whose first element is the string name of the update -kind. - -["resize", width, height] - The grid is resized to `width` and `height` cells. - -["clear"] - Clear the screen. - -["eol_clear"] - Clear from the cursor position to the end of the current line. - -["cursor_goto", row, col] - Move the cursor to position (row, col). Currently, the same cursor is - used to define the position for text insertion and the visible cursor. - However, only the last cursor position, after processing the entire - array in the "redraw" event, is intended to be a visible cursor - position. - -["update_fg", color] -["update_bg", color] -["update_sp", color] - Set the default foreground, background and special colors - respectively. - - - *ui-event-highlight_set* -["highlight_set", attrs] - Set the attributes that the next text put on the screen will have. - `attrs` is a dict with the keys below. Any absent key is reset - to its default value. Color defaults are set by the `update_fg` etc - updates. All boolean keys default to false. - - `foreground`: foreground color. - `background`: backround color. - `special`: color to use for underline and undercurl, when present. - `reverse`: reverse video. Foreground and background colors are - switched. - `italic`: italic text. - `bold`: bold text. - `underline`: underlined text. The line has `special` color. - `undercurl`: undercurled text. The curl has `special` color. - -["put", text] - The (utf-8 encoded) string `text` is put at the cursor position - (and the cursor is advanced), with the highlights as set by the - last `highlight_set` update. - -["set_scroll_region", top, bot, left, right] - Define the scroll region used by `scroll` below. - -["scroll", count] - Scroll the text in the scroll region. The diagrams below illustrate - what will happen, depending on the scroll direction. "=" is used to - represent the SR(scroll region) boundaries and "-" the moved rectangles. - Note that dst and src share a common region. - - If count is bigger than 0, move a rectangle in the SR up, this can - happen while scrolling down. -> - +-------------------------+ - | (clipped above SR) | ^ - |=========================| dst_top | - | dst (still in SR) | | - +-------------------------+ src_top | - | src (moved up) and dst | | - |-------------------------| dst_bot | - | src (cleared) | | - +=========================+ src_bot -< - If count is less than zero, move a rectangle in the SR down, this can - happen while scrolling up. -> - +=========================+ src_top - | src (cleared) | | - |------------------------ | dst_top | - | src (moved down) and dst| | - +-------------------------+ src_bot | - | dst (still in SR) | | - |=========================| dst_bot | - | (clipped below SR) | v - +-------------------------+ -< -["set_title", title] -["set_icon", icon] - Set the window title, and icon (minimized) window title, respectively. - In windowing systems not distinguishing between the two, "set_icon" - can be ignored. - -["mouse_on"] -["mouse_off"] - Tells the client whether mouse support, as determined by |'mouse'| - option, is considered to be active in the current mode. This is mostly - useful for a terminal frontend, or other situations where nvim mouse - would conflict with other usages of the mouse. It is safe for a client - to ignore this and always send mouse events. - -["busy_on"] -["busy_off"] - Nvim started or stopped being busy, and possibly not responsible to user - input. This could be indicated to the user by hiding the cursor. - -["suspend"] - |:suspend| command or |Ctrl-Z| mapping is used. A terminal client (or other - client where it makes sense) could suspend itself. Other clients can - safely ignore it. - -["bell"] -["visual_bell"] - Notify the user with an audible or visual bell, respectively. - -["update_menu"] - The menu mappings changed. - -["mode_info_set", cursor_style_enabled, mode_info] -`cursor_style_enabled` is a boolean indicating if the UI should set the cursor -style. `mode_info` is a list of mode property maps. The current mode is given -by the `mode_idx` field of the `mode_change` event. - -Each mode property map may contain these keys: - KEY DESCRIPTION ~ - `cursor_shape`: "block", "horizontal", "vertical" - `cell_percentage`: Cell % occupied by the cursor. - `blinkwait`, `blinkon`, `blinkoff`: See |cursor-blinking|. - `hl_id`: Cursor highlight group. - `hl_lm`: Cursor highlight group if 'langmap' is active. - `short_name`: Mode code name, see 'guicursor'. - `name`: Mode descriptive name. - `mouse_shape`: (To be implemented.) - -Some keys are missing in some modes. - -["mode_change", mode, mode_idx] -The mode changed. The first parameter `mode` is a string representing the -current mode. `mode_idx` is an index into the array received in the -`mode_info_set` event. UIs should change the cursor style according to the -properties specified in the corresponding item. The set of modes reported will -change in new versions of Nvim, for instance more submodes and temporary -states might be represented as separate modes. - - *ui-ext-popupmenu* -["popupmenu_show", items, selected, row, col] - When `popupmenu_external` is set to true, nvim will not draw the - popupmenu on the grid, instead when the popupmenu is to be displayed - this update is sent. `items` is an array of the items to show, the - items are themselves arrays of the form [word, kind, menu, info] - as defined at |complete-items|, except that `word` is replaced by - `abbr` if present. `selected` is the initially selected item, either a - zero-based index into the array of items, or -1 if no item is - selected. `row` and `col` is the anchor position, where the first - character of the completed word will be. - -["popupmenu_select", selected] - An item in the currently displayed popupmenu is selected. `selected` - is either a zero-based index into the array of items from the last - `popupmenu_show` event, or -1 if no item is selected. - -["popupmenu_hide"] - The popupmenu is hidden. - - *ui-ext-tabline* -["tabline_update", curtab, tabs] - Tabline was updated. UIs should present this data in a custom tabline - widget. - curtab: Current Tabpage - tabs: List of Dicts [{ "tab": Tabpage, "name": String }, ...] - - *ui-ext-cmdline* -["cmdline_show", content, pos, firstc, prompt, indent, level] - content: List of [attrs, string] - [[{}, "t"], [attrs, "est"], ...] - When cmdline_external is set to true, nvim will not draw the cmdline - on the grid, instead nvim will send ui events of the cmdline content - and cursor position to the remote ui. The `content` is the full content - that should be displayed in the cmdline, and the `pos` is the position - of the cursor that in the cmdline. This event will be triggered when - you type in the cmdline. The content is divided into chunks with - different highlight attributes represented as a dict, see - |ui-event-highlight_set|. - - `firstc` and `prompt` are text, that if non-empty should be - displayed in front of the command line. `firstc` always indicates - built in command lines such as `:` (ex command) and `/` `?` (search), - while `prompt` is an |input()| prompt. `indent` tells how many spaces - the content should be indented - - The command line in nvim can be invoked recursively, for instance by - typing `=` at the command line prompt. The `level` field is used - to distinguish different command lines active at the same time. The - first invoked command line will always have level 1, and the next - recursively invoked prompt will have level 2. Also, a command line - invoked while in command line window will have a higher level than - than the edited command line. - -["cmdline_pos", pos, level] - Change the cursor position in the cmdline. - -["cmdline_special_char", c, shift, level] - Display a special char in the cmdline at the cursor position. This is - typically used to indicate a pending state, like right after Ctrl-V. - if shift is true the text after the cursor should be shifted, - otherwise it should overshadow the char at the cursor. - Should be hidden at next cmdline_char - - -["cmdline_hide"] - Hide the cmdline. - -["cmdline_block_show", lines] - Show a block of context to the current command line. This occurs for - instance if a function is interactively defined at the command line. - `lines` is a list of lines where each line is represented as a list of - highlighted chunks, just like `contents` of |ui-event-cmdline_show|. - -["cmdline_block_append", line] - Append a line at the end of the currently shown block. - -["cmdline_block_hide"] - Hide the block. -============================================================================== - vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt new file mode 100644 index 0000000000..b875c1b183 --- /dev/null +++ b/runtime/doc/ui.txt @@ -0,0 +1,284 @@ +*ui.txt* Nvim + + + NVIM REFERENCE MANUAL by Thiago de Arruda + + +UI protocol *ui* + + Type to see the table of contents. + +============================================================================== +Introduction *ui-intro* + +GUIs can be implemented as external processes communicating with Nvim over the +RPC API. The UI model consists of a terminal-like grid with a single, +monospace font size. Some elements (UI "widgets") can be drawn separately from +the grid ("externalized"). + + *ui-options* +After connecting to Nvim (usually a spawned, embedded instance) use the +|nvim_ui_attach| API method to tell Nvim that your program wants to draw the +Nvim screen grid with a size of width × height cells. `options` must be +a dictionary with these (optional) keys: + `rgb` Controls what color format to use. + Set to true (default) to use 24-bit rgb + colors. + Set to false to use terminal color codes (at + most 256 different colors). + `ext_popupmenu` Externalize the popupmenu. |ui-popupmenu| + `ext_tabline` Externalize the tabline. |ui-tabline| + `ext_cmdline` Externalize the cmdline. |ui-cmdline| + +Nvim will then send msgpack-rpc notifications, with the method name "redraw" +and a single argument, an array of screen update events. +Update events are tuples whose first element is the string name of the update +kind. The rest are parameters for each update, described in the sections below. +These should be processed in order. Preferably the user should only be able to +see the screen state after all update events in the same "redraw" event are +processed (not any intermediate state after processing only a part of the +array). + +Section 2 and 3 describes grid and mode events that are send unconditionally, +and suffice to implement a terminal-like interface. Nvim also allows a number +of screen elements to be sent as descriptive events for the GUI to draw +itself, rather than Nvim drawing itself on the grid. This is controlled by the +`ext_` options. + +Future versions of Nvim may add new update kinds and may append new parameters +to existing update kinds. Clients must be prepared to ignore such extensions +to be forward-compatible. |api-contract| + +============================================================================== +Global Events *ui-global* + +["set_title", title] +["set_icon", icon] + Set the window title, and icon (minimized) window title, respectively. + In windowing systems not distinguishing between the two, "set_icon" + can be ignored. + +["mode_info_set", cursor_style_enabled, mode_info] + `cursor_style_enabled` is a boolean indicating if the UI should set + the cursor style. `mode_info` is a list of mode property maps. The + current mode is given by the `mode_idx` field of the `mode_change` + event. + +Each mode property map may contain these keys: + KEY DESCRIPTION ~ + `cursor_shape`: "block", "horizontal", "vertical" + `cell_percentage`: Cell % occupied by the cursor. + `blinkwait`, `blinkon`, `blinkoff`: See |cursor-blinking|. + `hl_id`: Cursor highlight group. + `hl_lm`: Cursor highlight group if 'langmap' is active. + `short_name`: Mode code name, see 'guicursor'. + `name`: Mode descriptive name. + `mouse_shape`: (To be implemented.) + +Some keys are missing in some modes. + +["mode_change", mode, mode_idx] + The mode changed. The first parameter `mode` is a string representing + the current mode. `mode_idx` is an index into the array received in + the `mode_info_set` event. UIs should change the cursor style + according to the properties specified in the corresponding item. The + set of modes reported will change in new versions of Nvim, for + instance more submodes and temporary states might be represented as + separate modes. + + +["mouse_on"] +["mouse_off"] + Tells the client whether mouse support, as determined by |'mouse'| + option, is considered to be active in the current mode. This is mostly + useful for a terminal frontend, or other situations where nvim mouse + would conflict with other usages of the mouse. It is safe for a client + to ignore this and always send mouse events. + +["busy_on"] +["busy_off"] + Nvim started or stopped being busy, and possibly not responsible to user + input. This could be indicated to the user by hiding the cursor. + +["suspend"] + |:suspend| command or |Ctrl-Z| mapping is used. A terminal client (or other + client where it makes sense) could suspend itself. Other clients can + safely ignore it. + +["update_menu"] + The menu mappings changed. + +["bell"] +["visual_bell"] + Notify the user with an audible or visual bell, respectively. + +============================================================================== +Grid Events *ui-grid* + +["resize", width, height] + The grid is resized to `width` and `height` cells. + +["clear"] + Clear the grid. + +["eol_clear"] + Clear from the cursor position to the end of the current line. + +["cursor_goto", row, col] + Move the cursor to position (row, col). Currently, the same cursor is + used to define the position for text insertion and the visible cursor. + However, only the last cursor position, after processing the entire + array in the "redraw" event, is intended to be a visible cursor + position. + +["update_fg", color] +["update_bg", color] +["update_sp", color] + Set the default foreground, background and special colors + respectively. + + *ui-event-highlight_set* +["highlight_set", attrs] + Set the attributes that the next text put on the grid will have. + `attrs` is a dict with the keys below. Any absent key is reset + to its default value. Color defaults are set by the `update_fg` etc + updates. All boolean keys default to false. + + `foreground`: foreground color. + `background`: backround color. + `special`: color to use for underline and undercurl, when present. + `reverse`: reverse video. Foreground and background colors are + switched. + `italic`: italic text. + `bold`: bold text. + `underline`: underlined text. The line has `special` color. + `undercurl`: undercurled text. The curl has `special` color. + +["put", text] + The (utf-8 encoded) string `text` is put at the cursor position + (and the cursor is advanced), with the highlights as set by the + last `highlight_set` update. + +["set_scroll_region", top, bot, left, right] + Define the scroll region used by `scroll` below. + +["scroll", count] + Scroll the text in the scroll region. The diagrams below illustrate + what will happen, depending on the scroll direction. "=" is used to + represent the SR(scroll region) boundaries and "-" the moved rectangles. + Note that dst and src share a common region. + + If count is bigger than 0, move a rectangle in the SR up, this can + happen while scrolling down. +> + +-------------------------+ + | (clipped above SR) | ^ + |=========================| dst_top | + | dst (still in SR) | | + +-------------------------+ src_top | + | src (moved up) and dst | | + |-------------------------| dst_bot | + | src (cleared) | | + +=========================+ src_bot +< + If count is less than zero, move a rectangle in the SR down, this can + happen while scrolling up. +> + +=========================+ src_top + | src (cleared) | | + |------------------------ | dst_top | + | src (moved down) and dst| | + +-------------------------+ src_bot | + | dst (still in SR) | | + |=========================| dst_bot | + | (clipped below SR) | v + +-------------------------+ +< +============================================================================== +Popupmenu Events *ui-popupmenu* + +Only sent if `ext_popupmenu` option is set in |ui-options| + +["popupmenu_show", items, selected, row, col] + `items` is an array of the items to show, the + items are themselves arrays of the form [word, kind, menu, info] + as defined at |complete-items|, except that `word` is replaced by + `abbr` if present. `selected` is the initially selected item, either a + zero-based index into the array of items, or -1 if no item is + selected. `row` and `col` is the anchor position, where the first + character of the completed word will be. + +["popupmenu_select", selected] + An item in the currently displayed popupmenu is selected. `selected` + is either a zero-based index into the array of items from the last + `popupmenu_show` event, or -1 if no item is selected. + +["popupmenu_hide"] + The popupmenu is hidden. + +============================================================================== +Tabline Events *ui-tabline* + +Only sent if `ext_tabline` option is set in |ui-options| + +["tabline_update", curtab, tabs] + Tabline was updated. UIs should present this data in a custom tabline + widget. + curtab: Current Tabpage + tabs: List of Dicts [{ "tab": Tabpage, "name": String }, ...] + +============================================================================== +Cmdline Events *ui-cmdline* + +Only sent if `ext_cmdline` option is set in |ui-options| + +["cmdline_show", content, pos, firstc, prompt, indent, level] + content: List of [attrs, string] + [[{}, "t"], [attrs, "est"], ...] + The `content` is the full content that should be displayed in the + cmdline, and the `pos` is the position of the cursor that in the + cmdline. This event will be triggered when you type in the cmdline. + The content is divided into chunks with different highlight attributes + represented as a dict, see |ui-event-highlight_set|. + + `firstc` and `prompt` are text, that if non-empty should be + displayed in front of the command line. `firstc` always indicates + built in command lines such as `:` (ex command) and `/` `?` (search), + while `prompt` is an |input()| prompt. `indent` tells how many spaces + the content should be indented + + The command line in nvim can be invoked recursively, for instance by + typing `=` at the command line prompt. The `level` field is used + to distinguish different command lines active at the same time. The + first invoked command line will always have level 1, and the next + recursively invoked prompt will have level 2. Also, a command line + invoked while in command line window will have a higher level than + than the edited command line. + +["cmdline_pos", pos, level] + Change the cursor position in the cmdline. + +["cmdline_special_char", c, shift, level] + Display a special char in the cmdline at the cursor position. This is + typically used to indicate a pending state, like right after Ctrl-V. + if shift is true the text after the cursor should be shifted, + otherwise it should overshadow the char at the cursor. + Should be hidden at next cmdline_char + +["cmdline_hide"] + Hide the cmdline. + +["cmdline_block_show", lines] + Show a block of context to the current command line. This occurs for + instance if a function is interactively defined at the command line. + `lines` is a list of lines where each line is represented as a list of + highlighted chunks, just like `contents` of |ui-event-cmdline_show|. + +["cmdline_block_append", line] + Append a line at the end of the currently shown block. + +["cmdline_block_hide"] + Hide the block. + +============================================================================== + vim:tw=78:ts=8:noet:ft=help:norl: -- cgit From aab16e6939a45b3c08f21cd4b5f348e9e612d947 Mon Sep 17 00:00:00 2001 From: ckelsel Date: Fri, 27 Oct 2017 09:41:41 +0800 Subject: vim-patch:8.0.0189 Problem: There are no tests for the :profile command. Solution: Add tests. (Dominique Pelle, closes vim/vim#1383) https://github.com/vim/vim/commit/296b1f28ca9cedeb55872f306808b2214b519ce7 --- src/nvim/testdir/Makefile | 1 + src/nvim/testdir/test_profile.vim | 135 ++++++++++++++++++++++++++++++++++++++ src/nvim/version.c | 2 +- 3 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 src/nvim/testdir/test_profile.vim diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index 38caa8815d..fb68292c77 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -62,6 +62,7 @@ NEW_TESTS ?= \ test_mksession_utf8.res \ test_nested_function.res \ test_normal.res \ + test_profile.res \ test_quickfix.res \ test_search.res \ test_signs.res \ diff --git a/src/nvim/testdir/test_profile.vim b/src/nvim/testdir/test_profile.vim new file mode 100644 index 0000000000..36c05683d5 --- /dev/null +++ b/src/nvim/testdir/test_profile.vim @@ -0,0 +1,135 @@ +" Test Vim profiler +if !has('profile') + finish +endif + +func Test_profile_func() + if !has('unix') + return + endif + let lines = [ + \ "func! Foo1()", + \ "endfunc", + \ "func! Foo2()", + \ " let count = 100", + \ " while count > 0", + \ " let count = count - 1", + \ " endwhile", + \ "endfunc", + \ "func! Foo3()", + \ "endfunc", + \ "func! Bar()", + \ "endfunc", + \ "call Foo1()", + \ "call Foo1()", + \ "profile pause", + \ "call Foo1()", + \ "profile continue", + \ "call Foo2()", + \ "call Foo3()", + \ "call Bar()", + \ "if !v:profiling", + \ " delfunc Foo2", + \ "endif", + \ "delfunc Foo3", + \ ] + + call writefile(lines, 'Xprofile_func.vim') + let a = system(v:progpath + \ . " -u NONE -i NONE --noplugin" + \ . " -c 'profile start Xprofile_func.log'" + \ . " -c 'profile func Foo*'" + \ . " -c 'so Xprofile_func.vim'" + \ . " -c 'qall!'") + let lines = readfile('Xprofile_func.log') + + call assert_equal(28, len(lines)) + + call assert_equal('FUNCTION Foo1()', lines[0]) + call assert_equal('Called 2 times', lines[1]) + call assert_equal('FUNCTION Foo2()', lines[7]) + call assert_equal('Called 1 time', lines[8]) + + " - Foo1() is called 3 times but should be reported as called twice + " since one call is in between "profile pause" .. "profile continue". + " - Foo2() should come before Foo1() since Foo1() does much more work.\ + " - Foo3() is not reported because function is deleted. + " - Unlike Foo3(), Foo2() should not be deleted since there is a check + " for v:profiling. + " - Bar() is not reported since it does not match "profile func Foo*". + call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[18]) + call assert_equal('count total (s) self (s) function', lines[19]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[20]) + call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[21]) + call assert_equal('', lines[22]) + call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[23]) + call assert_equal('count total (s) self (s) function', lines[24]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[25]) + call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[26]) + call assert_equal('', lines[27]) + + call delete('Xprofile_func.vim') + call delete('Xprofile_func.log') +endfunc + +func Test_profile_file() + if !has('unix') + return + endif + let lines = [ + \ 'func! Foo()', + \ 'endfunc', + \ 'for i in range(10)', + \ ' " a comment', + \ ' call Foo()', + \ 'endfor', + \ 'call Foo()', + \ ] + + call writefile(lines, 'Xprofile_file.vim') + let a = system(v:progpath + \ . " -u NONE -i NONE --noplugin" + \ . " -c 'profile start Xprofile_file.log'" + \ . " -c 'profile file Xprofile_file.vim'" + \ . " -c 'so Xprofile_file.vim'" + \ . " -c 'so Xprofile_file.vim'" + \ . " -c 'qall!'") + + let lines = readfile('Xprofile_file.log') + + call assert_equal(14, len(lines)) + + call assert_match('^SCRIPT .*Xprofile_file.vim$', lines[0]) + call assert_equal('Sourced 2 times', lines[1]) + call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[2]) + call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[3]) + call assert_equal('', lines[4]) + call assert_equal('count total (s) self (s)', lines[5]) + call assert_equal(' func! Foo()', lines[6]) + call assert_equal(' endfunc', lines[7]) + " Loop iterates 10 times. Since script runs twice, body executes 20 times. + " First line of loop executes one more time than body to detect end of loop. + call assert_match('^\s*22\s\+\d\+\.\d\+\s\+for i in range(10)$', lines[8]) + call assert_equal(' " a comment', lines[9]) + call assert_match('^\s*20\s\+\d\+\.\d\+\s\+\d\+\.\d\+\s\+call Foo()$', lines[10]) + call assert_match('^\s*20\s\+\d\+\.\d\+\s\+endfor$', lines[11]) + call assert_match('^\s*2\s\+\d\+\.\d\+\s\+\d\+\.\d\+\s\+call Foo()$', lines[12]) + call assert_equal('', lines[13]) + + call delete('Xprofile_file.vim') + call delete('Xprofile_file.log') +endfunc + +func Test_profile_completion() + call feedkeys(":profile \\\"\", 'tx') + call assert_equal('"profile continue file func pause start', @:) + + call feedkeys(":profile start test_prof\\\"\", 'tx') + call assert_match('^"profile start.* test_profile\.vim', @:) +endfunc + +func Test_profile_errors() + call assert_fails("profile func Foo", 'E750:') + call assert_fails("profile pause", 'E750:') + call assert_fails("profile continue", 'E750:') +endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index 6f3ca12458..3e4d51d70c 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -915,7 +915,7 @@ static const int included_patches[] = { // 192 NA // 191 NA 190, - // 189, + 189, 188, // 187 NA 186, -- cgit From 2bd424c1c5493f3311239a2c0932dd9ff6fac5a5 Mon Sep 17 00:00:00 2001 From: ckelsel Date: Fri, 27 Oct 2017 09:48:22 +0800 Subject: vim-patch:8.0.0194 Problem: Profile tests fails if total and self time are equal. Solution: Make one time optional. https://github.com/vim/vim/commit/e32bbded641a5da0263ecf82f9ccc95a8e0a089e --- src/nvim/testdir/test_profile.vim | 3 ++- src/nvim/version.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/nvim/testdir/test_profile.vim b/src/nvim/testdir/test_profile.vim index 36c05683d5..23d148e47d 100644 --- a/src/nvim/testdir/test_profile.vim +++ b/src/nvim/testdir/test_profile.vim @@ -113,7 +113,8 @@ func Test_profile_file() call assert_equal(' " a comment', lines[9]) call assert_match('^\s*20\s\+\d\+\.\d\+\s\+\d\+\.\d\+\s\+call Foo()$', lines[10]) call assert_match('^\s*20\s\+\d\+\.\d\+\s\+endfor$', lines[11]) - call assert_match('^\s*2\s\+\d\+\.\d\+\s\+\d\+\.\d\+\s\+call Foo()$', lines[12]) + " if self and total are equal we only get one number + call assert_match('^\s*2\s\+\(\d\+\.\d\+\s\+\)\=\d\+\.\d\+\s\+call Foo()$', lines[12]) call assert_equal('', lines[13]) call delete('Xprofile_file.vim') diff --git a/src/nvim/version.c b/src/nvim/version.c index 3e4d51d70c..7c2cb4d580 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -910,7 +910,7 @@ static const int included_patches[] = { // 197, // 196, 195, - // 194, + 194, // 193 NA // 192 NA // 191 NA -- cgit From 45a95a8a5b75473bf9d8f707ed10794ae4ae1528 Mon Sep 17 00:00:00 2001 From: ckelsel Date: Fri, 27 Oct 2017 09:49:36 +0800 Subject: vim-patch:8.0.0196 Problem: The test for :profile is slow and does not work on MS-Windows. Solution: Use the "-es" argument. (Dominique Pelle) Swap single and double quotes for system() https://github.com/vim/vim/commit/c011a3d083001bcd9853b4447422f1819f3cee2f --- src/nvim/testdir/test_profile.vim | 90 ++++++++++++++++++++++----------------- src/nvim/version.c | 2 +- 2 files changed, 51 insertions(+), 41 deletions(-) diff --git a/src/nvim/testdir/test_profile.vim b/src/nvim/testdir/test_profile.vim index 23d148e47d..5f15d51b47 100644 --- a/src/nvim/testdir/test_profile.vim +++ b/src/nvim/testdir/test_profile.vim @@ -4,16 +4,13 @@ if !has('profile') endif func Test_profile_func() - if !has('unix') - return - endif let lines = [ \ "func! Foo1()", \ "endfunc", \ "func! Foo2()", - \ " let count = 100", - \ " while count > 0", - \ " let count = count - 1", + \ " let l:count = 100", + \ " while l:count > 0", + \ " let l:count = l:count - 1", \ " endwhile", \ "endfunc", \ "func! Foo3()", @@ -35,47 +32,59 @@ func Test_profile_func() \ ] call writefile(lines, 'Xprofile_func.vim') - let a = system(v:progpath - \ . " -u NONE -i NONE --noplugin" - \ . " -c 'profile start Xprofile_func.log'" - \ . " -c 'profile func Foo*'" - \ . " -c 'so Xprofile_func.vim'" - \ . " -c 'qall!'") - let lines = readfile('Xprofile_func.log') - - call assert_equal(28, len(lines)) + call system(v:progpath + \ . ' -es -u NONE -U NONE -i NONE --noplugin' + \ . ' -c "profile start Xprofile_func.log"' + \ . ' -c "profile func Foo*"' + \ . ' -c "so Xprofile_func.vim"' + \ . ' -c "qall!"') + call assert_equal(0, v:shell_error) - call assert_equal('FUNCTION Foo1()', lines[0]) - call assert_equal('Called 2 times', lines[1]) - call assert_equal('FUNCTION Foo2()', lines[7]) - call assert_equal('Called 1 time', lines[8]) + let lines = readfile('Xprofile_func.log') " - Foo1() is called 3 times but should be reported as called twice " since one call is in between "profile pause" .. "profile continue". - " - Foo2() should come before Foo1() since Foo1() does much more work.\ + " - Foo2() should come before Foo1() since Foo1() does much more work. " - Foo3() is not reported because function is deleted. " - Unlike Foo3(), Foo2() should not be deleted since there is a check " for v:profiling. " - Bar() is not reported since it does not match "profile func Foo*". - call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[18]) - call assert_equal('count total (s) self (s) function', lines[19]) - call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[20]) - call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[21]) - call assert_equal('', lines[22]) - call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[23]) - call assert_equal('count total (s) self (s) function', lines[24]) - call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[25]) - call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[26]) - call assert_equal('', lines[27]) + call assert_equal(28, len(lines)) + + call assert_equal('FUNCTION Foo1()', lines[0]) + call assert_equal('Called 2 times', lines[1]) + call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[2]) + call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[3]) + call assert_equal('', lines[4]) + call assert_equal('count total (s) self (s)', lines[5]) + call assert_equal('', lines[6]) + call assert_equal('FUNCTION Foo2()', lines[7]) + call assert_equal('Called 1 time', lines[8]) + call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[9]) + call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[10]) + call assert_equal('', lines[11]) + call assert_equal('count total (s) self (s)', lines[12]) + call assert_match('^\s*1\s\+.*\slet l:count = 100$', lines[13]) + call assert_match('^\s*101\s\+.*\swhile l:count > 0$', lines[14]) + call assert_match('^\s*100\s\+.*\s let l:count = l:count - 1$', lines[15]) + call assert_match('^\s*100\s\+.*\sendwhile$', lines[16]) + call assert_equal('', lines[17]) + call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[18]) + call assert_equal('count total (s) self (s) function', lines[19]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[20]) + call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[21]) + call assert_equal('', lines[22]) + call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[23]) + call assert_equal('count total (s) self (s) function', lines[24]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[25]) + call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[26]) + call assert_equal('', lines[27]) call delete('Xprofile_func.vim') call delete('Xprofile_func.log') endfunc func Test_profile_file() - if !has('unix') - return - endif let lines = [ \ 'func! Foo()', \ 'endfunc', @@ -87,13 +96,14 @@ func Test_profile_file() \ ] call writefile(lines, 'Xprofile_file.vim') - let a = system(v:progpath - \ . " -u NONE -i NONE --noplugin" - \ . " -c 'profile start Xprofile_file.log'" - \ . " -c 'profile file Xprofile_file.vim'" - \ . " -c 'so Xprofile_file.vim'" - \ . " -c 'so Xprofile_file.vim'" - \ . " -c 'qall!'") + call system(v:progpath + \ . ' -es -u NONE -U NONE -i NONE --noplugin' + \ . ' -c "profile start Xprofile_file.log"' + \ . ' -c "profile file Xprofile_file.vim"' + \ . ' -c "so Xprofile_file.vim"' + \ . ' -c "so Xprofile_file.vim"' + \ . ' -c "qall!"') + call assert_equal(0, v:shell_error) let lines = readfile('Xprofile_file.log') diff --git a/src/nvim/version.c b/src/nvim/version.c index 7c2cb4d580..7fd5f2c588 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -908,7 +908,7 @@ static const int included_patches[] = { // 199 NA // 198, // 197, - // 196, + 196, 195, 194, // 193 NA -- cgit From 20f1bf325cf82ab80206115231e8aeed27253bf5 Mon Sep 17 00:00:00 2001 From: ckelsel Date: Fri, 27 Oct 2017 21:49:28 +0800 Subject: fix TEST_FILE=test_profile.res make oldtest failed --- src/nvim/testdir/test_profile.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/testdir/test_profile.vim b/src/nvim/testdir/test_profile.vim index 5f15d51b47..f58dba9b14 100644 --- a/src/nvim/testdir/test_profile.vim +++ b/src/nvim/testdir/test_profile.vim @@ -133,7 +133,7 @@ endfunc func Test_profile_completion() call feedkeys(":profile \\\"\", 'tx') - call assert_equal('"profile continue file func pause start', @:) + call assert_equal('"profile continue dump file func pause start stop', @:) call feedkeys(":profile start test_prof\\\"\", 'tx') call assert_match('^"profile start.* test_profile\.vim', @:) -- cgit From 1de5b041a729b56c49eac74a9ca060cbf35569c1 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 27 Oct 2017 19:34:02 +0200 Subject: doc: debian badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4016c9b3c2..87d2db8cae 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ [![Clang Scan Build](https://neovim.io/doc/reports/clang/badge.svg)](https://neovim.io/doc/reports/clang) [![PVS-studio Check](https://neovim.io/doc/reports/pvs/badge.svg)](https://neovim.io/doc/reports/pvs) -Debian +[![Debian CI](https://badges.debian.net/badges/debian/testing/neovim/version.svg)](https://buildd.debian.org/neovim) [![Downloads](https://img.shields.io/github/downloads/neovim/neovim/total.svg?maxAge=2592000)](https://github.com/neovim/neovim/releases/) Neovim is a project that seeks to aggressively refactor Vim in order to: -- cgit From b8a67551d8360ba095d1ffdbc9f8c40b612e9320 Mon Sep 17 00:00:00 2001 From: Sam Wilson Date: Wed, 25 Oct 2017 11:18:47 -0400 Subject: terminal: Account for number column (#5310) --- src/nvim/buffer.c | 2 +- src/nvim/eval.c | 5 +++-- src/nvim/screen.c | 6 ++++++ src/nvim/window.c | 8 ++++++-- test/functional/terminal/window_spec.lua | 28 ++++++++++++++++++++++++++++ 5 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index fc5bb90973..9d42fbc1b3 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1466,7 +1466,7 @@ void enter_buffer(buf_T *buf) if (buf->terminal) { terminal_resize(buf->terminal, - (uint16_t)curwin->w_width, + (uint16_t)(MAX(0, curwin->w_width - win_col_off(curwin))), (uint16_t)curwin->w_height); } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index aab777955c..ef2f671f36 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -16723,9 +16723,10 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } + uint16_t term_width = MAX(0, curwin->w_width - win_col_off(curwin)); TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit, true, false, false, cwd); - data->proc.pty.width = curwin->w_width; + data->proc.pty.width = term_width; data->proc.pty.height = curwin->w_height; data->proc.pty.term_name = xstrdup("xterm-256color"); if (!common_job_start(data, rettv)) { @@ -16733,7 +16734,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) } TerminalOptions topts; topts.data = data; - topts.width = curwin->w_width; + topts.width = term_width; topts.height = curwin->w_height; topts.write_cb = term_write; topts.resize_cb = term_resize; diff --git a/src/nvim/screen.c b/src/nvim/screen.c index f5730cf70a..28b85dcc5f 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -692,6 +692,12 @@ static void win_update(win_T *wp) if (wp->w_nrwidth != i) { type = NOT_VALID; wp->w_nrwidth = i; + + if (buf->terminal) { + terminal_resize(buf->terminal, + (uint16_t)(MAX(0, curwin->w_width - win_col_off(curwin))), + (uint16_t)curwin->w_height); + } } else if (buf->b_mod_set && buf->b_mod_xlines != 0 && wp->w_redraw_top != 0) { /* * When there are both inserted/deleted lines and specific lines to be diff --git a/src/nvim/window.c b/src/nvim/window.c index c2d0a9b3b1..2d64409a1c 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -3747,7 +3747,9 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, do_autochdir(); if (curbuf->terminal) { - terminal_resize(curbuf->terminal, curwin->w_width, curwin->w_height); + terminal_resize(curbuf->terminal, + (uint16_t)(MAX(0, curwin->w_width - win_col_off(curwin))), + (uint16_t)curwin->w_height); } } @@ -4946,7 +4948,9 @@ void win_new_width(win_T *wp, int width) if (wp->w_buffer->terminal) { if (wp->w_height != 0) { - terminal_resize(wp->w_buffer->terminal, wp->w_width, 0); + terminal_resize(wp->w_buffer->terminal, + (uint16_t)(MAX(0, curwin->w_width - win_col_off(curwin))), + 0); } } } diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua index 0f705cfe40..df8324fd6d 100644 --- a/test/functional/terminal/window_spec.lua +++ b/test/functional/terminal/window_spec.lua @@ -11,6 +11,34 @@ describe('terminal window', function() screen = thelpers.screen_setup() end) + describe('with number set', function() + before_each(function() + feed(':set numberi') + screen:expect([[ + {7: 1 }tty ready | + {7: 2 }rows: 6, cols: 46 | + {7: 3 }{1: } | + {7: 4 } | + {7: 5 } | + {7: 6 } | + {3:-- TERMINAL --} | + ]]) + end) + + it('wraps text correctly', function() + thelpers.feed_data({'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'}) + screen:expect([[ + {7: 1 }tty ready | + {7: 2 }rows: 6, cols: 46 | + {7: 3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRST| + {7: 4 }UVWXYZ{1: } | + {7: 5 } | + {7: 6 } | + {3:-- TERMINAL --} | + ]]) + end) + end) + describe('with colorcolumn set', function() before_each(function() feed('') -- cgit From bcf266de46b054b564727d5d31e4421ba09f5704 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 28 Oct 2017 17:54:29 +0200 Subject: test: :terminal + numberwidth=9 --- src/nvim/screen.c | 12 +++---- test/functional/terminal/window_spec.lua | 58 +++++++++++++++++++------------- 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 28b85dcc5f..38ecd88ec0 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -698,12 +698,12 @@ static void win_update(win_T *wp) (uint16_t)(MAX(0, curwin->w_width - win_col_off(curwin))), (uint16_t)curwin->w_height); } - } else if (buf->b_mod_set && buf->b_mod_xlines != 0 && wp->w_redraw_top != 0) { - /* - * When there are both inserted/deleted lines and specific lines to be - * redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw - * everything (only happens when redrawing is off for while). - */ + } else if (buf->b_mod_set + && buf->b_mod_xlines != 0 + && wp->w_redraw_top != 0) { + // When there are both inserted/deleted lines and specific lines to be + // redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw + // everything (only happens when redrawing is off for while). type = NOT_VALID; } else { /* diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua index df8324fd6d..10a9fabb42 100644 --- a/test/functional/terminal/window_spec.lua +++ b/test/functional/terminal/window_spec.lua @@ -11,37 +11,49 @@ describe('terminal window', function() screen = thelpers.screen_setup() end) - describe('with number set', function() - before_each(function() - feed(':set numberi') + describe("with 'number'", function() + it('wraps text', function() + feed([[]]) + feed([[:set numberwidth=1 numberi]]) screen:expect([[ - {7: 1 }tty ready | - {7: 2 }rows: 6, cols: 46 | - {7: 3 }{1: } | - {7: 4 } | - {7: 5 } | - {7: 6 } | + {7:1 }tty ready | + {7:2 }rows: 6, cols: 48 | + {7:3 }{1: } | + {7:4 } | + {7:5 } | + {7:6 } | {3:-- TERMINAL --} | ]]) - end) - - it('wraps text correctly', function() thelpers.feed_data({'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'}) screen:expect([[ - {7: 1 }tty ready | - {7: 2 }rows: 6, cols: 46 | - {7: 3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRST| - {7: 4 }UVWXYZ{1: } | - {7: 5 } | - {7: 6 } | + {7:1 }tty ready | + {7:2 }rows: 6, cols: 48 | + {7:3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV| + {7:4 }WXYZ{1: } | + {7:5 } | + {7:6 } | + {3:-- TERMINAL --} | + ]]) + + -- numberwidth=9 + feed([[]]) + feed([[:set numberwidth=9 numberi]]) + thelpers.feed_data({' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'}) + screen:expect([[ + {7: 1 }tty ready | + {7: 2 }rows: 6, cols: 48 | + {7: 3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO| + {7: 4 }WXYZ abcdefghijklmnopqrstuvwxyzABCDEFGHIJ| + {7: 5 }KLMNOPQRSTUVWXYZrows: 6, cols: 41 | + {7: 6 }{1: } | {3:-- TERMINAL --} | ]]) end) end) - describe('with colorcolumn set', function() + describe("with 'colorcolumn'", function() before_each(function() - feed('') + feed([[]]) screen:expect([[ tty ready | {2:^ } | @@ -51,7 +63,7 @@ describe('terminal window', function() | | ]]) - feed(':set colorcolumn=20i') + feed(':set colorcolumn=20i') end) it('wont show the color column', function() @@ -69,7 +81,7 @@ describe('terminal window', function() describe('with fold set', function() before_each(function() - feed(':set foldenable foldmethod=manuali') + feed([[:set foldenable foldmethod=manuali]]) thelpers.feed_data({'line1', 'line2', 'line3', 'line4', ''}) screen:expect([[ tty ready | @@ -83,7 +95,7 @@ describe('terminal window', function() end) it('wont show any folds', function() - feed('ggvGzf') + feed([[ggvGzf]]) wait() screen:expect([[ ^tty ready | -- cgit From da13d9a30cf7a5428649a24f8761ae1d5dbc1f02 Mon Sep 17 00:00:00 2001 From: Matthew Malcomson Date: Sat, 28 Oct 2017 17:01:38 +0100 Subject: test: ctrl_c_spec: bias timeouts for success (#7451) Having timeouts that are likely to fail incurs a penalty of waiting for screen:expect() to fail, hence removing such small timeouts will speed up the test on average. --- test/functional/ex_cmds/ctrl_c_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/ex_cmds/ctrl_c_spec.lua b/test/functional/ex_cmds/ctrl_c_spec.lua index 091a008814..8f76099f79 100644 --- a/test/functional/ex_cmds/ctrl_c_spec.lua +++ b/test/functional/ex_cmds/ctrl_c_spec.lua @@ -47,7 +47,7 @@ describe("CTRL-C (mapped)", function() end -- The test is time-sensitive. Try different sleep values. - local ms_values = {1, 10, 100, 1000, 10000} + local ms_values = {100, 1000, 10000} for i, ms in ipairs(ms_values) do if i < #ms_values then local status, _ = pcall(test_ctrl_c, ms) -- cgit From 122f52bf897abd1cda4fa467157657fee6bcfe94 Mon Sep 17 00:00:00 2001 From: KunMing Xie Date: Sun, 29 Oct 2017 00:05:59 +0800 Subject: vim-patch:8.0.0206 (#7446) Problem: Test coverage for :retab insufficient. Solution: Add test for :retab. (Dominique Pelle, closes vim/vim#1391) https://github.com/vim/vim/commit/8822744b4d9d40aa1fd59870a8bdd7c64c59a42b --- src/nvim/testdir/Makefile | 1 + src/nvim/testdir/test_retab.vim | 77 +++++++++++++++++++++++++++++++++++++++++ src/nvim/version.c | 2 +- 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 src/nvim/testdir/test_retab.vim diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index 38caa8815d..979021ff92 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -63,6 +63,7 @@ NEW_TESTS ?= \ test_nested_function.res \ test_normal.res \ test_quickfix.res \ + test_retab.res \ test_search.res \ test_signs.res \ test_smartindent.res \ diff --git a/src/nvim/testdir/test_retab.vim b/src/nvim/testdir/test_retab.vim new file mode 100644 index 0000000000..f11a32bade --- /dev/null +++ b/src/nvim/testdir/test_retab.vim @@ -0,0 +1,77 @@ +" Test :retab +func SetUp() + new + call setline(1, "\ta \t b c ") +endfunc + +func TearDown() + bwipe! +endfunc + +func Retab(bang, n) + let l:old_tabstop = &tabstop + let l:old_line = getline(1) + exe "retab" . a:bang . a:n + let l:line = getline(1) + call setline(1, l:old_line) + if a:n > 0 + " :retab changes 'tabstop' to n with argument n > 0. + call assert_equal(a:n, &tabstop) + exe 'set tabstop=' . l:old_tabstop + else + " :retab does not change 'tabstop' with empty or n <= 0. + call assert_equal(l:old_tabstop, &tabstop) + endif + return l:line +endfunc + +func Test_retab() + set tabstop=8 noexpandtab + call assert_equal("\ta\t b c ", Retab('', '')) + call assert_equal("\ta\t b c ", Retab('', 0)) + call assert_equal("\ta\t b c ", Retab('', 8)) + call assert_equal("\ta\t b\t c\t ", Retab('!', '')) + call assert_equal("\ta\t b\t c\t ", Retab('!', 0)) + call assert_equal("\ta\t b\t c\t ", Retab('!', 8)) + + call assert_equal("\t\ta\t\t\tb c ", Retab('', 4)) + call assert_equal("\t\ta\t\t\tb\t\t c\t ", Retab('!', 4)) + + call assert_equal(" a\t\tb c ", Retab('', 10)) + call assert_equal(" a\t\tb c ", Retab('!', 10)) + + set tabstop=8 expandtab + call assert_equal(" a b c ", Retab('', '')) + call assert_equal(" a b c ", Retab('', 0)) + call assert_equal(" a b c ", Retab('', 8)) + call assert_equal(" a b c ", Retab('!', '')) + call assert_equal(" a b c ", Retab('!', 0)) + call assert_equal(" a b c ", Retab('!', 8)) + + call assert_equal(" a b c ", Retab(' ', 4)) + call assert_equal(" a b c ", Retab('!', 4)) + + call assert_equal(" a b c ", Retab(' ', 10)) + call assert_equal(" a b c ", Retab('!', 10)) + + set tabstop=4 noexpandtab + call assert_equal("\ta\t\tb c ", Retab('', '')) + call assert_equal("\ta\t\tb\t\t c\t ", Retab('!', '')) + call assert_equal("\t a\t\t\tb c ", Retab('', 3)) + call assert_equal("\t a\t\t\tb\t\t\tc\t ", Retab('!', 3)) + call assert_equal(" a\t b c ", Retab('', 5)) + call assert_equal(" a\t b\t\t c\t ", Retab('!', 5)) + + set tabstop=4 expandtab + call assert_equal(" a b c ", Retab('', '')) + call assert_equal(" a b c ", Retab('!', '')) + call assert_equal(" a b c ", Retab('', 3)) + call assert_equal(" a b c ", Retab('!', 3)) + call assert_equal(" a b c ", Retab('', 5)) + call assert_equal(" a b c ", Retab('!', 5)) +endfunc + +func Test_retab_error() + call assert_fails('retab -1', 'E487:') + call assert_fails('retab! -1', 'E487:') +endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index 6f3ca12458..d841f58b92 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -898,7 +898,7 @@ static const int included_patches[] = { 209, 208, // 207, - // 206, + 206, 205, // 204, // 203 NA -- cgit From 8526902790680b9eea5462c19bd7d45caa40f16d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 28 Oct 2017 23:49:41 +0200 Subject: doc/ui.txt --- runtime/doc/ui.txt | 96 +++++++++++++++++++++++++++++------------------------- src/nvim/globals.h | 2 +- src/nvim/ui.c | 1 - 3 files changed, 52 insertions(+), 47 deletions(-) diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt index b875c1b183..deac1609c0 100644 --- a/runtime/doc/ui.txt +++ b/runtime/doc/ui.txt @@ -1,12 +1,12 @@ *ui.txt* Nvim - NVIM REFERENCE MANUAL by Thiago de Arruda + NVIM REFERENCE MANUAL -UI protocol *ui* +Nvim UI protocol *ui* - Type to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== Introduction *ui-intro* @@ -16,34 +16,35 @@ RPC API. The UI model consists of a terminal-like grid with a single, monospace font size. Some elements (UI "widgets") can be drawn separately from the grid ("externalized"). - *ui-options* + *ui-options* After connecting to Nvim (usually a spawned, embedded instance) use the |nvim_ui_attach| API method to tell Nvim that your program wants to draw the Nvim screen grid with a size of width × height cells. `options` must be a dictionary with these (optional) keys: - `rgb` Controls what color format to use. - Set to true (default) to use 24-bit rgb - colors. - Set to false to use terminal color codes (at - most 256 different colors). + `rgb` Decides the color format. + Set true (default) for 24-bit RGB colors. + Set false for terminal colors (max of 256). + *ui-ext-options* `ext_popupmenu` Externalize the popupmenu. |ui-popupmenu| `ext_tabline` Externalize the tabline. |ui-tabline| `ext_cmdline` Externalize the cmdline. |ui-cmdline| Nvim will then send msgpack-rpc notifications, with the method name "redraw" and a single argument, an array of screen update events. -Update events are tuples whose first element is the string name of the update -kind. The rest are parameters for each update, described in the sections below. -These should be processed in order. Preferably the user should only be able to -see the screen state after all update events in the same "redraw" event are -processed (not any intermediate state after processing only a part of the -array). - -Section 2 and 3 describes grid and mode events that are send unconditionally, -and suffice to implement a terminal-like interface. Nvim also allows a number -of screen elements to be sent as descriptive events for the GUI to draw -itself, rather than Nvim drawing itself on the grid. This is controlled by the -`ext_` options. +Update events are tuples whose first element is the event name and remaining +elements the event parameters. + +Events must be handled in order. The user should only see the updated screen +state after all events in the same "redraw" batch are processed (not any +intermediate state after processing only part of the array). + +Nvim sends |ui-global| and |ui-grid| events unconditionally; these suffice to +implement a terminal-like interface. + +Nvim optionally sends screen elements "semantically" as structured events +instead of raw grid-lines. Then the UI must decide how to present those +elements itself; Nvim will not draw those elements on the grid. This is +controlled by the |ui-ext-options|. Future versions of Nvim may add new update kinds and may append new parameters to existing update kinds. Clients must be prepared to ignore such extensions @@ -64,7 +65,8 @@ Global Events *ui-global* current mode is given by the `mode_idx` field of the `mode_change` event. -Each mode property map may contain these keys: + Each mode property map may contain these keys: + KEY DESCRIPTION ~ `cursor_shape`: "block", "horizontal", "vertical" `cell_percentage`: Cell % occupied by the cursor. @@ -75,7 +77,7 @@ Each mode property map may contain these keys: `name`: Mode descriptive name. `mouse_shape`: (To be implemented.) -Some keys are missing in some modes. + Some keys are missing in some modes. ["mode_change", mode, mode_idx] The mode changed. The first parameter `mode` is a string representing @@ -86,7 +88,6 @@ Some keys are missing in some modes. instance more submodes and temporary states might be represented as separate modes. - ["mouse_on"] ["mouse_off"] Tells the client whether mouse support, as determined by |'mouse'| @@ -97,8 +98,8 @@ Some keys are missing in some modes. ["busy_on"] ["busy_off"] - Nvim started or stopped being busy, and possibly not responsible to user - input. This could be indicated to the user by hiding the cursor. + Nvim started or stopped being busy, and possibly not responsive to + user input. This could be indicated to the user by hiding the cursor. ["suspend"] |:suspend| command or |Ctrl-Z| mapping is used. A terminal client (or other @@ -137,7 +138,7 @@ Grid Events *ui-grid* Set the default foreground, background and special colors respectively. - *ui-event-highlight_set* + *ui-event-highlight_set* ["highlight_set", attrs] Set the attributes that the next text put on the grid will have. `attrs` is a dict with the keys below. Any absent key is reset @@ -235,44 +236,49 @@ Only sent if `ext_cmdline` option is set in |ui-options| ["cmdline_show", content, pos, firstc, prompt, indent, level] content: List of [attrs, string] [[{}, "t"], [attrs, "est"], ...] + + Triggered when the user types in the cmdline. The `content` is the full content that should be displayed in the cmdline, and the `pos` is the position of the cursor that in the - cmdline. This event will be triggered when you type in the cmdline. - The content is divided into chunks with different highlight attributes - represented as a dict, see |ui-event-highlight_set|. + cmdline. The content is divided into chunks with different highlight + attributes represented as a dict (see |ui-event-highlight_set|). `firstc` and `prompt` are text, that if non-empty should be displayed in front of the command line. `firstc` always indicates - built in command lines such as `:` (ex command) and `/` `?` (search), + built-in command lines such as `:` (ex command) and `/` `?` (search), while `prompt` is an |input()| prompt. `indent` tells how many spaces - the content should be indented + the content should be indented. - The command line in nvim can be invoked recursively, for instance by + The Nvim command line can be invoked recursively, for instance by typing `=` at the command line prompt. The `level` field is used to distinguish different command lines active at the same time. The - first invoked command line will always have level 1, and the next - recursively invoked prompt will have level 2. Also, a command line - invoked while in command line window will have a higher level than - than the edited command line. + first invoked command line has level 1, the next recursively-invoked + prompt has level 2. A command line invoked from the |cmd-line-window| + has a higher level than than the edited command line. ["cmdline_pos", pos, level] Change the cursor position in the cmdline. ["cmdline_special_char", c, shift, level] Display a special char in the cmdline at the cursor position. This is - typically used to indicate a pending state, like right after Ctrl-V. - if shift is true the text after the cursor should be shifted, - otherwise it should overshadow the char at the cursor. - Should be hidden at next cmdline_char + typically used to indicate a pending state, e.g. after |c_CTRL-V|. If + `shift` is true the text after the cursor should be shifted, otherwise + it should overwrite the char at the cursor. + + Should be hidden at next cmdline_pos. ["cmdline_hide"] Hide the cmdline. ["cmdline_block_show", lines] - Show a block of context to the current command line. This occurs for - instance if a function is interactively defined at the command line. - `lines` is a list of lines where each line is represented as a list of - highlighted chunks, just like `contents` of |ui-event-cmdline_show|. + Show a block of context to the current command line. For example if + the user defines a |:function| interactively: > + :function Foo() + : echo "foo" + : +< + `lines` is a list of lines of highlighted chunks, in the same form as + the "cmdline_show" `contents` parameter. ["cmdline_block_append", line] Append a line at the end of the currently shown block. diff --git a/src/nvim/globals.h b/src/nvim/globals.h index f24286360a..0f3e132bc0 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -984,7 +984,7 @@ EXTERN int km_startsel INIT(= FALSE); EXTERN int cedit_key INIT(= -1); ///< key value of 'cedit' option EXTERN int cmdwin_type INIT(= 0); ///< type of cmdline window or 0 EXTERN int cmdwin_result INIT(= 0); ///< result of cmdline window or 0 -EXTERN int cmdwin_level INIT(= 0); ///< cmdline level of cmdline window or 0 +EXTERN int cmdwin_level INIT(= 0); ///< cmdline recursion level EXTERN char_u no_lines_msg[] INIT(= N_("--No lines in buffer--")); diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 6b09f6e6db..afe7a51d43 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -30,7 +30,6 @@ #include "nvim/os/input.h" #include "nvim/os/signal.h" #include "nvim/popupmnu.h" -#include "nvim/ex_getln.h" #include "nvim/screen.h" #include "nvim/syntax.h" #include "nvim/window.h" -- cgit From 1a93f5883105c304d496d6c2e841626ebb7d44c1 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 29 Oct 2017 00:56:00 +0200 Subject: test: ui/cmdline_spec.lua: enable on Windows --- test/functional/ui/cmdline_spec.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 6a9f4a22b4..0f8302b036 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -5,8 +5,6 @@ local source = helpers.source local ok = helpers.ok local command = helpers.command -if helpers.pending_win32(pending) then return end - describe('external cmdline', function() local screen local last_level = 0 -- cgit From 3a938fff0954513f34704485e53dcb9a0cc7c59d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 29 Oct 2017 02:10:37 +0100 Subject: test/win: partially disable :terminal resize test (#7453) --- test/functional/terminal/window_spec.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua index 10a9fabb42..231618c5da 100644 --- a/test/functional/terminal/window_spec.lua +++ b/test/functional/terminal/window_spec.lua @@ -2,6 +2,7 @@ local helpers = require('test.functional.helpers')(after_each) local thelpers = require('test.functional.terminal.helpers') local feed, clear = helpers.feed, helpers.clear local wait = helpers.wait +local iswin = helpers.iswin describe('terminal window', function() local screen @@ -35,6 +36,10 @@ describe('terminal window', function() {3:-- TERMINAL --} | ]]) + if iswin() then + return -- win: :terminal resize is unreliable #7007 + end + -- numberwidth=9 feed([[]]) feed([[:set numberwidth=9 numberi]]) -- cgit From 2a3bcd1ff883429a3dd17e7ae5ddc1396abbad17 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 29 Oct 2017 03:06:53 +0100 Subject: rpc: Don't delay notifications when request is pending (#6544) With the old behavior, if a GUI makes a blocking request that requires user interaction (like nvim_input()), it would not get any screen updates. The client, not nvim, should decide how to handle notifications during a pending request. If an rplugin wants to avoid async calls while a sync call is busy, it likely wants to avoid processing async calls while another async call also is handled as well. This may break the expectation of some existing rplugins. For compatibility, remote/define.vim reimplements the old behavior. Clients can opt-out by specifying `sync=urgent`. - Legacy hosts should be updated to use `sync=urgent`. They could add a flag indicating which async methods are always safe to call and which must wait until the main loop returns. - New hosts can expose the full asyncness, they don't need to offer both behaviors. ref #6532 ref #1398 d83868fe9071af1b4866594eac12f7aa0fa71b53 --- runtime/autoload/remote/define.vim | 32 +++++++++++++-- src/clint.py | 1 + src/nvim/msgpack_rpc/channel.c | 36 +--------------- test/functional/api/server_requests_spec.lua | 61 +++++++++++++++++++--------- 4 files changed, 74 insertions(+), 56 deletions(-) diff --git a/runtime/autoload/remote/define.vim b/runtime/autoload/remote/define.vim index b5c976c823..2688a62a82 100644 --- a/runtime/autoload/remote/define.vim +++ b/runtime/autoload/remote/define.vim @@ -169,14 +169,40 @@ function! remote#define#FunctionOnChannel(channel, method, sync, name, opts) exe function_def endfunction +let s:busy = {} +let s:pending_notifications = {} function! s:GetRpcFunction(sync) - if a:sync - return 'rpcrequest' + if a:sync ==# 'urgent' + return 'rpcnotify' + elseif a:sync + return 'remote#define#request' endif - return 'rpcnotify' + return 'remote#define#notify' endfunction +function! remote#define#notify(chan, ...) + if get(s:busy, a:chan, 0) > 0 + let pending = get(s:pending_notifications, a:chan, []) + call add(pending, deepcopy(a:000)) + let s:pending_notifications[a:chan] = pending + else + call call('rpcnotify', [a:chan] + a:000) + endif +endfunction + +function! remote#define#request(chan, ...) + let s:busy[a:chan] = get(s:busy, a:chan, 0)+1 + let val = call('rpcrequest', [a:chan]+a:000) + let s:busy[a:chan] -= 1 + if s:busy[a:chan] == 0 + for msg in get(s:pending_notifications, a:chan, []) + call call('rpcnotify', [a:chan] + msg) + endfor + let s:pending_notifications[a:chan] = [] + endif + return val +endfunction function! s:GetCommandPrefix(name, opts) return 'command!'.s:StringifyOpts(a:opts, ['nargs', 'complete', 'range', diff --git a/src/clint.py b/src/clint.py index 4a41650ec4..e63175a69b 100755 --- a/src/clint.py +++ b/src/clint.py @@ -2531,6 +2531,7 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error): r'(?pending_requests) { - // Pending request, queue the notification for later sending. - const String method = cstr_as_string((char *)name); - WBuffer *buffer = serialize_request(id, 0, method, args, &out_buffer, 1); - kv_push(channel->delayed_notifications, buffer); - } else { - send_event(channel, name, args); - } + send_event(channel, name, args); } else { broadcast_event(name, args); } @@ -248,10 +239,8 @@ Object channel_send_call(uint64_t id, // Push the frame ChannelCallFrame frame = { request_id, false, false, NIL }; kv_push(channel->call_stack, &frame); - channel->pending_requests++; LOOP_PROCESS_EVENTS_UNTIL(&main_loop, channel->events, -1, frame.returned); (void)kv_pop(channel->call_stack); - channel->pending_requests--; if (frame.errored) { if (frame.result.type == kObjectTypeString) { @@ -276,10 +265,6 @@ Object channel_send_call(uint64_t id, api_free_object(frame.result); } - if (!channel->pending_requests) { - send_delayed_notifications(channel); - } - decref(channel); return frame.errored ? NIL : frame.result; @@ -704,11 +689,7 @@ static void broadcast_event(const char *name, Array args) for (size_t i = 0; i < kv_size(subscribed); i++) { Channel *channel = kv_A(subscribed, i); - if (channel->pending_requests) { - kv_push(channel->delayed_notifications, buffer); - } else { - channel_write(channel, buffer); - } + channel_write(channel, buffer); } end: @@ -786,7 +767,6 @@ static void free_channel(Channel *channel) pmap_free(cstr_t)(channel->subscribed_events); kv_destroy(channel->call_stack); - kv_destroy(channel->delayed_notifications); if (channel->type != kChannelTypeProc) { multiqueue_free(channel->events); } @@ -811,11 +791,9 @@ static Channel *register_channel(ChannelType type, uint64_t id, rv->closed = false; rv->unpacker = msgpack_unpacker_new(MSGPACK_UNPACKER_INIT_BUFFER_SIZE); rv->id = id > 0 ? id : next_chan_id++; - rv->pending_requests = 0; rv->subscribed_events = pmap_new(cstr_t)(); rv->next_request_id = 1; kv_init(rv->call_stack); - kv_init(rv->delayed_notifications); pmap_put(uint64_t)(channels, rv->id, rv); ILOG("new channel %" PRIu64 " (%s): %s", rv->id, @@ -912,16 +890,6 @@ static WBuffer *serialize_response(uint64_t channel_id, return rv; } -static void send_delayed_notifications(Channel* channel) -{ - for (size_t i = 0; i < kv_size(channel->delayed_notifications); i++) { - WBuffer *buffer = kv_A(channel->delayed_notifications, i); - channel_write(channel, buffer); - } - - kv_size(channel->delayed_notifications) = 0; -} - static void incref(Channel *channel) { channel->refcount++; diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 9f245d913b..4380e52b8b 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -109,7 +109,28 @@ describe('server -> client', function() end) describe('requests and notifications interleaved', function() - -- This tests that the following scenario won't happen: + it('does not delay notifications during pending request', function() + local received = false + local function on_setup() + eq("retval", funcs.rpcrequest(cid, "doit")) + stop() + end + local function on_request(method) + if method == "doit" then + funcs.rpcnotify(cid, "headsup") + eq(true,received) + return "retval" + end + end + local function on_notification(method) + if method == "headsup" then + received = true + end + end + run(on_request, on_notification, on_setup) + end) + + -- This tests the following scenario: -- -- server->client [request ] (1) -- client->server [request ] (2) triggered by (1) @@ -124,36 +145,38 @@ describe('server -> client', function() -- only deals with one server->client request at a time. (In other words, -- the client cannot send a response to a request that is not at the top -- of nvim's request stack). - -- - -- But above scenario shoudn't happen by the way notifications are dealt in - -- Nvim: they are only sent after there are no pending server->client - -- request(the request stack fully unwinds). So (3) is only sent after the - -- client returns (6). - it('works', function() - local expected = 300 - local notified = 0 + pending('will close connection if not properly synchronized', function() local function on_setup() eq('notified!', eval('rpcrequest('..cid..', "notify")')) end local function on_request(method) - eq('notify', method) - eq(1, eval('rpcnotify('..cid..', "notification")')) - return 'notified!' + if method == "notify" then + eq(1, eval('rpcnotify('..cid..', "notification")')) + return 'notified!' + elseif method == "nested" then + -- do some busywork, so the first request will return + -- before this one + for _ = 1, 5 do + eq(2, eval("1+1")) + end + eq(1, eval('rpcnotify('..cid..', "nested_done")')) + return 'done!' + end end local function on_notification(method) - eq('notification', method) - if notified == expected then - stop() - return + if method == "notification" then + eq('done!', eval('rpcrequest('..cid..', "nested")')) + elseif method == "nested_done" then + -- this should never have been sent + ok(false) end - notified = notified + 1 - eq('notified!', eval('rpcrequest('..cid..', "notify")')) end run(on_request, on_notification, on_setup) - eq(expected, notified) + -- ignore disconnect failure, otherwise detected by after_each + clear() end) end) -- cgit From 6c43fccb278382e5ce59b6035a84fbdb3e7a1734 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 29 Oct 2017 13:46:40 +0100 Subject: vim-patch:8.0.0944 Problem: Test_profile is a little bit flaky. Solution: Accept a match when self and total time are the same. (James McCoy, closes vim/vim#1972) https://github.com/vim/vim/commit/d21b16f3c0c676bfe3a37aef1ac3118e1ecded60 --- src/nvim/testdir/test_profile.vim | 3 ++- src/nvim/version.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/nvim/testdir/test_profile.vim b/src/nvim/testdir/test_profile.vim index f58dba9b14..183f52b8ac 100644 --- a/src/nvim/testdir/test_profile.vim +++ b/src/nvim/testdir/test_profile.vim @@ -121,7 +121,8 @@ func Test_profile_file() " First line of loop executes one more time than body to detect end of loop. call assert_match('^\s*22\s\+\d\+\.\d\+\s\+for i in range(10)$', lines[8]) call assert_equal(' " a comment', lines[9]) - call assert_match('^\s*20\s\+\d\+\.\d\+\s\+\d\+\.\d\+\s\+call Foo()$', lines[10]) + " if self and total are equal we only get one number + call assert_match('^\s*20\s\+\(\d\+\.\d\+\s\+\)\=\d\+\.\d\+\s\+call Foo()$', lines[10]) call assert_match('^\s*20\s\+\d\+\.\d\+\s\+endfor$', lines[11]) " if self and total are equal we only get one number call assert_match('^\s*2\s\+\(\d\+\.\d\+\s\+\)\=\d\+\.\d\+\s\+call Foo()$', lines[12]) diff --git a/src/nvim/version.c b/src/nvim/version.c index 7fd5f2c588..e8d82d3b87 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -160,7 +160,7 @@ static const int included_patches[] = { // 947, // 946, // 945, - // 944, + 944, // 943, // 942, // 941, -- cgit