Skip to content

Commit 782cc10

Browse files
authored
Merge pull request #604 from pangloss/develop
Develop -> Master
2 parents 8e3f589 + 5900fce commit 782cc10

File tree

3 files changed

+108
-103
lines changed

3 files changed

+108
-103
lines changed

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ variables:
9797
let g:javascript_conceal_super = "Ω"
9898
let g:javascript_conceal_arrow_function = "⇒"
9999

100+
## Indentation Specific
101+
102+
* `:h cino-:`
103+
* End-of-line continuations : `g:javascript_continuation` ( slightly complicated, look at the source code )
104+
* Start-of-line continuations : `g:javascript_opfirst` ( same as above )
100105

101106
## Contributing
102107

after/ftplugin/javascript.vim

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@
55

66
setlocal iskeyword+=$ suffixesadd+=.js
77

8-
let b:undo_ftplugin .= ' | setlocal iskeyword< suffixesadd<'
8+
if exists('b:undo_ftplugin')
9+
let b:undo_ftplugin .= ' | setlocal iskeyword< suffixesadd<'
10+
else
11+
let b:undo_ftplugin = 'setlocal iskeyword< suffixesadd<'
12+
endif

indent/javascript.vim

+98-102
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
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
1010
endif
1111
let b:did_indent = 1
1212

1313
" Now, set up our indentation expression and keys that trigger it.
1414
setlocal indentexpr=GetJavascriptIndent()
15-
setlocal nolisp
15+
setlocal nolisp noautoindent nosmartindent
1616
setlocal indentkeys=0{,0},0),0],:,!^F,o,O,e
1717
setlocal 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
2424
endif
2525

@@ -28,125 +28,120 @@ set cpo&vim
2828

2929
" Get shiftwidth value
3030
if exists('*shiftwidth')
31-
func s:sw()
31+
function s:sw()
3232
return shiftwidth()
33-
endfunc
33+
endfunction
3434
else
35-
func s:sw()
35+
function s:sw()
3636
return &sw
37-
endfunc
37+
endfunction
3838
endif
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 [.
6264
if !exists('g:javascript_opfirst')
63-
let g:javascript_opfirst = '\%([,:?^%]\|\([-/.+]\)\%(\1\|\*\|\/\)\@!\|\*\/\@!\|=>\@!\||\|&\|in\%(stanceof\)\=\>\)\C'
65+
let g:javascript_opfirst = '\%([<>,:?^%|*&]\|\([-/.+]\)\1\@!\|=>\@!\|in\%(stanceof\)\=\>\)'
6466
endif
65-
let g:javascript_opfirst = s:line_pre . g:javascript_opfirst
66-
6767
if !exists('g:javascript_continuation')
68-
let g:javascript_continuation = '\%([*,.?:^%]\|+\@<!+\|-\@<!-\|\*\@<!\/\|=\||\|&\|\<in\%(stanceof\)\=\)\C'
68+
let g:javascript_continuation = '\%([<=,.?/*:^%|&]\|+\@<!+\|-\@<!-\|=\@<!>\|\<in\%(stanceof\)\=\)'
6969
endif
70+
71+
let g:javascript_opfirst = s:line_pre . g:javascript_opfirst
7072
let 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>') : ''
8081
endfunction
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()))
8788
endfunction
8889

90+
" Auxiliary Functions {{{2
91+
8992
" Find line above 'lnum' that isn't empty, in a comment, or in a string.
9093
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
9598
endif
96-
let lnum = prevnonblank(lnum - 1)
99+
let l:lnum = prevnonblank(l:lnum - 1)
97100
endwhile
98-
return lnum
99101
endfunction
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
123120
endfunction
124121
" }}}
125122

126123
function 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

194190
endfunction
195191

0 commit comments

Comments
 (0)