;;; slime-cl-indent.el --- enhanced lisp-indent mode
|
|
|
|
;; Copyright (C) 1987, 2000-2011 Free Software Foundation, Inc.
|
|
|
|
;; Author: Richard Mlynarik <mly@eddie.mit.edu>
|
|
;; Created: July 1987
|
|
;; Maintainer: FSF
|
|
;; Keywords: lisp, tools
|
|
;; Package: emacs
|
|
|
|
;; This file is forked from cl-indent.el, which is part of GNU Emacs.
|
|
|
|
;; GNU Emacs is free software: you can redistribute it and/or modify
|
|
;; it under the terms of the GNU General Public License as published by
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
;; (at your option) any later version.
|
|
|
|
;; GNU Emacs is distributed in the hope that it will be useful,
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;; GNU General Public License for more details.
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
;;; Commentary:
|
|
|
|
;; This package supplies a single entry point, common-lisp-indent-function,
|
|
;; which performs indentation in the preferred style for Common Lisp code.
|
|
;; To enable it:
|
|
;;
|
|
;; (setq lisp-indent-function 'common-lisp-indent-function)
|
|
;;
|
|
;; This file is substantially patched from original cl-indent.el,
|
|
;; which is in Emacs proper. It does not require SLIME, but is instead
|
|
;; required by one of it's contribs, `slime-indentation'.
|
|
;;
|
|
;; Before making modifications to this file, consider adding them to
|
|
;; Emacs's own `cl-indent' and refactoring this file to be an
|
|
;; extension of Emacs's.
|
|
|
|
;;; Code:
|
|
|
|
(require 'slime) ; only for its cl-lib loading smartness
|
|
(require 'cl-lib)
|
|
(eval-when-compile (require 'cl))
|
|
|
|
(defgroup lisp-indent nil
|
|
"Indentation in Lisp."
|
|
:group 'lisp)
|
|
|
|
(defcustom lisp-indent-maximum-backtracking 6
|
|
"Maximum depth to backtrack out from a sublist for structured indentation.
|
|
If this variable is 0, no backtracking will occur and forms such as `flet'
|
|
may not be correctly indented if this value is less than 4."
|
|
:type 'integer
|
|
:group 'lisp-indent)
|
|
|
|
(defcustom lisp-tag-indentation 1
|
|
"Indentation of tags relative to containing list.
|
|
This variable is used by the function `lisp-indent-tagbody'."
|
|
:type 'integer
|
|
:group 'lisp-indent)
|
|
|
|
(defcustom lisp-tag-body-indentation 3
|
|
"Indentation of non-tagged lines relative to containing list.
|
|
This variable is used by the function `lisp-indent-tagbody' to indent normal
|
|
lines (lines without tags).
|
|
The indentation is relative to the indentation of the parenthesis enclosing
|
|
the special form. If the value is t, the body of tags will be indented
|
|
as a block at the same indentation as the first s-expression following
|
|
the tag. In this case, any forms before the first tag are indented
|
|
by `lisp-body-indent'."
|
|
:type 'integer
|
|
:group 'lisp-indent)
|
|
|
|
(defcustom lisp-backquote-indentation t
|
|
"Whether or not to indent backquoted lists as code.
|
|
If nil, indent backquoted lists as data, i.e., like quoted lists."
|
|
:type 'boolean
|
|
:group 'lisp-indent)
|
|
|
|
(defcustom lisp-loop-indent-subclauses t
|
|
"Whether or not to indent loop subclauses."
|
|
:type 'boolean
|
|
:group 'lisp-indent)
|
|
|
|
(defcustom lisp-simple-loop-indentation 2
|
|
"Indentation of forms in simple loop forms."
|
|
:type 'integer
|
|
:group 'lisp-indent)
|
|
|
|
(defcustom lisp-loop-clauses-indentation 2
|
|
"Indentation of loop clauses if `loop' is immediately followed by a newline."
|
|
:type 'integer
|
|
:group 'lisp-indent)
|
|
|
|
(defcustom lisp-loop-indent-body-forms-relative-to-loop-start nil
|
|
"When true, indent loop body clauses relative to the open paren of the loop
|
|
form, instead of the keyword position."
|
|
:type 'boolean
|
|
:group 'lisp-indent)
|
|
|
|
(defcustom lisp-loop-body-forms-indentation 3
|
|
"Indentation of loop body clauses."
|
|
:type 'integer
|
|
:group 'lisp-indent)
|
|
|
|
(defcustom lisp-loop-indent-forms-like-keywords nil
|
|
"Whether or not to indent loop subforms just like
|
|
loop keywords. Only matters when `lisp-loop-indent-subclauses'
|
|
is nil."
|
|
:type 'boolean
|
|
:group 'lisp-indent)
|
|
|
|
(defcustom lisp-align-keywords-in-calls t
|
|
"Whether to align keyword arguments vertically or not.
|
|
If t (the default), keywords in contexts where no other
|
|
indentation rule takes precedence are aligned like this:
|
|
|
|
\(make-instance 'foo :bar t
|
|
:quux 42)
|
|
|
|
If nil, they are indented like any other function
|
|
call arguments:
|
|
|
|
\(make-instance 'foo :bar t
|
|
:quux 42)"
|
|
:type 'boolean
|
|
:group 'lisp-indent)
|
|
|
|
(defcustom lisp-lambda-list-indentation t
|
|
"Whether to indent lambda-lists specially. Defaults to t. Setting this to
|
|
nil makes `lisp-lambda-list-keyword-alignment',
|
|
`lisp-lambda-list-keyword-parameter-alignment', and
|
|
`lisp-lambda-list-keyword-parameter-indentation' meaningless, causing
|
|
lambda-lists to be indented as if they were data:
|
|
|
|
\(defun example (a b &optional o1 o2
|
|
o3 o4
|
|
&rest r
|
|
&key k1 k2
|
|
k3 k4)
|
|
#|...|#)"
|
|
:type 'boolean
|
|
:group 'lisp-indent)
|
|
|
|
(defcustom lisp-lambda-list-keyword-alignment nil
|
|
"Whether to vertically align lambda-list keywords together.
|
|
If nil (the default), keyworded lambda-list parts are aligned
|
|
with the initial mandatory arguments, like this:
|
|
|
|
\(defun foo (arg1 arg2 &rest rest
|
|
&key key1 key2)
|
|
#|...|#)
|
|
|
|
If non-nil, alignment is done with the first keyword
|
|
\(or falls back to the previous case), as in:
|
|
|
|
\(defun foo (arg1 arg2 &rest rest
|
|
&key key1 key2)
|
|
#|...|#)"
|
|
:type 'boolean
|
|
:group 'lisp-indent)
|
|
|
|
(defcustom lisp-lambda-list-keyword-parameter-indentation 2
|
|
"Indentation of lambda list keyword parameters.
|
|
See `lisp-lambda-list-keyword-parameter-alignment'
|
|
for more information."
|
|
:type 'integer
|
|
:group 'lisp-indent)
|
|
|
|
(defcustom lisp-lambda-list-keyword-parameter-alignment nil
|
|
"Whether to vertically align lambda-list keyword parameters together.
|
|
If nil (the default), the parameters are aligned
|
|
with their corresponding keyword, plus the value of
|
|
`lisp-lambda-list-keyword-parameter-indentation', like this:
|
|
|
|
\(defun foo (arg1 arg2 &key key1 key2
|
|
key3 key4)
|
|
#|...|#)
|
|
|
|
If non-nil, alignment is done with the first parameter
|
|
\(or falls back to the previous case), as in:
|
|
|
|
\(defun foo (arg1 arg2 &key key1 key2
|
|
key3 key4)
|
|
#|...|#)"
|
|
:type 'boolean
|
|
:group 'lisp-indent)
|
|
|
|
|
|
(defvar lisp-indent-defun-method '(4 &lambda &body)
|
|
"Defun-like indentation method.
|
|
This applies when the value of the `common-lisp-indent-function' property
|
|
is set to `defun'.")
|
|
|
|
|
|
;;;; Named styles.
|
|
;;;;
|
|
;;;; -*- common-lisp-style: foo -*-
|
|
;;;;
|
|
;;;; sets the style for the buffer.
|
|
;;;;
|
|
;;;; A Common Lisp style is a list of the form:
|
|
;;;;
|
|
;;;; (NAME INHERIT VARIABLES INDENTATION HOOK DOCSTRING)
|
|
;;;;
|
|
;;;; where NAME is a symbol naming the style, INHERIT is the name of the style
|
|
;;;; it inherits from, VARIABLES is an alist specifying buffer local variables
|
|
;;;; for the style, and INDENTATION is an alist specifying non-standard
|
|
;;;; indentations for Common Lisp symbols. HOOK is a function to call when
|
|
;;;; activating the style. DOCSTRING is the documentation for the style.
|
|
;;;;
|
|
;;;; Convenience accessors `common-lisp-style-name', &co exist.
|
|
;;;;
|
|
;;;; `common-lisp-style' stores the name of the current style.
|
|
;;;;
|
|
;;;; `common-lisp-style-default' stores the name of the style to use when none
|
|
;;;; has been specified.
|
|
;;;;
|
|
;;;; `common-lisp-active-style' stores a cons of the list specifying the
|
|
;;;; current style, and a hash-table containing all indentation methods of
|
|
;;;; that style and any styles it inherits from. Whenever we're indenting, we
|
|
;;;; check that this is up to date, and recompute when necessary.
|
|
;;;;
|
|
;;;; Just setting the buffer local common-lisp-style will be enough to have
|
|
;;;; the style take effect. `common-lisp-set-style' can also be called
|
|
;;;; explicitly, however, and offers name completion, etc.
|
|
|
|
;;; Convenience accessors
|
|
(defun common-lisp-style-name (style) (first style))
|
|
(defun common-lisp-style-inherits (style) (second style))
|
|
(defun common-lisp-style-variables (style) (third style))
|
|
(defun common-lisp-style-indentation (style) (fourth style))
|
|
(defun common-lisp-style-hook (style) (fifth style))
|
|
(defun common-lisp-style-docstring (style) (sixth style))
|
|
|
|
(defun common-lisp-make-style (stylename inherits variables indentation hook
|
|
documentation)
|
|
(list stylename inherits variables indentation hook documentation))
|
|
|
|
(defvar common-lisp-style nil)
|
|
|
|
;;; `define-common-lisp-style' updates the docstring of
|
|
;;; `common-lisp-style', using this as the base.
|
|
(put 'common-lisp-style 'common-lisp-style-base-doc
|
|
"Name of the Common Lisp indentation style used in the current buffer.
|
|
Set this by giving eg.
|
|
|
|
;; -*- common-lisp-style: sbcl -*-
|
|
|
|
in the first line of the file, or by calling `common-lisp-set-style'. If
|
|
buffer has no style specified, but `common-lisp-style-default' is set, that
|
|
style is used instead. Use `define-common-lisp-style' to define new styles.")
|
|
|
|
(make-variable-buffer-local 'common-lisp-style)
|
|
(set-default 'common-lisp-style nil)
|
|
|
|
;;; `lisp-mode' kills all buffer-local variables. Setting the
|
|
;;; `permanent-local' property allows us to retain the style.
|
|
(put 'common-lisp-style 'permanent-local t)
|
|
|
|
;;; Mark as safe when the style doesn't evaluate arbitrary code.
|
|
(put 'common-lisp-style 'safe-local-variable 'common-lisp-safe-style-p)
|
|
|
|
;;; Common Lisp indentation style specifications.
|
|
(defvar common-lisp-styles (make-hash-table :test 'equal))
|
|
|
|
(defun common-lisp-delete-style (stylename)
|
|
(remhash stylename common-lisp-styles))
|
|
|
|
(defun common-lisp-find-style (stylename)
|
|
(let ((name (if (symbolp stylename)
|
|
(symbol-name stylename)
|
|
stylename)))
|
|
(or (gethash name common-lisp-styles)
|
|
(error "Unknown Common Lisp style: %s" name))))
|
|
|
|
(defun common-lisp-safe-style-p (stylename)
|
|
"True for known Common Lisp style without an :EVAL option.
|
|
Ie. styles that will not evaluate arbitrary code on activation."
|
|
(let* ((style (ignore-errors (common-lisp-find-style stylename)))
|
|
(base (common-lisp-style-inherits style)))
|
|
(and style
|
|
(not (common-lisp-style-hook style))
|
|
(or (not base)
|
|
(common-lisp-safe-style-p base)))))
|
|
|
|
(defun common-lisp-add-style (stylename inherits variables indentation hooks
|
|
documentation)
|
|
;; Invalidate indentation methods cached in common-lisp-active-style.
|
|
(maphash (lambda (k v)
|
|
(puthash k (cl-copy-list v) common-lisp-styles))
|
|
common-lisp-styles)
|
|
;; Add/Redefine the specified style.
|
|
(puthash stylename
|
|
(common-lisp-make-style stylename inherits variables indentation
|
|
hooks documentation)
|
|
common-lisp-styles)
|
|
;; Frob `common-lisp-style' docstring.
|
|
(let ((doc (get 'common-lisp-style 'common-lisp-style-base-doc))
|
|
(all nil))
|
|
(setq doc (concat doc "\n\nAvailable styles are:\n"))
|
|
(maphash (lambda (name style)
|
|
(push (list name (common-lisp-style-docstring style)) all))
|
|
common-lisp-styles)
|
|
(dolist (info (sort all (lambda (a b) (string< (car a) (car b)))))
|
|
(let ((style-name (first info))
|
|
(style-doc (second info)))
|
|
(if style-doc
|
|
(setq doc (concat doc
|
|
"\n " style-name "\n"
|
|
" " style-doc "\n"))
|
|
(setq doc (concat doc
|
|
"\n " style-name " (undocumented)\n")))))
|
|
(put 'common-lisp-style 'variable-documentation doc))
|
|
stylename)
|
|
|
|
;;; Activate STYLENAME, adding its indentation methods to METHODS -- and
|
|
;;; recurse on style inherited from.
|
|
(defun common-lisp-activate-style (stylename methods)
|
|
(let* ((style (common-lisp-find-style stylename))
|
|
(basename (common-lisp-style-inherits style)))
|
|
;; Recurse on parent.
|
|
(when basename
|
|
(common-lisp-activate-style basename methods))
|
|
;; Copy methods
|
|
(dolist (spec (common-lisp-style-indentation style))
|
|
(puthash (first spec) (second spec) methods))
|
|
;; Bind variables.
|
|
(dolist (var (common-lisp-style-variables style))
|
|
(set (make-local-variable (first var)) (second var)))
|
|
;; Run hook.
|
|
(let ((hook (common-lisp-style-hook style)))
|
|
(when hook
|
|
(funcall hook)))))
|
|
|
|
;;; When a style is being used, `common-lisp-active-style' holds a cons
|
|
;;;
|
|
;;; (STYLE . METHODS)
|
|
;;;
|
|
;;; where STYLE is the list specifying the currently active style, and
|
|
;;; METHODS is the table of indentation methods -- including inherited
|
|
;;; ones -- for it. `common-lisp-active-style-methods' is reponsible
|
|
;;; for keeping this up to date.
|
|
(make-variable-buffer-local (defvar common-lisp-active-style nil))
|
|
|
|
;;; Makes sure common-lisp-active-style corresponds to common-lisp-style, and
|
|
;;; pick up redefinitions, etc. Returns the method table for the currently
|
|
;;; active style.
|
|
(defun common-lisp-active-style-methods ()
|
|
(let* ((name common-lisp-style)
|
|
(style (when name (common-lisp-find-style name))))
|
|
(if (eq style (car common-lisp-active-style))
|
|
(cdr common-lisp-active-style)
|
|
(when style
|
|
(let ((methods (make-hash-table :test 'equal)))
|
|
(common-lisp-activate-style name methods)
|
|
(setq common-lisp-active-style (cons style methods))
|
|
methods)))))
|
|
|
|
(defvar common-lisp-set-style-history nil)
|
|
|
|
(defun common-lisp-style-names ()
|
|
(let (names)
|
|
(maphash (lambda (k v)
|
|
(push (cons k v) names))
|
|
common-lisp-styles)
|
|
names))
|
|
|
|
(defun common-lisp-set-style (stylename)
|
|
"Set current buffer to use the Common Lisp style STYLENAME.
|
|
STYLENAME, a string, must be an existing Common Lisp style. Styles
|
|
are added (and updated) using `define-common-lisp-style'.
|
|
|
|
The buffer-local variable `common-lisp-style' will get set to STYLENAME.
|
|
|
|
A Common Lisp style is composed of local variables, indentation
|
|
specifications, and may also contain arbitrary elisp code to run upon
|
|
activation."
|
|
(interactive
|
|
(list (let ((completion-ignore-case t)
|
|
(prompt "Specify Common Lisp indentation style: "))
|
|
(completing-read prompt
|
|
(common-lisp-style-names) nil t nil
|
|
'common-lisp-set-style-history))))
|
|
(setq common-lisp-style (common-lisp-style-name
|
|
(common-lisp-find-style stylename))
|
|
common-lisp-active-style nil)
|
|
;; Actually activates the style.
|
|
(common-lisp-active-style-methods)
|
|
stylename)
|
|
|
|
(defmacro define-common-lisp-style (name documentation &rest options)
|
|
"Define a Common Lisp indentation style.
|
|
|
|
NAME is the name of the style.
|
|
|
|
DOCUMENTATION is the docstring for the style, automatically added to the
|
|
docstring of `common-lisp-style'.
|
|
|
|
OPTIONS are:
|
|
|
|
(:variables (name value) ...)
|
|
|
|
Specifying the buffer local variables associated with the style.
|
|
|
|
(:indentation (symbol spec) ...)
|
|
|
|
Specifying custom indentations associated with the style. SPEC is
|
|
a normal `common-lisp-indent-function' indentation specification.
|
|
|
|
(:inherit style)
|
|
|
|
Inherit variables and indentations from another Common Lisp style.
|
|
|
|
(:eval form ...)
|
|
|
|
Lisp code to evaluate when activating the style. This can be used to
|
|
eg. activate other modes. It is possible that over the lifetime of
|
|
a buffer same style gets activated multiple times, so code in :eval
|
|
option should cope with that.
|
|
"
|
|
(when (consp documentation)
|
|
(setq options (cons documentation options)
|
|
documentation nil))
|
|
`(common-lisp-add-style ,name
|
|
',(cadr (assoc :inherit options))
|
|
',(cdr (assoc :variables options))
|
|
',(cdr (assoc :indentation options))
|
|
,(when (assoc :eval options)
|
|
`(lambda ()
|
|
,@(cdr (assoc :eval options))))
|
|
,documentation))
|
|
|
|
(define-common-lisp-style "basic-common"
|
|
(:variables
|
|
(lisp-indent-maximum-backtracking 6)
|
|
(lisp-tag-indentation 1)
|
|
(lisp-tag-body-indentation 3)
|
|
(lisp-backquote-indentation t)
|
|
(lisp-loop-indent-subclauses t)
|
|
(lisp-loop-indent-forms-like-keywords nil)
|
|
(lisp-simple-loop-indentation 2)
|
|
(lisp-align-keywords-in-calls t)
|
|
(lisp-lambda-list-indentation t)
|
|
(lisp-lambda-list-keyword-alignment nil)
|
|
(lisp-lambda-list-keyword-parameter-indentation 2)
|
|
(lisp-lambda-list-keyword-parameter-alignment nil)
|
|
(lisp-indent-defun-method (4 &lambda &body))
|
|
(lisp-loop-clauses-indentation 2)
|
|
(lisp-loop-indent-body-forms-relative-to-loop-start nil)
|
|
(lisp-loop-body-forms-indentation 3)))
|
|
|
|
(define-common-lisp-style "basic-emacs25"
|
|
"This style adds a workaround needed for Emacs 25"
|
|
(:inherit "basic-common")
|
|
(:variables
|
|
;; Without these (;;foo would get a space inserted between
|
|
;; ( and ; by indent-sexp.
|
|
(comment-indent-function (lambda () nil))))
|
|
|
|
(define-common-lisp-style "basic-emacs26"
|
|
"This style is the same as basic-common. It doesn't need or
|
|
want the workaround used in Emacs 25. In Emacs 26, that
|
|
workaround introduces a weird behavior where a single
|
|
semicolon breaks the mode and causes the cursor to move to the
|
|
start of the line after every character inserted."
|
|
(:inherit "basic-common"))
|
|
|
|
(if (>= emacs-major-version 26)
|
|
(define-common-lisp-style "basic"
|
|
"This style merely gives all identation variables their default values,
|
|
making it easy to create new styles that are proof against user
|
|
customizations. It also adjusts comment indentation from default.
|
|
All other predefined modes inherit from basic."
|
|
(:inherit "basic-emacs26"))
|
|
(define-common-lisp-style "basic"
|
|
"This style merely gives all identation variables their default values,
|
|
making it easy to create new styles that are proof against user
|
|
customizations. It also adjusts comment indentation from default.
|
|
All other predefined modes inherit from basic."
|
|
(:inherit "basic-emacs25")))
|
|
|
|
(define-common-lisp-style "classic"
|
|
"This style of indentation emulates the most striking features of 1995
|
|
vintage cl-indent.el once included as part of Slime: IF indented by two
|
|
spaces, and CASE clause bodies indentented more deeply than the keys."
|
|
(:inherit "basic")
|
|
(:variables
|
|
(lisp-lambda-list-keyword-parameter-indentation 0))
|
|
(:indentation
|
|
(case (4 &rest (&whole 2 &rest 3)))
|
|
(if (4 2 2))))
|
|
|
|
(define-common-lisp-style "modern"
|
|
"A good general purpose style. Turns on lambda-list keyword and keyword
|
|
parameter alignment, and turns subclause aware loop indentation off.
|
|
(Loop indentation so because simpler style is more prevalent in existing
|
|
sources, not because it is necessarily preferred.)"
|
|
(:inherit "basic")
|
|
(:variables
|
|
(lisp-lambda-list-keyword-alignment t)
|
|
(lisp-lambda-list-keyword-parameter-alignment t)
|
|
(lisp-lambda-list-keyword-parameter-indentation 0)
|
|
(lisp-loop-indent-subclauses nil)))
|
|
|
|
(define-common-lisp-style "sbcl"
|
|
"Style used in SBCL sources. A good if somewhat intrusive general purpose
|
|
style based on the \"modern\" style. Adds indentation for a few SBCL
|
|
specific constructs, sets indentation to use spaces instead of tabs,
|
|
fill-column to 78, and activates whitespace-mode to show tabs and trailing
|
|
whitespace."
|
|
(:inherit "modern")
|
|
(:eval
|
|
(whitespace-mode 1))
|
|
(:variables
|
|
(whitespace-style (tabs trailing))
|
|
(indent-tabs-mode nil)
|
|
(comment-fill-column nil)
|
|
(fill-column 78))
|
|
(:indentation
|
|
(def!constant (as defconstant))
|
|
(def!macro (as defmacro))
|
|
(def!method (as defmethod))
|
|
(def!struct (as defstruct))
|
|
(def!type (as deftype))
|
|
(defmacro-mundanely (as defmacro))
|
|
(define-source-transform (as defun))
|
|
(!def-type-translator (as defun))
|
|
(!def-debug-command (as defun))))
|
|
|
|
(defcustom common-lisp-style-default nil
|
|
"Name of the Common Lisp indentation style to use in lisp-mode buffers if
|
|
none has been specified."
|
|
:type `(choice (const :tag "None" nil)
|
|
,@(mapcar (lambda (spec)
|
|
`(const :tag ,(car spec) ,(car spec)))
|
|
(common-lisp-style-names))
|
|
(string :tag "Other"))
|
|
:group 'lisp-indent)
|
|
|
|
;;; If style is being used, that's a sufficient invitation to snag
|
|
;;; the indentation function.
|
|
(defun common-lisp-lisp-mode-hook ()
|
|
(let ((style (or common-lisp-style common-lisp-style-default)))
|
|
(when style
|
|
(set (make-local-variable 'lisp-indent-function)
|
|
'common-lisp-indent-function)
|
|
(common-lisp-set-style style))))
|
|
(add-hook 'lisp-mode-hook 'common-lisp-lisp-mode-hook)
|
|
|
|
|
|
;;;; The indentation specs are stored at three levels. In order of priority:
|
|
;;;;
|
|
;;;; 1. Indentation as set by current style, from the indentation table
|
|
;;;; in the current style.
|
|
;;;;
|
|
;;;; 2. Globally set indentation, from the `common-lisp-indent-function'
|
|
;;;; property of the symbol.
|
|
;;;;
|
|
;;;; 3. Per-package indentation derived by the system. A live Common Lisp
|
|
;;;; system may (via Slime, eg.) add indentation specs to
|
|
;;;; common-lisp-system-indentation, where they are associated with
|
|
;;;; the package of the symbol. Then we run some lossy heuristics and
|
|
;;;; find something that looks promising.
|
|
;;;;
|
|
;;;; FIXME: for non-system packages the derived indentation should probably
|
|
;;;; take precedence.
|
|
|
|
;;; This maps symbols into lists of (INDENT . PACKAGES) where INDENT is
|
|
;;; an indentation spec, and PACKAGES are the names of packages where this
|
|
;;; applies.
|
|
;;;
|
|
;;; We never add stuff here by ourselves: this is for things like Slime to
|
|
;;; fill.
|
|
(defvar common-lisp-system-indentation (make-hash-table :test 'equal))
|
|
|
|
(defun common-lisp-guess-current-package ()
|
|
(let (pkg)
|
|
(save-excursion
|
|
(ignore-errors
|
|
(when (let ((case-fold-search t))
|
|
(search-backward "(in-package "))
|
|
(re-search-forward "[ :\"]+")
|
|
(let ((start (point)))
|
|
(re-search-forward "[\":)]")
|
|
(setf pkg (upcase (buffer-substring-no-properties
|
|
start (1- (point)))))))))
|
|
pkg))
|
|
|
|
(defvar common-lisp-current-package-function 'common-lisp-guess-current-package
|
|
"Used to derive the package name to use for indentation at a
|
|
given point. Defaults to `common-lisp-guess-current-package'.")
|
|
|
|
(defun common-lisp-symbol-package (string)
|
|
(if (and (stringp string) (string-match ":" string))
|
|
(let ((p (match-beginning 0)))
|
|
(if (eql 0 p)
|
|
"KEYWORD"
|
|
(upcase (substring string 0 p))))
|
|
(funcall common-lisp-current-package-function)))
|
|
|
|
(defun common-lisp-get-indentation (name &optional full)
|
|
"Retrieves the indentation information for NAME."
|
|
(let ((method
|
|
(or
|
|
;; From style
|
|
(when common-lisp-style
|
|
(gethash name (common-lisp-active-style-methods)))
|
|
;; From global settings.
|
|
(get name 'common-lisp-indent-function)
|
|
;; From system derived information.
|
|
(let ((system-info (gethash name common-lisp-system-indentation)))
|
|
(if (not (cdr system-info))
|
|
(caar system-info)
|
|
(let ((guess nil)
|
|
(guess-n 0)
|
|
(package (common-lisp-symbol-package full)))
|
|
(dolist (info system-info guess)
|
|
(let* ((pkgs (cdr info))
|
|
(n (length pkgs)))
|
|
(cond ((member package pkgs)
|
|
;; This is it.
|
|
(return (car info)))
|
|
((> n guess-n)
|
|
;; If we can't find the real thing, go with the one
|
|
;; accessible in most packages.
|
|
(setf guess (car info)
|
|
guess-n n)))))))))))
|
|
(if (and (consp method) (eq 'as (car method)))
|
|
(common-lisp-get-indentation (cadr method))
|
|
method)))
|
|
|
|
;;;; LOOP indentation, the simple version
|
|
|
|
(defun common-lisp-loop-type (loop-start)
|
|
"Returns the type of the loop form at LOOP-START.
|
|
Possible types are SIMPLE, SIMPLE/SPLIT, EXTENDED, and EXTENDED/SPLIT. */SPLIT
|
|
refers to extended loops whose body does not start on the same line as the
|
|
opening parenthesis of the loop."
|
|
(let (comment-split)
|
|
(condition-case ()
|
|
(save-excursion
|
|
(goto-char loop-start)
|
|
(let ((line (line-number-at-pos))
|
|
(maybe-split t))
|
|
(forward-char 1)
|
|
(forward-sexp 1)
|
|
(save-excursion
|
|
(when (looking-at "\\s-*\\\n*;")
|
|
(search-forward ";")
|
|
(backward-char 1)
|
|
(if (= line (line-number-at-pos))
|
|
(setq maybe-split nil)
|
|
(setq comment-split t))))
|
|
(forward-sexp 1)
|
|
(backward-sexp 1)
|
|
(if (eql (char-after) ?\()
|
|
(if (or (not maybe-split) (= line (line-number-at-pos)))
|
|
'simple
|
|
'simple/split)
|
|
(if (or (not maybe-split) (= line (line-number-at-pos)))
|
|
'extended
|
|
'extended/split))))
|
|
(error
|
|
(if comment-split
|
|
'simple/split
|
|
'simple)))))
|
|
|
|
(defun common-lisp-trailing-comment ()
|
|
(ignore-errors
|
|
;; If we had a trailing comment just before this, find it.
|
|
(save-excursion
|
|
(backward-sexp)
|
|
(forward-sexp)
|
|
(when (looking-at "\\s-*;")
|
|
(search-forward ";")
|
|
(1- (current-column))))))
|
|
|
|
;;;###autoload
|
|
(defun common-lisp-indent-function (indent-point state)
|
|
"Function to indent the arguments of a Lisp function call.
|
|
This is suitable for use as the value of the variable
|
|
`lisp-indent-function'. INDENT-POINT is the point at which the
|
|
indentation function is called, and STATE is the
|
|
`parse-partial-sexp' state at that position. Browse the
|
|
`lisp-indent' customize group for options affecting the behavior
|
|
of this function.
|
|
|
|
If the indentation point is in a call to a Lisp function, that
|
|
function's common-lisp-indent-function property specifies how
|
|
this function should indent it. Possible values for this
|
|
property are:
|
|
|
|
* defun, meaning indent according to `lisp-indent-defun-method';
|
|
i.e., like (4 &lambda &body), as explained below.
|
|
|
|
* any other symbol, meaning a function to call. The function should
|
|
take the arguments: PATH STATE INDENT-POINT SEXP-COLUMN NORMAL-INDENT.
|
|
PATH is a list of integers describing the position of point in terms of
|
|
list-structure with respect to the containing lists. For example, in
|
|
((a b c (d foo) f) g), foo has a path of (0 3 1). In other words,
|
|
to reach foo take the 0th element of the outermost list, then
|
|
the 3rd element of the next list, and finally the 1st element.
|
|
STATE and INDENT-POINT are as in the arguments to
|
|
`common-lisp-indent-function'. SEXP-COLUMN is the column of
|
|
the open parenthesis of the innermost containing list.
|
|
NORMAL-INDENT is the column the indentation point was
|
|
originally in. This function should behave like `lisp-indent-259'.
|
|
|
|
* an integer N, meaning indent the first N arguments like
|
|
function arguments, and any further arguments like a body.
|
|
This is equivalent to (4 4 ... &body).
|
|
|
|
* a list starting with `as' specifies an indirection: indentation is done as
|
|
if the form being indented had started with the second element of the list.
|
|
|
|
* any other list. The list element in position M specifies how to indent the
|
|
Mth function argument. If there are fewer elements than function arguments,
|
|
the last list element applies to all remaining arguments. The accepted list
|
|
elements are:
|
|
|
|
* nil, meaning the default indentation.
|
|
|
|
* an integer, specifying an explicit indentation.
|
|
|
|
* &lambda. Indent the argument (which may be a list) by 4.
|
|
|
|
* &rest. When used, this must be the penultimate element. The
|
|
element after this one applies to all remaining arguments.
|
|
|
|
* &body. This is equivalent to &rest lisp-body-indent, i.e., indent
|
|
all remaining elements by `lisp-body-indent'.
|
|
|
|
* &whole. This must be followed by nil, an integer, or a
|
|
function symbol. This indentation is applied to the
|
|
associated argument, and as a base indent for all remaining
|
|
arguments. For example, an integer P means indent this
|
|
argument by P, and all remaining arguments by P, plus the
|
|
value specified by their associated list element.
|
|
|
|
* a symbol. A function to call, with the 6 arguments specified above.
|
|
|
|
* a list, with elements as described above. This applies when the
|
|
associated function argument is itself a list. Each element of the list
|
|
specifies how to indent the associated argument.
|
|
|
|
For example, the function `case' has an indent property
|
|
\(4 &rest (&whole 2 &rest 1)), meaning:
|
|
* indent the first argument by 4.
|
|
* arguments after the first should be lists, and there may be any number
|
|
of them. The first list element has an offset of 2, all the rest
|
|
have an offset of 2+1=3."
|
|
(common-lisp-indent-function-1 indent-point state))
|
|
|
|
;;; XEmacs doesn't have looking-back, so we define a simple one. Faster to
|
|
;;; boot, and sufficient for our needs.
|
|
(defun common-lisp-looking-back (string)
|
|
(let ((len (length string)))
|
|
(dotimes (i len t)
|
|
(unless (eql (elt string (- len i 1)) (char-before (- (point) i)))
|
|
(return nil)))))
|
|
|
|
(defvar common-lisp-feature-expr-regexp "#!?\\(+\\|-\\)")
|
|
|
|
;;; Semi-feature-expression aware keyword check.
|
|
(defun common-lisp-looking-at-keyword ()
|
|
(or (looking-at ":")
|
|
(and (looking-at common-lisp-feature-expr-regexp)
|
|
(save-excursion
|
|
(forward-sexp)
|
|
(skip-chars-forward " \t\n")
|
|
(common-lisp-looking-at-keyword)))))
|
|
|
|
;;; Semi-feature-expression aware backwards movement for keyword
|
|
;;; argument pairs.
|
|
(defun common-lisp-backward-keyword-argument ()
|
|
(ignore-errors
|
|
(backward-sexp 2)
|
|
(when (looking-at common-lisp-feature-expr-regexp)
|
|
(cond ((ignore-errors
|
|
(save-excursion
|
|
(backward-sexp 2)
|
|
(looking-at common-lisp-feature-expr-regexp)))
|
|
(common-lisp-backward-keyword-argument))
|
|
((ignore-errors
|
|
(save-excursion
|
|
(backward-sexp 1)
|
|
(looking-at ":")))
|
|
(backward-sexp))))
|
|
t))
|
|
|
|
(defun common-lisp-indent-function-1 (indent-point state)
|
|
;; If we're looking at a splice, move to the first comma.
|
|
(when (or (common-lisp-looking-back ",") (common-lisp-looking-back ",@"))
|
|
(when (re-search-backward "[^,@'],")
|
|
(forward-char 1)))
|
|
(let ((normal-indent (current-column)))
|
|
;; Walk up list levels until we see something
|
|
;; which does special things with subforms.
|
|
(let ((depth 0)
|
|
;; Path describes the position of point in terms of
|
|
;; list-structure with respect to containing lists.
|
|
;; `foo' has a path of (0 3 1) in `((a b c (d foo) f) g)'.
|
|
(path ())
|
|
;; set non-nil when somebody works out the indentation to use
|
|
calculated
|
|
;; If non-nil, this is an indentation to use
|
|
;; if nothing else specifies it more firmly.
|
|
tentative-calculated
|
|
(last-point indent-point)
|
|
;; the position of the open-paren of the innermost containing list
|
|
(containing-form-start (common-lisp-indent-parse-state-start state))
|
|
;; the column of the above
|
|
sexp-column)
|
|
;; Move to start of innermost containing list
|
|
(goto-char containing-form-start)
|
|
(setq sexp-column (current-column))
|
|
|
|
;; Look over successively less-deep containing forms
|
|
(while (and (not calculated)
|
|
(< depth lisp-indent-maximum-backtracking))
|
|
(let ((containing-sexp (point)))
|
|
(forward-char 1)
|
|
(parse-partial-sexp (point) indent-point 1 t)
|
|
;; Move to the car of the relevant containing form
|
|
(let (tem full function method tentative-defun)
|
|
(if (not (looking-at "\\sw\\|\\s_"))
|
|
;; This form doesn't seem to start with a symbol
|
|
(setq function nil method nil full nil)
|
|
(setq tem (point))
|
|
(forward-sexp 1)
|
|
(setq full (downcase (buffer-substring-no-properties
|
|
tem (point)))
|
|
function full)
|
|
(goto-char tem)
|
|
(setq tem (intern-soft function)
|
|
method (common-lisp-get-indentation tem))
|
|
(cond ((and (null method)
|
|
(string-match ":[^:]+" function))
|
|
;; The pleblisp package feature
|
|
(setq function (substring function
|
|
(1+ (match-beginning 0)))
|
|
method (common-lisp-get-indentation
|
|
(intern-soft function) full)))
|
|
((and (null method))
|
|
;; backwards compatibility
|
|
(setq method (common-lisp-get-indentation tem)))))
|
|
(let ((n 0))
|
|
;; How far into the containing form is the current form?
|
|
(if (< (point) indent-point)
|
|
(while (condition-case ()
|
|
(progn
|
|
(forward-sexp 1)
|
|
(if (>= (point) indent-point)
|
|
nil
|
|
(parse-partial-sexp (point)
|
|
indent-point 1 t)
|
|
(setq n (1+ n))
|
|
t))
|
|
(error nil))))
|
|
(setq path (cons n path)))
|
|
|
|
;; Guess.
|
|
(when (and (not method) function (null (cdr path)))
|
|
;; (package prefix was stripped off above)
|
|
(cond ((and (string-match "\\`def" function)
|
|
(not (string-match "\\`default" function))
|
|
(not (string-match "\\`definition" function))
|
|
(not (string-match "\\`definer" function)))
|
|
(setq tentative-defun t))
|
|
((string-match
|
|
(eval-when-compile
|
|
(concat "\\`\\("
|
|
(regexp-opt '("with" "without" "do"))
|
|
"\\)-"))
|
|
function)
|
|
(setq method '(&lambda &body)))))
|
|
|
|
;; #+ and #- cleverness.
|
|
(save-excursion
|
|
(goto-char indent-point)
|
|
(backward-sexp)
|
|
(let ((indent (current-column)))
|
|
(when (or (looking-at common-lisp-feature-expr-regexp)
|
|
(ignore-errors
|
|
(backward-sexp)
|
|
(when (looking-at
|
|
common-lisp-feature-expr-regexp)
|
|
(setq indent (current-column))
|
|
(let ((line (line-number-at-pos)))
|
|
(while
|
|
(ignore-errors
|
|
(backward-sexp 2)
|
|
(and
|
|
(= line (line-number-at-pos))
|
|
(looking-at
|
|
common-lisp-feature-expr-regexp)))
|
|
(setq indent (current-column))))
|
|
t)))
|
|
(setq calculated (list indent containing-form-start)))))
|
|
|
|
(cond ((and (or (eq (char-after (1- containing-sexp)) ?\')
|
|
(and (not lisp-backquote-indentation)
|
|
(eq (char-after (1- containing-sexp)) ?\`)))
|
|
(not (eq (char-after (- containing-sexp 2)) ?\#)))
|
|
;; No indentation for "'(...)" elements
|
|
(setq calculated (1+ sexp-column)))
|
|
((eq (char-after (1- containing-sexp)) ?\#)
|
|
;; "#(...)"
|
|
(setq calculated (1+ sexp-column)))
|
|
((null method)
|
|
;; If this looks like a call to a `def...' form,
|
|
;; think about indenting it as one, but do it
|
|
;; tentatively for cases like
|
|
;; (flet ((defunp ()
|
|
;; nil)))
|
|
;; Set both normal-indent and tentative-calculated.
|
|
;; The latter ensures this value gets used
|
|
;; if there are no relevant containing constructs.
|
|
;; The former ensures this value gets used
|
|
;; if there is a relevant containing construct
|
|
;; but we are nested within the structure levels
|
|
;; that it specifies indentation for.
|
|
(if tentative-defun
|
|
(setq tentative-calculated
|
|
(common-lisp-indent-call-method
|
|
function lisp-indent-defun-method
|
|
path state indent-point
|
|
sexp-column normal-indent)
|
|
normal-indent tentative-calculated)
|
|
(when lisp-align-keywords-in-calls
|
|
;; No method so far. If we're looking at a keyword,
|
|
;; align with the first keyword in this expression.
|
|
;; This gives a reasonable indentation to most things
|
|
;; with keyword arguments.
|
|
(save-excursion
|
|
(goto-char indent-point)
|
|
(back-to-indentation)
|
|
(when (common-lisp-looking-at-keyword)
|
|
(while (common-lisp-backward-keyword-argument)
|
|
(when (common-lisp-looking-at-keyword)
|
|
(setq calculated
|
|
(list (current-column)
|
|
containing-form-start)))))))))
|
|
((integerp method)
|
|
;; convenient top-level hack.
|
|
;; (also compatible with lisp-indent-function)
|
|
;; The number specifies how many `distinguished'
|
|
;; forms there are before the body starts
|
|
;; Equivalent to (4 4 ... &body)
|
|
(setq calculated (cond ((cdr path)
|
|
normal-indent)
|
|
((<= (car path) method)
|
|
;; `distinguished' form
|
|
(list (+ sexp-column 4)
|
|
containing-form-start))
|
|
((= (car path) (1+ method))
|
|
;; first body form.
|
|
(+ sexp-column lisp-body-indent))
|
|
(t
|
|
;; other body form
|
|
normal-indent))))
|
|
(t
|
|
(setq calculated
|
|
(common-lisp-indent-call-method
|
|
function method path state indent-point
|
|
sexp-column normal-indent)))))
|
|
(goto-char containing-sexp)
|
|
(setq last-point containing-sexp)
|
|
(unless calculated
|
|
(condition-case ()
|
|
(progn (backward-up-list 1)
|
|
(setq depth (1+ depth)))
|
|
(error
|
|
(setq depth lisp-indent-maximum-backtracking))))))
|
|
|
|
(or calculated tentative-calculated
|
|
;; Fallback.
|
|
;;
|
|
;; Instead of punting directly to calculate-lisp-indent we
|
|
;; handle a few of cases it doesn't deal with:
|
|
;;
|
|
;; A: (foo (
|
|
;; bar zot
|
|
;; quux))
|
|
;;
|
|
;; would align QUUX with ZOT.
|
|
;;
|
|
;; B:
|
|
;; (foo (or x
|
|
;; y) t
|
|
;; z)
|
|
;;
|
|
;; would align the Z with Y.
|
|
;;
|
|
;; C:
|
|
;; (foo ;; Comment
|
|
;; (bar)
|
|
;; ;; Comment 2
|
|
;; (quux))
|
|
;;
|
|
;; would indent BAR and QUUX by one.
|
|
(ignore-errors
|
|
(save-excursion
|
|
(goto-char indent-point)
|
|
(back-to-indentation)
|
|
(let ((p (point)))
|
|
(goto-char containing-form-start)
|
|
(down-list)
|
|
(let ((one (current-column)))
|
|
(skip-chars-forward " \t")
|
|
(if (or (eolp) (looking-at ";"))
|
|
;; A.
|
|
(list one containing-form-start)
|
|
(forward-sexp 2)
|
|
(backward-sexp)
|
|
(if (/= p (point))
|
|
;; B.
|
|
(list (current-column) containing-form-start)
|
|
(backward-sexp)
|
|
(forward-sexp)
|
|
(let ((tmp (+ (current-column) 1)))
|
|
(skip-chars-forward " \t")
|
|
(if (looking-at ";")
|
|
;; C.
|
|
(list tmp containing-form-start)))))))))))))
|
|
|
|
|
|
(defun common-lisp-indent-call-method (function method path state indent-point
|
|
sexp-column normal-indent)
|
|
(let ((lisp-indent-error-function function))
|
|
(if (symbolp method)
|
|
(funcall method
|
|
path state indent-point
|
|
sexp-column normal-indent)
|
|
(lisp-indent-259 method path state indent-point
|
|
sexp-column normal-indent))))
|
|
|
|
;; Dynamically bound in common-lisp-indent-call-method.
|
|
(defvar lisp-indent-error-function)
|
|
|
|
(defun lisp-indent-report-bad-format (m)
|
|
(error "%s has a badly-formed %s property: %s"
|
|
;; Love those free variable references!!
|
|
lisp-indent-error-function 'common-lisp-indent-function m))
|
|
|
|
|
|
;; Lambda-list indentation is now done in LISP-INDENT-LAMBDA-LIST.
|
|
;; See also `lisp-lambda-list-keyword-alignment',
|
|
;; `lisp-lambda-list-keyword-parameter-alignment' and
|
|
;; `lisp-lambda-list-keyword-parameter-indentation' -- dvl
|
|
|
|
(defvar lisp-indent-lambda-list-keywords-regexp
|
|
"&\\(\
|
|
optional\\|rest\\|key\\|allow-other-keys\\|aux\\|whole\\|body\\|\
|
|
environment\\|more\
|
|
\\)\\>"
|
|
"Regular expression matching lambda-list keywords.")
|
|
|
|
(defun lisp-indent-lambda-list
|
|
(indent-point sexp-column containing-form-start)
|
|
(if (not lisp-lambda-list-indentation)
|
|
(1+ sexp-column)
|
|
(lisp-properly-indent-lambda-list
|
|
indent-point sexp-column containing-form-start)))
|
|
|
|
(defun lisp-properly-indent-lambda-list
|
|
(indent-point sexp-column containing-form-start)
|
|
(let (limit)
|
|
(cond
|
|
((save-excursion
|
|
(goto-char indent-point)
|
|
(back-to-indentation)
|
|
(setq limit (point))
|
|
(looking-at lisp-indent-lambda-list-keywords-regexp))
|
|
;; We're facing a lambda-list keyword.
|
|
(if lisp-lambda-list-keyword-alignment
|
|
;; Align to the first keyword if any, or to the beginning of
|
|
;; the lambda-list.
|
|
(save-excursion
|
|
(goto-char containing-form-start)
|
|
(down-list)
|
|
(let ((key-indent nil)
|
|
(next t))
|
|
(while (and next (< (point) indent-point))
|
|
(if (looking-at lisp-indent-lambda-list-keywords-regexp)
|
|
(setq key-indent (current-column)
|
|
next nil)
|
|
(setq next (ignore-errors (forward-sexp) t))
|
|
(if next
|
|
(ignore-errors
|
|
(forward-sexp)
|
|
(backward-sexp)))))
|
|
(or key-indent
|
|
(1+ sexp-column))))
|
|
;; Align to the beginning of the lambda-list.
|
|
(1+ sexp-column)))
|
|
(t
|
|
;; Otherwise, align to the first argument of the last lambda-list
|
|
;; keyword, the keyword itself, or the beginning of the
|
|
;; lambda-list.
|
|
(save-excursion
|
|
(goto-char indent-point)
|
|
(let ((indent nil)
|
|
(next t))
|
|
(while (and next (> (point) containing-form-start))
|
|
(setq next (ignore-errors (backward-sexp) t))
|
|
(let* ((col (current-column))
|
|
(pos
|
|
(save-excursion
|
|
(ignore-errors (forward-sexp))
|
|
(skip-chars-forward " \t")
|
|
(if (eolp)
|
|
(+ col
|
|
lisp-lambda-list-keyword-parameter-indentation)
|
|
col))))
|
|
(if (looking-at lisp-indent-lambda-list-keywords-regexp)
|
|
(setq indent
|
|
(if lisp-lambda-list-keyword-parameter-alignment
|
|
(or indent pos)
|
|
(+ col
|
|
lisp-lambda-list-keyword-parameter-indentation))
|
|
next nil)
|
|
(setq indent col))))
|
|
(or indent (1+ sexp-column))))))))
|
|
|
|
(defun common-lisp-lambda-list-initial-value-form-p (point)
|
|
(let ((state 'x)
|
|
(point (save-excursion
|
|
(goto-char point)
|
|
(back-to-indentation)
|
|
(point))))
|
|
(save-excursion
|
|
(backward-sexp)
|
|
(ignore-errors (down-list 1))
|
|
(while (and point (< (point) point))
|
|
(cond ((or (looking-at "&key") (looking-at "&optional")
|
|
(looking-at "&aux"))
|
|
(setq state 'key))
|
|
((looking-at lisp-indent-lambda-list-keywords-regexp)
|
|
(setq state 'x)))
|
|
(if (not (ignore-errors (forward-sexp) t))
|
|
(setq point nil)
|
|
(ignore-errors
|
|
(forward-sexp)
|
|
(backward-sexp))
|
|
(cond ((> (point) point)
|
|
(backward-sexp)
|
|
(when (eq state 'var)
|
|
(setq state 'x))
|
|
(or (ignore-errors
|
|
(down-list 1)
|
|
(cond ((> (point) point)
|
|
(backward-up-list))
|
|
((eq 'key state)
|
|
(setq state 'var)))
|
|
t)
|
|
(setq point nil)))
|
|
((eq state 'var)
|
|
(setq state 'form))))))
|
|
(eq 'form state)))
|
|
|
|
;; Blame the crufty control structure on dynamic scoping
|
|
;; -- not on me!
|
|
(defun lisp-indent-259
|
|
(method path state indent-point sexp-column normal-indent)
|
|
(catch 'exit
|
|
(let* ((p (cdr path))
|
|
(containing-form-start (elt state 1))
|
|
(n (1- (car path)))
|
|
tem tail)
|
|
(if (not (consp method))
|
|
(lisp-indent-report-bad-format method))
|
|
(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
|
|
(or (consp (car tem))
|
|
(and (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 ((eq tem '&body)
|
|
;; &body means (&rest <lisp-body-indent>)
|
|
(throw 'exit
|
|
(if (null p)
|
|
(+ 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 ((not (common-lisp-looking-back ")"))
|
|
;; If it's not a list at all, indent it
|
|
;; like body instead.
|
|
(if (null p)
|
|
(+ sexp-column lisp-body-indent)
|
|
normal-indent))
|
|
((common-lisp-lambda-list-initial-value-form-p
|
|
indent-point)
|
|
(if (consp normal-indent)
|
|
normal-indent
|
|
(list normal-indent containing-form-start)))
|
|
((null p)
|
|
(list (+ sexp-column 4) containing-form-start))
|
|
(t
|
|
;; Indentation within a lambda-list. -- dvl
|
|
(list (lisp-indent-lambda-list
|
|
indent-point
|
|
sexp-column
|
|
containing-form-start)
|
|
containing-form-start)))))
|
|
((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 p
|
|
;; descend
|
|
(setq method (cddr tem)
|
|
n (car p)
|
|
p (cdr p)
|
|
tail nil)
|
|
(let ((wholep (eq '&whole (car tem))))
|
|
(setq tem (cadr tem))
|
|
(throw 'exit
|
|
(cond (tail
|
|
(if (and wholep (integerp tem)
|
|
(save-excursion
|
|
(goto-char indent-point)
|
|
(back-to-indentation)
|
|
(looking-at "\\sw")))
|
|
;; There's a further level of
|
|
;; destructuring, but we're looking at a
|
|
;; word -- indent to sexp.
|
|
(+ sexp-column tem)
|
|
normal-indent))
|
|
((not tem)
|
|
(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))))))))))))
|
|
|
|
(defun lisp-indent-tagbody (path state indent-point sexp-column normal-indent)
|
|
(if (not (null (cdr path)))
|
|
normal-indent
|
|
(save-excursion
|
|
(goto-char indent-point)
|
|
(back-to-indentation)
|
|
(list (cond ((looking-at "\\sw\\|\\s_")
|
|
;; a tagbody tag
|
|
(+ sexp-column lisp-tag-indentation))
|
|
((integerp lisp-tag-body-indentation)
|
|
(+ sexp-column lisp-tag-body-indentation))
|
|
((eq lisp-tag-body-indentation 't)
|
|
(condition-case ()
|
|
(progn (backward-sexp 1) (current-column))
|
|
(error (1+ sexp-column))))
|
|
(t (+ sexp-column lisp-body-indent)))
|
|
; (cond ((integerp lisp-tag-body-indentation)
|
|
; (+ sexp-column lisp-tag-body-indentation))
|
|
; ((eq lisp-tag-body-indentation 't)
|
|
; normal-indent)
|
|
; (t
|
|
; (+ sexp-column lisp-body-indent)))
|
|
(elt state 1)
|
|
))))
|
|
|
|
(defun lisp-indent-do (path state indent-point sexp-column normal-indent)
|
|
(if (>= (car path) 3)
|
|
(let ((lisp-tag-body-indentation lisp-body-indent))
|
|
(funcall (function lisp-indent-tagbody)
|
|
path state indent-point sexp-column normal-indent))
|
|
(funcall (function lisp-indent-259)
|
|
'((&whole nil &rest
|
|
;; the following causes weird indentation
|
|
;;(&whole 1 1 2 nil)
|
|
)
|
|
(&whole nil &rest 1))
|
|
path state indent-point sexp-column normal-indent)))
|
|
|
|
(defun lisp-indent-defsetf
|
|
(path state indent-point sexp-column normal-indent)
|
|
(list
|
|
(cond
|
|
;; Inside the lambda-list in a long-form defsetf.
|
|
((and (eql 2 (car path)) (cdr path))
|
|
(lisp-indent-lambda-list indent-point sexp-column (elt state 1)))
|
|
;; Long form: has a lambda-list.
|
|
((or (cdr path)
|
|
(save-excursion
|
|
(goto-char (elt state 1))
|
|
(ignore-errors
|
|
(down-list)
|
|
(forward-sexp 3)
|
|
(backward-sexp)
|
|
(looking-at "nil\\|("))))
|
|
(+ sexp-column
|
|
(case (car path)
|
|
((1 3) 4)
|
|
(2 4)
|
|
(t 2))))
|
|
;; Short form.
|
|
(t
|
|
(+ sexp-column
|
|
(case (car path)
|
|
(1 4)
|
|
(2 4)
|
|
(t 2)))))
|
|
(elt state 1)))
|
|
|
|
(defun lisp-beginning-of-defmethod-qualifiers ()
|
|
(let ((regexp-1 "(defmethod\\|(DEFMETHOD")
|
|
(regexp-2 "(:method\\|(:METHOD"))
|
|
(while (and (not (or (looking-at regexp-1)
|
|
(looking-at regexp-2)))
|
|
(ignore-errors (backward-up-list) t)))
|
|
(cond ((looking-at regexp-1)
|
|
(forward-char)
|
|
;; Skip name.
|
|
(forward-sexp 2)
|
|
1)
|
|
((looking-at regexp-2)
|
|
(forward-char)
|
|
(forward-sexp 1)
|
|
0))))
|
|
|
|
;; LISP-INDENT-DEFMETHOD now supports the presence of more than one method
|
|
;; qualifier and indents the method's lambda list properly. -- dvl
|
|
(defun lisp-indent-defmethod
|
|
(path state indent-point sexp-column normal-indent)
|
|
(lisp-indent-259
|
|
(let ((nskip nil))
|
|
(if (save-excursion
|
|
(when (setq nskip (lisp-beginning-of-defmethod-qualifiers))
|
|
(skip-chars-forward " \t\n")
|
|
(while (looking-at "\\sw\\|\\s_")
|
|
(incf nskip)
|
|
(forward-sexp)
|
|
(skip-chars-forward " \t\n"))
|
|
t))
|
|
(append (make-list nskip 4) '(&lambda &body))
|
|
(common-lisp-get-indentation 'defun)))
|
|
path state indent-point sexp-column normal-indent))
|
|
|
|
(defun lisp-indent-function-lambda-hack (path state indent-point
|
|
sexp-column normal-indent)
|
|
;; indent (function (lambda () <newline> <body-forms>)) kludgily.
|
|
(if (or (cdr path) ; wtf?
|
|
(> (car path) 3))
|
|
;; line up under previous body form
|
|
normal-indent
|
|
;; line up under function rather than under lambda in order to
|
|
;; conserve horizontal space. (Which is what #' is for.)
|
|
(condition-case ()
|
|
(save-excursion
|
|
(backward-up-list 2)
|
|
(forward-char 1)
|
|
(if (looking-at "\\(lisp:+\\)?function\\(\\Sw\\|\\S_\\)")
|
|
(+ lisp-body-indent -1 (current-column))
|
|
(+ sexp-column lisp-body-indent)))
|
|
(error (+ sexp-column lisp-body-indent)))))
|
|
|
|
(defun lisp-indent-loop (path state indent-point sexp-column normal-indent)
|
|
(if (cdr path)
|
|
normal-indent
|
|
(let* ((loop-start (elt state 1))
|
|
(type (common-lisp-loop-type loop-start)))
|
|
(cond ((and lisp-loop-indent-subclauses
|
|
(member type '(extended extended/split)))
|
|
(list (common-lisp-indent-loop-macro-1 state indent-point)
|
|
(common-lisp-indent-parse-state-start state)))
|
|
(t
|
|
(common-lisp-loop-part-indentation indent-point state type))))))
|
|
|
|
;;;; LOOP indentation, the complex version -- handles subclause indentation
|
|
|
|
;; Regexps matching various varieties of loop macro keyword ...
|
|
(defvar common-lisp-body-introducing-loop-macro-keyword
|
|
"\\(#?:\\)?\\(do\\(ing\\)?\\|finally\\|initially\\)"
|
|
"Regexp matching loop macro keywords which introduce body forms.")
|
|
|
|
;; Not currenctly used
|
|
(defvar common-lisp-accumlation-loop-macro-keyword
|
|
"\\(#?:\\)?\\(collect\\(ing\\)?\\|append\\(ing\\)?\\|nconc\\(ing\\)?\\|\
|
|
count\\(ing\\)?\\|sum\\(ming\\)?\\|maximiz\\(e\\|ing\\)\\|\
|
|
minimiz\\(e\\|ing\\)\\)"
|
|
"Regexp matching loop macro keywords which introduce accumulation clauses.")
|
|
|
|
;; This is so "and when" and "else when" get handled right
|
|
;; (not to mention "else do" !!!)
|
|
(defvar common-lisp-prefix-loop-macro-keyword
|
|
"\\(#?:\\)?\\(and\\|else\\)"
|
|
"Regexp matching loop macro keywords which are prefixes.")
|
|
|
|
(defvar common-lisp-indent-clause-joining-loop-macro-keyword
|
|
"\\(#?:\\)?and"
|
|
"Regexp matching 'and', and anything else there ever comes to be like it.")
|
|
|
|
(defvar common-lisp-indent-indented-loop-macro-keyword
|
|
"\\(#?:\\)?\\(\\(up\\|down\\)?(from\\|to)\\|below\\|above\\|in\\(to\\)?\\|\
|
|
on\\|=\\|then\\|across\\|being\\|each\\|the\\|of\\|using\\|\
|
|
\\(present-\\|external-\\)?symbols?\\|fixnum\\|float\\|t\\|nil\\|of-type\\)"
|
|
"Regexp matching keywords introducing loop subclauses.
|
|
Always indented two.")
|
|
|
|
(defvar common-lisp-indenting-loop-macro-keyword
|
|
"\\(#?:\\)?\\(when\\|unless\\|if\\)"
|
|
"Regexp matching keywords introducing conditional clauses.
|
|
Cause subsequent clauses to be indented.")
|
|
|
|
(defvar common-lisp-loop-macro-else-keyword "\\(#?:\\)?else")
|
|
|
|
;;; Attempt to indent the loop macro ...
|
|
|
|
(defun common-lisp-indent-parse-state-depth (parse-state)
|
|
(car parse-state))
|
|
|
|
(defun common-lisp-indent-parse-state-start (parse-state)
|
|
(car (cdr parse-state)))
|
|
|
|
(defun common-lisp-indent-parse-state-prev (parse-state)
|
|
(car (cdr (cdr parse-state))))
|
|
|
|
(defun common-lisp-loop-part-indentation (indent-point state type)
|
|
"Compute the indentation of loop form constituents."
|
|
(let* ((loop-start (elt state 1))
|
|
(loop-indentation (save-excursion
|
|
(goto-char loop-start)
|
|
(if (eq type 'extended/split)
|
|
(- (current-column) 4)
|
|
(current-column))))
|
|
(indent nil)
|
|
(re "\\(\\(#?:\\)?\\sw+\\|)\\|\n\\)"))
|
|
(goto-char indent-point)
|
|
(back-to-indentation)
|
|
(cond ((eq type 'simple/split)
|
|
(+ loop-indentation lisp-simple-loop-indentation))
|
|
((eq type 'simple)
|
|
(+ loop-indentation 6))
|
|
;; We are already in a body, with forms in it.
|
|
((and (not (looking-at re))
|
|
(save-excursion
|
|
(while (and (ignore-errors (backward-sexp) t)
|
|
(not (looking-at re)))
|
|
(setq indent (current-column)))
|
|
(when (and indent
|
|
(looking-at
|
|
common-lisp-body-introducing-loop-macro-keyword))
|
|
t)))
|
|
(list indent loop-start))
|
|
;; Keyword-style or comment outside body
|
|
((or lisp-loop-indent-forms-like-keywords
|
|
(looking-at re)
|
|
(looking-at ";"))
|
|
(if (and (looking-at ";")
|
|
(let ((p (common-lisp-trailing-comment)))
|
|
(when p
|
|
(setq loop-indentation p))))
|
|
(list loop-indentation loop-start)
|
|
(list (+ loop-indentation 6) loop-start)))
|
|
;; Form-style
|
|
(t
|
|
(list (+ loop-indentation 9) loop-start)))))
|
|
|
|
(defun common-lisp-indent-loop-macro-1 (parse-state indent-point)
|
|
(catch 'return-indentation
|
|
(save-excursion
|
|
;; Find first clause of loop macro, and use it to establish
|
|
;; base column for indentation
|
|
(goto-char (common-lisp-indent-parse-state-start parse-state))
|
|
(let ((loop-start-column (current-column)))
|
|
(common-lisp-loop-advance-past-keyword-on-line)
|
|
|
|
(when (eolp)
|
|
(forward-line 1)
|
|
(end-of-line)
|
|
;; If indenting first line after "(loop <newline>"
|
|
;; cop out ...
|
|
(if (<= indent-point (point))
|
|
(throw 'return-indentation (+ lisp-loop-clauses-indentation
|
|
loop-start-column)))
|
|
(back-to-indentation))
|
|
|
|
(let* ((case-fold-search t)
|
|
(loop-macro-first-clause (point))
|
|
(previous-expression-start
|
|
(common-lisp-indent-parse-state-prev parse-state))
|
|
(default-value (current-column))
|
|
(loop-body-p nil)
|
|
(loop-body-indentation nil)
|
|
(indented-clause-indentation (+ 2 default-value)))
|
|
;; Determine context of this loop clause, starting with the
|
|
;; expression immediately preceding the line we're trying to indent
|
|
(goto-char previous-expression-start)
|
|
|
|
;; Handle a body-introducing-clause which ends a line specially.
|
|
(if (looking-at common-lisp-body-introducing-loop-macro-keyword)
|
|
(let ((keyword-position (current-column)))
|
|
(setq loop-body-p t)
|
|
(setq loop-body-indentation
|
|
(if (common-lisp-loop-advance-past-keyword-on-line)
|
|
(current-column)
|
|
(back-to-indentation)
|
|
(if (/= (current-column) keyword-position)
|
|
(+ 2 (current-column))
|
|
(+ lisp-loop-body-forms-indentation
|
|
(if lisp-loop-indent-body-forms-relative-to-loop-start
|
|
loop-start-column
|
|
keyword-position))))))
|
|
|
|
(back-to-indentation)
|
|
(if (< (point) loop-macro-first-clause)
|
|
(goto-char loop-macro-first-clause))
|
|
;; If there's an "and" or "else," advance over it.
|
|
;; If it is alone on the line, the next "cond" will treat it
|
|
;; as if there were a "when" and indent under it ...
|
|
(let ((exit nil))
|
|
(while (and (null exit)
|
|
(looking-at common-lisp-prefix-loop-macro-keyword))
|
|
(if (null (common-lisp-loop-advance-past-keyword-on-line))
|
|
(progn (setq exit t)
|
|
(back-to-indentation)))))
|
|
|
|
;; Found start of loop clause preceding the one we're
|
|
;; trying to indent. Glean context ...
|
|
(cond
|
|
((looking-at "(")
|
|
;; We're in the middle of a clause body ...
|
|
(setq loop-body-p t)
|
|
(setq loop-body-indentation (current-column)))
|
|
((looking-at common-lisp-body-introducing-loop-macro-keyword)
|
|
(setq loop-body-p t)
|
|
;; Know there's something else on the line (or would
|
|
;; have been caught above)
|
|
(common-lisp-loop-advance-past-keyword-on-line)
|
|
(setq loop-body-indentation (current-column)))
|
|
(t
|
|
(setq loop-body-p nil)
|
|
(if (or (looking-at common-lisp-indenting-loop-macro-keyword)
|
|
(looking-at common-lisp-prefix-loop-macro-keyword))
|
|
(setq default-value (+ 2 (current-column))))
|
|
(setq indented-clause-indentation (+ 2 (current-column)))
|
|
;; We still need loop-body-indentation for "syntax errors" ...
|
|
(goto-char previous-expression-start)
|
|
(setq loop-body-indentation (current-column)))))
|
|
|
|
;; Go to first non-blank character of the line we're trying
|
|
;; to indent. (if none, wind up poised on the new-line ...)
|
|
(goto-char indent-point)
|
|
(back-to-indentation)
|
|
(cond
|
|
((looking-at "(")
|
|
;; Clause body ...
|
|
loop-body-indentation)
|
|
((or (eolp) (looking-at ";"))
|
|
;; Blank line. If body-p, indent as body, else indent as
|
|
;; vanilla clause.
|
|
(if loop-body-p
|
|
loop-body-indentation
|
|
(or (and (looking-at ";") (common-lisp-trailing-comment))
|
|
default-value)))
|
|
((looking-at common-lisp-indent-indented-loop-macro-keyword)
|
|
indented-clause-indentation)
|
|
((looking-at common-lisp-indent-clause-joining-loop-macro-keyword)
|
|
(let ((stolen-indent-column nil))
|
|
(forward-line -1)
|
|
(while (and (null stolen-indent-column)
|
|
(> (point) loop-macro-first-clause))
|
|
(back-to-indentation)
|
|
(if (and (< (current-column) loop-body-indentation)
|
|
(looking-at "\\(#?:\\)?\\sw"))
|
|
(progn
|
|
(if (looking-at common-lisp-loop-macro-else-keyword)
|
|
(common-lisp-loop-advance-past-keyword-on-line))
|
|
(setq stolen-indent-column
|
|
(current-column)))
|
|
(forward-line -1)))
|
|
(if stolen-indent-column
|
|
stolen-indent-column
|
|
default-value)))
|
|
(t default-value)))))))
|
|
|
|
(defun common-lisp-loop-advance-past-keyword-on-line ()
|
|
(forward-word 1)
|
|
(while (and (looking-at "\\s-") (not (eolp)))
|
|
(forward-char 1))
|
|
(if (eolp)
|
|
nil
|
|
(current-column)))
|
|
|
|
;;;; IF* is not standard, but a plague upon the land
|
|
;;;; ...let's at least try to indent it.
|
|
|
|
(defvar common-lisp-indent-if*-keyword
|
|
"threnret\\|elseif\\|then\\|else"
|
|
"Regexp matching if* keywords")
|
|
|
|
(defun common-lisp-indent-if*
|
|
(path parse-state indent-point sexp-column normal-indent)
|
|
(list (common-lisp-indent-if*-1 parse-state indent-point)
|
|
(common-lisp-indent-parse-state-start parse-state)))
|
|
|
|
(defun common-lisp-indent-if*-1 (parse-state indent-point)
|
|
(catch 'return-indentation
|
|
(save-excursion
|
|
;; Find first clause of if* macro, and use it to establish
|
|
;; base column for indentation
|
|
(goto-char (common-lisp-indent-parse-state-start parse-state))
|
|
(let ((if*-start-column (current-column)))
|
|
(common-lisp-indent-if*-advance-past-keyword-on-line)
|
|
(let* ((case-fold-search t)
|
|
(if*-first-clause (point))
|
|
(previous-expression-start
|
|
(common-lisp-indent-parse-state-prev parse-state))
|
|
(default-value (current-column))
|
|
(if*-body-p nil)
|
|
(if*-body-indentation nil))
|
|
;; Determine context of this if* clause, starting with the
|
|
;; expression immediately preceding the line we're trying to indent
|
|
(goto-char previous-expression-start)
|
|
;; Handle a body-introducing-clause which ends a line specially.
|
|
(back-to-indentation)
|
|
(if (< (point) if*-first-clause)
|
|
(goto-char if*-first-clause))
|
|
;; Found start of if* clause preceding the one we're trying
|
|
;; to indent. Glean context ...
|
|
(cond
|
|
((looking-at common-lisp-indent-if*-keyword)
|
|
(setq if*-body-p t)
|
|
;; Know there's something else on the line (or would
|
|
;; have been caught above)
|
|
(common-lisp-indent-if*-advance-past-keyword-on-line)
|
|
(setq if*-body-indentation (current-column)))
|
|
((looking-at "#'\\|'\\|(")
|
|
;; We're in the middle of a clause body ...
|
|
(setq if*-body-p t)
|
|
(setq if*-body-indentation (current-column)))
|
|
(t
|
|
(setq if*-body-p nil)
|
|
;; We still need if*-body-indentation for "syntax errors" ...
|
|
(goto-char previous-expression-start)
|
|
(setq if*-body-indentation (current-column))))
|
|
|
|
;; Go to first non-blank character of the line we're trying
|
|
;; to indent. (if none, wind up poised on the new-line ...)
|
|
(goto-char indent-point)
|
|
(back-to-indentation)
|
|
(cond
|
|
((or (eolp) (looking-at ";"))
|
|
;; Blank line. If body-p, indent as body, else indent as
|
|
;; vanilla clause.
|
|
(if if*-body-p
|
|
if*-body-indentation
|
|
default-value))
|
|
((not (looking-at common-lisp-indent-if*-keyword))
|
|
;; Clause body ...
|
|
if*-body-indentation)
|
|
(t
|
|
(- (+ 7 if*-start-column)
|
|
(- (match-end 0) (match-beginning 0))))))))))
|
|
|
|
(defun common-lisp-indent-if*-advance-past-keyword-on-line ()
|
|
(forward-word 1)
|
|
(block move-forward
|
|
(while (and (looking-at "\\s-") (not (eolp)))
|
|
(forward-char 1)))
|
|
(if (eolp)
|
|
nil
|
|
(current-column)))
|
|
|
|
|
|
;;;; Indentation specs for standard symbols, and a few semistandard ones.
|
|
(defun common-lisp-init-standard-indentation ()
|
|
(let ((l '((block 1)
|
|
(case (4 &rest (&whole 2 &rest 1)))
|
|
(ccase (as case))
|
|
(ecase (as case))
|
|
(typecase (as case))
|
|
(etypecase (as case))
|
|
(ctypecase (as case))
|
|
(catch 1)
|
|
(cond (&rest (&whole 2 &rest nil)))
|
|
;; for DEFSTRUCT
|
|
(:constructor (4 &lambda))
|
|
(defvar (4 2 2))
|
|
(defclass (6 (&whole 4 &rest 1)
|
|
(&whole 2 &rest 1)
|
|
(&whole 2 &rest 1)))
|
|
(defconstant (as defvar))
|
|
(defcustom (4 2 2 2))
|
|
(defparameter (as defvar))
|
|
(defconst (as defcustom))
|
|
(define-condition (as defclass))
|
|
(define-modify-macro (4 &lambda &body))
|
|
(defsetf lisp-indent-defsetf)
|
|
(defun (4 &lambda &body))
|
|
(defgeneric (4 &lambda &body))
|
|
(define-setf-method (as defun))
|
|
(define-setf-expander (as defun))
|
|
(defmacro (as defun))
|
|
(defsubst (as defun))
|
|
(deftype (as defun))
|
|
(defmethod lisp-indent-defmethod)
|
|
(defpackage (4 2))
|
|
(defstruct ((&whole 4 &rest (&whole 2 &rest 1))
|
|
&rest (&whole 2 &rest 1)))
|
|
(destructuring-bind (&lambda 4 &body))
|
|
(do lisp-indent-do)
|
|
(do* (as do))
|
|
(dolist ((&whole 4 2 1) &body))
|
|
(dotimes (as dolist))
|
|
(eval-when 1)
|
|
(flet ((&whole 4 &rest (&whole 1 4 &lambda &body)) &body))
|
|
(labels (as flet))
|
|
(macrolet (as flet))
|
|
(generic-flet (as flet))
|
|
(generic-labels (as flet))
|
|
(handler-case (4 &rest (&whole 2 &lambda &body)))
|
|
(restart-case (as handler-case))
|
|
;; single-else style (then and else equally indented)
|
|
(if (&rest nil))
|
|
(if* common-lisp-indent-if*)
|
|
(lambda (&lambda &rest lisp-indent-function-lambda-hack))
|
|
(let ((&whole 4 &rest (&whole 1 1 2)) &body))
|
|
(let* (as let))
|
|
(compiler-let (as let))
|
|
(handler-bind (as let))
|
|
(restart-bind (as let))
|
|
(locally 1)
|
|
(loop lisp-indent-loop)
|
|
(:method lisp-indent-defmethod) ; in `defgeneric'
|
|
(multiple-value-bind ((&whole 6 &rest 1) 4 &body))
|
|
(multiple-value-call (4 &body))
|
|
(multiple-value-prog1 1)
|
|
(multiple-value-setq (4 2))
|
|
(multiple-value-setf (as multiple-value-setq))
|
|
(named-lambda (4 &lambda &rest lisp-indent-function-lambda-hack))
|
|
(pprint-logical-block (4 2))
|
|
(print-unreadable-object ((&whole 4 1 &rest 1) &body))
|
|
;; Combines the worst features of BLOCK, LET and TAGBODY
|
|
(prog (&lambda &rest lisp-indent-tagbody))
|
|
(prog* (as prog))
|
|
(prog1 1)
|
|
(prog2 2)
|
|
(progn 0)
|
|
(progv (4 4 &body))
|
|
(return 0)
|
|
(return-from (nil &body))
|
|
(symbol-macrolet (as let))
|
|
(tagbody lisp-indent-tagbody)
|
|
(throw 1)
|
|
(unless 1)
|
|
(unwind-protect (5 &body))
|
|
(when 1)
|
|
(with-accessors (as multiple-value-bind))
|
|
(with-compilation-unit ((&whole 4 &rest 1) &body))
|
|
(with-condition-restarts (as multiple-value-bind))
|
|
(with-output-to-string (4 2))
|
|
(with-slots (as multiple-value-bind))
|
|
(with-standard-io-syntax (2)))))
|
|
(dolist (el l)
|
|
(let* ((name (car el))
|
|
(spec (cdr el))
|
|
(indentation
|
|
(if (symbolp spec)
|
|
(error "Old style indirect indentation spec: %s" el)
|
|
(when (cdr spec)
|
|
(error "Malformed indentation specification: %s" el))
|
|
(car spec))))
|
|
(unless (symbolp name)
|
|
(error "Cannot set Common Lisp indentation of a non-symbol: %s"
|
|
name))
|
|
(put name 'common-lisp-indent-function indentation)))))
|
|
(common-lisp-init-standard-indentation)
|
|
|
|
(provide 'cl-indent)
|
|
(provide 'slime-cl-indent)
|
|
|
|
;;; slime-cl-indent.el ends here
|