From e00b02429520ad2c8f087024900c8adce5b42d46 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 28 Dec 2016 14:54:30 -0500 Subject: [PATCH 01/14] vim-patch:7.4.2149 Problem: If a test leaves a window open a following test may fail. Solution: Always close extra windows after running a test. https://github.com/vim/vim/commit/7cba71d7e3576639679b6a3aedeeb1ac07f7f2f5 Apply the runtest.vim changes that were missing from 4431975210b58c6b0403ee50172bad3c8729bbb2 --- src/nvim/testdir/runtest.vim | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim index 931013877d..20863bbaf3 100644 --- a/src/nvim/testdir/runtest.vim +++ b/src/nvim/testdir/runtest.vim @@ -86,6 +86,12 @@ function RunTheTest(test) if exists("*TearDown") call TearDown() endif + + " Close any extra windows and make the current one not modified. + while winnr('$') > 1 + bwipe! + endwhile + set nomodified endfunc " Source the test script. First grab the file name, in case the script From 92c7c42f7c2aab4b5f00b5d3785c06a3e2834c28 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 15 Nov 2016 16:28:23 -0500 Subject: [PATCH 02/14] vim-patch:7.4.2183 Problem: Sign tests are old style. Solution: Turn them into new style tests. (Dominique Pelle) https://github.com/vim/vim/commit/09de17536dd84e43aed7a575183e320e8d980b68 --- src/nvim/testdir/Makefile | 1 + src/nvim/testdir/test_signs.vim | 106 ++++++++++++++++++++++++++++++++ src/nvim/version.c | 2 +- 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 src/nvim/testdir/test_signs.vim diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index 7cd1921ce1..e27be54fc9 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -40,6 +40,7 @@ NEW_TESTS = \ test_match.res \ test_matchadd_conceal.res \ test_quickfix.res \ + test_signs.res \ test_syntax.res \ test_usercommands.res \ test_timers.res \ diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim new file mode 100644 index 0000000000..f280a3161e --- /dev/null +++ b/src/nvim/testdir/test_signs.vim @@ -0,0 +1,106 @@ +" Test for signs + +if !has('signs') + finish +endif + +func Test_sign() + new + call setline(1, ['a', 'b', 'c', 'd']) + + sign define Sign1 text=x + sign define Sign2 text=y + + " Test listing signs. + let a=execute('sign list') + call assert_equal("\nsign Sign1 text=x \nsign Sign2 text=y ", a) + + let a=execute('sign list Sign1') + call assert_equal("\nsign Sign1 text=x ", a) + + " Place the sign at line 3,then check that we can jump to it. + exe 'sign place 42 line=3 name=Sign1 buffer=' . bufnr('') + 1 + exe 'sign jump 42 buffer=' . bufnr('') + call assert_equal('c', getline('.')) + + " Can't change sign. + call assert_fails("exe 'sign place 43 name=Sign1 buffer=' . bufnr('')", 'E885:') + + let a=execute('sign place') + call assert_equal("\n--- Signs ---\nSigns for [NULL]:\n line=3 id=42 name=Sign1\n", a) + + " Unplace the sign and try jumping to it again should now fail. + sign unplace 42 + 1 + call assert_fails("exe 'sign jump 42 buffer=' . bufnr('')", 'E157:') + call assert_equal('a', getline('.')) + + " Unplace sign on current line. + exe 'sign place 43 line=4 name=Sign2 buffer=' . bufnr('') + 4 + sign unplace + let a=execute('sign place') + call assert_equal("\n--- Signs ---\n", a) + + " Try again to unplace sign on current line, it should fail this time. + call assert_fails('sign unplace', 'E159:') + + " Unplace all signs. + exe 'sign place 42 line=3 name=Sign1 buffer=' . bufnr('') + sign unplace * + let a=execute('sign place') + call assert_equal("\n--- Signs ---\n", a) + + " After undefining the sign, we should no longer be able to place it. + sign undefine Sign1 + sign undefine Sign2 + call assert_fails("exe 'sign place 42 line=3 name=Sign1 buffer=' . bufnr('')", 'E155:') + +endfunc + +func Test_sign_completion() + sign define Sign1 text=x + sign define Sign2 text=y + + call feedkeys(":sign \\\"\", 'tx') + call assert_equal('"sign define jump list place undefine unplace', @:) + + call feedkeys(":sign define Sign \\\"\", 'tx') + call assert_equal('"sign define Sign icon= linehl= text= texthl=', @:) + + call feedkeys(":sign define Sign linehl=Spell\\\"\", 'tx') + call assert_equal('"sign define Sign linehl=SpellBad SpellCap SpellLocal SpellRare', @:) + + call feedkeys(":sign undefine \\\"\", 'tx') + call assert_equal('"sign undefine Sign1 Sign2', @:) + + call feedkeys(":sign place 1 \\\"\", 'tx') + call assert_equal('"sign place 1 buffer= file= line= name=', @:) + + call feedkeys(":sign place 1 name=\\\"\", 'tx') + call assert_equal('"sign place 1 name=Sign1 Sign2', @:) + + call feedkeys(":sign unplace 1 \\\"\", 'tx') + call assert_equal('"sign unplace 1 buffer= file=', @:) + + call feedkeys(":sign list \\\"\", 'tx') + call assert_equal('"sign list Sign1 Sign2', @:) + + call feedkeys(":sign jump 1 \\\"\", 'tx') + call assert_equal('"sign jump 1 buffer= file=', @:) + + sign undefine Sign1 + sign undefine Sign2 + +endfunc + +func Test_sign_invalid_commands() + call assert_fails('sign', 'E471:') + call assert_fails('sign xxx', 'E160:') + call assert_fails('sign define', 'E156:') + call assert_fails('sign undefine', 'E156:') + call assert_fails('sign list xxx', 'E155:') + call assert_fails('sign place 1 buffer=', 'E158:') + call assert_fails('sign define Sign2 text=', 'E239:') +endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index df3fc1cbc2..14905a7bfa 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -257,7 +257,7 @@ static int included_patches[] = { // 2186 NA // 2185, // 2184, - // 2183, + 2183, // 2182 NA // 2181, // 2180, From d4671048162be61096cfcf6beef917166afa5267 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 15 Nov 2016 16:30:14 -0500 Subject: [PATCH 03/14] vim-patch:7.4.2194 Problem: Sign tests don't cover enough. Solution: Add more test cases. (Dominique Pelle) https://github.com/vim/vim/commit/446a973ce3ce4988607292c0e6345db788f12c7b --- src/nvim/testdir/test_signs.vim | 107 +++++++++++++++++++++++++++----- src/nvim/version.c | 2 +- 2 files changed, 93 insertions(+), 16 deletions(-) diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim index f280a3161e..79e60986ee 100644 --- a/src/nvim/testdir/test_signs.vim +++ b/src/nvim/testdir/test_signs.vim @@ -8,36 +8,71 @@ func Test_sign() new call setline(1, ['a', 'b', 'c', 'd']) + " Define some signs. + " We can specify icons even if not all versions of vim support icons as + " icon is ignored when not supported. "(not supported)" is shown after + " the icon name when listing signs. sign define Sign1 text=x - sign define Sign2 text=y + try + sign define Sign2 text=xy texthl=Title linehl=Error icon=../../pixmaps/stock_vim_find_help.png + catch /E255:/ + " ignore error: E255: Couldn't read in sign data! + " This error can happen when running in gui. + " Some gui like Motif do not support the png icon format. + endtry " Test listing signs. let a=execute('sign list') - call assert_equal("\nsign Sign1 text=x \nsign Sign2 text=y ", a) + call assert_match("^\nsign Sign1 text=x \nsign Sign2 icon=../../pixmaps/stock_vim_find_help.png .*text=xy linehl=Error texthl=Title$", a) let a=execute('sign list Sign1') call assert_equal("\nsign Sign1 text=x ", a) - " Place the sign at line 3,then check that we can jump to it. - exe 'sign place 42 line=3 name=Sign1 buffer=' . bufnr('') + " Split the window to the bottom to verify sign jump will stay in the current window + " if the buffer is displayed there. + let bn = bufnr('%') + let wn = winnr() + exe 'sign place 41 line=3 name=Sign1 buffer=' . bn 1 - exe 'sign jump 42 buffer=' . bufnr('') + bot split + exe 'sign jump 41 buffer=' . bufnr('%') + call assert_equal('c', getline('.')) + call assert_equal(3, winnr()) + call assert_equal(bn, bufnr('%')) + call assert_notequal(wn, winnr()) + + " Create a new buffer and check that ":sign jump" switches to the old buffer. + 1 + new foo + call assert_notequal(bn, bufnr('%')) + exe 'sign jump 41 buffer=' . bn + call assert_equal(bn, bufnr('%')) call assert_equal('c', getline('.')) - " Can't change sign. - call assert_fails("exe 'sign place 43 name=Sign1 buffer=' . bufnr('')", 'E885:') + " Redraw to make sure that screen redraw with sign gets exercised, + " with and without 'rightleft'. + if has('rightleft') + set rightleft + redraw + set norightleft + endif + redraw + " Check that we can't change sign. + call assert_fails("exe 'sign place 40 name=Sign1 buffer=' . bufnr('%')", 'E885:') + + " Check placed signs let a=execute('sign place') - call assert_equal("\n--- Signs ---\nSigns for [NULL]:\n line=3 id=42 name=Sign1\n", a) + call assert_equal("\n--- Signs ---\nSigns for [NULL]:\n line=3 id=41 name=Sign1\n", a) - " Unplace the sign and try jumping to it again should now fail. - sign unplace 42 + " Unplace the sign and try jumping to it again should fail. + sign unplace 41 1 - call assert_fails("exe 'sign jump 42 buffer=' . bufnr('')", 'E157:') + call assert_fails("exe 'sign jump 41 buffer=' . bufnr('%')", 'E157:') call assert_equal('a', getline('.')) " Unplace sign on current line. - exe 'sign place 43 line=4 name=Sign2 buffer=' . bufnr('') + exe 'sign place 42 line=4 name=Sign2 buffer=' . bufnr('%') 4 sign unplace let a=execute('sign place') @@ -47,16 +82,54 @@ func Test_sign() call assert_fails('sign unplace', 'E159:') " Unplace all signs. - exe 'sign place 42 line=3 name=Sign1 buffer=' . bufnr('') + exe 'sign place 41 line=3 name=Sign1 buffer=' . bufnr('%') sign unplace * let a=execute('sign place') call assert_equal("\n--- Signs ---\n", a) + " Check :jump with file=... + edit foo + call setline(1, ['A', 'B', 'C', 'D']) + + try + sign define Sign3 text=y texthl=DoesNotExist linehl=DoesNotExist icon=doesnotexist.xpm + catch /E255:/ + " ignore error: E255: it can happens for guis. + endtry + + let fn = expand('%:p') + exe 'sign place 43 line=2 name=Sign3 file=' . fn + edit bar + call assert_notequal(fn, expand('%:p')) + exe 'sign jump 43 file=' . fn + call assert_equal('B', getline('.')) + " After undefining the sign, we should no longer be able to place it. sign undefine Sign1 sign undefine Sign2 - call assert_fails("exe 'sign place 42 line=3 name=Sign1 buffer=' . bufnr('')", 'E155:') + sign undefine Sign3 + call assert_fails("exe 'sign place 41 line=3 name=Sign1 buffer=' . bufnr('%')", 'E155:') +endfunc +" Undefining placed sign is not recommended. +" Quoting :help sign +" +" :sign undefine {name} +" Deletes a previously defined sign. If signs with this {name} +" are still placed this will cause trouble. +func Test_sign_undefine_still_placed() + new foobar + sign define Sign text=x + exe 'sign place 41 line=1 name=Sign buffer=' . bufnr('%') + sign undefine Sign + + " Listing placed sign should show that sign is deleted. + let a=execute('sign place') + call assert_equal("\n--- Signs ---\nSigns for foobar:\n line=1 id=41 name=[Deleted]\n", a) + + sign unplace 41 + let a=execute('sign place') + call assert_equal("\n--- Signs ---\n", a) endfunc func Test_sign_completion() @@ -72,6 +145,9 @@ func Test_sign_completion() call feedkeys(":sign define Sign linehl=Spell\\\"\", 'tx') call assert_equal('"sign define Sign linehl=SpellBad SpellCap SpellLocal SpellRare', @:) + call feedkeys(":sign define Sign icon=../../pixmaps/tb_p\\\"\", 'tx') + call assert_equal('"sign define Sign icon=../../pixmaps/tb_paste.xpm ../../pixmaps/tb_print.xpm', @:) + call feedkeys(":sign undefine \\\"\", 'tx') call assert_equal('"sign undefine Sign1 Sign2', @:) @@ -92,13 +168,14 @@ func Test_sign_completion() sign undefine Sign1 sign undefine Sign2 - endfunc func Test_sign_invalid_commands() call assert_fails('sign', 'E471:') + call assert_fails('sign jump', 'E471:') call assert_fails('sign xxx', 'E160:') call assert_fails('sign define', 'E156:') + call assert_fails('sign define Sign1 xxx', 'E475:') call assert_fails('sign undefine', 'E156:') call assert_fails('sign list xxx', 'E155:') call assert_fails('sign place 1 buffer=', 'E158:') diff --git a/src/nvim/version.c b/src/nvim/version.c index 14905a7bfa..d146d8ff67 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -246,7 +246,7 @@ static int included_patches[] = { // 2197, // 2196, // 2195 NA - // 2194, + 2194, // 2193 NA // 2192 NA // 2191 NA From 99a8cd3be0509e97b649edc1599bfb74bf2b4802 Mon Sep 17 00:00:00 2001 From: Chris Lucas Date: Sat, 29 Oct 2016 17:04:13 -0700 Subject: [PATCH 04/14] vim-patch:7.4.2201 Problem: The sign column disappears when the last sign is deleted. Solution: Add the 'signcolumn' option. (Christian Brabandt) https://github.com/vim/vim/commit/95ec9d6a6ab3117d60ff638670a803d43974ba51 --- runtime/doc/options.txt | 16 +++++++++++----- runtime/optwin.vim | 3 +++ src/nvim/buffer_defs.h | 2 ++ src/nvim/edit.c | 2 +- src/nvim/move.c | 3 ++- src/nvim/option.c | 23 ++++++++++++++++++++++- src/nvim/option_defs.h | 1 + src/nvim/options.lua | 8 ++++++++ src/nvim/screen.c | 17 ++++------------- src/nvim/version.c | 2 +- 10 files changed, 55 insertions(+), 22 deletions(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 7cfc55ed79..20d46a9f0c 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -246,10 +246,10 @@ global value, which is used for new buffers. With ":set" both the local and global value is changed. With "setlocal" only the local value is changed, thus this value is not used when editing a new buffer. -When editing a buffer that has been edited before, the last used window -options are used again. If this buffer has been edited in this window, the -values from back then are used. Otherwise the values from the window where -the buffer was edited last are used. +When editing a buffer that has been edited before, the options from the window +that was last closed are used again. If this buffer has been edited in this +window, the values from back then are used. Otherwise the values from the +last closed window where the buffer was edited last are used. It's possible to set a local window option specifically for a type of buffer. When you edit another buffer in the same window, you don't want to keep @@ -5624,10 +5624,16 @@ A jump table for the options with a short description can be found at |Q_op|. Example: Try this together with 'sidescroll' and 'listchars' as in the following example to never allow the cursor to move - onto the "extends" character: + onto the "extends" character: > :set nowrap sidescroll=1 listchars=extends:>,precedes:< :set sidescrolloff=1 +< + *'signcolumn'* *'scl'* +'signcolumn' 'scl' string (default "auto") + local to window + Whether or not to draw the signcolumn. "auto" means it will only be + drawn when there is a sign to display. *'smartcase'* *'scs'* *'nosmartcase'* *'noscs'* diff --git a/runtime/optwin.vim b/runtime/optwin.vim index 3d585267d7..b8a2636d4d 100644 --- a/runtime/optwin.vim +++ b/runtime/optwin.vim @@ -1250,6 +1250,9 @@ call append("$", "\t(local to buffer)") call BinOptionL("bl") call append("$", "debug\tset to \"msg\" to see all error messages") call append("$", " \tset debug=" . &debug) +call append("$", "signcolumn\twhether to show the signcolumn") +call append("$", "\t(local to window)") +call OptionL("scl") set cpo&vim diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 0418a737eb..fda906fc59 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -237,6 +237,8 @@ typedef struct { # define w_p_crb w_onebuf_opt.wo_crb /* 'cursorbind' */ int wo_crb_save; /* 'cursorbind' state saved for diff mode*/ # define w_p_crb_save w_onebuf_opt.wo_crb_save + char_u *wo_scl; +# define w_p_scl w_onebuf_opt.wo_scl /* 'signcolumn' */ int wo_scriptID[WV_COUNT]; /* SIDs for window-local options */ # define w_p_scriptID w_onebuf_opt.wo_scriptID diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 7e917336e5..bb946337b5 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -5708,7 +5708,7 @@ comp_textwidth ( textwidth -= 1; textwidth -= curwin->w_p_fdc; - if (curwin->w_buffer->b_signlist != NULL) { + if (signcolumn_on(curwin)) { textwidth -= 1; } diff --git a/src/nvim/move.c b/src/nvim/move.c index 4c814f3ae0..4e7fe86adc 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -24,6 +24,7 @@ #include "nvim/mbyte.h" #include "nvim/memline.h" #include "nvim/misc1.h" +#include "nvim/option.h" #include "nvim/popupmnu.h" #include "nvim/screen.h" #include "nvim/strings.h" @@ -669,7 +670,7 @@ int win_col_off(win_T *wp) return ((wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) + 1 : 0) + (cmdwin_type == 0 || wp != curwin ? 0 : 1) + (int)wp->w_p_fdc - + (wp->w_buffer->b_signlist != NULL ? 2 : 0) + + (signcolumn_on(wp) ? 2 : 0) ; } diff --git a/src/nvim/option.c b/src/nvim/option.c index 797dd1dfe7..2249ef6e95 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -289,6 +289,7 @@ static char *(p_fcl_values[]) = { "all", NULL }; static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview", "noinsert", "noselect", NULL }; static char *(p_icm_values[]) = { "nosplit", "split", NULL }; +static char *(p_scl_values[]) = { "yes", "no", "auto", NULL }; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "option.c.generated.h" @@ -3008,6 +3009,12 @@ did_set_string_option ( completeopt_was_set(); } } + /* 'signcolumn' */ + else if (varp == &curwin->w_p_scl) { + if (check_opt_strings(*varp, p_scl_values, false) != OK) { + errmsg = e_invarg; + } + } /* 'pastetoggle': translate key codes like in a mapping */ else if (varp == &p_pt) { if (*p_pt) { @@ -4782,7 +4789,6 @@ static int find_key_option(const char_u *arg) return find_key_option_len(arg, STRLEN(arg)); } - /* * if 'all' == 0: show changed options * if 'all' == 1: show all normal options @@ -5428,6 +5434,7 @@ static char_u *get_varp(vimoption_T *p) case PV_UDF: return (char_u *)&(curbuf->b_p_udf); case PV_WM: return (char_u *)&(curbuf->b_p_wm); case PV_KMAP: return (char_u *)&(curbuf->b_p_keymap); + case PV_SCL: return (char_u *)&(curwin->w_p_scl); default: EMSG(_("E356: get_varp ERROR")); } /* always return a valid pointer to avoid a crash! */ @@ -5505,6 +5512,7 @@ void copy_winopt(winopt_T *from, winopt_T *to) to->wo_fde = vim_strsave(from->wo_fde); to->wo_fdt = vim_strsave(from->wo_fdt); to->wo_fmr = vim_strsave(from->wo_fmr); + to->wo_scl = vim_strsave(from->wo_scl); check_winopt(to); /* don't want NULL pointers */ } @@ -5528,6 +5536,7 @@ static void check_winopt(winopt_T *wop) check_string_option(&wop->wo_fde); check_string_option(&wop->wo_fdt); check_string_option(&wop->wo_fmr); + check_string_option(&wop->wo_scl); check_string_option(&wop->wo_rlc); check_string_option(&wop->wo_stl); check_string_option(&wop->wo_cc); @@ -5546,6 +5555,7 @@ void clear_winopt(winopt_T *wop) clear_string_option(&wop->wo_fde); clear_string_option(&wop->wo_fdt); clear_string_option(&wop->wo_fmr); + clear_string_option(&wop->wo_scl); clear_string_option(&wop->wo_rlc); clear_string_option(&wop->wo_stl); clear_string_option(&wop->wo_cc); @@ -6902,3 +6912,14 @@ int csh_like_shell(void) return strstr((char *)path_tail(p_sh), "csh") != NULL; } +/// Return true when window "wp" has a column to draw signs in. +bool signcolumn_on(win_T *wp) +{ + if (*wp->w_p_scl == 'n') { + return false; + } + if (*wp->w_p_scl == 'y') { + return true; + } + return wp->w_buffer->b_signlist != NULL; +} diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 6e89a093c8..82c618cf6f 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -799,6 +799,7 @@ enum { , WV_WFH , WV_WFW , WV_WRAP + , WV_SCL , WV_COUNT /* must be the last one */ }; diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 14707aaa6c..70d1f73cf4 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -2169,6 +2169,14 @@ return { varname='p_siso', defaults={if_true={vi=0}} }, + { + full_name='signcolumn', abbreviation='scl', + type='string', scope={'window'}, + vi_def=true, + alloced=true, + redraw={'current_window'}, + defaults={if_true={vi="auto"}} + }, { full_name='smartcase', abbreviation='scs', type='bool', scope={'global'}, diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 50517d2829..72549f1f21 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -575,15 +575,6 @@ void update_debug_sign(buf_T *buf, linenr_T lnum) update_finish(); } -/* - * Return TRUE when window "wp" has a column to draw signs in. - */ -static int draw_signcolumn(win_T *wp) -{ - return (wp->w_buffer->b_signlist != NULL); -} - - /* * Update a single window. * @@ -1598,7 +1589,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h ' ', ' ', hl_attr(HLF_FC)); } - if (draw_signcolumn(wp)) { + if (signcolumn_on(wp)) { int nn = n + 2; /* draw the sign column left of the fold column */ @@ -1639,7 +1630,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h n = nn; } - if (draw_signcolumn(wp)) + if (signcolumn_on(wp)) { int nn = n + 2; @@ -1753,7 +1744,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T RL_MEMSET(col, hl_attr(HLF_FL), wp->w_width - col); /* If signs are being displayed, add two spaces. */ - if (draw_signcolumn(wp)) { + if (signcolumn_on(wp)) { len = wp->w_width - col; if (len > 0) { if (len > 2) { @@ -2701,7 +2692,7 @@ win_line ( draw_state = WL_SIGN; /* Show the sign column when there are any signs in this * buffer or when using Netbeans. */ - if (draw_signcolumn(wp)) { + if (signcolumn_on(wp)) { int text_sign; /* Draw two cells with the sign value or blank. */ c_extra = ' '; diff --git a/src/nvim/version.c b/src/nvim/version.c index d146d8ff67..e89bc49210 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -239,7 +239,7 @@ static int included_patches[] = { // 2204, // 2203 NA // 2202 NA - // 2201, + 2201, // 2200, // 2199 NA // 2198, From 00466410701802214aba5c95f1cbb2e5086a37f5 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 15 Nov 2016 12:06:10 -0500 Subject: [PATCH 05/14] vim-patch:7.4.2204 Problem: It is not easy to get information about buffers, windows and tabpages. Solution: Add getbufinfo(), getwininfo() and gettabinfo(). (Yegappan Lakshmanan) https://github.com/vim/vim/commit/b5ae48e9ffd3b8eb6ca4057de11f1bddcde8ce6f --- runtime/doc/eval.txt | 84 ++++++++ runtime/doc/usr_41.txt | 5 +- src/nvim/eval.c | 256 ++++++++++++++++++++++++ src/nvim/eval.lua | 3 + src/nvim/option.c | 25 +++ src/nvim/testdir/Makefile | 1 + src/nvim/testdir/test_bufwintabinfo.vim | 38 ++++ src/nvim/version.c | 2 +- src/nvim/window.c | 13 ++ 9 files changed, 425 insertions(+), 2 deletions(-) create mode 100644 src/nvim/testdir/test_bufwintabinfo.vim diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 367f64df9b..9e08c64de9 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1956,6 +1956,7 @@ garbagecollect([{atexit}]) none free memory, breaking cyclic references get({list}, {idx} [, {def}]) any get item {idx} from {list} or {def} get({dict}, {key} [, {def}]) any get item {key} from {dict} or {def} get({func}, {what}) any get property of funcref/partial {func} +getbufinfo( [{expr}]) List information about buffers getbufline({expr}, {lnum} [, {end}]) List lines {lnum} to {end} of buffer {expr} getbufvar({expr}, {varname} [, {def}]) @@ -1986,10 +1987,12 @@ getqflist() List list of quickfix items getreg([{regname} [, 1 [, {list}]]]) String or List contents of register getregtype([{regname}]) String type of register +gettabinfo( [{expr}]) List list of tab pages gettabvar({nr}, {varname} [, {def}]) any variable {varname} in tab {nr} or {def} gettabwinvar({tabnr}, {winnr}, {name} [, {def}]) any {name} in {winnr} in tab page {tabnr} +getwininfo( [{winid}]) List list of windows getwinposx() Number X coord in pixels of GUI Vim window getwinposy() Number Y coord in pixels of GUI Vim window getwinvar({nr}, {varname} [, {def}]) @@ -3593,6 +3596,55 @@ get({func}, {what}) 'dict' The dictionary 'args' The list with arguments + *getbufinfo()* +getbufinfo([{expr}]) +getbufinfo([{dict}]) + Get information about buffers as a List of Dictionaries. + + Without an argument information about all the buffers is + returned. + + When the argument is a Dictionary only the buffers matching + the specified criteria are returned. The following keys can + be specified in {dict}: + buflisted include only listed buffers. + bufloaded include only loaded buffers. + + Otherwise, {expr} specifies a particular buffer to return + information for. For the use of {expr}, see |bufname()| + above. If the buffer is found the returned List has one item. + Otherwise the result is an empty list. + + Each returned List item is a dictionary with the following + entries: + changed TRUE if the buffer is modified. + changedtick number of changes made to the buffer. + hidden TRUE if the buffer is hidden. + listed TRUE if the buffer is listed. + lnum current line number in buffer. + loaded TRUE if the buffer is loaded. + name full path to the file in the buffer. + nr buffer number. + options dictionary of buffer local options. + signs list of signs placed in the buffer. + Each list item is a dictionary with + the following fields: + id sign identifier + lnum line number + name sign name + variables dictionary of buffer local variables. + windows list of window IDs with this buffer + + Examples: > + for buf in getbufinfo() + echo buf.name + endfor + for buf in getbufinfo({'buflisted':1}) + if buf.options.filetype == 'java' + .... + endif + endfor +< *getbufline()* getbufline({expr}, {lnum} [, {end}]) Return a |List| with the lines starting from {lnum} to {end} @@ -4050,6 +4102,18 @@ getregtype([{regname}]) *getregtype()* is one character with value 0x16. If {regname} is not specified, |v:register| is used. +gettabinfo([{arg}]) *gettabinfo()* + If {arg} is not specified, then information about all the tab + pages is returned as a List. Each List item is a Dictionary. + Otherwise, {arg} specifies the tab page number and information + about that one is returned. If the tab page does not exist an + empty List is returned. + + Each List item is a Dictionary with the following entries: + nr tab page number. + windows List of window IDs in the tag page. + variables dictionary of tabpage local variables. + gettabvar({tabnr}, {varname} [, {def}]) *gettabvar()* Get the value of a tab-local variable {varname} in tab page {tabnr}. |t:var| @@ -4091,6 +4155,26 @@ getwinposy() The result is a Number, which is the Y coordinate in pixels of the top of the GUI Vim window. The result will be -1 if the information is not available. +getwininfo([{winid}]) *getwininfo()* + Returns information about windows as a List with Dictionaries. + + If {winid} is given Information about the window with that ID + is returned. If the window does not exist the result is an + empty list. + + Without an information about all the windows in all the tab + pages is returned. + + Each List item is a Dictionary with the following entries: + nr window number. + tpnr tab page number. + winid window ID. + height window height. + width window width. + bufnum number of buffer in the window. + options dictionary of window local options. + variables dictionary of window local variables. + getwinvar({winnr}, {varname} [, {def}]) *getwinvar()* Like |gettabwinvar()| for the current tabpage. Examples: > diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt index 2896611274..49fcdf0bb7 100644 --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -1,4 +1,4 @@ -*usr_41.txt* For Vim version 7.4. Last change: 2016 Apr 12 +*usr_41.txt* For Vim version 7.4. Last change: 2016 Aug 07 VIM USER MANUAL - by Bram Moolenaar @@ -789,6 +789,9 @@ Buffers, windows and the argument list: bufwinnr() get the window number of a specific buffer winbufnr() get the buffer number of a specific window getbufline() get a list of lines from the specified buffer + getbufinfo() get a list with buffer information + gettabinfo() get a list with tab page information + getwininfo() get a list with window information Command line: *command-line-functions* getcmdline() get the current command line diff --git a/src/nvim/eval.c b/src/nvim/eval.c index bdbd77337d..91f7233a21 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6611,6 +6611,23 @@ int dict_add_list(dict_T *d, char *key, list_T *list) return OK; } +/// Add a dict entry to dictionary "d". +/// Returns FAIL when out of memory and when key already exists. +int dict_add_dict(dict_T *d, char *key, dict_T *dict) +{ + dictitem_T *item = dictitem_alloc((char_u *)key); + + item->di_tv.v_lock = 0; + item->di_tv.v_type = VAR_DICT; + item->di_tv.vval.v_dict = dict; + if (dict_add(d, item) == FAIL) { + dictitem_free(item); + return FAIL; + } + dict->dv_refcount++; + return OK; +} + /// Set all existing keys in "dict" as read-only. /// /// This does not protect against adding new keys to the Dictionary. @@ -9832,6 +9849,127 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) copy_tv(tv, rettv); } +/// Returns information about signs placed in a buffer as list of dicts. +static void get_buffer_signs(buf_T *buf, list_T *l) +{ + for (signlist_T *sign = buf->b_signlist; sign; sign = sign->next) { + dict_T *d = dict_alloc(); + + dict_add_nr_str(d, "id", sign->id, NULL); + dict_add_nr_str(d, "lnum", sign->lnum, NULL); + dict_add_nr_str(d, "name", 0L, vim_strsave(sign_typenr2name(sign->typenr))); + + list_append_dict(l, d); + } +} + +/// Returns buffer options, variables and other attributes in a dictionary. +static dict_T *get_buffer_info(buf_T *buf) +{ + dict_T *dict = dict_alloc(); + + dict_add_nr_str(dict, "nr", buf->b_fnum, NULL); + dict_add_nr_str(dict, "name", 0L, + buf->b_ffname != NULL ? buf->b_ffname : (char_u *)""); + dict_add_nr_str(dict, "lnum", buflist_findlnum(buf), NULL); + dict_add_nr_str(dict, "loaded", buf->b_ml.ml_mfp != NULL, NULL); + dict_add_nr_str(dict, "listed", buf->b_p_bl, NULL); + dict_add_nr_str(dict, "changed", bufIsChanged(buf), NULL); + dict_add_nr_str(dict, "changedtick", buf->b_changedtick, NULL); + dict_add_nr_str(dict, "hidden", + buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0, + NULL); + + // Copy buffer variables + dict_T *vars = dict_copy(NULL, buf->b_vars, true, 0); + if (vars != NULL) { + dict_add_dict(dict, "variables", vars); + } + + // Copy buffer options + dict_T *opts = get_winbuf_options(true); + if (opts != NULL) { + dict_add_dict(dict, "options", opts); + } + + // List of windows displaying this buffer + list_T *windows = list_alloc(); + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (wp->w_buffer == buf) { + list_append_number(windows, (varnumber_T)wp->handle); + } + } + dict_add_list(dict, "windows", windows); + + if (buf->b_signlist != NULL) { + // List of signs placed in this buffer + list_T *signs = list_alloc(); + get_buffer_signs(buf, signs); + dict_add_list(dict, "signs", signs); + } + + return dict; +} + +/// "getbufinfo()" function +static void f_getbufinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + buf_T *argbuf = NULL; + bool filtered = false; + bool sel_buflisted = false; + bool sel_bufloaded = false; + + rettv_list_alloc(rettv); + + // List of all the buffers or selected buffers + if (argvars[0].v_type == VAR_DICT) { + dict_T *sel_d = argvars[0].vval.v_dict; + + if (sel_d != NULL) { + dictitem_T *di; + + filtered = true; + + di = dict_find(sel_d, (char_u *)"buflisted", -1); + if (di != NULL && get_tv_number(&di->di_tv)) { + sel_buflisted = true; + } + + di = dict_find(sel_d, (char_u *)"bufloaded", -1); + if (di != NULL && get_tv_number(&di->di_tv)) { + sel_bufloaded = true; + } + } + } else if (argvars[0].v_type != VAR_UNKNOWN) { + // Information about one buffer. Argument specifies the buffer + (void)get_tv_number(&argvars[0]); // issue errmsg if type error + emsg_off++; + argbuf = get_buf_tv(&argvars[0], false); + emsg_off--; + if (argbuf == NULL) { + return; + } + } + + // Return information about all the buffers or a specified buffer + FOR_ALL_BUFFERS(buf) { + if (argbuf != NULL && argbuf != buf) { + continue; + } + if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL) + || (sel_buflisted && !buf->b_p_bl))) { + continue; + } + + dict_T *d = get_buffer_info(buf); + if (d != NULL) { + list_append_dict(rettv->vval.v_list, d); + } + if (argbuf != NULL) { + return; + } + } +} /* * Get line or list of lines from buffer "buf" into "rettv". @@ -10654,6 +10792,60 @@ static void f_getregtype(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_string = (char_u *)xstrdup(buf); } +/// Returns information (variables, options, etc.) about a tab page +/// as a dictionary. +static dict_T *get_tabpage_info(tabpage_T *tp, int tp_idx) +{ + dict_T *dict = dict_alloc(); + + dict_add_nr_str(dict, "nr", tp_idx, NULL); + + list_T *l = list_alloc(); + FOR_ALL_WINDOWS_IN_TAB(wp, tp) { + list_append_number(l, (varnumber_T)wp->handle); + } + dict_add_list(dict, "windows", l); + + // Copy tabpage variables + dict_T *vars = dict_copy(NULL, tp->tp_vars, true, 0); + if (vars != NULL) { + dict_add_dict(dict, "variables", vars); + } + + return dict; +} + +/// "gettabinfo()" function +static void f_gettabinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + tabpage_T *tparg = NULL; + + rettv_list_alloc(rettv); + + if (argvars[0].v_type != VAR_UNKNOWN) { + // Information about one tab page + tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); + if (tparg == NULL) + return; + } + + // Get information about a specific tab page or all tab pages + int tpnr = 0; + FOR_ALL_TABS(tp) { + tpnr++; + if (tparg != NULL && tp != tparg) { + continue; + } + dict_T *d = get_tabpage_info(tp, tpnr); + if (d != NULL) { + list_append_dict(rettv->vval.v_list, d); + } + if (tparg != NULL) { + return; + } + } +} + /* * "gettabvar()" function */ @@ -10701,6 +10893,70 @@ static void f_gettabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) getwinvar(argvars, rettv, 1); } +/// Returns information about a window as a dictionary. +static dict_T *get_win_info(win_T *wp, short tpnr, short winnr) +{ + dict_T *dict = dict_alloc(); + + dict_add_nr_str(dict, "tpnr", tpnr, NULL); + dict_add_nr_str(dict, "nr", winnr, NULL); + dict_add_nr_str(dict, "winid", wp->handle, NULL); + dict_add_nr_str(dict, "height", wp->w_height, NULL); + dict_add_nr_str(dict, "width", wp->w_width, NULL); + dict_add_nr_str(dict, "bufnum", wp->w_buffer->b_fnum, NULL); + + // Copy window variables + dict_T *vars = dict_copy(NULL, wp->w_vars, true, 0); + if (vars != NULL) { + dict_add_dict(dict, "variables", vars); + } + + // Copy window options + dict_T *opts = get_winbuf_options(false); + if (opts != NULL) { + dict_add_dict(dict, "options", opts); + } + + return dict; +} + +/// "getwininfo()" function +static void f_getwininfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + win_T *wparg = NULL; + + rettv_list_alloc(rettv); + + if (argvars[0].v_type != VAR_UNKNOWN) { + wparg = win_id2wp(argvars); + if (wparg == NULL) { + return; + } + } + + // Collect information about either all the windows across all the tab + // pages or one particular window. + short tabnr = 0; + FOR_ALL_TABS(tp) { + tabnr++; + short winnr = 0; + FOR_ALL_WINDOWS_IN_TAB(wp, tp) { + if (wparg != NULL && wp != wparg) { + continue; + } + winnr++; + dict_T *d = get_win_info(wp, tabnr, winnr); + if (d != NULL) { + list_append_dict(rettv->vval.v_list, d); + } + if (wparg != NULL) { + // found information about a specific window + return; + } + } + } +} + /* * "getwinposx()" function */ diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index a0671cac1f..980a8d2326 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -106,6 +106,7 @@ return { ['function']={args={1, 3}}, garbagecollect={args={0, 1}}, get={args={2, 3}}, + getbufinfo={args={0, 1}}, getbufline={args={2, 3}}, getbufvar={args={2, 3}}, getchar={args={0, 1}}, @@ -131,8 +132,10 @@ return { getqflist={}, getreg={args={0, 3}}, getregtype={args={0, 1}}, + gettabinfo={args={0, 1}}, gettabvar={args={2, 3}}, gettabwinvar={args={3, 4}}, + getwininfo={args={0, 1}}, getwinposx={}, getwinposy={}, getwinvar={args={2, 3}}, diff --git a/src/nvim/option.c b/src/nvim/option.c index 2249ef6e95..817e35d550 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -6923,3 +6923,28 @@ bool signcolumn_on(win_T *wp) } return wp->w_buffer->b_signlist != NULL; } + +/// Get window or buffer local options. +dict_T * get_winbuf_options(int bufopt) +{ + dict_T *d = dict_alloc(); + + for (int opt_idx = 0; options[opt_idx].fullname; opt_idx++) { + struct vimoption *opt = &options[opt_idx]; + + if ((bufopt && (opt->indir & PV_BUF)) + || (!bufopt && (opt->indir & PV_WIN))) { + char_u *varp = get_varp(opt); + + if (varp != NULL) { + if (opt->flags & P_STRING) { + dict_add_nr_str(d, opt->fullname, 0L, *(char_u **)varp); + } else { + dict_add_nr_str(d, opt->fullname, *varp, NULL); + } + } + } + } + + return d; +} diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index e27be54fc9..84a0c0b889 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -30,6 +30,7 @@ SCRIPTS := \ # Tests using runtest.vim.vim. # Keep test_alot*.res as the last one, sort the others. NEW_TESTS = \ + test_bufwintabinfo.res \ test_cmdline.res \ test_cscope.res \ test_diffmode.res \ diff --git a/src/nvim/testdir/test_bufwintabinfo.vim b/src/nvim/testdir/test_bufwintabinfo.vim new file mode 100644 index 0000000000..236ca30f99 --- /dev/null +++ b/src/nvim/testdir/test_bufwintabinfo.vim @@ -0,0 +1,38 @@ +" Tests for the getbufinfo(), getwininfo() and gettabinfo() functions + +function Test_getbufwintabinfo() + 1,$bwipeout + edit Xtestfile1 + edit Xtestfile2 + let buflist = getbufinfo() + call assert_equal(2, len(buflist)) + call assert_match('Xtestfile1', buflist[0].name) + call assert_match('Xtestfile2', getbufinfo('Xtestfile2')[0].name) + call assert_equal([], getbufinfo(2016)) + edit Xtestfile1 + hide edit Xtestfile2 + hide enew + call assert_equal(3, len(getbufinfo({'bufloaded':1}))) + + only + let w1_id = win_getid() + new + let w2_id = win_getid() + tabnew | let w3_id = win_getid() + new | let w4_id = win_getid() + new | let w5_id = win_getid() + tabfirst + let winlist = getwininfo() + call assert_equal(5, len(winlist)) + call assert_equal(2, winlist[3].tpnr) + let winfo = getwininfo(w5_id)[0] + call assert_equal(2, winfo.tpnr) + call assert_equal([], getwininfo(3)) + + let tablist = gettabinfo() + call assert_equal(2, len(tablist)) + call assert_equal(3, len(tablist[1].windows)) + call assert_equal([], gettabinfo(3)) + + tabonly | only +endfunction diff --git a/src/nvim/version.c b/src/nvim/version.c index e89bc49210..b1bb9f02f4 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -236,7 +236,7 @@ static int included_patches[] = { // 2207 NA // 2206 NA 2205, - // 2204, + 2204, // 2203 NA // 2202 NA 2201, diff --git a/src/nvim/window.c b/src/nvim/window.c index 3e7aed7867..00229ccca9 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -5797,6 +5797,19 @@ void win_id2tabwin(typval_T *argvars, list_T *list) list_append_number(list, winnr); } +win_T * win_id2wp(typval_T *argvars) +{ + int id = get_tv_number(&argvars[0]); + + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (wp->handle == id) { + return wp; + } + } + + return NULL; +} + int win_id2win(typval_T *argvars) { win_T *wp; From 6205846cd969bf6bafc933cb295c4cef819b9e84 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 15 Nov 2016 16:03:30 -0500 Subject: [PATCH 06/14] vim-patch:0952131 Updated runtime files. https://github.com/vim/vim/commit/0952131376a517fc12dc5ae908a97018b4ee23f0 --- runtime/doc/editing.txt | 12 ++- runtime/doc/options.txt | 6 +- runtime/doc/quickref.txt | 3 +- runtime/doc/sign.txt | 8 +- runtime/doc/syntax.txt | 4 +- runtime/indent/javascript.vim | 194 ++++++++++++++++++++++++++++++++-- runtime/optwin.vim | 2 +- runtime/syntax/dockerfile.vim | 8 +- runtime/syntax/sshconfig.vim | 6 +- 9 files changed, 214 insertions(+), 29 deletions(-) diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt index 8b6c14cc52..06dd21de06 100644 --- a/runtime/doc/editing.txt +++ b/runtime/doc/editing.txt @@ -1,4 +1,4 @@ -*editing.txt* For Vim version 7.4. Last change: 2016 Mar 28 +*editing.txt* For Vim version 7.4. Last change: 2016 Aug 06 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1046,10 +1046,12 @@ The names can be in upper- or lowercase. edited. See |:confirm| and 'confirm'. :q[uit]! Quit without writing, also when the current buffer has - changes. If this is the last window and there is a - modified hidden buffer, the current buffer is - abandoned and the first changed hidden buffer becomes - the current buffer. + changes. The buffer is unloaded, also when it has + 'hidden' set. + If this is the last window and there is a modified + hidden buffer, the current buffer is abandoned and the + first changed hidden buffer becomes the current + buffer. Use ":qall!" to exit always. :cq[uit] Quit always, without writing, and return an error diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 20d46a9f0c..e15fb9dc84 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -5632,8 +5632,10 @@ A jump table for the options with a short description can be found at |Q_op|. *'signcolumn'* *'scl'* 'signcolumn' 'scl' string (default "auto") local to window - Whether or not to draw the signcolumn. "auto" means it will only be - drawn when there is a sign to display. + Whether or not to draw the signcolumn. Valid values are: + "auto" only when there is a sign to display + "no" never + "yes" always *'smartcase'* *'scs'* *'nosmartcase'* *'noscs'* diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt index fcfecc02a1..2b5ed33f06 100644 --- a/runtime/doc/quickref.txt +++ b/runtime/doc/quickref.txt @@ -1,4 +1,4 @@ -*quickref.txt* For Vim version 7.4. Last change: 2016 Mar 30 +*quickref.txt* For Vim version 7.4. Last change: 2016 Aug 12 VIM REFERENCE MANUAL by Bram Moolenaar @@ -861,6 +861,7 @@ Short explanation of each option: *option-list* 'showtabline' 'stal' tells when the tab pages line is displayed 'sidescroll' 'ss' minimum number of columns to scroll horizontal 'sidescrolloff' 'siso' min. nr. of columns to left and right of cursor +'signcolumn' 'scl' when to display the sign column 'smartcase' 'scs' no ignore case when pattern has uppercase 'smartindent' 'si' smart autoindenting for C programs 'smarttab' 'sta' use 'shiftwidth' when inserting diff --git a/runtime/doc/sign.txt b/runtime/doc/sign.txt index 44a5361c5d..fd1fe8dce3 100644 --- a/runtime/doc/sign.txt +++ b/runtime/doc/sign.txt @@ -1,4 +1,4 @@ -*sign.txt* For Vim version 7.4. Last change: 2014 May 07 +*sign.txt* For Vim version 7.4. Last change: 2016 Aug 12 VIM REFERENCE MANUAL by Gordon Prieur @@ -40,8 +40,10 @@ There are two steps in using signs: When signs are defined for a file, Vim will automatically add a column of two characters to display them in. When the last sign is unplaced the column -disappears again. The color of the column is set with the SignColumn group -|hl-SignColumn|. Example to set the color: > +disappears again. This behavior can be changed with the 'signcolumn' option. + +The color of the column is set with the SignColumn group |hl-SignColumn|. +Example to set the color: > :highlight SignColumn guibg=darkgrey diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index 4030c7a681..4886828c82 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -1,4 +1,4 @@ -*syntax.txt* For Vim version 7.4. Last change: 2016 Apr 10 +*syntax.txt* For Vim version 7.4. Last change: 2016 Aug 10 VIM REFERENCE MANUAL by Bram Moolenaar @@ -944,6 +944,8 @@ Variable Highlight ~ *c_no_bracket_error* don't highlight {}; inside [] as errors *c_no_curly_error* don't highlight {}; inside [] and () as errors; except { and } in first column + Default is to highlight them, otherwise you + can't spot a missing ")". *c_curly_error* highlight a missing }; this forces syncing from the start of the file, can be slow *c_no_ansi* don't do standard ANSI types and constants diff --git a/runtime/indent/javascript.vim b/runtime/indent/javascript.vim index 21c8fff86c..3507e305ed 100644 --- a/runtime/indent/javascript.vim +++ b/runtime/indent/javascript.vim @@ -1,18 +1,192 @@ " Vim indent file -" Language: Javascript -" Maintainer: Going to be Darrick Wiebe -" Last Change: 2015 Jun 09 +" Language: Javascript +" Maintainer: vim-javascript community +" URL: https://github.com/pangloss/vim-javascript +" Last Change: August 12, 2016 " Only load this indent file when no other was loaded. -if exists("b:did_indent") - finish +if exists('b:did_indent') + finish endif let b:did_indent = 1 -" C indenting is not too bad. -setlocal cindent +" Now, set up our indentation expression and keys that trigger it. +setlocal indentexpr=GetJavascriptIndent() +setlocal nolisp +setlocal indentkeys=0{,0},0),0],:,!^F,o,O,e setlocal cinoptions+=j1,J1 -setlocal cinkeys-=0# -setlocal cinkeys+=0] -let b:undo_indent = "setl cin<" +let b:undo_indent = 'setlocal indentexpr< indentkeys< cinoptions<' + +" Only define the function once. +if exists('*GetJavascriptIndent') + finish +endif + +let s:cpo_save = &cpo +set cpo&vim + +" Get shiftwidth value +if exists('*shiftwidth') + function s:sw() + return shiftwidth() + endfunction +else + function s:sw() + return &sw + endfunction +endif + +let s:line_pre = '^\s*\%(\/\*.\{-}\*\/\s*\)*' +let s:expr_case = s:line_pre . '\%(\%(case\>.\+\)\|default\)\s*:' +" Regex of syntax group names that are or delimit string or are comments. +let s:syng_strcom = '\%(s\%(tring\|pecial\)\|comment\|regex\|doc\|template\)' + +" Regex of syntax group names that are strings or documentation. +let s:syng_comment = '\%(comment\|doc\)' + +" Expression used to check whether we should skip a match with searchpair(). +let s:skip_expr = "line('.') < (prevnonblank(v:lnum) - 2000) ? dummy : synIDattr(synID(line('.'),col('.'),0),'name') =~? '".s:syng_strcom."'" + +function s:lookForParens(start,end,flags,time) + if has('reltime') + return searchpair(a:start,'',a:end,a:flags,s:skip_expr,0,a:time) + else + return searchpair(a:start,'',a:end,a:flags,0,0) + endif +endfunction + +let s:line_term = '\%(\s*\%(\/\*.\{-}\*\/\s*\)\=\)\@>$' + +" configurable regexes that define continuation lines, not including (, {, or [. +if !exists('g:javascript_opfirst') + let g:javascript_opfirst = '\%([<>,:?^%]\|\([-/.+]\)\%(\1\|\*\|\/\)\@!\|\*\/\@!\|=>\@!\||\|&\|in\%(stanceof\)\=\>\)' +endif +let g:javascript_opfirst = s:line_pre . g:javascript_opfirst + +if !exists('g:javascript_continuation') + let g:javascript_continuation = '\%([<*,.?:^%]\|+\@\|\*\@' . (a:add ? '\|\ -1) && + \ s:lookForParens('(', ')', 'cbW', 100) > 0 && search((a:add ? + \ '\%(function\*\|[[:lower:][:upper:]_$][[:digit:][:lower:][:upper:]_$]*\)' : + \ '\<\%(for\%(\s\+each\)\=\|if\|let\|w\%(hile\|ith\)\)') . '\_s*\%#\C','bW') && + \ (a:add || (expand('') ==# 'while' ? !s:lookForParens('\\C', '\\C','bW',100) : 1)) +endfunction + +" Auxiliary Functions {{{2 + +" strip line of comment +function s:StripLine(c) + return a:c !~# s:expr_case ? substitute(a:c, '\%(:\@ 0 + if synIDattr(synID(l:lnum,matchend(getline(l:lnum), '^\s*[^''"]'),0),'name') !~? s:syng_strcom + break + endif + let l:lnum = prevnonblank(l:lnum - 1) + endwhile + return l:lnum +endfunction + +" Check if line 'lnum' has a balanced amount of parentheses. +function s:Balanced(lnum) + let open_0 = 0 + let open_2 = 0 + let open_4 = 0 + let l:line = getline(a:lnum) + let pos = match(l:line, '[][(){}]', 0) + while pos != -1 + if synIDattr(synID(a:lnum,pos + 1,0),'name') !~? s:syng_strcom + let idx = stridx('(){}[]', l:line[pos]) + if idx % 2 == 0 + let open_{idx} = open_{idx} + 1 + else + let open_{idx - 1} = open_{idx - 1} - 1 + endif + endif + let pos = match(l:line, '[][(){}]', pos + 1) + endwhile + return (!open_4 + !open_2 + !open_0) - 2 +endfunction +" }}} + +function GetJavascriptIndent() + if !exists('b:js_cache') + let b:js_cache = [0,0,0] + endif + " Get the current line. + let l:line = getline(v:lnum) + let syns = synIDattr(synID(v:lnum, 1, 0), 'name') + + " start with strings,comments,etc.{{{2 + if (l:line !~ '^[''"`]' && syns =~? 'string\|template') || + \ (l:line !~ '^\s*[/*]' && syns =~? s:syng_comment) + return -1 + endif + if l:line !~ '^\%(\/\*\|\s*\/\/\)' && syns =~? s:syng_comment + return cindent(v:lnum) + endif + let l:lnum = s:PrevCodeLine(v:lnum - 1) + if l:lnum == 0 + return 0 + endif + + if (l:line =~# s:expr_case) + let cpo_switch = &cpo + set cpo+=% + let ind = cindent(v:lnum) + let &cpo = cpo_switch + return ind + endif + "}}} + + " the containing paren, bracket, curly. Memoize, last lineNr either has the + " same scope or starts a new one, unless if it closed a scope. + call cursor(v:lnum,1) + if b:js_cache[0] >= l:lnum && b:js_cache[0] <= v:lnum && b:js_cache[0] && + \ (b:js_cache[0] > l:lnum || s:Balanced(l:lnum) > 0) + let num = b:js_cache[1] + elseif syns != '' && l:line[0] =~ '\s' + let pattern = syns =~? 'block' ? ['{','}'] : syns =~? 'jsparen' ? ['(',')'] : + \ syns =~? 'jsbracket'? ['\[','\]'] : ['[({[]','[])}]'] + let num = s:lookForParens(pattern[0],pattern[1],'bW',2000) + else + let num = s:lookForParens('[({[]','[])}]','bW',2000) + endif + let b:js_cache = [v:lnum,num,line('.') == v:lnum ? b:js_cache[2] : col('.')] + + if l:line =~ s:line_pre . '[])}]' + return indent(num) + endif + + let pline = s:StripLine(getline(l:lnum)) + let inb = num == 0 ? 1 : (s:Onescope(num, s:StripLine(strpart(getline(num),0,b:js_cache[2] - 1)),1) || + \ (l:line !~ s:line_pre . ',' && pline !~ ',' . s:line_term)) && num < l:lnum + let switch_offset = (!inb || num == 0) || expand("") !=# 'switch' ? 0 : &cino !~ ':' || !has('float') ? s:sw() : + \ float2nr(str2float(matchstr(&cino,'.*:\zs[-0-9.]*')) * (&cino =~# '.*:[^,]*s' ? s:sw() : 1)) + + " most significant, find the indent amount + if (inb && (l:line =~# g:javascript_opfirst || + \ (pline =~# g:javascript_continuation && pline !~# s:expr_case && (pline !~ ':' . s:line_term || l:line !~# + \ s:line_pre . '\%(d\%(o\|ebugger\)\|else\|f\%(or\|inally\)\|if\|let\|switch\|t\%(hrow\|ry\)\|w\%(hile\|ith\)\)\>')))) || + \ (num < l:lnum && s:Onescope(l:lnum,pline,0) && l:line !~ s:line_pre . '{') + return (num > 0 ? indent(num) : -s:sw()) + (s:sw() * 2) + switch_offset + elseif num > 0 + return indent(num) + s:sw() + switch_offset + endif + +endfunction + + +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/runtime/optwin.vim b/runtime/optwin.vim index b8a2636d4d..a7b94d73d4 100644 --- a/runtime/optwin.vim +++ b/runtime/optwin.vim @@ -1,7 +1,7 @@ " These commands create the option window. " " Maintainer: Bram Moolenaar -" Last Change: 2016 Apr 21 +" Last Change: 2016 Aug 12 " If there already is an option window, jump to that one. if bufwinnr("option-window") > 0 diff --git a/runtime/syntax/dockerfile.vim b/runtime/syntax/dockerfile.vim index d1693cba41..15b66925e5 100644 --- a/runtime/syntax/dockerfile.vim +++ b/runtime/syntax/dockerfile.vim @@ -1,7 +1,7 @@ " dockerfile.vim - Syntax highlighting for Dockerfiles -" Maintainer: Honza Pokorny -" Version: 0.5 -" Last Change: 2014 Aug 29 +" Maintainer: Honza Pokorny +" Version: 0.6 +" Last Change: 2016 Aug 9 " License: BSD @@ -13,7 +13,7 @@ let b:current_syntax = "dockerfile" syntax case ignore -syntax match dockerfileKeyword /\v^\s*(ONBUILD\s+)?(ADD|CMD|ENTRYPOINT|ENV|EXPOSE|FROM|MAINTAINER|RUN|USER|VOLUME|WORKDIR|COPY)\s/ +syntax match dockerfileKeyword /\v^\s*(ONBUILD\s+)?(ADD|ARG|CMD|COPY|ENTRYPOINT|ENV|EXPOSE|FROM|HEALTHCHECK|LABEL|MAINTAINER|RUN|SHELL|STOPSIGNAL|USER|VOLUME|WORKDIR)\s/ syntax region dockerfileString start=/\v"/ skip=/\v\\./ end=/\v"/ diff --git a/runtime/syntax/sshconfig.vim b/runtime/syntax/sshconfig.vim index bd9f0a3c28..302d073f1e 100644 --- a/runtime/syntax/sshconfig.vim +++ b/runtime/syntax/sshconfig.vim @@ -4,8 +4,9 @@ " Maintainer: Dominik Fischer " Contributor: Leonard Ehrenfried " Contributor: Karsten Hopp -" Last Change: 2016 Apr 7 -" SSH Version: 7.2p2 +" Contributor: Dean, Adam Kenneth +" Last Change: 2016 Aug 11 +" SSH Version: 7.3p1 " " Setup @@ -205,6 +206,7 @@ syn keyword sshconfigKeyword Port syn keyword sshconfigKeyword PreferredAuthentications syn keyword sshconfigKeyword Protocol syn keyword sshconfigKeyword ProxyCommand +syn keyword sshconfigKeyword ProxyJump syn keyword sshconfigKeyword ProxyUseFDPass syn keyword sshconfigKeyword PubkeyAcceptedKeyTypes syn keyword sshconfigKeyword PubkeyAuthentication From 4453aa0d29d7a4e488a4c1799c9d33bcbde432eb Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 15 Nov 2016 13:41:01 -0500 Subject: [PATCH 07/14] vim-patch:7.4.2215 Problem: It's not easy to find out if a window is a quickfix or location list window. Solution: Add "loclist" and "quickfix" entries to the dict returnec by getwininfo(). (Yegappan Lakshmanan) https://github.com/vim/vim/commit/386600f0cbcb8add099c723cf84634f46df2f788 --- runtime/doc/eval.txt | 18 +++++----- src/nvim/eval.c | 5 +++ src/nvim/testdir/test_bufwintabinfo.vim | 45 +++++++++++++++++++++++++ src/nvim/version.c | 2 +- 4 files changed, 61 insertions(+), 9 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 9e08c64de9..3bf13dfc34 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -4166,14 +4166,16 @@ getwininfo([{winid}]) *getwininfo()* pages is returned. Each List item is a Dictionary with the following entries: - nr window number. - tpnr tab page number. - winid window ID. - height window height. - width window width. - bufnum number of buffer in the window. - options dictionary of window local options. - variables dictionary of window local variables. + bufnum number of buffer in the window + height window height + loclist 1 if showing a location list + nr window number + options dictionary of window local options + quickfix 1 if quickfix or location list window + tpnr tab page number + variables dictionary of window local variables + width window width + winid window ID getwinvar({winnr}, {varname} [, {def}]) *getwinvar()* Like |gettabwinvar()| for the current tabpage. diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 91f7233a21..a59bfca2a5 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -10905,6 +10905,11 @@ static dict_T *get_win_info(win_T *wp, short tpnr, short winnr) dict_add_nr_str(dict, "width", wp->w_width, NULL); dict_add_nr_str(dict, "bufnum", wp->w_buffer->b_fnum, NULL); + dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL); + dict_add_nr_str(dict, "loclist", + (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), + NULL); + // Copy window variables dict_T *vars = dict_copy(NULL, wp->w_vars, true, 0); if (vars != NULL) { diff --git a/src/nvim/testdir/test_bufwintabinfo.vim b/src/nvim/testdir/test_bufwintabinfo.vim index 236ca30f99..fa9d97bc85 100644 --- a/src/nvim/testdir/test_bufwintabinfo.vim +++ b/src/nvim/testdir/test_bufwintabinfo.vim @@ -14,6 +14,27 @@ function Test_getbufwintabinfo() hide enew call assert_equal(3, len(getbufinfo({'bufloaded':1}))) + set tabstop&vim + let b:editor = 'vim' + let l = getbufinfo('%') + call assert_equal(bufnr('%'), l[0].nr) + call assert_equal(8, l[0].options.tabstop) + call assert_equal('vim', l[0].variables.editor) + call assert_notequal(-1, index(l[0].windows, bufwinid('%'))) + + if has('signs') + call append(0, ['Linux', 'Windows', 'Mac']) + sign define Mark text=>> texthl=Search + exe "sign place 2 line=3 name=Mark buffer=" . bufnr('%') + let l = getbufinfo('%') + call assert_equal(2, l[0].signs[0].id) + call assert_equal(3, l[0].signs[0].lnum) + call assert_equal('Mark', l[0].signs[0].name) + sign unplace * + sign undefine Mark + enew! + endif + only let w1_id = win_getid() new @@ -21,18 +42,42 @@ function Test_getbufwintabinfo() tabnew | let w3_id = win_getid() new | let w4_id = win_getid() new | let w5_id = win_getid() + call setwinvar(0, 'signal', 'green') tabfirst let winlist = getwininfo() call assert_equal(5, len(winlist)) + call assert_equal(winbufnr(2), winlist[1].bufnum) + call assert_equal(winheight(2), winlist[1].height) + call assert_equal(1, winlist[2].nr) + call assert_equal('auto', winlist[0].options.signcolumn) call assert_equal(2, winlist[3].tpnr) + call assert_equal('green', winlist[2].variables.signal) + call assert_equal(winwidth(1), winlist[0].width) + call assert_equal(w4_id, winlist[3].winid) let winfo = getwininfo(w5_id)[0] call assert_equal(2, winfo.tpnr) call assert_equal([], getwininfo(3)) + call settabvar(1, 'space', 'build') let tablist = gettabinfo() call assert_equal(2, len(tablist)) call assert_equal(3, len(tablist[1].windows)) + call assert_equal(2, tablist[1].nr) + call assert_equal('build', tablist[0].variables.space) + call assert_equal(w2_id, tablist[0].windows[0]) call assert_equal([], gettabinfo(3)) tabonly | only + + lexpr '' + lopen + copen + let winlist = getwininfo() + call assert_false(winlist[0].quickfix) + call assert_false(winlist[0].loclist) + call assert_true(winlist[1].quickfix) + call assert_true(winlist[1].loclist) + call assert_true(winlist[2].quickfix) + call assert_false(winlist[2].loclist) + wincmd t | only endfunction diff --git a/src/nvim/version.c b/src/nvim/version.c index b1bb9f02f4..8e9f7938cc 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -225,7 +225,7 @@ static int included_patches[] = { // 2218 NA 2217, // 2216 NA - // 2215, + 2215, // 2214 NA 2213, 2212, From 486e968bb6bdfb49d17305d6f7747408eda95926 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 15 Nov 2016 16:38:33 -0500 Subject: [PATCH 08/14] vim-patch:7.4.2225 Problem: Crash when placing a sign in a deleted buffer. Solution: Check for missing buffer name. (Dominique Pelle). Add a test. https://github.com/vim/vim/commit/bfd096d02087a10e8e2f4bdfb74e0435506fa8bb --- src/nvim/ex_cmds.c | 4 ++++ src/nvim/testdir/test_signs.vim | 12 ++++++++++++ src/nvim/version.c | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 42af5989a1..a53e8657cb 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -5675,6 +5675,10 @@ void ex_sign(exarg_T *eap) } else { // ... not currently in a window + if (buf->b_fname == NULL) { + EMSG(_("E934: Cannot jump to a buffer that does not have a name")); + return; + } char *cmd = xmalloc(STRLEN(buf->b_fname) + 25); sprintf(cmd, "e +%" PRId64 " %s", (int64_t)lnum, buf->b_fname); diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim index 79e60986ee..93cc62cd9c 100644 --- a/src/nvim/testdir/test_signs.vim +++ b/src/nvim/testdir/test_signs.vim @@ -181,3 +181,15 @@ func Test_sign_invalid_commands() call assert_fails('sign place 1 buffer=', 'E158:') call assert_fails('sign define Sign2 text=', 'E239:') endfunc + +func Test_sign_delete_buffer() + new + sign define Sign text=x + let bufnr = bufnr('%') + new + exe 'bd ' . bufnr + exe 'sign place 61 line=3 name=Sign buffer=' . bufnr + call assert_fails('sign jump 61 buffer=' . bufnr, 'E934:') + sign unplace 61 + sign undefine Sign +endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index 8e9f7938cc..756873f6d8 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -215,7 +215,7 @@ static int included_patches[] = { // 2228, 2227, // 2226, - // 2225, + 2225, // 2224, // 2223, // 2222, From c4c894b2fada371c424e55d26174110b9069b5f8 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 15 Nov 2016 16:46:11 -0500 Subject: [PATCH 09/14] vim-patch:7.4.2226 Problem: The field names used by getbufinfo(), gettabinfo() and getwininfo() are not consistent. Solution: Use bufnr, winnr and tabnr. (Yegappan Lakshmanan) https://github.com/vim/vim/commit/339288377072f66ec88e21903e75a82d23ffbf4f --- runtime/doc/eval.txt | 2 +- src/nvim/eval.c | 10 +++++----- src/nvim/testdir/test_bufwintabinfo.vim | 12 ++++++------ src/nvim/version.c | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 3bf13dfc34..d97c10ee84 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -3617,6 +3617,7 @@ getbufinfo([{dict}]) Each returned List item is a dictionary with the following entries: + bufnr buffer number. changed TRUE if the buffer is modified. changedtick number of changes made to the buffer. hidden TRUE if the buffer is hidden. @@ -3624,7 +3625,6 @@ getbufinfo([{dict}]) lnum current line number in buffer. loaded TRUE if the buffer is loaded. name full path to the file in the buffer. - nr buffer number. options dictionary of buffer local options. signs list of signs placed in the buffer. Each list item is a dictionary with diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a59bfca2a5..6dee5ed336 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -9868,7 +9868,7 @@ static dict_T *get_buffer_info(buf_T *buf) { dict_T *dict = dict_alloc(); - dict_add_nr_str(dict, "nr", buf->b_fnum, NULL); + dict_add_nr_str(dict, "bufnr", buf->b_fnum, NULL); dict_add_nr_str(dict, "name", 0L, buf->b_ffname != NULL ? buf->b_ffname : (char_u *)""); dict_add_nr_str(dict, "lnum", buflist_findlnum(buf), NULL); @@ -10798,7 +10798,7 @@ static dict_T *get_tabpage_info(tabpage_T *tp, int tp_idx) { dict_T *dict = dict_alloc(); - dict_add_nr_str(dict, "nr", tp_idx, NULL); + dict_add_nr_str(dict, "tabnr", tp_idx, NULL); list_T *l = list_alloc(); FOR_ALL_WINDOWS_IN_TAB(wp, tp) { @@ -10898,12 +10898,12 @@ static dict_T *get_win_info(win_T *wp, short tpnr, short winnr) { dict_T *dict = dict_alloc(); - dict_add_nr_str(dict, "tpnr", tpnr, NULL); - dict_add_nr_str(dict, "nr", winnr, NULL); + dict_add_nr_str(dict, "tabnr", tpnr, NULL); + dict_add_nr_str(dict, "winnr", winnr, NULL); dict_add_nr_str(dict, "winid", wp->handle, NULL); dict_add_nr_str(dict, "height", wp->w_height, NULL); dict_add_nr_str(dict, "width", wp->w_width, NULL); - dict_add_nr_str(dict, "bufnum", wp->w_buffer->b_fnum, NULL); + dict_add_nr_str(dict, "bufnr", wp->w_buffer->b_fnum, NULL); dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL); dict_add_nr_str(dict, "loclist", diff --git a/src/nvim/testdir/test_bufwintabinfo.vim b/src/nvim/testdir/test_bufwintabinfo.vim index fa9d97bc85..42c016621f 100644 --- a/src/nvim/testdir/test_bufwintabinfo.vim +++ b/src/nvim/testdir/test_bufwintabinfo.vim @@ -17,7 +17,7 @@ function Test_getbufwintabinfo() set tabstop&vim let b:editor = 'vim' let l = getbufinfo('%') - call assert_equal(bufnr('%'), l[0].nr) + call assert_equal(bufnr('%'), l[0].bufnr) call assert_equal(8, l[0].options.tabstop) call assert_equal('vim', l[0].variables.editor) call assert_notequal(-1, index(l[0].windows, bufwinid('%'))) @@ -46,23 +46,23 @@ function Test_getbufwintabinfo() tabfirst let winlist = getwininfo() call assert_equal(5, len(winlist)) - call assert_equal(winbufnr(2), winlist[1].bufnum) + call assert_equal(winbufnr(2), winlist[1].bufnr) call assert_equal(winheight(2), winlist[1].height) - call assert_equal(1, winlist[2].nr) + call assert_equal(1, winlist[2].winnr) call assert_equal('auto', winlist[0].options.signcolumn) - call assert_equal(2, winlist[3].tpnr) + call assert_equal(2, winlist[3].tabnr) call assert_equal('green', winlist[2].variables.signal) call assert_equal(winwidth(1), winlist[0].width) call assert_equal(w4_id, winlist[3].winid) let winfo = getwininfo(w5_id)[0] - call assert_equal(2, winfo.tpnr) + call assert_equal(2, winfo.tabnr) call assert_equal([], getwininfo(3)) call settabvar(1, 'space', 'build') let tablist = gettabinfo() call assert_equal(2, len(tablist)) call assert_equal(3, len(tablist[1].windows)) - call assert_equal(2, tablist[1].nr) + call assert_equal(2, tablist[1].tabnr) call assert_equal('build', tablist[0].variables.space) call assert_equal(w2_id, tablist[0].windows[0]) call assert_equal([], gettabinfo(3)) diff --git a/src/nvim/version.c b/src/nvim/version.c index 756873f6d8..21fa7253ba 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -214,7 +214,7 @@ static int included_patches[] = { // 2229, // 2228, 2227, - // 2226, + 2226, 2225, // 2224, // 2223, From 03ed7e1ebaf7f0934b176c71949a77a3fe2291fb Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 15 Nov 2016 16:53:07 -0500 Subject: [PATCH 10/14] vim-patch:7.4.2272 Problem: getbufinfo(), getwininfo() and gettabinfo() are inefficient. Solution: Instead of making a copy of the variables dictionary, use a reference. https://github.com/vim/vim/commit/9f8187c335b4fb07be9095dfdd0fc52670ba3c3f --- src/nvim/eval.c | 21 ++++++--------------- src/nvim/version.c | 2 +- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 6dee5ed336..59d1132c79 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -9880,11 +9880,8 @@ static dict_T *get_buffer_info(buf_T *buf) buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0, NULL); - // Copy buffer variables - dict_T *vars = dict_copy(NULL, buf->b_vars, true, 0); - if (vars != NULL) { - dict_add_dict(dict, "variables", vars); - } + // Get a reference to buffer variables + dict_add_dict(dict, "variables", buf->b_vars); // Copy buffer options dict_T *opts = get_winbuf_options(true); @@ -10806,11 +10803,8 @@ static dict_T *get_tabpage_info(tabpage_T *tp, int tp_idx) } dict_add_list(dict, "windows", l); - // Copy tabpage variables - dict_T *vars = dict_copy(NULL, tp->tp_vars, true, 0); - if (vars != NULL) { - dict_add_dict(dict, "variables", vars); - } + // Make a reference to tabpage variables + dict_add_dict(dict, "variables", tp->tp_vars); return dict; } @@ -10910,11 +10904,8 @@ static dict_T *get_win_info(win_T *wp, short tpnr, short winnr) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), NULL); - // Copy window variables - dict_T *vars = dict_copy(NULL, wp->w_vars, true, 0); - if (vars != NULL) { - dict_add_dict(dict, "variables", vars); - } + // Make a reference to window variables + dict_add_dict(dict, "variables", wp->w_vars); // Copy window options dict_T *opts = get_winbuf_options(false); diff --git a/src/nvim/version.c b/src/nvim/version.c index 21fa7253ba..4ad4c82928 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -168,7 +168,7 @@ static int included_patches[] = { // 2275, 2274, // 2273, - // 2272, + 2272, // 2271 NA // 2270 NA // 2269, From fe03ce23bfc5c45545b53d4959aeeb27d82753ed Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 23:01:53 -0500 Subject: [PATCH 11/14] vim-patch:7.4.2273 Problem: getwininfo() and getbufinfo() are inefficient. Solution: Do not make a copy of all window/buffer-local options. Make it possible to get them with gettabwinvar() or getbufvar(). https://github.com/vim/vim/commit/3056735ae8a366aa7fcb51872520895251858637 --- runtime/doc/eval.txt | 47 +++++++++++++++++++------ src/nvim/eval.c | 43 +++++++++++++--------- src/nvim/testdir/test_bufwintabinfo.vim | 24 +++++++++++-- src/nvim/version.c | 2 +- 4 files changed, 86 insertions(+), 30 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index d97c10ee84..0a5a51a0e1 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 7.4. Last change: 2016 Jun 04 +*eval.txt* For Vim version 7.4. Last change: 2016 Aug 27 VIM REFERENCE MANUAL by Bram Moolenaar @@ -3625,25 +3625,30 @@ getbufinfo([{dict}]) lnum current line number in buffer. loaded TRUE if the buffer is loaded. name full path to the file in the buffer. - options dictionary of buffer local options. signs list of signs placed in the buffer. Each list item is a dictionary with the following fields: id sign identifier lnum line number name sign name - variables dictionary of buffer local variables. - windows list of window IDs with this buffer + variables a reference to the dictionary with + buffer-local variables. + windows list of |window-ID|s that display this + buffer Examples: > for buf in getbufinfo() echo buf.name endfor for buf in getbufinfo({'buflisted':1}) - if buf.options.filetype == 'java' + if buf.changed .... endif endfor +< + To get buffer-local options use: > + getbufvar({bufnr}, '&') + < *getbufline()* getbufline({expr}, {lnum} [, {end}]) @@ -3676,6 +3681,10 @@ getbufvar({expr}, {varname} [, {def}]) *getbufvar()* must be used. When {varname} is empty returns a dictionary with all the buffer-local variables. + When {varname} is equal to "&" returns a dictionary with all + the buffer-local options. + Otherwise, when {varname} starts with "&" returns the value of + a buffer-local option. This also works for a global or buffer-local option, but it doesn't work for a global variable, window-local variable or window-local option. @@ -4111,8 +4120,9 @@ gettabinfo([{arg}]) *gettabinfo()* Each List item is a Dictionary with the following entries: nr tab page number. + variables a reference to the dictionary with + tabpage-local variables windows List of window IDs in the tag page. - variables dictionary of tabpage local variables. gettabvar({tabnr}, {varname} [, {def}]) *gettabvar()* Get the value of a tab-local variable {varname} in tab page @@ -4127,10 +4137,12 @@ gettabvar({tabnr}, {varname} [, {def}]) *gettabvar()* gettabwinvar({tabnr}, {winnr}, {varname} [, {def}]) *gettabwinvar()* Get the value of window-local variable {varname} in window {winnr} in tab page {tabnr}. - When {varname} starts with "&" get the value of a window-local - option. When {varname} is empty a dictionary with all window-local variables is returned. + When {varname} is equal to "&" get the values of all + window-local options in a Dictionary. + Otherwise, when {varname} starts with "&" get the value of a + window-local option. Note that {varname} must be the name without "w:". Tabs are numbered starting with one. For the current tabpage use |getwinvar()|. @@ -4170,13 +4182,16 @@ getwininfo([{winid}]) *getwininfo()* height window height loclist 1 if showing a location list nr window number - options dictionary of window local options quickfix 1 if quickfix or location list window tpnr tab page number - variables dictionary of window local variables + variables a reference to the dictionary with + window-local variables width window width winid window ID + To obtain all window-local variables use: > + gettabwinvar({tabnr}, {winnr}, '&') + getwinvar({winnr}, {varname} [, {def}]) *getwinvar()* Like |gettabwinvar()| for the current tabpage. Examples: > @@ -5544,6 +5559,16 @@ printf({fmt}, {expr1} ...) *printf()* numeric field; if the result of a conversion is wider than the field width, the field is expanded to contain the conversion result. + The 'h' modifier indicates the argument is 16 bits. + The 'l' modifier indicates the argument is 32 bits. + The 'L' modifier indicates the argument is 64 bits. + Generally, these modifiers are not useful. They are + ignored when type is known from the argument. + + i alias for d + D alias for ld + U alias for lu + O alias for lo *printf-c* c The Number argument is converted to a byte, and the @@ -5560,7 +5585,7 @@ printf({fmt}, {expr1} ...) *printf()* feature works just like 's'. *printf-f* *E807* - f The Float argument is converted into a string of the + f F The Float argument is converted into a string of the form 123.456. The precision specifies the number of digits after the decimal point. When the precision is zero the decimal point is omitted. When the precision diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 59d1132c79..2b325bbf20 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -9883,12 +9883,6 @@ static dict_T *get_buffer_info(buf_T *buf) // Get a reference to buffer variables dict_add_dict(dict, "variables", buf->b_vars); - // Copy buffer options - dict_T *opts = get_winbuf_options(true); - if (opts != NULL) { - dict_add_dict(dict, "options", opts); - } - // List of windows displaying this buffer list_T *windows = list_alloc(); FOR_ALL_TAB_WINDOWS(tp, wp) { @@ -10056,8 +10050,20 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) curbuf = buf; if (*varname == '&') { /* buffer-local-option */ - if (get_option_tv(&varname, rettv, TRUE) == OK) + if (varname[1] == NUL) { + // get all buffer-local options in a dict + dict_T *opts = get_winbuf_options(true); + + if (opts != NULL) { + rettv->v_type = VAR_DICT; + rettv->vval.v_dict = opts; + opts->dv_refcount++; + done = true; + } + } else if (get_option_tv(&varname, rettv, true) == OK) { + // buffer-local-option done = TRUE; + } } else if (STRCMP(varname, "changedtick") == 0) { rettv->v_type = VAR_NUMBER; rettv->vval.v_number = curbuf->b_changedtick; @@ -10904,15 +10910,9 @@ static dict_T *get_win_info(win_T *wp, short tpnr, short winnr) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), NULL); - // Make a reference to window variables + // Add a reference to window variables dict_add_dict(dict, "variables", wp->w_vars); - // Copy window options - dict_T *opts = get_winbuf_options(false); - if (opts != NULL) { - dict_add_dict(dict, "options", opts); - } - return dict; } @@ -11072,8 +11072,19 @@ getwinvar ( bool need_switch_win = tp != curtab || win != curwin; if (!need_switch_win || switch_win(&oldcurwin, &oldtabpage, win, tp, true) == OK) { - if (*varname == '&') { // window-local-option - if (get_option_tv(&varname, rettv, 1) == OK) { + if (*varname == '&') { + if (varname[1] == NUL) { + // get all window-local options in a dict + dict_T *opts = get_winbuf_options(false); + + if (opts != NULL) { + rettv->v_type = VAR_DICT; + rettv->vval.v_dict = opts; + opts->dv_refcount++; + done = true; + } + } else if (get_option_tv(&varname, rettv, 1) == OK) { + // window-local-option done = true; } } else { diff --git a/src/nvim/testdir/test_bufwintabinfo.vim b/src/nvim/testdir/test_bufwintabinfo.vim index 42c016621f..5c916e2dd7 100644 --- a/src/nvim/testdir/test_bufwintabinfo.vim +++ b/src/nvim/testdir/test_bufwintabinfo.vim @@ -18,7 +18,6 @@ function Test_getbufwintabinfo() let b:editor = 'vim' let l = getbufinfo('%') call assert_equal(bufnr('%'), l[0].bufnr) - call assert_equal(8, l[0].options.tabstop) call assert_equal('vim', l[0].variables.editor) call assert_notequal(-1, index(l[0].windows, bufwinid('%'))) @@ -49,7 +48,6 @@ function Test_getbufwintabinfo() call assert_equal(winbufnr(2), winlist[1].bufnr) call assert_equal(winheight(2), winlist[1].height) call assert_equal(1, winlist[2].winnr) - call assert_equal('auto', winlist[0].options.signcolumn) call assert_equal(2, winlist[3].tabnr) call assert_equal('green', winlist[2].variables.signal) call assert_equal(winwidth(1), winlist[0].width) @@ -81,3 +79,25 @@ function Test_getbufwintabinfo() call assert_false(winlist[2].loclist) wincmd t | only endfunction + +function Test_get_buf_options() + let opts = getbufvar(bufnr('%'), '&') + call assert_equal(v:t_dict, type(opts)) + call assert_equal(8, opts.tabstop) +endfunc + +function Test_get_win_options() + let opts = getwinvar(1, '&') + call assert_equal(v:t_dict, type(opts)) + call assert_equal(0, opts.linebreak) + if has('signs') + call assert_equal('auto', opts.signcolumn) + endif + + let opts = gettabwinvar(1, 1, '&') + call assert_equal(v:t_dict, type(opts)) + call assert_equal(0, opts.linebreak) + if has('signs') + call assert_equal('auto', opts.signcolumn) + endif +endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index 4ad4c82928..55d86b3aec 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -167,7 +167,7 @@ static int included_patches[] = { // 2276, // 2275, 2274, - // 2273, + 2273, 2272, // 2271 NA // 2270 NA From de025d6dd05de41a1226721420ffa51018e07fed Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 23:22:50 -0500 Subject: [PATCH 12/14] vim-patch:7.4.2277 Problem: Memory leak in getbufinfo() when there is a sign. (Dominique Pelle) Solution: Remove extra vim_strsave(). https://github.com/vim/vim/commit/6a402edbeb693113f05d9319cd20ec382a0a1a20 --- src/nvim/eval.c | 2 +- src/nvim/version.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 2b325bbf20..2016e0bb45 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -9857,7 +9857,7 @@ static void get_buffer_signs(buf_T *buf, list_T *l) dict_add_nr_str(d, "id", sign->id, NULL); dict_add_nr_str(d, "lnum", sign->lnum, NULL); - dict_add_nr_str(d, "name", 0L, vim_strsave(sign_typenr2name(sign->typenr))); + dict_add_nr_str(d, "name", 0L, sign_typenr2name(sign->typenr)); list_append_dict(l, d); } diff --git a/src/nvim/version.c b/src/nvim/version.c index 55d86b3aec..9e555d1694 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -163,7 +163,7 @@ static int included_patches[] = { // 2280, // 2279, // 2278 NA - // 2277, + 2277, // 2276, // 2275, 2274, From 552cc4d0b3c9ebfd7ca30bfac71fab4ee5d9188e Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 23:26:51 -0500 Subject: [PATCH 13/14] vim-patch:7.4.2294 Problem: Sign test fails on MS-Windows when using the distributed zip archives. Solution: Create dummy files instead of relying on files in the pixmaps directory. https://github.com/vim/vim/commit/64cefedfc834aa4dac54ae5f91ccbc04e2d56bc5 --- src/nvim/testdir/test_signs.vim | 8 ++++++-- src/nvim/version.c | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim index 93cc62cd9c..75dbd74b34 100644 --- a/src/nvim/testdir/test_signs.vim +++ b/src/nvim/testdir/test_signs.vim @@ -145,8 +145,12 @@ func Test_sign_completion() call feedkeys(":sign define Sign linehl=Spell\\\"\", 'tx') call assert_equal('"sign define Sign linehl=SpellBad SpellCap SpellLocal SpellRare', @:) - call feedkeys(":sign define Sign icon=../../pixmaps/tb_p\\\"\", 'tx') - call assert_equal('"sign define Sign icon=../../pixmaps/tb_paste.xpm ../../pixmaps/tb_print.xpm', @:) + call writefile(['foo'], 'XsignOne') + call writefile(['bar'], 'XsignTwo') + call feedkeys(":sign define Sign icon=Xsig\\\"\", 'tx') + call assert_equal('"sign define Sign icon=XsignOne XsignTwo', @:) + call delete('XsignOne') + call delete('XsignTwo') call feedkeys(":sign undefine \\\"\", 'tx') call assert_equal('"sign undefine Sign1 Sign2', @:) diff --git a/src/nvim/version.c b/src/nvim/version.c index 9e555d1694..d06741f1b6 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -146,7 +146,7 @@ static int included_patches[] = { // 2297 NA // 2296, // 2295, - // 2294, + 2294, // 2293, // 2292, // 2291, From 46235a30edc4ee09fdbd4f489865982bafde247d Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 27 Dec 2016 23:26:51 -0500 Subject: [PATCH 14/14] lint --- src/nvim/buffer_defs.h | 4 +- src/nvim/eval.c | 13 +- src/nvim/ex_cmds.c | 695 +++++++++++++++++++---------------------- src/nvim/move.c | 3 +- src/nvim/option.c | 7 +- src/nvim/option_defs.h | 2 +- src/nvim/screen.c | 5 +- 7 files changed, 334 insertions(+), 395 deletions(-) diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index fda906fc59..2b66a07f48 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -237,8 +237,8 @@ typedef struct { # define w_p_crb w_onebuf_opt.wo_crb /* 'cursorbind' */ int wo_crb_save; /* 'cursorbind' state saved for diff mode*/ # define w_p_crb_save w_onebuf_opt.wo_crb_save - char_u *wo_scl; -# define w_p_scl w_onebuf_opt.wo_scl /* 'signcolumn' */ + char_u *wo_scl; +# define w_p_scl w_onebuf_opt.wo_scl // 'signcolumn' int wo_scriptID[WV_COUNT]; /* SIDs for window-local options */ # define w_p_scriptID w_onebuf_opt.wo_scriptID diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 2016e0bb45..32e1991742 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -10049,7 +10049,7 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) save_curbuf = curbuf; curbuf = buf; - if (*varname == '&') { /* buffer-local-option */ + if (*varname == '&') { // buffer-local-option if (varname[1] == NUL) { // get all buffer-local options in a dict dict_T *opts = get_winbuf_options(true); @@ -10062,7 +10062,7 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } else if (get_option_tv(&varname, rettv, true) == OK) { // buffer-local-option - done = TRUE; + done = true; } } else if (STRCMP(varname, "changedtick") == 0) { rettv->v_type = VAR_NUMBER; @@ -10825,8 +10825,9 @@ static void f_gettabinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (argvars[0].v_type != VAR_UNKNOWN) { // Information about one tab page tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); - if (tparg == NULL) + if (tparg == NULL) { return; + } } // Get information about a specific tab page or all tab pages @@ -10894,7 +10895,7 @@ static void f_gettabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// Returns information about a window as a dictionary. -static dict_T *get_win_info(win_T *wp, short tpnr, short winnr) +static dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr) { dict_T *dict = dict_alloc(); @@ -10932,10 +10933,10 @@ static void f_getwininfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) // Collect information about either all the windows across all the tab // pages or one particular window. - short tabnr = 0; + int16_t tabnr = 0; FOR_ALL_TABS(tp) { tabnr++; - short winnr = 0; + int16_t winnr = 0; FOR_ALL_WINDOWS_IN_TAB(wp, tp) { if (wparg != NULL && wp != wparg) { continue; diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index a53e8657cb..0a429a8d99 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -5351,389 +5351,330 @@ static int sign_cmd_idx( */ void ex_sign(exarg_T *eap) { - char_u *arg = eap->arg; - char_u *p; - int idx; - sign_T *sp; - sign_T *sp_prev; + char_u *arg = eap->arg; + char_u *p; + int idx; + sign_T *sp; + sign_T *sp_prev; - /* Parse the subcommand. */ - p = skiptowhite(arg); - idx = sign_cmd_idx(arg, p); - if (idx == SIGNCMD_LAST) - { - EMSG2(_("E160: Unknown sign command: %s"), arg); - return; + // Parse the subcommand. + p = skiptowhite(arg); + idx = sign_cmd_idx(arg, p); + if (idx == SIGNCMD_LAST) { + EMSG2(_("E160: Unknown sign command: %s"), arg); + return; + } + arg = skipwhite(p); + + if (idx <= SIGNCMD_LIST) { + // Define, undefine or list signs. + if (idx == SIGNCMD_LIST && *arg == NUL) { + // ":sign list": list all defined signs + for (sp = first_sign; sp != NULL && !got_int; sp = sp->sn_next) { + sign_list_defined(sp); + } + } else if (*arg == NUL) { + EMSG(_("E156: Missing sign name")); + } else { + // Isolate the sign name. If it's a number skip leading zeroes, + // so that "099" and "99" are the same sign. But keep "0". + p = skiptowhite(arg); + if (*p != NUL) { + *p++ = NUL; + } + while (arg[0] == '0' && arg[1] != NUL) { + arg++; + } + + sp_prev = NULL; + for (sp = first_sign; sp != NULL; sp = sp->sn_next) { + if (STRCMP(sp->sn_name, arg) == 0) { + break; + } + sp_prev = sp; + } + if (idx == SIGNCMD_DEFINE) { + // ":sign define {name} ...": define a sign + if (sp == NULL) { + sign_T *lp; + int start = next_sign_typenr; + + // Allocate a new sign. + sp = xcalloc(1, sizeof(sign_T)); + + // Check that next_sign_typenr is not already being used. + // This only happens after wrapping around. Hopefully + // another one got deleted and we can use its number. + for (lp = first_sign; lp != NULL; ) { + if (lp->sn_typenr == next_sign_typenr) { + next_sign_typenr++; + if (next_sign_typenr == MAX_TYPENR) { + next_sign_typenr = 1; + } + if (next_sign_typenr == start) { + xfree(sp); + EMSG(_("E612: Too many signs defined")); + return; + } + lp = first_sign; // start all over + continue; + } + lp = lp->sn_next; + } + + sp->sn_typenr = next_sign_typenr; + if (++next_sign_typenr == MAX_TYPENR) { + next_sign_typenr = 1; // wrap around + } + + sp->sn_name = vim_strsave(arg); + + // add the new sign to the list of signs + if (sp_prev == NULL) { + first_sign = sp; + } else { + sp_prev->sn_next = sp; + } + } + + // set values for a defined sign. + for (;;) { + arg = skipwhite(p); + if (*arg == NUL) { + break; + } + p = skiptowhite_esc(arg); + if (STRNCMP(arg, "icon=", 5) == 0) { + arg += 5; + xfree(sp->sn_icon); + sp->sn_icon = vim_strnsave(arg, (int)(p - arg)); + backslash_halve(sp->sn_icon); + } else if (STRNCMP(arg, "text=", 5) == 0) { + char_u *s; + int cells; + int len; + + arg += 5; + + // Count cells and check for non-printable chars + cells = 0; + for (s = arg; s < p; s += (*mb_ptr2len)(s)) { + if (!vim_isprintc((*mb_ptr2char)(s))) { + break; + } + cells += (*mb_ptr2cells)(s); + } + // Currently must be one or two display cells + if (s != p || cells < 1 || cells > 2) { + *p = NUL; + EMSG2(_("E239: Invalid sign text: %s"), arg); + return; + } + + xfree(sp->sn_text); + // Allocate one byte more if we need to pad up + // with a space. + len = (int)(p - arg + ((cells == 1) ? 1 : 0)); + sp->sn_text = vim_strnsave(arg, len); + + if (cells == 1) { + STRCPY(sp->sn_text + len - 1, " "); + } + } else if (STRNCMP(arg, "linehl=", 7) == 0) { + arg += 7; + sp->sn_line_hl = syn_check_group(arg, (int)(p - arg)); + } else if (STRNCMP(arg, "texthl=", 7) == 0) { + arg += 7; + sp->sn_text_hl = syn_check_group(arg, (int)(p - arg)); + } else { + EMSG2(_(e_invarg2), arg); + return; + } + } + } else if (sp == NULL) { + EMSG2(_("E155: Unknown sign: %s"), arg); + } else if (idx == SIGNCMD_LIST) { + // ":sign list {name}" + sign_list_defined(sp); + } else { + // ":sign undefine {name}" + sign_undefine(sp, sp_prev); + } } - arg = skipwhite(p); + } else { + int id = -1; + linenr_T lnum = -1; + char_u *sign_name = NULL; + char_u *arg1; - if (idx <= SIGNCMD_LIST) - { - /* - * Define, undefine or list signs. - */ - if (idx == SIGNCMD_LIST && *arg == NUL) - { - /* ":sign list": list all defined signs */ - for (sp = first_sign; sp != NULL && !got_int; sp = sp->sn_next) - sign_list_defined(sp); - } - else if (*arg == NUL) - EMSG(_("E156: Missing sign name")); - else - { - /* Isolate the sign name. If it's a number skip leading zeroes, - * so that "099" and "99" are the same sign. But keep "0". */ - p = skiptowhite(arg); - if (*p != NUL) - *p++ = NUL; - while (arg[0] == '0' && arg[1] != NUL) - ++arg; - - sp_prev = NULL; - for (sp = first_sign; sp != NULL; sp = sp->sn_next) - { - if (STRCMP(sp->sn_name, arg) == 0) - break; - sp_prev = sp; - } - if (idx == SIGNCMD_DEFINE) - { - /* ":sign define {name} ...": define a sign */ - if (sp == NULL) - { - sign_T *lp; - int start = next_sign_typenr; - - /* Allocate a new sign. */ - sp = xcalloc(1, sizeof(sign_T)); - - /* Check that next_sign_typenr is not already being used. - * This only happens after wrapping around. Hopefully - * another one got deleted and we can use its number. */ - for (lp = first_sign; lp != NULL; ) - { - if (lp->sn_typenr == next_sign_typenr) - { - ++next_sign_typenr; - if (next_sign_typenr == MAX_TYPENR) - next_sign_typenr = 1; - if (next_sign_typenr == start) - { - xfree(sp); - EMSG(_("E612: Too many signs defined")); - return; - } - lp = first_sign; /* start all over */ - continue; - } - lp = lp->sn_next; - } - - sp->sn_typenr = next_sign_typenr; - if (++next_sign_typenr == MAX_TYPENR) - next_sign_typenr = 1; /* wrap around */ - - sp->sn_name = vim_strsave(arg); - - /* add the new sign to the list of signs */ - if (sp_prev == NULL) - first_sign = sp; - else - sp_prev->sn_next = sp; - } - - /* set values for a defined sign. */ - for (;;) - { - arg = skipwhite(p); - if (*arg == NUL) - break; - p = skiptowhite_esc(arg); - if (STRNCMP(arg, "icon=", 5) == 0) - { - arg += 5; - xfree(sp->sn_icon); - sp->sn_icon = vim_strnsave(arg, (int)(p - arg)); - backslash_halve(sp->sn_icon); - } - else if (STRNCMP(arg, "text=", 5) == 0) - { - char_u *s; - int cells; - int len; - - arg += 5; - - /* Count cells and check for non-printable chars */ - if (has_mbyte) - { - cells = 0; - for (s = arg; s < p; s += (*mb_ptr2len)(s)) - { - if (!vim_isprintc((*mb_ptr2char)(s))) - break; - cells += (*mb_ptr2cells)(s); - } - } - else - - { - for (s = arg; s < p; ++s) - if (!vim_isprintc(*s)) - break; - cells = (int)(s - arg); - } - /* Currently must be one or two display cells */ - if (s != p || cells < 1 || cells > 2) - { - *p = NUL; - EMSG2(_("E239: Invalid sign text: %s"), arg); - return; - } - - xfree(sp->sn_text); - /* Allocate one byte more if we need to pad up - * with a space. */ - len = (int)(p - arg + ((cells == 1) ? 1 : 0)); - sp->sn_text = vim_strnsave(arg, len); - - if (cells == 1) - STRCPY(sp->sn_text + len - 1, " "); - } - else if (STRNCMP(arg, "linehl=", 7) == 0) - { - arg += 7; - sp->sn_line_hl = syn_check_group(arg, (int)(p - arg)); - } - else if (STRNCMP(arg, "texthl=", 7) == 0) - { - arg += 7; - sp->sn_text_hl = syn_check_group(arg, (int)(p - arg)); - } - else - { - EMSG2(_(e_invarg2), arg); - return; - } - } - } - else if (sp == NULL) - EMSG2(_("E155: Unknown sign: %s"), arg); - else if (idx == SIGNCMD_LIST) - /* ":sign list {name}" */ - sign_list_defined(sp); - else - /* ":sign undefine {name}" */ - sign_undefine(sp, sp_prev); - } + if (*arg == NUL) { + if (idx == SIGNCMD_PLACE) { + // ":sign place": list placed signs in all buffers + sign_list_placed(NULL); + } else if (idx == SIGNCMD_UNPLACE) { + // ":sign unplace": remove placed sign at cursor + id = buf_findsign_id(curwin->w_buffer, curwin->w_cursor.lnum); + if (id > 0) { + buf_delsign(curwin->w_buffer, id); + update_debug_sign(curwin->w_buffer, curwin->w_cursor.lnum); + } else { + EMSG(_("E159: Missing sign number")); + } + } else { + EMSG(_(e_argreq)); + } + return; } - else - { - int id = -1; - linenr_T lnum = -1; - char_u *sign_name = NULL; - char_u *arg1; - if (*arg == NUL) - { - if (idx == SIGNCMD_PLACE) - { - /* ":sign place": list placed signs in all buffers */ - sign_list_placed(NULL); - } - else if (idx == SIGNCMD_UNPLACE) - { - /* ":sign unplace": remove placed sign at cursor */ - id = buf_findsign_id(curwin->w_buffer, curwin->w_cursor.lnum); - if (id > 0) - { - buf_delsign(curwin->w_buffer, id); - update_debug_sign(curwin->w_buffer, curwin->w_cursor.lnum); - } - else - EMSG(_("E159: Missing sign number")); - } - else - EMSG(_(e_argreq)); - return; - } - - if (idx == SIGNCMD_UNPLACE && arg[0] == '*' && arg[1] == NUL) - { - /* ":sign unplace *": remove all placed signs */ - buf_delete_all_signs(); - return; - } - - /* first arg could be placed sign id */ - arg1 = arg; - if (ascii_isdigit(*arg)) - { - id = getdigits_int(&arg); - if (!ascii_iswhite(*arg) && *arg != NUL) - { - id = -1; - arg = arg1; - } - else - { - arg = skipwhite(arg); - if (idx == SIGNCMD_UNPLACE && *arg == NUL) - { - // ":sign unplace {id}": remove placed sign by number - FOR_ALL_BUFFERS(buf) { - if ((lnum = buf_delsign(buf, id)) != 0) { - update_debug_sign(buf, lnum); - } - } - return; - } - } - } - - /* - * Check for line={lnum} name={name} and file={fname} or buffer={nr}. - * Leave "arg" pointing to {fname}. - */ - - buf_T *buf = NULL; - for (;;) - { - if (STRNCMP(arg, "line=", 5) == 0) - { - arg += 5; - lnum = atoi((char *)arg); - arg = skiptowhite(arg); - } - else if (STRNCMP(arg, "*", 1) == 0 && idx == SIGNCMD_UNPLACE) - { - if (id != -1) - { - EMSG(_(e_invarg)); - return; - } - id = -2; - arg = skiptowhite(arg + 1); - } - else if (STRNCMP(arg, "name=", 5) == 0) - { - arg += 5; - sign_name = arg; - arg = skiptowhite(arg); - if (*arg != NUL) - *arg++ = NUL; - while (sign_name[0] == '0' && sign_name[1] != NUL) - ++sign_name; - } - else if (STRNCMP(arg, "file=", 5) == 0) - { - arg += 5; - buf = buflist_findname(arg); - break; - } - else if (STRNCMP(arg, "buffer=", 7) == 0) - { - arg += 7; - buf = buflist_findnr(getdigits_int(&arg)); - if (*skipwhite(arg) != NUL) - EMSG(_(e_trailing)); - break; - } - else - { - EMSG(_(e_invarg)); - return; - } - arg = skipwhite(arg); - } - - if (buf == NULL) - { - EMSG2(_("E158: Invalid buffer name: %s"), arg); - } - else if (id <= 0 && !(idx == SIGNCMD_UNPLACE && id == -2)) - { - if (lnum >= 0 || sign_name != NULL) - EMSG(_(e_invarg)); - else - /* ":sign place file={fname}": list placed signs in one file */ - sign_list_placed(buf); - } - else if (idx == SIGNCMD_JUMP) - { - /* ":sign jump {id} file={fname}" */ - if (lnum >= 0 || sign_name != NULL) - EMSG(_(e_invarg)); - else if ((lnum = buf_findsign(buf, id)) > 0) - { /* goto a sign ... */ - if (buf_jump_open_win(buf) != NULL) - { /* ... in a current window */ - curwin->w_cursor.lnum = lnum; - check_cursor_lnum(); - beginline(BL_WHITE); - } - else - { // ... not currently in a window - if (buf->b_fname == NULL) { - EMSG(_("E934: Cannot jump to a buffer that does not have a name")); - return; - } - char *cmd = xmalloc(STRLEN(buf->b_fname) + 25); - sprintf(cmd, "e +%" PRId64 " %s", - (int64_t)lnum, buf->b_fname); - do_cmdline_cmd(cmd); - xfree(cmd); - } - - foldOpenCursor(); - } - else - EMSGN(_("E157: Invalid sign ID: %" PRId64), id); - } - else if (idx == SIGNCMD_UNPLACE) - { - if (lnum >= 0 || sign_name != NULL) - EMSG(_(e_invarg)); - else if (id == -2) - { - /* ":sign unplace * file={fname}" */ - redraw_buf_later(buf, NOT_VALID); - buf_delete_signs(buf); - } - else - { - /* ":sign unplace {id} file={fname}" */ - lnum = buf_delsign(buf, id); - update_debug_sign(buf, lnum); - } - } - /* idx == SIGNCMD_PLACE */ - else if (sign_name != NULL) - { - for (sp = first_sign; sp != NULL; sp = sp->sn_next) - if (STRCMP(sp->sn_name, sign_name) == 0) - break; - if (sp == NULL) - { - EMSG2(_("E155: Unknown sign: %s"), sign_name); - return; - } - if (lnum > 0) - /* ":sign place {id} line={lnum} name={name} file={fname}": - * place a sign */ - buf_addsign(buf, id, lnum, sp->sn_typenr); - else - /* ":sign place {id} file={fname}": change sign type */ - lnum = buf_change_sign_type(buf, id, sp->sn_typenr); - if (lnum > 0) - update_debug_sign(buf, lnum); - else - EMSG2(_("E885: Not possible to change sign %s"), sign_name); - } - else - EMSG(_(e_invarg)); + if (idx == SIGNCMD_UNPLACE && arg[0] == '*' && arg[1] == NUL) { + // ":sign unplace *": remove all placed signs + buf_delete_all_signs(); + return; } + + // first arg could be placed sign id + arg1 = arg; + if (ascii_isdigit(*arg)) { + id = getdigits_int(&arg); + if (!ascii_iswhite(*arg) && *arg != NUL) { + id = -1; + arg = arg1; + } else { + arg = skipwhite(arg); + if (idx == SIGNCMD_UNPLACE && *arg == NUL) { + // ":sign unplace {id}": remove placed sign by number + FOR_ALL_BUFFERS(buf) { + if ((lnum = buf_delsign(buf, id)) != 0) { + update_debug_sign(buf, lnum); + } + } + return; + } + } + } + + // Check for line={lnum} name={name} and file={fname} or buffer={nr}. + // Leave "arg" pointing to {fname}. + + buf_T *buf = NULL; + for (;;) { + if (STRNCMP(arg, "line=", 5) == 0) { + arg += 5; + lnum = atoi((char *)arg); + arg = skiptowhite(arg); + } else if (STRNCMP(arg, "*", 1) == 0 && idx == SIGNCMD_UNPLACE) { + if (id != -1) { + EMSG(_(e_invarg)); + return; + } + id = -2; + arg = skiptowhite(arg + 1); + } else if (STRNCMP(arg, "name=", 5) == 0) { + arg += 5; + sign_name = arg; + arg = skiptowhite(arg); + if (*arg != NUL) { + *arg++ = NUL; + } + while (sign_name[0] == '0' && sign_name[1] != NUL) { + sign_name++; + } + } else if (STRNCMP(arg, "file=", 5) == 0) { + arg += 5; + buf = buflist_findname(arg); + break; + } else if (STRNCMP(arg, "buffer=", 7) == 0) { + arg += 7; + buf = buflist_findnr(getdigits_int(&arg)); + if (*skipwhite(arg) != NUL) { + EMSG(_(e_trailing)); + } + break; + } else { + EMSG(_(e_invarg)); + return; + } + arg = skipwhite(arg); + } + + if (buf == NULL) { + EMSG2(_("E158: Invalid buffer name: %s"), arg); + } else if (id <= 0 && !(idx == SIGNCMD_UNPLACE && id == -2)) { + if (lnum >= 0 || sign_name != NULL) { + EMSG(_(e_invarg)); + } else { + // ":sign place file={fname}": list placed signs in one file + sign_list_placed(buf); + } + } else if (idx == SIGNCMD_JUMP) { + // ":sign jump {id} file={fname}" + if (lnum >= 0 || sign_name != NULL) { + EMSG(_(e_invarg)); + } else if ((lnum = buf_findsign(buf, id)) > 0) { + // goto a sign ... + if (buf_jump_open_win(buf) != NULL) { + // ... in a current window + curwin->w_cursor.lnum = lnum; + check_cursor_lnum(); + beginline(BL_WHITE); + } else { + // ... not currently in a window + if (buf->b_fname == NULL) { + EMSG(_("E934: Cannot jump to a buffer that does not have a name")); + return; + } + size_t cmdlen = STRLEN(buf->b_fname) + 24; + char *cmd = xmallocz(cmdlen); + snprintf(cmd, cmdlen, "e +%" PRId64 " %s", + (int64_t)lnum, buf->b_fname); + do_cmdline_cmd(cmd); + xfree(cmd); + } + + foldOpenCursor(); + } else { + EMSGN(_("E157: Invalid sign ID: %" PRId64), id); + } + } else if (idx == SIGNCMD_UNPLACE) { + if (lnum >= 0 || sign_name != NULL) { + EMSG(_(e_invarg)); + } else if (id == -2) { + // ":sign unplace * file={fname}" + redraw_buf_later(buf, NOT_VALID); + buf_delete_signs(buf); + } else { + // ":sign unplace {id} file={fname}" + lnum = buf_delsign(buf, id); + update_debug_sign(buf, lnum); + } + } else if (sign_name != NULL) { + // idx == SIGNCMD_PLACE + for (sp = first_sign; sp != NULL; sp = sp->sn_next) { + if (STRCMP(sp->sn_name, sign_name) == 0) { + break; + } + } + if (sp == NULL) { + EMSG2(_("E155: Unknown sign: %s"), sign_name); + return; + } + if (lnum > 0) { + // ":sign place {id} line={lnum} name={name} file={fname}": + // place a sign + buf_addsign(buf, id, lnum, sp->sn_typenr); + } else { + // ":sign place {id} file={fname}": change sign type + lnum = buf_change_sign_type(buf, id, sp->sn_typenr); + } + if (lnum > 0) { + update_debug_sign(buf, lnum); + } else { + EMSG2(_("E885: Not possible to change sign %s"), sign_name); + } + } else { + EMSG(_(e_invarg)); + } + } } /* diff --git a/src/nvim/move.c b/src/nvim/move.c index 4e7fe86adc..bb6c032db1 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -670,8 +670,7 @@ int win_col_off(win_T *wp) return ((wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) + 1 : 0) + (cmdwin_type == 0 || wp != curwin ? 0 : 1) + (int)wp->w_p_fdc - + (signcolumn_on(wp) ? 2 : 0) - ; + + (signcolumn_on(wp) ? 2 : 0); } int curwin_col_off(void) diff --git a/src/nvim/option.c b/src/nvim/option.c index 817e35d550..52a8b19ca4 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -3008,9 +3008,8 @@ did_set_string_option ( } else { completeopt_was_set(); } - } - /* 'signcolumn' */ - else if (varp == &curwin->w_p_scl) { + } else if (varp == &curwin->w_p_scl) { + // 'signcolumn' if (check_opt_strings(*varp, p_scl_values, false) != OK) { errmsg = e_invarg; } @@ -5513,7 +5512,7 @@ void copy_winopt(winopt_T *from, winopt_T *to) to->wo_fdt = vim_strsave(from->wo_fdt); to->wo_fmr = vim_strsave(from->wo_fmr); to->wo_scl = vim_strsave(from->wo_scl); - check_winopt(to); /* don't want NULL pointers */ + check_winopt(to); // don't want NULL pointers } /* diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 82c618cf6f..32021da922 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -800,7 +800,7 @@ enum { , WV_WFW , WV_WRAP , WV_SCL - , WV_COUNT /* must be the last one */ + , WV_COUNT // must be the last one }; /* Value for b_p_ul indicating the global value must be used. */ diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 72549f1f21..b737c23851 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -1630,8 +1630,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h n = nn; } - if (signcolumn_on(wp)) - { + if (signcolumn_on(wp)) { int nn = n + 2; /* draw the sign column after the fold column */ @@ -1743,7 +1742,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T * text */ RL_MEMSET(col, hl_attr(HLF_FL), wp->w_width - col); - /* If signs are being displayed, add two spaces. */ + // If signs are being displayed, add two spaces. if (signcolumn_on(wp)) { len = wp->w_width - col; if (len > 0) {