Skip to content
Browse files

Replaces indent with version from aszlig

I put here the indent file from aszlig to see in a future if it is a
good start point to improve the indent algorithm.
  • Loading branch information...
1 parent 07731b8 commit e5596ecf41ccff53d6c9da1ac33c764eb86e7e33 @jimenezrick committed Nov 14, 2011
Showing with 170 additions and 110 deletions.
  1. +170 −110 indent/erlang.vim
View
280 indent/erlang.vim
@@ -1,143 +1,126 @@
" 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>
-" Version: 2011/09/06
+" 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
-" Only load this indent file when no other was loaded
+" Only load this indent file when no other was loaded.
if exists("b:did_indent")
- finish
-else
- let b:did_indent = 1
+ finish
endif
+let b:did_indent = 1
setlocal indentexpr=ErlangIndent()
setlocal indentkeys+==after,=end,=catch,=),=],=}
-" Only define the functions once
+" Only define the functions once.
if exists("*ErlangIndent")
- finish
+ 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
+" 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 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 '#'
+ 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 comments
- if a:line =~# '^\s*%'
- return 0
+ " ignore type annotation lines
+ if a:l =~# '^\s*-type'
+ return 0
endif
- " Partial function head where the guard is missing
- if a:line =~# "\\(^\\l[[:alnum:]_]*\\)\\|\\(^'[^']\\+'\\)(" && a:line !~# '->'
- return 2
- endif
+ while 0<= i && i < length
- " 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
+ 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 last_fun = 0
- let last_receive = 0
- elseif a:line[(i):(m-1)] =~# '^\%(case\|if\|try\)$'
+ let lastFun = 0
+ let lastReceive = 0
+ elseif a:l[(i):(m-1)] =~# '^\%(case\|if\|try\)$'
let ind = ind + 1
- elseif a:line[(i):(m-1)] =~# '^receive$'
+ elseif a:l[(i):(m-1)] =~# '^receive$'
let ind = ind + 1
- let last_receive = 1
- elseif a:line[(i):(m-1)] =~# '^begin$'
+ let lastReceive = 1
+ elseif a:l[(i):(m-1)] =~# '^begin$'
let ind = ind + 2
- let last_receive = 0
- elseif a:line[(i):(m-1)] =~# '^end$'
+ let lastReceive = 0
+ elseif a:l[(i):(m-1)] =~# '^end$'
let ind = ind - 2
- let last_receive = 0
- elseif a:line[(i):(m-1)] =~# '^after$'
- if last_receive == 0
+ let lastReceive = 0
+ elseif a:l[(i):(m-1)] =~# '^after$'
+ if lastReceive == 0
let ind = ind - 1
else
let ind = ind + 0
endif
- let last_receive = 0
- elseif a:line[(i):(m-1)] =~# '^fun$'
+ let lastReceive = 0
+ elseif a:l[(i):(m-1)] =~# '^fun$'
let ind = ind + 1
- let last_fun = 1
- let last_receive = 0
+ let lastFun = 1
+ let lastReceive = 0
endif
- elseif a:line[i] =~# "[A-Z_]"
- let m = matchend(a:line,".[[:alnum:]_]*",i)
- let last_receive = 0
- elseif a:line[i] == '$'
+ 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 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
+ let lastReceive = 0
+ elseif a:l[i] == "." && (i+1>=length || a:l[i+1]!~ "[0-9]")
+ if matchend(a:l, '[^({<[]*[)}>\]]', i) == -1
+ if lastHashMark
+ let lastHashMark = 0
+ else
+ let ind = ind - 1
+ endif
endif
- let last_receive = 0
- elseif a:line[i] == '-' && (i+1<linelen && a:line[i+1]=='>')
+ let m = i+1
+ let lastReceive = 0
+ elseif a:l[i] == '-' && (i+1<length && a:l[i+1]=='>')
let m = i+2
let ind = ind + 1
- let last_receive = 0
- elseif a:line[i] == ';' && a:line[(i):(linelen)] !~# '.*->.*'
+ let lastReceive = 0
+ elseif a:l[i] == ';' && a:l[(i):(length)] !~# '.*->.*'
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 lastReceive = 0
+ elseif a:l[i] == '#'
let m = i+1
- let ind = ind - 1
- let last_receive = 0
+ let lastHashMark = 1
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 '%'
+ " continue to search above if the current line begins with a '%'
while line =~# '^\s*%.*$'
let lnum = prevnonblank(lnum - 1)
if 0 == lnum
@@ -148,35 +131,101 @@ function s:FindPrevNonBlankNonComment(lnum)
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
+" Galculate the lowest distance between two parent ranges
+function s:ErlangInnermostParenSorter(p1, p2)
+ let diff = a:p2[0] - a:p1[0]
+ return diff == 0 ? a:p2[1] - a:p1[1] : diff
+endfunction
+
+" Find the next parens to curline and curcol and get the best math by sorter
+function s:ErlangSearchParens(curline, curcol, sorter)
+ let parens = [['(', ')'],
+ \ ['\[', '\]'],
+ \ ['{', '}'],
+ \ ['<<', '>>']]
+
+ let skip = "synIDattr(synID(line('.'), col('.'), 1), 'name')"
+ \ ." =~? '\\(modifier\\|comment\\|string\\)$'"
+
+
+ let plist = []
+
+ " search all paren types
+ for [lpar, rpar] in parens
+ call cursor(a:curline, a:curcol)
+ let result = searchpair(lpar, '', rpar, 'bW', skip)
+ let plist += [[result, col('.')]]
+ endfor
+
+ " get and return best match
+ call sort(plist, a:sorter)
+ return plist[0]
+endfunction
+
+" Find the innermost starting parens/braces/brackets/funnels and calculate the
+" indentation level according to their position.
+function s:ErlangHandleParens(curline, curcol)
+ let [line, column] = s:ErlangSearchParens(a:curline, a:curcol, "s:ErlangInnermostParenSorter")
+
+ if line > 0
+ let matchdata = getline(line)
+ let linedata = getline(a:curline)
+
+ " first closing par in current line
+ let clpar = match(linedata, '^\s*\%([)}\]]\|>>\)') != -1
+
+ if match(matchdata, '\%([({[]\|<<\)\s*$', column - 1) != -1
+ " block data
+ let ind = indent(line) + (clpar ? 0 : &sw)
+ else
+ " inline data
+ let ind = column - (clpar ? 1 : 0)
+ endif
+
+ return ind >= 0 ? ind : -1
+ endif
+
+ return -1
endfunction
function ErlangIndent()
- " Find a non-blank line above the current line
+
+ " Find a non-blank line above the current line.
let lnum = prevnonblank(v:lnum - 1)
- " Hit the start of the file, use zero indent
+ " 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
+ let newind = s:ErlangHandleParens(v:lnum, 1)
+ if newind >= 0
+ return newind
+ endif
+
+ let soup = prevline
+
+ let ind = indent(lnum)
+
+ if prevline =~# '\([)}\]]\|>>\)'
+ " Last line contains an end paren, so indent at the same level as
+ " the statement introducing the paren.
+ let pllastparen = match(prevline, '\([)}\]]\|>>\)[^)}>\]]*$')
+ let [pl, pc] = s:ErlangSearchParens(lnum, pllastparen, "s:ErlangInnermostParenSorter")
+ if pl > 0 && pl != lnum
+ let ind = indent(pl)
+ " Let's put all that soup together so we can later find
+ " the right keywords and indent according to them.
+ let soup = join(getline(pl, lnum), ' ')
+ endif
endif
- " Special cases:
+ let ind = ind + &sw * s:ErlangIndentAfterLine(soup)
+
+ " special cases:
if prevline =~# '^\s*\%(after\|end\)\>'
let ind = ind + 2*&sw
endif
@@ -186,18 +235,12 @@ function ErlangIndent()
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
+ " 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
@@ -209,4 +252,21 @@ function ErlangIndent()
let ind = 0
endif
return ind
+
endfunction
+
+" TODO:
+"
+" f() ->
+" x("foo
+" bar")
+" ,
+" bad_indent.
+"
+" fun
+" init/0,
+" bad_indent
+"
+" #rec
+" .field,
+" bad_indent

1 comment on commit e5596ec

@jhlywa
jhlywa commented on e5596ec Dec 8, 2011

This new indent file is an awesome improvement. Kudos to aszlig!

Please sign in to comment.
Something went wrong with that request. Please try again.