Login

Editor setup

vim, pre-caveman version

https://ocaml.org/docs/set-up-editor#vim

opam install merlin
opam user-setup install

Throw something like this in your .vimrc if you like:

au FileType ocaml setlocal formatoptions-=r formatoptions-=o formatoptions-=q
au BufRead,BufNewFile *.ml map <C-p> :silent:w!<Return>:%!ocamlformat %<Return>
au BufRead,BufNewFile *.ml map K :MerlinDocument<Return>
au BufRead,BufNewFile *.ml map <C-n> :MerlinErrorCheck<Return>
au BufRead,BufNewFile *.ml map <Leader>, :MerlinLocateImpl<Return>
au BufRead,BufNewFile *.ml map <Leader>. :MerlinLocateIntf<Return>
au BufRead,BufNewFile *.ml map <Leader>T :MerlinLocateType<Return>
au BufRead,BufNewFile *.ml imap <C-n> <C-x><C-o>

Also explained below. <leader>t, probably \t, will run :MerlinTypeOf

The vim experience with merlin is not quite as nice as the LSP experience below, but vim+merlin has the incredible feature of not breaking the editor.

Neovim, caveman version

If you want to use init.lua instead of init.vim (this is a good idea), just wrap all of these lines with

vim.cmd [[
... all the vim stuff
]]

As a quick conversion you lose some syntax highlighting on the config. You can't have both an init.vim and an init.lua at the same time, but you can dump your entire init.vim into the above and it'll work.

  1. Ensure the neovim config directories exists:
    mkdir -pv ~/.config/nvim/colors
  2. Add a nice color scheme:
    wget -O ~/.config/nvim/colors/takodachi.vim \
    https://raw.githubusercontent.com/mildewchan/takodachi.vim/master/colors/takodachi.vim
  3. Add some lines to your ~/.config/nvim/init.vim:
    au BufRead,BufNewFile *.ml colorscheme takodachi
    au FileType ocaml setlocal formatoptions-=r formatoptions-=o formatoptions-=q
    au BufRead,BufNewFile *.ml map <C-p> :silent:w!<Return>:%!ocamlformat %<Return>

The formatoptions changes prevent nvim from creating star-walls in your comments:

(* you generally shouldn't do
 * this in OCaml, because documents
 * created from your comments will
 * retain these extra asterisks. *)
  1. put a reasonable default .ocamlformat in your home directory:
    cat > ~/.ocamlformat <<EOF
    profile = conventional
    
    leading-nested-match-parens = false
    space-around-variants = false
    space-around-arrays = false
    space-around-lists = false
    space-around-records = false
    break-infix = fit-or-vertical
    break-separators = after
    break-cases = fit-or-vertical
    cases-exp-indent = 2
    exp-grouping = preserve
    if-then-else = fit-or-vertical
    let-and = sparse
    type-decl = sparse
    This is is just dream's .ocamlformat with the version removed - ocamlformat will complain about version mismatches, which can be helpful if you want a reminder to reconsider your config after an update.
  2. install prerequisites with opam:
    opam install ocaml-lsp-server user-setup
    opam user-setup install
    and then copy the vim config from ~/.vimrc into your ~/.config/nvim/init.vim
  3. disable merlin which breaks in nvim. You do this by removing "merlin" from this assignment in the copied config:
    let s:opam_packages = ["ocp-indent", "ocp-index"]
  4. at this point you have syntax highlighting, good indentation with ocp-indent, and automatic formatting with a keypress (NB. you need to be in command mode). The next thing to add is completion and type information by setting up the LSP from ocaml.org's instructions. Add this to ~/.config/nvim/lsp/ocamllsp.lua
    vim.lsp.config['ocamllsp'] = {
      cmd = { 'ocamllsp' },
      filetypes = { 
        'ocaml',
        'ocaml.interface',
        'ocaml.menhir',
        'ocaml.ocamllex',
        'dune',
        'reason'
      },
      root_markers = {
        { 'dune-project', 'dune-workspace' },
        { "*.opam", "esy.json", "package.json" },
        '.git'
      },
      settings = {},
    }
    
    vim.lsp.enable 'ocamllsp'
    then add this to your init.vim (without the 'lua' wrapper if to init.lua):
    au BufRead,BufNewFile *.ml imap <C-n> <C-x><C-o>
    lua << EOF
    vim.lsp.enable('ocamllsp')
    vim.keymap.set('n', '<C-n>', function() vim.diagnostic.goto_next() end, opts)
    EOF

Useful keys:

NB. LSP causes nvim to shit itself when opening a new OCaml buffer with :e