Also the $ opam install tuareg output works fine but puzzles me a bit, because it refers a fixed switch while I would expect emacs to use the current switch:
=> If you have not yet done so, please add the following line to ~/.emacs.d/init.el or ~/.emacs:
(load "/Users/mro/.opam/4.10.2/share/emacs/site-lisp/tuareg-site-file")
=> You should consider installing "merlin" (completion, displaying types,...)
or "caml-mode" (displaying types). See https://github.com/ocaml/tuareg
for customization tips.
And installing “merlin” is a bit vague – could it point to a helpful URL of merlin?
Since you’re coming from vim, I would recommend starting with Doom Emacs. It’s a configuration framework that comes with evil-mode, out-of-the-box support for OCaml (and many other languages) and nice non-archaic defaults. You can choose merlin or ocaml-lsp, and lsp-mode or eglot, with a single-line configuration change.
This is how I setup my Emacs (using caml-mode because I don’t use Tuareg).
Begin by installing merlin, ocp-indent, caml-mode, etc, using opam:
opam install merlin ocp-indent caml-mode
Then add the following bits of code to your Emacs init file.
The first bit of code will add the emacs/site-lisp directory of the current opam switch to the Emacs load path:
Doom is supposed to be more lightweight, and uses a declarative (and many people say nicer) configuration system that allows it to lazy load only what’s needed. It’s been a long time since I last tried (and got scared away from) Spacemacs though, so this is just based on what I hear from others. In terms of functionality I think they’re very similar.
A bit off-topic, but if you are planning to use Emacs for real-life development, I recommend using vanilla Emacs with as little customization as possible. This works great on both Unix and Windows, is very fast, and if you ever find yourself without your init file (eg when ssh-ing into an unknown machine) it isn’t a problem because you won’t depend on fancy extension packages.
indeed i found customization often overrated, a nuisance to manage machines and leading to idiosyncrasies. Or as the fish shell puts it: “Configurability is the root of all evil”.
I aim for an unambitioned setup and also look at others (nano, micro). I want it available on unixes, have syntax highlighting for OCaml and be able to pipe marked text through a command.
I like the command execution of vim, e.g. :!wc -c % and :%!wc -c
I think the particulars of your editor configuration will likely vary from person to person, so I’d warn against generalising too much from a single data point. Personally, I do most of my main development from a single machine, so I invest heavily in customising my Emacs to maximise my own efficiency - in the rare case I’m editing on a foreign machine, I can either use tramp or spawn a light VI process and rely on my fading VI muscle memory. For people who develop on remote machines more frequently, then maybe a lighter configuration might be a better option.
For example, here’s a very useful function that I find myself using quite a bit:
Which allows me to jump to the nearest enclosing dune file for the current buffer by just pressing C-c C-q - it’s especially useful when I quickly need to add or remove dependencies for a dune file, and has probably cumulatively saved me at least an hour of unnecassary keypresses.
Naturally, Emacs can do that - it’s just M-| (shell-command-on-region) with vanilla bindings. (prefix with C-u to output the result back into the same buffer).
It’s possible that what I’m about to suggest is … not useful to you, but just in case:
If you don’t need LSP/Merlin, then might I suggest running Emacs locally on your Mac, and using tramp-mode to access remote filesystems ? I’ve been doing that pretty much exclusively for … 30+ years (before TRAMP, ange-ftp) and it works great. You get a local GUI Emacs, with all the responsiveness, a single editor experience across many machines you might access, etc. You can M-x compile, etc, no problemo (TRAMP figures out it needs to ssh to the remote machine to run the compile command).
I know some people have mentioned that LSP/Merlin don’t seem to work over SSH, and since I don’t use 'em, I don’t know whether that’s fixable. But I kinda suspect it is, since magit-mode (Emacs git mode) works remotely no problemo.
having a local ssh-agent and using ControlMaster channels also makes this work really sweetly.
But OTOH, if you don’t like “living on the control key”, this might not be a useful suggestion.
That’s partly why I suggested Doom, which comes with vim bindings (evil-mode) out of the box. Not that it would be too hard to set up on a barebones config either. But Doom also comes with a space-triggered menu (ala Spacemacs) for all the non-vim commands, so you don’t ever have to touch Ctrl or Alt.
I use Emacs as an IDE, not a text editor. For that purpose I use vim, which is always going to boot faster, and for the most part the key bindings work the same in both.
It’s the bee’s knees. Seriously! I never fire up editors on remote machines except for editing things under sudo. The only limitation is that it’s too complicated to set up the edit-server stuff so you can run emacsclient on the remote machine and have the file show up in your local emacs. I’ve read instructions on how to do that, but … too damn complicated. Someday I’ll look into how chromeos does it from inside the linux container, and try to replicate that.
Here’s my personal Emacs config for OCaml programming (it’s based on use-package, but this can converted to the plain old config format easily):
;;;; OCaml support
;; major mode for editing OCaml code
;; it also features basic toplevel integration
(use-package tuareg
:ensure t
:mode (("\\.ocamlinit\\'" . tuareg-mode)))
;; major mode for editing Dune files
(use-package dune
:ensure t)
;; Merlin provides a lot of IDE-like features for OCaml editors
;; e.g. code completion, go to definition, show type of expression, etc
(use-package merlin
:ensure t
:config
(add-hook 'tuareg-mode-hook #'merlin-mode)
(add-hook 'merlin-mode-hook #'company-mode)
;; we're using flycheck instead
(setq merlin-error-after-save nil))
;; eldoc integration for Merlin
(use-package merlin-eldoc
:ensure t
:hook ((tuareg-mode) . merlin-eldoc-setup))
;; Code Linting
;; This uses Merlin internally
(use-package flycheck-ocaml
:ensure t
:config
(flycheck-ocaml-setup))
;; utop integration
(use-package utop
:ensure t
:config
(add-hook 'tuareg-mode-hook #'utop-minor-mode))
I’d say you can start with just tuareg, dune and merlin initially and include additional packages down the road. I’ve preferred to use merlin-mode directly over using OCamlLISP as the LSP server is implemented in terms of Merlin anyways, and I like the simplicity of merlin-mode.