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