Skip to content
Erik Martin-Dorel edited this page Sep 19, 2023 · 33 revisions

There are two ways of installing merlin: through opam and manually. If you do not wish to try the development version, it is recommended to install merlin through opam.

Keep your existing tuareg-mode or caml-mode configuration. Merlin doesn't provide syntax highlighting nor indentation. It is a minor mode that can be enabled on top of one of the existing OCaml modes. It will add completion, navigation, etc on top.

merlin-mode can also show you errors, but flycheck users might prefer https://github.com/flycheck/flycheck-ocaml to ensure errors are always shown.

Installing merlin and its emacs mode with opam

To install merlin with opam just issue

opam install merlin

It should download and install the last release of merlin. To check that merlin is indeed installed (and that you have a well configured opam) you can try to run ocamlmerlin.

Then add the following at the end of your emacs configuration file (for instance ~/.emacs.el) :

(let ((opam-share (ignore-errors (car (process-lines "opam" "var" "share")))))
 (when (and opam-share (file-directory-p opam-share))
  (add-to-list 'load-path (expand-file-name "emacs/site-lisp" opam-share))
  (autoload 'merlin-mode "merlin" nil t nil)
  (add-hook 'tuareg-mode-hook 'merlin-mode t)
  (add-hook 'caml-mode-hook 'merlin-mode t)))

Then whenever you start emacs, merlin will be loaded. Try it by issuing (in emacs) M-x merlin-version. It should display the version of merlin you are using.

You can now skip the next section and play with merlin.

Installing merlin manually

To compile and install merlin, the process is standard:

git clone https://github.com/the-lambda-church/merlin.git
cd merlin
./configure --prefix /usr/local
make
sudo make install

You can specify any path for the prefix, and merlin will install itself in this directory (the default being /usr/local).

You can now run ocamlmerlin to check if the installation is successful.

The process is similar to the installation with opam, you have to append to your emacs configuration file (for instance ~/.emacs.el):

(add-to-list 'load-path "<PREFIX>/share/emacs/site-lisp")
(autoload 'merlin-mode "merlin" nil t nil)
(add-hook 'tuareg-mode-hook 'merlin-mode t)
(add-hook 'caml-mode-hook 'merlin-mode t)
(setq merlin-command "<PREFIX>/bin/ocamlmerlin")

where <PREFIX> is the prefix you specified to the configure script of merlin in the previous step. You can now restart emacs and check if that worked by executing M-x merlin-version.

Discovering the emacs mode

To enable the mode, type:

M-x merlin-mode

If you wish to enable merlin whenever you open a ML buffer you can put the following in your configuration file:

(add-hook 'tuareg-mode-hook 'merlin-mode)

if you are using tuareg, or

(add-hook 'caml-mode-hook 'merlin-mode)

if you are using the caml-mode.

Synchronization and error reporting

Merlin works by running its own typechecker on your buffer. Synchronization is done automatically when you save your buffer, and when you call a command.

When calling a command, emacs and merlin reconcile their view of the buffer so that merlin always have fresh information to answer your query.

Upon saving emacs will ask merlin about all the errors (of syntax or type) in your buffer and report them. If your buffer contains error the erroneous chunks of the buffer will indeed be highlighted and emacs will display markers in the margin (! for errors, ? for warnings').

You can jump to errors using the merlin-error-next command (C-c C-x by default).

Note the you can tell merlin not to report warnings using:

(setq merlin-report-warnings nil)

Completion

The emacs mode provides three ways to complete expressions:

  • completion-at-point: the native completion engine of emacs
  • auto-complete: a fancier completion system, installed by default on emacs 24, and available on marmalade.
  • company-mode: available on melpa, an alternative completion system (with a saner default configuration).

Completion using completion-at-point should work out of the box. To try it, type List.m followed by M-x completion-at-point (bound to M-tab by default in emacs 24), it will display a completion buffer with the different candidates and their types.

completion-at-point at work:

emacs completion at point

Auto-complete

By default, if auto-complete is installed, merlin will only register a source named merlin-ac-source and do nothing about it. If you issue:

(setq merlin-ac-setup 'easy)

it will enable auto-complete in merlin buffers and add the merlin source to the default sources. You can now use auto-complete as you usually do, or run M-x auto-complete. If you have not configured auto-complete, see its documentation.

Using auto-complete-mode you should see something looking like this:

emacs auto complete mode

If you want autocomplete to suggest completions without prompting, simply replace 'easy with t in the above setq.

Company-mode

To use the company mode plugins, you just have to issue:

; Make company aware of merlin
(with-eval-after-load 'company
 (add-to-list 'company-backends 'merlin-company-backend))
; Enable company on merlin managed buffers
(add-hook 'merlin-mode-hook 'company-mode)
; Or enable it globally:
; (add-hook 'after-init-hook 'global-company-mode)

And then it should work out of the box. See the documentation of company mode for more information.

Getting the types of expressions

To get the type of ident under the cursor, call merlin-type-enclosing (bound to C-c C-t by default). It will highlight the ident and display its type. You can then call C-<up> (and C-<down>) to climb the typed tree and see type of bigger expressions surrounding the cursor.

The result should look something like this :

emacs type enclosing

If there is an active region, it will instead display the type of the region.

Further calls to C-c C-t will improve the verbosity of the displayed type, by expanding aliases.

Also, note that merlin-type-expr (C-u C-c C-t) will prompt you for an arbitrary expression and will try to type it in the context active at your cursor position.

Source browsing

You can navigate between phrases of your buffer using merlin-phrase-next (C-c C-n) and merlin-phrase-prev (C-c C-p).

Merlin also provide a way to switch between files of your project using the commands merlin-switch-to-ml / merlin-switch-to-mli, these will prompt you for a (toplevel) module name, and will then open the associated ml[i] file.

And last but not least : the command merlin-locate (bound to C-c C-l by default) when called on an identifier will try to bring you to the place were it is introduced (i.e. defined or bound).
You can also use that facility from auto-complete completion menu; issuing C-c C-l when that menu is open will call the locate command on the highlighted suggestion.

Note that it might happen that merlin fails to find the definition location of the identifier you gave him. Several things might explain that:

  1. you are asking for the definition of something defined in an other file and:
    • either that file is not in the load path of merlin (you need to setup a .merlin!)
    • or you didn't compile with -bin-annot.
  2. you are asking him for the definition of something local to your file but the place where that thing is defined doesn't parse or doesn't typecheck, and the identifier is not present in the environment

If it doesn't work, but none of the above explains why, open an issue!

Case analysis (destruct)

Destruct is a powerful feature of Merlin that allows one to generate and manipulate pattern matching expressions.

The main command, M-x merlin-destruct (C-c M-d or C-c |), behaves differently depending on the cursor's context:

When called on:

  • an expression it replaces it by a pattern matching over it's constructors

  • a wildcard pattern in a matching it will refine it if possible

  • a pattern of a non-exhaustive matching it will make the pattern matching exhaustive by adding missing cases

Expression construction (since 4.3.1)

Merlin provides commands to browse and fill typed holes (_). Such holes sometimes appear in the result of other commands like destruct and can also also be inserted manually in the source code to get access to code generation.

  • M-x merlin-next-hole and M-x merlin-previous-hole
    Navigates to the next or previous typed hole (_) in the buffer.

  • M-x merlin-construct
    Provides valid type-based constructions when the cursor is on a typed hole (_) that could fill this hole. Can be used in alternation with destruct.

Configuring Merlin

See project configuration for a full description of .merlin files.

Per-session configuration

You can use the merlin-use command to tell Merlin that you're using a findlib/opam package. This will prompt you for a package name (completion on packages name is provided, but you can always call ocamlfind list from a shell to have the list of installed packages).

This is equivalent to the PKG directive in .merlin.

You can enable syntax extensions with M-x merlin-extension-enable. This is equivalent to EXT in .merlin.

Troubleshooting

It happens that merlin and emacs get desynchronized. In this case, you can always issue merlin-restart-process to start from a fresh state.