├── .gitignore ├── README.md ├── compiler └── ocaml.vim ├── doc ├── ocaml.txt └── opam.txt ├── ftdetect ├── dune.vim ├── oasis.vim ├── ocaml.vim ├── ocamlbuild_tags.vim ├── ocpbuild.vim ├── ocpbuildroot.vim ├── omake.vim ├── opam.vim └── sexplib.vim ├── ftplugin ├── dune.vim ├── oasis.vim ├── ocaml.vim ├── ocamlbuild_tags.vim ├── omake.vim └── sexplib.vim ├── indent ├── dune.vim ├── ocaml.vim └── omake.vim ├── plugin └── opam.vim ├── syntax-testcases ├── exception_alias.ml ├── functor1.ml ├── functor2.ml ├── functor3.mli ├── functor_param.ml ├── module_paren1.ml ├── module_paren2.ml ├── module_type.ml ├── module_type_of.mli ├── module_underscore.ml ├── module_with_signature.ml ├── poly_variant_in_type.ml └── type-linter-test.ml ├── syntax ├── dune.vim ├── oasis.vim ├── ocaml.vim ├── ocamlbuild_tags.vim ├── ocpbuild.vim ├── ocpbuildroot.vim ├── omake.vim ├── opam.vim └── sexplib.vim └── type-linter-notes.md /.gitignore: -------------------------------------------------------------------------------- 1 | /doc/tags 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-ocaml 2 | 3 | Vim runtime files for OCaml. These are synced periodically with the builtin 4 | support that comes with Vim. Users are recommended to use this repository 5 | directly however as it's more up to date. 6 | 7 | ## Installation 8 | 9 | Depending on your plugin manager: 10 | 11 | ```vim 12 | Plugin 'ocaml/vim-ocaml' 13 | ``` 14 | 15 | ```vim 16 | NeoBundleInstall ocaml/vim-ocaml' 17 | 18 | " or use NeoBundleLazy 19 | NeoBundleLazy 'rgrinberg/vim-ocaml', {'autoload' : {'filetypes' : 20 | \ ['ocaml', 'dune', 'opam', 'oasis', 'omake', 'ocamlbuild_tags', 'sexplib']}} 21 | ``` 22 | 23 | ## History 24 | 25 | This repo started out by @rgrinberg extracting Markus Mottl's improvements to 26 | the builtin OCaml support in Vim. Later, support for more OCaml related tools 27 | was added: dune, opam etc. Nowadays, it's maintained by a team. 28 | -------------------------------------------------------------------------------- /compiler/ocaml.vim: -------------------------------------------------------------------------------- 1 | " Vim Compiler File 2 | " Compiler: ocaml 3 | " Maintainer: Markus Mottl 4 | " URL: https://github.com/ocaml/vim-ocaml 5 | " Last Change: 6 | " 2023 Nov 24 - Improved error format (Samuel Hym) 7 | " 2021 Nov 03 - Improved error format (Jules Aguillon) 8 | " 2020 Mar 28 - Improved error format (Thomas Leonard) 9 | " 2017 Nov 26 - Improved error format (Markus Mottl) 10 | " 2013 Aug 27 - Added a new OCaml error format (Markus Mottl) 11 | " 12 | " Marc Weber's comments: 13 | " Setting makeprg doesn't make sense, because there is ocamlc, ocamlopt, 14 | " ocamake and whatnot. So which one to use? 15 | 16 | if exists("current_compiler") 17 | finish 18 | endif 19 | let current_compiler = "ocaml" 20 | 21 | let s:cpo_save = &cpo 22 | set cpo&vim 23 | 24 | " Patch 8.2.4329 introduces %e and %k as end line and end column positions 25 | 26 | if has('patch-8.2.4329') 27 | CompilerSet errorformat = 28 | \%EFile\ \"%f\"\\,\ lines\ %l-%e\\,\ characters\ %c-%k:, 29 | \%EFile\ \"%f\"\\,\ line\ %l\\,\ characters\ %c-%k:, 30 | \%EFile\ \"%f\"\\,\ line\ %l\\,\ characters\ %c-%k\ %.%#, 31 | else 32 | CompilerSet errorformat = 33 | \%EFile\ \"%f\"\\,\ lines\ %l-%*\\d\\,\ characters\ %c-%*\\d:, 34 | \%EFile\ \"%f\"\\,\ line\ %l\\,\ characters\ %c-%*\\d:, 35 | \%EFile\ \"%f\"\\,\ line\ %l\\,\ characters\ %c-%*\\d\ %.%#, 36 | endif 37 | 38 | CompilerSet errorformat += 39 | \%EFile\ \"%f\"\\,\ line\ %l\\,\ character\ %c:%m, 40 | \%EFile\ \"%f\"\\,\ line\ %l:, 41 | \%+EReference\ to\ unbound\ regexp\ name\ %m, 42 | \%Eocamlyacc:\ e\ -\ line\ %l\ of\ \"%f\"\\,\ %m, 43 | \%Wocamlyacc:\ w\ -\ %m, 44 | \%-Zmake%.%# 45 | 46 | if get(g:, "ocaml_compiler_compact_messages", v:true) 47 | CompilerSet errorformat += 48 | \%C%*\\d\ \|%.%#, 49 | \%C%p^%#, 50 | \%C%m 51 | endif 52 | 53 | CompilerSet errorformat += 54 | \%Z, 55 | \%D%*\\a[%*\\d]:\ Entering\ directory\ `%f', 56 | \%X%*\\a[%*\\d]:\ Leaving\ directory\ `%f', 57 | \%D%*\\a:\ Entering\ directory\ `%f', 58 | \%X%*\\a:\ Leaving\ directory\ `%f', 59 | \%D%*\\a[%*\\d]:\ Entering\ directory\ '%f', 60 | \%X%*\\a[%*\\d]:\ Leaving\ directory\ '%f', 61 | \%D%*\\a:\ Entering\ directory\ '%f', 62 | \%X%*\\a:\ Leaving\ directory\ '%f', 63 | \%DEntering\ directory\ '%f', 64 | \%XLeaving\ directory\ '%f', 65 | \%DMaking\ %*\\a\ in\ %f 66 | 67 | if get(g:, "ocaml_compiler_compact_messages", v:true) 68 | CompilerSet errorformat += 69 | \%+G%m 70 | endif 71 | 72 | 73 | let &cpo = s:cpo_save 74 | unlet s:cpo_save 75 | -------------------------------------------------------------------------------- /doc/ocaml.txt: -------------------------------------------------------------------------------- 1 | *ocaml.txt* Filetype plugin for OCaml 2 | 3 | CONFIGURATION *ocaml-configuration* 4 | 5 | *g:ocaml_highlight_operators* 6 | 7 | By default operators are not linked to the Operator group and thus not 8 | highlighted. You can turn on highlighting of operators by defining: 9 | 10 | let g:ocaml_highlight_operators = 1 11 | 12 | *g:ocaml_compiler_compact_messages* 13 | 14 | By default the output of the OCaml compiler is filtered to keep only the 15 | location and message by the compiler plugin. You can keep the full multi-line 16 | messages as displayed by the compiler by defining: 17 | 18 | let g:ocaml_compiler_compact_messages = 0 19 | 20 | vim:tw=78:et:ft=help:norl: 21 | -------------------------------------------------------------------------------- /doc/opam.txt: -------------------------------------------------------------------------------- 1 | *opam.txt* Switch OCaml versions from inside Vim using opam 2 | 3 | Author: Rudi Grinberg 4 | License: Same terms as Vim itself (see |license|) 5 | 6 | This plugin is only available if 'compatible' is not set. 7 | 8 | COMMANDS *:opam* 9 | 10 | :Opam With no argument. Refresh the environment using |opam env|. 11 | 12 | :Opam {version} Set the current switch to {version}. 13 | 14 | CONFIGURATION *opam-configuration* 15 | 16 | *g:opam_set_switch* 17 | 18 | If this variable is set to a non-zero value, |:Opam| will set the |$OPAMSWITCH| 19 | environment variable. This variable will make sure that every |opam| commands 20 | run from inside Vim will continue to act on the same switch even if the 21 | selected switch is changed. 22 | This also mean that selecting a different switch without using the |:Opam| 23 | command will not take effect in this instance of Vim. 24 | Defaults to |0|. 25 | 26 | let g:opam_set_switch = 1 27 | 28 | *g:opam_init_env* 29 | 30 | If this variable is set to a non-zero value, Opam's environment will be 31 | refreshed when the plugin is loaded for the first time. 32 | This is equivalent to calling |:Opam| when first opening an OCaml file. 33 | 34 | let g:opam_init_env = 1 35 | 36 | ABOUT *opam-about* 37 | 38 | Grab the latest version or report a bug on GitHub: 39 | 40 | https://github.com/ocaml/vim-ocaml 41 | 42 | vim:tw=78:et:ft=help:norl: 43 | -------------------------------------------------------------------------------- /ftdetect/dune.vim: -------------------------------------------------------------------------------- 1 | au BufNewFile,BufRead jbuild,dune,dune-project,dune-workspace,dune-file setf dune 2 | -------------------------------------------------------------------------------- /ftdetect/oasis.vim: -------------------------------------------------------------------------------- 1 | au BufNewFile,BufRead _oasis setf oasis 2 | -------------------------------------------------------------------------------- /ftdetect/ocaml.vim: -------------------------------------------------------------------------------- 1 | au BufNewFile,BufRead *.ml,*.mli,*.mll,*.mly,.ocamlinit,*.mlt,*.mlp,*.mlip,*.mli.cppo,*.ml.cppo setf ocaml 2 | -------------------------------------------------------------------------------- /ftdetect/ocamlbuild_tags.vim: -------------------------------------------------------------------------------- 1 | au BufNewFile,BufRead _tags setf ocamlbuild_tags 2 | -------------------------------------------------------------------------------- /ftdetect/ocpbuild.vim: -------------------------------------------------------------------------------- 1 | au BufNewFile,BufRead *.ocp setf ocpbuild 2 | -------------------------------------------------------------------------------- /ftdetect/ocpbuildroot.vim: -------------------------------------------------------------------------------- 1 | au BufNewFile,BufRead *.root setf ocpbuildroot 2 | -------------------------------------------------------------------------------- /ftdetect/omake.vim: -------------------------------------------------------------------------------- 1 | au! BufNewFile,BufRead OMakefile,OMakeroot,*.om,OMakeroot.in setf omake 2 | -------------------------------------------------------------------------------- /ftdetect/opam.vim: -------------------------------------------------------------------------------- 1 | au BufNewFile,BufRead opam,*.opam,*.opam.template,opam.locked,*.opam.locked setf opam 2 | -------------------------------------------------------------------------------- /ftdetect/sexplib.vim: -------------------------------------------------------------------------------- 1 | au BufNewFile,BufRead *.sexp setf sexplib 2 | -------------------------------------------------------------------------------- /ftplugin/dune.vim: -------------------------------------------------------------------------------- 1 | " Language: Dune buildsystem 2 | " Maintainer: Markus Mottl 3 | " Anton Kochkov 4 | " URL: https://github.com/ocaml/vim-ocaml 5 | " Last Change: 6 | " 2018 Nov 3 - Added commentstring (Markus Mottl) 7 | " 2017 Sep 6 - Initial version (Etienne Millon) 8 | 9 | if exists("b:did_ftplugin") 10 | finish 11 | endif 12 | let b:did_ftplugin=1 13 | 14 | setl lisp 15 | 16 | " Comment string 17 | setl commentstring=;\ %s 18 | setl comments=n:; 19 | 20 | setl iskeyword+=#,?,.,/ 21 | 22 | let b:undo_ftplugin = "setlocal lisp< cms< com< isk<" 23 | -------------------------------------------------------------------------------- /ftplugin/oasis.vim: -------------------------------------------------------------------------------- 1 | if exists("b:did_ftplugin") 2 | finish 3 | endif 4 | let b:did_ftplugin=1 5 | 6 | setlocal comments=:# 7 | setlocal commentstring=#\ %s 8 | 9 | let b:undo_ftplugin = "com< cms<" 10 | -------------------------------------------------------------------------------- /ftplugin/ocaml.vim: -------------------------------------------------------------------------------- 1 | " Language: OCaml 2 | " Maintainer: David Baelde 3 | " Mike Leary 4 | " Markus Mottl 5 | " Pierre Vittet 6 | " Stefano Zacchiroli 7 | " Vincent Aravantinos 8 | " URL: https://github.com/ocaml/vim-ocaml 9 | " Last Change: 10 | " 2013 Oct 27 - Added commentstring (MM) 11 | " 2013 Jul 26 - load default compiler settings (MM) 12 | " 2013 Jul 24 - removed superfluous efm-setting (MM) 13 | " 2013 Jul 22 - applied fixes supplied by Hirotaka Hamada (MM) 14 | 15 | if exists("b:did_ftplugin") 16 | finish 17 | endif 18 | let b:did_ftplugin=1 19 | 20 | " Use standard compiler settings unless user wants otherwise 21 | if !exists("current_compiler") 22 | :compiler ocaml 23 | endif 24 | 25 | " some macro 26 | if exists('*fnameescape') 27 | function! s:Fnameescape(s) 28 | return fnameescape(a:s) 29 | endfun 30 | else 31 | function! s:Fnameescape(s) 32 | return escape(a:s," \t\n*?[{`$\\%#'\"|!<") 33 | endfun 34 | endif 35 | 36 | " Error handling -- helps moving where the compiler wants you to go 37 | let s:cposet=&cpoptions 38 | set cpo&vim 39 | 40 | " Comment string 41 | setlocal comments=sr:(*\ ,mb:\ ,ex:*) 42 | setlocal comments^=sr:(**,mb:\ \ ,ex:*) 43 | setlocal commentstring=(*%s*) 44 | 45 | let b:undo_ftplugin = "setlocal com< cms<" 46 | 47 | " Add mappings, unless the user didn't want this. 48 | if !exists("no_plugin_maps") && !exists("no_ocaml_maps") 49 | " (un)commenting 50 | if !hasmapto('Comment') 51 | nmap c LUncomOn 52 | xmap c BUncomOn 53 | nmap C LUncomOff 54 | xmap C BUncomOff 55 | let b:undo_ftplugin .= 56 | \ " | silent! execute 'nunmap c'" . 57 | \ " | silent! execute 'xunmap c'" . 58 | \ " | silent! execute 'nunmap C'" . 59 | \ " | silent! execute 'xunmap C'" 60 | endif 61 | 62 | nnoremap LUncomOn gI(* *) 63 | nnoremap LUncomOff :s/^(\* \(.*\) \*)/\1/:noh 64 | xnoremap BUncomOn :'<,'>`0i(*`>o0i*)`< 65 | xnoremap BUncomOff :'<,'>`dd`< 66 | 67 | nmap s OCamlSwitchEdit 68 | nmap S OCamlSwitchNewWin 69 | 70 | nmap t OCamlPrintType 71 | xmap t OCamlPrintType 72 | 73 | let b:undo_ftplugin .= 74 | \ " | silent! execute 'nunmap s'" . 75 | \ " | silent! execute 'nunmap S'" . 76 | \ " | silent! execute 'nunmap t'" . 77 | \ " | silent! execute 'xunmap t'" 78 | endif 79 | 80 | if exists("loaded_matchit") && !exists("b:match_words") 81 | " Let % jump between structure elements (due to Issac Trotts) 82 | let b:mw = '\:\:\(\\|;;\)' 83 | let b:mw = b:mw . ',\:\:\' 84 | let b:mw = b:mw . ',\<\(for\|while\)\>:\:\' 85 | let b:mw = b:mw . ',\<\(object\|sig\|struct\|begin\)\>:\' 86 | let b:mw = b:mw . ',\<\(match\|try\)\>:\' 87 | let b:match_words = b:mw 88 | 89 | let b:match_ignorecase=0 90 | 91 | let b:undo_ftplugin .= " | unlet! b:match_ignorecase b:match_words" 92 | endif 93 | 94 | function! s:OcpGrep(bang,args) abort 95 | let grepprg = &l:grepprg 96 | let grepformat = &l:grepformat 97 | let shellpipe = &shellpipe 98 | try 99 | let &l:grepprg = "ocp-grep -c never" 100 | setlocal grepformat=%f:%l:%m 101 | if &shellpipe ==# '2>&1| tee' || &shellpipe ==# '|& tee' 102 | let &shellpipe = "| tee" 103 | endif 104 | execute 'grep! '.a:args 105 | if empty(a:bang) && !empty(getqflist()) 106 | return 'cfirst' 107 | else 108 | return '' 109 | endif 110 | finally 111 | let &l:grepprg = grepprg 112 | let &l:grepformat = grepformat 113 | let &shellpipe = shellpipe 114 | endtry 115 | endfunction 116 | command! -bar -bang -complete=file -nargs=+ Ocpgrep exe s:OcpGrep(, ) 117 | 118 | " switching between interfaces (.mli) and implementations (.ml) 119 | if !exists("g:did_ocaml_switch") 120 | let g:did_ocaml_switch = 1 121 | nnoremap OCamlSwitchEdit :call OCaml_switch(0) 122 | nnoremap OCamlSwitchNewWin :call OCaml_switch(1) 123 | fun OCaml_switch(newwin) 124 | let open_command = a:newwin == 1 ? "new" : "arge" 125 | if (match(bufname(""), "\\.mli$") >= 0) 126 | let fname = s:Fnameescape(substitute(bufname(""), "\\.mli$", ".ml", "")) 127 | elseif (match(bufname(""), "\\.ml$") >= 0) 128 | let fname = s:Fnameescape(bufname("")) . "i" 129 | endif 130 | exec open_command " " . fname 131 | endfun 132 | endif 133 | 134 | " Folding support 135 | 136 | " Get the modeline because folding depends on indentation 137 | let lnum = search('^\s*(\*:o\?caml:', 'n') 138 | let s:modeline = lnum? getline(lnum): "" 139 | 140 | " Get the indentation params 141 | let s:m = matchstr(s:modeline,'default\s*=\s*\d\+') 142 | if s:m != "" 143 | let s:idef = matchstr(s:m,'\d\+') 144 | elseif exists("g:omlet_indent") 145 | let s:idef = g:omlet_indent 146 | else 147 | let s:idef = 2 148 | endif 149 | let s:m = matchstr(s:modeline,'struct\s*=\s*\d\+') 150 | if s:m != "" 151 | let s:i = matchstr(s:m,'\d\+') 152 | elseif exists("g:omlet_indent_struct") 153 | let s:i = g:omlet_indent_struct 154 | else 155 | let s:i = s:idef 156 | endif 157 | 158 | " Set the folding method 159 | if exists("g:ocaml_folding") 160 | setlocal foldmethod=expr 161 | setlocal foldexpr=OMLetFoldLevel(v:lnum) 162 | let b:undo_ftplugin .= " | setlocal fdm< fde<" 163 | endif 164 | 165 | " - Only definitions below, executed once ------------------------------------- 166 | 167 | if exists("*OMLetFoldLevel") 168 | finish 169 | endif 170 | 171 | function s:topindent(lnum) 172 | let l = a:lnum 173 | while l > 0 174 | if getline(l) =~ '\s*\%(\\|\\|\\)' 175 | return indent(l) 176 | endif 177 | let l = l-1 178 | endwhile 179 | return -s:i 180 | endfunction 181 | 182 | function OMLetFoldLevel(l) 183 | 184 | " This is for not merging blank lines around folds to them 185 | if getline(a:l) !~ '\S' 186 | return -1 187 | endif 188 | 189 | " We start folds for modules, classes, and every toplevel definition 190 | if getline(a:l) =~ '^\s*\%(\\|\\|\\|\\|\\|\\|\\|\\|\\)' 191 | exe 'return ">' (indent(a:l)/s:i)+1 '"' 192 | endif 193 | 194 | " Toplevel let are detected thanks to the indentation 195 | if getline(a:l) =~ '^\s*let\>' && indent(a:l) == s:i+s:topindent(a:l) 196 | exe 'return ">' (indent(a:l)/s:i)+1 '"' 197 | endif 198 | 199 | " We close fold on end which are associated to struct, sig or object. 200 | " We use syntax information to do that. 201 | if getline(a:l) =~ '^\s*end\>' && synIDattr(synID(a:l, indent(a:l)+1, 0), "name") != "ocamlKeyword" 202 | return (indent(a:l)/s:i)+1 203 | endif 204 | 205 | " Folds end on ;; 206 | if getline(a:l) =~ '^\s*;;' 207 | exe 'return "<' (indent(a:l)/s:i)+1 '"' 208 | endif 209 | 210 | " Comments around folds aren't merged to them. 211 | if synIDattr(synID(a:l, indent(a:l)+1, 0), "name") == "ocamlComment" 212 | return -1 213 | endif 214 | 215 | return '=' 216 | endfunction 217 | 218 | " Vim support for OCaml .annot files 219 | " 220 | " Last Change: 2007 Jul 17 221 | " Maintainer: Vincent Aravantinos 222 | " License: public domain 223 | " 224 | " Originally inspired by 'ocaml-dtypes.vim' by Stefano Zacchiroli. 225 | " The source code is quite radically different for we not use python anymore. 226 | " However this plugin should have the exact same behaviour, that's why the 227 | " following lines are the quite exact copy of Stefano's original plugin : 228 | " 229 | " << 230 | " Executing Ocaml_print_type() function will display in the Vim bottom 231 | " line(s) the type of an ocaml value getting it from the corresponding .annot 232 | " file (if any). If Vim is in visual mode, should be "visual" and the 233 | " selected ocaml value correspond to the highlighted text, otherwise ( 234 | " can be anything else) it corresponds to the literal found at the current 235 | " cursor position. 236 | " 237 | " Typing 't' (LocalLeader defaults to '\', see :h LocalLeader) 238 | " will cause " Ocaml_print_type function to be invoked with the right 239 | " argument depending on the current mode (visual or not). 240 | " >> 241 | " 242 | " If you find something not matching this behaviour, please signal it. 243 | " 244 | " Differences are: 245 | " - no need for python support 246 | " + plus : more portable 247 | " + minus: no more lazy parsing, it looks very fast however 248 | " 249 | " - ocamlbuild support, ie. 250 | " + the plugin finds the _build directory and looks for the 251 | " corresponding file inside; 252 | " + if the user decides to change the name of the _build directory thanks 253 | " to the '-build-dir' option of ocamlbuild, the plugin will manage in 254 | " most cases to find it out (most cases = if the source file has a unique 255 | " name among your whole project); 256 | " + if ocamlbuild is not used, the usual behaviour holds; ie. the .annot 257 | " file should be in the same directory as the source file; 258 | " + for vim plugin programmers: 259 | " the variable 'b:_build_dir' contains the inferred path to the build 260 | " directory, even if this one is not named '_build'. 261 | " 262 | " Bonus : 263 | " - latin1 accents are handled 264 | " - lists are handled, even on multiple lines, you don't need the visual mode 265 | " (the cursor must be on the first bracket) 266 | " - parenthesized expressions, arrays, and structures (ie. '(...)', '[|...|]', 267 | " and '{...}') are handled the same way 268 | 269 | " Copied from Stefano's original plugin : 270 | " << 271 | " .annot ocaml file representation 272 | " 273 | " File format (copied verbatim from caml-types.el) 274 | " 275 | " file ::= block * 276 | " block ::= position position annotation * 277 | " position ::= filename num num num 278 | " annotation ::= keyword open-paren data close-paren 279 | " 280 | " is a space character (ASCII 0x20) 281 | " is a line-feed character (ASCII 0x0A) 282 | " num is a sequence of decimal digits 283 | " filename is a string with the lexical conventions of O'Caml 284 | " open-paren is an open parenthesis (ASCII 0x28) 285 | " close-paren is a closed parenthesis (ASCII 0x29) 286 | " data is any sequence of characters where is always followed by 287 | " at least two space characters. 288 | " 289 | " - in each block, the two positions are respectively the start and the 290 | " end of the range described by the block. 291 | " - in a position, the filename is the name of the file, the first num 292 | " is the line number, the second num is the offset of the beginning 293 | " of the line, the third num is the offset of the position itself. 294 | " - the char number within the line is the difference between the third 295 | " and second nums. 296 | " 297 | " For the moment, the only possible keyword is \"type\"." 298 | " >> 299 | 300 | 301 | " 1. Finding the annotation file even if we use ocamlbuild 302 | 303 | " In: two strings representing paths 304 | " Out: one string representing the common prefix between the two paths 305 | function! s:Find_common_path (p1,p2) 306 | let temp = a:p2 307 | while matchstr(a:p1,temp) == '' 308 | let temp = substitute(temp,'/[^/]*$','','') 309 | endwhile 310 | return temp 311 | endfun 312 | 313 | " After call: 314 | " 315 | " Following information have been put in s:annot_file_list, using 316 | " annot_file_name name as key: 317 | " - annot_file_path : 318 | " path to the .annot file corresponding to the 319 | " source file (dealing with ocamlbuild stuff) 320 | " - _build_path: 321 | " path to the build directory even if this one is 322 | " not named '_build' 323 | " - date_of_last annot: 324 | " Set to 0 until we load the file. It contains the 325 | " date at which the file has been loaded. 326 | function! s:Locate_annotation() 327 | let annot_file_name = s:Fnameescape(expand('%:t:r')).'.annot' 328 | if !exists ("s:annot_file_list[annot_file_name]") 329 | silent exe 'cd' s:Fnameescape(expand('%:p:h')) 330 | " 1st case : the annot file is in the same directory as the buffer (no ocamlbuild) 331 | let annot_file_path = findfile(annot_file_name,'.') 332 | if annot_file_path != '' 333 | let annot_file_path = getcwd().'/'.annot_file_path 334 | let _build_path = '' 335 | else 336 | " 2nd case : the buffer and the _build directory are in the same directory 337 | " .. 338 | " / \ 339 | " / \ 340 | " _build .ml 341 | " 342 | let _build_path = finddir('_build','.') 343 | if _build_path != '' 344 | let _build_path = getcwd().'/'._build_path 345 | let annot_file_path = findfile(annot_file_name,'_build') 346 | if annot_file_path != '' 347 | let annot_file_path = getcwd().'/'.annot_file_path 348 | endif 349 | else 350 | " 3rd case : the _build directory is in a directory higher in the file hierarchy 351 | " (it can't be deeper by ocamlbuild requirements) 352 | " .. 353 | " / \ 354 | " / \ 355 | " _build ... 356 | " \ 357 | " \ 358 | " .ml 359 | " 360 | let _build_path = finddir('_build',';') 361 | if _build_path != '' 362 | let project_path = substitute(_build_path,'/_build$','','') 363 | let path_relative_to_project = s:Fnameescape(substitute(expand('%:p:h'),project_path.'/','','')) 364 | let annot_file_path = findfile(annot_file_name,project_path.'/_build/'.path_relative_to_project) 365 | else 366 | let annot_file_path = findfile(annot_file_name,'**') 367 | "4th case : what if the user decided to change the name of the _build directory ? 368 | " -> we relax the constraints, it should work in most cases 369 | if annot_file_path != '' 370 | " 4a. we suppose the renamed _build directory is in the current directory 371 | let _build_path = matchstr(annot_file_path,'^[^/]*') 372 | if annot_file_path != '' 373 | let annot_file_path = getcwd().'/'.annot_file_path 374 | let _build_path = getcwd().'/'._build_path 375 | endif 376 | else 377 | let annot_file_name = '' 378 | "(Pierre Vittet: I have commented 4b because this was crashing 379 | "my vim (it produced infinite loop)) 380 | " 381 | " 4b. anarchy : the renamed _build directory may be higher in the hierarchy 382 | " this will work if the file for which we are looking annotations has a unique name in the whole project 383 | " if this is not the case, it may still work, but no warranty here 384 | "let annot_file_path = findfile(annot_file_name,'**;') 385 | "let project_path = s:Find_common_path(annot_file_path,expand('%:p:h')) 386 | "let _build_path = matchstr(annot_file_path,project_path.'/[^/]*') 387 | endif 388 | endif 389 | endif 390 | endif 391 | 392 | if annot_file_path == '' 393 | throw 'E484: no annotation file found' 394 | endif 395 | 396 | silent exe 'cd' '-' 397 | let s:annot_file_list[annot_file_name]= [annot_file_path, _build_path, 0] 398 | endif 399 | endfun 400 | 401 | " This variable contains a dictionary of lists. Each element of the dictionary 402 | " represents an annotation system. An annotation system is a list with: 403 | " - annotation file name as its key 404 | " - annotation file path as first element of the contained list 405 | " - build path as second element of the contained list 406 | " - annot_file_last_mod (contain the date of .annot file) as third element 407 | let s:annot_file_list = {} 408 | 409 | " 2. Finding the type information in the annotation file 410 | 411 | " a. The annotation file is opened in vim as a buffer that 412 | " should be (almost) invisible to the user. 413 | 414 | " After call: 415 | " The current buffer is now the one containing the .annot file. 416 | " We manage to keep all this hidden to the user's eye. 417 | function! s:Enter_annotation_buffer(annot_file_path) 418 | let s:current_pos = getpos('.') 419 | let s:current_hidden = &l:hidden 420 | set hidden 421 | let s:current_buf = bufname('%') 422 | if bufloaded(a:annot_file_path) 423 | silent exe 'keepj keepalt' 'buffer' s:Fnameescape(a:annot_file_path) 424 | else 425 | silent exe 'keepj keepalt' 'view' s:Fnameescape(a:annot_file_path) 426 | endif 427 | call setpos(".", [0, 0 , 0 , 0]) 428 | endfun 429 | 430 | " After call: 431 | " The original buffer has been restored in the exact same state as before. 432 | function! s:Exit_annotation_buffer() 433 | silent exe 'keepj keepalt' 'buffer' s:Fnameescape(s:current_buf) 434 | let &l:hidden = s:current_hidden 435 | call setpos('.',s:current_pos) 436 | endfun 437 | 438 | " After call: 439 | " The annot file is loaded and assigned to a buffer. 440 | " This also handles the modification date of the .annot file, eg. after a 441 | " compilation (return an updated annot_file_list). 442 | function! s:Load_annotation(annot_file_name) 443 | let annot = s:annot_file_list[a:annot_file_name] 444 | let annot_file_path = annot[0] 445 | let annot_file_last_mod = 0 446 | if exists("annot[2]") 447 | let annot_file_last_mod = annot[2] 448 | endif 449 | if bufloaded(annot_file_path) && annot_file_last_mod < getftime(annot_file_path) 450 | " if there is a more recent file 451 | let nr = bufnr(annot_file_path) 452 | silent exe 'keepj keepalt' 'bunload' nr 453 | endif 454 | if !bufloaded(annot_file_path) 455 | call s:Enter_annotation_buffer(annot_file_path) 456 | setlocal nobuflisted 457 | setlocal bufhidden=hide 458 | setlocal noswapfile 459 | setlocal buftype=nowrite 460 | call s:Exit_annotation_buffer() 461 | let annot[2] = getftime(annot_file_path) 462 | " List updated with the new date 463 | let s:annot_file_list[a:annot_file_name] = annot 464 | endif 465 | endfun 466 | 467 | "b. 'search' and 'match' work to find the type information 468 | 469 | "In: - lin1,col1: position of expression first char 470 | " - lin2,col2: position of expression last char 471 | "Out: - the pattern to be looked for to find the block 472 | " Must be called in the source buffer (use of line2byte) 473 | function! s:Block_pattern(lin1,lin2,col1,col2) 474 | let start_num1 = a:lin1 475 | let start_num2 = line2byte(a:lin1) - 1 476 | let start_num3 = start_num2 + a:col1 477 | let path = '"\(\\"\|[^"]\)\+"' 478 | let start_pos = path.' '.start_num1.' '.start_num2.' '.start_num3 479 | let end_num1 = a:lin2 480 | let end_num2 = line2byte(a:lin2) - 1 481 | let end_num3 = end_num2 + a:col2 482 | let end_pos = path.' '.end_num1.' '.end_num2.' '.end_num3 483 | return '^'.start_pos.' '.end_pos."$" 484 | " rq: the '^' here is not totally correct regarding the annot file "grammar" 485 | " but currently the annotation file respects this, and it's a little bit faster with the '^'; 486 | " can be removed safely. 487 | endfun 488 | 489 | "In: (the cursor position should be at the start of an annotation) 490 | "Out: the type information 491 | " Must be called in the annotation buffer (use of search) 492 | function! s:Match_data() 493 | " rq: idem as previously, in the following, the '^' at start of patterns is not necessary 494 | keepj while search('^type($','ce',line(".")) == 0 495 | keepj if search('^.\{-}($','e') == 0 496 | throw "no_annotation" 497 | endif 498 | keepj if searchpair('(','',')') == 0 499 | throw "malformed_annot_file" 500 | endif 501 | endwhile 502 | let begin = line(".") + 1 503 | keepj if searchpair('(','',')') == 0 504 | throw "malformed_annot_file" 505 | endif 506 | let end = line(".") - 1 507 | return join(getline(begin,end),"\n") 508 | endfun 509 | 510 | "In: the pattern to look for in order to match the block 511 | "Out: the type information (calls s:Match_data) 512 | " Should be called in the annotation buffer 513 | function! s:Extract_type_data(block_pattern, annot_file_name) 514 | let annot_file_path = s:annot_file_list[a:annot_file_name][0] 515 | call s:Enter_annotation_buffer(annot_file_path) 516 | try 517 | if search(a:block_pattern,'e') == 0 518 | throw "no_annotation" 519 | endif 520 | call cursor(line(".") + 1,1) 521 | let annotation = s:Match_data() 522 | finally 523 | call s:Exit_annotation_buffer() 524 | endtry 525 | return annotation 526 | endfun 527 | 528 | "c. link this stuff with what the user wants 529 | " ie. get the expression selected/under the cursor 530 | 531 | let s:ocaml_word_char = '\w|[\xc0-\xff]|''' 532 | 533 | "In: the current mode (eg. "visual", "normal", etc.) 534 | "Out: the borders of the expression we are looking for the type 535 | function! s:Match_borders(mode) 536 | if a:mode == "visual" 537 | let cur = getpos(".") 538 | normal `< 539 | let col1 = col(".") 540 | let lin1 = line(".") 541 | normal `> 542 | let col2 = col(".") 543 | let lin2 = line(".") 544 | call cursor(cur[1],cur[2]) 545 | return [lin1,lin2,col1-1,col2] 546 | else 547 | let cursor_line = line(".") 548 | let cursor_col = col(".") 549 | let line = getline('.') 550 | if line[cursor_col-1:cursor_col] == '[|' 551 | let [lin2,col2] = searchpairpos('\[|','','|\]','n') 552 | return [cursor_line,lin2,cursor_col-1,col2+1] 553 | elseif line[cursor_col-1] == '[' 554 | let [lin2,col2] = searchpairpos('\[','','\]','n') 555 | return [cursor_line,lin2,cursor_col-1,col2] 556 | elseif line[cursor_col-1] == '(' 557 | let [lin2,col2] = searchpairpos('(','',')','n') 558 | return [cursor_line,lin2,cursor_col-1,col2] 559 | elseif line[cursor_col-1] == '{' 560 | let [lin2,col2] = searchpairpos('{','','}','n') 561 | return [cursor_line,lin2,cursor_col-1,col2] 562 | else 563 | let [lin1,col1] = searchpos('\v%('.s:ocaml_word_char.'|\.)*','ncb') 564 | let [lin2,col2] = searchpos('\v%('.s:ocaml_word_char.'|\.)*','nce') 565 | if col1 == 0 || col2 == 0 566 | throw "no_expression" 567 | endif 568 | return [cursor_line,cursor_line,col1-1,col2] 569 | endif 570 | endif 571 | endfun 572 | 573 | "In: the current mode (eg. "visual", "normal", etc.) 574 | "Out: the type information (calls s:Extract_type_data) 575 | function! s:Get_type(mode, annot_file_name) 576 | let [lin1,lin2,col1,col2] = s:Match_borders(a:mode) 577 | return s:Extract_type_data(s:Block_pattern(lin1,lin2,col1,col2), a:annot_file_name) 578 | endfun 579 | 580 | "In: A string destined to be printed in the 'echo buffer'. It has line 581 | "break and 2 space at each line beginning. 582 | "Out: A string destined to be yanked, without space and double space. 583 | function s:unformat_ocaml_type(res) 584 | "Remove end of line. 585 | let res = substitute (a:res, "\n", "", "g" ) 586 | "remove double space 587 | let res =substitute(res , " ", " ", "g") 588 | "remove space at beginning of string. 589 | let res = substitute(res, "^ *", "", "g") 590 | return res 591 | endfunction 592 | 593 | "d. main 594 | "In: the current mode (eg. "visual", "normal", etc.) 595 | "After call: the type information is displayed 596 | if !exists("*Ocaml_get_type") 597 | function Ocaml_get_type(mode) 598 | let annot_file_name = s:Fnameescape(expand('%:t:r')).'.annot' 599 | call s:Locate_annotation() 600 | call s:Load_annotation(annot_file_name) 601 | let res = s:Get_type(a:mode, annot_file_name) 602 | " Copy result in the unnamed buffer 603 | let @" = s:unformat_ocaml_type(res) 604 | return res 605 | endfun 606 | endif 607 | 608 | if !exists("*Ocaml_get_type_or_not") 609 | function Ocaml_get_type_or_not(mode) 610 | let t=reltime() 611 | try 612 | let res = Ocaml_get_type(a:mode) 613 | return res 614 | catch 615 | return "" 616 | endtry 617 | endfun 618 | endif 619 | 620 | if !exists("*Ocaml_print_type") 621 | function Ocaml_print_type(mode) 622 | if expand("%:e") == "mli" 623 | echohl ErrorMsg | echo "No annotations for interface (.mli) files" | echohl None 624 | return 625 | endif 626 | try 627 | echo Ocaml_get_type(a:mode) 628 | catch /E484:/ 629 | echohl ErrorMsg | echo "No type annotations (.annot) file found" | echohl None 630 | catch /no_expression/ 631 | echohl ErrorMsg | echo "No expression found under the cursor" | echohl None 632 | catch /no_annotation/ 633 | echohl ErrorMsg | echo "No type annotation found for the given text" | echohl None 634 | catch /malformed_annot_file/ 635 | echohl ErrorMsg | echo "Malformed .annot file" | echohl None 636 | endtry 637 | endfun 638 | endif 639 | 640 | " Maps 641 | nnoremap OCamlPrintType :call Ocaml_print_type("normal") 642 | xnoremap OCamlPrintType :call Ocaml_print_type("visual")`< 643 | 644 | " Make sure the environment is consistent 645 | if !exists('g:opam_current_compiler') && exists('g:opam_init_env') && g:opam_init_env != 0 646 | call opam#eval_env() 647 | endif 648 | 649 | let &cpoptions=s:cposet 650 | unlet s:cposet 651 | 652 | " vim:sw=2 fdm=indent 653 | -------------------------------------------------------------------------------- /ftplugin/ocamlbuild_tags.vim: -------------------------------------------------------------------------------- 1 | if exists("b:did_ftplugin") 2 | finish 3 | endif 4 | let b:did_ftplugin=1 5 | 6 | setlocal comments=:# 7 | setlocal commentstring=#\ %s 8 | 9 | let b:undo_ftplugin = "com< cms<" 10 | -------------------------------------------------------------------------------- /ftplugin/omake.vim: -------------------------------------------------------------------------------- 1 | " Vim filetype plugin file 2 | " Language: OMake 3 | 4 | " Only do this when not done yet for this buffer 5 | if exists("b:did_ftplugin") 6 | finish 7 | endif 8 | let b:did_ftplugin = 1 9 | 10 | " Set 'formatoptions' to break comment lines but not other lines, 11 | " and insert the comment leader when hitting or using "o". 12 | setlocal fo-=t fo+=croql 13 | 14 | " Set 'comments' to format dashed lists in comments 15 | setlocal com=sO:#\ -,mO:#\ \ ,b:# 16 | 17 | " Set 'commentstring' to put the marker after a #. 18 | setlocal commentstring=#\ %s 19 | 20 | " always use spaces and not tabs 21 | setlocal expandtab 22 | 23 | " Including files. 24 | let &l:include = '^\s*include' 25 | 26 | let b:undo_ftplugin = "fo< com< cms< et< inc<" 27 | -------------------------------------------------------------------------------- /ftplugin/sexplib.vim: -------------------------------------------------------------------------------- 1 | " Vim filetype plugin file 2 | " Language: Sexplib 3 | " Maintainer: Markus Mottl 4 | " URL: https://github.com/ocaml/vim-ocaml 5 | " Last Change: 6 | " 2017 Apr 12 - First version (MM) 7 | 8 | if exists("b:did_ftplugin") 9 | finish 10 | endif 11 | let b:did_ftplugin=1 12 | 13 | " Comment string 14 | setl commentstring=;\ %s 15 | setl comments=n:; 16 | 17 | let b:undo_ftplugin = "setl cms< com<" 18 | -------------------------------------------------------------------------------- /indent/dune.vim: -------------------------------------------------------------------------------- 1 | " Vim indent file 2 | " Language: dune 3 | " Maintainers: Markus Mottl 4 | " URL: https://github.com/ocaml/vim-ocaml 5 | " Last Change: 2020 Dec 31 6 | 7 | if exists("b:did_indent") 8 | finish 9 | endif 10 | let b:did_indent = 1 11 | 12 | " dune format-dune-file uses 1 space to indent 13 | setlocal softtabstop=1 shiftwidth=1 expandtab 14 | 15 | let b:undo_indent = "setl et< sts< sw<" 16 | -------------------------------------------------------------------------------- /indent/ocaml.vim: -------------------------------------------------------------------------------- 1 | " Vim indent file 2 | " Language: OCaml 3 | " Maintainers: Jean-Francois Yuen 4 | " Mike Leary 5 | " Markus Mottl 6 | " URL: https://github.com/ocaml/vim-ocaml 7 | " Last Change: 2017 Jun 13 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. 16 | if exists("b:did_indent") 17 | finish 18 | endif 19 | let b:did_indent = 1 20 | 21 | setlocal expandtab 22 | setlocal indentexpr=GetOCamlIndent() 23 | setlocal 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) 24 | setlocal nolisp 25 | setlocal nosmartindent 26 | 27 | let b:undo_indent = "setl et< inde< indk< lisp< si<" 28 | 29 | " At least Marc Weber and Markus Mottl do not like this: 30 | " setlocal textwidth=80 31 | 32 | " Comment formatting 33 | if !exists("no_ocaml_comments") 34 | if (has("comments")) 35 | setlocal comments=sr:(*\ ,mb:\ ,ex:*) 36 | setlocal comments^=sr:(**,mb:\ \ ,ex:*) 37 | setlocal fo=cqort 38 | let b:undo_indent .= " | setl com< fo<" 39 | endif 40 | endif 41 | 42 | " Only define the function once. 43 | if exists("*GetOCamlIndent") 44 | finish 45 | endif 46 | 47 | " Define some patterns: 48 | let s:beflet = '^\s*\(initializer\|method\|try\)\|\(\<\(begin\|do\|else\|in\|then\|try\)\|->\|<-\|=\|;\|(\)\s*$' 49 | let s:letpat = '^\s*\(let\|type\|module\|class\|open\|exception\|val\|include\|external\)\>' 50 | let s:letlim = '\(\<\(sig\|struct\)\|;;\)\s*$' 51 | let s:lim = '^\s*\(exception\|external\|include\|let\|module\|open\|type\|val\)\>' 52 | let s:module = '\<\%(begin\|sig\|struct\|object\)\>' 53 | let s:obj = '^\s*\(constraint\|inherit\|initializer\|method\|val\)\>\|\<\(object\|object\s*(.*)\)\s*$' 54 | let s:type = '^\s*\%(class\|let\|type\)\>.*=' 55 | 56 | " Skipping pattern, for comments 57 | function! s:GetLineWithoutFullComment(lnum) 58 | let lnum = prevnonblank(a:lnum - 1) 59 | let lline = substitute(getline(lnum), '(\*.*\*)\s*$', '', '') 60 | while lline =~ '^\s*$' && lnum > 0 61 | let lnum = prevnonblank(lnum - 1) 62 | let lline = substitute(getline(lnum), '(\*.*\*)\s*$', '', '') 63 | endwhile 64 | return lnum 65 | endfunction 66 | 67 | " Indent for ';;' to match multiple 'let' 68 | function! s:GetInd(lnum, pat, lim) 69 | let llet = search(a:pat, 'bW') 70 | let old = indent(a:lnum) 71 | while llet > 0 72 | let old = indent(llet) 73 | let nb = s:GetLineWithoutFullComment(llet) 74 | if getline(nb) =~ a:lim 75 | return old 76 | endif 77 | let llet = search(a:pat, 'bW') 78 | endwhile 79 | return old 80 | endfunction 81 | 82 | " Indent pairs 83 | function! s:FindPair(pstart, pmid, pend) 84 | call search(a:pend, 'bW') 85 | return indent(searchpair(a:pstart, a:pmid, a:pend, 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string\\|comment"')) 86 | endfunction 87 | 88 | " Indent 'let' 89 | function! s:FindLet(pstart, pmid, pend) 90 | call search(a:pend, 'bW') 91 | return indent(searchpair(a:pstart, a:pmid, a:pend, 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string\\|comment" || getline(".") =~ "^\\s*let\\>.*=.*\\\s*$' 108 | return ind + 2 * shiftwidth() 109 | endif 110 | 111 | let line = getline(v:lnum) 112 | 113 | " Indent if current line begins with 'end': 114 | if line =~ '^\s*end\>' 115 | return s:FindPair(s:module, '','\') 116 | 117 | " Indent if current line begins with 'done' for 'do': 118 | elseif line =~ '^\s*done\>' 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 ']', '|]' or '>]': 126 | elseif line =~ '^\s*\(\||\|>\)\]' 127 | return s:FindPair('\[', '','\]') 128 | 129 | " Indent if current line begins with ')': 130 | elseif line =~ '^\s*)' 131 | return s:FindPair('(', '',')') 132 | 133 | " Indent if current line begins with 'let': 134 | elseif line =~ '^\s*let\>' 135 | if lline !~ s:lim . '\|' . s:letlim . '\|' . s:beflet 136 | return s:FindLet(s:type, '','\' 141 | if lline !~ s:lim . '\|\\)\|\<\(function\|parser\|private\|with\)\s*$' 148 | call search('|', 'bW') 149 | return indent(searchpair('^\s*\(match\|type\)\>\|\<\(function\|parser\|private\|with\)\s*$', '', '^\s*|', 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string\\|comment" || getline(".") !~ "^\\s*|.*->"')) 150 | endif 151 | 152 | " Indent if current line begins with ';;': 153 | elseif line =~ '^\s*;;' 154 | if lline !~ ';;\s*$' 155 | return s:GetInd(v:lnum, s:letpat, s:letlim) 156 | endif 157 | 158 | " Indent if current line begins with 'in': 159 | elseif line =~ '^\s*in\>' 160 | if lline !~ '^\s*\(let\|and\)\>' 161 | return s:FindPair('\', '', '\') 162 | endif 163 | 164 | " Indent if current line begins with 'else': 165 | elseif line =~ '^\s*else\>' 166 | if lline !~ '^\s*\(if\|then\)\>' 167 | return s:FindPair('\', '', '\') 168 | endif 169 | 170 | " Indent if current line begins with 'then': 171 | elseif line =~ '^\s*then\>' 172 | if lline !~ '^\s*\(if\|else\)\>' 173 | return s:FindPair('\', '', '\') 174 | endif 175 | 176 | " Indent if current line begins with 'and': 177 | elseif line =~ '^\s*and\>' 178 | if lline !~ '^\s*\(and\|let\|type\)\>\|\' 184 | if lline !~ '^\s*\(match\|try\)\>' 185 | return s:FindPair('\<\%(match\|try\)\>', '','\') 186 | endif 187 | 188 | " Indent if current line begins with 'exception', 'external', 'include' or 189 | " 'open': 190 | elseif line =~ '^\s*\(exception\|external\|include\|open\)\>' 191 | if lline !~ s:lim . '\|' . s:letlim 192 | call search(line) 193 | return indent(search('^\s*\(\(exception\|external\|include\|open\|type\)\>\|val\>.*:\)', 'bW')) 194 | endif 195 | 196 | " Indent if current line begins with 'val': 197 | elseif line =~ '^\s*val\>' 198 | if lline !~ '^\s*\(exception\|external\|include\|open\)\>\|' . s:obj . '\|' . s:letlim 199 | return indent(search('^\s*\(\(exception\|include\|initializer\|method\|open\|type\|val\)\>\|external\>.*:\)', 'bW')) 200 | endif 201 | 202 | " Indent if current line begins with 'constraint', 'inherit', 'initializer' 203 | " or 'method': 204 | elseif line =~ '^\s*\(constraint\|inherit\|initializer\|method\)\>' 205 | if lline !~ s:obj 206 | return indent(search('\<\(object\|object\s*(.*)\)\s*$', 'bW')) + shiftwidth() 207 | endif 208 | 209 | endif 210 | 211 | " Add a 'shiftwidth' after lines ending with: 212 | if lline =~ '\(:\|=\|->\|<-\|(\|\[\|{\|{<\|\[|\|\[<\|\<\(begin\|do\|else\|fun\|function\|functor\|if\|initializer\|object\|parser\|private\|sig\|struct\|then\|try\)\|\') 222 | 223 | " Back to normal indent after lines ending with 'in': 224 | elseif lline =~ '\' 225 | let ind = s:FindPair('\', '', '\') 226 | 227 | " Back to normal indent after lines ending with 'done': 228 | elseif lline =~ '\', '','\') 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 lines ending with ']', '|]' or '>]': 236 | elseif lline =~ '\(\||\|>\)\]\s*$' 237 | let ind = s:FindPair('\[', '','\]') 238 | 239 | " Back to normal indent after comments: 240 | elseif lline =~ '\*)\s*$' 241 | call search('\*)', 'bW') 242 | let ind = indent(searchpair('(\*', '', '\*)', 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string"')) 243 | 244 | " Back to normal indent after lines ending with ')': 245 | elseif lline =~ ')\s*$' 246 | let ind = s:FindPair('(', '',')') 247 | 248 | " If this is a multiline comment then align '*': 249 | elseif lline =~ '^\s*(\*' && line =~ '^\s*\*' 250 | let ind = ind + 1 251 | 252 | else 253 | " Don't change indentation of this line 254 | " for new lines (indent==0) use indentation of previous line 255 | 256 | " This is for preventing removing indentation of these args: 257 | " let f x = 258 | " let y = x + 1 in 259 | " Printf.printf 260 | " "o" << here 261 | " "oeuth" << don't touch indentation 262 | 263 | let i = indent(v:lnum) 264 | return i == 0 ? ind : i 265 | 266 | endif 267 | 268 | " Subtract a 'shiftwidth' after lines matching 'match ... with parser': 269 | if lline =~ '\.*\\s*\,=else,=endif 11 | setlocal nosmartindent 12 | 13 | if exists("*GetMakeIndent") 14 | finish 15 | endif 16 | 17 | let s:comment_rx = '^\s*#' 18 | let s:rule_rx = '^[^ \t#:][^#:]*:\{1,2}\%([^=:]\|$\)' 19 | let s:continued_rule_rx = '^[^#:]*:\{1,2}\%([^=:]\|$\)' 20 | let s:continuation_rx = '\\$' 21 | let s:assignment_rx = '^\s*\h\w*\s*[+?]\==\s*\zs.*\\$' 22 | let s:folded_assignment_rx = '^\s*\h\w*\s*[+?]\==' 23 | " TODO: This needs to be a lot more restrictive in what it matches. 24 | let s:just_inserted_rule_rx = '^\s*[^#:]\+:\{1,2}$' 25 | let s:conditional_directive_rx = '^ *\%(ifn\=\%(eq\|def\)\|else\)\>' 26 | let s:end_conditional_directive_rx = '^\s*\%(else\|endif\)\>' 27 | 28 | function s:remove_continuation(line) 29 | return substitute(a:line, s:continuation_rx, "", "") 30 | endfunction 31 | 32 | function GetMakeIndent() 33 | " TODO: Should this perhaps be v:lnum -1? 34 | " let prev_lnum = prevnonblank(v:lnum - 1) 35 | let prev_lnum = v:lnum - 1 36 | if prev_lnum == 0 37 | return 0 38 | endif 39 | let prev_line = getline(prev_lnum) 40 | 41 | let prev_prev_lnum = prev_lnum - 1 42 | let prev_prev_line = prev_prev_lnum != 0 ? getline(prev_prev_lnum) : "" 43 | 44 | " TODO: Deal with comments. In comments, continuations aren't interesting. 45 | if prev_line =~ s:continuation_rx 46 | if prev_prev_line =~ s:continuation_rx 47 | return indent(prev_lnum) 48 | elseif prev_line =~ s:rule_rx 49 | return &sw 50 | elseif prev_line =~ s:assignment_rx 51 | call cursor(prev_lnum, 1) 52 | if search(s:assignment_rx, 'W') != 0 53 | return virtcol('.') - 1 54 | else 55 | " TODO: ? 56 | return &sw 57 | endif 58 | else 59 | " TODO: OK, this might be a continued shell command, so perhaps indent 60 | " properly here? Leave this out for now, but in the next release this 61 | " should be using indent/sh.vim somehow. 62 | "if prev_line =~ '^\t' " s:rule_command_rx 63 | " if prev_line =~ '^\s\+[@-]\%(if\)\>' 64 | " return indent(prev_lnum) + 2 65 | " endif 66 | "endif 67 | return indent(prev_lnum) + &sw 68 | endif 69 | elseif prev_prev_line =~ s:continuation_rx 70 | let folded_line = s:remove_continuation(prev_prev_line) . ' ' . s:remove_continuation(prev_line) 71 | let lnum = prev_prev_lnum - 1 72 | let line = getline(lnum) 73 | while line =~ s:continuation_rx 74 | let folded_line = s:remove_continuation(line) . ' ' . folded_line 75 | let lnum -= 1 76 | let line = getline(lnum) 77 | endwhile 78 | let folded_lnum = lnum + 1 79 | if folded_line =~ s:rule_rx 80 | if getline(v:lnum) =~ s:rule_rx 81 | return 0 82 | else 83 | return &ts 84 | endif 85 | else 86 | " elseif folded_line =~ s:folded_assignment_rx 87 | if getline(v:lnum) =~ s:rule_rx 88 | return 0 89 | else 90 | return indent(folded_lnum) 91 | endif 92 | " else 93 | " " TODO: ? 94 | " return indent(prev_lnum) 95 | endif 96 | elseif prev_line =~ s:rule_rx 97 | if getline(v:lnum) =~ s:rule_rx 98 | return 0 99 | else 100 | return &ts 101 | endif 102 | elseif prev_line =~ s:conditional_directive_rx 103 | return &sw 104 | else 105 | let line = getline(v:lnum) 106 | if line =~ s:just_inserted_rule_rx 107 | return 0 108 | elseif line =~ s:end_conditional_directive_rx 109 | return v:lnum - 1 == 0 ? 0 : indent(v:lnum - 1) - &sw 110 | else 111 | return v:lnum - 1 == 0 ? 0 : indent(v:lnum - 1) 112 | endif 113 | endif 114 | endfunction 115 | -------------------------------------------------------------------------------- /plugin/opam.vim: -------------------------------------------------------------------------------- 1 | " opam.vim - Switch ocaml versions from inside Vim 2 | " Maintainer: Rudi Grinberg 3 | " Version: 1.0 4 | 5 | if exists('g:loaded_opam') || v:version < 700 || &cp 6 | finish 7 | endif 8 | 9 | let g:loaded_opam = 1 10 | 11 | if !exists('g:opam_set_switch') 12 | let g:opam_set_switch = 0 13 | endif 14 | 15 | " Utility {{{1 16 | 17 | function! opam#eval_env() 18 | let l:env_extra_args = "" 19 | if g:opam_set_switch 20 | " Unlet so 'opam env' uses the selected switch 21 | unlet $OPAMSWITCH 22 | " Will add OPAMSWITCH and OPAMROOT to the output 23 | let l:env_extra_args = " --set-switch --set-root" 24 | endif 25 | let opam_eval = system("opam env --readonly" . l:env_extra_args) 26 | if v:shell_error 27 | return 0 28 | endif 29 | let cmds = split(opam_eval, "\n") 30 | for cmd in cmds 31 | let var = split(split(cmd, ";")[0], "=") 32 | execute 'let $' . var[0] . " = " . var[1] 33 | endfor 34 | if g:opam_set_switch 35 | let g:opam_current_compiler = $OPAMSWITCH 36 | else 37 | let g:opam_current_compiler = opam#compiler_version() 38 | endif 39 | return 1 40 | endfunction 41 | 42 | function! opam#switch(ocaml_version) 43 | let res = system('opam switch --color=never ' . s:shellesc(a:ocaml_version)) 44 | let success = empty(matchstr(res, 'ERROR')) 45 | if success 46 | call opam#eval_env() 47 | endif 48 | return success 49 | endfunction 50 | 51 | function! opam#chomp(s) 52 | return substitute(a:s, '\n', '', 'g') 53 | endfunction 54 | 55 | function! opam#compiler_version() 56 | return opam#chomp(system("opam switch show")) 57 | endfunction 58 | 59 | function! s:shellesc(arg) abort 60 | if a:arg =~ '^[A-Za-z0-9_/.-]\+$' 61 | return a:arg 62 | else 63 | return shellescape(a:arg) 64 | endif 65 | endfunction 66 | 67 | " }}}1 68 | " :Opam {{{1 69 | 70 | function! opam#cmd_switch(version) 71 | let success = opam#switch(a:version) 72 | if success 73 | if g:opam_current_compiler == a:version 74 | let l:extra_msg = "" 75 | elseif !g:opam_set_switch && exists('$OPAMSWITCH') 76 | let l:extra_msg = " (set with OPAMSWITCH)" 77 | else 78 | let l:extra_msg = " (local switch)" 79 | endif 80 | echomsg "Using " . g:opam_current_compiler . l:extra_msg 81 | else 82 | echoerr "Switching to " . a:version . " failed" 83 | endif 84 | endfunction 85 | 86 | function! s:Opam(bang,...) abort 87 | if len(a:000) > 1 88 | if a:1 ==# "switch" 89 | call opam#cmd_switch(a:2) 90 | else 91 | echoerr "Only switching is supported for now" 92 | end 93 | elseif len(a:000) > 0 94 | call opam#cmd_switch(a:1) 95 | else 96 | if opam#eval_env() 97 | echomsg "Using " . g:opam_current_compiler 98 | else 99 | echomsg "Updating the environment failed." 100 | endif 101 | end 102 | endfunction 103 | 104 | function! s:Complete(A,L,P) 105 | let switches = split((system("opam switch --short 2> /dev/null")), "\n") 106 | call map(switches, 'opam#chomp(v:val)') 107 | return join(switches, "\n") 108 | endfunction 109 | 110 | command! -bar -nargs=* -complete=custom,s:Complete Opam :call s:Opam(0,) 111 | 112 | " }}}1 113 | " Statusline {{{1 114 | 115 | function! opam#statusline() 116 | if exists('g:opam_current_compiler') 117 | let c = g:opam_current_compiler 118 | else 119 | let c = opam#compiler_version() 120 | endif 121 | return substitute('['.c.']','^\[\]$','','') 122 | endfunction 123 | 124 | function! opam#statusline_ft_ocaml() 125 | if &filetype ==# 'ocaml' 126 | return opam#statusline() 127 | else 128 | return '' 129 | endif 130 | endfunction 131 | 132 | " }}}1 133 | 134 | " vim:set sw=2 sts=2: 135 | -------------------------------------------------------------------------------- /syntax-testcases/exception_alias.ml: -------------------------------------------------------------------------------- 1 | (* ok *) 2 | exception E = F 3 | -------------------------------------------------------------------------------- /syntax-testcases/functor1.ml: -------------------------------------------------------------------------------- 1 | (* ok *) 2 | module M : sig 3 | module type F 4 | = functor () (X : Ord) -> sig end 5 | module F 6 | : functor () (X : Ord) -> sig end 7 | end 8 | = struct 9 | module type F 10 | = functor () (X : Ord) -> sig end 11 | module F 12 | : functor () (X : Ord) -> sig end 13 | = functor () (X : Ord) -> struct end 14 | end 15 | 16 | module type F 17 | = functor () (X : Ord) -> sig end 18 | module F 19 | : functor () (X : Ord) -> sig end 20 | = functor () (X : Ord) -> struct end 21 | -------------------------------------------------------------------------------- /syntax-testcases/functor2.ml: -------------------------------------------------------------------------------- 1 | (* https://github.com/ocaml/vim-ocaml/issues/3 *) 2 | 3 | module Make (M : sig end) = struct module type S = sig end end 4 | module Test : Make(Make(Int)).S = struct end 5 | (* ----------------^ the inner modules are linted as constructors *) 6 | -------------------------------------------------------------------------------- /syntax-testcases/functor3.mli: -------------------------------------------------------------------------------- 1 | module Make : functor(X: Ord) -> sig 2 | module Bar : module type of Make(X) 3 | 4 | val x : int 5 | val y : int 6 | end 7 | -------------------------------------------------------------------------------- /syntax-testcases/functor_param.ml: -------------------------------------------------------------------------------- 1 | module M : sig 2 | module F () (X : Ord) : sig end 3 | end 4 | = struct 5 | module F () (X : Ord) : sig end = struct end 6 | end 7 | 8 | module F () (X : Ord) : sig end = struct end 9 | -------------------------------------------------------------------------------- /syntax-testcases/module_paren1.ml: -------------------------------------------------------------------------------- 1 | module M0 : sig end = struct let x = 0 end 2 | (* => linting of struct is correct *) 3 | 4 | module M1 : sig end = (struct let x = 0 end : sig end) 5 | (* => linting of struct is correct 6 | (but linting of last sig is buggy because of the type linter of PR#76) *) 7 | 8 | module M2 = (struct let x = 0 end : sig end) 9 | (* => ^^^^^^^^^^^^^^^^^^^^ 10 | the whole struct is linted with a wrong, uniform style 11 | (but linting of last sig is correct) *) 12 | -------------------------------------------------------------------------------- /syntax-testcases/module_paren2.ml: -------------------------------------------------------------------------------- 1 | (* https://github.com/ocaml/vim-ocaml/issues/6 *) 2 | 3 | module IM = Stdlib.Map.Make(Int) 4 | (* ^^^^^^^^^^^^^^^^^^^^ 5 | shown as a module/functor, with a uniform style *) 6 | 7 | module IM : sig end = Stdlib.Map.Make(Int) 8 | (* ^^^^^^^^^^^^^^^^^^^^ 9 | shown as as an expression (a datatype constructor `Make` 10 | prefixed with a module path, and a constructor `Int`) *) 11 | -------------------------------------------------------------------------------- /syntax-testcases/module_type.ml: -------------------------------------------------------------------------------- 1 | (* https://github.com/ocaml/vim-ocaml/issues/84 *) 2 | (* Foo is highlighted incorrectly *) 3 | type x = (module Foo) 4 | -------------------------------------------------------------------------------- /syntax-testcases/module_type_of.mli: -------------------------------------------------------------------------------- 1 | (* approximately ok: 2 | * - "module type of" linted as ocamlKeyword 3 | * - "F" linted as ocamlModule 4 | * - "(X)" linted meaninglessly but by chance it doesn’t look SO bad 5 | *) 6 | module N : module type of F(X) 7 | 8 | module M : sig 9 | module N : module type of X 10 | module N : module type of F(X) 11 | val x : int 12 | end 13 | -------------------------------------------------------------------------------- /syntax-testcases/module_underscore.ml: -------------------------------------------------------------------------------- 1 | (* ok *) 2 | module _ = struct 3 | let () = () 4 | end 5 | -------------------------------------------------------------------------------- /syntax-testcases/module_with_signature.ml: -------------------------------------------------------------------------------- 1 | module F : Bar = Foo 2 | 3 | module Test : Make(Int).S = struct end 4 | -------------------------------------------------------------------------------- /syntax-testcases/poly_variant_in_type.ml: -------------------------------------------------------------------------------- 1 | (* https://github.com/ocaml/vim-ocaml/issues/88 *) 2 | (* foo is highlighted incorrectly on every line *) 3 | val bar : [>foo] 4 | let decode x = (Dns.Packet.decode x : (_, Dns.Packet.err) result :> (_, [> foo]) result) 5 | type t = [Dns.Packet.foo | Dns.Packet.bar] 6 | -------------------------------------------------------------------------------- /syntax-testcases/type-linter-test.ml: -------------------------------------------------------------------------------- 1 | (* TODO: 2 | * - error reporting of wrong keywords in type context: mutable/of/done/etc. 3 | * - class type parameters 4 | * 5 | * Cases which were not detected by examining the OCaml grammar in the manual: 6 | * - let f (type a b) … 7 | * - module M : MSIG with type t = u = struct … end 8 | * - module M (X : …) … 9 | * - (x : t :> t) 10 | * - (x : name :> t) (“name :” looks like a label) 11 | * - let f : type a b. a -> b = … 12 | * - let f ~x:local_name … 13 | * - false, true, (), [], :: are constructors 14 | * - extensible type: type u = .. , type u += U2 15 | * - destructive substitution (lang. extension): with type t := … 16 | *) 17 | 18 | (* TYPE EXPRESSIONS *) 19 | 20 | type t0 = unit 21 | type _ t1 = bool 22 | type (_, _) t2 = int 23 | type u = char 24 | type v = string 25 | type w = bytes 26 | 27 | (* type expressions with arrows, tuples, 0-ary type constructors *) 28 | type t = t0 * t0 -> t0 29 | (* type expressions with type arguments *) 30 | type t = t0 * u t1 -> (v, w) t2 31 | (* type expressions with builtin type names *) 32 | type t = unit option * bool ref * int array * char list -> (string, bytes) result 33 | (* type expressions with type variables *) 34 | type ('a, 'b) t = 'a list * ('a, 'b) result 35 | (* type expressions with module paths *) 36 | type t = Scanf.Scanning . in_channel 37 | type t = Stdlib.Set.Make ( Stdlib.Set.Make(Stdlib.Set.Make(Int)) ) . t 38 | (* type expressions with labels *) 39 | type t = name : int -> int 40 | type t = ?name : int -> int 41 | (* conflict between labels in type expressions and builtin type names *) 42 | type t = int : int -> int 43 | type t = ?int : int -> int 44 | (* type expressions with parentheses *) 45 | type t = (((?name : int -> int) -> int) -> int) 46 | (* quantified type expression *) 47 | let f : 'a 'b . 'a -> 'b -> 'a * 'b = fun x y -> (x, y) 48 | 49 | (* object types *) 50 | type 't t = 51 | < 52 | method1 : int * int ; 53 | method2 : name:int -> int ; 54 | .. 55 | > as 't 56 | 57 | (* polymorphic variant types *) 58 | type 't t = [< `a ] as 't 59 | type 't t = [> `a ] as 't 60 | type t = [ `a ] 61 | type t = [ `a | `b ] 62 | type 't t = [< `a of int * int & char -> char ] as 't 63 | type 't t = [< `a of int * int & char -> char | `b of int * int ] as 't 64 | (* syntax errors *) 65 | (*! type 't t = [ `a : int * int -> t & (char -> char) -> t ] as 't !*) 66 | (*! type 't t = [ `a : int * int -> t & (char -> char) -> t | `b : int * int -> t ] as 't !*) 67 | 68 | (* TYPE DEFINITIONS *) 69 | 70 | (* type definitions with type variables *) 71 | type 'a t = 'a option 72 | type ('a, 'b) t = ('a, 'b) result 73 | type _ t = int 74 | type ('a, _) t = 'a 75 | 76 | (* type definitions with injectivity and variance precisions *) 77 | type + 'a t = int 78 | type + _ t = int 79 | type - 'a t = int 80 | type - _ t = int 81 | type (+'a, -_) t = int 82 | type ! 'a t = 'a list 83 | type ! + 'a t = 'a list 84 | type + ! 'a t = 'a list 85 | type (-!'a, !+'b) t = 'a -> 'b 86 | 87 | (* type definitions with “nonrec” and “private” *) 88 | type nonrec 'a r = 'a ref = private { mutable contents : 'a } 89 | type nonrec 'a r = private 'a r 90 | type nonrec 'a o = 'a option = private None | Some of 'a 91 | type nonrec 'a o = private 'a o 92 | 93 | (* type definitions with “as” *) 94 | type 'a t = int as 'a 95 | (* the “as” keyword outside of type contexts: *) 96 | let x as y = 0 97 | 98 | (* type definitions with constraints *) 99 | type 'a t = int * 'a constraint (int * int) * int = 'a t * int 100 | type t = A constraint int = int 101 | 102 | (* mutually recursive type definitions *) 103 | type t = int and u = int 104 | type t = A and u = B 105 | type t = int constraint int = t and u = int constraint int = u 106 | 107 | (* definition of record types *) 108 | type t = 109 | { 110 | mutable field1 : int * int ; 111 | field2 : name:int -> int 112 | } 113 | 114 | (* definition of sum types *) 115 | type t = A 116 | type t = | A 117 | type t = A | B 118 | type t = | A | B 119 | type t = A of int * int 120 | type t = | A of int * int 121 | type t = A : int * int -> t 122 | type t = | A : int * int -> t 123 | type t = A of int * int | B of int * int 124 | type t = | A of int * int | B of int * int 125 | type t = A : int * int -> t | B : int * int -> t 126 | type t = | A : int * int -> t | B : int * int -> t 127 | 128 | (* definition of sum types with inline records *) 129 | type t = A of { field1 : int ; mutable field2 : int } 130 | type t = A : { field1 : int ; mutable field2 : int } -> t 131 | 132 | (* definition of extensible sum types *) 133 | type t = .. 134 | type t += A | B 135 | type t += C of int 136 | type t += D : int -> t 137 | 138 | (* definition of exceptions *) 139 | exception E 140 | exception E of int 141 | exception E : int -> exn 142 | exception E' = E 143 | exception F = Stdlib.Not_found 144 | (* local exceptions *) 145 | let _ = let exception E in () 146 | let _ = let exception E of int * int in () 147 | let _ = let exception E : int -> exn in () 148 | (* exception patterns *) 149 | let _ = match () with () -> () | exception E 42 -> () 150 | let _ = match () with exception E 42 -> () | () -> () 151 | let _ = match () with exception E 42 -> () | () -> () | exception E' 42 -> () 152 | (* exception patterns under or-patterns (since OCaml 4.08) *) 153 | let _ = match () with (exception E 42 | exception E 43) -> () | _ -> () 154 | (* empty type definition followed by an exception definition *) 155 | type t = | exception E 156 | 157 | (* definition with a constant constructor followed by a comment *) 158 | type t = A (* should work *) 159 | exception E (* should work *) 160 | 161 | (* corner case: “false”, “true”, “()” “[]” and “::” are constructors, too! *) 162 | module DamageControl = struct 163 | type 'a t = ( ) | false | true of 'a | [ ] | (::) of 'a * 'a 164 | end 165 | 166 | (* definition of an empty type *) 167 | type t = | 168 | 169 | (* TYPE ANNOTATIONS *) 170 | 171 | (* annotations on let binders *) 172 | let _ : float = 0. 173 | let f x : float = 0. 174 | let f (x : int) = 0. 175 | let f (x : int) : float = 0. 176 | let f ~(x : int) = 0. 177 | let f ?(x : int option)() = 0. 178 | let f ?(x : int = 0)() = 0. 179 | 180 | (* conflict between type annotations and local renaming of labels *) 181 | (* y is the local name of x, int is the type of x, float is the return type *) 182 | let f ~x:y = float y 183 | let f ~x: y = float y 184 | let f ~x :float = float x 185 | let f ~x : float = float x 186 | let f ~x:y:float = float y 187 | let f ~x:y :float = float y 188 | let f ~x:y: float = float y 189 | let f ~x:y : float = float y 190 | let f ~x: y:float = float y 191 | let f ~x: y :float = float y 192 | let f ~x: y: float = float y 193 | let f ~x: y : float = float y 194 | let f ~x:(y:int) : float = float y 195 | let f ~x:(y : int) : float = float y 196 | (*! let f ~x : y : float = float y (* syntax error *) !*) 197 | (* the same with optional arguments *) 198 | let[@warning "-16"] f ?x:y = 0. 199 | let[@warning "-16"] f ?x: y = 0. 200 | let[@warning "-16"] f ?x :float = 0. 201 | let[@warning "-16"] f ?x : float = 0. 202 | let[@warning "-16"] f ?x:y:float = 0. 203 | let[@warning "-16"] f ?x:y :float = 0. 204 | let[@warning "-16"] f ?x:y: float = 0. 205 | let[@warning "-16"] f ?x:y : float = 0. 206 | let[@warning "-16"] f ?x: y:float = 0. 207 | let[@warning "-16"] f ?x: y :float = 0. 208 | let[@warning "-16"] f ?x: y: float = 0. 209 | let[@warning "-16"] f ?x: y : float = 0. 210 | let[@warning "-16"] f ?x:(y:int option) : float = 0. 211 | let[@warning "-16"] f ?x:(y : int option) : float = 0. 212 | let[@warning "-16"] f ?x:(y : int = 0) : float = 0. 213 | (*! let f ?x : y : float = 0. (* syntax error *) !*) 214 | (* even worse *) 215 | let f ~x:y:z:unit->float = fun ~z:_ -> 0. 216 | let[@warning "-16"] f ?x:y:z:unit->float = fun ~z:_ -> 0. 217 | 218 | (* annotations and coercions on expressions *) 219 | let f x = (x : int) 220 | let f x = (x :> int) 221 | let f x = (x : int :> int) 222 | 223 | (* nested within parentheses *) 224 | let _ = let x : int = 0 in x 225 | let _ = (let x : int = 0 in x) 226 | 227 | (* nested type expressions *) 228 | let _ : < x : int ; y : int > = object method x = 0 method y = 0 end 229 | type 'a t = { 230 | field1 : int * < method1 : int -> string ; .. > as 'a ; 231 | field2 : int * < method1 : int -> string > ; 232 | } 233 | 234 | (* annotations in pattern-matching *) 235 | type t = A | B of int 236 | let _ = function 237 | | A -> () 238 | | (B (x:int) : t) -> () 239 | 240 | (* annotations on record fields *) 241 | type t = { x : int ; y : int } 242 | let _ = { x : int = 0 ; y : int = 0 } 243 | let _ = let x = 0 and y = 0 in { x : int ; y : int } 244 | 245 | (* annotations on object values and methods *) 246 | class c : object val v : int method x : int method y : int end = 247 | object val v : int = 0 method x : int = 0 method y : int = 0 end 248 | 249 | (* LOCALLY ABSTRACT TYPES *) 250 | 251 | (* type parameter *) 252 | let f (type a) (x : a) : a = x 253 | (* existential type when pattern-matching a GADT (since OCaml 4.13) *) 254 | (*! type t = A : ('a * ('a->string)) -> t !*) 255 | (*! let f t = match t with A (type a) (x, print : a * _) -> print x !*) 256 | (* polymorphic syntax for locally abstract types; 257 | * NOTE: this is only allowed on let/method defs, right after the colon. *) 258 | let f : type a b . a -> b -> a * b = fun x y -> (x, y) 259 | let _ = object method f : type a b. a -> b -> a * b = f end 260 | (* annotations on let must eat "type" but annotations on val must not *) 261 | module type SIG = sig 262 | type t = int 263 | val x : int 264 | type u = int 265 | end 266 | 267 | (* CLASS TYPES *) 268 | 269 | class c : x:int -> object 270 | method f : int 271 | method g : float 272 | constraint int = int 273 | inherit object end 274 | end = 275 | fun ~x -> 276 | object 277 | method f : int = 0 278 | method g : float = 0. 279 | end 280 | 281 | (* FIXME the type parameters of the class should be highlighted as types: *) 282 | class ['a, 'b] c : x:int -> 283 | let open List in 284 | object end 285 | = 286 | fun ~x -> 287 | object end 288 | 289 | (* MODULES *) 290 | 291 | module type SIG = sig type t end 292 | 293 | (* modules with type constraints *) 294 | module F (M : sig end) : SIG with type t = int = struct type t = int end 295 | module F (M : SIG with type t = int) : SIG = M 296 | 297 | (* destructive type substitutions inside signatures *) 298 | module type SIG = sig type t val x : t end 299 | module type SIGINT = SIG with type t := int 300 | 301 | (* nesting *) 302 | module M : sig 303 | val f : 'a -> 'a 304 | type t = A | B of int | C of {x:int} 305 | module M : sig 306 | val f : 'a -> 'a 307 | type t = A | B of int | C of {x:int} 308 | end 309 | end = struct 310 | let f : type a. a -> a = fun x -> x 311 | type t = A | B of int | C of {x:int} 312 | module M : sig 313 | val f : 'a -> 'a 314 | type t = A | B of int | C of {x:int} 315 | end = struct 316 | let f : type a. a -> a = fun x -> x 317 | type t = A | B of int | C of {x:int} 318 | end 319 | end 320 | 321 | (* ATTRIBUTES AND COMMENTS *) 322 | 323 | exception[@my.attr "payld"] (*c*) E [@my.attr "payld"] (*c*) 324 | type[@my.attr "payld"] (*c*) t (*c*) = (*c*) int [@@my.attr "payld"] (*c*) 325 | type t = (int [@my.attr "payld"] (*c*)) 326 | type t = < x : int [@my.attr "payld"] ; (*c*) y (*c*) : (*c*) int (*c*) > 327 | type t = < x : int ; [@my.attr "payld"] (*c*) y (*c*) : (*c*) int (*c*) > 328 | type t = { x : int [@my.attr "payld"] ; (*c*) y (*c*) : (*c*) int (*c*) } 329 | type t = { x : int ; [@my.attr "payld"] (*c*) y (*c*) : (*c*) int (*c*) } 330 | type t = [ `A of int [@my.attr "payld"] (*c*) | (*c*) `B (*c*) of (*c*) int (*c*) ] 331 | type t = | A of int [@my.attr "payld"] (*c*) | (*c*) B (*c*) of (*c*) int (*c*) 332 | let _ : unit [@my.attr "payld"] (*c*) = () 333 | 334 | (* VARIOUS TRAPS *) 335 | 336 | (* items that have different meanings at type level and at value level *) 337 | let float ~float = float 338 | (* let-bound identifier 339 | * | optional named arg 340 | * | | local name for named arg 341 | * | | | TYPE OF NAMED ARG RETURN TYPE 342 | * | | | <------------> <---> 343 | * | | | named arg in type builtin type 344 | * | | | | builtin | variable in expr 345 | * | | | | | default value of optional arg 346 | * | | | | | | | | 347 | * v v v v v v v v *) 348 | let float ?float:(float:float:_->float=float)() : float = float ~float:0. 349 | let _ : < bool : bool * bool > = object method bool = 1 < 2 * 3, 4 * 5 > 6 end 350 | 351 | (* expression items that start with a colon *) 352 | let f r x = r := x 353 | let _ = 0 :: [] 354 | 355 | (* different uses of the syntax “name : type -> type” *) 356 | type t = ( x : int -> bool ) (* x is a label of type int *) 357 | type t = { x : int -> bool } (* x is a field of type int->bool *) 358 | let f x = ( x : int -> bool ) (* x is an expr of type int->bool *) 359 | let f = ( fun x -> x : int -> int ) (* x is an expr of type int *) 360 | let f (=) x = ( x = x : int -> bool ) (* totally irrealistic case *) 361 | 362 | (* return type of a `fun` *) 363 | let _ = fun x : int -> 42 (* int is the return type, `->` ends the type! *) 364 | let _ = fun (f : int -> int) : int -> 42 365 | -------------------------------------------------------------------------------- /syntax/dune.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file 2 | " Language: Dune buildsystem 3 | " Maintainer: Markus Mottl 4 | " Anton Kochkov 5 | " URL: https://github.com/ocaml/vim-ocaml 6 | " Last Change: 7 | " 2023 Nov 24 - Add end-of-line strings (Samuel Hym) 8 | " 2019 Feb 27 - Add newer keywords to the syntax (Simon Cruanes) 9 | " 2018 May 8 - Check current_syntax (Kawahara Satoru) 10 | " 2018 Mar 29 - Extend jbuild syntax with more keywords (Petter A. Urkedal) 11 | " 2017 Sep 6 - Initial version (Etienne Millon) 12 | 13 | if exists("b:current_syntax") 14 | finish 15 | endif 16 | 17 | set syntax=lisp 18 | syn case match 19 | 20 | " The syn-iskeyword setting lacks #,? from the iskeyword setting here. 21 | " Clearing it avoids maintaining keyword characters in multiple places. 22 | syn iskeyword clear 23 | 24 | syn keyword lispDecl jbuild_version library executable executables rule ocamllex ocamlyacc menhir alias install 25 | 26 | syn keyword lispKey name public_name synopsis modules libraries wrapped 27 | syn keyword lispKey preprocess preprocessor_deps optional c_names cxx_names 28 | syn keyword lispKey install_c_headers modes no_dynlink self_build_stubs_archive 29 | syn keyword lispKey ppx_runtime_libraries virtual_deps js_of_ocaml link_flags 30 | syn keyword lispKey javascript_files flags ocamlc_flags ocamlopt_flags pps staged_pps 31 | syn keyword lispKey library_flags c_flags c_library_flags kind package action 32 | syn keyword lispKey deps targets locks fallback 33 | syn keyword lispKey inline_tests tests test names 34 | 35 | syn keyword lispAtom true false 36 | 37 | syn keyword lispFunc cat chdir copy# diff? echo run setenv 38 | syn keyword lispFunc ignore-stdout ignore-stderr ignore-outputs 39 | syn keyword lispFunc with-stdout-to with-stderr-to with-outputs-to 40 | syn keyword lispFunc write-file system bash 41 | 42 | syn region lispString start=+"\\[>|]+ end=+$+ contains=@Spell 43 | 44 | syn cluster lispBaseListCluster add=duneVar 45 | syn match duneVar '\${[@<^]}' containedin=lispSymbol 46 | syn match duneVar '\${\k\+\(:\k\+\)\?}' containedin=lispSymbol 47 | 48 | hi def link duneVar Identifier 49 | 50 | let b:current_syntax = "dune" 51 | -------------------------------------------------------------------------------- /syntax/oasis.vim: -------------------------------------------------------------------------------- 1 | if exists("b:current_syntax") 2 | finish 3 | endif 4 | 5 | syn keyword oasisSpecialFeatures ocamlbuild_more_args compiled_setup_ml pure_interface stdfiles_markdown 6 | syn keyword oasisTodo FIXME NOTE NOTES TODO XXX contained 7 | syn match oasisComment "#.*$" contains=oasisTodo,@Spell 8 | syn keyword oasisPlugin META DevFiles StdFiles 9 | 10 | syn match oasisOperator "(\|)\|>=\|,\|&&" 11 | syn match oasisVariable "$\w\+" 12 | syn match oasisVersion "\<\d\+\(.\(\d\)\+\)\+\>" 13 | syn region oasisString start=/"/ end=/"/ 14 | 15 | syntax keyword oasisSection Document Executable Flag Library Document Test SourceRepository 16 | 17 | syntax match oasisKey "OASISFormat:" 18 | syntax match oasisKey "OCamlVersion:" 19 | syntax match oasisKey "Copyrights:" 20 | syntax match oasisKey "Maintainers:" 21 | syntax match oasisKey "XStdFilesAUTHORS:" 22 | syntax match oasisKey "XStdFilesREADME:" 23 | syntax match oasisKey "FindlibVersion:" 24 | syntax match oasisKey "Name:" 25 | syntax match oasisKey "Version:" 26 | syntax match oasisKey "Synopsis:" 27 | syntax match oasisKey "Authors:" 28 | syntax match oasisKey "Homepage:" 29 | syntax match oasisKey "License:" 30 | syntax match oasisKey "LicenseFile:" 31 | syntax match oasisKey "BuildTools:" 32 | syntax match oasisKey "Plugins:" 33 | syntax match oasisKey "Description:" 34 | syntax match oasisKey "AlphaFeatures:" 35 | syntax match oasisKey "BetaFeatures:" 36 | syntax match oasisKey "PostConfCommand:" 37 | syntax match oasisKey "FilesAB:" 38 | 39 | syntax match oasisKey2 "\c\s\+Index\$\=:" 40 | syntax match oasisKey2 "\c\s\+Format\$\=:" 41 | syntax match oasisKey2 "\c\s\+TestTools\$\=:" 42 | syntax match oasisKey2 "\c\s\+Description\$\=:" 43 | syntax match oasisKey2 "\c\s\+Pack\$\=:" 44 | syntax match oasisKey2 "\c\s\+Default\$\=:" 45 | syntax match oasisKey2 "\c\s\+Path\$\=:" 46 | syntax match oasisKey2 "\c\s\+Findlibname\$\=:" 47 | syntax match oasisKey2 "\c\s\+Modules\$\=:" 48 | syntax match oasisKey2 "\c\s\+BuildDepends\$\=:" 49 | syntax match oasisKey2 "\c\s\+MainIs\$\=:" 50 | syntax match oasisKey2 "\c\s\+Install\$\=:" 51 | syntax match oasisKey2 "\c\s\+Custom\$\=:" 52 | syntax match oasisKey2 "\c\s\+InternalModules\$\=:" 53 | syntax match oasisKey2 "\c\s\+Build\$\=:" 54 | syntax match oasisKey2 "\c\s\+CompiledObject\$\=:" 55 | syntax match oasisKey2 "\c\s\+Title\$\=:" 56 | syntax match oasisKey2 "\c\s\+Type\$\=:" 57 | syntax match oasisKey2 "\c\s\+FindlibParent\$\=:" 58 | syntax match oasisKey2 "\c\s\+Command\$\=:" 59 | syntax match oasisKey2 "\c\s\+Run\$\=:" 60 | syntax match oasisKey2 "\c\s\+WorkingDirectory\$\=:" 61 | syntax match oasisKey2 "\c\s\+BuildTools+:" 62 | syntax match oasisKey2 "\c\s\+XMETARequires\$\=:" 63 | syntax match oasisKey2 "\c\s\+XMETADescription\$\=:" 64 | syntax match oasisKey2 "\c\s\+XMETAType\$\=:" 65 | syntax match oasisKey2 "\c\s\+XMETAExtraLines\$\=:" 66 | syntax match oasisKey2 "\c\s\+XMETAEnable\$\=:" 67 | syntax match oasisKey2 "\c\s\+InstallDir\$\=:" 68 | syntax match oasisKey2 "\c\s\+XOCamlbuildLibraries\$\=:" 69 | syntax match oasisKey2 "\c\s\+XOCamlbuildPath\$\=:" 70 | syntax match oasisKey2 "\c\s\+XOCamlbuildExtraArgs\$\=:" 71 | syntax match oasisKey2 "\c\s\+XOCamlbuildModules\$\=:" 72 | syntax match oasisKey2 "\c\s\+Type\$\=:" 73 | syntax match oasisKey2 "\c\s\+Location\$\=:" 74 | syntax match oasisKey2 "\c\s\+Branch\$\=:" 75 | syntax match oasisKey2 "\c\s\+Browser\$\=:" 76 | syntax match oasisKey2 "\c\s\+CSources\$\=:" 77 | syntax match oasisKey2 "\c\s\+CCLib\$\=:" 78 | syntax match oasisKey2 "\c\s\+CCOpt\$\=:" 79 | syntax match oasisKey2 "\c\s\+ByteOpt\$\=:" 80 | syntax match oasisKey2 "\c\s\+NativeOpt\$\=:" 81 | syntax match oasisKey2 "\c\s\+Tag\$\=:" 82 | 83 | highlight link oasisSection Keyword 84 | highlight link oasisKey Identifier 85 | highlight link oasisKey2 Function 86 | highlight link oasisTodo Todo 87 | highlight link oasisComment Comment 88 | highlight link oasisPlugin Type 89 | highlight link oasisSpecialFeatures Exception 90 | highlight link oasisOperator Operator 91 | highlight link oasisVariable Statement 92 | highlight link oasisString String 93 | highlight link oasisVersion Number 94 | 95 | let b:current_syntax = "oasis" 96 | -------------------------------------------------------------------------------- /syntax/ocaml.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file 2 | " Language: OCaml 3 | " Filenames: *.ml *.mli *.mll *.mly 4 | " Maintainers: Markus Mottl 5 | " Karl-Heinz Sylla 6 | " Issac Trotts 7 | " URL: https://github.com/ocaml/vim-ocaml 8 | " Last Change: 9 | " 2019 Nov 05 - Accurate type highlighting (Maëlan) 10 | " 2018 Nov 08 - Improved highlighting of operators (Maëlan) 11 | " 2018 Apr 22 - Improved support for PPX (Andrey Popp) 12 | " 2018 Mar 16 - Remove raise, lnot and not from keywords (Étienne Millon, "copy") 13 | " 2017 Apr 11 - Improved matching of negative numbers (MM) 14 | " 2016 Mar 11 - Improved support for quoted strings (Glen Mével) 15 | " 2015 Aug 13 - Allow apostrophes in identifiers (Jonathan Chan, Einar Lielmanis) 16 | " 2015 Jun 17 - Added new "nonrec" keyword (MM) 17 | 18 | " A minor patch was applied to the official version so that object/end 19 | " can be distinguished from begin/end, which is used for indentation, 20 | " and folding. (David Baelde) 21 | 22 | " Quit when a syntax file was already loaded 23 | if exists("b:current_syntax") && b:current_syntax == "ocaml" 24 | finish 25 | endif 26 | 27 | let s:keepcpo = &cpo 28 | set cpo&vim 29 | 30 | " ' can be used in OCaml identifiers 31 | setlocal iskeyword+=' 32 | 33 | " ` is part of the name of polymorphic variants 34 | setlocal iskeyword+=` 35 | 36 | " OCaml is case sensitive. 37 | syn case match 38 | 39 | " Access to the method of an object 40 | syn match ocamlMethod "#" 41 | 42 | " Scripting directives 43 | syn match ocamlScript "^#\<\(quit\|labels\|warnings\|warn_error\|directory\|remove_directory\|cd\|load\|load_rec\|use\|mod_use\|install_printer\|remove_printer\|require\|list\|ppx\|principal\|predicates\|rectypes\|thread\|trace\|untrace\|untrace_all\|print_depth\|print_length\|camlp4o\|camlp4r\|topfind_log\|topfind_verbose\)\>" 44 | 45 | " lowercase identifier - the standard way to match 46 | syn match ocamlLCIdentifier /\<\(\l\|_\)\(\w\|'\)*\>/ 47 | 48 | " Errors 49 | syn match ocamlBraceErr "}" 50 | syn match ocamlBrackErr "\]" 51 | syn match ocamlParenErr ")" 52 | syn match ocamlArrErr "|]" 53 | 54 | syn match ocamlCountErr "\" 55 | syn match ocamlCountErr "\" 56 | 57 | if !exists("ocaml_revised") 58 | syn match ocamlDoErr "\" 59 | endif 60 | 61 | syn match ocamlDoneErr "\" 62 | syn match ocamlThenErr "\" 63 | 64 | " Error-highlighting of "end" without synchronization: 65 | " as keyword or as error (default) 66 | if exists("ocaml_noend_error") 67 | syn match ocamlKeyword "\" 68 | else 69 | syn match ocamlEndErr "\" 70 | endif 71 | 72 | " These keywords are only expected nested in constructions that are handled by 73 | " the type linter, so outside of type contexts we highlight them as errors: 74 | syn match ocamlKwErr "\<\(mutable\|nonrec\|of\|private\)\>" 75 | 76 | " Some convenient clusters 77 | syn cluster ocamlAllErrs contains=@ocamlAENoParen,ocamlParenErr 78 | syn cluster ocamlAENoParen contains=ocamlBraceErr,ocamlBrackErr,ocamlCountErr,ocamlDoErr,ocamlDoneErr,ocamlEndErr,ocamlThenErr,ocamlKwErr 79 | 80 | syn cluster ocamlContained contains=ocamlTodo,ocamlPreDef,ocamlModParam,ocamlModParam1,ocamlModTypePre,ocamlModRHS,ocamlFuncWith,ocamlModTypeRestr,ocamlModTRWith,ocamlWith,ocamlWithRest,ocamlFullMod,ocamlVal 81 | 82 | 83 | " Enclosing delimiters 84 | syn region ocamlNone transparent matchgroup=ocamlEncl start="(" matchgroup=ocamlEncl end=")" contains=ALLBUT,@ocamlContained,ocamlParenErr 85 | syn region ocamlNone transparent matchgroup=ocamlEncl start="{" matchgroup=ocamlEncl end="}" contains=ALLBUT,@ocamlContained,ocamlBraceErr 86 | syn region ocamlNone transparent matchgroup=ocamlEncl start="\[" matchgroup=ocamlEncl end="\]" contains=ALLBUT,@ocamlContained,ocamlBrackErr 87 | syn region ocamlNone transparent matchgroup=ocamlEncl start="\[|" matchgroup=ocamlEncl end="|\]" contains=ALLBUT,@ocamlContained,ocamlArrErr 88 | 89 | 90 | " Comments 91 | syn region ocamlComment start="(\*" end="\*)" contains=@Spell,ocamlComment,ocamlTodo 92 | syn keyword ocamlTodo contained TODO FIXME XXX NOTE 93 | 94 | 95 | " Objects 96 | syn region ocamlEnd matchgroup=ocamlObject start="\" matchgroup=ocamlObject end="\" contains=ALLBUT,@ocamlContained,ocamlEndErr 97 | 98 | 99 | " Blocks 100 | if !exists("ocaml_revised") 101 | syn region ocamlEnd matchgroup=ocamlKeyword start="\" matchgroup=ocamlKeyword end="\" contains=ALLBUT,@ocamlContained,ocamlEndErr 102 | endif 103 | 104 | 105 | " "for" 106 | syn region ocamlNone matchgroup=ocamlKeyword start="\" matchgroup=ocamlKeyword end="\<\(to\|downto\)\>" contains=ALLBUT,@ocamlContained,ocamlCountErr 107 | 108 | 109 | " "do" 110 | if !exists("ocaml_revised") 111 | syn region ocamlDo matchgroup=ocamlKeyword start="\" matchgroup=ocamlKeyword end="\" contains=ALLBUT,@ocamlContained,ocamlDoneErr 112 | endif 113 | 114 | " "if" 115 | syn region ocamlNone matchgroup=ocamlKeyword start="\" matchgroup=ocamlKeyword end="\" contains=ALLBUT,@ocamlContained,ocamlThenErr 116 | 117 | "" PPX nodes 118 | 119 | syn match ocamlPpxIdentifier /\(\[@\{1,3\}\)\@<=\w\+\(\.\w\+\)*/ 120 | syn region ocamlPpx matchgroup=ocamlPpxEncl start="\[@\{1,3\}" contains=TOP end="\]" 121 | 122 | "" Modules 123 | 124 | " "open" 125 | syn match ocamlKeyword "\" skipwhite skipempty nextgroup=ocamlFullMod 126 | 127 | " "include" 128 | syn match ocamlKeyword "\" skipwhite skipempty nextgroup=ocamlModParam,ocamlFullMod 129 | 130 | " "module" - somewhat complicated stuff ;-) 131 | " 2022-10: please document it? 132 | syn region ocamlModule matchgroup=ocamlKeyword start="\" matchgroup=ocamlModule end="\<_\|\u\(\w\|'\)*\>" contains=@ocamlAllErrs,ocamlComment skipwhite skipempty nextgroup=ocamlPreDef 133 | syn region ocamlPreDef start="."me=e-1 end="[a-z:=)]\@=" contained contains=@ocamlAllErrs,ocamlComment,ocamlModParam,ocamlGenMod,ocamlModTypeRestr nextgroup=ocamlModTypePre,ocamlModPreRHS 134 | syn region ocamlModParam start="(\*\@!" end=")" contained contains=ocamlGenMod,ocamlModParam,ocamlModParam1,ocamlSig,ocamlVal 135 | syn match ocamlModParam1 "\<\u\(\w\|'\)*\>" contained skipwhite skipempty 136 | syn match ocamlGenMod "()" contained skipwhite skipempty 137 | 138 | syn match ocamlModTypePre ":" contained skipwhite skipempty nextgroup=ocamlModTRWith,ocamlSig,ocamlFunctor,ocamlModTypeRestr,ocamlModTypeOf 139 | syn match ocamlModTypeRestr "\<\w\(\w\|'\)*\( *\. *\w\(\w\|'\)*\)*\>" contained 140 | 141 | syn match ocamlModPreRHS "=" contained skipwhite skipempty nextgroup=ocamlModParam,ocamlFullMod 142 | syn keyword ocamlKeyword val 143 | syn region ocamlVal matchgroup=ocamlKeyword start="\" matchgroup=ocamlLCIdentifier end="\<\l\(\w\|'\)*\>" contains=@ocamlAllErrs,ocamlComment,ocamlFullMod skipwhite skipempty nextgroup=ocamlModTypePre 144 | syn region ocamlModRHS start="." end=". *\w\|([^*]"me=e-2 contained contains=ocamlComment skipwhite skipempty nextgroup=ocamlModParam,ocamlFullMod 145 | syn match ocamlFullMod "\<\u\(\w\|'\)*\( *\. *\u\(\w\|'\)*\)*" contained skipwhite skipempty nextgroup=ocamlFuncWith 146 | 147 | syn region ocamlFuncWith start="([*)]\@!" end=")" contained contains=ocamlComment,ocamlWith,ocamlStruct skipwhite skipempty nextgroup=ocamlFuncWith 148 | 149 | syn region ocamlModTRWith start="(\*\@!" end=")" contained contains=@ocamlAENoParen,ocamlWith 150 | syn match ocamlWith "\<\(\u\(\w\|'\)* *\. *\)*\w\(\w\|'\)*\>" contained skipwhite skipempty nextgroup=ocamlWithRest 151 | syn region ocamlWithRest start="[^)]" end=")"me=e-1 contained contains=ALLBUT,@ocamlContained 152 | 153 | " "struct" 154 | syn region ocamlStruct matchgroup=ocamlStructEncl start="\<\(module\s\+\)\=struct\>" matchgroup=ocamlStructEncl end="\" contains=ALLBUT,@ocamlContained,ocamlEndErr 155 | 156 | " "sig" 157 | syn region ocamlSig matchgroup=ocamlSigEncl start="\" matchgroup=ocamlSigEncl end="\" contains=ALLBUT,@ocamlContained,ocamlEndErr 158 | 159 | " "functor" 160 | syn region ocamlFunctor start="\" matchgroup=ocamlKeyword end="->" contains=@ocamlAllErrs,ocamlComment,ocamlModParam,ocamlGenMod skipwhite skipempty nextgroup=ocamlStruct,ocamlSig,ocamlFuncWith,ocamlFunctor 161 | 162 | " "module type" 163 | syn region ocamlModTypeOf start="\" matchgroup=ocamlModule end="\<\w\(\w\|'\)*\>" contains=ocamlComment skipwhite skipempty nextgroup=ocamlMTDef 164 | syn match ocamlMTDef "=\s*\w\(\w\|'\)*\>"hs=s+1,me=s+1 skipwhite skipempty nextgroup=ocamlFullMod 165 | 166 | " Quoted strings 167 | syn region ocamlString matchgroup=ocamlQuotedStringDelim start="{\z\([a-z_]*\)|" end="|\z1}" contains=@Spell 168 | syn region ocamlString matchgroup=ocamlQuotedStringDelim start="{%[a-z_]\+\(\.[a-z_]\+\)\?\( \z\([a-z_]\+\)\)\?|" end="|\z1}" contains=@Spell 169 | 170 | syn keyword ocamlKeyword and as assert class 171 | syn keyword ocamlKeyword else 172 | syn keyword ocamlKeyword external 173 | syn keyword ocamlKeyword in inherit initializer 174 | syn keyword ocamlKeyword lazy let match 175 | syn keyword ocamlKeyword method new 176 | syn keyword ocamlKeyword parser rec 177 | syn keyword ocamlKeyword try 178 | syn keyword ocamlKeyword virtual when while with 179 | 180 | " Keywords which are handled by the type linter: 181 | " as (within a type equation) 182 | " constraint exception mutable nonrec of private type 183 | 184 | " The `fun` keyword has special treatment because of the syntax `fun … : t -> e` 185 | " where `->` ends the type context rather than being part of it; to handle that, 186 | " we blacklist the ocamlTypeAnnot matchgroup, and we plug ocamlFunTypeAnnot 187 | " instead (later in this file, by using containedin=ocamlFun): 188 | syn region ocamlFun matchgroup=ocamlKeyword start='\' matchgroup=ocamlArrow end='->' 189 | \ contains=ALLBUT,@ocamlContained,ocamlArrow,ocamlInfixOp,ocamlTypeAnnot 190 | 191 | if exists("ocaml_revised") 192 | syn keyword ocamlKeyword do value 193 | syn keyword ocamlBoolean True False 194 | else 195 | syn keyword ocamlKeyword function 196 | syn keyword ocamlBoolean true false 197 | endif 198 | 199 | syn match ocamlEmptyConstructor "(\s*)" 200 | syn match ocamlEmptyConstructor "\[\s*\]" 201 | syn match ocamlEmptyConstructor "\[|\s*>|]" 202 | syn match ocamlEmptyConstructor "\[<\s*>\]" 203 | syn match ocamlConstructor "\u\(\w\|'\)*\>" 204 | 205 | " Polymorphic variants 206 | syn match ocamlConstructor "`\w\(\w\|'\)*\>" 207 | 208 | " Module prefix 209 | syn match ocamlModPath "\u\(\w\|'\)* *\."he=e-1 210 | 211 | syn match ocamlCharacter "'\\\d\d\d'\|'\\[\'ntbr]'\|'.'" 212 | syn match ocamlCharacter "'\\x\x\x'" 213 | syn match ocamlCharErr "'\\\d\d'\|'\\\d'" 214 | syn match ocamlCharErr "'\\[^\'ntbr]'" 215 | syn region ocamlString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@Spell 216 | 217 | syn match ocamlAnyVar "\<_\>" 218 | syn match ocamlKeyChar "|]\@!" 219 | syn match ocamlKeyChar ";" 220 | syn match ocamlKeyChar "\~" 221 | syn match ocamlKeyChar "?" 222 | 223 | " NOTE: for correct precedence, the rule for ";;" must come after that for ";" 224 | syn match ocamlTopStop ";;" 225 | 226 | "" Operators 227 | 228 | " The grammar of operators is found there: 229 | " https://caml.inria.fr/pub/docs/manual-ocaml/names.html#operator-name 230 | " https://caml.inria.fr/pub/docs/manual-ocaml/extn.html#s:ext-ops 231 | " https://caml.inria.fr/pub/docs/manual-ocaml/extn.html#s:index-operators 232 | " = is both an operator name and a keyword, we let the user choose how 233 | " to display it (has to be declared before regular infix operators): 234 | syn match ocamlEqual "=" 235 | " Custom indexing operators: 236 | syn region ocamlIndexing matchgroup=ocamlIndexingOp 237 | \ start="\.[~?!:|&$%=>@^/*+-][~?!.:|&$%<=>@^*/+-]*\_s*(" 238 | \ end=")\(\_s*<-\)\?" 239 | \ contains=ALLBUT,@ocamlContained,ocamlParenErr 240 | syn region ocamlIndexing matchgroup=ocamlIndexingOp 241 | \ start="\.[~?!:|&$%=>@^/*+-][~?!.:|&$%<=>@^*/+-]*\_s*\[" 242 | \ end="]\(\_s*<-\)\?" 243 | \ contains=ALLBUT,@ocamlContained,ocamlBrackErr 244 | syn region ocamlIndexing matchgroup=ocamlIndexingOp 245 | \ start="\.[~?!:|&$%=>@^/*+-][~?!.:|&$%<=>@^*/+-]*\_s*{" 246 | \ end="}\(\_s*<-\)\?" 247 | \ contains=ALLBUT,@ocamlContained,ocamlBraceErr 248 | " Extension operators (has to be declared before regular infix operators): 249 | syn match ocamlExtensionOp "#[#~?!.:|&$%<=>@^*/+-]\+" 250 | " Infix and prefix operators: 251 | syn match ocamlPrefixOp "![~?!.:|&$%<=>@^*/+-]*" 252 | syn match ocamlPrefixOp "[~?][~?!.:|&$%<=>@^*/+-]\+" 253 | syn match ocamlInfixOp "[&$%<>@^*/+-][~?!.:|&$%<=>@^*/+-]*" 254 | syn match ocamlInfixOp "[|=][~?!.:|&$%<=>@^*/+-]\+" 255 | syn match ocamlInfixOp "#[~?!.:|&$%<=>@^*/+-]\+#\@!" 256 | syn match ocamlInfixOp "!=[~?!.:|&$%<=>@^*/+-]\@!" 257 | syn keyword ocamlInfixOpKeyword asr land lor lsl lsr lxor mod or 258 | " := is technically an infix operator, but we may want to show it as a keyword 259 | " (somewhat analogously to = for let‐bindings and <- for assignations): 260 | syn match ocamlRefAssign ":=" 261 | " :: is technically not an operator, but we may want to show it as such: 262 | syn match ocamlCons "::" 263 | " -> and <- are keywords, not operators (but can appear in longer operators): 264 | syn match ocamlArrow "->[~?!.:|&$%<=>@^*/+-]\@!" 265 | if exists("ocaml_revised") 266 | syn match ocamlErr "<-[~?!.:|&$%<=>@^*/+-]\@!" 267 | else 268 | syn match ocamlKeyChar "<-[~?!.:|&$%<=>@^*/+-]\@!" 269 | endif 270 | 271 | " Script shebang (has to be declared after operators) 272 | syn match ocamlShebang "\%1l^#!.*$" 273 | 274 | syn match ocamlNumber "-\=\<\d\(_\|\d\)*[l|L|n]\?\>" 275 | syn match ocamlNumber "-\=\<0[x|X]\(\x\|_\)\+[l|L|n]\?\>" 276 | syn match ocamlNumber "-\=\<0[o|O]\(\o\|_\)\+[l|L|n]\?\>" 277 | syn match ocamlNumber "-\=\<0[b|B]\([01]\|_\)\+[l|L|n]\?\>" 278 | syn match ocamlFloat "-\=\<\d\(_\|\d\)*\.\?\(_\|\d\)*\([eE][-+]\=\d\(_\|\d\)*\)\=\>" 279 | 280 | " Labels 281 | syn match ocamlLabel "[~?]\(\l\|_\)\(\w\|'\)*:\?" 282 | syn region ocamlLabel transparent matchgroup=ocamlLabel start="[~?](\(\l\|_\)\(\w\|'\)*"lc=2 end=")"me=e-1 contains=ALLBUT,@ocamlContained,ocamlParenErr 283 | 284 | """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 285 | 286 | "" Type contexts 287 | 288 | " How we recognize type contexts is explained in `type-linter-notes.md` 289 | " and a test suite is found in `type-linter-test.ml`. 290 | " 291 | " ocamlTypeExpr is the cluster of things that can make up a type expression 292 | " (in a loose sense, e.g. the “as” keyword and universal quantification are 293 | " included). Regions containing a type expression use it like this: 294 | " 295 | " contains=@ocamlTypeExpr,... 296 | " 297 | " ocamlTypeContained is the cluster of things that can be found in a type 298 | " expression or a type definition. It is not expected to be used in any region, 299 | " it exists solely for throwing things in it that should not pollute the main 300 | " linter. 301 | " 302 | " Both clusters are filled in incrementally. Every match group that is not to be 303 | " found at the main level must be declared as “contained” and added to either 304 | " ocamlTypeExpr or ocamlTypeContained. 305 | " 306 | " In these clusters we don’t put generic things that can also be found elswhere, 307 | " i.e. ocamlComment and ocamlPpx, because everything that is in these clusters 308 | " is also put in ocamlContained and thus ignored by the main linter. 309 | 310 | "syn cluster ocamlTypeExpr contains= 311 | syn cluster ocamlTypeContained contains=@ocamlTypeExpr 312 | syn cluster ocamlContained add=@ocamlTypeContained 313 | 314 | " We’ll use a “catch-all” highlighting group to show as error anything that is 315 | " not matched more specifically; we don’t want spaces to be reported as errors 316 | " (different background color), so we just catch them here: 317 | syn cluster ocamlTypeExpr add=ocamlTypeBlank 318 | syn match ocamlTypeBlank contained "\_s\+" 319 | hi link ocamlTypeBlank NONE 320 | 321 | " NOTE: Carefully avoid catching "(*" here. 322 | syn cluster ocamlTypeExpr add=ocamlTypeParen 323 | syn region ocamlTypeParen contained transparent 324 | \ matchgroup=ocamlEncl start="(\*\@!" 325 | \ matchgroup=ocamlEncl end=")" 326 | \ contains=@ocamlTypeExpr,ocamlComment,ocamlPpx 327 | 328 | syn cluster ocamlTypeExpr add=ocamlTypeKeyChar,ocamlTypeAs 329 | syn match ocamlTypeKeyChar contained "->" 330 | syn match ocamlTypeKeyChar contained "\*" 331 | syn match ocamlTypeKeyChar contained "#" 332 | syn match ocamlTypeKeyChar contained "," 333 | syn match ocamlTypeKeyChar contained "\." 334 | syn keyword ocamlTypeAs contained as 335 | hi link ocamlTypeAs ocamlKeyword 336 | 337 | syn cluster ocamlTypeExpr add=ocamlTypeVariance 338 | syn match ocamlTypeVariance contained "[-+!]\ze *\('\|\<_\>\)" 339 | syn match ocamlTypeVariance contained "[-+] *!\+\ze *\('\|\<_\>\)" 340 | syn match ocamlTypeVariance contained "! *[-+]\+\ze *\('\|\<_\>\)" 341 | 342 | syn cluster ocamlTypeContained add=ocamlTypeEq 343 | syn match ocamlTypeEq contained "[+:]\?=" 344 | hi link ocamlTypeEq ocamlKeyChar 345 | 346 | syn cluster ocamlTypeExpr add=ocamlTypeVar,ocamlTypeConstr,ocamlTypeAnyVar,ocamlTypeBuiltin 347 | syn match ocamlTypeVar contained "'\(\l\|_\)\(\w\|'\)*\>" 348 | syn match ocamlTypeConstr contained "\<\(\l\|_\)\(\w\|'\)*\>" 349 | " NOTE: for correct precedence, the rule for the wildcard (ocamlTypeAnyVar) 350 | " must come after the rule for type constructors (ocamlTypeConstr). 351 | syn match ocamlTypeAnyVar contained "\<_\>" 352 | " NOTE: For correct precedence, these builtin names must occur after the rule 353 | " for type constructors (ocamlTypeConstr) but before the rule for non-optional 354 | " labeled arguments (ocamlTypeLabel). For the latter to take precedence over 355 | " these builtin names, we use “syn match” here instead of “syn keyword”. 356 | syn match ocamlTypeBuiltin contained "\" 357 | syn match ocamlTypeBuiltin contained "\" 358 | syn match ocamlTypeBuiltin contained "\" 359 | syn match ocamlTypeBuiltin contained "\" 360 | syn match ocamlTypeBuiltin contained "\" 361 | syn match ocamlTypeBuiltin contained "\" 362 | syn match ocamlTypeBuiltin contained "\" 363 | syn match ocamlTypeBuiltin contained "\" 364 | syn match ocamlTypeBuiltin contained "\" 365 | syn match ocamlTypeBuiltin contained "\" 366 | syn match ocamlTypeBuiltin contained "\" 367 | syn match ocamlTypeBuiltin contained "\" 368 | syn match ocamlTypeBuiltin contained "\" 369 | syn match ocamlTypeBuiltin contained "\" 370 | syn match ocamlTypeBuiltin contained "\" 371 | syn match ocamlTypeBuiltin contained "\" 372 | syn match ocamlTypeBuiltin contained "\" 373 | syn match ocamlTypeBuiltin contained "\" 374 | syn match ocamlTypeBuiltin contained "\" 375 | syn match ocamlTypeBuiltin contained "\" 376 | syn match ocamlTypeBuiltin contained "\" 377 | syn match ocamlTypeBuiltin contained "\" 378 | syn match ocamlTypeBuiltin contained "\" 379 | 380 | syn cluster ocamlTypeExpr add=ocamlTypeLabel 381 | syn match ocamlTypeLabel contained "?\?\(\l\|_\)\(\w\|'\)*\_s*:[>=]\@!" 382 | hi link ocamlTypeLabel ocamlLabel 383 | 384 | " Object type 385 | syn cluster ocamlTypeExpr add=ocamlTypeObject 386 | syn region ocamlTypeObject contained 387 | \ matchgroup=ocamlEncl start="<" 388 | \ matchgroup=ocamlEncl end=">" 389 | \ contains=ocamlTypeObjectDots,ocamlLCIdentifier,ocamlTypeObjectAnnot,ocamlTypeBlank,ocamlComment,ocamlPpx 390 | hi link ocamlTypeObject ocamlTypeCatchAll 391 | syn cluster ocamlTypeContained add=ocamlTypeObjectDots 392 | syn match ocamlTypeObjectDots contained "\.\." 393 | hi link ocamlTypeObjectDots ocamlKeyChar 394 | syn cluster ocamlTypeContained add=ocamlTypeObjectAnnot 395 | syn region ocamlTypeObjectAnnot contained 396 | \ matchgroup=ocamlKeyChar start=":" 397 | \ matchgroup=ocamlKeyChar end=";\|>\@=" 398 | \ contains=@ocamlTypeExpr,ocamlComment,ocamlPpx 399 | hi link ocamlTypeObjectAnnot ocamlTypeCatchAll 400 | 401 | " Record type definition 402 | syn cluster ocamlTypeContained add=ocamlTypeRecordDecl 403 | syn region ocamlTypeRecordDecl contained 404 | \ matchgroup=ocamlEncl start="{" 405 | \ matchgroup=ocamlEncl end="}" 406 | \ contains=ocamlTypeMutable,ocamlLCIdentifier,ocamlTypeRecordAnnot,ocamlTypeBlank,ocamlComment,ocamlPpx 407 | hi link ocamlTypeRecordDecl ocamlTypeCatchAll 408 | syn cluster ocamlTypeContained add=ocamlTypeMutable 409 | syn keyword ocamlTypeMutable contained mutable 410 | hi link ocamlTypeMutable ocamlKeyword 411 | syn cluster ocamlTypeContained add=ocamlTypeRecordAnnot 412 | syn region ocamlTypeRecordAnnot contained 413 | \ matchgroup=ocamlKeyChar start=":" 414 | \ matchgroup=ocamlKeyChar end=";\|}\@=" 415 | \ contains=@ocamlTypeExpr,ocamlComment,ocamlPpx 416 | hi link ocamlTypeRecordAnnot ocamlTypeCatchAll 417 | 418 | " Polymorphic variant types 419 | " NOTE: Carefully avoid catching "[@" here. 420 | syn cluster ocamlTypeExpr add=ocamlTypeVariant 421 | syn region ocamlTypeVariant contained 422 | \ matchgroup=ocamlEncl start="\[>" start="\[<" start="\[@\@!" 423 | \ matchgroup=ocamlEncl end="\]" 424 | \ contains=ocamlTypeVariantKeyChar,ocamlTypeVariantConstr,ocamlTypeVariantAnnot,ocamlTypeBlank,ocamlComment,ocamlPpx 425 | hi link ocamlTypeVariant ocamlTypeCatchAll 426 | syn cluster ocamlTypeContained add=ocamlTypeVariantKeyChar 427 | syn match ocamlTypeVariantKeyChar contained "|" 428 | syn match ocamlTypeVariantKeyChar contained ">" 429 | hi link ocamlTypeVariantKeyChar ocamlKeyChar 430 | syn cluster ocamlTypeContained add=ocamlTypeVariantConstr 431 | syn match ocamlTypeVariantConstr contained "`\w\(\w\|'\)*\>" 432 | hi link ocamlTypeVariantConstr ocamlConstructor 433 | syn cluster ocamlTypeContained add=ocamlTypeVariantAnnot 434 | syn region ocamlTypeVariantAnnot contained 435 | \ matchgroup=ocamlKeyword start="\" 436 | \ matchgroup=ocamlKeyChar end="|\|>\|\]\@=" 437 | \ contains=@ocamlTypeExpr,ocamlTypeAmp,ocamlComment,ocamlPpx 438 | hi link ocamlTypeVariantAnnot ocamlTypeCatchAll 439 | syn cluster ocamlTypeContained add=ocamlTypeAmp 440 | syn match ocamlTypeAmp contained "&" 441 | hi link ocamlTypeAmp ocamlTypeKeyChar 442 | 443 | " Sum type definition 444 | syn cluster ocamlTypeContained add=ocamlTypeSumDecl 445 | syn region ocamlTypeSumDecl contained 446 | \ matchgroup=ocamlTypeSumBar start="|" 447 | \ matchgroup=ocamlTypeSumConstr start="\<\u\(\w\|'\)*\>" 448 | \ matchgroup=ocamlTypeSumConstr start="\" start="\" 449 | \ matchgroup=ocamlTypeSumConstr start="(\_s*)" start="\[\_s*]" start="(\_s*::\_s*)" 450 | \ matchgroup=NONE end="\(\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|)\|]\|}\|;\|;;\|=\)\@=" 451 | \ matchgroup=NONE end="\(\\)\@=" 452 | \ contains=ocamlTypeSumBar,ocamlTypeSumConstr,ocamlTypeSumAnnot,ocamlTypeBlank,ocamlComment,ocamlPpx 453 | hi link ocamlTypeSumDecl ocamlTypeCatchAll 454 | syn cluster ocamlTypeContained add=ocamlTypeSumBar 455 | syn match ocamlTypeSumBar contained "|" 456 | hi link ocamlTypeSumBar ocamlKeyChar 457 | syn cluster ocamlTypeContained add=ocamlTypeSumConstr 458 | syn match ocamlTypeSumConstr contained "\<\u\(\w\|'\)*\>" 459 | syn match ocamlTypeSumConstr contained "\" 460 | syn match ocamlTypeSumConstr contained "\" 461 | syn match ocamlTypeSumConstr contained "(\_s*)" 462 | syn match ocamlTypeSumConstr contained "\[\_s*]" 463 | syn match ocamlTypeSumConstr contained "(\_s*::\_s*)" 464 | hi link ocamlTypeSumConstr ocamlConstructor 465 | syn cluster ocamlTypeContained add=ocamlTypeSumAnnot 466 | syn region ocamlTypeSumAnnot contained 467 | \ matchgroup=ocamlKeyword start="\" 468 | \ matchgroup=ocamlKeyChar start=":" 469 | \ matchgroup=NONE end="|\@=" 470 | \ matchgroup=NONE end="\(\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|)\|]\|}\|;\|;;\)\@=" 471 | \ matchgroup=NONE end="\(\\)\@=" 472 | \ contains=@ocamlTypeExpr,ocamlTypeRecordDecl,ocamlComment,ocamlPpx 473 | hi link ocamlTypeSumAnnot ocamlTypeCatchAll 474 | 475 | " Type context opened by “type” (type definition), “constraint” (type 476 | " constraint) and “exception” (exception definition) 477 | syn region ocamlTypeDef 478 | \ matchgroup=ocamlKeyword start="\\(\_s\+\\)\?\|\\|\" 479 | \ matchgroup=NONE end="\(\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|)\|]\|}\|;\|;;\)\@=" 480 | \ contains=@ocamlTypeExpr,ocamlTypeEq,ocamlTypePrivate,ocamlTypeDefDots,ocamlTypeRecordDecl,ocamlTypeSumDecl,ocamlTypeDefAnd,ocamlComment,ocamlPpx 481 | hi link ocamlTypeDef ocamlTypeCatchAll 482 | syn cluster ocamlTypeContained add=ocamlTypePrivate 483 | syn keyword ocamlTypePrivate contained private 484 | hi link ocamlTypePrivate ocamlKeyword 485 | syn cluster ocamlTypeContained add=ocamlTypeDefAnd 486 | syn keyword ocamlTypeDefAnd contained and 487 | hi link ocamlTypeDefAnd ocamlKeyword 488 | syn cluster ocamlTypeContained add=ocamlTypeDefDots 489 | syn match ocamlTypeDefDots contained "\.\." 490 | hi link ocamlTypeDefDots ocamlKeyChar 491 | 492 | " When "exception" is preceded by "with", "|" or "(", that’s not an exception 493 | " definition but an exception pattern; we simply highlight the keyword without 494 | " starting a type context. 495 | " NOTE: These rules must occur after that for "exception". 496 | syn match ocamlKeyword "\"lc=4 497 | syn match ocamlKeyword "|\_s*exception\>"lc=1 498 | syn match ocamlKeyword "(\_s*exception\>"lc=1 499 | 500 | " Type context opened by “:” (countless kinds of type annotations) and “:>” 501 | " (type coercions) 502 | syn region ocamlTypeAnnot matchgroup=ocamlKeyChar start=":\(>\|\_s*type\>\|[>:=]\@!\)" 503 | \ matchgroup=NONE end="\(\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|\\|)\|]\|}\|;\|;;\)\@=" 504 | \ matchgroup=NONE end="\(;\|}\)\@=" 505 | \ matchgroup=NONE end="\(=\|:>\)\@=" 506 | \ contains=@ocamlTypeExpr,ocamlComment,ocamlPpx 507 | hi link ocamlTypeAnnot ocamlTypeCatchAll 508 | 509 | " Type annotation that gives the return type of a `fun` keyword 510 | " (the type context is ended by `->`) 511 | syn cluster ocamlTypeContained add=ocamlFunTypeAnnot 512 | syn region ocamlFunTypeAnnot contained containedin=ocamlFun 513 | \ matchgroup=ocamlKeyChar start=":" 514 | \ matchgroup=NONE end="\(->\)\@=" 515 | \ contains=@ocamlTypeExpr,ocamlComment,ocamlPpx 516 | hi link ocamlFunTypeAnnot ocamlTypeCatchAll 517 | 518 | " Module paths (including functors) in types. 519 | " NOTE: This rule must occur after the rule for ocamlTypeSumDecl as it must take 520 | " precedence over it (otherwise the module name would be mistakenly highlighted 521 | " as a constructor). 522 | " NOTE: Carefully avoid catching "(*" here. 523 | syn cluster ocamlTypeExpr add=ocamlTypeModPath 524 | syn match ocamlTypeModPath contained "\<\u\(\w\|'\)*\_s*\." 525 | syn region ocamlTypeModPath contained transparent 526 | \ matchgroup=ocamlModPath start="\<\u\(\w\|'\)*\_s*(\*\@!" 527 | \ matchgroup=ocamlModPath end=")\_s*\." 528 | \ contains=ocamlTypeDotlessModPath,ocamlTypeBlank,ocamlComment,ocamlPpx 529 | hi link ocamlTypeModPath ocamlModPath 530 | syn cluster ocamlTypeContained add=ocamlTypeDotlessModPath 531 | syn match ocamlTypeDotlessModPath contained "\<\u\(\w\|'\)*\_s*\.\?" 532 | syn region ocamlTypeDotlessModPath contained transparent 533 | \ matchgroup=ocamlModPath start="\<\u\(\w\|'\)*\_s*(\*\@!" 534 | \ matchgroup=ocamlModPath end=")\_s*\.\?" 535 | \ contains=ocamlTypeDotlessModPath,ocamlTypeBlank,ocamlComment,ocamlPpx 536 | hi link ocamlTypeDotlessModPath ocamlTypeModPath 537 | 538 | """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 539 | 540 | " Synchronization 541 | syn sync minlines=50 542 | syn sync maxlines=500 543 | 544 | if !exists("ocaml_revised") 545 | syn sync match ocamlDoSync grouphere ocamlDo "\" 546 | syn sync match ocamlDoSync groupthere ocamlDo "\" 547 | endif 548 | 549 | if exists("ocaml_revised") 550 | syn sync match ocamlEndSync grouphere ocamlEnd "\<\(object\)\>" 551 | else 552 | syn sync match ocamlEndSync grouphere ocamlEnd "\<\(begin\|object\)\>" 553 | endif 554 | 555 | syn sync match ocamlEndSync groupthere ocamlEnd "\" 556 | syn sync match ocamlStructSync grouphere ocamlStruct "\" 557 | syn sync match ocamlStructSync groupthere ocamlStruct "\" 558 | syn sync match ocamlSigSync grouphere ocamlSig "\" 559 | syn sync match ocamlSigSync groupthere ocamlSig "\" 560 | 561 | " Define the default highlighting. 562 | 563 | hi def link ocamlBraceErr Error 564 | hi def link ocamlBrackErr Error 565 | hi def link ocamlParenErr Error 566 | hi def link ocamlArrErr Error 567 | 568 | hi def link ocamlCountErr Error 569 | hi def link ocamlDoErr Error 570 | hi def link ocamlDoneErr Error 571 | hi def link ocamlEndErr Error 572 | hi def link ocamlThenErr Error 573 | hi def link ocamlKwErr Error 574 | 575 | hi def link ocamlCharErr Error 576 | 577 | hi def link ocamlErr Error 578 | 579 | hi def link ocamlComment Comment 580 | hi def link ocamlShebang ocamlComment 581 | 582 | hi def link ocamlModPath Include 583 | hi def link ocamlObject Include 584 | hi def link ocamlModule Include 585 | hi def link ocamlModParam1 Include 586 | hi def link ocamlGenMod Include 587 | hi def link ocamlFullMod Include 588 | hi def link ocamlFuncWith Include 589 | hi def link ocamlModParam Include 590 | hi def link ocamlModTypeRestr Include 591 | hi def link ocamlWith Include 592 | hi def link ocamlMTDef Include 593 | hi def link ocamlSigEncl ocamlModule 594 | hi def link ocamlStructEncl ocamlModule 595 | 596 | hi def link ocamlScript Include 597 | 598 | hi def link ocamlConstructor Constant 599 | hi def link ocamlEmptyConstructor ocamlConstructor 600 | 601 | hi def link ocamlVal Keyword 602 | hi def link ocamlModTypePre Keyword 603 | hi def link ocamlModPreRHS Keyword 604 | hi def link ocamlFunctor Keyword 605 | hi def link ocamlModTypeOf Keyword 606 | hi def link ocamlKeyword Keyword 607 | hi def link ocamlMethod Include 608 | hi def link ocamlArrow Keyword 609 | hi def link ocamlKeyChar Keyword 610 | hi def link ocamlAnyVar Keyword 611 | hi def link ocamlTopStop Keyword 612 | 613 | hi def link ocamlRefAssign ocamlKeyChar 614 | hi def link ocamlEqual ocamlKeyChar 615 | hi def link ocamlCons ocamlInfixOp 616 | 617 | hi def link ocamlPrefixOp ocamlOperator 618 | hi def link ocamlInfixOp ocamlOperator 619 | hi def link ocamlExtensionOp ocamlOperator 620 | hi def link ocamlIndexingOp ocamlOperator 621 | 622 | if exists("ocaml_highlight_operators") 623 | hi def link ocamlInfixOpKeyword ocamlOperator 624 | hi def link ocamlOperator Operator 625 | else 626 | hi def link ocamlInfixOpKeyword Keyword 627 | endif 628 | 629 | hi def link ocamlBoolean Boolean 630 | hi def link ocamlCharacter Character 631 | hi def link ocamlNumber Number 632 | hi def link ocamlFloat Float 633 | hi def link ocamlString String 634 | hi def link ocamlQuotedStringDelim Identifier 635 | 636 | hi def link ocamlLabel Identifier 637 | 638 | " Type linting groups that the user can customize: 639 | " - ocamlTypeCatchAll: anything in a type context that is not caught by more 640 | " specific rules (in principle, this should only match syntax errors) 641 | " - ocamlTypeConstr: type constructors 642 | " - ocamlTypeBuiltin: builtin type constructors (like int or list) 643 | " - ocamlTypeVar: type variables ('a) 644 | " - ocamlTypeAnyVar: wildcard (_) 645 | " - ocamlTypeVariance: variance and injectivity indications (+'a, !'a) 646 | " - ocamlTypeKeyChar: symbols such as -> and * 647 | " Default values below mimick the behavior before the type linter was 648 | " implemented, but now we can do better. :-) 649 | hi def link ocamlTypeCatchAll Error 650 | hi def link ocamlTypeConstr NONE 651 | hi def link ocamlTypeBuiltin Type 652 | hi def link ocamlTypeVar NONE 653 | hi def link ocamlTypeAnyVar NONE 654 | hi def link ocamlTypeVariance ocamlKeyChar 655 | hi def link ocamlTypeKeyChar ocamlKeyChar 656 | 657 | hi def link ocamlTodo Todo 658 | 659 | hi def link ocamlEncl Keyword 660 | 661 | hi def link ocamlPpxEncl ocamlEncl 662 | 663 | let b:current_syntax = "ocaml" 664 | 665 | let &cpo = s:keepcpo 666 | unlet s:keepcpo 667 | 668 | " vim: ts=8 669 | -------------------------------------------------------------------------------- /syntax/ocamlbuild_tags.vim: -------------------------------------------------------------------------------- 1 | if exists("b:current_syntax") 2 | finish 3 | endif 4 | 5 | syn keyword ocamlbuild_tagsOperator ",\|:\|-\|(\|)" 6 | syn keyword ocamlbuild_tagsTodo FIXME NOTE NOTES TODO XXX contained 7 | 8 | syn keyword ocamlbuild_tagsKeyword1 true annot bin_annot traverse not_hygienic custom package include debug principal strict_sequence strict_formats short_paths or no_alias_deps safe_string warn syntax thread 9 | syn match ocamlbuild_tagsKeyword2 "for-pack" 10 | 11 | syn match ocamlbuild_tagsOr "or" contained 12 | 13 | syn region ocamlbuild_tagsString start=/"/ end=/"/ 14 | syn region ocamlbuild_tagsPattern start=// contains=ocamlbuild_tagsGlob,ocamlbuild_tagsAlt,ocamlbuild_tagsOr 15 | 16 | syn match ocamlbuild_tagsComment "#.*$" contains=ocamlbuild_tagsTodo,@Spell 17 | 18 | syn match ocamlbuild_tagsGlob "\*\|\*\*\|\/" contained 19 | 20 | syn match ocamlbuild_tagsComma "," 21 | syn region ocamlbuild_tagsAlt start=/{/ end=/}/ contains=ocamlbuild_tagsComma contained 22 | 23 | syn match ocamlbuild_tagsFindlibPkg "\vpkg_[a-zA-Z_.]+" 24 | 25 | hi! link ocamlbuild_tagsKeyword1 Keyword 26 | hi! link ocamlbuild_tagsKeyword2 Keyword 27 | hi! link ocamlbuild_tagsOr Keyword 28 | 29 | hi! link ocamlbuild_tagsString String 30 | hi! link ocamlbuild_tagsPattern Statement 31 | 32 | hi! link ocamlbuild_tagsGlob Operator 33 | hi! link ocamlbuild_tagsOperator Operator 34 | hi! link ocamlbuild_tagsComma Operator 35 | 36 | hi! link ocamlbuild_tagsComment Comment 37 | 38 | hi link ocamlbuild_tagsFindlibPkg Identifier 39 | 40 | let b:current_syntax = "ocamlbuild_tags" 41 | -------------------------------------------------------------------------------- /syntax/ocpbuild.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file 2 | " Language: ocp-build files 3 | " Maintainer: Florent Monnier 4 | " Latest Revision: 14 September 2013 5 | 6 | if exists("b:current_syntax") 7 | finish 8 | endif 9 | 10 | syn keyword ocpKeywords begin end pack 11 | syn keyword ocpKeywords if then else 12 | 13 | syn keyword ocpBlockKind library syntax objects program test 14 | 15 | syn keyword ocpFields files generated dirname archive 16 | syn keyword ocpFields requires bundle 17 | syn keyword ocpFields tests test_dir test_args test_benchmark 18 | syn keyword ocpFields bytecomp bytelink link 19 | syn keyword ocpFields has_asm nopervasives sort 20 | syn keyword ocpFields comp ccopt byte has_byte 21 | syn keyword ocpFields version authors license copyright 22 | syn keyword ocpFields lib_files install installed 23 | 24 | syn keyword ocpPreProc test_exit ocp2ml env_strings 25 | syn keyword ocpPreProc ocaml_major_version 26 | syn keyword ocpPreProc system 27 | 28 | " Strings 29 | syn region ocpString start=+"+ end=+"+ 30 | 31 | " Comments 32 | syn keyword ocpTodo TODO XXX FIXME BUG contained 33 | syn region ocpComment start="(\*" end="\*)" contains=ocpTodo 34 | 35 | " Usual Values 36 | syn keyword ocpNumber None 37 | syn keyword ocpNumber true 38 | syn keyword ocpNumber false 39 | 40 | hi def link ocpTodo Todo 41 | hi def link ocpComment Comment 42 | hi def link ocpString String 43 | hi def link ocpBlockKind Identifier 44 | hi def link ocpNumber Number 45 | hi def link ocpFields Structure 46 | hi def link ocpKeywords Keyword 47 | hi def link ocpPreProc PreProc 48 | 49 | let b:current_syntax = "ocpbuild" 50 | 51 | -------------------------------------------------------------------------------- /syntax/ocpbuildroot.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file 2 | " Language: ocp-build.root files 3 | " Maintainer: Florent Monnier 4 | " Latest Revision: 14 September 2013 5 | 6 | if exists("b:current_syntax") 7 | finish 8 | endif 9 | 10 | " Keywords 11 | syn keyword ocprKeywords digest 12 | syn keyword ocprKeywords verbosity 13 | syn keyword ocprKeywords njobs 14 | syn keyword ocprKeywords autoscan 15 | syn keyword ocprKeywords bytecode 16 | syn keyword ocprKeywords native 17 | syn keyword ocprKeywords meta_dirnames 18 | syn keyword ocprKeywords install_destdir 19 | syn keyword ocprKeywords install_bin 20 | syn keyword ocprKeywords install_lib 21 | syn keyword ocprKeywords install_data 22 | syn keyword ocprKeywords install_doc 23 | syn keyword ocprKeywords ocamllib 24 | syn keyword ocprKeywords use_ocamlfind 25 | syn keyword ocprKeywords ocpbuild_version 26 | syn keyword ocprKeywords project_external_dirs 27 | syn keyword ocprKeywords files 28 | syn keyword ocprKeywords install_docdir 29 | syn keyword ocprKeywords install_datadir 30 | syn keyword ocprKeywords install_libdir 31 | syn keyword ocprKeywords install_bindir 32 | syn keyword ocprKeywords install_metadir 33 | 34 | syn keyword ocprNumber None 35 | syn keyword ocprNumber true 36 | syn keyword ocprNumber false 37 | 38 | " Strings 39 | syn match ocprString "\".\{-}\"" 40 | 41 | " Comments 42 | syn keyword ocprTodo TODO XXX FIXME BUG contained 43 | syn region ocprComment start="(\*" end="\*)" contains=ocprTodo 44 | 45 | 46 | hi def link ocprKeywords Keyword 47 | hi def link ocprTodo Todo 48 | hi def link ocprComment Comment 49 | hi def link ocprString String 50 | hi def link ocprNumber Number 51 | 52 | let b:current_syntax = "ocpbuildroot" 53 | 54 | -------------------------------------------------------------------------------- /syntax/omake.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file 2 | " Language: OMakefile 3 | 4 | " For version 5.x: Clear all syntax items 5 | " For version 6.x: Quit when a syntax file was already loaded 6 | if exists("b:current_syntax") 7 | finish 8 | endif 9 | 10 | syn match omakeRuleOption +:\(optional\|exists\|effects\|scanner\|value\):+ 11 | syn match omakeKeyword "^\s*\(case\|catch\|class\|declare\|default\|do\|elseif\|else\|export\|extends\|finally\|if\|import\|include\|match\|open\|raise\|return\|section\|switch\|try\|value\|when\|while\)\s*" 12 | syn match omakeOperator "\[\]\|=\|+=" 13 | 14 | " some special characters 15 | syn match makeSpecial "^\s*[@+-]\+" 16 | syn match makeNextLine "\\\n\s*" 17 | 18 | " some directives 19 | syn match makeInclude "^ *[-s]\=include" 20 | syn match makeStatement "^ *vpath" 21 | syn match makeExport "^ *\(export\|unexport\)\>" 22 | syn match makeSection "^\s*section\s*$" 23 | syn match makeOverride "^ *override" 24 | hi link makeOverride makeStatement 25 | hi link makeExport makeStatement 26 | hi link makeSection makeStatement 27 | 28 | " Koehler: catch unmatched define/endef keywords. endef only matches it is by itself on a line 29 | syn region makeDefine start="^\s*define\s" end="^\s*endef\s*$" contains=makeStatement,makeIdent,makeDefine 30 | 31 | " Microsoft Makefile specials 32 | syn case ignore 33 | syn match makeInclude "^! *include" 34 | syn case match 35 | 36 | " identifiers 37 | syn region makeIdent start="\$(" skip="\\)\|\\\\" end=")" contains=makeStatement,makeIdent,makeSString,makeDString,omakeDoubleQuoteString,omakeSingleQuoteString 38 | syn region makeIdent start="\${" skip="\\}\|\\\\" end="}" contains=makeStatement,makeIdent,makeSString,makeDString,omakeDoubleQuoteString,omakeSingleQuoteString 39 | syn match makeIdent "\$\$\w*" 40 | syn match makeIdent "\$[^({]" 41 | syn match makeIdent "^ *\a\w*\s*[:+?!*]="me=e-2 42 | syn match makeIdent "^ *\a\w*\s*="me=e-1 43 | syn match makeIdent "%" 44 | 45 | " Makefile.in variables 46 | syn match makeConfig "@[A-Za-z0-9_]\+@" 47 | 48 | " make targets 49 | " syn match makeSpecTarget "^\.\(STATIC\|PHONY\|DEFAULT\|MEMO\|INCLUDE\|ORDER\|SCANNER\|SUBDIRS\|BUILD_BEGIN\|BUILD_FAILURE\|BUILD_SUCCESS\|BUILDORDER\)\>" 50 | syn match makeImplicit "^\.[A-Za-z0-9_./\t -]\+\s*:[^=]"me=e-2 nextgroup=makeSource 51 | syn match makeImplicit "^\.[A-Za-z0-9_./\t -]\+\s*:$"me=e-1 nextgroup=makeSource 52 | 53 | syn region makeTarget transparent matchgroup=makeTarget start="^[A-Za-z0-9_./$()%-][A-Za-z0-9_./\t $()%-]*:\{1,2}[^:=]"rs=e-1 end=";"re=e-1,me=e-1 end="[^\\]$" keepend contains=makeIdent,makeSpecTarget,makeNextLine skipnl nextGroup=makeCommands 54 | syn match makeTarget "^[A-Za-z0-9_./$()%*@-][A-Za-z0-9_./\t $()%*@-]*::\=\s*$" contains=makeIdent,makeSpecTarget skipnl nextgroup=makeCommands 55 | 56 | syn region makeSpecTarget transparent matchgroup=makeSpecTarget start="^\s*\.\(STATIC\|PHONY\|DEFAULT\|MEMO\|INCLUDE\|ORDER\|SCANNER\|SUBDIRS\|BUILD_BEGIN\|BUILD_FAILURE\|BUILD_SUCCESS\|BUILDORDER\)\>\s*:\{1,2}[^:=]"rs=e-1 end="[^\\]$" keepend contains=makeIdent,makeSpecTarget,makeNextLine skipnl nextGroup=makeCommands 57 | syn match makeSpecTarget "^\s*\.\(STATIC\|PHONY\|DEFAULT\|MEMO\|INCLUDE\|ORDER\|SCANNER\|SUBDIRS\|BUILD_BEGIN\|BUILD_FAILURE\|BUILD_SUCCESS\|BUILDORDER\)\>\s*::\=\s*$" contains=makeIdent skipnl nextgroup=makeCommands 58 | 59 | syn region makeCommands start=";"hs=s+1 start="^\t" end="^[^\t#]"me=e-1,re=e-1 end="^$" contained contains=makeCmdNextLine,makeSpecial,makeComment,makeIdent,makeDefine,makeDString,makeSString 60 | syn match makeCmdNextLine "\\\n."he=e-1 contained 61 | 62 | 63 | " Statements / Functions (GNU make) 64 | syn match makeStatement contained "(\(subst\|abspath\|addprefix\|addsuffix\|and\|basename\|call\|dir\|error\|eval\|filter-out\|filter\|findstring\|firstword\|flavor\|foreach\|if\|info\|join\|lastword\|notdir\|or\|origin\|patsubst\|realpath\|shell\|sort\|strip\|suffix\|value\|warning\|wildcard\|word\|wordlist\|words\)\>"ms=s+1 65 | 66 | " Comment 67 | syn region makeComment start="#" end="^$" end="[^\\]$" keepend contains=@Spell,makeTodo 68 | syn match makeComment "#$" contains=@Spell 69 | syn keyword makeTodo TODO FIXME XXX contained 70 | 71 | " match escaped quotes and any other escaped character 72 | " except for $, as a backslash in front of a $ does 73 | " not make it a standard character, but instead it will 74 | " still act as the beginning of a variable 75 | " The escaped char is not highlighted currently 76 | syn match makeEscapedChar "\\[^$]" 77 | 78 | syn match omakeCallExpr "\$(\h[a-zA-Z0-9_-]*\s\+[^(]\+)" contains=@omakeExpr 79 | syn match omakeVar "\$(\h[a-zA-Z0-9_-]*)" 80 | syn cluster omakeExpr contains=omakeVar,omakeCallExpr 81 | 82 | syn region omakeSingleQuoteString start=+\$'+ skip=+[^']+ end=+'+ 83 | syn region omakeDoubleQuoteString start=+\$"+ skip=+\\.+ end=+"+ 84 | syn region omakeDoubleQuoteString start=+\$"""+ skip=+\\.+ end=+"""+ 85 | 86 | syn region makeDString start=+\(\\\)\@ 4 | " URL: https://github.com/ocaml/vim-ocaml 5 | " Last Change: 6 | " 2020 Dec 31 - Added header (Markus Mottl) 7 | 8 | if exists("b:current_syntax") 9 | finish 10 | endif 11 | 12 | " need %{vars}% 13 | " env: [[CAML_LD_LIBRARY_PATH = "%{lib}%/stublibs"]] 14 | syn iskeyword a-z,A-Z,- 15 | syn keyword opamKeyword1 author 16 | syn keyword opamKeyword1 authors 17 | syn keyword opamKeyword1 available 18 | syn keyword opamKeyword1 bug-reports 19 | syn keyword opamKeyword1 build 20 | syn keyword opamKeyword1 build-env 21 | syn keyword opamKeyword1 conflict-class 22 | syn keyword opamKeyword1 conflicts 23 | syn keyword opamKeyword1 depends 24 | syn keyword opamKeyword1 depexts 25 | syn keyword opamKeyword1 depopts 26 | syn keyword opamKeyword1 description 27 | syn keyword opamKeyword1 dev-repo 28 | syn keyword opamKeyword1 doc 29 | syn keyword opamKeyword1 extra-files 30 | syn keyword opamKeyword1 features 31 | syn keyword opamKeyword1 flags 32 | syn keyword opamKeyword1 homepage 33 | syn keyword opamKeyword1 install 34 | syn keyword opamKeyword1 libraries 35 | syn keyword opamKeyword1 license 36 | syn keyword opamKeyword1 maintainer 37 | syn keyword opamKeyword1 messages 38 | syn keyword opamKeyword1 name 39 | syn keyword opamKeyword1 opam-version 40 | syn keyword opamKeyword1 patches 41 | syn keyword opamKeyword1 pin-depends 42 | syn keyword opamKeyword1 post-messages 43 | syn keyword opamKeyword1 remove 44 | syn keyword opamKeyword1 run-test 45 | syn keyword opamKeyword1 setenv 46 | syn keyword opamKeyword1 substs 47 | syn keyword opamKeyword1 synopsis 48 | syn keyword opamKeyword1 syntax 49 | syn keyword opamKeyword1 tags 50 | syn keyword opamKeyword1 version 51 | 52 | syn keyword opamTodo FIXME NOTE NOTES TODO XXX contained 53 | syn match opamComment "#.*$" contains=opamTodo,@Spell 54 | syn match opamOperator ">\|<\|=\|<=\|>=" 55 | 56 | syn match opamUnclosedInterpolate "%{[^ "]*" contained 57 | syn match opamInterpolate "%{[^ "]\+}%" contained 58 | syn region opamString start=/"/ end=/"/ contains=opamInterpolate,OpamUnclosedInterpolate 59 | syn region opamSeq start=/\[/ end=/\]/ contains=ALLBUT,opamKeyword1 60 | syn region opamExp start=/{/ end=/}/ contains=ALLBUT,opamKeyword1 61 | 62 | hi link opamKeyword1 Keyword 63 | 64 | hi link opamString String 65 | hi link opamExp Function 66 | hi link opamSeq Statement 67 | hi link opamOperator Operator 68 | hi link opamComment Comment 69 | hi link opamInterpolate Identifier 70 | hi link opamUnclosedInterpolate Error 71 | 72 | let b:current_syntax = "opam" 73 | 74 | " vim: ts=2 sw=2 75 | -------------------------------------------------------------------------------- /syntax/sexplib.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file 2 | " Language: S-expressions as used in Sexplib 3 | " Filenames: *.sexp 4 | " Maintainers: Markus Mottl 5 | " URL: https://github.com/ocaml/vim-ocaml 6 | " Last Change: 2020 Dec 31 - Updated header for Vim contribution (MM) 7 | " 2017 Apr 11 - Improved matching of negative numbers (MM) 8 | " 2012 Jun 20 - Fixed a block comment highlighting bug (MM) 9 | 10 | " For version 5.x: Clear all syntax items 11 | " For version 6.x: Quit when a syntax file was already loaded 12 | if version < 600 13 | syntax clear 14 | elseif exists("b:current_syntax") && b:current_syntax == "sexplib" 15 | finish 16 | endif 17 | 18 | " Sexplib is case sensitive. 19 | syn case match 20 | 21 | " Comments 22 | syn keyword sexplibTodo contained TODO FIXME XXX NOTE 23 | syn region sexplibBlockComment matchgroup=sexplibComment start="#|" matchgroup=sexplibComment end="|#" contains=ALLBUT,sexplibQuotedAtom,sexplibUnquotedAtom,sexplibEncl,sexplibComment 24 | syn match sexplibSexpComment "#;" skipwhite skipempty nextgroup=sexplibQuotedAtomComment,sexplibUnquotedAtomComment,sexplibListComment,sexplibComment 25 | syn region sexplibQuotedAtomComment start=+"+ skip=+\\\\\|\\"+ end=+"+ contained 26 | syn match sexplibUnquotedAtomComment /\([^;()" \t#|]\|#[^;()" \t|]\||[^;()" \t#]\)[^;()" \t]*/ contained 27 | syn region sexplibListComment matchgroup=sexplibComment start="(" matchgroup=sexplibComment end=")" contained contains=ALLBUT,sexplibEncl,sexplibString,sexplibQuotedAtom,sexplibUnquotedAtom,sexplibTodo,sexplibNumber,sexplibFloat 28 | syn match sexplibComment ";.*" contains=sexplibTodo 29 | 30 | " Atoms 31 | syn match sexplibUnquotedAtom /\([^;()" \t#|]\|#[^;()" \t|]\||[^;()" \t#]\)[^;()" \t]*/ 32 | syn region sexplibQuotedAtom start=+"+ skip=+\\\\\|\\"+ end=+"+ 33 | syn match sexplibNumber "-\=\<\d\(_\|\d\)*[l|L|n]\?\>" 34 | syn match sexplibNumber "-\=\<0[x|X]\(\x\|_\)\+[l|L|n]\?\>" 35 | syn match sexplibNumber "-\=\<0[o|O]\(\o\|_\)\+[l|L|n]\?\>" 36 | syn match sexplibNumber "-\=\<0[b|B]\([01]\|_\)\+[l|L|n]\?\>" 37 | syn match sexplibFloat "-\=\<\d\(_\|\d\)*\.\?\(_\|\d\)*\([eE][-+]\=\d\(_\|\d\)*\)\=\>" 38 | 39 | " Lists 40 | syn region sexplibEncl transparent matchgroup=sexplibEncl start="(" matchgroup=sexplibEncl end=")" contains=ALLBUT,sexplibParenErr 41 | 42 | " Errors 43 | syn match sexplibUnquotedAtomErr /\([^;()" \t#|]\|#[^;()" \t|]\||[^;()" \t#]\)[^;()" \t]*\(#|\||#\)[^;()" \t]*/ 44 | syn match sexplibParenErr ")" 45 | 46 | " Synchronization 47 | syn sync minlines=50 48 | syn sync maxlines=500 49 | 50 | " Define the default highlighting. 51 | " For version 5.7 and earlier: only when not done already 52 | " For version 5.8 and later: only when an item doesn't have highlighting yet 53 | if version >= 508 || !exists("did_sexplib_syntax_inits") 54 | if version < 508 55 | let did_sexplib_syntax_inits = 1 56 | command -nargs=+ HiLink hi link 57 | else 58 | command -nargs=+ HiLink hi def link 59 | endif 60 | 61 | HiLink sexplibParenErr Error 62 | HiLink sexplibUnquotedAtomErr Error 63 | 64 | HiLink sexplibComment Comment 65 | HiLink sexplibSexpComment Comment 66 | HiLink sexplibQuotedAtomComment Include 67 | HiLink sexplibUnquotedAtomComment Comment 68 | HiLink sexplibBlockComment Comment 69 | HiLink sexplibListComment Comment 70 | 71 | HiLink sexplibBoolean Boolean 72 | HiLink sexplibCharacter Character 73 | HiLink sexplibNumber Number 74 | HiLink sexplibFloat Float 75 | HiLink sexplibUnquotedAtom Identifier 76 | HiLink sexplibEncl Identifier 77 | HiLink sexplibQuotedAtom Keyword 78 | 79 | HiLink sexplibTodo Todo 80 | 81 | HiLink sexplibEncl Keyword 82 | 83 | delcommand HiLink 84 | endif 85 | 86 | let b:current_syntax = "sexplib" 87 | 88 | " vim: ts=8 89 | -------------------------------------------------------------------------------- /type-linter-notes.md: -------------------------------------------------------------------------------- 1 | Below are the tokens that are used as delimiters for type contexts. It has been 2 | constituted in late 2018 by (manually…) inspecting the (possibly inaccurate) 3 | grammar given in the reference manual; in May 2022, I read through the changelog 4 | from 4.08 to 4.14 and checked that listed syntax-related changes are supported. 5 | So the current implementation *should* support OCaml 4.14, but: 6 | 7 | * I may have missed cases when reading the grammar (I think the documented 8 | grammar is maintained by hand so it might be incomplete or out-of-sync; 9 | also, I originally missed some cases because they were only documented in 10 | the “extensions“ section of the reference manual); 11 | * a few pathological cases cannot be handled (unless by implementing a pattern 12 | parser…). 13 | 14 | **opening delimiters** 15 | + `type`, `type nonrec`, `constraint` 16 | + `exception` (excepted when preceded by `with`, `|` or `(`) 17 | * the rule is so that `exception` opens a type context when it is used for 18 | defining an exception, but not when it is used for pattern-matching; the 19 | case `( exception` is to handle exception patterns under or-patterns, 20 | which is allowed since OCaml 4.08: `| (exception E 42 | _) -> …` 21 | + `of`, `:` in sum type definitions 22 | + `:`, `: type`, `:>` 23 | * `: type` is because of polymorphic locally abstract types: `let f : type a b . … = …` 24 | that is necessary because otherwise the type linter would treat `type` 25 | as beginning a toplevel type definition, which has different delimiters 26 | (it spans across `=`). 27 | 28 | **common closing delimiters** 29 | + `type`, `exception`, `val` 30 | + `module`, `class` 31 | + `method`, `constraint`, `inherit` 32 | * because of class types: `class c : object method x : int … end` 33 | + `object` 34 | * because of `class c : object … end` 35 | + `struct` 36 | * because of `module M : MSIG with type t = u = struct … end` 37 | + `open`, `include` 38 | + `let`, `external` 39 | + `in` 40 | * because of `let exception E of typ in expr` 41 | + `end` 42 | + `)` 43 | * because of type annotations: `(x : int)` 44 | * but also of functors: `(M : SIG with type t = int)` 45 | * and also of type abstractions: `let f (type a b) …` 46 | + `]` and `}` 47 | * for error reporting 48 | + `;` 49 | * why not 50 | + `;;` 51 | + EOF 52 | 53 | Not all closing delimiters are useful in all situations, but it is safe to add 54 | them anyway, and it may help error reporting (e.g. by adding `}` and `]`, we can 55 | spot dangling closing parentheses). 56 | 57 | **more closing delimiters for `type` and `type nonrec` and `constraint` and `exception`** 58 | - `and` ? 59 | * to support `type … and …` 60 | * nope, we rather implement it as a keyword contained in the region 61 | (because otherwise, we’d need `and` to also be an opening delimiter for 62 | type contexts, but at that point we would not be able to distinguish 63 | between `type … and …` and `let … and …`) 64 | 65 | **more closing delimiters for sum type definitions** 66 | + → the additional closing delimiters for `type` 67 | + `and` 68 | + `=` (because of `exception E = F`) 69 | 70 | **more closing delimiters for `of` and `:` in sum type definitions** 71 | + → the additional closing delimiters for sum type definitions (excepted `=`) 72 | + `|` 73 | 74 | **more closing delimiters for `:` and `: type` and `:>`** 75 | + `=` 76 | + `:>` 77 | * to support `(x : … :> …)` 78 | + `}` and `;` 79 | * for record fields in record expressions 80 | 81 | **places where a comment is not recognized (uses of the regex `"\_s"`)** 82 | - the `nonrec` keyword: `type ??? nonrec` 83 | - polymorphic locally abstract types: `: ??? type` 84 | - exception patterns: `with ??? exception`, `| ??? exception`, `( ??? exception` 85 | - special constructors in sum type definitions: `( ??? )`, `[ ??? ]`, `( ??? :: ??? )` 86 | - module paths in types: `MyMod ??? .`, `MyFunc ??? (M) ??? .` 87 | - labeled arguments in types: `myname ??? :`, `?myname ??? :` 88 | - variance and/or injectivity indications in type definitions: `+ ??? ! ??? 'a` 89 | 90 | I think this is good enough, inserting comments there would be strange style. 91 | --------------------------------------------------------------------------------