lang/ocaml: major refactor
+ Load flyspell-mode a little later, to allow file/dir-local variables to customize flyspell. + Ensure setters (in merlin's config) are used as late as possible, by making merlin's (and all the other packages) config run after tuareg is loaded. + As discussed, installing packages locally is a bit unreliable, so I'm commenting out the +ocaml-site-lisp flag, and rely solely on packages from MELPA. + Add optional ocamlformat check in doctor.el and conditionally load the ocamlformat package (if editor/format is enabled). + Add docstrings to init hooks.
This commit is contained in:
parent
4e81605463
commit
d1d9cffcc8
3 changed files with 103 additions and 89 deletions
|
@ -1,83 +1,91 @@
|
||||||
;;; lang/ocaml/config.el -*- lexical-binding: t; -*-
|
;;; lang/ocaml/config.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
;; def-project-mode!/associate! doesn't work when a
|
(after! tuareg
|
||||||
;; package is lazy loaded, and everything is compiled
|
|
||||||
|
|
||||||
(def-package! tuareg
|
|
||||||
:defer t ;; modes set by autoload
|
|
||||||
:config
|
|
||||||
;; tuareg-mode has the prettify symbols itself
|
;; tuareg-mode has the prettify symbols itself
|
||||||
(set-pretty-symbols! 'tuareg-mode :alist
|
(set-pretty-symbols! 'tuareg-mode :alist
|
||||||
(append tuareg-prettify-symbols-basic-alist
|
(append tuareg-prettify-symbols-basic-alist
|
||||||
tuareg-prettify-symbols-extra-alist))
|
tuareg-prettify-symbols-extra-alist))
|
||||||
|
;; harmless if `prettify-symbols-mode' isn't active
|
||||||
(setq tuareg-prettify-symbols-full t)
|
(setq tuareg-prettify-symbols-full t)
|
||||||
|
|
||||||
;; Use opam to set environment
|
;; Use opam to set environment
|
||||||
(setq tuareg-opam-insinuate t)
|
(setq tuareg-opam-insinuate t)
|
||||||
(tuareg-opam-update-env (tuareg-opam-current-compiler))
|
(tuareg-opam-update-env (tuareg-opam-current-compiler))
|
||||||
|
|
||||||
;; Spell-check comments
|
;; Spell-check comments
|
||||||
(when (featurep! :feature spellcheck)
|
(when (featurep! :feature spellcheck)
|
||||||
(add-hook 'tuareg-mode-hook #'flyspell-prog-mode)))
|
(add-hook 'tuareg-mode-local-vars-hook #'flyspell-prog-mode))
|
||||||
|
|
||||||
(def-package! merlin
|
|
||||||
:after tuareg
|
|
||||||
:init
|
|
||||||
(set-lookup-handlers! 'tuareg-mode
|
|
||||||
:definition #'merlin-locate
|
|
||||||
:references #'merlin-occurrences
|
|
||||||
:documentation #'merlin-document)
|
|
||||||
(defun +ocaml|init-merlin ()
|
|
||||||
(when (and (projectile-locate-dominating-file default-directory ".merlin")
|
|
||||||
(executable-find "ocamlmerlin"))
|
|
||||||
(merlin-mode)))
|
|
||||||
(add-hook 'tuareg-mode-hook #'+ocaml|init-merlin)
|
|
||||||
|
|
||||||
:config
|
(def-package! merlin
|
||||||
(map! :map tuareg-mode-map
|
:defer t
|
||||||
:localleader
|
:init
|
||||||
:n "t" #'merlin-type-enclosing
|
(defun +ocaml|init-merlin ()
|
||||||
:n "a" #'tuareg-find-alternate-file)
|
"Activate `merlin-mode' if the ocamlmerlin executable exists and the
|
||||||
(set-company-backend! 'tuareg-mode 'merlin-company-backend)
|
current project possesses a .merlin file."
|
||||||
(setq merlin-completion-with-doc t))
|
(when (and (projectile-locate-dominating-file default-directory ".merlin")
|
||||||
|
(executable-find "ocamlmerlin"))
|
||||||
|
(merlin-mode)))
|
||||||
|
(add-hook 'tuareg-mode-hook #'+ocaml|init-merlin)
|
||||||
|
|
||||||
(def-package! flycheck-ocaml
|
(set-company-backend! 'tuareg-mode 'merlin-company-backend)
|
||||||
:when (featurep! :feature syntax-checker)
|
(set-lookup-handlers! 'tuareg-mode
|
||||||
:after merlin
|
:definition #'merlin-locate
|
||||||
:config
|
:references #'merlin-occurrences
|
||||||
;; Disable Merlin's own error checking
|
:documentation #'merlin-document)
|
||||||
(setq merlin-error-after-save nil)
|
:config
|
||||||
;; Enable Flycheck checker
|
(setq merlin-completion-with-doc t)
|
||||||
(flycheck-ocaml-setup))
|
|
||||||
|
|
||||||
(def-package! ocp-indent
|
(map! :map tuareg-mode-map
|
||||||
;; must be careful to always defer this, it has autoloads that adds hooks
|
:localleader
|
||||||
;; which we do not want if the executable can't be found
|
:n "t" #'merlin-type-enclosing
|
||||||
:defer t
|
:n "a" #'tuareg-find-alternate-file))
|
||||||
:init
|
|
||||||
(defun +ocaml|init-ocp-indent ()
|
|
||||||
(when (executable-find "ocp-indent")
|
|
||||||
(ocp-setup-indent)))
|
|
||||||
(add-hook 'tuareg-mode-hook #'+ocaml|init-ocp-indent))
|
|
||||||
|
|
||||||
(def-package! utop
|
|
||||||
:defer t ;; loaded by hook below
|
|
||||||
:when (featurep! :feature eval)
|
|
||||||
:init
|
|
||||||
(set-repl-handler! 'tuareg-mode #'utop)
|
|
||||||
(set-eval-handler! 'tuareg-mode #'utop-eval-region)
|
|
||||||
(defun +ocaml|init-utop ()
|
|
||||||
(when (executable-find "utop")
|
|
||||||
(utop-minor-mode)))
|
|
||||||
(add-hook 'tuareg-mode-hook #'+ocaml|init-utop))
|
|
||||||
|
|
||||||
(def-package! ocamlformat
|
(def-package! flycheck-ocaml
|
||||||
:after tuareg
|
:when (featurep! :feature syntax-checker)
|
||||||
:commands (ocamlformat)
|
:after merlin
|
||||||
:init
|
:config
|
||||||
(set-formatter! 'ocamlformat #'ocamlformat
|
;; Disable Merlin's own error checking
|
||||||
:modes '(caml-mode tuareg-mode))
|
(setq merlin-error-after-save nil)
|
||||||
(defun +ocaml|init-ocamlformat ()
|
;; Enable Flycheck checker
|
||||||
(setq +format-with 'ocp-indent)
|
(flycheck-ocaml-setup))
|
||||||
(when (and (executable-find "ocamlformat")
|
|
||||||
(locate-dominating-file default-directory ".ocamlformat"))
|
|
||||||
(setq +format-with 'ocamlformat)))
|
(def-package! utop
|
||||||
(add-hook 'tuareg-mode-hook #'+ocaml|init-ocamlformat))
|
:when (featurep! :feature eval)
|
||||||
|
:defer t ; loaded by hook below
|
||||||
|
:init
|
||||||
|
(set-repl-handler! 'tuareg-mode #'utop)
|
||||||
|
(set-eval-handler! 'tuareg-mode #'utop-eval-region)
|
||||||
|
(defun +ocaml|init-utop ()
|
||||||
|
(when (executable-find "utop")
|
||||||
|
(utop-minor-mode)))
|
||||||
|
(add-hook 'tuareg-mode-hook #'+ocaml|init-utop))
|
||||||
|
|
||||||
|
|
||||||
|
(def-package! ocp-indent
|
||||||
|
;; must be careful to always defer this, it has autoloads that adds hooks
|
||||||
|
;; which we do not want if the executable can't be found
|
||||||
|
:defer t
|
||||||
|
:init
|
||||||
|
(defun +ocaml|init-ocp-indent ()
|
||||||
|
"Run `ocp-setup-indent', so long as the ocp-indent binary exists."
|
||||||
|
(when (executable-find "ocp-indent")
|
||||||
|
(ocp-setup-indent)))
|
||||||
|
(add-hook 'tuareg-mode-hook #'+ocaml|init-ocp-indent))
|
||||||
|
|
||||||
|
|
||||||
|
(def-package! ocamlformat
|
||||||
|
:when (featurep! :editor format)
|
||||||
|
:commands ocamlformat
|
||||||
|
:init
|
||||||
|
(set-formatter! 'ocamlformat #'ocamlformat
|
||||||
|
:modes '(caml-mode tuareg-mode))
|
||||||
|
;; TODO Fix region-based formatting support
|
||||||
|
(defun +ocaml|init-ocamlformat ()
|
||||||
|
(setq +format-with 'ocp-indent)
|
||||||
|
(when (and (executable-find "ocamlformat")
|
||||||
|
(locate-dominating-file default-directory ".ocamlformat"))
|
||||||
|
(setq +format-with 'ocamlformat)))
|
||||||
|
(add-hook 'tuareg-mode-hook #'+ocaml|init-ocamlformat)))
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
;;; lang/ocaml/doctor.el
|
;;; lang/ocaml/doctor.el
|
||||||
|
|
||||||
(unless (executable-find "ocamlmerlin")
|
(unless (executable-find "ocamlmerlin")
|
||||||
(warn! "Couldn't find ocamlmerlin. Lookup, completion and syntax checking won't work."))
|
(warn! "Couldn't find ocamlmerlin. Lookup, completion and syntax checking won't work"))
|
||||||
|
|
||||||
;; Tuareg can still indent
|
;; Tuareg can still indent
|
||||||
(unless (executable-find "ocp-indent")
|
(unless (executable-find "ocp-indent")
|
||||||
(warn! "Couldn't find ocp-indent. Auto-indentation will be less precise."))
|
(warn! "Couldn't find ocp-indent. Auto-indentation will be less precise"))
|
||||||
|
|
||||||
(when (featurep! :feature eval)
|
(when (featurep! :feature eval)
|
||||||
(unless (executable-find "utop")
|
(unless (executable-find "utop")
|
||||||
|
@ -15,4 +15,8 @@
|
||||||
(unless (executable-find "dune")
|
(unless (executable-find "dune")
|
||||||
(warn! "Couldn't find dune. Won't be able to highlight dune files"))
|
(warn! "Couldn't find dune. Won't be able to highlight dune files"))
|
||||||
|
|
||||||
|
(when (featurep! :editor format)
|
||||||
|
(unless (executable-find "ocamlformat")
|
||||||
|
(warn! "Couldn't find ocamlformat. Code-formatting will be unavailable")))
|
||||||
|
|
||||||
;; ocamlformat is optional, don't warn about it
|
;; ocamlformat is optional, don't warn about it
|
||||||
|
|
|
@ -1,30 +1,32 @@
|
||||||
;; -*- no-byte-compile: t; -*-
|
;; -*- no-byte-compile: t; -*-
|
||||||
;;; lang/ocaml/packages.el
|
;;; lang/ocaml/packages.el
|
||||||
|
|
||||||
(when (featurep! +opam-site-lisp)
|
|
||||||
(defvar +ocaml-elisp-dir
|
|
||||||
(when (executable-find "opam")
|
|
||||||
(let ((opam-share (ignore-errors (car (process-lines "opam" "config" "var" "share" "--safe")))))
|
|
||||||
(when (and opam-share (file-directory-p opam-share))
|
|
||||||
(expand-file-name "emacs/site-lisp" opam-share)))))
|
|
||||||
|
|
||||||
(defmacro localpackage! (name)
|
|
||||||
`(package! ,name :recipe (:fetcher file :path ,+ocaml-elisp-dir)))
|
|
||||||
|
|
||||||
(localpackage! opam-site-lisp))
|
|
||||||
|
|
||||||
(package! tuareg)
|
(package! tuareg)
|
||||||
|
(package! merlin)
|
||||||
|
(package! ocp-indent)
|
||||||
|
|
||||||
(when (featurep! :feature syntax-checker)
|
(when (featurep! :feature syntax-checker)
|
||||||
(package! flycheck-ocaml))
|
(package! flycheck-ocaml))
|
||||||
|
|
||||||
(unless (featurep! +opam-site-lisp)
|
(when (featurep! :feature eval)
|
||||||
(package! merlin)
|
(package! utop))
|
||||||
(package! ocp-indent)
|
|
||||||
(when (featurep! :feature eval)
|
(when (featurep! :editor format)
|
||||||
(package! utop))
|
;; by default quelpa generated a version 0pre0.20180929.192844, which got
|
||||||
(when (featurep! :editor format)
|
;; parsed into (0 -1 0 ...), which when compared with version nil (0) in
|
||||||
;; by default quelpa generated a version 0pre0.20180929.192844, which got parsed into (0 -1 0 ...), which when compared with version nil (0)
|
;; package-installed-p always yielded false
|
||||||
;; in package-installed-p always yielded false
|
(package! ocamlformat :recipe (:fetcher github :repo "ocaml-ppx/ocamlformat" :files ("emacs/*.el"))))
|
||||||
(package! ocamlformat :recipe (:fetcher github :repo "ocaml-ppx/ocamlformat" :files ("emacs/*.el"))))
|
|
||||||
(package! dune :recipe (:fetcher github :repo "ocaml/dune" :files ("editor-integration/emacs/*.el"))))
|
(package! dune :recipe (:fetcher github :repo "ocaml/dune" :files ("editor-integration/emacs/*.el")))
|
||||||
|
|
||||||
|
|
||||||
|
;; (defvar +ocaml-elisp-dir
|
||||||
|
;; (when (executable-find "opam")
|
||||||
|
;; (let ((opam-share (ignore-errors (car (process-lines "opam" "config" "var" "share" "--safe")))))
|
||||||
|
;; (when (and opam-share (file-directory-p opam-share))
|
||||||
|
;; (expand-file-name "emacs/site-lisp" opam-share)))))
|
||||||
|
;;
|
||||||
|
;; (defmacro localpackage! (name)
|
||||||
|
;; `(package! ,name :recipe (:fetcher file :path ,+ocaml-elisp-dir)))
|
||||||
|
;;
|
||||||
|
;; (localpackage! opam-site-lisp)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue