diff --git a/extras/flow.vim b/extras/flow.vim index a1848830..028ea3fc 100644 --- a/extras/flow.vim +++ b/extras/flow.vim @@ -6,7 +6,7 @@ syntax region jsFlowParens contained matchgroup=jsFlowNoise start=/(/ syntax match jsFlowNoise contained /[:;,<>]/ syntax keyword jsFlowType contained boolean number string null void any mixed JSON array function object array bool class syntax keyword jsFlowTypeof contained typeof skipempty skipempty nextgroup=jsFlowTypeCustom,jsFlowType -syntax match jsFlowTypeCustom contained /\k*/ skipwhite skipempty nextgroup=jsFlowGroup +syntax match jsFlowTypeCustom contained /[0-9a-zA-Z_.]*/ skipwhite skipempty nextgroup=jsFlowGroup syntax region jsFlowGroup contained matchgroup=jsFlowNoise start=// contains=@jsFlowCluster syntax region jsFlowArrowArguments contained matchgroup=jsFlowNoise start=/(/ end=/)\%(\s*=>\)\@=/ oneline skipwhite skipempty nextgroup=jsFlowArrow contains=@jsFlowCluster syntax match jsFlowArrow contained /=>/ skipwhite skipempty nextgroup=jsFlowType,jsFlowTypeCustom,jsFlowParens diff --git a/indent/javascript.vim b/indent/javascript.vim index 1591dac0..9720c7f8 100644 --- a/indent/javascript.vim +++ b/indent/javascript.vim @@ -1,8 +1,8 @@ " Vim indent file " Language: Javascript -" Maintainer: vim-javascript community +" Maintainer: Chris Paul ( https://github.com/bounceme ) " URL: https://github.com/pangloss/vim-javascript -" Last Change: September 4, 2016 +" Last Change: October 9, 2016 " Only load this indent file when no other was loaded. if exists('b:did_indent') @@ -38,63 +38,124 @@ else endif let s:line_pre = '^\s*\%(\%(\%(\/\*.\{-}\)\=\*\+\/\s*\)\=\)\@>' -let s:expr_case = s:line_pre . '\%(\%(case\>.\+\)\|default\)\s*:\C' +let s:line_term = '\s*\%(\%(\/\%(\%(\*.\{-}\*\/\)\|\%(\*\+\)\)\)\s*\)\=$' + +let s:expr_case = '\<\%(\%(case\>\s*\S.\{-}\)\|default\)\s*:\C' " 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."'" function s:skip_func(lnum) - if !s:free || getline(line('.')) =~ '[''/"\\]' || search('`','nW',a:lnum) || search('\*\/','nW',a:lnum) + if !s:free || search('`','nW',a:lnum) || search('\*\/','nW',a:lnum) let s:free = !eval(s:skip_expr) + let s:looksyn = s:free ? line('.') : s:looksyn + return !s:free endif - let s:looksyn = s:free ? line('.') : s:looksyn - return !s:free + let s:looksyn = line('.') + return (search('\/','nbW',line('.')) || search('[''"\\]','nW',line('.'))) && eval(s:skip_expr) endfunction if has('reltime') - function s:GetPair(start,end,flags,skip,time) - return searchpair(a:start,'',a:end,a:flags,a:skip,max([prevnonblank(v:lnum) - 2000,0]),a:time) + function s:GetPair(start,end,flags,skip,time,...) + return searchpair(a:start,'',a:end,a:flags,a:skip,max([prevnonblank(v:lnum) - 2000,0] + a:000),a:time) endfunction else function s:GetPair(start,end,flags,...) - return searchpair(a:start,'',a:end,a:flags,0,max([prevnonblank(v:lnum) - 2000,0])) + return searchpair(a:start,'',a:end,a:flags,"line('.') < prevnonblank(v:lnum) - 2000 ? dummy : 0") endfunction endif -let s:line_term = '\s*\%(\%(\/\%(\%(\*.\{-}\*\/\)\|\%(\*\+\)\)\)\s*\)\=$' +" indent/python.vim +function s:Trimline(ln) + let pline = getline(a:ln) + let min = match(pline,'\/[/*]') + 1 + if min && synIDattr(synID(a:ln, strlen(pline), 0), 'name') =~? '\%(comment\|doc\)' + let max = match(pline,'.*\zs\/[/*]') + 1 + while min < max + let col = (min + max) / 2 + if synIDattr(synID(a:ln, col, 0), 'name') =~? '\%(comment\|doc\)' + let max = col + else + let min = match(pline,'\/[/*]',col) + 1 + endif + endwhile + let pline = strpart(pline, 0, min - 1) + endif + return substitute(pline,'\s*$','','') +endfunction " configurable regexes that define continuation lines, not including (, {, or [. if !exists('g:javascript_opfirst') - let g:javascript_opfirst = '\%([<>,?^%|*&]\|\/[^/*]\|\([-.:+]\)\1\@!\|=>\@!\|in\%(stanceof\)\=\>\)' + let g:javascript_opfirst = '\%([<>,?^%|*&]\|\/[/*]\@!\|\([-.:+]\)\1\@!\|=>\@!\|in\%(stanceof\)\=\>\)' endif if !exists('g:javascript_continuation') let g:javascript_continuation = '\%([<=,.?/*^%|&:]\|+\@\|\\)' . s:line_term ? 'no b' : - \ cursor(a:lnum, match(' ' . a:text, ')' . s:line_term)) > -1 && - \ s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0 && search('\C\l\+\_s*\%#','bW') && - \ (expand('') !=# 'while' || s:GetPair('\C\', '\C\','nbW',s:skip_expr,100) <= 0) && - \ (expand('') !=# 'each' || search('\C\') : '' + return cursor(a:lnum, match(' ' . a:text, '\%(\\)$')) > -1 || + \ cursor(a:lnum, match(' ' . a:text, ')$')) > -1 && + \ s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0 && + \ search('\C\<\%(for\%(\_s\+\%(await\|each\)\)\=\|if\|let\|w\%(hile\|ith\)\)\_s*\%#','bW') +endfunction + +function s:iscontOne(i,num,cont) + let [l:i, l:cont, l:num] = [a:i, a:cont, a:num + !a:num] + let pind = a:num ? indent(l:num) : -s:W + let ind = indent(l:i) + (!l:cont * s:W) + let bL = 0 + while l:i >= l:num && (!l:cont || ind > pind + s:W) + if indent(l:i) < ind " first line always true for !a:cont, false for !!a:cont + if s:OneScope(l:i,s:Trimline(l:i)) + if expand('') ==# 'while' && + \ s:GetPair(s:line_pre . '\C\','\C\','bW',s:skip_expr,100,l:num + !!a:num) > 0 + return 0 + endif + let bL += 1 + let [l:cont, l:i] = [0, line('.')] + elseif !l:cont + break + endif + let ind = indent(l:i) + endif + let l:i = s:PrevCodeLine(l:i - 1) + endwhile + return bL * s:W 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\%(\\|\*\@') !~# + \ '^\%(var\|const\|let\|\%(im\|ex\)port\|yield\|de\%(fault\|lete\)\|void\|t\%(ypeof\|hrow\)\|new\|in\%(stanceof\)\=\)$' + elseif char == '>' + return search('=\%#','bW') || synIDattr(synID(line('.'),col('.'),0),'name') =~? 'flownoise' + elseif char == ':' + return strpart(getline(line('.')),0,col('.')) =~# s:expr_case . '$' + elseif char == '{' + return s:IsBlock() + else + return char !~# '[-=~!<*+,./?^%|&\[(]' + endif + else + return 1 + endif + endif endfunction -" Auxiliary Functions {{{2 - " 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) @@ -114,7 +175,7 @@ function s:Balanced(lnum) 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 + if !(idx % 2) let open_{idx} += 1 else let open_{idx - 1} -= 1 @@ -125,11 +186,13 @@ function s:Balanced(lnum) endif let pos = match(l:line, '[][(){}]', pos + 1) endwhile - return (!open_4 + !open_2 + !open_0) - 2 + return !(open_4 || open_2 || open_0) endfunction -" }}} function GetJavascriptIndent() + try + let save_magic = &magic + set magic if !exists('b:js_cache') let b:js_cache = [0,0,0] endif @@ -137,66 +200,85 @@ function GetJavascriptIndent() 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) + " start with strings,comments,etc. + if syns =~? '\%(comment\|doc\)' + if l:line =~ '^\s*\*' + return cindent(v:lnum) + elseif l:line !~ '^\s*\/' + return -1 + endif + elseif syns =~? '\%(string\|template\)' && l:line !~ '^[''"]' 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 l:line = substitute(l:line,'^\s*\%(\/\*.\{-}\*\/\s*\)*','','') + + 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. - let [s:looksyn,s:free] = [v:lnum - 1,1] call cursor(v:lnum,1) - if b:js_cache[0] < v:lnum && b:js_cache[0] >= l:lnum && - \ (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','s:skip_func(s:looksyn)',2000) + if getline(l:lnum) !~ '^\S' + let [s:looksyn,s:free] = [v:lnum - 1,1] + if b:js_cache[0] >= l:lnum && b:js_cache[0] < v:lnum && + \ (b:js_cache[0] > l:lnum || s:Balanced(l:lnum)) + let num = b:js_cache[1] + elseif l:line =~ '^[])}]' + let id = stridx('])}',l:line[0]) + let num = s:GetPair(escape('[({'[id],'['), escape('])}'[id],']'),'bW','s:skip_func(s:looksyn)',2000) + elseif syns != '' && getline(v:lnum)[0] =~ '\s' + let pattern = syns =~? 'block' ? ['{','}'] : syns =~? 'jsparen' ? ['(',')'] : + \ syns =~? 'jsbracket'? ['\[','\]'] : ['[({[]','[])}]'] + let num = s:GetPair(pattern[0],pattern[1],'bW','s:skip_func(s:looksyn)',2000) + else + let num = s:GetPair('[({[]','[])}]','bW','s:skip_func(s:looksyn)',2000) + endif else - let num = s:GetPair('[({[]','[])}]','bW','s:skip_func(s:looksyn)',2000) + let num = s:GetPair('[({[]','[])}]','bW',s:skip_expr,200,l:lnum) endif + let num = (num > 0) * num + if l:line =~ '^[])}]' + return !!num * indent(num) + 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) + call cursor(v:lnum,1) + if l:line =~# '^while\>' && s:GetPair(s:line_pre . '\C\','\C\','bW',s:skip_expr,100,num + 1) > 0 + return indent(line('.')) endif - let pline = substitute(substitute(getline(l:lnum),s:expr_case,'\=repeat(" ",strlen(submatch(0)))',''), '\%(:\@ 0 && search('\C\' && - \ 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 isOp = l:line =~# g:javascript_opfirst || pline !~# s:expr_case . '$' && pline =~# g:javascript_continuation + let bL = s:iscontOne(l:lnum,num,isOp) + let bL -= (bL && l:line =~ '^{') * s:W + if isOp && (!num || cursor(b:js_cache[1],b:js_cache[2]) || s:IsBlock()) + 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 + finally + let &magic = save_magic + endtry endfunction diff --git a/syntax/javascript.vim b/syntax/javascript.vim index e6503357..74b619b1 100644 --- a/syntax/javascript.vim +++ b/syntax/javascript.vim @@ -84,7 +84,7 @@ syntax match jsObjectSeparator contained /,/ syntax region jsObjectValue contained start=/:/ end=/\%(,\|}\)\@=/ contains=jsObjectColon,@jsExpression extend syntax match jsObjectFuncName contained /\<[a-zA-Z_$][0-9a-zA-Z_$]*\>[\r\n\t ]*(\@=/ skipwhite skipempty nextgroup=jsFuncArgs syntax match jsFunctionKey contained /\<[a-zA-Z_$][0-9a-zA-Z_$]*\>\(\s*:\s*function\s*\)\@=/ -syntax match jsObjectMethodType contained /\%(get\|set\|static\|async\)\%( \k\+\)\@=/ contains=jsAsyncKeyword skipwhite skipempty nextgroup=jsObjectFuncName +syntax match jsObjectMethodType contained /\%(get\|set\|static\|async\)\%( \k\+\)\@=/ skipwhite skipempty nextgroup=jsObjectFuncName syntax region jsObjectStringKey contained start=+"+ skip=+\\\("\|$\)+ end=+"\|$+ contains=jsSpecial,@Spell extend skipwhite skipempty nextgroup=jsFuncArgs,jsObjectValue syntax region jsObjectStringKey contained start=+'+ skip=+\\\('\|$\)+ end=+'\|$+ contains=jsSpecial,@Spell extend skipwhite skipempty nextgroup=jsFuncArgs,jsObjectValue @@ -101,21 +101,20 @@ syntax keyword jsStatement contained break continue with yield debugger syntax keyword jsConditional if skipwhite skipempty nextgroup=jsParenIfElse syntax keyword jsConditional else skipwhite skipempty nextgroup=jsCommentMisc,jsIfElseBlock syntax keyword jsConditional switch skipwhite skipempty nextgroup=jsParenSwitch -syntax keyword jsRepeat while for skipwhite skipempty nextgroup=jsParenRepeat +syntax keyword jsRepeat while for skipwhite skipempty nextgroup=jsParenRepeat,jsForAwait syntax keyword jsDo do skipwhite skipempty nextgroup=jsRepeatBlock syntax keyword jsLabel contained case default syntax keyword jsTry try skipwhite skipempty nextgroup=jsTryCatchBlock syntax keyword jsFinally contained finally skipwhite skipempty nextgroup=jsFinallyBlock syntax keyword jsCatch contained catch skipwhite skipempty nextgroup=jsParenCatch syntax keyword jsException throw -syntax keyword jsAsyncKeyword async skipwhite skipempty nextgroup=jsFunction,jsFuncName -syntax keyword jsAwaitKeyword await +syntax keyword jsAsyncKeyword async await syntax match jsSwitchColon contained /:/ skipwhite skipempty nextgroup=jsSwitchBlock " Keywords syntax keyword jsGlobalObjects Array Boolean Date Function Iterator Number Object Symbol Map WeakMap Set RegExp String Proxy Promise Buffer ParallelArray ArrayBuffer DataView Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray JSON Math console document window Intl Collator DateTimeFormat NumberFormat syntax keyword jsGlobalNodeObjects module exports global process -syntax match jsGlobalNodeObjects /require/ contains=jsFuncCall +syntax match jsGlobalNodeObjects /require/ containedin=jsFuncCall syntax keyword jsExceptions Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError syntax keyword jsBuiltins decodeURI decodeURIComponent encodeURI encodeURIComponent eval isFinite isNaN parseFloat parseInt uneval " DISCUSS: How imporant is this, really? Perhaps it should be linked to an error because I assume the keywords are reserved? @@ -165,6 +164,7 @@ syntax match jsFuncName contained /\<[a-zA-Z_$][0-9a-zA-Z_$]*\>/ s syntax region jsFuncArgExpression contained matchgroup=jsFuncArgOperator start=/=/ end=/[,)]\@=/ contains=@jsExpression extend syntax match jsFuncArgCommas contained ',' syntax keyword jsArguments contained arguments +syntax keyword jsForAwait contained await skipwhite skipempty nextgroup=jsParenRepeat " Matches a single keyword argument with no parens syntax match jsArrowFuncArgs /\k\+\s*\%(=>\)\@=/ skipwhite contains=jsFuncArgs skipwhite skipempty nextgroup=jsArrowFunction extend @@ -172,12 +172,12 @@ syntax match jsArrowFuncArgs /\k\+\s*\%(=>\)\@=/ skipwhite contains=jsFuncArg syntax match jsArrowFuncArgs /([^()]*)\s*\(=>\)\@=/ contains=jsFuncArgs skipempty skipwhite nextgroup=jsArrowFunction extend exe 'syntax match jsFunction /\/ skipwhite skipempty nextgroup=jsGenerator,jsFuncName,jsFuncArgs skipwhite '.(exists('g:javascript_conceal_function') ? 'conceal cchar='.g:javascript_conceal_function : '') -exe 'syntax match jsArrowFunction /=>/ skipwhite skipempty nextgroup=jsFuncBlock contains=jsFuncBraces '.(exists('g:javascript_conceal_arrow_function') ? 'conceal cchar='.g:javascript_conceal_arrow_function : '') +exe 'syntax match jsArrowFunction /=>/ skipwhite skipempty nextgroup=jsFuncBlock,jsCommentFunction '.(exists('g:javascript_conceal_arrow_function') ? 'conceal cchar='.g:javascript_conceal_arrow_function : '') " Classes syntax keyword jsClassKeywords contained extends class syntax match jsClassNoise contained /\./ -syntax match jsClassMethodType contained /\%(get\|set\|static\|async\)\%( \k\+\)\@=/ contains=jsAsyncKeyword skipwhite skipempty nextgroup=jsFuncName,jsClassProperty +syntax match jsClassMethodType contained /\%(get\|set\|static\|async\)\%( \k\+\)\@=/ skipwhite skipempty nextgroup=jsFuncName,jsClassProperty syntax match jsClassDefinition /\\%( [a-zA-Z_$][0-9a-zA-Z_$ \n.]*\)*/ contains=jsClassKeywords,jsClassNoise skipwhite skipempty nextgroup=jsCommentClass,jsClassBlock,jsFlowClassGroup syntax match jsClassProperty contained /\<[0-9a-zA-Z_$]*\>\(\s*=\)\@=/ skipwhite skipempty nextgroup=jsClassValue syntax region jsClassValue contained start=/=/ end=/\%(;\|}\|\n\)\@=/ contains=@jsExpression @@ -227,8 +227,8 @@ if exists("javascript_plugin_flow") runtime extras/flow.vim endif -syntax cluster jsExpression contains=jsBracket,jsParen,jsObject,jsBlock,jsTernaryIf,jsTaggedTemplate,jsTemplateString,jsString,jsRegexpString,jsNumber,jsFloat,jsOperator,jsBooleanTrue,jsBooleanFalse,jsNull,jsFunction,jsArrowFunction,jsGlobalObjects,jsExceptions,jsFutureKeys,jsDomErrNo,jsDomNodeConsts,jsHtmlEvents,jsFuncCall,jsUndefined,jsNan,jsPrototype,jsBuiltins,jsNoise,jsClassDefinition,jsArrowFunction,jsArrowFuncArgs,jsParensError,jsComment,jsArguments,jsThis,jsSuper,jsDo,jsAsyncKeyword,jsAwaitKeyword -syntax cluster jsAll contains=@jsExpression,jsExportContainer,jsImportContainer,jsStorageClass,jsConditional,jsRepeat,jsReturn,jsStatement,jsException,jsTry +syntax cluster jsExpression contains=jsBracket,jsParen,jsObject,jsBlock,jsTernaryIf,jsTaggedTemplate,jsTemplateString,jsString,jsRegexpString,jsNumber,jsFloat,jsOperator,jsBooleanTrue,jsBooleanFalse,jsNull,jsFunction,jsArrowFunction,jsGlobalObjects,jsExceptions,jsFutureKeys,jsDomErrNo,jsDomNodeConsts,jsHtmlEvents,jsFuncCall,jsUndefined,jsNan,jsPrototype,jsBuiltins,jsNoise,jsClassDefinition,jsArrowFunction,jsArrowFuncArgs,jsParensError,jsComment,jsArguments,jsThis,jsSuper,jsDo +syntax cluster jsAll contains=@jsExpression,jsExportContainer,jsImportContainer,jsStorageClass,jsConditional,jsRepeat,jsReturn,jsStatement,jsException,jsTry,jsAsyncKeyword " Define the default highlighting. " For version 5.7 and earlier: only when not done already @@ -276,7 +276,7 @@ if version >= 508 || !exists("did_javascript_syn_inits") HiLink jsFinally Exception HiLink jsCatch Exception HiLink jsAsyncKeyword Keyword - HiLink jsAwaitKeyword Keyword + HiLink jsForAwait Keyword HiLink jsArrowFunction Type HiLink jsFunction Type HiLink jsGenerator jsFunction