Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
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...
commit e5596ecf41ccff53d6c9da1ac33c764eb86e7e33 1 parent 07731b8
@jimenezrick authored
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,20 +131,69 @@ 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
@@ -169,14 +201,31 @@ function ErlangIndent()
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

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.