11" Vim indent file
22" Language: Javascript
3- " Maintainer: vim-javascript community
4- " URL: https://github.com/pangloss/vim-javascript
5- " Acknowledgement: Based off of vim-ruby maintained by Nikolai Weibull http://vim-ruby.rubyforge.org
3+ " Maintainer: vim-javascript community
4+ " URL: https://github.com/pangloss/vim-javascript
5+ " Last Change: August 20, 2016
66
77" Only load this indent file when no other was loaded.
8- if exists (" b:did_indent" )
8+ if exists (' b:did_indent' )
99 finish
1010endif
1111let b: did_indent = 1
1212
1313" Now, set up our indentation expression and keys that trigger it.
1414setlocal indentexpr = GetJavascriptIndent ()
15- setlocal nolisp
15+ setlocal nolisp noautoindent nosmartindent
1616setlocal indentkeys = 0 {,0 },0 ),0 ],:,! ^F,o ,O,e
1717setlocal cinoptions += j1,J1
1818
19- let b: undo_indent = ' setlocal indentexpr< indentkeys< cinoptions<'
19+ let b: undo_indent = ' setlocal indentexpr< smartindent< autoindent< indentkeys< cinoptions<'
2020
2121" Only define the function once.
22- if exists (" *GetJavascriptIndent" )
22+ if exists (' *GetJavascriptIndent' )
2323 finish
2424endif
2525
@@ -28,125 +28,120 @@ set cpo&vim
2828
2929" Get shiftwidth value
3030if exists (' *shiftwidth' )
31- func s: sw ()
31+ function s: sw ()
3232 return shiftwidth ()
33- endfunc
33+ endfunction
3434else
35- func s: sw ()
35+ function s: sw ()
3636 return &sw
37- endfunc
37+ endfunction
3838endif
3939
40- let s: line_pre = ' ^\s*\%(\/\*.*\*\ /\s*\)* '
41- let s: expr_case = s: line_pre . ' \%(\%(case\>.*\ )\|default\)\s*:\C '
40+ let s: line_pre = ' ^\s*\%(\%(\%(\ /\*.\{-}\)\=\*\+\ /\s*\)\=\)\@> '
41+ let s: expr_case = s: line_pre . ' \%(\%(case\>.\+\ )\|default\)\s*:'
4242" Regex of syntax group names that are or delimit string or are comments.
43- let s: syng_strcom = ' \%(string\|regex\|special\|doc\|comment \|template\)\c '
43+ let s: syng_strcom = ' \%(s\%(tring\|pecial\)\|comment\|regex\|doc \|template\)'
4444
4545" Regex of syntax group names that are strings or documentation.
46- let s: syng_comment = ' \%(comment\|doc\)\c '
46+ let s: syng_comment = ' \%(comment\|doc\)'
4747
4848" Expression used to check whether we should skip a match with searchpair().
49- let s: skip_expr = " line('.') < (prevnonblank(v:lnum) - 2000) ? dummy : s:IsSyn( line('.'),col('.'),'') "
49+ let s: skip_expr = " synIDattr(synID( line('.'),col('.'),0),'name') =~? ' " . s: syng_strcom . " ' "
5050
51- func s: lookForParens (start ,end ,flags,time)
52- try
53- return searchpair (a: start ,' ' ,a: end ,a: flags ,s: skip_expr ,0 ,a: time )
54- catch /E118/
55- return searchpair (a: start ,' ' ,a: end ,a: flags ,0 ,0 )
56- endtry
57- endfunc
51+ if has (' reltime' )
52+ function s: GetPair (start ,end ,flags,time)
53+ return searchpair (a: start ,' ' ,a: end ,a: flags ,s: skip_expr ,max ([prevnonblank (v: lnum ) - 2000 ,0 ]),a: time )
54+ endfunction
55+ else
56+ function s: GetPair (start ,end ,flags,n )
57+ return searchpair (a: start ,' ' ,a: end ,a: flags ,0 ,max ([prevnonblank (v: lnum ) - 2000 ,0 ]))
58+ endfunction
59+ endif
5860
59- let s: line_term = ' \s*\%(\%(:\@<!\/\/.*\)\=\ |\%(\/\*.*\*\/\s*\) *\)$'
61+ let s: line_term = ' \s*\%(\%(\/\%(\%(\*.\{-}\*\/\)\ |\%(\*\+\)\)\)\s *\)\= $'
6062
6163" configurable regexes that define continuation lines, not including (, {, or [.
6264if ! exists (' g:javascript_opfirst' )
63- let g: javascript_opfirst = ' \%([,:?^%]\|\([-/.+]\)\%(\1\|\*\|\/\)\ @!\|\*\/\@!\| =>\@!\||\|&\| in\%(stanceof\)\=\>\)\C '
65+ let g: javascript_opfirst = ' \%([<> ,:?^%|*& ]\|\([-/.+]\)\1\ @!\|=>\@!\|in\%(stanceof\)\=\>\)'
6466endif
65- let g: javascript_opfirst = s: line_pre . g: javascript_opfirst
66-
6767if ! exists (' g:javascript_continuation' )
68- let g: javascript_continuation = ' \%([* ,.?:^%]\|+\@<!+\|-\@<!-\|\*\ @<!\/\|=\||\|&\|\ <in\%(stanceof\)\=\)\C '
68+ let g: javascript_continuation = ' \%([<= ,.?/* :^%|& ]\|+\@<!+\|-\@<!-\|=\ @<!>\|\ <in\%(stanceof\)\=\)'
6969endif
70+
71+ let g: javascript_opfirst = s: line_pre . g: javascript_opfirst
7072let g: javascript_continuation .= s: line_term
7173
72- function s: Onescope (lnum,text,add )
73- return a: text = ~ ' \%(\<else\|\<do\|=>' . (a: add ? ' \|\<try\|\<finally' : ' ' ) . ' \)\C' . s: line_term ||
74- \ (a: add && a: text = ~ s: line_pre . s: line_term && getline (s: PrevCodeLine (a: lnum - 1 )) = ~ ' )' . s: line_term ) ||
75- \ (cursor (a: lnum , match (a: text , ' )' . s: line_term )) > -1 &&
76- \ s: lookForParens (' (' , ' )' , ' cbW' , 100 ) > 0 &&
77- \ search ((a: add ? ' \%(function\*\|[A-Za-z_$][0-9A-Za-z_$]*\)\C' :
78- \ ' \<\%(for\%(\s+each\)\=\|if\|let\|switch\|while\|with\)\C' ) . ' \_s*\%#' ,' bW' )) &&
79- \ (a: add || (expand (" <cword>" ) == ' while' ? ! s: lookForParens (' \<do\>\C' , ' \<while\>\C' ,' bW' ,100 ) : 1 ))
74+ function s: OneScope (lnum,text,add )
75+ return a: text = ~# ' \%(\<else\|\<do\|=>\)' . s: line_term ? ' no b' :
76+ \ ((a: add && a: text = ~ s: line_pre . ' $' && search (' \%' . s: PrevCodeLine (a: lnum - 1 ) . ' l.)' . s: line_term )) ||
77+ \ cursor (a: lnum , match (a: text , ' )' . s: line_term )) > -1 ) &&
78+ \ s: GetPair (' (' , ' )' , ' cbW' , 100 ) > 0 && search (' \C\l\+\_s*\%#' ,' bW' ) &&
79+ \ (a: add || ((expand (' <cword>' ) !=# ' while' || ! s: GetPair (' \C\<do\>' , ' \C\<while\>' ,' nbW' ,100 )) &&
80+ \ expand (' cword' ) !=# ' each' || search (' \C\<for\_s\+\%#' ,' nbW' ))) ? expand (' <cword>' ) : ' '
8081endfunction
8182
82- " Auxiliary Functions {{{2
83-
84- " Check if the character at lnum: col is inside a string, comment, or is ascii.
85- function s: IsSyn (lnum, col , reg )
86- return synIDattr ( synID ( a: lnum , a: col , 1 ), ' name ' ) = ~? ( a: reg != ' ' ? a: reg : s: syng_strcom )
83+ " https://github.com/sweet-js/sweet.js/wiki/design#give-lookbehind-to-the-reader
84+ function s: IsBlock ()
85+ return getline ( line ( ' . ' ))[ col ( ' . ' ) -1 ] == ' { ' && ! search (
86+ \ ' \C\%(\<return\s*\|\%([-=~!<*+,.?^%|&\[(]\|=\@<!>\|\*\@<!\/\|\<\%(var\|const\|let\|yield\|delete\|void\|t\%(ypeof\|hrow\)\|new\|\<in\%(stanceof\)\=\)\)\_s*\)\%# ' , ' bnW ' ) &&
87+ \ ( ! search ( ' :\_s*\%# ' , ' bW ' ) || ( ! s: GetPair ( ' [({[] ' , ' [])}] ' , ' bW ' , 200 ) || s: IsBlock ()) )
8788endfunction
8889
90+ " Auxiliary Functions {{{2
91+
8992" Find line above 'lnum' that isn't empty, in a comment, or in a string.
9093function s: PrevCodeLine (lnum)
91- let lnum = prevnonblank (a: lnum )
92- while lnum > 0
93- if ! s: IsSyn ( lnum, matchend (getline (lnum), ' ^\s*[^'' "]' ),' ' )
94- break
94+ let l: lnum = prevnonblank (a: lnum )
95+ while l: lnum
96+ if synIDattr ( synID ( l: lnum ,matchend (getline (l: lnum ), ' ^\s*[^'' "]' ),0 ), ' name ' ) !~? s: syng_strcom
97+ return l: lnum
9598 endif
96- let lnum = prevnonblank (lnum - 1 )
99+ let l: lnum = prevnonblank (l: lnum - 1 )
97100 endwhile
98- return lnum
99101endfunction
100102
101- " Check if line 'lnum' has more opening brackets than closing ones.
102- function s: LineHasOpeningBrackets (lnum)
103- let open_0 = 0
104- let open_2 = 0
105- let open_4 = 0
106- let line = getline (a: lnum )
107- let pos = match (line , ' [][(){}]' , 0 )
108- let last = 0
103+ " Check if line 'lnum' has a balanced amount of parentheses.
104+ function s: Balanced (lnum)
105+ let [open_0,open_2,open_4] = [0 ,0 ,0 ]
106+ let l: line = getline (a: lnum )
107+ let pos = match (l: line , ' [][(){}]' , 0 )
109108 while pos != -1
110- if ! s: IsSyn ( a: lnum , pos + 1 , ' ' )
111- let idx = stridx (' (){}[]' , line [pos])
109+ if synIDattr ( synID ( a: lnum ,pos + 1 ,0 ), ' name ' ) !~? s: syng_strcom
110+ let idx = stridx (' (){}[]' , l: line [pos])
112111 if idx % 2 == 0
113112 let open_{idx} = open_{idx} + 1
114- let last = pos
115113 else
116114 let open_{idx - 1 } = open_{idx - 1 } - 1
117115 endif
118116 endif
119- let pos = match (line , ' [][(){}]' , pos + 1 )
117+ let pos = match (l: line , ' [][(){}]' , pos + 1 )
120118 endwhile
121- return [(open_0 > 0 ? 1 : (open_0 == 0 ? 0 : 2 )) . (open_2 > 0 ? 1 : (open_2 == 0 ? 0 : 2 )) .
122- \ (open_4 > 0 ? 1 : (open_4 == 0 ? 0 : 2 )), last ]
119+ return (! open_4 + ! open_2 + ! open_0) - 2
123120endfunction
124121" }}}
125122
126123function GetJavascriptIndent ()
127124 if ! exists (' b:js_cache' )
128125 let b: js_cache = [0 ,0 ,0 ]
129- end
130- " Get the current line.
131- let line = getline (v: lnum )
132- " previous nonblank line number
133- let prevline = prevnonblank (v: lnum - 1 )
134- " previous line of code
135- let lnum = s: PrevCodeLine (v: lnum - 1 )
136- if lnum == 0
137- return 0
138126 endif
127+ " Get the current line.
128+ let l: line = getline (v: lnum )
129+ let syns = synIDattr (synID (v: lnum , 1 , 0 ), ' name' )
139130
140131 " start with strings,comments,etc.{{{2
141- if (line !~ ' ^['' "`]' && s: IsSyn ( v: lnum , 1 , ' string\|template' ) ) ||
142- \ (line !~ ' ^\s*[/*]' && s: IsSyn ( v: lnum , 1 , s: syng_comment) )
132+ if (l: line !~ ' ^['' "`]' && syns = ~? ' \%( string\|template\) ' ) ||
133+ \ (l: line !~ ' ^\s*[/*]' && syns = ~? s: syng_comment )
143134 return -1
144135 endif
145- if line !~ ' ^\%(\/\*\|\s*\/\/\)' && s: IsSyn ( v: lnum , 1 , s: syng_comment)
136+ if l: line !~ ' ^\%(\/\*\|\s*\/\/\)' && syns = ~? s: syng_comment
146137 return cindent (v: lnum )
147138 endif
139+ let l: lnum = s: PrevCodeLine (v: lnum - 1 )
140+ if l: lnum == 0
141+ return 0
142+ endif
148143
149- if (line = ~ s: expr_case )
144+ if (l: line = ~# s: expr_case )
150145 let cpo_switch = &cpo
151146 set cpo += %
152147 let ind = cindent (v: lnum )
@@ -155,41 +150,42 @@ function GetJavascriptIndent()
155150 endif
156151 " }}}
157152
158- " the containing paren, bracket, curly
159- let pcounts = [0 ]
160- if b: js_cache [0 ] >= lnum && b: js_cache [0 ] <= v: lnum && b: js_cache [0 ] &&
161- \ (b: js_cache [0 ] > lnum || map (pcounts,' s:LineHasOpeningBrackets(lnum)' )[0 ][0 ] !~ ' 2' )
162- let num = pcounts[0 ][0 ] = ~ ' 1' ? lnum : b: js_cache [1 ]
163- if pcounts[0 ][0 ] = ~' 1'
164- call cursor (lnum,pcounts[0 ][1 ])
165- end
153+ " the containing paren, bracket, curly. Memoize, last lineNr either has the
154+ " same scope or starts a new one, unless if it closed a scope.
155+ call cursor (v: lnum ,1 )
156+ if b: js_cache [0 ] >= l: lnum && b: js_cache [0 ] < v: lnum && b: js_cache [0 ] &&
157+ \ (b: js_cache [0 ] > l: lnum || s: Balanced (l: lnum ) > 0 )
158+ let num = b: js_cache [1 ]
159+ elseif syns != ' ' && l: line [0 ] = ~ ' \s'
160+ let pattern = syns = ~? ' block' ? [' {' ,' }' ] : syns = ~? ' jsparen' ? [' (' ,' )' ] :
161+ \ syns = ~? ' jsbracket' ? [' \[' ,' \]' ] : [' [({[]' ,' [])}]' ]
162+ let num = s: GetPair (pattern[0 ],pattern[1 ],' bW' ,2000 )
166163 else
167- call cursor (v: lnum ,1 )
168- let syns = synIDattr (synID (v: lnum , 1 , 1 ), ' name' )
169- if line [0 ] = ~ ' \s' && syns != ' '
170- let pattern = syns = ~? ' funcblock' ? [' {' ,' }' ] : syns = ~? ' jsparen' ? [' (' ,' )' ] : syns = ~? ' jsbracket' ? [' \[' ,' \]' ] :
171- \ [' (\|{\|\[' ,' )\|}\|\]' ]
172- let num = s: lookForParens (pattern[0 ],pattern[1 ],' bW' ,2000 )
173- else
174- let num = s: lookForParens (' (\|{\|\[' ,' )\|}\|\]' ,' bW' ,2000 )
175- end
176- end
164+ let num = s: GetPair (' [({[]' ,' [])}]' ,' bW' ,2000 )
165+ endif
177166 let b: js_cache = [v: lnum ,num,line (' .' ) == v: lnum ? b: js_cache [2 ] : col (' .' )]
178167
179- " most significant part
180- if line = ~ s: line_pre . ' [])}]'
168+ if l: line = ~ s: line_pre . ' [])}]'
181169 return indent (num)
182- end
183- let inb = num == 0 ? 1 : s: Onescope (num, strpart (getline (num),0 ,b: js_cache [2 ] - 1 ),1 )
184- let switch_offset = (! inb || num == 0 ) || expand (" <cword>" ) != ' switch' ? 0 : &cino !~ ' :' || ! has (' float' ) ? s: sw () :
185- \ float2nr (str2float (matchstr (&cino ,' .*:\zs[-0-9.]*' )) * (match (&cino ,' .*:\zs[^,]*s' ) ? s: sw () : 1 ))
186- if ((line = ~ g: javascript_opfirst ||
187- \ (getline (lnum) = ~ g: javascript_continuation && getline (lnum) !~ s: expr_case )) &&
188- \ inb) || (s: Onescope (lnum,getline (lnum),0 ) && line !~ s: line_pre . ' {' )
170+ endif
171+
172+ call cursor (b: js_cache [1 ],b: js_cache [2 ])
173+
174+ let swcase = getline (l: lnum ) = ~# s: expr_case
175+ let pline = swcase ? getline (l: lnum ) : substitute (getline (l: lnum ), ' \%(:\@<!\/\/.*\)$' , ' ' ,' ' )
176+ let inb = num == 0 || num < l: lnum && ((l: line !~ s: line_pre . ' ,' && pline !~ ' ,' . s: line_term ) || s: IsBlock ())
177+ let switch_offset = num == 0 || s: OneScope (num, strpart (getline (num),0 ,b: js_cache [2 ] - 1 ),1 ) !=# ' switch' ? 0 :
178+ \ &cino !~ ' :' || ! has (' float' ) ? s: sw () :
179+ \ float2nr (str2float (matchstr (&cino ,' .*:\zs[-0-9.]*' )) * (&cino = ~# ' .*:[^,]*s' ? s: sw () : 1 ))
180+
181+ " most significant, find the indent amount
182+ if inb && ! swcase && ((l: line = ~# g: javascript_opfirst || pline = ~# g: javascript_continuation ) ||
183+ \ num < l: lnum && s: OneScope (l: lnum ,pline,0 ) = ~# ' \<\%(for\|each\|if\|let\|no\sb\|w\%(hile\|ith\)\)\>' &&
184+ \ l: line !~ s: line_pre . ' {' )
189185 return (num > 0 ? indent (num) : - s: sw ()) + (s: sw () * 2 ) + switch_offset
190186 elseif num > 0
191187 return indent (num) + s: sw () + switch_offset
192- end
188+ endif
193189
194190endfunction
195191
0 commit comments