1821 lines
73 KiB
EmacsLisp
1821 lines
73 KiB
EmacsLisp
;;; 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
|