Bram Moolenaar | 3577c6f | 2008-06-24 21:16:56 +0000 | [diff] [blame] | 1 | " Vim indent file |
| 2 | " Language: Erlang |
| 3 | " Maintainer: Csaba Hoch <csaba.hoch@gmail.com> |
| 4 | " Contributor: Edwin Fine <efine145_nospam01 at usa dot net> |
| 5 | " Last Change: 2008 Mar 12 |
| 6 | |
| 7 | " Only load this indent file when no other was loaded. |
| 8 | if exists("b:did_indent") |
| 9 | finish |
| 10 | endif |
| 11 | let b:did_indent = 1 |
| 12 | |
| 13 | setlocal indentexpr=ErlangIndent() |
| 14 | setlocal indentkeys+==after,=end,=catch,=),=],=} |
| 15 | |
| 16 | " Only define the functions once. |
| 17 | if exists("*ErlangIndent") |
| 18 | finish |
| 19 | endif |
| 20 | |
| 21 | " The function go through the whole line, analyses it and sets the indentation |
| 22 | " (ind variable). |
| 23 | " l: the number of the line to be examined. |
| 24 | function s:ErlangIndentAtferLine(l) |
| 25 | let i = 0 " the index of the current character in the line |
| 26 | let length = strlen(a:l) " the length of the line |
| 27 | let ind = 0 " how much should be the difference between the indentation of |
| 28 | " the current line and the indentation of the next line? |
| 29 | " e.g. +1: the indentation of the next line should be equal to |
| 30 | " the indentation of the current line plus one shiftwidth |
| 31 | let lastFun = 0 " the last token was a 'fun' |
| 32 | let lastReceive = 0 " the last token was a 'receive'; needed for 'after' |
| 33 | let lastHashMark = 0 " the last token was a 'hashmark' |
| 34 | |
| 35 | while 0<= i && i < length |
| 36 | |
| 37 | " m: the next value of the i |
| 38 | if a:l[i] == '%' |
| 39 | break |
| 40 | elseif a:l[i] == '"' |
| 41 | let m = matchend(a:l,'"\%([^"\\]\|\\.\)*"',i) |
| 42 | let lastReceive = 0 |
| 43 | elseif a:l[i] == "'" |
| 44 | let m = matchend(a:l,"'[^']*'",i) |
| 45 | let lastReceive = 0 |
| 46 | elseif a:l[i] =~# "[a-z]" |
| 47 | let m = matchend(a:l,".[[:alnum:]_]*",i) |
| 48 | if lastFun |
| 49 | let ind = ind - 1 |
| 50 | let lastFun = 0 |
| 51 | let lastReceive = 0 |
| 52 | elseif a:l[(i):(m-1)] =~# '^\%(case\|if\|try\)$' |
| 53 | let ind = ind + 1 |
| 54 | elseif a:l[(i):(m-1)] =~# '^receive$' |
| 55 | let ind = ind + 1 |
| 56 | let lastReceive = 1 |
| 57 | elseif a:l[(i):(m-1)] =~# '^begin$' |
| 58 | let ind = ind + 2 |
| 59 | let lastReceive = 0 |
| 60 | elseif a:l[(i):(m-1)] =~# '^end$' |
| 61 | let ind = ind - 2 |
| 62 | let lastReceive = 0 |
| 63 | elseif a:l[(i):(m-1)] =~# '^after$' |
| 64 | if lastReceive == 0 |
| 65 | let ind = ind - 1 |
| 66 | else |
| 67 | let ind = ind + 0 |
| 68 | end |
| 69 | let lastReceive = 0 |
| 70 | elseif a:l[(i):(m-1)] =~# '^fun$' |
| 71 | let ind = ind + 1 |
| 72 | let lastFun = 1 |
| 73 | let lastReceive = 0 |
| 74 | endif |
| 75 | elseif a:l[i] =~# "[A-Z_]" |
| 76 | let m = matchend(a:l,".[[:alnum:]_]*",i) |
| 77 | let lastReceive = 0 |
| 78 | elseif a:l[i] == '$' |
| 79 | let m = i+2 |
| 80 | let lastReceive = 0 |
| 81 | elseif a:l[i] == "." && (i+1>=length || a:l[i+1]!~ "[0-9]") |
| 82 | let m = i+1 |
| 83 | if lastHashMark |
| 84 | let lastHashMark = 0 |
| 85 | else |
| 86 | let ind = ind - 1 |
| 87 | end |
| 88 | let lastReceive = 0 |
| 89 | elseif a:l[i] == '-' && (i+1<length && a:l[i+1]=='>') |
| 90 | let m = i+2 |
| 91 | let ind = ind + 1 |
| 92 | let lastReceive = 0 |
| 93 | elseif a:l[i] == ';' |
| 94 | let m = i+1 |
| 95 | let ind = ind - 1 |
| 96 | let lastReceive = 0 |
| 97 | elseif a:l[i] == '#' |
| 98 | let m = i+1 |
| 99 | let lastHashMark = 1 |
| 100 | elseif a:l[i] =~# '[({[]' |
| 101 | let m = i+1 |
| 102 | let ind = ind + 1 |
| 103 | let lastFun = 0 |
| 104 | let lastReceive = 0 |
| 105 | let lastHashMark = 0 |
| 106 | elseif a:l[i] =~# '[)}\]]' |
| 107 | let m = i+1 |
| 108 | let ind = ind - 1 |
| 109 | let lastReceive = 0 |
| 110 | else |
| 111 | let m = i+1 |
| 112 | endif |
| 113 | |
| 114 | let i = m |
| 115 | |
| 116 | endwhile |
| 117 | |
| 118 | return ind |
| 119 | |
| 120 | endfunction |
| 121 | |
| 122 | function s:FindPrevNonBlankNonComment(lnum) |
| 123 | let lnum = prevnonblank(a:lnum) |
| 124 | let line = getline(lnum) |
| 125 | " continue to search above if the current line begins with a '%' |
| 126 | while line =~# '^\s*%.*$' |
| 127 | let lnum = prevnonblank(lnum - 1) |
| 128 | if 0 == lnum |
| 129 | return 0 |
| 130 | endif |
| 131 | let line = getline(lnum) |
| 132 | endwhile |
| 133 | return lnum |
| 134 | endfunction |
| 135 | |
| 136 | function ErlangIndent() |
| 137 | |
| 138 | " Find a non-blank line above the current line. |
| 139 | let lnum = prevnonblank(v:lnum - 1) |
| 140 | |
| 141 | " Hit the start of the file, use zero indent. |
| 142 | if lnum == 0 |
| 143 | return 0 |
| 144 | endif |
| 145 | |
| 146 | let prevline = getline(lnum) |
| 147 | let currline = getline(v:lnum) |
| 148 | |
| 149 | let ind = indent(lnum) + &sw * s:ErlangIndentAtferLine(prevline) |
| 150 | |
| 151 | " special cases: |
| 152 | if prevline =~# '^\s*\%(after\|end\)\>' |
| 153 | let ind = ind + 2*&sw |
| 154 | endif |
| 155 | if currline =~# '^\s*end\>' |
| 156 | let ind = ind - 2*&sw |
| 157 | endif |
| 158 | if currline =~# '^\s*after\>' |
| 159 | let plnum = s:FindPrevNonBlankNonComment(v:lnum-1) |
| 160 | if getline(plnum) =~# '^[^%]*\<receive\>\s*\%(%.*\)\=$' |
| 161 | let ind = ind - 1*&sw |
| 162 | " If the 'receive' is not in the same line as the 'after' |
| 163 | else |
| 164 | let ind = ind - 2*&sw |
| 165 | endif |
| 166 | endif |
| 167 | if prevline =~# '^\s*[)}\]]' |
| 168 | let ind = ind + 1*&sw |
| 169 | endif |
| 170 | if currline =~# '^\s*[)}\]]' |
| 171 | let ind = ind - 1*&sw |
| 172 | endif |
| 173 | if prevline =~# '^\s*\%(catch\)\s*\%(%\|$\)' |
| 174 | let ind = ind + 1*&sw |
| 175 | endif |
| 176 | if currline =~# '^\s*\%(catch\)\s*\%(%\|$\)' |
| 177 | let ind = ind - 1*&sw |
| 178 | endif |
| 179 | |
| 180 | if ind<0 |
| 181 | let ind = 0 |
| 182 | endif |
| 183 | return ind |
| 184 | |
| 185 | endfunction |
| 186 | |
| 187 | " TODO: |
| 188 | " |
| 189 | " f() -> |
| 190 | " x("foo |
| 191 | " bar") |
| 192 | " , |
| 193 | " bad_indent. |
| 194 | " |
| 195 | " fun |
| 196 | " init/0, |
| 197 | " bad_indent |
| 198 | " |
| 199 | " #rec |
| 200 | " .field, |
| 201 | " bad_indent |
| 202 | " |
| 203 | " case X of |
| 204 | " 1 when A; B -> |
| 205 | " bad_indent |
| 206 | |