An Emacs major mode for editing Agda code embedded in Org files
(.lagda.org
files.)
See the
Agda manual
for more information.
An older version of this support is documented in a blog post. The current version is a complete departure, motivated by
- the support in recent Agda versions (> 2.6) for literate files with
.lagda.org
extensions, and - the ability to work in multiple Emacs modes at once via the Polymode package.
;;; org-agda-mode.el --- Major mode for working with literate Org Agda files
;;; -*- lexical-binding: t
;;; Commentary:
;; A Major mode for editing Agda code embedded in Org files (.lagda.org files.)
;; See the Agda manual for more information:
;; https://agda.readthedocs.io/en/v2.6.1/tools/literate-programming.html#literate-org
;;; Code:
Simply place org-agda-mode.el
in your Emacs load path,
and add
(require 'org-agda-mode)
to your Emacs initialisation file.
Alternatively, if you use straight.el and use-package, then this package can be installed by adding the following to your emacs configuration.
(use-package polymode)
(use-package org-agda-mode
:straight (:host github
:repo "alhassy/org-agda-mode"
:branch "master"
:files ("org-agda-mode.el")
)
)
Polymode allows us to use more than one major mode in a buffer, something usually impossible in Emacs. Note there do exist several other solutions for this, such as MMM; Polymode seemed the best candidate for what I want during my (admittedly rather brief) search for solutions.
(require 'polymode)
(require 'agda2-mode)
(defgroup org-agda-mode nil
"org-agda-mode customisations"
:group 'languages)
Naturally, users will often want to use Agda input mode to enter unicode characters in their literate documentation. Do note that it’s also possible to enable this input mode globally in your Emacs init.
(defcustom use-agda-input t
"Whether to use Agda input mode in non-Agda parts of the file."
:group 'org-agda-mode
:type 'boolean)
Org is our hostmode.
(define-hostmode poly-org-agda-hostmode
:mode 'org-mode
:keep-in-mode 'host)
Agda is our inner mode, delimited by Org source blocks.
(define-innermode poly-org-agda-innermode
:mode 'agda2-mode
:head-matcher "#\\+begin_src agda2"
:tail-matcher "#\\+end_src"
;; Keep the code block wrappers in Org mode, so they can be folded, etc.
:head-mode 'org-mode
:tail-mode 'org-mode
;; Disable font-lock-mode, which interferes with Agda annotations,
;; and undo the change to indent-line-function Polymode makes.
:init-functions '((lambda (_) (font-lock-mode 0))
(lambda (_) (setq indent-line-function #'indent-relative))))
Now we define the polymode using the above host and inner modes.
(define-polymode org-agda-mode
:hostmode 'poly-org-agda-hostmode
:innermodes '(poly-org-agda-innermode)
(when use-agda-input (set-input-method "Agda")))
Agda’s highlighting mode makes use of annotate
to apply syntax highlighting
throughout the buffer, including the literate portion,
which agda2-highlight
identifies as “background”.
Older versions of Agda would highlight the background using
font-lock-comment-face
(so, making them the same colour as comments).
Newer versions (since
this
commit) simply apply Emacs’ default face.
Since we’re using Org mode for the literate portion, we don’t want Agda to apply any annotation there. We can achieve this by simply removing the setting for background from the Agda highlight faces attribute list.
(assq-delete-all 'background agda2-highlight-faces)
annotate
and font-lock
that we need to fix.
Finally, add our new mode to the auto mode list.
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.lagda.org" . org-agda-mode))
(provide 'org-agda-mode)
;;; org-agda-mode ends here
- Enable Agda loading, and more generally all the agda keybindings,
anywhere in .lagda.org files.
- At least the important ones that don’t obviously clash with Org bindings.
- I’ve tried loading via
M-x agda2-load
from the Org portion, and it works (yay!), but it loses the Agda syntax highlighting?
- To enable monolith
.lagda.org
files (large literate files which tangle several individual clean source files), we need a way to strip one level of indentation after tangling.- Actually it’s not needed; Agda does allow the contents of the toplevel module (so, the remainder of the file) to be indented; but it breaks convention.
- Discover the exact version of Agda that added support for
interactive programming in
.lagda.org
files.