Emacs code for indent mk:defsystem and asdf:defsystem
Raymond Toy <[email protected]> Tue, 28 Apr 2026 20:59:19 -0700
| Newsgroups | gmane.comp.mathematics.maxima.general |
|---|---|
| Message-ID | <[email protected]> |
I got tired of looking at the weirdly indented mk:defsystem definition that we have. I asked Claude to create some elisp code to indent them in a more natural form. Matches the current maxima.asd form, roughly. For kicks, I asked Claude to add a similar version for indenting asdf:defsystem. I haven’t applied it yet. I’m sure people will have different opinions on how to indent, but if someone wants to propose an “official” version, I’d be happy to use it. I’ve attached the elisp file. Just load it in emacs. Put point at the opening paren of |(mk:defsystem ...)| and enter |M-x mk-defsystem-reformat|. Use |asdf-defsystem-reformat| for asdf. Claude created some keybindings. Not sure I’ll use those. ​ _______________________________________________ Maxima-discuss mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/maxima-discuss
defsys-indent.el
(text/x-emacs-lisp, 5.5 KB)
;;; mk:defsystem and asdf:defsystem editing support
(require 'cl-indent)
(add-hook 'lisp-mode-hook
(lambda ()
(setq-local lisp-indent-function 'common-lisp-indent-function)))
;;; ---------------------------------------------------------------
;;; mk:defsystem
;;; ---------------------------------------------------------------
(defun mk-defsystem-indent (path state indent-point sexp-column normal-indent)
"Custom indent for mk:defsystem and component forms.
- :depends-on / :serial-depends-on values: data-list alignment
(continuation at open-paren + 1).
- Otherwise: defun-style body indent at +2."
(let* ((current-open (elt state 1))
(enclosing-kw (save-excursion
(goto-char current-open)
(condition-case nil
(progn
(backward-sexp 1)
(when (looking-at ":[a-zA-Z-]+")
(intern (match-string 0))))
(error nil)))))
(if (memq enclosing-kw '(:depends-on :serial-depends-on))
(save-excursion
(goto-char current-open)
(1+ (current-column)))
(lisp-indent-259 '(4 &rest 2) path state indent-point
sexp-column normal-indent))))
(put 'mk:defsystem 'common-lisp-indent-function 'mk-defsystem-indent)
(put 'defsystem 'common-lisp-indent-function 'mk-defsystem-indent)
(put :module 'common-lisp-indent-function 'mk-defsystem-indent)
(put :file 'common-lisp-indent-function 'mk-defsystem-indent)
(put :system 'common-lisp-indent-function 'mk-defsystem-indent)
(defvar mk-defsystem-break-before-keywords
'(":depends-on" ":components" ":serial-depends-on"
":source-pathname" ":source-extension"
":binary-pathname" ":binary-extension"
":initially-do" ":finally-do"
":compiler-options")
"Keywords in mk:defsystem that should start on a new line.")
(defun mk-defsystem-reformat ()
"Reformat the current top-level mk:defsystem form."
(interactive)
(defsystem-reformat-1 mk-defsystem-break-before-keywords))
;;; ---------------------------------------------------------------
;;; asdf:defsystem
;;; ---------------------------------------------------------------
(defun asdf-defsystem-indent (path state indent-point sexp-column normal-indent)
"Custom indent for asdf:defsystem.
- :depends-on values: data-list alignment.
- Otherwise: defun-style body indent at +2."
(let* ((current-open (elt state 1))
(enclosing-kw (save-excursion
(goto-char current-open)
(condition-case nil
(progn
(backward-sexp 1)
(when (looking-at ":[a-zA-Z-]+")
(intern (match-string 0))))
(error nil)))))
(if (memq enclosing-kw '(:depends-on :weakly-depends-on
:defsystem-depends-on))
(save-excursion
(goto-char current-open)
(1+ (current-column)))
(lisp-indent-259 '(4 &rest 2) path state indent-point
sexp-column normal-indent))))
(put 'asdf:defsystem 'common-lisp-indent-function 'asdf-defsystem-indent)
(defvar asdf-defsystem-break-before-keywords
'(":depends-on" ":weakly-depends-on" ":defsystem-depends-on"
":components" ":serial"
":pathname" ":default-component-class"
":author" ":maintainer" ":license" ":licence"
":description" ":long-description" ":version"
":homepage" ":bug-tracker" ":mailto" ":source-control"
":entry-point" ":build-operation" ":build-pathname"
":around-compile" ":encoding"
":in-order-to" ":perform"
":if-feature")
"Keywords in asdf:defsystem that should start on a new line.")
(defun asdf-defsystem-reformat ()
"Reformat the current top-level asdf:defsystem form."
(interactive)
(defsystem-reformat-1 asdf-defsystem-break-before-keywords))
;;; ---------------------------------------------------------------
;;; Shared reformatting machinery
;;; ---------------------------------------------------------------
(defun defsystem-reformat-1 (break-before-keywords)
"Break lines before each keyword in BREAK-BEFORE-KEYWORDS, then re-indent."
(save-excursion
(when (looking-at "(")
(forward-char 1))
(let ((bounds (bounds-of-thing-at-point 'defun)))
(unless bounds
(user-error "Not inside a top-level form"))
(save-restriction
(narrow-to-region (car bounds) (cdr bounds))
(goto-char (point-min))
(let ((re (concat "\\(?:#[-+][^ \t\n]+[ \t]+\\)?"
"\\_<"
(regexp-opt break-before-keywords)
"\\_>")))
(while (re-search-forward re nil t)
(let ((kw-start (match-beginning 0))
(ppss (syntax-ppss)))
(unless (or (nth 3 ppss) (nth 4 ppss)
(= (nth 0 ppss) 0))
(save-excursion
(goto-char kw-start)
(unless (looking-back "^[ \t]*" (line-beginning-position))
(delete-horizontal-space)
(insert "\n"))))))))
(indent-region (car bounds) (cdr bounds)))))
;;; ---------------------------------------------------------------
;;; Key bindings
;;; ---------------------------------------------------------------
(with-eval-after-load 'lisp-mode
(define-key lisp-mode-map (kbd "C-c C-=") #'mk-defsystem-reformat)
(define-key lisp-mode-map (kbd "C-c C-+") #'asdf-defsystem-reformat))