Odoc .mld support in tuareg-mode (and my terrible hack)

As I’ve been spending some time lately trying to improve my doc game as I approach re-releasing a library I work on, I finally got around to using odoc’s .mld markdown format. Currently .mlds do not have any support (that I am aware of) in emacs, and I found the lack of the highlighting to be a bit of a bummer, leading to more mistakes being caught by the build. Anyway, I haven’t really done a whole lot of playing around in elisp beyond glorified configuration, so comprehending font-lock and how I could extend tuareg-mode to support setting up font-lock to treat the entire .mld as a doc comment is still a bit beyond me.

In lieu, I have come up with a dirty hack to get highlighting:

(add-to-list 'auto-mode-alist '("\\.mld\\'" . tuareg-mode))

(defun is-mld ()
  (string-equal "mld" (file-name-extension buffer-file-name)))

(defun is-doc-wrapped ()
  (and (string-equal (buffer-substring-no-properties 1 5) "(** ")
     (let* ((end (point-max)))
      (string-equal (buffer-substring-no-properties (- end 3) end) " *)"))))

(defun doc-wrap ()
  (unless (is-doc-wrapped)
    (save-excursion
      (goto-char (point-min))
      (insert "(** ")
      (goto-char (point-max))
      (insert " *)"))))

(defun doc-unwrap ()
    (when (is-doc-wrapped)
      (save-excursion
        (goto-char (point-min))
        (delete-char 4)
        (goto-char (point-max))
        (delete-char -3))))

(defun doc-wrapping-advice (fontify &rest args)
  (if (is-mld)
     (progn
       (doc-wrap)
       (apply fontify args)
       (doc-unwrap))
     (apply fontify args)))

(add-hook 'before-save-hook
  (lambda ()
    (when (and (eq major-mode 'tuareg-mode)
               (not (is-mld)))
      (ocamlformat))))

(add-hook 'lsp-mode-hook
  (lambda ()
    (when (and (eq major-mode 'tuareg-mode)
              lsp-mode
              (is-mld))
      (lsp-disconnect))))

(add-hook 'tuareg-mode-hook
  (lambda () (advice-add 'jit-lock--run-functions :around #'doc-wrapping-advice)))

Basically, I’m transiently wrapping the whole buffer in a doc comment (** ... *) whenever 'jit-lock--run-functions is called (which is managing the re-fontifying, as jit-lock is the active support mode for font-lock in my case). Other bits include avoiding ocamlformat and the lsp while working in an .mld, since those are normally active along with tuareg-mode.

There is probably (definitely) a better way to accomplish this, if anyone has any pointers/thoughts on how this could be improved / made more reliable, please share!

2 Likes