1" Vim indent file 2" Language: OCaml 3" Maintainers: Jean-Francois Yuen <[email protected]> 4" Mike Leary <[email protected]> 5" Markus Mottl <[email protected]> 6" URL: http://www.ocaml.info/vim/indent/ocaml.vim 7" Last Change: 2013 Jun 29 8" 2005 Jun 25 - Fixed multiple bugs due to 'else\nreturn ind' working 9" 2005 May 09 - Added an option to not indent OCaml-indents specially (MM) 10" 2013 June - commented textwidth (Marc Weber) 11" 12" Marc Weber's comment: This file may contain a lot of (very custom) stuff 13" which eventually should be moved somewhere else .. 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=GetOCamlIndent() 23setlocal indentkeys+=0=and,0=class,0=constraint,0=done,0=else,0=end,0=exception,0=external,0=if,0=in,0=include,0=inherit,0=initializer,0=let,0=method,0=open,0=then,0=type,0=val,0=with,0;;,0>\],0\|\],0>},0\|,0},0\],0) 24setlocal nolisp 25setlocal nosmartindent 26 27" At least Marc Weber and Markus Mottl do not like this: 28" setlocal textwidth=80 29 30" Comment formatting 31if !exists("no_ocaml_comments") 32 if (has("comments")) 33 setlocal comments=sr:(*,mb:*,ex:*) 34 setlocal fo=cqort 35 endif 36endif 37 38" Only define the function once. 39if exists("*GetOCamlIndent") 40 finish 41endif 42 43" Define some patterns: 44let s:beflet = '^\s*\(initializer\|method\|try\)\|\(\<\(begin\|do\|else\|in\|then\|try\)\|->\|<-\|=\|;\|(\)\s*$' 45let s:letpat = '^\s*\(let\|type\|module\|class\|open\|exception\|val\|include\|external\)\>' 46let s:letlim = '\(\<\(sig\|struct\)\|;;\)\s*$' 47let s:lim = '^\s*\(exception\|external\|include\|let\|module\|open\|type\|val\)\>' 48let s:module = '\<\%(begin\|sig\|struct\|object\)\>' 49let s:obj = '^\s*\(constraint\|inherit\|initializer\|method\|val\)\>\|\<\(object\|object\s*(.*)\)\s*$' 50let s:type = '^\s*\%(class\|let\|type\)\>.*=' 51 52" Skipping pattern, for comments 53function! s:GetLineWithoutFullComment(lnum) 54 let lnum = prevnonblank(a:lnum - 1) 55 let lline = substitute(getline(lnum), '(\*.*\*)\s*$', '', '') 56 while lline =~ '^\s*$' && lnum > 0 57 let lnum = prevnonblank(lnum - 1) 58 let lline = substitute(getline(lnum), '(\*.*\*)\s*$', '', '') 59 endwhile 60 return lnum 61endfunction 62 63" Indent for ';;' to match multiple 'let' 64function! s:GetInd(lnum, pat, lim) 65 let llet = search(a:pat, 'bW') 66 let old = indent(a:lnum) 67 while llet > 0 68 let old = indent(llet) 69 let nb = s:GetLineWithoutFullComment(llet) 70 if getline(nb) =~ a:lim 71 return old 72 endif 73 let llet = search(a:pat, 'bW') 74 endwhile 75 return old 76endfunction 77 78" Indent pairs 79function! s:FindPair(pstart, pmid, pend) 80 call search(a:pend, 'bW') 81 return indent(searchpair(a:pstart, a:pmid, a:pend, 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string\\|comment"')) 82endfunction 83 84" Indent 'let' 85function! s:FindLet(pstart, pmid, pend) 86 call search(a:pend, 'bW') 87 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:beflet')) 88endfunction 89 90function! GetOCamlIndent() 91 " Find a non-commented line above the current line. 92 let lnum = s:GetLineWithoutFullComment(v:lnum) 93 94 " At the start of the file use zero indent. 95 if lnum == 0 96 return 0 97 endif 98 99 let ind = indent(lnum) 100 let lline = substitute(getline(lnum), '(\*.*\*)\s*$', '', '') 101 102 " Return double 'shiftwidth' after lines matching: 103 if lline =~ '^\s*|.*->\s*$' 104 return ind + &sw + &sw 105 endif 106 107 let line = getline(v:lnum) 108 109 " Indent if current line begins with 'end': 110 if line =~ '^\s*end\>' 111 return s:FindPair(s:module, '','\<end\>') 112 113 " Indent if current line begins with 'done' for 'do': 114 elseif line =~ '^\s*done\>' 115 return s:FindPair('\<do\>', '','\<done\>') 116 117 " Indent if current line begins with '}' or '>}': 118 elseif line =~ '^\s*\(\|>\)}' 119 return s:FindPair('{', '','}') 120 121 " Indent if current line begins with ']', '|]' or '>]': 122 elseif line =~ '^\s*\(\||\|>\)\]' 123 return s:FindPair('\[', '','\]') 124 125 " Indent if current line begins with ')': 126 elseif line =~ '^\s*)' 127 return s:FindPair('(', '',')') 128 129 " Indent if current line begins with 'let': 130 elseif line =~ '^\s*let\>' 131 if lline !~ s:lim . '\|' . s:letlim . '\|' . s:beflet 132 return s:FindLet(s:type, '','\<let\s*$') 133 endif 134 135 " Indent if current line begins with 'class' or 'type': 136 elseif line =~ '^\s*\(class\|type\)\>' 137 if lline !~ s:lim . '\|\<and\s*$\|' . s:letlim 138 return s:FindLet(s:type, '','\<\(class\|type\)\s*$') 139 endif 140 141 " Indent for pattern matching: 142 elseif line =~ '^\s*|' 143 if lline !~ '^\s*\(|[^\]]\|\(match\|type\|with\)\>\)\|\<\(function\|parser\|private\|with\)\s*$' 144 call search('|', 'bW') 145 return indent(searchpair('^\s*\(match\|type\)\>\|\<\(function\|parser\|private\|with\)\s*$', '', '^\s*|', 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string\\|comment" || getline(".") !~ "^\\s*|.*->"')) 146 endif 147 148 " Indent if current line begins with ';;': 149 elseif line =~ '^\s*;;' 150 if lline !~ ';;\s*$' 151 return s:GetInd(v:lnum, s:letpat, s:letlim) 152 endif 153 154 " Indent if current line begins with 'in': 155 elseif line =~ '^\s*in\>' 156 if lline !~ '^\s*\(let\|and\)\>' 157 return s:FindPair('\<let\>', '', '\<in\>') 158 endif 159 160 " Indent if current line begins with 'else': 161 elseif line =~ '^\s*else\>' 162 if lline !~ '^\s*\(if\|then\)\>' 163 return s:FindPair('\<if\>', '', '\<else\>') 164 endif 165 166 " Indent if current line begins with 'then': 167 elseif line =~ '^\s*then\>' 168 if lline !~ '^\s*\(if\|else\)\>' 169 return s:FindPair('\<if\>', '', '\<then\>') 170 endif 171 172 " Indent if current line begins with 'and': 173 elseif line =~ '^\s*and\>' 174 if lline !~ '^\s*\(and\|let\|type\)\>\|\<end\s*$' 175 return ind - &sw 176 endif 177 178 " Indent if current line begins with 'with': 179 elseif line =~ '^\s*with\>' 180 if lline !~ '^\s*\(match\|try\)\>' 181 return s:FindPair('\<\%(match\|try\)\>', '','\<with\>') 182 endif 183 184 " Indent if current line begins with 'exception', 'external', 'include' or 185 " 'open': 186 elseif line =~ '^\s*\(exception\|external\|include\|open\)\>' 187 if lline !~ s:lim . '\|' . s:letlim 188 call search(line) 189 return indent(search('^\s*\(\(exception\|external\|include\|open\|type\)\>\|val\>.*:\)', 'bW')) 190 endif 191 192 " Indent if current line begins with 'val': 193 elseif line =~ '^\s*val\>' 194 if lline !~ '^\s*\(exception\|external\|include\|open\)\>\|' . s:obj . '\|' . s:letlim 195 return indent(search('^\s*\(\(exception\|include\|initializer\|method\|open\|type\|val\)\>\|external\>.*:\)', 'bW')) 196 endif 197 198 " Indent if current line begins with 'constraint', 'inherit', 'initializer' 199 " or 'method': 200 elseif line =~ '^\s*\(constraint\|inherit\|initializer\|method\)\>' 201 if lline !~ s:obj 202 return indent(search('\<\(object\|object\s*(.*)\)\s*$', 'bW')) + &sw 203 endif 204 205 endif 206 207 " Add a 'shiftwidth' after lines ending with: 208 if lline =~ '\(:\|=\|->\|<-\|(\|\[\|{\|{<\|\[|\|\[<\|\<\(begin\|do\|else\|fun\|function\|functor\|if\|initializer\|object\|parser\|private\|sig\|struct\|then\|try\)\|\<object\s*(.*)\)\s*$' 209 let ind = ind + &sw 210 211 " Back to normal indent after lines ending with ';;': 212 elseif lline =~ ';;\s*$' && lline !~ '^\s*;;' 213 let ind = s:GetInd(v:lnum, s:letpat, s:letlim) 214 215 " Back to normal indent after lines ending with 'end': 216 elseif lline =~ '\<end\s*$' 217 let ind = s:FindPair(s:module, '','\<end\>') 218 219 " Back to normal indent after lines ending with 'in': 220 elseif lline =~ '\<in\s*$' && lline !~ '^\s*in\>' 221 let ind = s:FindPair('\<let\>', '', '\<in\>') 222 223 " Back to normal indent after lines ending with 'done': 224 elseif lline =~ '\<done\s*$' 225 let ind = s:FindPair('\<do\>', '','\<done\>') 226 227 " Back to normal indent after lines ending with '}' or '>}': 228 elseif lline =~ '\(\|>\)}\s*$' 229 let ind = s:FindPair('{', '','}') 230 231 " Back to normal indent after lines ending with ']', '|]' or '>]': 232 elseif lline =~ '\(\||\|>\)\]\s*$' 233 let ind = s:FindPair('\[', '','\]') 234 235 " Back to normal indent after comments: 236 elseif lline =~ '\*)\s*$' 237 call search('\*)', 'bW') 238 let ind = indent(searchpair('(\*', '', '\*)', 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string"')) 239 240 " Back to normal indent after lines ending with ')': 241 elseif lline =~ ')\s*$' 242 let ind = s:FindPair('(', '',')') 243 244 " If this is a multiline comment then align '*': 245 elseif lline =~ '^\s*(\*' && line =~ '^\s*\*' 246 let ind = ind + 1 247 248 else 249 " Don't change indentation of this line 250 " for new lines (indent==0) use indentation of previous line 251 252 " This is for preventing removing indentation of these args: 253 " let f x = 254 " let y = x + 1 in 255 " Printf.printf 256 " "o" << here 257 " "oeuth" << don't touch indentation 258 259 let i = indent(v:lnum) 260 return i == 0 ? ind : i 261 262 endif 263 264 " Subtract a 'shiftwidth' after lines matching 'match ... with parser': 265 if lline =~ '\<match\>.*\<with\>\s*\<parser\s*$' 266 let ind = ind - &sw 267 endif 268 269 return ind 270 271endfunction 272 273" vim:sw=2 274