-*todo.txt* For Vim version 8.0. Last change: 2017 Jan 02
+*todo.txt* For Vim version 8.0. Last change: 2017 Jan 09
VIM REFERENCE MANUAL by Bram Moolenaar
Issues can also be entered online: https://github.com/vim/vim/issues
Only use this for bug reports, not for questions! Those belong on the
-maillist. Updates will be forwarded to the vim_dev maillist. Issues entered
-there will not be repeated below, unless there is extra information.
+maillist. Updates will be forwarded to the |vim_dev| maillist. Issues
+entered there will not be repeated below, unless there is extra information.
*known-bugs*
-------------------- Known bugs and current work -----------------------
Make html indent file use javascript indent, now that it's not just cindent.
#1220
-Patch to fix completion of :filter command. (Ichizok, 2016 Dec 3, #1299)
-
-Patch to use buffer id for system() and systemlist() (LemonBoy, 2016 Nov 7,
-#1240)
-
Concatenation with null string causes an error: 'a'[1:0] .. 'b'
Might as well handle it like an empty string.
json_encode(): should convert to utf-8. (Nikolai Pavlov, 2016 Jan 23)
What if there is an invalid character?
-Putting "k" early in 'complete' does not use dictionary first?
-(RubenGZ, 2016 Dec 10, #1316)
-patch proposed by Hirohito Higashi, 2016 Dec 11.
-
-Patch to fix NULL pointer when sorting zero elements. (Dominique, 2016 Dec 15)
+Include rust files. (Klabnik, #1356)
-Patch to test float functions. (Dominique, 2016 Dec 16)
-
-Patch to improve completion of :syntax command. (Dominique, 2016 Dec 12)
-
-Patch to use IEMSG() in more places. (Dominique, 2016 Dec 27)
+More float tests. (Dominique, #1364)
Patch to avoid ubsan warning for integer overflow. (Dominique, 2016 Dec 26)
-Bug: ":earlier 100d" doesn't work after using undo file.
-(Pavol Juhas, 2016 Nov 15, #1254)
-Fix by Christian, but lacks a test.
-Test in testdir/test_undo.vim doesn't catch the problem.
-Test by Pavol Juhas, Nov 22.
-Patch with test (Pavol Juhas,, 2016 Dec 3, #1300)
-
Bug: Json with same key should not give internal error. (Lcd, 2016 Oct 26)
Make dict_add give a duplicate key error.
2016 Oct 23 #1193)
Remarks from nuko8, 2016 Nov 2.
+Multi-byte bug: dv} splits char. (Urtica Dioica, 2017 Jan 9)
+
Patch to change order of compiler flags. (Yousong Zhou, 2016 Sep 19, #1100)
Patch to add command line completion for :cexpr commands. (Yegappan
Lakshmanan, 2016 Dec 13)
+Patch for :pyx, run python commands depending on the supported version.
+(Marc Weber, update from Ken Takata, 2016 Sep 19, 2017 Jan 6)
+
Patch to avoid warnings for overflow. (Mike Williams, 2016 Dec 16)
Update Dec 19.
Patch for better explanation of 'compatible' side effects.
https://github.com/vim/vim/pull/1161/files
+Patch to add 'makeencoding', useful when the system encoding differs from
+Vim's 'encoding' setting. (Ken Takata, 2017 Jan 6)
+
Patch to adjust marks when adding a new line to the end of buffer in diff
mode. (James McCoy, 2016 Dec 14, #1329)
Patch to make v:shell_error writable. (Christian Brabandt, 2016 Sep 27)
Useful to restore it. Is there another solution?
+"ci[" does not look for next [ like ci" does look for next ".
+(J.F. 2017 Jan 7)
+
On MS-Windows with 'clipboard' set to "unnamed" this doesn't work to double
lines: :g/^/normal yyp On Unix it works OK. (Bryce Orgill, 2016 Nov 5)
Patch for 'cursorlinenr' option. (Ozaki Kiichi, 2016 Nov 30)
+When adding an item to a new quickfix list make ":cnext" jump to that item.
+Make a difference being at the first item and not having used :cnext at all.
+(Afanasiy Fet, 2017 Jan 3)
+
Invalid behavior with NULL list. (Nikolai Pavlov, #768)
E.g. deepcopy(test_null_list())
Patch to add "cmdline" completion to getcompletion(). (Shougo, Oct 1, #1140)
+Feature request: Complete members of a dictionary. (Luc Hermitte, 2017 Jan 4,
+#1350)
+
Patch for systemlist(), add empty item. (thinca, Sep 30, #1135)
Add an argument to choose binary or non-binary (like readfile()), when omitted
use the current behavior.
patch for 'spellcamelcase' option: spellcheck each CamelCased word.
(Ben Tucker, 2016 Dec 2)
-Patch for :pyx, run python commands depending on the supported version.
-(Marc Weber, update from Ken Takata, 2016 Sep 19)
-
When using ":diffput" through a mapping, undo in the target buffer isn't
synced. (Ryan Carney, 2016 Sep 14)
Patch to fix wrong encoding of error message on Cygwin/MSYS terminal.
(Ken Takata, 2016 Oct 4)
+Patch to introduce 'cmdencoding'. (Ken Takata, Aug 18?)
+Better help Aug 19.
+Problem: applies to too many commands, such as :cbuffer.
+Updated patch with three options, 2016 Sep 8.
+ Win32: When running ":make" and 'encoding' differs from the system locale,
+ the output should be converted. Esp. when 'encoding' is "utf-8". (Yongwei
+ Wu) Should we use 'termencoding' for this?
+
+Patch to add 'systemencoding', convert between 'encoding' and this for file
+names, shell commands and the like. (Kikuchan, 2010 Oct 14)
+Assume the system converts between the actual encoding of the filesystem to
+the system encoding (usually utf-8).
+
'hlsearch' interferes with a Conceal match. (Rom Grk, 2016 Aug 9)
Patch to add context information to quickfix/location list. (Yegappan
Or use $XDG_DATA_DIRS.
Also need to run update-desktop-database (Kuriyama Kazunobu, 2015 Nov 4)
-Patch to introduce 'cmdencoding'. (Ken Takata, Aug 18?)
-Better help Aug 19.
-Problem: applies to too many commands, such as :cbuffer.
-Updated patch with three options, 2016 Sep 8.
- Win32: When running ":make" and 'encoding' differs from the system locale,
- the output should be converted. Esp. when 'encoding' is "utf-8". (Yongwei
- Wu) Should we use 'termencoding' for this?
-
Patch to have text objects defined by arbitrary single characters. (Daniel
Thau, 2013 Nov 20, 2014 Jan 29, 2014 Jan 31)
Added tests (James McCoy, 2016 Aug 3). Still needs more work.
":cd C:\Windows\System32\drivers\etc*" does not work, even though the
directory exists. (Sergio Gallelli, 2013 Dec 29)
+In debug mode one can inspect variables, but not the function parameters
+(starting with a:). (Luc Hermitte, 2017 Jan 4, #1352)
+
7 Add a watchpoint in the debug mode: An expression that breaks execution
when evaluating to non-zero. Add the "watchadd expr" command, stop when
the value of the expression changes. ":watchdel" deletes an item,
7.2.274. (Christian Brabandt, 2010 May 27) Generally, folding with
'foldmethod' set to "syntax" is slow. Do profiling to find out why.
-Patch to add 'systemencoding', convert between 'encoding' and this for file
-names, shell commands and the like. (Kikuchan, 2010 Oct 14)
-Assume the system converts between the actual encoding of the filesystem to
-the system encoding (usually utf-8).
-
Problem producing tags file when hebrew.frx is present. It has a BOM.
Results in E670. (Tony Mechelynck, 2010 May 2)
" Language: Javascript
" Maintainer: Chris Paul ( https://github.com/bounceme )
" URL: https://github.com/pangloss/vim-javascript
-" Last Change: August 25, 2016
+" Last Change: December 31, 2016
" Only load this indent file when no other was loaded.
if exists('b:did_indent')
" Now, set up our indentation expression and keys that trigger it.
setlocal indentexpr=GetJavascriptIndent()
-setlocal nolisp noautoindent nosmartindent
-setlocal indentkeys=0{,0},0),0],:,!^F,o,O,e
-setlocal cinoptions+=j1,J1
+setlocal autoindent nolisp nosmartindent
+setlocal indentkeys+=0],0)
-let b:undo_indent = 'setlocal indentexpr< smartindent< autoindent< indentkeys< cinoptions<'
+let b:undo_indent = 'setlocal indentexpr< smartindent< autoindent< indentkeys<'
" Only define the function once.
if exists('*GetJavascriptIndent')
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 = "synIDattr(synID(line('.'),col('.'),0),'name') =~? '".s:syng_strcom."'"
-
+" searchpair() wrapper
if has('reltime')
- function s:GetPair(start,end,flags,time)
- return searchpair(a:start,'',a:end,a:flags,s:skip_expr,max([prevnonblank(v:lnum) - 2000,0]),a:time)
+ function s:GetPair(start,end,flags,skip,time,...)
+ return searchpair('\m'.a:start,'','\m'.a:end,a:flags,a:skip,max([prevnonblank(v:lnum) - 2000,0] + a:000),a:time)
endfunction
else
- function s:GetPair(start,end,flags,n)
- return searchpair(a:start,'',a:end,a:flags,0,max([prevnonblank(v:lnum) - 2000,0]))
+ function s:GetPair(start,end,flags,skip,...)
+ return searchpair('\m'.a:start,'','\m'.a:end,a:flags,a:skip,max([prevnonblank(v:lnum) - 1000,get(a:000,1)]))
endfunction
endif
-let s:line_term = '\s*\%(\%(\/\%(\%(\*.\{-}\*\/\)\|\%(\*\+\)\)\)\s*\)\=$'
+" Regex of syntax group names that are or delimit string or are comments.
+let s:syng_strcom = 'string\|comment\|regex\|special\|doc\|template'
+let s:syng_str = 'string\|template'
+let s:syng_com = 'comment\|doc'
+" Expression used to check whether we should skip a match with searchpair().
+let s:skip_expr = "synIDattr(synID(line('.'),col('.'),0),'name') =~? '".s:syng_strcom."'"
-" configurable regexes that define continuation lines, not including (, {, or [.
-if !exists('g:javascript_opfirst')
- let g:javascript_opfirst = '\%([<>,:?^%|*&]\|\/[^/*]\|\([-.+]\)\1\@!\|=>\@!\|in\%(stanceof\)\=\>\)'
-endif
-if !exists('g:javascript_continuation')
- let g:javascript_continuation = '\%([<=,.?/*:^%|&]\|+\@<!+\|-\@<!-\|=\@<!>\|\<in\%(stanceof\)\=\)'
-endif
+function s:skip_func()
+ if !s:free || search('\m`\|\*\/','nW',s:looksyn)
+ let s:free = !eval(s:skip_expr)
+ let s:looksyn = s:free ? line('.') : s:looksyn
+ return !s:free
+ endif
+ let s:looksyn = line('.')
+ return (search('\m\/','nbW',s:looksyn) || search('\m[''"]\|\\$','nW',s:looksyn)) && eval(s:skip_expr)
+endfunction
-let g:javascript_opfirst = s:line_pre . g:javascript_opfirst
-let g:javascript_continuation .= s:line_term
+function s:alternatePair(stop)
+ let pos = getpos('.')[1:2]
+ while search('\m[][(){}]','bW',a:stop)
+ if !s:skip_func()
+ let idx = stridx('])}',s:looking_at())
+ if idx + 1
+ if !s:GetPair(['\[','(','{'][idx], '])}'[idx],'bW','s:skip_func()',2000,a:stop)
+ break
+ endif
+ else
+ return
+ endif
+ endif
+ endwhile
+ call call('cursor',pos)
+endfunction
-function s:OneScope(lnum,text,add)
- return a:text =~# '\%(\<else\|\<do\|=>\)' . s:line_term ? 'no b' :
- \ ((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:GetPair('(', ')', 'cbW', 100) > 0 && search('\C\l\+\_s*\%#','bW') &&
- \ (a:add || ((expand('<cword>') !=# 'while' || !s:GetPair('\C\<do\>', '\C\<while\>','nbW',100)) &&
- \ (expand('<cword>') !=# 'each' || search('\C\<for\_s\+\%#','nbW')))) ? expand('<cword>') : ''
+function s:save_pos(f,...)
+ let l:pos = getpos('.')[1:2]
+ let ret = call(a:f,a:000)
+ call call('cursor',l:pos)
+ return ret
endfunction
-" https://github.com/sweet-js/sweet.js/wiki/design#give-lookbehind-to-the-reader
-function s:IsBlock()
- return getline(line('.'))[col('.')-1] == '{' && !search(
- \ '\C\%(\<return\s*\|\%([-=~!<*+,.?^%|&\[(]\|=\@<!>\|\*\@<!\/\|\<\%(var\|const\|let\|import\|export\%(\_s\+default\)\=\|yield\|delete\|void\|t\%(ypeof\|hrow\)\|new\|in\%(stanceof\)\=\)\)\_s*\)\%#','bnW') &&
- \ (!search(':\_s*\%#','bW') || (!s:GetPair('[({[]','[])}]','bW',200) || s:IsBlock()))
+function s:syn_at(l,c)
+ return synIDattr(synID(a:l,a:c,0),'name')
+endfunction
+
+function s:looking_at()
+ return getline('.')[col('.')-1]
+endfunction
+
+function s:token()
+ return s:looking_at() =~ '\k' ? expand('<cword>') : s:looking_at()
+endfunction
+
+function s:b_token()
+ if s:looking_at() =~ '\k'
+ call search('\m\<','cbW')
+ endif
+ return search('\m\S','bW')
+endfunction
+
+function s:previous_token()
+ let l:n = line('.')
+ while s:b_token()
+ if (s:looking_at() == '/' || line('.') != l:n && search('\m\/\/','nbW',
+ \ line('.'))) && s:syn_at(line('.'),col('.')) =~? s:syng_com
+ call search('\m\_[^/]\zs\/[/*]','bW')
+ else
+ return s:token()
+ endif
+ endwhile
+ return ''
+endfunction
+
+function s:others(p)
+ return "((line2byte(line('.')) + col('.')) <= ".(line2byte(a:p[0]) + a:p[1]).") || ".s:skip_expr
+endfunction
+
+function s:tern_skip(p)
+ return s:GetPair('{','}','nbW',s:others(a:p),200,a:p[0]) > 0
+endfunction
+
+function s:tern_col(p)
+ return s:GetPair('?',':\@<!::\@!','nbW',s:others(a:p)
+ \ .' || s:tern_skip('.string(a:p).')',200,a:p[0]) > 0
+endfunction
+
+function s:label_col()
+ let pos = getpos('.')[1:2]
+ let [s:looksyn,s:free] = pos
+ call s:alternatePair(0)
+ if s:save_pos('s:IsBlock')
+ let poss = getpos('.')[1:2]
+ return call('cursor',pos) || !s:tern_col(poss)
+ elseif s:looking_at() == ':'
+ return !s:tern_col([0,0])
+ endif
+endfunction
+
+" configurable regexes that define continuation lines, not including (, {, or [.
+let s:opfirst = '^' . get(g:,'javascript_opfirst',
+ \ '\%([<>=,?^%|*/&]\|\([-.:+]\)\1\@!\|!=\|in\%(stanceof\)\=\>\)')
+let s:continuation = get(g:,'javascript_continuation',
+ \ '\%([<=,.~!?/*^%|&:]\|+\@<!+\|-\@<!-\|=\@<!>\|\<\%(typeof\|delete\|void\|in\|instanceof\)\)') . '$'
+
+function s:continues(ln,con)
+ return !cursor(a:ln, match(' '.a:con,s:continuation)) &&
+ \ eval((['s:syn_at(line("."),col(".")) !~? "regex"'] +
+ \ repeat(['s:previous_token() != "."'],5) + [1])[
+ \ index(split('/ typeof in instanceof void delete'),s:token())])
endfunction
-" Auxiliary Functions {{{2
+" get the line of code stripped of comments and move cursor to the last
+" non-comment char.
+function s:Trim(ln)
+ let pline = substitute(getline(a:ln),'\s*$','','')
+ let l:max = max([match(pline,'.*[^/]\zs\/[/*]'),0])
+ while l:max && s:syn_at(a:ln, strlen(pline)) =~? s:syng_com
+ let pline = substitute(strpart(pline, 0, l:max),'\s*$','','')
+ let l:max = max([match(pline,'.*[^/]\zs\/[/*]'),0])
+ endwhile
+ return cursor(a:ln,strlen(pline)) ? pline : pline
+endfunction
-" Find line above 'lnum' that isn't empty, in a comment, or in a string.
+" Find line above 'lnum' that isn't empty or in a comment
function s:PrevCodeLine(lnum)
- let l:lnum = prevnonblank(a:lnum)
- while l:lnum
- if synIDattr(synID(l:lnum,matchend(getline(l:lnum), '^\s*[^''"]'),0),'name') !~? s:syng_strcom
- return l:lnum
+ let l:n = prevnonblank(a:lnum)
+ while l:n
+ if getline(l:n) =~ '^\s*\/[/*]'
+ if (stridx(getline(l:n),'`') > 0 || getline(l:n-1)[-1:] == '\') &&
+ \ s:syn_at(l:n,1) =~? s:syng_str
+ return l:n
+ endif
+ let l:n = prevnonblank(l:n-1)
+ elseif s:syn_at(l:n,1) =~? s:syng_com
+ let l:n = s:save_pos('eval',
+ \ 'cursor('.l:n.',1) + search(''\m\/\*'',"bW")')
+ else
+ return l:n
endif
- let l:lnum = prevnonblank(l:lnum - 1)
endwhile
endfunction
" Check if line 'lnum' has a balanced amount of parentheses.
function s:Balanced(lnum)
- let [open_0,open_2,open_4] = [0,0,0]
+ let l:open = 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
+ if s:syn_at(a:lnum,pos + 1) !~? s:syng_strcom
+ let l:open += match(' ' . l:line[pos],'[[({]')
+ if l:open < 0
+ return
endif
endif
let pos = match(l:line, '[][(){}]', pos + 1)
endwhile
- return (!open_4 + !open_2 + !open_0) - 2
+ return !l:open
endfunction
-" }}}
-function GetJavascriptIndent()
- if !exists('b:js_cache')
- let b:js_cache = [0,0,0]
+function s:OneScope(lnum)
+ let pline = s:Trim(a:lnum)
+ let kw = 'else do'
+ if pline[-1:] == ')' && s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0
+ call s:previous_token()
+ let kw = 'for if let while with'
+ if index(split('await each'),s:token()) + 1
+ call s:previous_token()
+ let kw = 'for'
+ endif
+ endif
+ return pline[-2:] == '=>' || index(split(kw),s:token()) + 1 &&
+ \ s:save_pos('s:previous_token') != '.'
+endfunction
+
+" returns braceless levels started by 'i' and above lines * &sw. 'num' is the
+" lineNr which encloses the entire context, 'cont' if whether line 'i' + 1 is
+" a continued expression, which could have started in a braceless context
+function s:iscontOne(i,num,cont)
+ let [l:i, l:num, bL] = [a:i, a:num + !a:num, 0]
+ let pind = a:num ? indent(l:num) + s:W : 0
+ let ind = indent(l:i) + (a:cont ? 0 : s:W)
+ while l:i >= l:num && (ind > pind || l:i == l:num)
+ if indent(l:i) < ind && s:OneScope(l:i)
+ let bL += s:W
+ let l:i = line('.')
+ elseif !a:cont || bL || ind < indent(a:i)
+ break
+ endif
+ let ind = min([ind, indent(l:i)])
+ let l:i = s:PrevCodeLine(l:i - 1)
+ endwhile
+ return bL
+endfunction
+
+" https://github.com/sweet-js/sweet.js/wiki/design#give-lookbehind-to-the-reader
+function s:IsBlock()
+ if s:looking_at() == '{'
+ let l:n = line('.')
+ let char = s:previous_token()
+ let syn = char =~ '[{>/]' ? s:syn_at(line('.'),col('.')-(char == '{')) : ''
+ if syn =~? 'xml\|jsx'
+ return char != '{'
+ elseif char =~ '\k'
+ return index(split('return const let import export yield default delete var await void typeof throw case new in instanceof')
+ \ ,char) < (line('.') != l:n) || s:previous_token() == '.'
+ elseif char == '>'
+ return getline('.')[col('.')-2] == '=' || syn =~? '^jsflow'
+ elseif char == ':'
+ return getline('.')[col('.')-2] != ':' && s:label_col()
+ endif
+ return syn =~? 'regex' || char !~ '[-=~!<*+,/?^%|&([]'
endif
+endfunction
+
+function GetJavascriptIndent()
+ let b:js_cache = get(b:,'js_cache',[0,0,0])
" Get the current line.
- let l:line = getline(v:lnum)
- let syns = synIDattr(synID(v:lnum, 1, 0), 'name')
+ call cursor(v:lnum,1)
+ let l:line = getline('.')
+ let syns = s:syn_at(v:lnum, 1)
- " start with strings,comments,etc.{{{2
- if (l:line !~ '^[''"`]' && syns =~? '\%(string\|template\)') ||
- \ (l:line !~ '^\s*[/*]' && syns =~? s:syng_comment)
+ " start with strings,comments,etc.
+ if syns =~? s:syng_com
+ if l:line =~ '^\s*\*'
+ return cindent(v:lnum)
+ elseif l:line !~ '^\s*\/[/*]'
+ return -1
+ endif
+ elseif syns =~? s:syng_str && l:line !~ '^[''"]'
+ if b:js_cache[0] == v:lnum - 1 && s:Balanced(v:lnum-1)
+ let b:js_cache[0] = v:lnum
+ endif
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
+ if !l:lnum
+ return
endif
- if (l:line =~# s:expr_case)
- let cpo_switch = &cpo
- set cpo+=%
- let ind = cindent(v:lnum)
- let &cpo = cpo_switch
- return ind
+ let l:line = substitute(l:line,'^\s*','','')
+ if l:line[:1] == '/*'
+ let l:line = substitute(l:line,'^\%(\/\*.\{-}\*\/\s*\)*','','')
+ endif
+ if l:line =~ '^\/[/*]'
+ let l:line = ''
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:GetPair(pattern[0],pattern[1],'bW',2000)
+ " the containing paren, bracket, or curly. Many hacks for performance
+ let idx = strlen(l:line) ? stridx('])}',l:line[0]) : -1
+ if b:js_cache[0] >= l:lnum && b:js_cache[0] < v:lnum &&
+ \ (b:js_cache[0] > l:lnum || s:Balanced(l:lnum))
+ call call('cursor',b:js_cache[1:])
else
- let num = s:GetPair('[({[]','[])}]','bW',2000)
+ let [s:looksyn, s:free, top] = [v:lnum - 1, 1, (!indent(l:lnum) &&
+ \ s:syn_at(l:lnum,1) !~? s:syng_str) * l:lnum]
+ if idx + 1
+ call s:GetPair(['\[','(','{'][idx], '])}'[idx],'bW','s:skip_func()',2000,top)
+ elseif indent(v:lnum) && syns =~? 'block'
+ call s:GetPair('{','}','bW','s:skip_func()',2000,top)
+ else
+ call s:alternatePair(top)
+ endif
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)
+ if idx + 1 || l:line[:1] == '|}'
+ if idx == 2 && search('\m\S','bW',line('.')) && s:looking_at() == ')'
+ call s:GetPair('(',')','bW',s:skip_expr,200)
+ endif
+ return indent('.')
endif
- call cursor(b:js_cache[1],b:js_cache[2])
-
- let swcase = getline(l:lnum) =~# s:expr_case
- let pline = swcase ? getline(l:lnum) : substitute(getline(l:lnum), '\%(:\@<!\/\/.*\)$', '','')
- let inb = num == 0 || num < l:lnum && ((l:line !~ s:line_pre . ',' && pline !~ ',' . s:line_term) || s:IsBlock())
- let switch_offset = num == 0 || s:OneScope(num, strpart(getline(num),0,b:js_cache[2] - 1),1) !=# '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 && !swcase && ((l:line =~# g:javascript_opfirst || pline =~# g:javascript_continuation) ||
- \ num < l:lnum && s:OneScope(l:lnum,pline,0) =~# '\<\%(for\|each\|if\|let\|no\sb\|w\%(hile\|ith\)\)\>' &&
- \ 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
+ let b:js_cache = [v:lnum] + (line('.') == v:lnum ? [0,0] : getpos('.')[1:2])
+ let num = b:js_cache[1]
+
+ let [s:W, isOp, bL, switch_offset] = [s:sw(),0,0,0]
+ if !num || s:IsBlock()
+ let pline = s:save_pos('s:Trim',l:lnum)
+ if num && s:looking_at() == ')' && s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0
+ let num = line('.')
+ if s:previous_token() ==# 'switch' && s:previous_token() != '.'
+ if &cino !~ ':' || !has('float')
+ let switch_offset = s:W
+ else
+ let cinc = matchlist(&cino,'.*:\(-\)\=\([0-9.]*\)\(s\)\=\C')
+ let switch_offset = float2nr(str2float(cinc[1].(strlen(cinc[2]) ? cinc[2] : strlen(cinc[3])))
+ \ * (strlen(cinc[3]) ? s:W : 1))
+ endif
+ if pline[-1:] != '.' && l:line =~# '^\%(default\|case\)\>'
+ return indent(num) + switch_offset
+ endif
+ endif
+ endif
+ if pline[-1:] !~ '[{;]'
+ if pline =~# ':\@<!:$'
+ call cursor(l:lnum,strlen(pline))
+ let isOp = s:tern_col(b:js_cache[1:2])
+ else
+ let isOp = l:line =~# s:opfirst || s:continues(l:lnum,pline)
+ endif
+ let bL = s:iscontOne(l:lnum,num,isOp)
+ let bL -= (bL && l:line[0] == '{') * s:W
+ endif
endif
+ " main return
+ if isOp
+ return (num ? indent(num) : -s:W) + (s:W * 2) + switch_offset + bL
+ elseif num
+ return indent(num) + s:W + switch_offset + bL
+ endif
+ return bL
endfunction
-
let &cpo = s:cpo_save
unlet s:cpo_save