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