aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames McCoy <jamessan@jamessan.com>2017-01-01 15:12:33 -0500
committerGitHub <noreply@github.com>2017-01-01 15:12:33 -0500
commitc5f4b92ff93a40ec4e77b78d0576903e7a60eefd (patch)
treed4bdbc55eec66541aa95a03adff0403d6ab71685
parent57ce8b56488a781088cb503f0da723f59e2f9554 (diff)
parent46235a30edc4ee09fdbd4f489865982bafde247d (diff)
downloadrneovim-c5f4b92ff93a40ec4e77b78d0576903e7a60eefd.tar.gz
rneovim-c5f4b92ff93a40ec4e77b78d0576903e7a60eefd.tar.bz2
rneovim-c5f4b92ff93a40ec4e77b78d0576903e7a60eefd.zip
Merge pull request #5613 from jamessan/vim-7.4.2183
vim-patch:7.4.2183,7.4.2194,7.4.2201,7.4.2204,0952131,7.4.2215,7.4.2225,7.4.2226,7.4.2272,7.4.2273,7.4.2277,7.4.2294
-rw-r--r--runtime/doc/editing.txt12
-rw-r--r--runtime/doc/eval.txt119
-rw-r--r--runtime/doc/options.txt18
-rw-r--r--runtime/doc/quickref.txt3
-rw-r--r--runtime/doc/sign.txt8
-rw-r--r--runtime/doc/syntax.txt4
-rw-r--r--runtime/doc/usr_41.txt5
-rw-r--r--runtime/indent/javascript.vim194
-rw-r--r--runtime/optwin.vim5
-rw-r--r--runtime/syntax/dockerfile.vim8
-rw-r--r--runtime/syntax/sshconfig.vim6
-rw-r--r--src/nvim/buffer_defs.h2
-rw-r--r--src/nvim/edit.c2
-rw-r--r--src/nvim/eval.c274
-rw-r--r--src/nvim/eval.lua3
-rw-r--r--src/nvim/ex_cmds.c695
-rw-r--r--src/nvim/move.c4
-rw-r--r--src/nvim/option.c49
-rw-r--r--src/nvim/option_defs.h3
-rw-r--r--src/nvim/options.lua8
-rw-r--r--src/nvim/screen.c20
-rw-r--r--src/nvim/testdir/Makefile2
-rw-r--r--src/nvim/testdir/runtest.vim6
-rw-r--r--src/nvim/testdir/test_bufwintabinfo.vim103
-rw-r--r--src/nvim/testdir/test_signs.vim199
-rw-r--r--src/nvim/version.c22
-rw-r--r--src/nvim/window.c13
27 files changed, 1338 insertions, 449 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/eval.txt b/runtime/doc/eval.txt
index 367f64df9b..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
@@ -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,60 @@ 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:
+ 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.
+ 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.
+ 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 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.changed
+ ....
+ endif
+ endfor
+<
+ To get buffer-local options use: >
+ getbufvar({bufnr}, '&')
+
+<
*getbufline()*
getbufline({expr}, {lnum} [, {end}])
Return a |List| with the lines starting from {lnum} to {end}
@@ -3624,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.
@@ -4050,6 +4111,19 @@ getregtype([{regname}]) *getregtype()*
<CTRL-V> 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.
+ variables a reference to the dictionary with
+ tabpage-local variables
+ windows List of window IDs in the tag page.
+
gettabvar({tabnr}, {varname} [, {def}]) *gettabvar()*
Get the value of a tab-local variable {varname} in tab page
{tabnr}. |t:var|
@@ -4063,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()|.
@@ -4091,6 +4167,31 @@ 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:
+ bufnum number of buffer in the window
+ height window height
+ loclist 1 if showing a location list
+ nr window number
+ quickfix 1 if quickfix or location list window
+ tpnr tab page number
+ 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: >
@@ -5458,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
@@ -5474,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/runtime/doc/options.txt b/runtime/doc/options.txt
index 7cfc55ed79..e15fb9dc84 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,18 @@ 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. 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 <Tab>
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/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/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 = '\%([<*,.?:^%]\|+\@<!+\|-\@<!-\|=\@<!>\|\*\@<!\/\|=\||\|&\|\<in\%(stanceof\)\=\)'
+endif
+let g:javascript_continuation .= s:line_term
+
+function s:Onescope(lnum,text,add)
+ return a:text =~# '\%(\<else\|\<do\|=>' . (a:add ? '\|\<try\|\<finally' : '' ) . '\)' . s:line_term ||
+ \ ((a:add && a:text =~ s:line_pre . '$' && search('\%' . s:PrevCodeLine(a:lnum - 1) . 'l.)' . s:line_term)) ||
+ \ cursor(a:lnum, match(a:text, ')' . s:line_term)) > -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('<cword>') ==# 'while' ? !s:lookForParens('\<do\>\C', '\<while\>\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, '\%(:\@<!\/\/.*\)$', '','') : a:c
+endfunction
+
+" Find line above 'lnum' that isn't empty, in a comment, or in a string.
+function s:PrevCodeLine(lnum)
+ let l:lnum = prevnonblank(a:lnum)
+ while l:lnum > 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("<cword>") !=# '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 3d585267d7..a7b94d73d4 100644
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -1,7 +1,7 @@
" These commands create the option window.
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" 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
@@ -1250,6 +1250,9 @@ call append("$", "\t(local to buffer)")
call <SID>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 <SID>OptionL("scl")
set cpo&vim
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 <http://honza.ca>
-" Version: 0.5
-" Last Change: 2014 Aug 29
+" Maintainer: Honza Pokorny <https://honza.ca>
+" 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 <d dot f dot fischer at web dot de>
" Contributor: Leonard Ehrenfried <leonard.ehrenfried@web.de>
" Contributor: Karsten Hopp <karsten@redhat.com>
-" Last Change: 2016 Apr 7
-" SSH Version: 7.2p2
+" Contributor: Dean, Adam Kenneth <adam.ken.dean@hpe.com>
+" 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
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 0418a737eb..2b66a07f48 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/eval.c b/src/nvim/eval.c
index bdbd77337d..32e1991742 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,118 @@ 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, 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, "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);
+ 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);
+
+ // Get a reference to buffer variables
+ dict_add_dict(dict, "variables", buf->b_vars);
+
+ // 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".
@@ -9920,9 +10049,21 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
save_curbuf = curbuf;
curbuf = buf;
- if (*varname == '&') { /* buffer-local-option */
- if (get_option_tv(&varname, rettv, TRUE) == OK)
- done = TRUE;
+ if (*varname == '&') { // buffer-local-option
+ 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;
@@ -10654,6 +10795,58 @@ 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, "tabnr", 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);
+
+ // Make a reference to tabpage variables
+ dict_add_dict(dict, "variables", tp->tp_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 +10894,66 @@ 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, int16_t tpnr, int16_t winnr)
+{
+ dict_T *dict = dict_alloc();
+
+ 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, "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",
+ (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL),
+ NULL);
+
+ // Add a reference to window variables
+ dict_add_dict(dict, "variables", wp->w_vars);
+
+ 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.
+ int16_t tabnr = 0;
+ FOR_ALL_TABS(tp) {
+ tabnr++;
+ int16_t 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
*/
@@ -10820,8 +11073,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/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/ex_cmds.c b/src/nvim/ex_cmds.c
index 73a1ab7723..fcaf17a0fc 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -5351,385 +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;
-
- /* Parse the subcommand. */
- p = skiptowhite(arg);
- idx = sign_cmd_idx(arg, p);
- if (idx == SIGNCMD_LAST)
- {
- EMSG2(_("E160: Unknown sign command: %s"), arg);
- return;
+ 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;
+ }
+ 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);
+ }
+ }
+ } 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;
}
- 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 */
- 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 (idx == SIGNCMD_UNPLACE && arg[0] == '*' && arg[1] == NUL) {
+ // ":sign unplace *": remove all placed signs
+ buf_delete_all_signs();
+ 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
- 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));
+
+ // 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 4c814f3ae0..bb6c032db1 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,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
- + (wp->w_buffer->b_signlist != NULL ? 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 797dd1dfe7..52a8b19ca4 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"
@@ -3007,6 +3008,11 @@ did_set_string_option (
} else {
completeopt_was_set();
}
+ } else if (varp == &curwin->w_p_scl) {
+ // 'signcolumn'
+ 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) {
@@ -4782,7 +4788,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 +5433,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,7 +5511,8 @@ 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);
- check_winopt(to); /* don't want NULL pointers */
+ to->wo_scl = vim_strsave(from->wo_scl);
+ check_winopt(to); // don't want NULL pointers
}
/*
@@ -5528,6 +5535,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 +5554,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 +6911,39 @@ 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;
+}
+
+/// 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/option_defs.h b/src/nvim/option_defs.h
index 6e89a093c8..32021da922 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -799,7 +799,8 @@ enum {
, WV_WFH
, WV_WFW
, WV_WRAP
- , WV_COUNT /* must be the last one */
+ , WV_SCL
+ , WV_COUNT // must be the last one
};
/* Value for b_p_ul indicating the global value must be used. */
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
@@ -2170,6 +2170,14 @@ return {
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'},
vi_def=true,
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index bf6e316c06..41acc48f97 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -581,15 +581,6 @@ void update_debug_sign(buf_T *buf, linenr_T lnum)
}
/*
- * 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.
*
* This may cause the windows below it also to be redrawn (when clearing the
@@ -1603,7 +1594,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 */
@@ -1644,8 +1635,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;
/* draw the sign column after the fold column */
@@ -1757,8 +1747,8 @@ 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 (draw_signcolumn(wp)) {
+ // If signs are being displayed, add two spaces.
+ if (signcolumn_on(wp)) {
len = wp->w_width - col;
if (len > 0) {
if (len > 2) {
@@ -2706,7 +2696,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/testdir/Makefile b/src/nvim/testdir/Makefile
index 7cd1921ce1..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 \
@@ -40,6 +41,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/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
diff --git a/src/nvim/testdir/test_bufwintabinfo.vim b/src/nvim/testdir/test_bufwintabinfo.vim
new file mode 100644
index 0000000000..5c916e2dd7
--- /dev/null
+++ b/src/nvim/testdir/test_bufwintabinfo.vim
@@ -0,0 +1,103 @@
+" 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})))
+
+ set tabstop&vim
+ let b:editor = 'vim'
+ let l = getbufinfo('%')
+ call assert_equal(bufnr('%'), l[0].bufnr)
+ 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
+ let w2_id = win_getid()
+ 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].bufnr)
+ call assert_equal(winheight(2), winlist[1].height)
+ call assert_equal(1, winlist[2].winnr)
+ 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.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].tabnr)
+ 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
+
+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/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim
new file mode 100644
index 0000000000..75dbd74b34
--- /dev/null
+++ b/src/nvim/testdir/test_signs.vim
@@ -0,0 +1,199 @@
+" Test for signs
+
+if !has('signs')
+ finish
+endif
+
+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
+ 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_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)
+
+ " 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
+ 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('.'))
+
+ " 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=41 name=Sign1\n", a)
+
+ " Unplace the sign and try jumping to it again should fail.
+ sign unplace 41
+ 1
+ call assert_fails("exe 'sign jump 41 buffer=' . bufnr('%')", 'E157:')
+ call assert_equal('a', getline('.'))
+
+ " Unplace sign on current line.
+ exe 'sign place 42 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 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
+ 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()
+ sign define Sign1 text=x
+ sign define Sign2 text=y
+
+ call feedkeys(":sign \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign define jump list place undefine unplace', @:)
+
+ call feedkeys(":sign define Sign \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign define Sign icon= linehl= text= texthl=', @:)
+
+ call feedkeys(":sign define Sign linehl=Spell\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign define Sign linehl=SpellBad SpellCap SpellLocal SpellRare', @:)
+
+ call writefile(['foo'], 'XsignOne')
+ call writefile(['bar'], 'XsignTwo')
+ call feedkeys(":sign define Sign icon=Xsig\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign define Sign icon=XsignOne XsignTwo', @:)
+ call delete('XsignOne')
+ call delete('XsignTwo')
+
+ call feedkeys(":sign undefine \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign undefine Sign1 Sign2', @:)
+
+ call feedkeys(":sign place 1 \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign place 1 buffer= file= line= name=', @:)
+
+ call feedkeys(":sign place 1 name=\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign place 1 name=Sign1 Sign2', @:)
+
+ call feedkeys(":sign unplace 1 \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign unplace 1 buffer= file=', @:)
+
+ call feedkeys(":sign list \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign list Sign1 Sign2', @:)
+
+ call feedkeys(":sign jump 1 \<C-A>\<C-B>\"\<CR>", '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 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:')
+ 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 9f3395680b..9f2b7a26c3 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,
@@ -163,12 +163,12 @@ static int included_patches[] = {
// 2280,
// 2279,
// 2278 NA
- // 2277,
+ 2277,
// 2276,
// 2275,
2274,
- // 2273,
- // 2272,
+ 2273,
+ 2272,
// 2271 NA
// 2270 NA
// 2269,
@@ -214,8 +214,8 @@ static int included_patches[] = {
// 2229,
// 2228,
2227,
- // 2226,
- // 2225,
+ 2226,
+ 2225,
// 2224,
// 2223,
// 2222,
@@ -225,7 +225,7 @@ static int included_patches[] = {
// 2218 NA
2217,
// 2216 NA
- // 2215,
+ 2215,
// 2214 NA
2213,
2212,
@@ -236,17 +236,17 @@ static int included_patches[] = {
// 2207 NA
// 2206 NA
2205,
- // 2204,
+ 2204,
// 2203 NA
// 2202 NA
- // 2201,
+ 2201,
// 2200,
// 2199 NA
// 2198,
// 2197,
// 2196,
// 2195 NA
- // 2194,
+ 2194,
// 2193 NA
// 2192 NA
// 2191 NA
@@ -257,7 +257,7 @@ static int included_patches[] = {
// 2186 NA
// 2185,
// 2184,
- // 2183,
+ 2183,
// 2182 NA
// 2181,
// 2180,
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;