diff options
Diffstat (limited to 'indent')
| -rw-r--r-- | indent/erlang.vim | 235 | 
1 files changed, 192 insertions, 43 deletions
| diff --git a/indent/erlang.vim b/indent/erlang.vim index 370a8810..61833f74 100644 --- a/indent/erlang.vim +++ b/indent/erlang.vim @@ -1,58 +1,207 @@  " Vim indent file -" Language: Erlang -" Author:   Ricardo Catalinas Jiménez <jimenezrick@gmail.com> -" License:  Vim license -" Version:  2013/09/11 +" Language:     Erlang +" Maintainer:   Csaba Hoch <csaba.hoch@gmail.com> +" Contributor:  Edwin Fine <efine145_nospam01 at usa dot net> +" Contributor:  Pawel 'kTT' Salata <rockplayer.pl@gmail.com> +" Last Change:  2010 Aug 30 -if !exists('g:erlang_force_use_vimerl_indent') -	let g:erlang_force_use_vimerl_indent = 0 -endif - -if exists('b:did_indent') || (v:version >= 704 && !g:erlang_force_use_vimerl_indent) -	finish -else -	let b:did_indent = 1 +" Only load this indent file when no other was loaded. +if exists("b:did_indent") +  finish  endif +let b:did_indent = 1  setlocal indentexpr=ErlangIndent() -setlocal indentkeys=!^F,o,O,=),=},=],=>>,=of,=catch,=after,=end +setlocal indentkeys+==after,=end,=catch,=),=],=} -if exists('*ErlangIndent') -	finish +" Only define the functions once. +if exists("*ErlangIndent") +   finish  endif -let s:erlang_indent_file = expand('<sfile>:p:h') . '/erlang_indent.erl' -if filewritable(expand('<sfile>:p:h')) == 2 -	let s:in_fifo  = expand('<sfile>:p:h') . '/vimerl_in_fifo.' . getpid() -	let s:out_fifo = expand('<sfile>:p:h') . '/vimerl_out_fifo.' . getpid() -else -	let s:in_fifo  = '/tmp/vimerl_in_fifo.' . getpid() -	let s:out_fifo = '/tmp/vimerl_out_fifo.' . getpid() -endif +" The function go through the whole line, analyses it and sets the indentation +" (ind variable). +" l: the number of the line to be examined. +function s:ErlangIndentAfterLine(l) +    let i = 0 " the index of the current character in the line +    let length = strlen(a:l) " the length of 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 lastFun = 0 " the last token was a 'fun' +    let lastReceive = 0 " the last token was a 'receive'; needed for 'after' +    let lastHashMark = 0 " the last token was a 'hashmark' + +    " ignore type annotation lines +    if a:l =~# '^\s*-type' +	return 0 +    endif + +    while 0<= i && i < length -execute 'silent !mkfifo' s:in_fifo -execute 'silent !mkfifo' s:out_fifo -execute 'silent !' . s:erlang_indent_file s:out_fifo s:in_fifo '&' +        " m: the next value of the i +        if a:l[i] == '%' +            break +        elseif a:l[i] == '"' +            let m = matchend(a:l,'"\%([^"\\]\|\\.\)*"',i) +            let lastReceive = 0 +        elseif a:l[i] == "'" +            let m = matchend(a:l,"'[^']*'",i) +            let lastReceive = 0 +        elseif a:l[i] =~# "[a-z]" +            let m = matchend(a:l,".[[:alnum:]_]*",i) +            if lastFun +                let ind = ind - 1 +                let lastFun = 0 +                let lastReceive = 0 +            elseif a:l[(i):(m-1)] =~# '^\%(case\|if\|try\)$' +                let ind = ind + 1 +            elseif a:l[(i):(m-1)] =~# '^receive$' +                let ind = ind + 1 +                let lastReceive = 1 +            elseif a:l[(i):(m-1)] =~# '^begin$' +                let ind = ind + 2 +                let lastReceive = 0 +            elseif a:l[(i):(m-1)] =~# '^end$' +                let ind = ind - 2 +                let lastReceive = 0 +            elseif a:l[(i):(m-1)] =~# '^after$' +                if lastReceive == 0 +                    let ind = ind - 1 +                else +                    let ind = ind + 0 +                endif +                let lastReceive = 0 +            elseif a:l[(i):(m-1)] =~# '^fun$' +                let ind = ind + 1 +                let lastFun = 1 +                let lastReceive = 0 +            endif +        elseif a:l[i] =~# "[A-Z_]" +            let m = matchend(a:l,".[[:alnum:]_]*",i) +            let lastReceive = 0 +        elseif a:l[i] == '$' +            let m = i+2 +            let lastReceive = 0 +        elseif a:l[i] == "." && (i+1>=length || a:l[i+1]!~ "[0-9]") +            let m = i+1 +            if lastHashMark +                let lastHashMark = 0 +            else +                let ind = ind - 1 +            endif +            let lastReceive = 0 +        elseif a:l[i] == '-' && (i+1<length && a:l[i+1]=='>') +            let m = i+2 +            let ind = ind + 1 +            let lastReceive = 0 +        elseif a:l[i] == ';' && a:l[(i):(length)] !~# '.*->.*' +            let m = i+1 +            let ind = ind - 1 +            let lastReceive = 0 +        elseif a:l[i] == '#' +            let m = i+1 +            let lastHashMark = 1 +        elseif a:l[i] =~# '[({[]' +            let m = i+1 +            let ind = ind + 1 +            let lastFun = 0 +            let lastReceive = 0 +            let lastHashMark = 0 +        elseif a:l[i] =~# '[)}\]]' +            let m = i+1 +            let ind = ind - 1 +            let lastReceive = 0 +        else +            let m = i+1 +        endif -autocmd VimLeave * call <SID>StopIndenter() +        let i = m + +    endwhile + +    return ind + +endfunction -function s:StopIndenter() -	call writefile([], s:out_fifo) -	call delete(s:in_fifo) -	call delete(s:out_fifo) +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  function ErlangIndent() -	if v:lnum == 1 -		return 0 -	else -		call writefile([v:lnum] + getline(1, v:lnum), s:out_fifo) -		let indent = split(readfile(s:in_fifo)[0]) - -		if len(indent) == 1 || !&expandtab -			return indent[0] * &shiftwidth -		else -			return indent[1] -		endif -	endif + +    " 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 = indent(lnum) + &sw * s:ErlangIndentAfterLine(prevline) + +    " 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*\%(%.*\)\=$' +            let ind = ind - 1*&sw +            " If the 'receive' is not in the same line as the 'after' +        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 + +" TODO: +"  +" f() -> +"     x("foo +"         bar") +"         , +"         bad_indent. +" +" fun +"     init/0, +"     bad_indent +" +"     #rec +"     .field, +" bad_indent | 
