Emacs: Setting Up mmm-mode for Literate Haskell

2015-07-28
programming, emacs, haskell

I use Literate Haskell for some of my personal Haskell projects and for a long time I used the auto-loaded literate-haskell-mode that comes with haskell-mode. This past weekend, I finally buckled down and made use of mmm-mode to make the literate programming experience better. The biggest advantage of using mmm-mode is that you can define subregions of your file which are handled by a different major mode. In other words, you can get proper syntax highlighting for 2, 3, or more different languages in the same file!

Setup

You’ll need to install mmm-mode along with haskell-mode. I personally use MELPA for all of my Emacs packages because once you set it up it’s really painless.

In your emacs configuration file add these lines:

; Remove the hard-coded 'literate-haskell-mode' activation for `.lhs' files that
; haskell-mode comes with. In exchange, enable LaTeX mode whenever we open up a
; `.lhs' file. Using mmm-mode, we will activate `haskell-mode' in the code
; sections.
(setq auto-mode-alist
  (remove
    (rassoc 'literate-haskell-mode auto-mode-alist) auto-mode-alist))
(add-to-list 'auto-mode-alist '("\\.lhs$" . latex-mode))

; Literate Haskell - mmm-mode. Adopted from
; https://wiki.haskell.org/Literate_programming#Multi-mode_support_in_Emacs
(require 'mmm-auto)

(mmm-add-classes
  '((literate-haskell-latex
    :submode haskell-mode
    :front "^\\\\begin{code}\n"
    :back "^\\\\end{code}"
  )))

; Re-fontify sub-mode portions when idle. The manual command for this is
; `mmm-parse-buffer'. If you don't do this, then syntax highlighting won't work
; for new regions of Haskell code in the \begin{code}...\end{code} blocks.
(setq mmm-parse-when-idle 't)

. Now it’s a matter of running the following commands whenever you open up a .lhs file:

(setq mmm-global-mode 't)
(setq mmm-submode-decoration-level 1)
(mmm-ify-by-class 'literate-haskell-latex)

. Personally I use kakapo-mode so I have a file called kakapo-project-settings that has this snippet in it:

(defun my-kakapo-indents ()

  ...

  ; Literate Haskell
  ((string-match "\\.lhs$" b)
    (progn
      (h 'latex-mode-hook t 4)
      (setq mmm-global-mode 't)
      (setq mmm-submode-decoration-level 1)
      (mmm-ify-by-class 'literate-haskell-latex)
    )
  )

  ...

)

. Emacs will now automatically pick up .lhs files and apply latex-mode and haskell-mode with mmm-mode. Happy hacking!