home *** CD-ROM | disk | FTP | other *** search
- " Vim indent file
- " Language: Erlang
- " Author: Csaba Hoch <csaba.hoch@gmail.com>
- " Contributors: Edwin Fine <efine145_nospam01 at usa dot net>
- " Pawel 'kTT' Salata <rockplayer.pl@gmail.com>
- " Ricardo Catalinas Jiménez <jimenezrick@gmail.com>
- " License: Vim license
- " Version: 2011/09/06
-
- " Only load this indent file when no other was loaded
- if exists("b:did_indent")
- finish
- else
- let b:did_indent = 1
- endif
-
- setlocal indentexpr=ErlangIndent()
- setlocal indentkeys+==after,=end,=catch,=),=],=}
-
- " Only define the functions once
- if exists("*ErlangIndent")
- finish
- endif
-
- " The function goes through the whole line, analyses it and returns the
- " indentation level.
- "
- " line: the line to be examined
- " return: the indentation level of the examined line
- function s:ErlangIndentAfterLine(line)
- let linelen = strlen(a:line) " the length of the line
- let i = 0 " the index of the current character in the line
- let ind = 0 " how much should be the difference between the indentation of
- " the current line and the indentation of the next line?
- " e.g. +1: the indentation of the next line should be equal to
- " the indentation of the current line plus one shiftwidth
- let last_fun = 0 " the last token was a 'fun'
- let last_receive = 0 " the last token was a 'receive'; needed for 'after'
- let last_hash_sym = 0 " the last token was a '#'
-
- " Ignore comments
- if a:line =~# '^\s*%'
- return 0
- endif
-
- " Partial function head where the guard is missing
- if a:line =~# "\\(^\\l[[:alnum:]_]*\\)\\|\\(^'[^']\\+'\\)(" && a:line !~# '->'
- return 2
- endif
-
- " The missing guard from the split function head
- if a:line =~# '^\s*when\s\+.*->'
- return -1
- endif
-
- while 0<=i && i<linelen
- " m: the next value of the i
- if a:line[i] == '"'
- let m = matchend(a:line,'"\%([^"\\]\|\\.\)*"',i)
- let last_receive = 0
- elseif a:line[i] == "'"
- let m = matchend(a:line,"'[^']*'",i)
- let last_receive = 0
- elseif a:line[i] =~# "[a-z]"
- let m = matchend(a:line,".[[:alnum:]_]*",i)
- if last_fun
- let ind = ind - 1
- let last_fun = 0
- let last_receive = 0
- elseif a:line[(i):(m-1)] =~# '^\%(case\|if\|try\)$'
- let ind = ind + 1
- elseif a:line[(i):(m-1)] =~# '^receive$'
- let ind = ind + 1
- let last_receive = 1
- elseif a:line[(i):(m-1)] =~# '^begin$'
- let ind = ind + 2
- let last_receive = 0
- elseif a:line[(i):(m-1)] =~# '^end$'
- let ind = ind - 2
- let last_receive = 0
- elseif a:line[(i):(m-1)] =~# '^after$'
- if last_receive == 0
- let ind = ind - 1
- else
- let ind = ind + 0
- endif
- let last_receive = 0
- elseif a:line[(i):(m-1)] =~# '^fun$'
- let ind = ind + 1
- let last_fun = 1
- let last_receive = 0
- endif
- elseif a:line[i] =~# "[A-Z_]"
- let m = matchend(a:line,".[[:alnum:]_]*",i)
- let last_receive = 0
- elseif a:line[i] == '$'
- let m = i+2
- let last_receive = 0
- elseif a:line[i] == "." && (i+1>=linelen || a:line[i+1]!~ "[0-9]")
- let m = i+1
- if last_hash_sym
- let last_hash_sym = 0
- else
- let ind = ind - 1
- endif
- let last_receive = 0
- elseif a:line[i] == '-' && (i+1<linelen && a:line[i+1]=='>')
- let m = i+2
- let ind = ind + 1
- let last_receive = 0
- elseif a:line[i] == ';' && a:line[(i):(linelen)] !~# '.*->.*'
- let m = i+1
- let ind = ind - 1
- let last_receive = 0
- elseif a:line[i] == '#'
- let m = i+1
- let last_hash_sym = 1
- elseif a:line[i] =~# '[({[]'
- let m = i+1
- let ind = ind + 1
- let last_fun = 0
- let last_receive = 0
- let last_hash_sym = 0
- elseif a:line[i] =~# '[)}\]]'
- let m = i+1
- let ind = ind - 1
- let last_receive = 0
- else
- let m = i+1
- endif
-
- let i = m
- endwhile
-
- return ind
- endfunction
-
- function s:FindPrevNonBlankNonComment(lnum)
- let lnum = prevnonblank(a:lnum)
- let line = getline(lnum)
- " Continue to search above if the current line begins with a '%'
- while line =~# '^\s*%.*$'
- let lnum = prevnonblank(lnum - 1)
- if 0 == lnum
- return 0
- endif
- let line = getline(lnum)
- endwhile
- return lnum
- endfunction
-
- " The function returns the indentation level of the line adjusted to a mutiple
- " of 'shiftwidth' option.
- "
- " lnum: line number
- " return: the indentation level of the line
- function s:GetLineIndent(lnum)
- return (indent(a:lnum) / &sw) * &sw
- endfunction
-
- function ErlangIndent()
- " Find a non-blank line above the current line
- let lnum = prevnonblank(v:lnum - 1)
-
- " Hit the start of the file, use zero indent
- if lnum == 0
- return 0
- endif
-
- let prevline = getline(lnum)
- let currline = getline(v:lnum)
-
- let ind_after = s:ErlangIndentAfterLine(prevline)
- if ind_after != 0
- let ind = s:GetLineIndent(lnum) + ind_after * &sw
- else
- let ind = indent(lnum) + ind_after * &sw
- endif
-
- " Special cases:
- if prevline =~# '^\s*\%(after\|end\)\>'
- let ind = ind + 2*&sw
- endif
- if currline =~# '^\s*end\>'
- let ind = ind - 2*&sw
- endif
- if currline =~# '^\s*after\>'
- let plnum = s:FindPrevNonBlankNonComment(v:lnum-1)
- if getline(plnum) =~# '^[^%]*\<receive\>\s*\%(%.*\)\=$'
- " If the 'receive' is not in the same line as the 'after'
- let ind = ind - 1*&sw
- else
- let ind = ind - 2*&sw
- endif
- endif
- if prevline =~# '^\s*[)}\]]'
- let ind = ind + 1*&sw
- endif
- if currline =~# '^\s*[)}\]]'
- let ind = ind - 1*&sw
- endif
- if prevline =~# '^\s*\%(catch\)\s*\%(%\|$\)'
- let ind = ind + 1*&sw
- endif
- if currline =~# '^\s*\%(catch\)\s*\%(%\|$\)'
- let ind = ind - 1*&sw
- endif
-
- if ind<0
- let ind = 0
- endif
- return ind
- endfunction
-