diff options
| author | Adam Stankiewicz <sheerun@sher.pl> | 2013-09-12 16:17:03 +0200 | 
|---|---|---|
| committer | Adam Stankiewicz <sheerun@sher.pl> | 2013-09-12 16:17:03 +0200 | 
| commit | 01fe1500df97577452f755b526c09d8ed0c802ea (patch) | |
| tree | 9e2e038630cc9e82abcd17da6dd3407a9b3bc62a /indent | |
| parent | dce12af91b404835938e95de9e6d839d52487ed5 (diff) | |
| download | vim-polyglot-01fe1500df97577452f755b526c09d8ed0c802ea.tar.gz vim-polyglot-01fe1500df97577452f755b526c09d8ed0c802ea.zip | |
Add support for basic languages
coffee, cucumbeer, eruby, haml, haskell, javascript,
json, less, nginx, ocaml, ruby, sass, scss, slim,
stylus, textile, tmux
Diffstat (limited to '')
| -rw-r--r-- | indent/coffee.vim | 418 | ||||
| -rw-r--r-- | indent/cucumber.vim | 74 | ||||
| -rw-r--r-- | indent/eruby.vim | 91 | ||||
| -rw-r--r-- | indent/haml.vim | 73 | ||||
| -rw-r--r-- | indent/haskell.vim | 85 | ||||
| -rw-r--r-- | indent/javascript.vim | 439 | ||||
| -rw-r--r-- | indent/less.vim | 11 | ||||
| -rw-r--r-- | indent/ocaml.vim | 267 | ||||
| -rw-r--r-- | indent/ruby.vim | 537 | ||||
| -rw-r--r-- | indent/sass.vim | 40 | ||||
| -rw-r--r-- | indent/scss.vim | 12 | ||||
| -rw-r--r-- | indent/slim.vim | 75 | ||||
| -rw-r--r-- | indent/stylus.vim | 129 | 
13 files changed, 2251 insertions, 0 deletions
| diff --git a/indent/coffee.vim b/indent/coffee.vim new file mode 100644 index 00000000..49953151 --- /dev/null +++ b/indent/coffee.vim @@ -0,0 +1,418 @@ +" Language:    CoffeeScript +" Maintainer:  Mick Koch <kchmck@gmail.com> +" URL:         http://github.com/kchmck/vim-coffee-script +" License:     WTFPL + +if exists('b:did_indent') +  finish +endif + +let b:did_indent = 1 + +setlocal autoindent +setlocal indentexpr=GetCoffeeIndent(v:lnum) +" Make sure GetCoffeeIndent is run when these are typed so they can be +" indented or outdented. +setlocal indentkeys+=0],0),0.,=else,=when,=catch,=finally + +" If no indenting or outdenting is needed, either keep the indent of the cursor +" (use autoindent) or match the indent of the previous line. +if exists('g:coffee_indent_keep_current') +  let s:DEFAULT_LEVEL = '-1' +else +  let s:DEFAULT_LEVEL = 'indent(prevnlnum)' +endif + +" Only define the function once. +if exists('*GetCoffeeIndent') +  finish +endif + +" Keywords that begin a block +let s:BEGIN_BLOCK_KEYWORD = '\C^\%(if\|unless\|else\|for\|while\|until\|' +\                         . 'loop\|switch\|when\|try\|catch\|finally\|' +\                         . 'class\)\>\%(\s*:\)\@!' + +" An expression that uses the result of a statement +let s:COMPOUND_EXPRESSION = '\C\%([^-]-\|[^+]+\|[^/]/\|[:=*%&|^<>]\)\s*' +\                         . '\%(if\|unless\|for\|while\|until\|loop\|switch\|' +\                         . 'try\|class\)\>' + +" Combine the two above +let s:BEGIN_BLOCK = s:BEGIN_BLOCK_KEYWORD . '\|' . s:COMPOUND_EXPRESSION + +" Operators that begin a block but also count as a continuation +let s:BEGIN_BLOCK_OP = '[([{:=]$' + +" Begins a function block +let s:FUNCTION = '[-=]>$' + +" Operators that continue a line onto the next line +let s:CONTINUATION_OP = '\C\%(\<\%(is\|isnt\|and\|or\)\>\|' +\                     . '[^-]-\|[^+]+\|[^-=]>\|[^.]\.\|[<*/%&|^,]\)$' + +" Ancestor operators that prevent continuation indenting +let s:CONTINUATION = s:CONTINUATION_OP . '\|' . s:BEGIN_BLOCK_OP + +" A closing bracket by itself on a line followed by a continuation +let s:BRACKET_CONTINUATION = '^\s*[}\])]\s*' . s:CONTINUATION_OP + +" A continuation dot access +let s:DOT_ACCESS = '^\.' + +" Keywords that break out of a block +let s:BREAK_BLOCK_OP = '\C^\%(return\|break\|continue\|throw\)\>' + +" A condition attached to the end of a statement +let s:POSTFIX_CONDITION = '\C\S\s\+\zs\<\%(if\|unless\|when\|while\|until\)\>' + +" A then contained in brackets +let s:CONTAINED_THEN = '\C[(\[].\{-}\<then\>.\{-\}[)\]]' + +" An else with a condition attached +let s:ELSE_COND = '\C^\s*else\s\+\<\%(if\|unless\)\>' + +" A single-line else statement (without a condition attached) +let s:SINGLE_LINE_ELSE = '\C^else\s\+\%(\<\%(if\|unless\)\>\)\@!' + +" Pairs of starting and ending keywords, with an initial pattern to match +let s:KEYWORD_PAIRS = [ +\  ['\C^else\>', '\C\<\%(if\|unless\|when\|else\s\+\%(if\|unless\)\)\>', +\   '\C\<else\>'], +\  ['\C^catch\>', '\C\<try\>', '\C\<catch\>'], +\  ['\C^finally\>', '\C\<try\>', '\C\<finally\>'] +\] + +" Pairs of starting and ending brackets +let s:BRACKET_PAIRS = {']': '\[', '}': '{', ')': '('} + +" Max lines to look back for a match +let s:MAX_LOOKBACK = 50 + +" Syntax names for strings +let s:SYNTAX_STRING = 'coffee\%(String\|AssignString\|Embed\|Regex\|Heregex\|' +\                   . 'Heredoc\)' + +" Syntax names for comments +let s:SYNTAX_COMMENT = 'coffee\%(Comment\|BlockComment\|HeregexComment\)' + +" Syntax names for strings and comments +let s:SYNTAX_STRING_COMMENT = s:SYNTAX_STRING . '\|' . s:SYNTAX_COMMENT + +" Get the linked syntax name of a character. +function! s:SyntaxName(lnum, col) +  return synIDattr(synID(a:lnum, a:col, 1), 'name') +endfunction + +" Check if a character is in a comment. +function! s:IsComment(lnum, col) +  return s:SyntaxName(a:lnum, a:col) =~ s:SYNTAX_COMMENT +endfunction + +" Check if a character is in a string. +function! s:IsString(lnum, col) +  return s:SyntaxName(a:lnum, a:col) =~ s:SYNTAX_STRING +endfunction + +" Check if a character is in a comment or string. +function! s:IsCommentOrString(lnum, col) +  return s:SyntaxName(a:lnum, a:col) =~ s:SYNTAX_STRING_COMMENT +endfunction + +" Search a line for a regex until one is found outside a string or comment. +function! s:SearchCode(lnum, regex) +  " Start at the first column and look for an initial match (including at the +  " cursor.) +  call cursor(a:lnum, 1) +  let pos = search(a:regex, 'c', a:lnum) + +  while pos +    if !s:IsCommentOrString(a:lnum, col('.')) +      return 1 +    endif + +    " Move to the match and continue searching (don't accept matches at the +    " cursor.) +    let pos = search(a:regex, '', a:lnum) +  endwhile + +  return 0 +endfunction + +" Search for the nearest previous line that isn't a comment. +function! s:GetPrevNormalLine(startlnum) +  let curlnum = a:startlnum + +  while curlnum +    let curlnum = prevnonblank(curlnum - 1) + +    " Return the line if the first non-whitespace character isn't a comment. +    if !s:IsComment(curlnum, indent(curlnum) + 1) +      return curlnum +    endif +  endwhile + +  return 0 +endfunction + +function! s:SearchPair(startlnum, lookback, skip, open, close) +  " Go to the first column so a:close will be matched even if it's at the +  " beginning of the line. +  call cursor(a:startlnum, 1) +  return searchpair(a:open, '', a:close, 'bnW', a:skip, max([1, a:lookback])) +endfunction + +" Skip if a match +"  - is in a string or comment +"  - is a single-line statement that isn't immediately +"    adjacent +"  - has a postfix condition and isn't an else statement or compound +"    expression +function! s:ShouldSkip(startlnum, lnum, col) +  return s:IsCommentOrString(a:lnum, a:col) || +  \      s:SearchCode(a:lnum, '\C\<then\>') && a:startlnum - a:lnum > 1 || +  \      s:SearchCode(a:lnum, s:POSTFIX_CONDITION) && +  \      getline(a:lnum) !~ s:ELSE_COND && +  \     !s:SearchCode(a:lnum, s:COMPOUND_EXPRESSION) +endfunction + +" Search for the nearest and farthest match for a keyword pair. +function! s:SearchMatchingKeyword(startlnum, open, close) +  let skip = 's:ShouldSkip(' . a:startlnum . ", line('.'), line('.'))" + +  " Search for the nearest match. +  let nearestlnum = s:SearchPair(a:startlnum, a:startlnum - s:MAX_LOOKBACK, +  \                              skip, a:open, a:close) + +  if !nearestlnum +    return [] +  endif + +  " Find the nearest previous line with indent less than or equal to startlnum. +  let ind = indent(a:startlnum) +  let lookback = s:GetPrevNormalLine(a:startlnum) + +  while lookback && indent(lookback) > ind +    let lookback = s:GetPrevNormalLine(lookback) +  endwhile + +  " Search for the farthest match. If there are no other matches, then the +  " nearest match is also the farthest one. +  let matchlnum = nearestlnum + +  while matchlnum +    let lnum = matchlnum +    let matchlnum = s:SearchPair(matchlnum, lookback, skip, a:open, a:close) +  endwhile + +  return [nearestlnum, lnum] +endfunction + +" Strip a line of a trailing comment and surrounding whitespace. +function! s:GetTrimmedLine(lnum) +  " Try to find a comment starting at the first column. +  call cursor(a:lnum, 1) +  let pos = search('#', 'c', a:lnum) + +  " Keep searching until a comment is found or search returns 0. +  while pos +    if s:IsComment(a:lnum, col('.')) +      break +    endif + +    let pos = search('#', '', a:lnum) +  endwhile + +  if !pos +    " No comment was found so use the whole line. +    let line = getline(a:lnum) +  else +    " Subtract 1 to get to the column before the comment and another 1 for +    " column indexing -> zero-based indexing. +    let line = getline(a:lnum)[:col('.') - 2] +  endif + +  return substitute(substitute(line, '^\s\+', '', ''), +  \                                  '\s\+$', '', '') +endfunction + +" Get the indent policy when no special rules are used. +function! s:GetDefaultPolicy(curlnum) +  " Check whether equalprg is being ran on existing lines. +  if strlen(getline(a:curlnum)) == indent(a:curlnum) +    " If not indenting an existing line, use the default policy. +    return s:DEFAULT_LEVEL +  else +    " Otherwise let autoindent determine what to do with an existing line. +    return '-1' +  endif +endfunction + +function! GetCoffeeIndent(curlnum) +  " Get the previous non-blank line (may be a comment.) +  let prevlnum = prevnonblank(a:curlnum - 1) + +  " Bail if there's no code before. +  if !prevlnum +    return -1 +  endif + +  " Bail if inside a multiline string. +  if s:IsString(a:curlnum, 1) +    let prevnlnum = prevlnum +    exec 'return' s:GetDefaultPolicy(a:curlnum) +  endif + +  " Get the code part of the current line. +  let curline = s:GetTrimmedLine(a:curlnum) +  " Get the previous non-comment line. +  let prevnlnum = s:GetPrevNormalLine(a:curlnum) + +  " Check if the current line is the closing bracket in a bracket pair. +  if has_key(s:BRACKET_PAIRS, curline[0]) +    " Search for a matching opening bracket. +    let matchlnum = s:SearchPair(a:curlnum, a:curlnum - s:MAX_LOOKBACK, +    \                            "s:IsCommentOrString(line('.'), col('.'))", +    \                            s:BRACKET_PAIRS[curline[0]], curline[0]) + +    if matchlnum +      " Match the indent of the opening bracket. +      return indent(matchlnum) +    else +      " No opening bracket found (bad syntax), so bail. +      exec 'return' s:GetDefaultPolicy(a:curlnum) +    endif +  endif + +  " Check if the current line is the closing keyword in a keyword pair. +  for pair in s:KEYWORD_PAIRS +    if curline =~ pair[0] +      " Find the nearest and farthest matches within the same indent level. +      let matches = s:SearchMatchingKeyword(a:curlnum, pair[1], pair[2]) + +      if len(matches) +        " Don't force indenting/outdenting as long as line is already lined up +        " with a valid match +        return max([min([indent(a:curlnum), indent(matches[0])]), +        \           indent(matches[1])]) +      else +        " No starting keyword found (bad syntax), so bail. +        exec 'return' s:GetDefaultPolicy(a:curlnum) +      endif +    endif +  endfor + +  " Check if the current line is a `when` and not the first in a switch block. +  if curline =~ '\C^when\>' && !s:SearchCode(prevnlnum, '\C\<switch\>') +    " Look back for a `when`. +    while prevnlnum +      if getline(prevnlnum) =~ '\C^\s*when\>' +        " Indent to match the found `when`, but don't force indenting (for when +        " indenting nested switch blocks.) +        return min([indent(a:curlnum), indent(prevnlnum)]) +      endif + +      let prevnlnum = s:GetPrevNormalLine(prevnlnum) +    endwhile + +    " No matching `when` found (bad syntax), so bail. +    exec 'return' s:GetDefaultPolicy(a:curlnum) +  endif + +  " If the previous line is a comment, use its indentation, but don't force +  " indenting. +  if prevlnum != prevnlnum +    return min([indent(a:curlnum), indent(prevlnum)]) +  endif + +  let prevline = s:GetTrimmedLine(prevnlnum) + +  " Always indent after these operators. +  if prevline =~ s:BEGIN_BLOCK_OP +    return indent(prevnlnum) + shiftwidth() +  endif + +  " Indent if the previous line starts a function block, but don't force +  " indenting if the line is non-blank (for empty function bodies.) +  if prevline =~ s:FUNCTION +    if strlen(getline(a:curlnum)) > indent(a:curlnum) +      return min([indent(prevnlnum) + shiftwidth(), indent(a:curlnum)]) +    else +      return indent(prevnlnum) + shiftwidth() +    endif +  endif + +  " Check if continuation indenting is needed. If the line ends in a slash, make +  " sure it isn't a regex. +  if prevline =~ s:CONTINUATION_OP && +  \  !(prevline =~ '/$' && s:IsString(prevnlnum, col([prevnlnum, '$']) - 1)) +    " Don't indent if the continuation follows a closing bracket. +    if prevline =~ s:BRACKET_CONTINUATION +      exec 'return' s:GetDefaultPolicy(a:curlnum) +    endif + +    let prevprevnlnum = s:GetPrevNormalLine(prevnlnum) + +    " Don't indent if not the first continuation. +    if prevprevnlnum && s:GetTrimmedLine(prevprevnlnum) =~ s:CONTINUATION +      exec 'return' s:GetDefaultPolicy(a:curlnum) +    endif + +    " Continuation indenting seems to vary between programmers, so if the line +    " is non-blank, don't override the indentation +    if strlen(getline(a:curlnum)) > indent(a:curlnum) +      exec 'return' s:GetDefaultPolicy(a:curlnum) +    endif + +    " Otherwise indent a level. +    return indent(prevnlnum) + shiftwidth() +  endif + +  " Check if the previous line starts with a keyword that begins a block. +  if prevline =~ s:BEGIN_BLOCK +    " Indent if the current line doesn't start with `then` and the previous line +    " isn't a single-line statement. +    if curline !~ '\C^\<then\>' && !s:SearchCode(prevnlnum, '\C\<then\>') && +    \  prevline !~ s:SINGLE_LINE_ELSE +      return indent(prevnlnum) + shiftwidth() +    else +      exec 'return' s:GetDefaultPolicy(a:curlnum) +    endif +  endif + +  " Indent a dot access if it's the first. +  if curline =~ s:DOT_ACCESS +    if prevline !~ s:DOT_ACCESS +      return indent(prevnlnum) + shiftwidth() +    else +      exec 'return' s:GetDefaultPolicy(a:curlnum) +    endif +  endif + +  " Outdent if a keyword breaks out of a block as long as it doesn't have a +  " postfix condition (and the postfix condition isn't a single-line statement.) +  if prevline =~ s:BREAK_BLOCK_OP +    if !s:SearchCode(prevnlnum, s:POSTFIX_CONDITION) || +    \   s:SearchCode(prevnlnum, '\C\<then\>') && +    \  !s:SearchCode(prevnlnum, s:CONTAINED_THEN) +      " Don't force indenting. +      return min([indent(a:curlnum), indent(prevnlnum) - shiftwidth()]) +    else +      exec 'return' s:GetDefaultPolicy(a:curlnum) +    endif +  endif + +  " Check if inside brackets. +  let matchlnum = s:SearchPair(a:curlnum, a:curlnum - s:MAX_LOOKBACK, +  \                            "s:IsCommentOrString(line('.'), col('.'))", +  \                            '\[\|(\|{', '\]\|)\|}') + +  " If inside brackets, indent relative to the brackets, but don't outdent an +  " already indented line. +  if matchlnum +    return max([indent(a:curlnum), indent(matchlnum) + shiftwidth()]) +  endif + +  " No special rules applied, so use the default policy. +  exec 'return' s:GetDefaultPolicy(a:curlnum) +endfunction diff --git a/indent/cucumber.vim b/indent/cucumber.vim new file mode 100644 index 00000000..802d2243 --- /dev/null +++ b/indent/cucumber.vim @@ -0,0 +1,74 @@ +" Vim indent file +" Language:	Cucumber +" Maintainer:	Tim Pope <vimNOSPAM@tpope.org> +" Last Change:	2010 May 21 + +if exists("b:did_indent") +  finish +endif +let b:did_indent = 1 + +setlocal autoindent +setlocal indentexpr=GetCucumberIndent() +setlocal indentkeys=o,O,*<Return>,<:>,0<Bar>,0#,=,!^F + +let b:undo_indent = 'setl ai< inde< indk<' + +" Only define the function once. +if exists("*GetCucumberIndent") +  finish +endif + +function! s:syn(lnum) +  return synIDattr(synID(a:lnum,1+indent(a:lnum),1),'name') +endfunction + +function! GetCucumberIndent() +  let line  = getline(prevnonblank(v:lnum-1)) +  let cline = getline(v:lnum) +  let nline = getline(nextnonblank(v:lnum+1)) +  let syn = s:syn(prevnonblank(v:lnum-1)) +  let csyn = s:syn(v:lnum) +  let nsyn = s:syn(nextnonblank(v:lnum+1)) +  if csyn ==# 'cucumberFeature' || cline =~# '^\s*Feature:' +    " feature heading +    return 0 +  elseif csyn ==# 'cucumberExamples' || cline =~# '^\s*\%(Examples\|Scenarios\):' +    " examples heading +    return 2 * &sw +  elseif csyn =~# '^cucumber\%(Background\|Scenario\|ScenarioOutline\)$' || cline =~# '^\s*\%(Background\|Scenario\|Scenario Outline\):' +    " background, scenario or outline heading +    return &sw +  elseif syn ==# 'cucumberFeature' || line =~# '^\s*Feature:' +    " line after feature heading +    return &sw +  elseif syn ==# 'cucumberExamples' || line =~# '^\s*\%(Examples\|Scenarios\):' +    " line after examples heading +    return 3 * &sw +  elseif syn =~# '^cucumber\%(Background\|Scenario\|ScenarioOutline\)$' || line =~# '^\s*\%(Background\|Scenario\|Scenario Outline\):' +    " line after background, scenario or outline heading +    return 2 * &sw +  elseif cline =~# '^\s*[@#]' && (nsyn == 'cucumberFeature' || nline =~# '^\s*Feature:' || indent(prevnonblank(v:lnum-1)) <= 0) +    " tag or comment before a feature heading +    return 0 +  elseif cline =~# '^\s*@' +    " other tags +    return &sw +  elseif cline =~# '^\s*[#|]' && line =~# '^\s*|' +    " mid-table +    " preserve indent +    return indent(prevnonblank(v:lnum-1)) +  elseif cline =~# '^\s*|' && line =~# '^\s*[^|]' +    " first line of a table, relative indent +    return indent(prevnonblank(v:lnum-1)) + &sw +  elseif cline =~# '^\s*[^|]' && line =~# '^\s*|' +    " line after a table, relative unindent +    return indent(prevnonblank(v:lnum-1)) - &sw +  elseif cline =~# '^\s*#' && getline(v:lnum-1) =~ '^\s*$' && (nsyn =~# '^cucumber\%(Background\|Scenario\|ScenarioOutline\)$' || nline =~# '^\s*\%(Background\|Scenario\|Scenario Outline\):') +    " comments on scenarios +    return &sw +  endif +  return indent(prevnonblank(v:lnum-1)) +endfunction + +" vim:set sts=2 sw=2: diff --git a/indent/eruby.vim b/indent/eruby.vim new file mode 100644 index 00000000..19109ceb --- /dev/null +++ b/indent/eruby.vim @@ -0,0 +1,91 @@ +" Vim indent file +" Language:		eRuby +" Maintainer:		Tim Pope <vimNOSPAM@tpope.org> +" URL:			https://github.com/vim-ruby/vim-ruby +" Release Coordinator:	Doug Kearns <dougkearns@gmail.com> + +if exists("b:did_indent") +  finish +endif + +runtime! indent/ruby.vim +unlet! b:did_indent +setlocal indentexpr= + +if exists("b:eruby_subtype") +  exe "runtime! indent/".b:eruby_subtype.".vim" +else +  runtime! indent/html.vim +endif +unlet! b:did_indent + +if &l:indentexpr == '' +  if &l:cindent +    let &l:indentexpr = 'cindent(v:lnum)' +  else +    let &l:indentexpr = 'indent(prevnonblank(v:lnum-1))' +  endif +endif +let b:eruby_subtype_indentexpr = &l:indentexpr + +let b:did_indent = 1 + +setlocal indentexpr=GetErubyIndent() +setlocal indentkeys=o,O,*<Return>,<>>,{,},0),0],o,O,!^F,=end,=else,=elsif,=rescue,=ensure,=when + +" Only define the function once. +if exists("*GetErubyIndent") +  finish +endif + +function! GetErubyIndent(...) +  if a:0 && a:1 == '.' +    let v:lnum = line('.') +  elseif a:0 && a:1 =~ '^\d' +    let v:lnum = a:1 +  endif +  let vcol = col('.') +  call cursor(v:lnum,1) +  let inruby = searchpair('<%','','%>','W') +  call cursor(v:lnum,vcol) +  if inruby && getline(v:lnum) !~ '^<%\|^\s*[-=]\=%>' +    let ind = GetRubyIndent(v:lnum) +  else +    exe "let ind = ".b:eruby_subtype_indentexpr + +    " Workaround for Andy Wokula's HTML indent +    if b:eruby_subtype_indentexpr =~# '^HtmlIndent(' +	  \ && exists('b:indent') +	  \ && type(b:indent) == type({}) +	  \ && has_key(b:indent, 'lnum') +      " Force HTML indent to not keep state +      let b:indent.lnum = -1 +    endif +  endif +  let lnum = prevnonblank(v:lnum-1) +  let line = getline(lnum) +  let cline = getline(v:lnum) +  if cline =~# '^\s*<%[-=]\=\s*\%(}\|end\|else\|\%(ensure\|rescue\|elsif\|when\).\{-\}\)\s*\%([-=]\=%>\|$\)' +    let ind = ind - &sw +  endif +  if line =~# '\S\s*<%[-=]\=\s*\%(}\|end\).\{-\}\s*\%([-=]\=%>\|$\)' +    let ind = ind - &sw +  endif +  if line =~# '\%({\|\<do\)\%(\s*|[^|]*|\)\=\s*[-=]\=%>' +    let ind = ind + &sw +  elseif line =~# '<%[-=]\=\s*\%(module\|class\|def\|if\|for\|while\|until\|else\|elsif\|case\|when\|unless\|begin\|ensure\|rescue\)\>.*%>' +    let ind = ind + &sw +  endif +  if line =~# '^\s*<%[=#-]\=\s*$' && cline !~# '^\s*end\>' +    let ind = ind + &sw +  endif +  if line !~# '^\s*<%' && line =~# '%>\s*$' +    let ind = ind - &sw +  endif +  if cline =~# '^\s*[-=]\=%>\s*$' +    let ind = ind - &sw +  endif +  return ind +endfunction + +" vim:set sw=2 sts=2 ts=8 noet: diff --git a/indent/haml.vim b/indent/haml.vim new file mode 100644 index 00000000..710aefc0 --- /dev/null +++ b/indent/haml.vim @@ -0,0 +1,73 @@ +" Vim indent file +" Language:	Haml +" Maintainer:	Tim Pope <vimNOSPAM@tpope.org> +" Last Change:	2010 May 21 + +if exists("b:did_indent") +  finish +endif +runtime! indent/ruby.vim +unlet! b:did_indent +let b:did_indent = 1 + +setlocal autoindent sw=2 et +setlocal indentexpr=GetHamlIndent() +setlocal indentkeys=o,O,*<Return>,},],0),!^F,=end,=else,=elsif,=rescue,=ensure,=when + +" Only define the function once. +if exists("*GetHamlIndent") +  finish +endif + +let s:attributes = '\%({.\{-\}}\|\[.\{-\}\]\)' +let s:tag = '\%([%.#][[:alnum:]_-]\+\|'.s:attributes.'\)*[<>]*' + +if !exists('g:haml_self_closing_tags') +  let g:haml_self_closing_tags = 'base|link|meta|br|hr|img|input' +endif + +function! GetHamlIndent() +  let lnum = prevnonblank(v:lnum-1) +  if lnum == 0 +    return 0 +  endif +  let line = substitute(getline(lnum),'\s\+$','','') +  let cline = substitute(substitute(getline(v:lnum),'\s\+$','',''),'^\s\+','','') +  let lastcol = strlen(line) +  let line = substitute(line,'^\s\+','','') +  let indent = indent(lnum) +  let cindent = indent(v:lnum) +  if cline =~# '\v^-\s*%(elsif|else|when)>' +    let indent = cindent < indent ? cindent : indent - &sw +  endif +  let increase = indent + &sw +  if indent == indent(lnum) +    let indent = cindent <= indent ? -1 : increase +  endif + +  let group = synIDattr(synID(lnum,lastcol,1),'name') + +  if line =~ '^!!!' +    return indent +  elseif line =~ '^/\%(\[[^]]*\]\)\=$' +    return increase +  elseif group == 'hamlFilter' +    return increase +  elseif line =~ '^'.s:tag.'[&!]\=[=~-]\s*\%(\%(if\|else\|elsif\|unless\|case\|when\|while\|until\|for\|begin\|module\|class\|def\)\>\%(.*\<end\>\)\@!\|.*do\%(\s*|[^|]*|\)\=\s*$\)' +    return increase +  elseif line =~ '^'.s:tag.'[&!]\=[=~-].*,\s*$' +    return increase +  elseif line == '-#' +    return increase +  elseif group =~? '\v^(hamlSelfCloser)$' || line =~? '^%\v%('.g:haml_self_closing_tags.')>' +    return indent +  elseif group =~? '\v^%(hamlTag|hamlAttributesDelimiter|hamlObjectDelimiter|hamlClass|hamlId|htmlTagName|htmlSpecialTagName)$' +    return increase +  elseif synIDattr(synID(v:lnum,1,1),'name') ==? 'hamlRubyFilter' +    return GetRubyIndent() +  else +    return indent +  endif +endfunction + +" vim:set sw=2: diff --git a/indent/haskell.vim b/indent/haskell.vim new file mode 100644 index 00000000..4e6a1eff --- /dev/null +++ b/indent/haskell.vim @@ -0,0 +1,85 @@ +" Vim indent file +" Language:     Haskell +" Author:       motemen <motemen@gmail.com> +" Version:      0.1 +" Last Change:  2007-07-25 +" +" Modify g:haskell_indent_if and g:haskell_indent_case to +" change indentation for `if'(default 3) and `case'(default 5). +" Example (in .vimrc): +" > let g:haskell_indent_if = 2 + +if exists('b:did_indent') +    finish +endif + +let b:did_indent = 1 + +if !exists('g:haskell_indent_if') +    " if bool +    " >>>then ... +    " >>>else ... +    let g:haskell_indent_if = 2 +endif + +if !exists('g:haskell_indent_case') +    " case xs of +    " >>>>>[] -> ... +    " >>>>>(y:ys) -> ... +    let g:haskell_indent_case = 2 +endif + +setlocal indentexpr=GetHaskellIndent() +setlocal indentkeys=!^F,o,O + +function! GetHaskellIndent() +    let line = substitute(getline(getpos('.')[1] - 1), '\t', repeat(' ', &tabstop), 'g') + +    if line =~ '[!#$%&*+./<=>?@\\^|~-]$\|\<do$' +        return match(line, '\s*where \zs\|\S') + &shiftwidth +    endif + +    if line =~ '{$' +        return match(line, '\s*where \zs\|\S') + &shiftwidth +    endif + +    if line =~ '^\(instance\|class\).*\&.*where$' +        return &shiftwidth +    endif + +    if line =~ ')$' +        let pos = getpos('.') +        normal k$ +        let paren_end   = getpos('.') +        normal % +        let paren_begin = getpos('.') +        call setpos('.', pos) +        if paren_begin[1] != paren_end[1] +            return paren_begin[2] - 1 +        endif +    endif + +    if line !~ '\<else\>' +        let s = match(line, '\<if\>.*\&.*\zs\<then\>') +        if s > 0 +            return s +        endif + +        let s = match(line, '\<if\>') +        if s > 0 +            return s + g:haskell_indent_if +        endif +    endif + +    let s = match(line, '\<do\s\+\zs[^{]\|\<where\s\+\zs\w\|\<let\s\+\zs\S\|^\s*\zs|\s') +    if s > 0 +        return s +    endif + +    let s = match(line, '\<case\>') +    if s > 0 +        return s + g:haskell_indent_case +    endif + +    return match(line, '\S') +endfunction
\ No newline at end of file diff --git a/indent/javascript.vim b/indent/javascript.vim new file mode 100644 index 00000000..29fba2ba --- /dev/null +++ b/indent/javascript.vim @@ -0,0 +1,439 @@ +" Vim indent file +" Language: Javascript +" Acknowledgement: Based off of vim-ruby maintained by Nikolai Weibull http://vim-ruby.rubyforge.org + +" 0. Initialization {{{1 +" ================= + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") +  finish +endif +let b:did_indent = 1 + +setlocal nosmartindent + +" Now, set up our indentation expression and keys that trigger it. +setlocal indentexpr=GetJavascriptIndent() +setlocal indentkeys=0{,0},0),0],0\,,!^F,o,O,e + +" Only define the function once. +if exists("*GetJavascriptIndent") +  finish +endif + +let s:cpo_save = &cpo +set cpo&vim + +" 1. Variables {{{1 +" ============ + +let s:js_keywords = '^\s*\(break\|case\|catch\|continue\|debugger\|default\|delete\|do\|else\|finally\|for\|function\|if\|in\|instanceof\|new\|return\|switch\|this\|throw\|try\|typeof\|var\|void\|while\|with\)' + +" Regex of syntax group names that are or delimit string or are comments. +let s:syng_strcom = 'string\|regex\|comment\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' + +" Regex of syntax group names that are line comment. +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*\%(\%(\/\/\).*\)\=$' + +" Regex that defines continuation lines, not including (, {, or [. +let s:continuation_regex = '\%([\\*+/.:]\|\%(<%\)\@<![=-]\|\W[|&?]\|||\|&&\)' . s:line_term + +" Regex that defines continuation lines. +" TODO: this needs to deal with if ...: and so on +let s:msl_regex = '\%([\\*+/.:([]\|\%(<%\)\@<![=-]\|\W[|&?]\|||\|&&\)' . s:line_term + +let s:one_line_scope_regex = '\<\%(if\|else\|for\|while\)\>[^{;]*' . s:line_term + +" Regex that defines blocks. +let s:block_regex = '\%([{[]\)\s*\%(|\%([*@]\=\h\w*,\=\s*\)\%(,\s*[*@]\=\h\w*\)*|\)\=' . s:line_term + +let s:var_stmt = '^\s*var' + +let s:comma_first = '^\s*,' +let s:comma_last = ',\s*$' + +let s:ternary = '^\s\+[?|:]' +let s:ternary_q = '^\s\+?' + +" 2. Auxiliary Functions {{{1 +" ====================== + +" Check if the character at lnum:col is inside a string, comment, or is ascii. +function s:IsInStringOrComment(lnum, col) +  return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_strcom +endfunction + +" Check if the character at lnum:col is inside a string. +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 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 +endfunction + +" Check if the character at lnum:col is a line comment. +function s:IsLineComment(lnum, col) +  return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_linecom +endfunction + +" Find line above 'lnum' that isn't empty, in a comment, or in a string. +function s:PrevNonBlankNonString(lnum) +  let in_block = 0 +  let lnum = prevnonblank(a:lnum) +  while lnum > 0 +    " 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 line =~ '/\*' +      if in_block +        let in_block = 0 +      else +        break +      endif +    elseif !in_block && line =~ '\*/' +      let in_block = 1 +    elseif !in_block && line !~ '^\s*\%(//\).*$' && !(s:IsInStringOrComment(lnum, 1) && s:IsInStringOrComment(lnum, strlen(line))) +      break +    endif +    let lnum = prevnonblank(lnum - 1) +  endwhile +  return lnum +endfunction + +" Find line above 'lnum' that started the continuation 'lnum' may be part of. +function s:GetMSL(lnum, in_one_line_scope) +  " Start on the line we're at and use its indent. +  let msl = a:lnum +  let lnum = s:PrevNonBlankNonString(a:lnum - 1) +  while lnum > 0 +    " 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 +    if (col > 0 && !s:IsInStringOrComment(lnum, col)) || s:IsInString(lnum, strlen(line)) +      let msl = lnum +    else +      " Don't use lines that are part of a one line scope as msl unless the +      " flag in_one_line_scope is set to 1 +      " +      if a:in_one_line_scope +        break +      end +      let msl_one_line = s:Match(lnum, s:one_line_scope_regex) +      if msl_one_line == 0 +        break +      endif +    endif +    let lnum = s:PrevNonBlankNonString(lnum - 1) +  endwhile +  return msl +endfunction + +function s:RemoveTrailingComments(content) +  let single = '\/\/\(.*\)\s*$' +  let multi = '\/\*\(.*\)\*\/\s*$' +  return substitute(substitute(a:content, single, '', ''), multi, '', '') +endfunction + +" Find if the string is inside var statement (but not the first string) +function s:InMultiVarStatement(lnum) +  let lnum = s:PrevNonBlankNonString(a:lnum - 1) + +"  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) + +    " if the line is a js keyword +    if (line =~ 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) +        return lnum +      endif + +      " other js keywords, not a var +      return 0 +    endif + +    let lnum = s:PrevNonBlankNonString(lnum - 1) +  endwhile + +  " beginning of program, not a var +  return 0 +endfunction + +" Find line above with beginning of the var statement or returns 0 if it's not +" this statement +function s:GetVarIndent(lnum) +  let lvar = s:InMultiVarStatement(a:lnum) +  let prev_lnum = s:PrevNonBlankNonString(a:lnum - 1) + +  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) - &sw +    else +      return indent(lvar) + &sw +    endif +  endif + +  return -1 +endfunction + + +" Check if line 'lnum' has more opening brackets than closing ones. +function s:LineHasOpeningBrackets(lnum) +  let open_0 = 0 +  let open_2 = 0 +  let open_4 = 0 +  let line = getline(a:lnum) +  let pos = match(line, '[][(){}]', 0) +  while pos != -1 +    if !s:IsInStringOrComment(a:lnum, pos + 1) +      let idx = stridx('(){}[]', line[pos]) +      if idx % 2 == 0 +        let open_{idx} = open_{idx} + 1 +      else +        let open_{idx - 1} = open_{idx - 1} - 1 +      endif +    endif +    let pos = match(line, '[][(){}]', pos + 1) +  endwhile +  return (open_0 > 0) . (open_2 > 0) . (open_4 > 0) +endfunction + +function s:Match(lnum, regex) +  let col = match(getline(a:lnum), a:regex) + 1 +  return col > 0 && !s:IsInStringOrComment(a:lnum, col) ? col : 0 +endfunction + +function s:IndentWithContinuation(lnum, ind, width) +  " Set up variables to use and search for MSL to the previous line. +  let p_lnum = a:lnum +  let lnum = s:GetMSL(a:lnum, 1) +  let line = getline(lnum) + +  " If the previous line wasn't a MSL and is continuation return its indent. +  " TODO: the || s:IsInString() thing worries me a bit. +  if p_lnum != lnum +    if s:Match(p_lnum,s:continuation_regex)||s:IsInString(p_lnum,strlen(line)) +      return a:ind +    endif +  endif + +  " Set up more variables now that we know we aren't continuation bound. +  let msl_ind = indent(lnum) + +  " If the previous line ended with [*+/.-=], start a continuation that +  " indents an extra level. +  if s:Match(lnum, s:continuation_regex) +    if lnum == p_lnum +      return msl_ind + a:width +    else +      return msl_ind +    endif +  endif + +  return a:ind +endfunction + +function s:InOneLineScope(lnum) +  let msl = s:GetMSL(a:lnum, 1) +  if msl > 0 && s:Match(msl, s:one_line_scope_regex) +    return msl +  endif +  return 0 +endfunction + +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) +      return 0 +    else +      let prev_msl = s:GetMSL(msl - 1, 1) +      if s:Match(prev_msl, s:one_line_scope_regex) +        return prev_msl +      endif +    endif +  endif +  return 0 +endfunction + +" 3. GetJavascriptIndent Function {{{1 +" ========================= + +function GetJavascriptIndent() +  " 3.1. Setup {{{2 +  " ---------- + +  " Set up variables for restoring position in file.  Could use v:lnum here. +  let vcol = col('.') + +  " 3.2. Work on the current line {{{2 +  " ----------------------------- + +  let ind = -1 +  " Get the current line. +  let line = getline(v:lnum) +  " previous nonblank line number +  let prevline = prevnonblank(v:lnum - 1) + +  " 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*[],})]') +  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) + &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 +    endif +    return ind +  endif + +  " If the line is comma first, dedent 1 level +  if (getline(prevline) =~ s:comma_first) +    return indent(prevline) - &sw +  endif + +  if (line =~ s:ternary) +    if (getline(prevline) =~ s:ternary_q) +      return indent(prevline) +    else +      return indent(prevline) + &sw +    endif +  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 +  " ------------------------------- + +  " If the line is empty and the previous nonblank line was a multi-line +  " comment, use that comment's indent. Deduct one char to account for the +  " space in ' */'. +  if line =~ '^\s*$' && s:IsInMultilineComment(prevline, 1) +    return indent(prevline) - 1 +  endif + +  " Find a non-blank, non-multi-line string line above the current line. +  let lnum = s:PrevNonBlankNonString(v:lnum - 1) + +  " If the line is empty and inside a string, use the previous line. +  if line =~ '^\s*$' && lnum != prevline +    return indent(prevnonblank(v:lnum)) +  endif + +  " At the start of the file use zero indent. +  if lnum == 0 +    return 0 +  endif + +  " Set up variables for current line. +  let line = getline(lnum) +  let ind = indent(lnum) + +  " If the previous line ended with a block opening, add a level of indent. +  if s:Match(lnum, s:block_regex) +    return indent(s:GetMSL(lnum, 0)) + &sw +  endif + +  " 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('$') +        return ind + &sw +      else +        return virtcol('.') +      endif +    elseif counts[1] == '1' || counts[2] == '1' +      return ind + &sw +    else +      call cursor(v:lnum, vcol) +    end +  endif + +  " 3.4. Work on the MSL line. {{{2 +  " -------------------------- + +  let ind_con = ind +  let ind = s:IndentWithContinuation(lnum, ind_con, &sw) + +  " }}}2 +  " +  " +  let ols = s:InOneLineScope(lnum) +  if ols > 0 +    let ind = ind + &sw +  else +    let ols = s:ExitingOneLineScope(lnum) +    while ols > 0 && ind > 0 +      let ind = ind - &sw +      let ols = s:InOneLineScope(ols - 1) +    endwhile +  endif + +  return ind +endfunction + +" }}}1 + +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/indent/less.vim b/indent/less.vim new file mode 100644 index 00000000..fea8846d --- /dev/null +++ b/indent/less.vim @@ -0,0 +1,11 @@ +" Vim indent file +" Language:	    LessCSS +" Maintainer:	Leonard Ehrenfried <leonard.ehrenfried@web.de> +" Last Change:	2011 Sep 26 + +if exists("b:did_indent") +  finish +endif + +runtime! indent/css.vim + diff --git a/indent/ocaml.vim b/indent/ocaml.vim new file mode 100644 index 00000000..a84c992e --- /dev/null +++ b/indent/ocaml.vim @@ -0,0 +1,267 @@ +" Vim indent file +" Language:     OCaml +" Maintainers:  Jean-Francois Yuen   <jfyuen@happycoders.org> +"               Mike Leary           <leary@nwlink.com> +"               Markus Mottl         <markus.mottl@gmail.com> +" URL:          http://www.ocaml.info/vim/indent/ocaml.vim +" Last Change:  2010 Sep 04 - Added an indentation improvement by Mark Weber +"               2005 Jun 25 - Fixed multiple bugs due to 'else\nreturn ind' working +"               2005 May 09 - Added an option to not indent OCaml-indents specially (MM) + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal expandtab +setlocal indentexpr=GetOCamlIndent() +setlocal indentkeys+=0=and,0=class,0=constraint,0=done,0=else,0=end,0=exception,0=external,0=if,0=in,0=include,0=inherit,0=initializer,0=let,0=method,0=open,0=then,0=type,0=val,0=with,0;;,0>\],0\|\],0>},0\|,0},0\],0) +setlocal nolisp +setlocal nosmartindent +setlocal textwidth=80 + +" Comment formatting +if !exists("no_ocaml_comments") + if (has("comments")) +   setlocal comments=sr:(*,mb:*,ex:*) +   setlocal fo=cqort + endif +endif + +" Only define the function once. +if exists("*GetOCamlIndent") + finish +endif + +" Define some patterns: +let s:beflet = '^\s*\(initializer\|method\|try\)\|\(\<\(begin\|do\|else\|in\|then\|try\)\|->\|<-\|=\|;\|(\)\s*$' +let s:letpat = '^\s*\(let\|type\|module\|class\|open\|exception\|val\|include\|external\)\>' +let s:letlim = '\(\<\(sig\|struct\)\|;;\)\s*$' +let s:lim = '^\s*\(exception\|external\|include\|let\|module\|open\|type\|val\)\>' +let s:module = '\<\%(begin\|sig\|struct\|object\)\>' +let s:obj = '^\s*\(constraint\|inherit\|initializer\|method\|val\)\>\|\<\(object\|object\s*(.*)\)\s*$' +let s:type = '^\s*\%(class\|let\|type\)\>.*=' + +" Skipping pattern, for comments +function! s:GetLineWithoutFullComment(lnum) + let lnum = prevnonblank(a:lnum - 1) + let lline = substitute(getline(lnum), '(\*.*\*)\s*$', '', '') + while lline =~ '^\s*$' && lnum > 0 +   let lnum = prevnonblank(lnum - 1) +   let lline = substitute(getline(lnum), '(\*.*\*)\s*$', '', '') + endwhile + return lnum +endfunction + +" Indent for ';;' to match multiple 'let' +function! s:GetInd(lnum, pat, lim) + let llet = search(a:pat, 'bW') + let old = indent(a:lnum) + while llet > 0 +   let old = indent(llet) +   let nb = s:GetLineWithoutFullComment(llet) +   if getline(nb) =~ a:lim +     return old +   endif +   let llet = search(a:pat, 'bW') + endwhile + return old +endfunction + +" Indent pairs +function! s:FindPair(pstart, pmid, pend) + call search(a:pend, 'bW') + return indent(searchpair(a:pstart, a:pmid, a:pend, 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string\\|comment"')) +endfunction + +" Indent 'let' +function! s:FindLet(pstart, pmid, pend) + call search(a:pend, 'bW') + return indent(searchpair(a:pstart, a:pmid, a:pend, 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string\\|comment" || getline(".") =~ "^\\s*let\\>.*=.*\\<in\\s*$" || getline(prevnonblank(".") - 1) =~ s:beflet')) +endfunction + +function! GetOCamlIndent() + " Find a non-commented line above the current line. + let lnum = s:GetLineWithoutFullComment(v:lnum) + + " At the start of the file use zero indent. + if lnum == 0 +   return 0 + endif + + let ind = indent(lnum) + let lline = substitute(getline(lnum), '(\*.*\*)\s*$', '', '') + + " Return double 'shiftwidth' after lines matching: + if lline =~ '^\s*|.*->\s*$' +   return ind + &sw + &sw + endif + + let line = getline(v:lnum) + + " Indent if current line begins with 'end': + if line =~ '^\s*end\>' +   return s:FindPair(s:module, '','\<end\>') + + " Indent if current line begins with 'done' for 'do': + elseif line =~ '^\s*done\>' +   return s:FindPair('\<do\>', '','\<done\>') + + " Indent if current line begins with '}' or '>}': + elseif line =~ '^\s*\(\|>\)}' +   return s:FindPair('{', '','}') + + " Indent if current line begins with ']', '|]' or '>]': + elseif line =~ '^\s*\(\||\|>\)\]' +   return s:FindPair('\[', '','\]') + + " Indent if current line begins with ')': + elseif line =~ '^\s*)' +   return s:FindPair('(', '',')') + + " Indent if current line begins with 'let': + elseif line =~ '^\s*let\>' +   if lline !~ s:lim . '\|' . s:letlim . '\|' . s:beflet +     return s:FindLet(s:type, '','\<let\s*$') +   endif + + " Indent if current line begins with 'class' or 'type': + elseif line =~ '^\s*\(class\|type\)\>' +   if lline !~ s:lim . '\|\<and\s*$\|' . s:letlim +     return s:FindLet(s:type, '','\<\(class\|type\)\s*$') +   endif + + " Indent for pattern matching: + elseif line =~ '^\s*|' +   if lline !~ '^\s*\(|[^\]]\|\(match\|type\|with\)\>\)\|\<\(function\|parser\|private\|with\)\s*$' +     call search('|', 'bW') +     return indent(searchpair('^\s*\(match\|type\)\>\|\<\(function\|parser\|private\|with\)\s*$', '', '^\s*|', 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string\\|comment" || getline(".") !~ "^\\s*|.*->"')) +   endif + + " Indent if current line begins with ';;': + elseif line =~ '^\s*;;' +   if lline !~ ';;\s*$' +     return s:GetInd(v:lnum, s:letpat, s:letlim) +   endif + + " Indent if current line begins with 'in': + elseif line =~ '^\s*in\>' +   if lline !~ '^\s*\(let\|and\)\>' +     return s:FindPair('\<let\>', '', '\<in\>') +   endif + + " Indent if current line begins with 'else': + elseif line =~ '^\s*else\>' +   if lline !~ '^\s*\(if\|then\)\>' +     return s:FindPair('\<if\>', '', '\<else\>') +   endif + + " Indent if current line begins with 'then': + elseif line =~ '^\s*then\>' +   if lline !~ '^\s*\(if\|else\)\>' +     return s:FindPair('\<if\>', '', '\<then\>') +   endif + + " Indent if current line begins with 'and': + elseif line =~ '^\s*and\>' +   if lline !~ '^\s*\(and\|let\|type\)\>\|\<end\s*$' +     return ind - &sw +   endif + + " Indent if current line begins with 'with': + elseif line =~ '^\s*with\>' +   if lline !~ '^\s*\(match\|try\)\>' +     return s:FindPair('\<\%(match\|try\)\>', '','\<with\>') +   endif + + " Indent if current line begins with 'exception', 'external', 'include' or + " 'open': + elseif line =~ '^\s*\(exception\|external\|include\|open\)\>' +   if lline !~ s:lim . '\|' . s:letlim +     call search(line) +     return indent(search('^\s*\(\(exception\|external\|include\|open\|type\)\>\|val\>.*:\)', 'bW')) +   endif + + " Indent if current line begins with 'val': + elseif line =~ '^\s*val\>' +   if lline !~ '^\s*\(exception\|external\|include\|open\)\>\|' . s:obj . '\|' . s:letlim +     return indent(search('^\s*\(\(exception\|include\|initializer\|method\|open\|type\|val\)\>\|external\>.*:\)', 'bW')) +   endif + + " Indent if current line begins with 'constraint', 'inherit', 'initializer' + " or 'method': + elseif line =~ '^\s*\(constraint\|inherit\|initializer\|method\)\>' +   if lline !~ s:obj +     return indent(search('\<\(object\|object\s*(.*)\)\s*$', 'bW')) + &sw +   endif + + endif + + " Add a 'shiftwidth' after lines ending with: + if lline =~ '\(:\|=\|->\|<-\|(\|\[\|{\|{<\|\[|\|\[<\|\<\(begin\|do\|else\|fun\|function\|functor\|if\|initializer\|object\|parser\|private\|sig\|struct\|then\|try\)\|\<object\s*(.*)\)\s*$' +   let ind = ind + &sw + + " Back to normal indent after lines ending with ';;': + elseif lline =~ ';;\s*$' && lline !~ '^\s*;;' +   let ind = s:GetInd(v:lnum, s:letpat, s:letlim) + + " Back to normal indent after lines ending with 'end': + elseif lline =~ '\<end\s*$' +   let ind = s:FindPair(s:module, '','\<end\>') + + " Back to normal indent after lines ending with 'in': + elseif lline =~ '\<in\s*$' && lline !~ '^\s*in\>' +   let ind = s:FindPair('\<let\>', '', '\<in\>') + + " Back to normal indent after lines ending with 'done': + elseif lline =~ '\<done\s*$' +   let ind = s:FindPair('\<do\>', '','\<done\>') + + " Back to normal indent after lines ending with '}' or '>}': + elseif lline =~ '\(\|>\)}\s*$' +   let ind = s:FindPair('{', '','}') + + " Back to normal indent after lines ending with ']', '|]' or '>]': + elseif lline =~ '\(\||\|>\)\]\s*$' +   let ind = s:FindPair('\[', '','\]') + + " Back to normal indent after comments: + elseif lline =~ '\*)\s*$' +   call search('\*)', 'bW') +   let ind = indent(searchpair('(\*', '', '\*)', 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string"')) + + " Back to normal indent after lines ending with ')': + elseif lline =~ ')\s*$' +   let ind = s:FindPair('(', '',')') + + " If this is a multiline comment then align '*': + elseif lline =~ '^\s*(\*' && line =~ '^\s*\*' +   let ind = ind + 1 + + else + " Don't change indentation of this line + " for new lines (indent==0) use indentation of previous line + + " This is for preventing removing indentation of these args: + "   let f x = + "     let y = x + 1 in + "     Printf.printf + "       "o"           << here + "       "oeuth"       << don't touch indentation + +   let i = indent(v:lnum) +   return i == 0 ? ind : i + + endif + + " Subtract a 'shiftwidth' after lines matching 'match ... with parser': + if lline =~ '\<match\>.*\<with\>\s*\<parser\s*$' +   let ind = ind - &sw + endif + + return ind + +endfunction + +" vim:sw=2 diff --git a/indent/ruby.vim b/indent/ruby.vim new file mode 100644 index 00000000..095b3a43 --- /dev/null +++ b/indent/ruby.vim @@ -0,0 +1,537 @@ +" Vim indent file +" Language:		Ruby +" Maintainer:		Nikolai Weibull <now at bitwi.se> +" URL:			https://github.com/vim-ruby/vim-ruby +" Release Coordinator:	Doug Kearns <dougkearns@gmail.com> + +" 0. Initialization {{{1 +" ================= + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") +  finish +endif +let b:did_indent = 1 + +setlocal nosmartindent + +" Now, set up our indentation expression and keys that trigger it. +setlocal indentexpr=GetRubyIndent(v:lnum) +setlocal indentkeys=0{,0},0),0],!^F,o,O,e +setlocal indentkeys+==end,=else,=elsif,=when,=ensure,=rescue,==begin,==end + +" Only define the function once. +if exists("*GetRubyIndent") +  finish +endif + +let s:cpo_save = &cpo +set cpo&vim + +" 1. Variables {{{1 +" ============ + +" Regex of syntax group names that are or delimit strings/symbols or are comments. +let s:syng_strcom = '\<ruby\%(Regexp\|RegexpDelimiter\|RegexpEscape' . +      \ '\|Symbol\|String\|StringDelimiter\|StringEscape\|ASCIICode' . +      \ '\|Interpolation\|NoInterpolation\|Comment\|Documentation\)\>' + +" Regex of syntax group names that are strings. +let s:syng_string = +      \ '\<ruby\%(String\|Interpolation\|NoInterpolation\|StringEscape\)\>' + +" Regex of syntax group names that are strings or documentation. +let s:syng_stringdoc = +      \'\<ruby\%(String\|Interpolation\|NoInterpolation\|StringEscape\|Documentation\)\>' + +" 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."'" + +" Regex used for words that, at the start of a line, add a level of indent. +let s:ruby_indent_keywords = '^\s*\zs\<\%(module\|class\|def\|if\|for' . +      \ '\|while\|until\|else\|elsif\|case\|when\|unless\|begin\|ensure' . +      \ '\|rescue\):\@!\>' . +      \ '\|\%([=,*/%+-]\|<<\|>>\|:\s\)\s*\zs' . +      \    '\<\%(if\|for\|while\|until\|case\|unless\|begin\):\@!\>' + +" Regex used for words that, at the start of a line, remove a level of indent. +let s:ruby_deindent_keywords = +      \ '^\s*\zs\<\%(ensure\|else\|rescue\|elsif\|when\|end\):\@!\>' + +" Regex that defines the start-match for the 'end' keyword. +"let s:end_start_regex = '\%(^\|[^.]\)\<\%(module\|class\|def\|if\|for\|while\|until\|case\|unless\|begin\|do\)\>' +" TODO: the do here should be restricted somewhat (only at end of line)? +let s:end_start_regex = +      \ '\C\%(^\s*\|[=,*/%+\-|;{]\|<<\|>>\|:\s\)\s*\zs' . +      \ '\<\%(module\|class\|def\|if\|for\|while\|until\|case\|unless\|begin\):\@!\>' . +      \ '\|\%(^\|[^.:@$]\)\@<=\<do:\@!\>' + +" Regex that defines the middle-match for the 'end' keyword. +let s:end_middle_regex = '\<\%(ensure\|else\|\%(\%(^\|;\)\s*\)\@<=\<rescue:\@!\>\|when\|elsif\):\@!\>' + +" Regex that defines the end-match for the 'end' keyword. +let s:end_end_regex = '\%(^\|[^.:@$]\)\@<=\<end:\@!\>' + +" Expression used for searchpair() call for finding match for 'end' keyword. +let s:end_skip_expr = s:skip_expr . +      \ ' || (expand("<cword>") == "do"' . +      \ ' && getline(".") =~ "^\\s*\\<\\(while\\|until\\|for\\):\\@!\\>")' + +" Regex that defines continuation lines, not including (, {, or [. +let s:non_bracket_continuation_regex = '\%([\\.,:*/%+]\|\<and\|\<or\|\%(<%\)\@<![=-]\|\W[|&?]\|||\|&&\)\s*\%(#.*\)\=$' + +" Regex that defines continuation lines. +" TODO: this needs to deal with if ...: and so on +let s:continuation_regex = +      \ '\%(%\@<![({[\\.,:*/%+]\|\<and\|\<or\|\%(<%\)\@<![=-]\|\W[|&?]\|||\|&&\)\s*\%(#.*\)\=$' + +" Regex that defines bracket continuations +let s:bracket_continuation_regex = '%\@<!\%([({[]\)\s*\%(#.*\)\=$' + +" Regex that defines the first part of a splat pattern +let s:splat_regex = '[[,(]\s*\*\s*\%(#.*\)\=$' + +" Regex that defines blocks. +" +" Note that there's a slight problem with this regex and s:continuation_regex. +" Code like this will be matched by both: +" +"   method_call do |(a, b)| +" +" The reason is that the pipe matches a hanging "|" operator. +" +let s:block_regex = +      \ '\%(\<do:\@!\>\|%\@<!{\)\s*\%(|\s*(*\s*\%([*@&]\=\h\w*,\=\s*\)\%(,\s*(*\s*[*@&]\=\h\w*\s*)*\s*\)*|\)\=\s*\%(#.*\)\=$' + +let s:block_continuation_regex = '^\s*[^])}\t ].*'.s:block_regex + +" 2. Auxiliary Functions {{{1 +" ====================== + +" Check if the character at lnum:col is inside a string, comment, or is ascii. +function s:IsInStringOrComment(lnum, col) +  return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_strcom +endfunction + +" Check if the character at lnum:col is inside a string. +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 string or documentation. +function s:IsInStringOrDocumentation(lnum, col) +  return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_stringdoc +endfunction + +" Check if the character at lnum:col is inside a string delimiter +function s:IsInStringDelimiter(lnum, col) +  return synIDattr(synID(a:lnum, a:col, 1), 'name') == 'rubyStringDelimiter' +endfunction + +" Find line above 'lnum' that isn't empty, in a comment, or in a string. +function s:PrevNonBlankNonString(lnum) +  let in_block = 0 +  let lnum = prevnonblank(a:lnum) +  while lnum > 0 +    " 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 line =~ '^=begin' +      if in_block +        let in_block = 0 +      else +        break +      endif +    elseif !in_block && line =~ '^=end' +      let in_block = 1 +    elseif !in_block && line !~ '^\s*#.*$' && !(s:IsInStringOrComment(lnum, 1) +          \ && s:IsInStringOrComment(lnum, strlen(line))) +      break +    endif +    let lnum = prevnonblank(lnum - 1) +  endwhile +  return lnum +endfunction + +" Find line above 'lnum' that started the continuation 'lnum' may be part of. +function s:GetMSL(lnum) +  " Start on the line we're at and use its indent. +  let msl = a:lnum +  let msl_body = getline(msl) +  let lnum = s:PrevNonBlankNonString(a:lnum - 1) +  while lnum > 0 +    " 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) + +    if s:Match(lnum, s:splat_regex) +      " If the above line looks like the "*" of a splat, use the current one's +      " indentation. +      " +      " Example: +      "   Hash[* +      "     method_call do +      "       something +      " +      return msl +    elseif s:Match(line, s:non_bracket_continuation_regex) && +          \ s:Match(msl, s:non_bracket_continuation_regex) +      " If the current line is a non-bracket continuation and so is the +      " previous one, keep its indent and continue looking for an MSL. +      " +      " Example: +      "   method_call one, +      "     two, +      "     three +      " +      let msl = lnum +    elseif s:Match(lnum, s:non_bracket_continuation_regex) && +          \ (s:Match(msl, s:bracket_continuation_regex) || s:Match(msl, s:block_continuation_regex)) +      " If the current line is a bracket continuation or a block-starter, but +      " the previous is a non-bracket one, respect the previous' indentation, +      " and stop here. +      " +      " Example: +      "   method_call one, +      "     two { +      "     three +      " +      return lnum +    elseif s:Match(lnum, s:bracket_continuation_regex) && +          \ (s:Match(msl, s:bracket_continuation_regex) || s:Match(msl, s:block_continuation_regex)) +      " If both lines are bracket continuations (the current may also be a +      " block-starter), use the current one's and stop here +      " +      " Example: +      "   method_call( +      "     other_method_call( +      "       foo +      return msl +    elseif s:Match(lnum, s:block_regex) && +          \ !s:Match(msl, s:continuation_regex) && +          \ !s:Match(msl, s:block_continuation_regex) +      " If the previous line is a block-starter and the current one is +      " mostly ordinary, use the current one as the MSL. +      " +      " Example: +      "   method_call do +      "     something +      "     something_else +      return msl +    else +      let col = match(line, s:continuation_regex) + 1 +      if (col > 0 && !s:IsInStringOrComment(lnum, col)) +            \ || s:IsInString(lnum, strlen(line)) +        let msl = lnum +      else +        break +      endif +    endif + +    let msl_body = getline(msl) +    let lnum = s:PrevNonBlankNonString(lnum - 1) +  endwhile +  return msl +endfunction + +" Check if line 'lnum' has more opening brackets than closing ones. +function s:ExtraBrackets(lnum) +  let opening = {'parentheses': [], 'braces': [], 'brackets': []} +  let closing = {'parentheses': [], 'braces': [], 'brackets': []} + +  let line = getline(a:lnum) +  let pos  = match(line, '[][(){}]', 0) + +  " Save any encountered opening brackets, and remove them once a matching +  " closing one has been found. If a closing bracket shows up that doesn't +  " close anything, save it for later. +  while pos != -1 +    if !s:IsInStringOrComment(a:lnum, pos + 1) +      if line[pos] == '(' +        call add(opening.parentheses, {'type': '(', 'pos': pos}) +      elseif line[pos] == ')' +        if empty(opening.parentheses) +          call add(closing.parentheses, {'type': ')', 'pos': pos}) +        else +          let opening.parentheses = opening.parentheses[0:-2] +        endif +      elseif line[pos] == '{' +        call add(opening.braces, {'type': '{', 'pos': pos}) +      elseif line[pos] == '}' +        if empty(opening.braces) +          call add(closing.braces, {'type': '}', 'pos': pos}) +        else +          let opening.braces = opening.braces[0:-2] +        endif +      elseif line[pos] == '[' +        call add(opening.brackets, {'type': '[', 'pos': pos}) +      elseif line[pos] == ']' +        if empty(opening.brackets) +          call add(closing.brackets, {'type': ']', 'pos': pos}) +        else +          let opening.brackets = opening.brackets[0:-2] +        endif +      endif +    endif + +    let pos = match(line, '[][(){}]', pos + 1) +  endwhile + +  " Find the rightmost brackets, since they're the ones that are important in +  " both opening and closing cases +  let rightmost_opening = {'type': '(', 'pos': -1} +  let rightmost_closing = {'type': ')', 'pos': -1} + +  for opening in opening.parentheses + opening.braces + opening.brackets +    if opening.pos > rightmost_opening.pos +      let rightmost_opening = opening +    endif +  endfor + +  for closing in closing.parentheses + closing.braces + closing.brackets +    if closing.pos > rightmost_closing.pos +      let rightmost_closing = closing +    endif +  endfor + +  return [rightmost_opening, rightmost_closing] +endfunction + +function s:Match(lnum, regex) +  let col = match(getline(a:lnum), '\C'.a:regex) + 1 +  return col > 0 && !s:IsInStringOrComment(a:lnum, col) ? col : 0 +endfunction + +function s:MatchLast(lnum, regex) +  let line = getline(a:lnum) +  let col = match(line, '.*\zs' . a:regex) +  while col != -1 && s:IsInStringOrComment(a:lnum, col) +    let line = strpart(line, 0, col) +    let col = match(line, '.*' . a:regex) +  endwhile +  return col + 1 +endfunction + +" 3. GetRubyIndent Function {{{1 +" ========================= + +function GetRubyIndent(...) +  " 3.1. Setup {{{2 +  " ---------- + +  " For the current line, use the first argument if given, else v:lnum +  let clnum = a:0 ? a:1 : v:lnum + +  " Set up variables for restoring position in file.  Could use clnum here. +  let vcol = col('.') + +  " 3.2. Work on the current line {{{2 +  " ----------------------------- + +  " Get the current line. +  let line = getline(clnum) +  let ind = -1 + +  " 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*[]})]') +  if col > 0 && !s:IsInStringOrComment(clnum, col) +    call cursor(clnum, col) +    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('.'))) +      endif +    endif +    return ind +  endif + +  " If we have a =begin or =end set indent to first column. +  if match(line, '^\s*\%(=begin\|=end\)$') != -1 +    return 0 +  endif + +  " If we have a deindenting keyword, find its match and indent to its level. +  " TODO: this is messy +  if s:Match(clnum, s:ruby_deindent_keywords) +    call cursor(clnum, 1) +    if searchpair(s:end_start_regex, s:end_middle_regex, s:end_end_regex, 'bW', +          \ s:end_skip_expr) > 0 +      let msl  = s:GetMSL(line('.')) +      let line = getline(line('.')) + +      if strpart(line, 0, col('.') - 1) =~ '=\s*$' && +            \ strpart(line, col('.') - 1, 2) !~ 'do' +        let ind = virtcol('.') - 1 +      elseif getline(msl) =~ '=\s*\(#.*\)\=$' +        let ind = indent(line('.')) +      else +        let ind = indent(msl) +      endif +    endif +    return ind +  endif + +  " If we are in a multi-line string or line-comment, don't do anything to it. +  if s:IsInStringOrDocumentation(clnum, matchend(line, '^\s*') + 1) +    return indent('.') +  endif + +  " If we are at the closing delimiter of a "<<" heredoc-style string, set the +  " indent to 0. +  if line =~ '^\k\+\s*$' +        \ && s:IsInStringDelimiter(clnum, 1) +        \ && search('\V<<'.line, 'nbW') > 0 +    return 0 +  endif + +  " 3.3. Work on the previous line. {{{2 +  " ------------------------------- + +  " Find a non-blank, non-multi-line string line above the current line. +  let lnum = s:PrevNonBlankNonString(clnum - 1) + +  " If the line is empty and inside a string, use the previous line. +  if line =~ '^\s*$' && lnum != prevnonblank(clnum - 1) +    return indent(prevnonblank(clnum)) +  endif + +  " At the start of the file use zero indent. +  if lnum == 0 +    return 0 +  endif + +  " Set up variables for the previous line. +  let line = getline(lnum) +  let ind = indent(lnum) + +  " If the previous line ended with a block opening, add a level of indent. +  if s:Match(lnum, s:block_regex) +    return indent(s:GetMSL(lnum)) + &sw +  endif + +  " If the previous line ended with the "*" of a splat, add a level of indent +  if line =~ s:splat_regex +    return indent(lnum) + &sw +  endif + +  " If the previous line contained unclosed opening brackets and we are still +  " in them, find the rightmost one and add indent depending on the bracket +  " type. +  " +  " If it contained hanging closing brackets, find the rightmost one, find its +  " match and indent according to that. +  if line =~ '[[({]' || line =~ '[])}]\s*\%(#.*\)\=$' +    let [opening, closing] = s:ExtraBrackets(lnum) + +    if opening.pos != -1 +      if opening.type == '(' && searchpair('(', '', ')', 'bW', s:skip_expr) > 0 +        if col('.') + 1 == col('$') +          return ind + &sw +        else +          return virtcol('.') +        endif +      else +        let nonspace = matchend(line, '\S', opening.pos + 1) - 1 +        return nonspace > 0 ? nonspace : ind + &sw +      endif +    elseif closing.pos != -1 +      call cursor(lnum, closing.pos + 1) +      normal! % + +      if s:Match(line('.'), s:ruby_indent_keywords) +        return indent('.') + &sw +      else +        return indent('.') +      endif +    else +      call cursor(clnum, vcol) +    end +  endif + +  " If the previous line ended with an "end", match that "end"s beginning's +  " indent. +  let col = s:Match(lnum, '\%(^\|[^.:@$]\)\<end\>\s*\%(#.*\)\=$') +  if col > 0 +    call cursor(lnum, col) +    if searchpair(s:end_start_regex, '', s:end_end_regex, 'bW', +          \ s:end_skip_expr) > 0 +      let n = line('.') +      let ind = indent('.') +      let msl = s:GetMSL(n) +      if msl != n +        let ind = indent(msl) +      end +      return ind +    endif +  end + +  let col = s:Match(lnum, s:ruby_indent_keywords) +  if col > 0 +    call cursor(lnum, col) +    let ind = virtcol('.') - 1 + &sw +    " TODO: make this better (we need to count them) (or, if a searchpair +    " fails, we know that something is lacking an end and thus we indent a +    " level +    if s:Match(lnum, s:end_end_regex) +      let ind = indent('.') +    endif +    return ind +  endif + +  " 3.4. Work on the MSL line. {{{2 +  " -------------------------- + +  " Set up variables to use and search for MSL to the previous line. +  let p_lnum = lnum +  let lnum = s:GetMSL(lnum) + +  " If the previous line wasn't a MSL and is continuation return its indent. +  " TODO: the || s:IsInString() thing worries me a bit. +  if p_lnum != lnum +    if s:Match(p_lnum, s:non_bracket_continuation_regex) || s:IsInString(p_lnum,strlen(line)) +      return ind +    endif +  endif + +  " Set up more variables, now that we know we wasn't continuation bound. +  let line = getline(lnum) +  let msl_ind = indent(lnum) + +  " If the MSL line had an indenting keyword in it, add a level of indent. +  " TODO: this does not take into account contrived things such as +  " module Foo; class Bar; end +  if s:Match(lnum, s:ruby_indent_keywords) +    let ind = msl_ind + &sw +    if s:Match(lnum, s:end_end_regex) +      let ind = ind - &sw +    endif +    return ind +  endif + +  " If the previous line ended with [*+/.,-=], but wasn't a block ending or a +  " closing bracket, indent one extra level. +  if s:Match(lnum, s:non_bracket_continuation_regex) && !s:Match(lnum, '^\s*\([\])}]\|end\)') +    if lnum == p_lnum +      let ind = msl_ind + &sw +    else +      let ind = msl_ind +    endif +    return ind +  endif + +  " }}}2 + +  return ind +endfunction + +" }}}1 + +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim:set sw=2 sts=2 ts=8 et: diff --git a/indent/sass.vim b/indent/sass.vim new file mode 100644 index 00000000..1da83193 --- /dev/null +++ b/indent/sass.vim @@ -0,0 +1,40 @@ +" Vim indent file +" Language:	Sass +" Maintainer:	Tim Pope <vimNOSPAM@tpope.org> +" Last Change:	2010 May 21 + +if exists("b:did_indent") +  finish +endif +let b:did_indent = 1 + +setlocal autoindent sw=2 et +setlocal indentexpr=GetSassIndent() +setlocal indentkeys=o,O,*<Return>,<:>,!^F + +" Only define the function once. +if exists("*GetSassIndent") +  finish +endif + +let s:property = '^\s*:\|^\s*[[:alnum:]#{}-]\+\%(:\|\s*=\)' +let s:extend = '^\s*\%(@extend\|@include\|+\)' + +function! GetSassIndent() +  let lnum = prevnonblank(v:lnum-1) +  let line = substitute(getline(lnum),'\s\+$','','') +  let cline = substitute(substitute(getline(v:lnum),'\s\+$','',''),'^\s\+','','') +  let lastcol = strlen(line) +  let line = substitute(line,'^\s\+','','') +  let indent = indent(lnum) +  let cindent = indent(v:lnum) +  if line !~ s:property && line !~ s:extend && cline =~ s:property +    return indent + &sw +  "elseif line =~ s:property && cline !~ s:property +    "return indent - &sw +  else +    return -1 +  endif +endfunction + +" vim:set sw=2: diff --git a/indent/scss.vim b/indent/scss.vim new file mode 100644 index 00000000..82bba492 --- /dev/null +++ b/indent/scss.vim @@ -0,0 +1,12 @@ +" Vim indent file +" Language:	SCSS +" Maintainer:	Tim Pope <vimNOSPAM@tpope.org> +" Last Change:	2010 Jul 26 + +if exists("b:did_indent") +  finish +endif + +runtime! indent/css.vim + +" vim:set sw=2: diff --git a/indent/slim.vim b/indent/slim.vim new file mode 100644 index 00000000..5b843bfb --- /dev/null +++ b/indent/slim.vim @@ -0,0 +1,75 @@ +" Vim indent file +" Language:	Slim + +if exists("b:did_indent") +  finish +endif +runtime! indent/ruby.vim +unlet! b:did_indent +let b:did_indent = 1 + +setlocal autoindent sw=2 et +setlocal indentexpr=GetSlimIndent() +setlocal indentkeys=o,O,*<Return>,},],0),!^F,=end,=else,=elsif,=rescue,=ensure,=when + +" Only define the function once. +if exists("*GetSlimIndent") +  finish +endif + +let s:attributes = '\%({.\{-\}}\|\[.\{-\}\]\)' +let s:tag = '\%([%.#][[:alnum:]_-]\+\|'.s:attributes.'\)*[<>]*' + +if !exists('g:haml_self_closing_tags') +  let g:haml_self_closing_tags = 'meta|link|img|hr|br' +endif + +function! GetSlimIndent() +  let lnum = prevnonblank(v:lnum-1) +  if lnum == 0 +    return 0 +  endif +  let line = substitute(getline(lnum),'\s\+$','','') +  let cline = substitute(substitute(getline(v:lnum),'\s\+$','',''),'^\s\+','','') +  let lastcol = strlen(line) +  let line = substitute(line,'^\s\+','','') +  let indent = indent(lnum) +  let cindent = indent(v:lnum) +  if cline =~# '\v^-\s*%(elsif|else|when)>' +    let indent = cindent < indent ? cindent : indent - &sw +  endif +  let increase = indent + &sw +  if indent == indent(lnum) +    let indent = cindent <= indent ? -1 : increase +  endif + +  let group = synIDattr(synID(lnum,lastcol,1),'name') + +  if line =~ '^doctype' +    return indent +  elseif line =~ '^/\%(\[[^]]*\]\)\=$' +    return increase +  elseif line =~ '^[\.#]' +    return increase +  elseif line =~? '^div' +    return increase +  elseif group == 'hamlFilter' +    return increase +  elseif line =~ '^'.s:tag.'[&!]\=[=~-]\s*\%(\%(if\|else\|elsif\|unless\|case\|when\|while\|until\|for\|begin\|module\|class\|def\)\>\%(.*\<end\>\)\@!\|.*do\%(\s*|[^|]*|\)\=\s*$\)' +    return increase +  elseif line =~ '^'.s:tag.'[&!]\=[=~-].*,\s*$' +    return increase +  elseif line == '-#' +    return increase +  elseif group =~? '\v^(hamlSelfCloser)$' || line =~? '^\v('.g:haml_self_closing_tags.')>' +    return indent +  elseif group =~? '\v^(hamlTag|hamlAttributesDelimiter|hamlObjectDelimiter|hamlClass|hamlId|htmlTagName|htmlSpecialTagName)$' +    return increase +  elseif synIDattr(synID(v:lnum,1,1),'name') ==? 'hamlRubyFilter' +    return GetRubyIndent() +  else +    return indent +  endif +endfunction + +" vim:set sw=2: diff --git a/indent/stylus.vim b/indent/stylus.vim new file mode 100644 index 00000000..8707e619 --- /dev/null +++ b/indent/stylus.vim @@ -0,0 +1,129 @@ +" Vim indent file +" Language: Stylus +" Maintainer: Marc Harter +" Last Change: 2010 May 21 +" Based On: sass.vim from Tim Pope +" +if exists("b:did_indent") +  finish +endif +unlet! b:did_indent +let b:did_indent = 1 + +setlocal indentexpr=GetStylusIndent() +setlocal indentkeys=o,O,*<Return>,},],0),!^F +setlocal formatoptions+=r + +if exists("*GetStylusIndent")  " only define once +  finish +endif + +function s:prevnonblanknoncomment(lnum) +  let lnum = a:lnum +  while lnum > 1 +    let lnum = prevnonblank(lnum) +    let line = getline(lnum) +    if line =~ '\*/' +      while lnum > 1 && line !~ '/\*' +        let lnum -= 1 +      endwhile +      if line =~ '^\s*/\*' +        let lnum -= 1 +      else +        break +      endif +    else +      break +    endif +  endwhile +  return lnum +endfunction + +function s:count_braces(lnum, count_open) +  let n_open = 0 +  let n_close = 0 +  let line = getline(a:lnum) +  let pattern = '[{}]' +  let i = match(line, pattern) +  while i != -1 +    if synIDattr(synID(a:lnum, i + 1, 0), 'name') !~ 'css\%(Comment\|StringQ\{1,2}\)' +      if line[i] == '{' +        let n_open += 1 +      elseif line[i] == '}' +        if n_open > 0 +          let n_open -= 1 +        else +          let n_close += 1 +        endif +      endif +    endif +    let i = match(line, pattern, i + 1) +  endwhile +  return a:count_open ? n_open : n_close +endfunction + +" function CheckCSSIndent() +"   let line = getline(v:lnum) +"   if line =~ '^\s*\*' +"     return cindent(v:lnum) +"   endif +"  +"   let pnum = s:prevnonblanknoncomment(v:lnum - 1) +"   if pnum == 0 +"     return 0 +"   endif +"  +"   return indent(pnum) + s:count_braces(pnum, 1) * &sw +"         \ - s:count_braces(v:lnum, 0) * &sw +" endfunction + +function! GetStylusIndent() +  let line = getline(v:lnum) +  if line =~ '^\s*\*' +    return cindent(v:lnum) +  endif + +  let pnum = s:prevnonblanknoncomment(v:lnum - 1) +  if pnum == 0 +    return 0 +  endif + +  let lnum     = prevnonblank(v:lnum-1) +  if lnum == 0 +    return 0 +  endif + +  let pline = getline(pnum) + +  if pline =~ '[}{]' +    return indent(pnum) + s:count_braces(pnum, 1) * &sw - s:count_braces(v:lnum, 0) * &sw +  endif + +  let line     = substitute(getline(lnum),'[\s()]\+$','','')  " get last line strip ending whitespace +  let cline    = substitute(substitute(getline(v:lnum),'\s\+$','',''),'^\s\+','','')  " get current line, trimmed +  let lastcol  = strlen(line)  " get last col in prev line +  let line     = substitute(line,'^\s\+','','')  " then remove preceeding whitespace +  let indent   = indent(lnum)  " get indent on prev line +  let cindent  = indent(v:lnum)  " get indent on current line +  let increase = indent + &sw  " increase indent by the shift width +  if indent   == indent(lnum) +    let indent = cindent <= indent ? indent : increase +  endif + +  let group = synIDattr(synID(lnum,lastcol,1),'name') + +  " for debugging only +  echo group + +  " if group !~? 'css.*' && line =~? ')\s*$' " match user functions +  "   return increase +  if group =~? '\v^%(cssTagName|cssClassName|cssIdentifier|cssSelectorOp|cssSelectorOp2|cssBraces|cssAttributeSelector|cssPseudoClass|cssPseudoClassId|stylusId|stylusClass)$' +    return increase +  elseif (group == 'stylusUserFunction') && (indent(lnum) == '0') " mixin definition +    return increase +  else +    return indent +  endif +endfunction + +" vim:set sw=2; | 
