-
Notifications
You must be signed in to change notification settings - Fork 232
emacs from scratch
This document is a work in progress, any feedback or addition is welcomed.
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.
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
) :
(setq opam-share (substring (shell-command-to-string "opam config var share 2> /dev/null") 0 -1))
(add-to-list 'load-path (concat opam-share "/emacs/site-lisp"))
(require 'merlin)
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.
To compile and install merlin, the process is standard:
git clone https://github.com/def-lkb/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")
(require 'merlin)
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
issuing M-x merlin-version
.
To enable the mode, issue (in a ML buffer, merlin works only on implementations):
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.
Merlin works by synchronizing your buffer with a toplevel, and querying the toplevel to get the type of expressions or to provide completion. Synchronization is done automatically when you save your buffer, and when you call a command.
When calling a command emacs and merlin will reconcile their view of the buffer up to your cursor position, that way merlin will use the environment active at that position to compute the answer to your query.
Upon saving emacs will ask merlin about all the errors (of syntax or type) in
your buffer, and display them to you.
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-next-error
command (C-c C-x
by
default).
Note the you can tell merlin not to report warnings using:
(setq merlin-report-warnings nil)
One last point, you can force merlin to synchronize up to the point by using the
command merlin-to-point
, then only errors before the cursor will show up.
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,
for instance 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.
See:
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-use-auto-complete-mode '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.
On top of that merlin defines a binding C-c <tab>
(merlin-try-completion
)
that calls explicitly auto-complete.
Using auto-complete-mode you should see something looking like this:
To use the company mode plugins, you just have to issue:
; Make company aware of merlin
(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.
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 :
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-c t
by default) will prompt you for an
arbitrary expression and will try to type it in the context active at your
cursor position.
First 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:
- you are asking him 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.
- 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!
Or " I've changed the interface of a module of my project, why doesn't merlin pick it up? "
If you have changed the interface of an other module of your project, and want
merlin to know about it, you need to refresh its .cmi
cache using
merlin-refresh
(bound to C-c C-u
by default).
For people using OMake or jenga's polling, wrapper scripts are provided to
notify merlin at the end of each successful compilation cycle.
They are called omake-merlin
and jenga-merlin
respectively.
If you want to restart the merlin processus, issue merlin-restart-process
(bound to C-c C-r
).
Or " why doesn't merlin know about my other files? "
By default, when you edit a file in a directory foo/
merlin will add foo/
to
its load path. As your projects grow however, your files will often be spread
among several (sub)directories, at this point you will need to inform merlin
about the structure of your project.
To do that, you need to create a .merlin
file at the root of your project.
A .merlin
file will look something like :
# structure of my awesome project
S src
S src/foo
S src/bar
B _build/src
B _build/src/foo
B _build/src/bar
The S
directive tells merlin where to find source files and the B
tells it where to find cmi (used for basically everything) and cmt
(used for merlin-locate
) files.
There is a lot more to .merlin
files than just S
and B
. Have a look at
the power guide to .merlin to know more.
Or " merlin complains about 'Unbound module Core' "
When you want to use external libraries that you installed with findlib (that's the case when you install them with opam) you need to tell merlin which ones you use.
You can do that on a per-session basis using the merlin-use
command which 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).
Or you can set it once and for all for your project by adding the directive
PKG
followed by packages name to the .merlin of your project.
For example :
PKG core lwt
Or " merlin complains about 'Unbound value lwt' "
Merlin has specifics support for syntax extensions, however not all are enabled by default. Those who aren't enabled are the one introducing new keywords, lwt for example.
You can activate these by using the EXT
directive in the .merlin of your
project.
TODO.