* Completion ** Company I use company mode as a completion backend #+BEGIN_SRC emacs-lisp (use-package company :ensure t :custom (company-quickhelp-delay 0) (company-tooltip-align-annotations t) :hook ((prog-mode utop-mode) . company-mode) :config (company-quickhelp-mode 1) :bind ("M-o" . company-complete) ) #+END_SRC Popup for documentation or help #+BEGIN_SRC emacs-lisp (use-package company-quickhelp :ensure t :bind (:map company-active-map ("M-h" . company-quickhelp-manual-begin)) ) #+END_SRC * Languages ** Ocaml/Reason Util function to select where to load merlin from. #+BEGIN_SRC emacs-lisp (defun shell-cmd (cmd) "Returns the stdout output of a shell command or nil if the command returned an error" (car (ignore-errors (apply 'process-lines (split-string cmd))))) (setq opam-p (shell-cmd "which opam")) (setq reason-p (shell-cmd "which refmt")) #+END_SRC *** Load opam Setup environment variables using opam. #+BEGIN_SRC emacs-lisp :tangle no (if opam-p (dolist (var (car (read-from-string (shell-command-to-string "opam config env --sexp")))) (setenv (car var) (cadr var)))) #+END_SRC Add opam libs. #+BEGIN_SRC emacs-lisp (if opam-p (let ((opam-share (ignore-errors (car (process-lines "opam" "config" "var" "share"))))) (when (and opam-share (file-directory-p opam-share)) (add-to-list 'load-path (expand-file-name "emacs/site-lisp" opam-share))))) #+END_SRC *** caml, reasonml and tuareg modes ~caml~ is required because ~caml-types-expr-face~ is used by merlin. #+BEGIN_SRC emacs-lisp (use-package caml :ensure t) #+END_SRC We don't need the tuareg package from the emacs repositories, it comes from opam. #+BEGIN_SRC emacs-lisp (use-package tuareg :if opam-p :mode ("\\.ml[ily]?$" . tuareg-mode)) #+END_SRC When using ~reason-mode~, we want to load merlin from ~node_modules~ rather than opam. #+BEGIN_SRC emacs-lisp (use-package reason-mode :if reason-p :ensure t :config (let* ((refmt-bin (or (shell-cmd "refmt ----where") (shell-cmd "which refmt"))) (merlin-bin (or (shell-cmd "ocamlmerlin ----where") (shell-cmd "which ocamlmerlin"))) (merlin-base-dir (when merlin-bin (replace-regexp-in-string "bin/ocamlmerlin$" "" merlin-bin)))) ;; Add npm merlin.el to the emacs load path and tell emacs where to find ocamlmerlin (when merlin-bin (add-to-list 'load-path (concat merlin-base-dir "share/emacs/site-lisp/")) (setq merlin-command merlin-bin)) (when refmt-bin (setq refmt-command refmt-bin))) ) #+END_SRC *** ocp tools Require ocp stuff first because of conflicts between shortcuts. It is installed from opam, ~ensure~ is not required. #+BEGIN_SRC emacs-lisp (use-package ocp-indent :if opam-p) (use-package ocp-index :if opam-p) #+END_SRC *** merlin Configure merlin. Magical autocompletion and IDE features. #+BEGIN_SRC emacs-lisp (use-package merlin :custom (merlin-completion-with-doc t) :bind (:map merlin-mode-map ("M-." . merlin-locate) ("M-," . merlin-pop-stack) ("M-?" . merlin-occurrences) ("C-c C-j" . merlin-jump) ("C-c i" . merlin-locate-ident) ("C-c C-e" . merlin-iedit-occurrences) ) :hook ;; Start merlin on ml files ((reason-mode tuareg-mode caml-mode) . merlin-mode) ) #+END_SRC *** utop #+BEGIN_SRC emacs-lisp (use-package utop :custom (utop-edit-command nil) :hook (tuareg-mode . (lambda () (setq utop-command "utop -emacs") (utop-minor-mode))) (reason-mode . (lambda () (setq utop-command "rtop -emacs") (setq utop-prompt (lambda () (let ((prompt (format "rtop[%d]> " utop-command-number))) (add-text-properties 0 (length prompt) '(face utop-prompt) prompt) prompt))) (utop-minor-mode))) ) #+END_SRC