1" Vim indent file 2" Language: SML 3" Maintainer: Saikat Guha <[email protected]> 4" Hubert Chao <[email protected]> 5" Original OCaml Version: 6" Jean-Francois Yuen <[email protected]> 7" Mike Leary <[email protected]> 8" Markus Mottl <[email protected]> 9" OCaml URL: http://www.oefai.at/~markus/vim/indent/ocaml.vim 10" Last Change: 2003 Jan 04 - Adapted to SML 11" 2002 Nov 06 - Some fixes (JY) 12" 2002 Oct 28 - Fixed bug with indentation of ']' (MM) 13" 2002 Oct 22 - Major rewrite (JY) 14 15" Only load this indent file when no other was loaded. 16if exists("b:did_indent") 17 finish 18endif 19let b:did_indent = 1 20 21setlocal expandtab 22setlocal indentexpr=GetSMLIndent() 23setlocal indentkeys+=0=and,0=else,0=end,0=handle,0=if,0=in,0=let,0=then,0=val,0=fun,0=\|,0=*),0) 24setlocal nolisp 25setlocal nosmartindent 26setlocal textwidth=80 27setlocal shiftwidth=2 28 29" Comment formatting 30if (has("comments")) 31 set comments=sr:(*,mb:*,ex:*) 32 set fo=cqort 33endif 34 35" Only define the function once. 36"if exists("*GetSMLIndent") 37"finish 38"endif 39 40" Define some patterns: 41let s:beflet = '^\s*\(initializer\|method\|try\)\|\(\<\(begin\|do\|else\|in\|then\|try\)\|->\|;\)\s*$' 42let s:letpat = '^\s*\(let\|type\|module\|class\|open\|exception\|val\|include\|external\)\>' 43let s:letlim = '\(\<\(sig\|struct\)\|;;\)\s*$' 44let s:lim = '^\s*\(exception\|external\|include\|let\|module\|open\|type\|val\)\>' 45let s:module = '\<\%(let\|sig\|struct\)\>' 46let s:obj = '^\s*\(constraint\|inherit\|initializer\|method\|val\)\>\|\<\(object\|object\s*(.*)\)\s*$' 47let s:type = '^\s*\%(let\|type\)\>.*=' 48let s:val = '^\s*\(val\|external\)\>.*:' 49 50" Skipping pattern, for comments 51function! s:SkipPattern(lnum, pat) 52 let def = prevnonblank(a:lnum - 1) 53 while def > 0 && getline(def) =~ a:pat 54 let def = prevnonblank(def - 1) 55 endwhile 56 return def 57endfunction 58 59" Indent for ';;' to match multiple 'let' 60function! s:GetInd(lnum, pat, lim) 61 let llet = search(a:pat, 'bW') 62 let old = indent(a:lnum) 63 while llet > 0 64 let old = indent(llet) 65 let nb = s:SkipPattern(llet, '^\s*(\*.*\*)\s*$') 66 if getline(nb) =~ a:lim 67 return old 68 endif 69 let llet = search(a:pat, 'bW') 70 endwhile 71 return old 72endfunction 73 74" Indent pairs 75function! s:FindPair(pstart, pmid, pend) 76 call search(a:pend, 'bW') 77" return indent(searchpair(a:pstart, a:pmid, a:pend, 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string\\|comment"')) 78 let lno = searchpair(a:pstart, a:pmid, a:pend, 'bW', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string\\|comment"') 79 if lno == -1 80 return indent(lno) 81 else 82 return col(".") - 1 83 endif 84endfunction 85 86function! s:FindLet(pstart, pmid, pend) 87 call search(a:pend, 'bW') 88" return indent(searchpair(a:pstart, a:pmid, a:pend, 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string\\|comment"')) 89 let lno = searchpair(a:pstart, a:pmid, a:pend, 'bW', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string\\|comment"') 90 let moduleLine = getline(lno) 91 if lno == -1 || moduleLine =~ '^\s*\(fun\|structure\|signature\)\>' 92 return indent(lno) 93 else 94 return col(".") - 1 95 endif 96endfunction 97 98" Indent 'let' 99"function! s:FindLet(pstart, pmid, pend) 100" call search(a:pend, 'bW') 101" return indent(searchpair(a:pstart, a:pmid, a:pend, 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string\\|comment" || getline(".") =~ "^\\s*let\\>.*=.*\\<in\\s*$" || getline(prevnonblank(".") - 1) =~ "^\\s*let\\>.*=\\s*$\\|" . s:beflet')) 102"endfunction 103 104function! GetSMLIndent() 105 " Find a non-blank line above the current line. 106 let lnum = prevnonblank(v:lnum - 1) 107 108 " At the start of the file use zero indent. 109 if lnum == 0 110 return 0 111 endif 112 113 let ind = indent(lnum) 114 let lline = getline(lnum) 115 116 " Return double 'shiftwidth' after lines matching: 117 if lline =~ '^\s*|.*=>\s*$' 118 return ind + 2 *shiftwidth() 119 elseif lline =~ '^\s*val\>.*=\s*$' 120 return ind + shiftwidth() 121 endif 122 123 let line = getline(v:lnum) 124 125 " Indent lines starting with 'end' to matching module 126 if line =~ '^\s*end\>' 127 return s:FindLet(s:module, '', '\<end\>') 128 129 " Match 'else' with 'if' 130 elseif line =~ '^\s*else\>' 131 if lline !~ '^\s*\(if\|else\|then\)\>' 132 return s:FindPair('\<if\>', '', '\<then\>') 133 else 134 return ind 135 endif 136 137 " Match 'then' with 'if' 138 elseif line =~ '^\s*then\>' 139 if lline !~ '^\s*\(if\|else\|then\)\>' 140 return s:FindPair('\<if\>', '', '\<then\>') 141 else 142 return ind 143 endif 144 145 " Indent if current line begins with ']' 146 elseif line =~ '^\s*\]' 147 return s:FindPair('\[','','\]') 148 149 " Indent current line starting with 'in' to last matching 'let' 150 elseif line =~ '^\s*in\>' 151 let ind = s:FindLet('\<let\>','','\<in\>') 152 153 " Indent from last matching module if line matches: 154 elseif line =~ '^\s*\(fun\|val\|open\|structure\|and\|datatype\|type\|exception\)\>' 155 cursor(lnum,1) 156 let lastModule = indent(searchpair(s:module, '', '\<end\>', 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string\\|comment"')) 157 if lastModule == -1 158 return 0 159 else 160 return lastModule + shiftwidth() 161 endif 162 163 " Indent lines starting with '|' from matching 'case', 'handle' 164 elseif line =~ '^\s*|' 165 " cursor(lnum,1) 166 let lastSwitch = search('\<\(case\|handle\|fun\|datatype\)\>','bW') 167 let switchLine = getline(lastSwitch) 168 let switchLineIndent = indent(lastSwitch) 169 if lline =~ '^\s*|' 170 return ind 171 endif 172 if switchLine =~ '\<case\>' 173 return col(".") + 2 174 elseif switchLine =~ '\<handle\>' 175 return switchLineIndent + shiftwidth() 176 elseif switchLine =~ '\<datatype\>' 177 call search('=') 178 return col(".") - 1 179 else 180 return switchLineIndent + 2 181 endif 182 183 184 " Indent if last line ends with 'sig', 'struct', 'let', 'then', 'else', 185 " 'in' 186 elseif lline =~ '\<\(sig\|struct\|let\|in\|then\|else\)\s*$' 187 let ind = ind + shiftwidth() 188 189 " Indent if last line ends with 'of', align from 'case' 190 elseif lline =~ '\<\(of\)\s*$' 191 call search('\<case\>',"bW") 192 let ind = col(".")+4 193 194 " Indent if current line starts with 'of' 195 elseif line =~ '^\s*of\>' 196 call search('\<case\>',"bW") 197 let ind = col(".")+1 198 199 200 " Indent if last line starts with 'fun', 'case', 'fn' 201 elseif lline =~ '^\s*\(fun\|fn\|case\)\>' 202 let ind = ind + shiftwidth() 203 204 endif 205 206 " Don't indent 'let' if last line started with 'fun', 'fn' 207 if line =~ '^\s*let\>' 208 if lline =~ '^\s*\(fun\|fn\)' 209 let ind = ind - shiftwidth() 210 endif 211 endif 212 213 return ind 214 215endfunction 216 217" vim:sw=2 218