lisp indent style

TOC TOC

默认缩进样式

The default indent style for lisp is1 and 2 and 3:

You can set lisp-indent-offset to 2, but you almost certainly don't want to do this, unless you really know what you're doing.

Lisp-style languages adhere to a slightly different indentation philosophy than other languages. When the first element of an S-expression is alone after the open parenthesis, the convention is to line up the remaining elements to start in the same column:

(first-item
 second-item
 third-item fourth-item fifth-item
 sixth-item)

When the second element is on the same line with the first one, the convention is to align the following elements the second one:

(first-item second-item
            third-item fourth-item fifth-item
            sixth-item)

This convention applies to sexps that are not special forms, including function calls such as the call to string-append. Special forms, sexps that are specially interpreted by the evaluator and the compiler, follow slightly different indentation. A form that provides expressions to evaluate will be indented with two spaces:

(lambda (value)
  (display value)
  (send-eof))

To an experienced Lisper, two spaces subtly denote that the expression is a special form whose two-space-indented subforms will be evaluated in sequence. When you create your own special forms using define-syntax or defmacro, you can tell Emacs to indent their subforms the same way:

;; define a CL-style `unless` macro...
(defmacro unless (test &rest forms)
  `(or ,test (progn ,@forms)))

;; ...and tell emacs to indent its body forms with two spaces
;; (unless (= value 0)
;;   (display value)
;;   (send-eof))
(put 'unless 'lisp-indent-function 2)

Changing the indentation level would send the wrong signal to the reader about what is going on, detracting from your code. If you don't like how Emacs indents your call to string-append, I suggest to switch to the second form, which will automatically indent the strings further to the right:

(string-append "foo "
               "bar "
               "baz")

总结就是:

  1. 如果sexp的第一个元素独立成一行,那么随后换行的元素全部和第一个元素对其

    (elem1
     elem2
     elem3) 
    
  2. 如果sexp的第二个元素和第一个元素在同一个行,那么随后换行的元素全部和第二个元素对其

    (elem1 elem2
           elem3) 
    
  3. 如果sexp的第一个元素是special form,那么随后换行的元素缩进两个空格:

    (defun f ()
      (message "hello world!"))
    (if cond
        then
      else)
    

更改缩进样式

更改缩进样式阔以参考所列的references,相关信息阔以用:

(info "(elisp) Indenting Macros") 

来查看。可以通过给指定 form 设置 lisp-indent-function 属性来设置 indent 规则:

(put 'when2 'lisp-indent-function 'defun)

这样对应 form 的缩进就会按照 special form 的规则缩进

(when2 a
  (b)
  (c))

也可以参考4,设置为数字2:

(put 'when3 'lisp-indent-function 2)
(when3 a
    (b)
  (c)
  (d))

设置Emacs里Scheme的缩进

scheme 的缩进对应 scheme-indent-function 属性,参考5

(put 'when2 'scheme-indent-function 'defun)
(when2 a
  (b)
  (c))

References


  1. Emacs scheme (scheme-mode) indentation↩︎

  2. Why does Emacs indent my Lisp LOOP construct weirdly?↩︎

  3. Modifying the indentation of some Emacs Lisp forms↩︎

  4. emacs-indentation↩︎

  5. emacs-indentation↩︎