* 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