blob: 53431c9b0b9e3bcc072fd4f1ae9e94a94deac1b1 [file] [log] [blame]
Bram Moolenaara5792f52005-11-23 21:25:05 +00001" Language: OCaml
2" Maintainer: David Baelde <firstname.name@ens-lyon.org>
3" Mike Leary <leary@nwlink.com>
4" Markus Mottl <markus.mottl@gmail.com>
5" Stefano Zacchiroli <zack@bononia.it>
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006" Vincent Aravantinos <firstname.name@imag.fr>
Bram Moolenaara5792f52005-11-23 21:25:05 +00007" URL: http://www.ocaml.info/vim/ftplugin/ocaml.vim
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00008" Last Change: 2007 Sep 09 - Added .annot support for ocamlbuild, python not
9" needed anymore (VA)
10" 2006 May 01 - Added .annot support for file.whateverext (SZ)
11" 2006 Apr 11 - Fixed an initialization bug; fixed ASS abbrev (MM)
Bram Moolenaar4c3f5362006-04-11 21:38:50 +000012" 2005 Oct 13 - removed GPL; better matchit support (MM, SZ)
Bram Moolenaara5792f52005-11-23 21:25:05 +000013"
Bram Moolenaar4c3f5362006-04-11 21:38:50 +000014if exists("b:did_ftplugin")
15 finish
16endif
Bram Moolenaara5792f52005-11-23 21:25:05 +000017let b:did_ftplugin=1
Bram Moolenaar071d4272004-06-13 20:20:40 +000018
Bram Moolenaara5792f52005-11-23 21:25:05 +000019" Error handling -- helps moving where the compiler wants you to go
20let s:cposet=&cpoptions
Bram Moolenaar071d4272004-06-13 20:20:40 +000021set cpo-=C
Bram Moolenaar071d4272004-06-13 20:20:40 +000022setlocal efm=
Bram Moolenaara5792f52005-11-23 21:25:05 +000023 \%EFile\ \"%f\"\\,\ line\ %l\\,\ characters\ %c-%*\\d:,
24 \%EFile\ \"%f\"\\,\ line\ %l\\,\ character\ %c:%m,
25 \%+EReference\ to\ unbound\ regexp\ name\ %m,
26 \%Eocamlyacc:\ e\ -\ line\ %l\ of\ \"%f\"\\,\ %m,
27 \%Wocamlyacc:\ w\ -\ %m,
28 \%-Zmake%.%#,
29 \%C%m,
30 \%D%*\\a[%*\\d]:\ Entering\ directory\ `%f',
31 \%X%*\\a[%*\\d]:\ Leaving\ directory\ `%f',
32 \%D%*\\a:\ Entering\ directory\ `%f',
33 \%X%*\\a:\ Leaving\ directory\ `%f',
34 \%DMaking\ %*\\a\ in\ %f
Bram Moolenaar071d4272004-06-13 20:20:40 +000035
36" Add mappings, unless the user didn't want this.
37if !exists("no_plugin_maps") && !exists("no_ocaml_maps")
Bram Moolenaara5792f52005-11-23 21:25:05 +000038 " (un)commenting
Bram Moolenaar071d4272004-06-13 20:20:40 +000039 if !hasmapto('<Plug>Comment')
40 nmap <buffer> <LocalLeader>c <Plug>LUncomOn
41 vmap <buffer> <LocalLeader>c <Plug>BUncomOn
42 nmap <buffer> <LocalLeader>C <Plug>LUncomOff
43 vmap <buffer> <LocalLeader>C <Plug>BUncomOff
44 endif
45
46 nnoremap <buffer> <Plug>LUncomOn mz0i(* <ESC>$A *)<ESC>`z
Bram Moolenaara5792f52005-11-23 21:25:05 +000047 nnoremap <buffer> <Plug>LUncomOff :s/^(\* \(.*\) \*)/\1/<CR>:noh<CR>
Bram Moolenaar071d4272004-06-13 20:20:40 +000048 vnoremap <buffer> <Plug>BUncomOn <ESC>:'<,'><CR>`<O<ESC>0i(*<ESC>`>o<ESC>0i*)<ESC>`<
49 vnoremap <buffer> <Plug>BUncomOff <ESC>:'<,'><CR>`<dd`>dd`<
50
51 if !hasmapto('<Plug>Abbrev')
Bram Moolenaar4c3f5362006-04-11 21:38:50 +000052 iabbrev <buffer> ASS (assert (0=1) (* XXX *))
Bram Moolenaar071d4272004-06-13 20:20:40 +000053 endif
54endif
Bram Moolenaar5eb86f92004-07-26 12:53:41 +000055
56" Let % jump between structure elements (due to Issac Trotts)
Bram Moolenaara5792f52005-11-23 21:25:05 +000057let b:mw = ''
58let b:mw = b:mw . ',\<let\>:\<and\>:\(\<in\>\|;;\)'
59let b:mw = b:mw . ',\<if\>:\<then\>:\<else\>'
60let b:mw = b:mw . ',\<\(for\|while\)\>:\<do\>:\<done\>,'
61let b:mw = b:mw . ',\<\(object\|sig\|struct\|begin\)\>:\<end\>'
62let b:mw = b:mw . ',\<\(match\|try\)\>:\<with\>'
63let b:match_words = b:mw
64
65let b:match_ignorecase=0
Bram Moolenaar5eb86f92004-07-26 12:53:41 +000066
67" switching between interfaces (.mli) and implementations (.ml)
68if !exists("g:did_ocaml_switch")
69 let g:did_ocaml_switch = 1
Bram Moolenaara5792f52005-11-23 21:25:05 +000070 map <LocalLeader>s :call OCaml_switch(0)<CR>
71 map <LocalLeader>S :call OCaml_switch(1)<CR>
Bram Moolenaar5eb86f92004-07-26 12:53:41 +000072 fun OCaml_switch(newwin)
73 if (match(bufname(""), "\\.mli$") >= 0)
74 let fname = substitute(bufname(""), "\\.mli$", ".ml", "")
75 if (a:newwin == 1)
Bram Moolenaara5792f52005-11-23 21:25:05 +000076 exec "new " . fname
Bram Moolenaar5eb86f92004-07-26 12:53:41 +000077 else
Bram Moolenaara5792f52005-11-23 21:25:05 +000078 exec "arge " . fname
Bram Moolenaar5eb86f92004-07-26 12:53:41 +000079 endif
80 elseif (match(bufname(""), "\\.ml$") >= 0)
81 let fname = bufname("") . "i"
82 if (a:newwin == 1)
Bram Moolenaara5792f52005-11-23 21:25:05 +000083 exec "new " . fname
Bram Moolenaar5eb86f92004-07-26 12:53:41 +000084 else
Bram Moolenaara5792f52005-11-23 21:25:05 +000085 exec "arge " . fname
Bram Moolenaar5eb86f92004-07-26 12:53:41 +000086 endif
87 endif
88 endfun
89endif
90
Bram Moolenaara5792f52005-11-23 21:25:05 +000091" Folding support
92
93" Get the modeline because folding depends on indentation
94let s:s = line2byte(line('.'))+col('.')-1
95if search('^\s*(\*:o\?caml:')
96 let s:modeline = getline(".")
97else
98 let s:modeline = ""
99endif
100if s:s > 0
101 exe 'goto' s:s
102endif
103
104" Get the indentation params
105let s:m = matchstr(s:modeline,'default\s*=\s*\d\+')
106if s:m != ""
107 let s:idef = matchstr(s:m,'\d\+')
108elseif exists("g:omlet_indent")
109 let s:idef = g:omlet_indent
110else
111 let s:idef = 2
112endif
113let s:m = matchstr(s:modeline,'struct\s*=\s*\d\+')
114if s:m != ""
115 let s:i = matchstr(s:m,'\d\+')
116elseif exists("g:omlet_indent_struct")
117 let s:i = g:omlet_indent_struct
118else
119 let s:i = s:idef
120endif
121
122" Set the folding method
123if exists("g:ocaml_folding")
124 setlocal foldmethod=expr
125 setlocal foldexpr=OMLetFoldLevel(v:lnum)
126endif
127
128" - Only definitions below, executed once -------------------------------------
129
130if exists("*OMLetFoldLevel")
131 finish
132endif
133
134function s:topindent(lnum)
135 let l = a:lnum
136 while l > 0
137 if getline(l) =~ '\s*\%(\<struct\>\|\<sig\>\|\<object\>\)'
138 return indent(l)
139 endif
140 let l = l-1
141 endwhile
142 return -s:i
143endfunction
144
145function OMLetFoldLevel(l)
146
147 " This is for not merging blank lines around folds to them
148 if getline(a:l) !~ '\S'
149 return -1
150 endif
151
152 " We start folds for modules, classes, and every toplevel definition
153 if getline(a:l) =~ '^\s*\%(\<val\>\|\<module\>\|\<class\>\|\<type\>\|\<method\>\|\<initializer\>\|\<inherit\>\|\<exception\>\|\<external\>\)'
154 exe 'return ">' (indent(a:l)/s:i)+1 '"'
155 endif
156
157 " Toplevel let are detected thanks to the indentation
158 if getline(a:l) =~ '^\s*let\>' && indent(a:l) == s:i+s:topindent(a:l)
159 exe 'return ">' (indent(a:l)/s:i)+1 '"'
160 endif
161
162 " We close fold on end which are associated to struct, sig or object.
163 " We use syntax information to do that.
164 if getline(a:l) =~ '^\s*end\>' && synIDattr(synID(a:l, indent(a:l)+1, 0), "name") != "ocamlKeyword"
165 return (indent(a:l)/s:i)+1
166 endif
167
168 " Folds end on ;;
169 if getline(a:l) =~ '^\s*;;'
170 exe 'return "<' (indent(a:l)/s:i)+1 '"'
171 endif
172
173 " Comments around folds aren't merged to them.
174 if synIDattr(synID(a:l, indent(a:l)+1, 0), "name") == "ocamlComment"
175 return -1
176 endif
177
178 return '='
179endfunction
180
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000181" Vim support for OCaml .annot files
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000182"
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000183" Last Change: 2007 Jul 17
184" Maintainer: Vincent Aravantinos <vincent.aravantinos@gmail.com>
185" License: public domain
186"
187" Originally inspired by 'ocaml-dtypes.vim' by Stefano Zacchiroli.
188" The source code is quite radically different for we not use python anymore.
189" However this plugin should have the exact same behaviour, that's why the
190" following lines are the quite exact copy of Stefano's original plugin :
191"
192" <<
193" Executing Ocaml_print_type(<mode>) function will display in the Vim bottom
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000194" line(s) the type of an ocaml value getting it from the corresponding .annot
195" file (if any). If Vim is in visual mode, <mode> should be "visual" and the
196" selected ocaml value correspond to the highlighted text, otherwise (<mode>
197" can be anything else) it corresponds to the literal found at the current
198" cursor position.
199"
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000200" Typing '<LocalLeader>t' (LocalLeader defaults to '\', see :h LocalLeader)
201" will cause " Ocaml_print_type function to be invoked with the right
202" argument depending on the current mode (visual or not).
203" >>
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000204"
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000205" If you find something not matching this behaviour, please signal it.
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000206"
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000207" Differences are:
208" - no need for python support
209" + plus : more portable
210" + minus: no more lazy parsing, it looks very fast however
211"
212" - ocamlbuild support, ie.
213" + the plugin finds the _build directory and looks for the
214" corresponding file inside;
215" + if the user decides to change the name of the _build directory thanks
216" to the '-build-dir' option of ocamlbuild, the plugin will manage in
217" most cases to find it out (most cases = if the source file has a unique
218" name among your whole project);
219" + if ocamlbuild is not used, the usual behaviour holds; ie. the .annot
220" file should be in the same directory as the source file;
221" + for vim plugin programmers:
222" the variable 'b:_build_dir' contains the inferred path to the build
223" directory, even if this one is not named '_build'.
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000224"
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000225" Bonus :
226" - latin1 accents are handled
227" - lists are handled, even on multiple lines, you don't need the visual mode
228" (the cursor must be on the first bracket)
229" - parenthesized expressions, arrays, and structures (ie. '(...)', '[|...|]',
230" and '{...}') are handled the same way
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000231
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000232 " Copied from Stefano's original plugin :
233 " <<
234 " .annot ocaml file representation
235 "
236 " File format (copied verbatim from caml-types.el)
237 "
238 " file ::= block *
239 " block ::= position <SP> position <LF> annotation *
240 " position ::= filename <SP> num <SP> num <SP> num
241 " annotation ::= keyword open-paren <LF> <SP> <SP> data <LF> close-paren
242 "
243 " <SP> is a space character (ASCII 0x20)
244 " <LF> is a line-feed character (ASCII 0x0A)
245 " num is a sequence of decimal digits
246 " filename is a string with the lexical conventions of O'Caml
247 " open-paren is an open parenthesis (ASCII 0x28)
248 " close-paren is a closed parenthesis (ASCII 0x29)
249 " data is any sequence of characters where <LF> is always followed by
250 " at least two space characters.
251 "
252 " - in each block, the two positions are respectively the start and the
253 " end of the range described by the block.
254 " - in a position, the filename is the name of the file, the first num
255 " is the line number, the second num is the offset of the beginning
256 " of the line, the third num is the offset of the position itself.
257 " - the char number within the line is the difference between the third
258 " and second nums.
259 "
260 " For the moment, the only possible keyword is \"type\"."
261 " >>
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000262
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000263" 1. Finding the annotation file even if we use ocamlbuild
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000264
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000265 " In: two strings representing paths
266 " Out: one string representing the common prefix between the two paths
267 function! s:Find_common_path (p1,p2)
268 let temp = a:p2
269 while matchstr(a:p1,temp) == ''
270 let temp = substitute(temp,'/[^/]*$','','')
271 endwhile
272 return temp
273 endfun
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000274
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000275 " After call:
276 " - b:annot_file_path :
277 " path to the .annot file corresponding to the
278 " source file (dealing with ocamlbuild stuff)
279 " - b:_build_path:
280 " path to the build directory even if this one is
281 " not named '_build'
282 " - b:source_file_relative_path :
283 " relative path of the source file *in* the build
284 " directory ; this is how it is reffered to in the
285 " .annot file
286 function! s:Locate_annotation()
287 if !b:annotation_file_located
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000288
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000289 silent exe 'cd' expand('%:p:h')
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000290
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000291 let annot_file_name = expand('%:r').'.annot'
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000292
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000293 " 1st case : the annot file is in the same directory as the buffer (no ocamlbuild)
294 let b:annot_file_path = findfile(annot_file_name,'.')
295 if b:annot_file_path != ''
296 let b:annot_file_path = getcwd().'/'.b:annot_file_path
297 let b:_build_path = ''
298 let b:source_file_relative_path = expand('%')
299 else
300 " 2nd case : the buffer and the _build directory are in the same directory
301 " ..
302 " / \
303 " / \
304 " _build .ml
305 "
306 let b:_build_path = finddir('_build','.')
307 if b:_build_path != ''
308 let b:_build_path = getcwd().'/'.b:_build_path
309 let b:annot_file_path = findfile(annot_file_name,'_build')
310 if b:annot_file_path != ''
311 let b:annot_file_path = getcwd().'/'.b:annot_file_path
312 endif
313 let b:source_file_relative_path = expand('%')
314 else
315 " 3rd case : the _build directory is in a directory higher in the file hierarchy
316 " (it can't be deeper by ocamlbuild requirements)
317 " ..
318 " / \
319 " / \
320 " _build ...
321 " \
322 " \
323 " .ml
324 "
325 let b:_build_path = finddir('_build',';')
326 if b:_build_path != ''
327 let project_path = substitute(b:_build_path,'/_build$','','')
328 let path_relative_to_project = substitute(expand('%:p:h'),project_path.'/','','')
329 let b:annot_file_path = findfile(annot_file_name,project_path.'/_build/'.path_relative_to_project)
330 let b:source_file_relative_path = substitute(expand('%:p'),project_path.'/','','')
331 else
332 let b:annot_file_path = findfile(annot_file_name,'**')
333 "4th case : what if the user decided to change the name of the _build directory ?
334 " -> we relax the constraints, it should work in most cases
335 if b:annot_file_path != ''
336 " 4a. we suppose the renamed _build directory is in the current directory
337 let b:_build_path = matchstr(b:annot_file_path,'^[^/]*')
338 if b:annot_file_path != ''
339 let b:annot_file_path = getcwd().'/'.b:annot_file_path
340 let b:_build_path = getcwd().'/'.b:_build_path
341 endif
342 let b:source_file_relative_path = expand('%')
343 else
344 " 4b. anarchy : the renamed _build directory may be higher in the hierarchy
345 " this will work if the file for which we are looking annotations has a unique name in the whole project
346 " if this is not the case, it may still work, but no warranty here
347 let b:annot_file_path = findfile(annot_file_name,'**;')
348 let project_path = s:Find_common_path(b:annot_file_path,expand('%:p:h'))
349 let b:_build_path = matchstr(b:annot_file_path,project_path.'/[^/]*')
350 let b:source_file_relative_path = substitute(expand('%:p'),project_path.'/','','')
351 endif
352 endif
353 endif
354 endif
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000355
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000356 if b:annot_file_path == ''
357 throw 'E484: no annotation file found'
358 endif
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000359
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000360 silent exe 'cd' '-'
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000361
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000362 let b:annotation_file_located = 1
363 endif
364 endfun
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000365
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000366 " This in order to locate the .annot file only once
367 let b:annotation_file_located = 0
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000368
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000369" 2. Finding the type information in the annotation file
370
371 " a. The annotation file is opened in vim as a buffer that
372 " should be (almost) invisible to the user.
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000373
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000374 " After call:
375 " The current buffer is now the one containing the .annot file.
376 " We manage to keep all this hidden to the user's eye.
377 function! s:Enter_annotation_buffer()
378 let s:current_pos = getpos('.')
379 let s:current_hidden = &l:hidden
380 set hidden
381 let s:current_buf = bufname('%')
382 if bufloaded(b:annot_file_path)
383 silent exe 'keepj keepalt' 'buffer' b:annot_file_path
384 else
385 silent exe 'keepj keepalt' 'view' b:annot_file_path
386 endif
387 endfun
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000388
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000389 " After call:
390 " The original buffer has been restored in the exact same state as before.
391 function! s:Exit_annotation_buffer()
392 silent exe 'keepj keepalt' 'buffer' s:current_buf
393 let &l:hidden = s:current_hidden
394 call setpos('.',s:current_pos)
395 endfun
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000396
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000397 " After call:
398 " The annot file is loaded and assigned to a buffer.
399 " This also handles the modification date of the .annot file, eg. after a
400 " compilation.
401 function! s:Load_annotation()
402 if bufloaded(b:annot_file_path) && b:annot_file_last_mod < getftime(b:annot_file_path)
403 call s:Enter_annotation_buffer()
404 silent exe "bunload"
405 call s:Exit_annotation_buffer()
406 endif
407 if !bufloaded(b:annot_file_path)
408 call s:Enter_annotation_buffer()
409 setlocal nobuflisted
410 setlocal bufhidden=hide
411 setlocal noswapfile
412 setlocal buftype=nowrite
413 call s:Exit_annotation_buffer()
414 let b:annot_file_last_mod = getftime(b:annot_file_path)
415 endif
416 endfun
417
418 "b. 'search' and 'match' work to find the type information
419
420 "In: - lin1,col1: postion of expression first char
421 " - lin2,col2: postion of expression last char
422 "Out: - the pattern to be looked for to find the block
423 " Must be called in the source buffer (use of line2byte)
424 function! s:Block_pattern(lin1,lin2,col1,col2)
425 let start_num1 = a:lin1
426 let start_num2 = line2byte(a:lin1) - 1
427 let start_num3 = start_num2 + a:col1
428 let start_pos = '"'.b:source_file_relative_path.'" '.start_num1.' '.start_num2.' '.start_num3
429 let end_num1 = a:lin2
430 let end_num2 = line2byte(a:lin2) - 1
431 let end_num3 = end_num2 + a:col2
432 let end_pos = '"'.b:source_file_relative_path.'" '.end_num1.' '.end_num2.' '.end_num3
433 return '^'.start_pos.' '.end_pos."$"
434 " rq: the '^' here is not totally correct regarding the annot file "grammar"
435 " but currently the annotation file respects this, and it's a little bit faster with the '^';
436 " can be removed safely.
437 endfun
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000438
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000439 "In: (the cursor position should be at the start of an annotation)
440 "Out: the type information
441 " Must be called in the annotation buffer (use of search)
442 function! s:Match_data()
443 " rq: idem as previously, in the following, the '^' at start of patterns is not necessary
444 keepj while search('^type($','ce',line(".")) == 0
445 keepj if search('^.\{-}($','e') == 0
446 throw "no_annotation"
447 endif
448 keepj if searchpair('(','',')') == 0
449 throw "malformed_annot_file"
450 endif
451 endwhile
452 let begin = line(".") + 1
453 keepj if searchpair('(','',')') == 0
454 throw "malformed_annot_file"
455 endif
456 let end = line(".") - 1
457 return join(getline(begin,end),"\n")
458 endfun
459
460 "In: the pattern to look for in order to match the block
461 "Out: the type information (calls s:Match_data)
462 " Should be called in the annotation buffer
463 function! s:Extract_type_data(block_pattern)
464 call s:Enter_annotation_buffer()
465 try
466 if search(a:block_pattern,'e') == 0
467 throw "no_annotation"
468 endif
469 call cursor(line(".") + 1,1)
470 let annotation = s:Match_data()
471 finally
472 call s:Exit_annotation_buffer()
473 endtry
474 return annotation
475 endfun
476
477 "c. link this stuff with what the user wants
478 " ie. get the expression selected/under the cursor
479
480 let s:ocaml_word_char = '\w|[À-ÿ]|'''
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000481
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000482 "In: the current mode (eg. "visual", "normal", etc.)
483 "Out: the borders of the expression we are looking for the type
484 function! s:Match_borders(mode)
485 if a:mode == "visual"
486 let cur = getpos(".")
487 normal `<
488 let col1 = col(".")
489 let lin1 = line(".")
490 normal `>
491 let col2 = col(".")
492 let lin2 = line(".")
493 call cursor(cur[1],cur[2])
494 return [lin1,lin2,col1-1,col2]
495 else
496 let cursor_line = line(".")
497 let cursor_col = col(".")
498 let line = getline('.')
499 if line[cursor_col-1:cursor_col] == '[|'
500 let [lin2,col2] = searchpairpos('\[|','','|\]','n')
501 return [cursor_line,lin2,cursor_col-1,col2+1]
502 elseif line[cursor_col-1] == '['
503 let [lin2,col2] = searchpairpos('\[','','\]','n')
504 return [cursor_line,lin2,cursor_col-1,col2]
505 elseif line[cursor_col-1] == '('
506 let [lin2,col2] = searchpairpos('(','',')','n')
507 return [cursor_line,lin2,cursor_col-1,col2]
508 elseif line[cursor_col-1] == '{'
509 let [lin2,col2] = searchpairpos('{','','}','n')
510 return [cursor_line,lin2,cursor_col-1,col2]
511 else
512 let [lin1,col1] = searchpos('\v%('.s:ocaml_word_char.'|\.)*','ncb')
513 let [lin2,col2] = searchpos('\v%('.s:ocaml_word_char.'|\.)*','nce')
514 if col1 == 0 || col2 == 0
515 throw "no_expression"
516 endif
517 return [cursor_line,cursor_line,col1-1,col2]
518 endif
519 endif
520 endfun
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000521
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000522 "In: the current mode (eg. "visual", "normal", etc.)
523 "Out: the type information (calls s:Extract_type_data)
524 function! s:Get_type(mode)
525 let [lin1,lin2,col1,col2] = s:Match_borders(a:mode)
526 return s:Extract_type_data(s:Block_pattern(lin1,lin2,col1,col2))
527 endfun
528
529 "d. main
530 "In: the current mode (eg. "visual", "normal", etc.)
531 "After call: the type information is displayed
532 if !exists("*Ocaml_get_type")
533 function Ocaml_get_type(mode)
534 call s:Locate_annotation()
535 call s:Load_annotation()
536 return s:Get_type(a:mode)
537 endfun
538 endif
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000539
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000540 if !exists("*Ocaml_get_type_or_not")
541 function Ocaml_get_type_or_not(mode)
542 let t=reltime()
543 try
544 return Ocaml_get_type(a:mode)
545 catch
546 return ""
547 endtry
548 endfun
549 endif
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000550
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000551 if !exists("*Ocaml_print_type")
552 function Ocaml_print_type(mode)
553 if expand("%:e") == "mli"
554 echohl ErrorMsg | echo "No annotations for interface (.mli) files" | echohl None
555 return
556 endif
557 try
558 echo Ocaml_get_type(a:mode)
559 catch /E484:/
560 echohl ErrorMsg | echo "No type annotations (.annot) file found" | echohl None
561 catch /no_expression/
562 echohl ErrorMsg | echo "No expression found under the cursor" | echohl None
563 catch /no_annotation/
564 echohl ErrorMsg | echo "No type annotation found for the given text" | echohl None
565 catch /malformed_annot_file/
566 echohl ErrorMsg | echo "Malformed .annot file" | echohl None
567 endtry
568 endfun
569 endif
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000570
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000571" Maps
572 map <silent> <LocalLeader>t :call Ocaml_print_type("normal")<CR>
573 vmap <silent> <LocalLeader>t :<C-U>call Ocaml_print_type("visual")<CR>`<
Bram Moolenaara5792f52005-11-23 21:25:05 +0000574
575let &cpoptions=s:cposet
576unlet s:cposet
577
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000578" vim:sw=2 fdm=indent