I'm typing in some old lisp code that makes heavy use of (prog) and (go).
I was trying to figure out how to get emacs to format the tagbody labels like the original source listing:
(PROG (X Y Z)
(...)
LOOP
(...)
(GO LOOP) )
I discovered that the common lisp indentation is supposed to support it, but it wasn't working.
The first line of the prog gets properly indented as either an _expression_ or a tag, but then every following line just gets the same indentation as the previous one.
Sure enough, lisp-indent-259 only only runs the indentation function for the first item after &rest:
(cond ((and tail (not (symbolp tem)))
;; indent tail of &rest in same way as first elt of rest
(throw 'exit normal-indent))
With this change the tagbodies get properly indented:
(cond ((and tail (not (or (consp tem) (symbolp tem))))
;; indent tail of &rest in same way as first elt of rest
(throw 'exit normal-indent))
Here's the entire patched function.
(defun lisp-indent-259
(method path state indent-point sexp-column normal-indent)
(catch 'exit
(let ((p path)
(containing-form-start (elt state 1))
n tem tail)
;; Isn't tail-recursion wonderful?
(while p
;; This while loop is for destructuring.
;; p is set to (cdr p) each iteration.
(if (not (consp method)) (lisp-indent-report-bad-format method))
(setq n (1- (car p))
p (cdr p)
tail nil)
(while n
;; This while loop is for advancing along a method
;; until the relevant (possibly &rest/&body) pattern
;; is reached.
;; n is set to (1- n) and method to (cdr method)
;; each iteration.
(setq tem (car method))
(or (eq tem 'nil) ;default indentation
(eq tem '&lambda) ;lambda list
(and (eq tem '&body) (null (cdr method)))
(and (eq tem '&rest)
(consp (cdr method))
(null (cddr method)))
(integerp tem) ;explicit indentation specified
(and (consp tem) ;destructuring
(eq (car tem) '&whole)
(or (symbolp (cadr tem))
(integerp (cadr tem))))
(and (symbolp tem) ;a function to call to do the work.
(null (cdr method)))
(lisp-indent-report-bad-format method))
(cond ((and tail (not (or (consp tem) (symbolp tem))))
;; indent tail of &rest in same way as first elt of rest
(throw 'exit normal-indent))
((eq tem '&body)
;; &body means (&rest <lisp-body-indent>)
(throw 'exit
(if (and (= n 0) ;first body form
(null p)) ;not in subforms
(+ sexp-column
lisp-body-indent)
normal-indent)))
((eq tem '&rest)
;; this pattern holds for all remaining forms
(setq tail (> n 0)
n 0
method (cdr method)))
((> n 0)
;; try next element of pattern
(setq n (1- n)
method (cdr method))
(if (< n 0)
;; Too few elements in pattern.
(throw 'exit normal-indent)))
((eq tem 'nil)
(throw 'exit (if (consp normal-indent)
normal-indent
(list normal-indent containing-form-start))))
((eq tem '&lambda)
(throw 'exit
(cond ((null p)
(list (+ sexp-column 4) containing-form-start))
((null (cdr p))
;; Indentation within a lambda-list. -- dvl
(list (lisp-indent-lambda-list
indent-point
sexp-column
containing-form-start)
containing-form-start))
(t
normal-indent))))
((integerp tem)
(throw 'exit
(if (null p) ;not in subforms
(list (+ sexp-column tem) containing-form-start)
normal-indent)))
((symbolp tem) ;a function to call
(throw 'exit
(funcall tem path state indent-point
sexp-column normal-indent)))
(t
;; must be a destructing frob
(if (not (null p))
;; descend
(setq method (cddr tem)
n nil)
(setq tem (cadr tem))
(throw 'exit
(cond (tail
normal-indent)
((eq tem 'nil)
(list normal-indent
containing-form-start))
((integerp tem)
(list (+ sexp-column tem)
containing-form-start))
(t
(funcall tem path state indent-point
sexp-column normal-indent))))))))))))
In GNU Emacs 25.1.1 (x86_64-pc-linux-gnu)
of 2017-09-14, modified by Debian built on trouble
System Description: Debian GNU/Linux 9.8 (stretch)
Configured using:
'configure --build x86_64-linux-gnu --prefix=/usr
--sharedstatedir=/var/lib --libexecdir=/usr/lib
--localstatedir=/var/lib --infodir=/usr/share/info
--mandir=/usr/share/man --with-pop=yes
--enable-locallisppath=/etc/emacs25:/etc/emacs:/usr/local/share/emacs/25.1/site-lisp:/usr/local/share/emacs/site-lisp:/usr/share/emacs/25.1/site-lisp:/usr/share/emacs/site-lisp
--with-sound=alsa --build x86_64-linux-gnu --prefix=/usr
--sharedstatedir=/var/lib --libexecdir=/usr/lib
--localstatedir=/var/lib --infodir=/usr/share/info
--mandir=/usr/share/man --with-pop=yes
--enable-locallisppath=/etc/emacs25:/etc/emacs:/usr/local/share/emacs/25.1/site-lisp:/usr/local/share/emacs/site-lisp:/usr/share/emacs/25.1/site-lisp:/usr/share/emacs/site-lisp
--with-sound=alsa --with-x=no --without-gconf --without-gsettings
'CFLAGS=-g -O2
-fdebug-prefix-map=/build/emacs25-wN2qS3/emacs25-25.1+1=. -fstack-protector-strong
-Wformat -Werror=format-security -Wall' 'CPPFLAGS=-Wdate-time
-D_FORTIFY_SOURCE=2' LDFLAGS=-Wl,-z,relro'
Configured features:
JPEG SOUND GPM DBUS NOTIFY ACL LIBSELINUX GNUTLS LIBXML2 ZLIB
Important settings:
value of $LANG: en_US.UTF-8
locale-coding-system: utf-8-unix
Major mode: Lisp
Minor modes in effect:
tooltip-mode: t
global-eldoc-mode: t
electric-indent-mode: t
menu-bar-mode: t
file-name-shadow-mode: t
global-font-lock-mode: t
font-lock-mode: t
auto-composition-mode: t
auto-encryption-mode: t
auto-compression-mode: t
line-number-mode: t
transient-mark-mode: t
Recent messages:
Auto-saving...
Mark set
Auto-saving...done
Auto-saving...done
next-line: End of buffer
Auto-saving...done
Mark set [2 times]
Auto-saving...done
Saving file /home/ryan/sin.lisp...
Wrote /home/ryan/sin.lisp
Load-path shadows:
/usr/share/emacs/25.1/site-lisp/debian-startup hides /usr/share/emacs/site-lisp/debian-startup
Features:
(shadow sort mail-extr emacsbug message dired format-spec rfc822 mml
mml-sec password-cache epg epg-config gnus-util mm-decode mm-bodies
mm-encode mail-parse rfc2231 mailabbrev gmm-utils mailheader sendmail
rfc2047 rfc2045 ietf-drums mm-util mail-prsvr mail-utils cl-extra
thingatpt help-fns help-mode tool-bar cus-edit cus-start cus-load
wid-edit regexp-opt gv find-func edebug easymenu cl-loaddefs pcase
cl-lib misearch multi-isearch jka-compr term/xterm xterm time-date
cl-indent mule-util tooltip eldoc electric uniquify ediff-hook vc-hooks
lisp-float-type tabulated-list newcomment elisp-mode lisp-mode prog-mode
register page menu-bar rfn-eshadow timer select mouse jit-lock font-lock
syntax facemenu font-core frame cl-generic cham georgian utf-8-lang
misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms
cp51932 hebrew greek romanian slovak czech european ethiopic indian
cyrillic chinese charscript case-table epa-hook jka-cmpr-hook help
simple abbrev minibuffer cl-preloaded nadvice loaddefs button faces
cus-face macroexp files text-properties overlay sha1 md5 base64 format
env code-pages mule custom widget hashtable-print-readable backquote
dbusbind inotify multi-tty make-network-process emacs)
Memory information:
((conses 16 124690 4205)
(symbols 48 20939 0)
(miscs 40 122 580)
(strings 32 20140 4691)
(string-bytes 1 550849)
(vectors 16 11774)
(vector-slots 8 399804 2164)
(floats 8 172 959)
(intervals 56 3273 0)
(buffers 976 25))