1
1
" Vim indent file
2
2
" 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
6
6
7
7
" Only load this indent file when no other was loaded.
8
- if exists (" b:did_indent" )
8
+ if exists (' b:did_indent' )
9
9
finish
10
10
endif
11
11
let b: did_indent = 1
12
12
13
13
" Now, set up our indentation expression and keys that trigger it.
14
14
setlocal indentexpr = GetJavascriptIndent ()
15
- setlocal nolisp
15
+ setlocal nolisp noautoindent nosmartindent
16
16
setlocal indentkeys = 0 {,0 },0 ),0 ],:,! ^F,o ,O,e
17
17
setlocal cinoptions += j1,J1
18
18
19
- let b: undo_indent = ' setlocal indentexpr< indentkeys< cinoptions<'
19
+ let b: undo_indent = ' setlocal indentexpr< smartindent< autoindent< indentkeys< cinoptions<'
20
20
21
21
" Only define the function once.
22
- if exists (" *GetJavascriptIndent" )
22
+ if exists (' *GetJavascriptIndent' )
23
23
finish
24
24
endif
25
25
@@ -28,125 +28,120 @@ set cpo&vim
28
28
29
29
" Get shiftwidth value
30
30
if exists (' *shiftwidth' )
31
- func s: sw ()
31
+ function s: sw ()
32
32
return shiftwidth ()
33
- endfunc
33
+ endfunction
34
34
else
35
- func s: sw ()
35
+ function s: sw ()
36
36
return &sw
37
- endfunc
37
+ endfunction
38
38
endif
39
39
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*:'
42
42
" 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\)'
44
44
45
45
" 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\)'
47
47
48
48
" 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 . " ' "
50
50
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
58
60
59
- let s: line_term = ' \s*\%(\%(:\@<!\/\/.*\)\=\ |\%(\/\*.*\*\/\s*\) *\)$'
61
+ let s: line_term = ' \s*\%(\%(\/\%(\%(\*.\{-}\*\/\)\ |\%(\*\+\)\)\)\s *\)\= $'
60
62
61
63
" configurable regexes that define continuation lines, not including (, {, or [.
62
64
if ! exists (' g:javascript_opfirst' )
63
- let g: javascript_opfirst = ' \%([,:?^%]\|\([-/.+]\)\%(\1\|\*\|\/\)\ @!\|\*\/\@!\| =>\@!\||\|&\| in\%(stanceof\)\=\>\)\C '
65
+ let g: javascript_opfirst = ' \%([<> ,:?^%|*& ]\|\([-/.+]\)\1\ @!\|=>\@!\|in\%(stanceof\)\=\>\)'
64
66
endif
65
- let g: javascript_opfirst = s: line_pre . g: javascript_opfirst
66
-
67
67
if ! exists (' g:javascript_continuation' )
68
- let g: javascript_continuation = ' \%([* ,.?:^%]\|+\@<!+\|-\@<!-\|\*\ @<!\/\|=\||\|&\|\ <in\%(stanceof\)\=\)\C '
68
+ let g: javascript_continuation = ' \%([<= ,.?/* :^%|& ]\|+\@<!+\|-\@<!-\|=\ @<!>\|\ <in\%(stanceof\)\=\)'
69
69
endif
70
+
71
+ let g: javascript_opfirst = s: line_pre . g: javascript_opfirst
70
72
let g: javascript_continuation .= s: line_term
71
73
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>' ) : ' '
80
81
endfunction
81
82
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 ()) )
87
88
endfunction
88
89
90
+ " Auxiliary Functions {{{2
91
+
89
92
" Find line above 'lnum' that isn't empty, in a comment, or in a string.
90
93
function 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
95
98
endif
96
- let lnum = prevnonblank (lnum - 1 )
99
+ let l: lnum = prevnonblank (l: lnum - 1 )
97
100
endwhile
98
- return lnum
99
101
endfunction
100
102
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 )
109
108
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])
112
111
if idx % 2 == 0
113
112
let open_{idx} = open_{idx} + 1
114
- let last = pos
115
113
else
116
114
let open_{idx - 1 } = open_{idx - 1 } - 1
117
115
endif
118
116
endif
119
- let pos = match (line , ' [][(){}]' , pos + 1 )
117
+ let pos = match (l: line , ' [][(){}]' , pos + 1 )
120
118
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
123
120
endfunction
124
121
" }}}
125
122
126
123
function GetJavascriptIndent ()
127
124
if ! exists (' b:js_cache' )
128
125
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
138
126
endif
127
+ " Get the current line.
128
+ let l: line = getline (v: lnum )
129
+ let syns = synIDattr (synID (v: lnum , 1 , 0 ), ' name' )
139
130
140
131
" 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 )
143
134
return -1
144
135
endif
145
- if line !~ ' ^\%(\/\*\|\s*\/\/\)' && s: IsSyn ( v: lnum , 1 , s: syng_comment)
136
+ if l: line !~ ' ^\%(\/\*\|\s*\/\/\)' && syns = ~? s: syng_comment
146
137
return cindent (v: lnum )
147
138
endif
139
+ let l: lnum = s: PrevCodeLine (v: lnum - 1 )
140
+ if l: lnum == 0
141
+ return 0
142
+ endif
148
143
149
- if (line = ~ s: expr_case )
144
+ if (l: line = ~# s: expr_case )
150
145
let cpo_switch = &cpo
151
146
set cpo += %
152
147
let ind = cindent (v: lnum )
@@ -155,41 +150,42 @@ function GetJavascriptIndent()
155
150
endif
156
151
" }}}
157
152
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 )
166
163
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
177
166
let b: js_cache = [v: lnum ,num,line (' .' ) == v: lnum ? b: js_cache [2 ] : col (' .' )]
178
167
179
- " most significant part
180
- if line = ~ s: line_pre . ' [])}]'
168
+ if l: line = ~ s: line_pre . ' [])}]'
181
169
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 . ' {' )
189
185
return (num > 0 ? indent (num) : - s: sw ()) + (s: sw () * 2 ) + switch_offset
190
186
elseif num > 0
191
187
return indent (num) + s: sw () + switch_offset
192
- end
188
+ endif
193
189
194
190
endfunction
195
191
0 commit comments