summaryrefslogtreecommitdiffstats
path: root/indent
diff options
context:
space:
mode:
authorAdam Stankiewicz <sheerun@sher.pl>2013-09-12 16:17:03 +0200
committerAdam Stankiewicz <sheerun@sher.pl>2013-09-12 16:17:03 +0200
commit01fe1500df97577452f755b526c09d8ed0c802ea (patch)
tree9e2e038630cc9e82abcd17da6dd3407a9b3bc62a /indent
parentdce12af91b404835938e95de9e6d839d52487ed5 (diff)
downloadvim-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 'indent')
-rw-r--r--indent/coffee.vim418
-rw-r--r--indent/cucumber.vim74
-rw-r--r--indent/eruby.vim91
-rw-r--r--indent/haml.vim73
-rw-r--r--indent/haskell.vim85
-rw-r--r--indent/javascript.vim439
-rw-r--r--indent/less.vim11
-rw-r--r--indent/ocaml.vim267
-rw-r--r--indent/ruby.vim537
-rw-r--r--indent/sass.vim40
-rw-r--r--indent/scss.vim12
-rw-r--r--indent/slim.vim75
-rw-r--r--indent/stylus.vim129
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;