diff options
author | Adam Stankiewicz <sheerun@sher.pl> | 2016-05-31 01:53:12 +0200 |
---|---|---|
committer | Adam Stankiewicz <sheerun@sher.pl> | 2016-05-31 01:53:12 +0200 |
commit | 44b3d860cb85ccb4edd52fb0dcf6a4102d12e82a (patch) | |
tree | 537e871f1d923c01c3d5098fd2958c198d093977 /indent/javascript.vim | |
parent | 5a65ffe66d19da9989ae6b71962830ca6c80f5b5 (diff) | |
download | vim-polyglot-44b3d860cb85ccb4edd52fb0dcf6a4102d12e82a.tar.gz vim-polyglot-44b3d860cb85ccb4edd52fb0dcf6a4102d12e82a.zip |
Updatev2.9.1
Diffstat (limited to 'indent/javascript.vim')
-rw-r--r-- | indent/javascript.vim | 327 |
1 files changed, 147 insertions, 180 deletions
diff --git a/indent/javascript.vim b/indent/javascript.vim index 90e84cb5..68e21ed2 100644 --- a/indent/javascript.vim +++ b/indent/javascript.vim @@ -19,6 +19,7 @@ setlocal nosmartindent setlocal indentexpr=GetJavascriptIndent() setlocal formatexpr=Fixedgq(v:lnum,v:count) setlocal indentkeys=0{,0},0),0],0\,:,!^F,o,O,e +setlocal cinoptions+=j1,J1 " Only define the function once. if exists("*GetJavascriptIndent") @@ -42,19 +43,17 @@ endif " 1. Variables {{{1 " ============ -let s:js_keywords = '^\s*\(break\|catch\|const\|continue\|debugger\|delete\|do\|else\|finally\|for\|function\|if\|in\|instanceof\|let\|new\|return\|switch\|this\|throw\|try\|typeof\|var\|void\|while\|with\)' -let s:expr_case = '^\s*\(case\s\+[^\:]*\|default\)\s*:\s*' +let s:line_pre = '^\s*\%(\/\*.*\*\/\s*\)*' +let s:js_keywords = s:line_pre . '\%(break\|catch\|const\|continue\|debugger\|delete\|do\|else\|finally\|for\|function\|if\|in\|instanceof\|let\|new\|return\|switch\|this\|throw\|try\|typeof\|var\|void\|while\|with\)\>\C' +let s:expr_case = s:line_pre . '\%(case\s\+[^\:]*\|default\)\s*:\s*\C' " Regex of syntax group names that are or delimit string or are comments. -let s:syng_strcom = '\%(\%(template\)\@<!string\|regex\|comment\)\c' - -" Regex of syntax group names that are or delimit template strings -let s:syng_template = 'template\c' +let s:syng_strcom = '\%(string\|regex\|comment\|template\)\c' " Regex of syntax group names that are strings. let s:syng_string = 'regex\c' " Regex of syntax group names that are strings or documentation. -let s:syng_multiline = 'comment\c' +let s:syng_multiline = '\%(comment\|doc\)\c' " Regex of syntax group names that are line comment. let s:syng_linecom = 'linecomment\c' @@ -62,37 +61,39 @@ let s:syng_linecom = 'linecomment\c' " Expression used to check whether we should skip a match with searchpair(). let s:skip_expr = "synIDattr(synID(line('.'),col('.'),1),'name') =~ '".s:syng_strcom."'" -let s:line_term = '\s*\%(\%(\/\/\).*\)\=$' +let s:line_term = '\s*\%(\%(\/\/.*\)\=\|\%(\/\*.*\*\/\s*\)*\)$' " Regex that defines continuation lines, not including (, {, or [. -let s:continuation_regex = '\%([\\*/.:]\|+\@<!+\|-\@<!-\|\%(<%\)\@<!=\|\W[|&?]\|||\|&&\|[^=]=[^=>].*,\)' . s:line_term +let s:continuation_regex = '\%([*.?:]\|+\@<!+\|-\@<!-\|\*\@<!\/\|=\|||\|&&\)' . s:line_term -" Regex that defines continuation lines. -" TODO: this needs to deal with if ...: and so on -let s:msl_regex = s:continuation_regex.'\|'.s:expr_case +let s:one_line_scope_regex = '\%(\<else\>\|=>\)\C' . s:line_term -let s:one_line_scope_regex = '\%(\%(\<else\>\|\<\%(if\|for\|while\)\>\s*(\%([^()]*\|[^()]*(\%([^()]*\|[^()]*(\%([^()]*\|[^()]*([^()]*)[^()]*\))[^()]*\))[^()]*\))\)\|=>\)' . s:line_term +function s:Onescope(lnum) + if getline(a:lnum) =~ s:one_line_scope_regex + return 1 + end + let mypos = col('.') + call cursor(a:lnum, 1) + if search('\<\%(while\|for\|if\)\>\s*(\C', 'ce', a:lnum) > 0 && + \ searchpair('(', '', ')', 'W', s:skip_expr, a:lnum) > 0 && + \ col('.') == strlen(s:RemoveTrailingComments(getline(a:lnum))) + call cursor(a:lnum, mypos) + return 1 + else + call cursor(a:lnum, mypos) + return 0 + end +endfunction " Regex that defines blocks. -let s:block_regex = '\%([{([]\)\s*\%(|\%([*@]\=\h\w*,\=\s*\)\%(,\s*[*@]\=\h\w*\)*|\)\=' . s:line_term +let s:block_regex = '[{([]' . s:line_term -let s:operator_first = '^\s*\%([*/.:?]\|\([-+]\)\1\@!\|||\|&&\)' +let s:operator_first = s:line_pre . '\%([.,:?]\|\([-/+*]\)\%(\1\|\*\|\/\)\@!\|||\|&&\)' -let s:var_stmt = '^\s*\%(const\|let\|var\)' +let s:var_stmt = s:line_pre . '\%(const\|let\|var\)\s\+\C' -let s:comma_first = '^\s*,' -let s:comma_last = ',\s*$' +let s:comma_last = ',' . s:line_term -let s:case_indent = s:sw() -let s:case_indent_after = s:sw() -let s:m = matchlist(&cinoptions, ':\(.\)') -if (len(s:m) > 2) - let s:case_indent = s:m[1] -endif -let s:m = matchlist(&cinoptions, '=\(.\)') -if (len(s:m) > 2) - let s:case_indent_after = s:m[1] -endif " 2. Auxiliary Functions {{{1 " ====================== @@ -106,11 +107,6 @@ function s:IsInString(lnum, col) return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_string endfunction -" Check if the character at lnum:col is inside a template string. -function s:IsInTempl(lnum, col) - return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_template -endfunction - " Check if the character at lnum:col is inside a multi-line comment. function s:IsInMultilineComment(lnum, col) return !s:IsLineComment(a:lnum, a:col) && synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_multiline @@ -129,15 +125,15 @@ function s:PrevNonBlankNonString(lnum) " Go in and out of blocks comments as necessary. " If the line isn't empty (with opt. comment) or in a string, end search. let line = getline(lnum) - if s:IsInMultilineComment(lnum, matchend(line, '/\*') - 1) + if s:IsInMultilineComment(lnum, matchend(line, '^\s*/\*') - 1) && line !~ s:line_pre . '$' if in_block let in_block = 0 else break endif - elseif !in_block && s:IsInMultilineComment(lnum, matchend(line, '\*/') - 1) + elseif !in_block && s:IsInMultilineComment(lnum, match(line, '\*/\s*$') + 1) && line !~ s:line_pre . '$' let in_block = 1 - elseif !in_block && line !~ '^\s*\%(//\).*$' && !(s:IsInStringOrComment(lnum, 1) && s:IsInStringOrComment(lnum, strlen(line))) + elseif !in_block && line !~ s:line_pre . '\%(//\).*$' && !(s:IsInStringOrComment(lnum, 1) && s:IsInStringOrComment(lnum, strlen(line))) break endif let lnum = prevnonblank(lnum - 1) @@ -154,10 +150,12 @@ function s:GetMSL(lnum, in_one_line_scope) " If we have a continuation line, or we're in a string, use line as MSL. " Otherwise, terminate search as we have found our MSL already. let line = getline(lnum) - let col = match(line, s:msl_regex) + 1 + let col = match(line, s:continuation_regex) + 1 + let coal = match(line, s:comma_last) + 1 let line2 = getline(msl) let col2 = matchend(line2, ')') - if (col > 0 && !s:IsInStringOrComment(lnum, col)) || s:IsInString(lnum, strlen(line)) + if ((col > 0 && !s:IsInStringOrComment(lnum, col) || coal > 0 && !s:IsInStringOrComment(lnum,coal)) && + \ !s:Match(lnum, s:expr_case)) || s:IsInString(lnum, strlen(line)) let msl = lnum " if there are more closing brackets, continue from the line which has the matching opening bracket @@ -176,7 +174,7 @@ function s:GetMSL(lnum, in_one_line_scope) if a:in_one_line_scope break end - let msl_one_line = s:Match(lnum, s:one_line_scope_regex) + let msl_one_line = s:Onescope(lnum) if msl_one_line == 0 break endif @@ -187,34 +185,41 @@ function s:GetMSL(lnum, in_one_line_scope) endfunction function s:RemoveTrailingComments(content) - let single = '\/\/\(.*\)\s*$' - let multi = '\/\*\(.*\)\*\/\s*$' - return substitute(substitute(a:content, single, '', ''), multi, '', '') + let single = '\/\/\%(.*\)\s*$' + let multi = '\/\*\%(.*\)\*\/\s*$' + return substitute(substitute(substitute(a:content, single, '', ''), multi, '', ''), '\s\+$', '', '') endfunction " Find if the string is inside var statement (but not the first string) -function s:InMultiVarStatement(lnum) +function s:InMultiVarStatement(lnum, cont, prev) let lnum = s:PrevNonBlankNonString(a:lnum - 1) -" let type = synIDattr(synID(lnum, indent(lnum) + 1, 0), 'name') + " let type = synIDattr(synID(lnum, indent(lnum) + 1, 0), 'name') " loop through previous expressions to find a var statement - while lnum > 0 - let line = getline(lnum) - + while lnum > 0 && (s:Match(lnum, s:comma_last) ||(a:cont && getline(lnum) =~ s:line_pre . '}') || + \ s:Match(lnum,s:continuation_regex)) || (a:prev && (s:Match(a:prev, s:comma_last) || + \ s:Match(a:prev,s:continuation_regex))) " if the line is a js keyword - if (line =~ s:js_keywords) + if a:cont + call cursor(lnum,1) + if searchpair('{', '', '}', 'bW', s:skip_expr) > 0 + let lnum = line('.') + end + end + if s:Match(lnum, s:js_keywords) " check if the line is a var stmt " if the line has a comma first or comma last then we can assume that we " are in a multiple var statement - if (line =~ s:var_stmt) + if s:Match(lnum, s:var_stmt) && (s:Match(lnum, s:comma_last)||s:Match(lnum,s:continuation_regex)) return lnum endif " other js keywords, not a var - return 0 + if !s:Match(lnum, s:comma_last)||!s:Match(lnum,s:continuation_regex) + return 0 + end endif - let lnum = s:PrevNonBlankNonString(lnum - 1) endwhile @@ -222,25 +227,25 @@ function s:InMultiVarStatement(lnum) return 0 endfunction -" Find line above with beginning of the var statement or returns 0 if it's not +" Find line above with beginning of the var statement or returns 0 if it's not"{{{2 " this statement -function s:GetVarIndent(lnum) - let lvar = s:InMultiVarStatement(a:lnum) - let prev_lnum = s:PrevNonBlankNonString(a:lnum - 1) +" function s:GetVarIndent(lnum) +" let lvar = s:InMultiVarStatement(a:lnum, 0,0) +" let prev_lnum = s:PrevNonBlankNonString(a:lnum - 1) - if lvar - let line = s:RemoveTrailingComments(getline(prev_lnum)) +" if lvar +" let line = s:RemoveTrailingComments(getline(prev_lnum)) - " if the previous line doesn't end in a comma, return to regular indent - if (line !~ s:comma_last) - return indent(prev_lnum) - s:sw() - else - return indent(lvar) + s:sw() - endif - endif +" " if the previous line doesn't end in a comma, return to regular indent +" if (line !~ s:comma_last) +" return indent(prev_lnum) - s:sw() +" else +" return indent(lvar) + s:sw() +" endif +" endif - return -1 -endfunction +" return -1 +" endfunction"}}} " Check if line 'lnum' has more opening brackets than closing ones. @@ -261,7 +266,7 @@ function s:LineHasOpeningBrackets(lnum) endif let pos = match(line, '[][(){}]', pos + 1) endwhile - return (open_0 > 0 ? 1 : (open_0 == 0 ? 0 : 2)) . (open_2 > 0) . (open_4 > 0) + return (open_0 > 0 ? 1 : (open_0 == 0 ? 0 : 2)) . (open_2 > 0 ? 1 : (open_2 == 0 ? 0 : 2)) . (open_4 > 0 ? 1 : (open_4 == 0 ? 0 : 2)) endfunction function s:Match(lnum, regex) @@ -293,7 +298,9 @@ function s:IndentWithContinuation(lnum, ind, width) return msl_ind + a:width else return msl_ind - endif + end + elseif s:InMultiVarStatement(p_lnum, 0, s:PrevNonBlankNonString(p_lnum - 1)) + return indent(p_lnum) - s:sw() endif return a:ind @@ -301,7 +308,7 @@ endfunction function s:InOneLineScope(lnum) let msl = s:GetMSL(a:lnum, 1) - if msl > 0 && s:Match(msl, s:one_line_scope_regex) + if msl > 0 && s:Onescope(msl) return msl endif return 0 @@ -311,11 +318,11 @@ function s:ExitingOneLineScope(lnum) let msl = s:GetMSL(a:lnum, 1) if msl > 0 " if the current line is in a one line scope .. - if s:Match(msl, s:one_line_scope_regex) + if s:Onescope(msl) return 0 else let prev_msl = s:GetMSL(msl - 1, 1) - if s:Match(prev_msl, s:one_line_scope_regex) + if s:Onescope(prev_msl) return prev_msl endif endif @@ -327,13 +334,12 @@ endfunction " ========================= function GetJavascriptIndent() - " 3.1. Setup {{{2 + " 3.1. Setup {{{1 " ---------- - " Set up variables for restoring position in file. Could use v:lnum here. let vcol = col('.') - " 3.2. Work on the current line {{{2 + " 3.2. Work on the current line {{{1 " ----------------------------- let ind = -1 @@ -341,117 +347,80 @@ function GetJavascriptIndent() let line = getline(v:lnum) " previous nonblank line number let prevline = prevnonblank(v:lnum - 1) + + " to not change multiline string values + if synIDattr(synID(v:lnum, 1, 1), 'name') =~? 'string\|template' && line !~ s:line_pre . '[''"`]' + return indent(v:lnum) + endif + + " If we are in a multi-line comment, cindent does the right thing. + if s:IsInMultilineComment(v:lnum, 1) && !s:IsLineComment(v:lnum, 1) && + \ s:IsInMultilineComment(v:lnum, match(line, '\s*$')) && line !~ '^\/\*' + return cindent(v:lnum) + endif + + " single opening bracket will assume you want a c style of indenting + if s:Match(v:lnum, s:line_pre . '{' . s:line_term) + return cindent(v:lnum) + endif + " cindent each line which has a switch label if (line =~ s:expr_case) - if (getline(prevline) =~ s:expr_case) - return indent(prevline) - else - if (getline(prevline) =~ s:block_regex) - return indent(prevline) + s:case_indent - else - return indent(prevline) - s:case_indent_after - endif - endif + return cindent(v:lnum) endif + " If we got a closing bracket on an empty line, find its match and indent " according to it. For parentheses we indent to its column - 1, for the " others we indent to the containing line's MSL's level. Return -1 if fail. - let col = matchend(line, '^\s*[],})]') + let col = matchend(line, s:line_pre . '[]})]') if col > 0 && !s:IsInStringOrComment(v:lnum, col) call cursor(v:lnum, col) - let lvar = s:InMultiVarStatement(v:lnum) - if lvar - let prevline_contents = s:RemoveTrailingComments(getline(prevline)) - - " check for comma first - if (line[col - 1] =~ ',') - " if the previous line ends in comma or semicolon don't indent - if (prevline_contents =~ '[;,]\s*$') - return indent(s:GetMSL(line('.'), 0)) - " get previous line indent, if it's comma first return prevline indent - elseif (prevline_contents =~ s:comma_first) - return indent(prevline) - " otherwise we indent 1 level - else - return indent(lvar) + s:sw() - endif - endif - endif - let bs = strpart('(){}[]', stridx(')}]', line[col - 1]) * 2, 2) if searchpair(escape(bs[0], '\['), '', bs[1], 'bW', s:skip_expr) > 0 - if line[col-1]==')' && col('.') != col('$') - 1 - let ind = virtcol('.')-1 - else - let ind = indent(s:GetMSL(line('.'), 0)) - endif + let ind = s:InMultiVarStatement(line('.'), 0, 0) ? indent(line('.')) : indent(s:GetMSL(line('.'), 0)) endif return ind endif - " If the line is comma first, dedent 1 level - if (getline(prevline) =~ s:comma_first) - return indent(prevline) - s:sw() - endif - if (getline(prevline) =~ s:expr_case) - return indent(prevline) + s:case_indent_after - endif - " If line starts with an operator... - if (s:Match(v:lnum, s:operator_first)) + if (line =~ s:operator_first) if (s:Match(prevline, s:operator_first)) " and so does previous line, don't indent return indent(prevline) end let counts = s:LineHasOpeningBrackets(prevline) - if counts[0] == '2' + if counts[0] == '2' || counts[1] == '2' || counts[2] == '2' call cursor(prevline, 1) " Search for the opening tag - let mnum = searchpair('(', '', ')', 'bW', s:skip_expr) - if mnum > 0 && s:Match(mnum, s:operator_first) - return indent(mnum) + let bs = strpart('(){}[]', stridx(')}]', line[col - 1]) * 2, 2) + if searchpair(escape(bs[0], '\['), '', bs[1], 'bW', s:skip_expr) > 0 && s:Match(line('.'), s:operator_first) + return indent(line('.')) end elseif counts[0] != '1' && counts[1] != '1' && counts[2] != '1' " otherwise, indent 1 level return indent(prevline) + s:sw() end + " If previous line starts with an operator... - elseif s:Match(prevline, s:operator_first) && !s:Match(prevline, s:comma_last) && !s:Match(prevline, '};\=' . s:line_term) + elseif (s:Match(prevline, s:operator_first) && !s:Match(prevline,s:continuation_regex))||getline(prevline) =~ ');\=' . s:line_term let counts = s:LineHasOpeningBrackets(prevline) - if counts[0] == '2' && counts[1] == '1' + if counts[0] == '2' && !s:Match(prevline, s:operator_first) call cursor(prevline, 1) " Search for the opening tag let mnum = searchpair('(', '', ')', 'bW', s:skip_expr) - if mnum > 0 && !s:Match(mnum, s:operator_first) - return indent(mnum) + s:sw() + if mnum > 0 && s:Match(mnum, s:operator_first) + return indent(mnum) - s:sw() + end + elseif s:Match(prevline, s:operator_first) + if counts[0] != '1' && counts[1] != '1' && counts[2] != '1' + return indent(prevline) - s:sw() end - elseif counts[0] != '1' && counts[1] != '1' && counts[2] != '1' - return indent(prevline) - s:sw() end end - if getline(prevline) =~ '^\s*`$' && s:IsInTempl(v:lnum, 1) - if line !~ '^\s*`$' - return indent(prevline) + s:sw() - endif - elseif line =~ '^\s*`$' && s:IsInTempl(prevline, 1) - return indent(prevline) - s:sw() - endif - - " If we are in a multi-line comment, cindent does the right thing. - if s:IsInMultilineComment(v:lnum, 1) && !s:IsLineComment(v:lnum, 1) - return cindent(v:lnum) - endif - - " Check for multiple var assignments -" let var_indent = s:GetVarIndent(v:lnum) -" if var_indent >= 0 -" return var_indent -" endif - - " 3.3. Work on the previous line. {{{2 + " 3.3. Work on the previous line. {{{1 " ------------------------------- " If the line is empty and the previous nonblank line was a multi-line @@ -477,11 +446,7 @@ function GetJavascriptIndent() " If the previous line ended with a block opening, add a level of indent. if s:Match(lnum, s:block_regex) - if (line =~ s:expr_case) - return indent(s:GetMSL(lnum, 0)) + s:sw()/2 - else - return indent(s:GetMSL(lnum, 0)) + s:sw() - endif + return s:InMultiVarStatement(lnum, 0, 0) ? indent(lnum) + s:sw() : indent(s:GetMSL(lnum, 0)) + s:sw() endif " Set up variables for current line. @@ -489,43 +454,43 @@ function GetJavascriptIndent() let ind = indent(lnum) " If the previous line contained an opening bracket, and we are still in it, " add indent depending on the bracket type. - if line =~ '[[({]' - let counts = s:LineHasOpeningBrackets(lnum) - if counts[0] == '1' && searchpair('(', '', ')', 'bW', s:skip_expr) > 0 - if col('.') + 1 == col('$') || line =~ s:one_line_scope_regex - return ind + s:sw() - else - return virtcol('.') - endif - elseif counts[1] == '1' || counts[2] == '1' && counts[0] != '2' - return ind + s:sw() - else - call cursor(v:lnum, vcol) - end - elseif line =~ '.\+};\=' . s:line_term - call cursor(lnum, 1) - " Search for the opening tag - let mnum = searchpair('{', '', '}', 'bW', s:skip_expr) - if mnum > 0 - return indent(s:GetMSL(mnum, 0)) - end - elseif line =~ '.\+);\=' || line =~ s:comma_last + if s:Match(lnum, '[[({})\]]') let counts = s:LineHasOpeningBrackets(lnum) if counts[0] == '2' call cursor(lnum, 1) " Search for the opening tag - let mnum = searchpair('(', '', ')', 'bW', s:skip_expr) - if mnum > 0 - return indent(s:GetMSL(mnum, 0)) + if searchpair('(', '', ')', 'bW', s:skip_expr) > 0 + return indent(s:GetMSL(line('.'), 0)) end - elseif line !~ s:var_stmt - return indent(prevline) + elseif counts[1] == '2' && !s:Match(lnum, s:line_pre . '}') + call cursor(lnum, 1) + " Search for the opening tag + if searchpair('{', '', '}', 'bW', s:skip_expr) > 0 + return indent(s:GetMSL(line('.'), 0)) + end + elseif counts[2] == '2' && !s:Match(lnum, s:line_pre . ']') + call cursor(lnum, 1) + " Search for the opening tag + if searchpair('\[', '', '\]', 'bW', s:skip_expr) > 0 + return indent(s:GetMSL(line('.'), 0)) + end + elseif counts[1] == '1' || counts[2] == '1' || counts[0] == '1' || s:Onescope(lnum) + return ind + s:sw() + else + call cursor(v:lnum, vcol) end end - " 3.4. Work on the MSL line. {{{2 + " 3.4. Work on the MSL line. {{{1 " -------------------------- + if s:Match(lnum, s:comma_last) && !s:Match(lnum, s:continuation_regex) + return s:Match(lnum, s:var_stmt) ? indent(lnum) + s:sw() : indent(lnum) + elseif s:Match(s:PrevNonBlankNonString(lnum - 1), s:comma_last) + if !s:Match(lnum, s:comma_last) && s:InMultiVarStatement(lnum,1,0) + return indent(lnum) - s:sw() + end + end let ind_con = ind let ind = s:IndentWithContinuation(lnum, ind_con, s:sw()) @@ -550,7 +515,7 @@ endfunction let &cpo = s:cpo_save unlet s:cpo_save - +" gq{{{2 function! Fixedgq(lnum, count) let l:tw = &tw ? &tw : 80; @@ -611,5 +576,7 @@ function! Fixedgq(lnum, count) return 0 endfunction +"}}} +" vim: foldmethod=marker:foldlevel=1 endif |