;;; lisp-mode.el --- Lisp mode, and its idiosyncratic commands
;; Copyright (C) 1985, 1986, 1999, 2000, 2001, 2002, 2003, 2004,
-;; 2005 Free Software Foundation, Inc.
+;; 2005, 2006, 2007 Free Software Foundation, Inc.
;; Maintainer: FSF
;; Keywords: lisp, languages
;;; Code:
+(defvar font-lock-comment-face)
+(defvar font-lock-doc-face)
+(defvar font-lock-keywords-case-fold-search)
+(defvar font-lock-string-face)
+
(defvar lisp-mode-abbrev-table nil)
(defvar emacs-lisp-mode-syntax-table
(while (< i 128)
(modify-syntax-entry i "_ " table)
(setq i (1+ i)))
- (modify-syntax-entry ? " " table)
+ (modify-syntax-entry ?\s " " table)
(modify-syntax-entry ?\t " " table)
(modify-syntax-entry ?\f " " table)
(modify-syntax-entry ?\n "> " table)
-;;; This is probably obsolete since nowadays such features use overlays.
-;;; ;; Give CR the same syntax as newline, for selective-display.
-;;; (modify-syntax-entry ?\^m "> " table)
+ ;; This is probably obsolete since nowadays such features use overlays.
+ ;; ;; Give CR the same syntax as newline, for selective-display.
+ ;; (modify-syntax-entry ?\^m "> " table)
(modify-syntax-entry ?\; "< " table)
(modify-syntax-entry ?` "' " table)
(modify-syntax-entry ?' "' " table)
(let ((table (copy-syntax-table emacs-lisp-mode-syntax-table)))
(modify-syntax-entry ?\[ "_ " table)
(modify-syntax-entry ?\] "_ " table)
- (modify-syntax-entry ?# "' 14bn" table)
- (modify-syntax-entry ?| "\" 23b" table)
+ (modify-syntax-entry ?# "' 14b" table)
+ (modify-syntax-entry ?| "\" 23bn" table)
table))
(define-abbrev-table 'lisp-mode-abbrev-table ())
(regexp-opt
'("defun" "defun*" "defsubst" "defmacro"
"defadvice" "define-skeleton"
- "define-minor-mode" "define-derived-mode"
- "define-generic-mode"
+ "define-minor-mode" "define-global-minor-mode"
+ "define-globalized-minor-mode"
+ "define-derived-mode" "define-generic-mode"
"define-compiler-macro" "define-modify-macro"
"defsetf" "define-setf-expander"
"define-method-combination"
"defgeneric" "defmethod") t))
- "\\s-+\\(\\sw\\(\\sw\\|\\s_\\)+\\)"))
+ "\\s-+\\(\\(\\sw\\|\\s_\\)+\\)"))
2)
(list (purecopy "Variables")
(purecopy (concat "^\\s-*("
(regexp-opt
'("defvar" "defconst" "defconstant" "defcustom"
"defparameter" "define-symbol-macro") t))
- "\\s-+\\(\\sw\\(\\sw\\|\\s_\\)+\\)"))
+ "\\s-+\\(\\(\\sw\\|\\s_\\)+\\)"))
2)
(list (purecopy "Types")
(purecopy (concat "^\\s-*("
'("defgroup" "deftheme" "deftype" "defstruct"
"defclass" "define-condition" "define-widget"
"defface" "defpackage") t))
- "\\s-+'?\\(\\sw\\(\\sw\\|\\s_\\)+\\)"))
+ "\\s-+'?\\(\\(\\sw\\|\\s_\\)+\\)"))
2))
"Imenu generic expression for Lisp mode. See `imenu-generic-expression'.")
(put 'define-compilation-mode 'doc-string-elt 3)
(put 'easy-mmode-define-minor-mode 'doc-string-elt 2)
(put 'define-minor-mode 'doc-string-elt 2)
+(put 'easy-mmode-define-global-mode 'doc-string-elt 2)
+(put 'define-global-minor-mode 'doc-string-elt 2)
+(put 'define-globalized-minor-mode 'doc-string-elt 2)
(put 'define-generic-mode 'doc-string-elt 7)
-;; define-global-mode has no explicit docstring.
-(put 'easy-mmode-define-global-mode 'doc-string-elt 0)
(put 'define-ibuffer-filter 'doc-string-elt 2)
(put 'define-ibuffer-op 'doc-string-elt 3)
(put 'define-ibuffer-sorter 'doc-string-elt 2)
+(put 'lambda 'doc-string-elt 2)
+(put 'defalias 'doc-string-elt 3)
+(put 'defvaralias 'doc-string-elt 3)
+(put 'define-category 'doc-string-elt 2)
+
+(defvar lisp-doc-string-elt-property 'doc-string-elt
+ "The symbol property that holds the docstring position info.")
(defun lisp-font-lock-syntactic-face-function (state)
(if (nth 3 state)
- (if (and (eq (nth 0 state) 1)
- ;; This might be a docstring.
- (save-excursion
- (let ((n 0))
- (goto-char (nth 8 state))
- (condition-case nil
- (while (and (not (bobp))
- (progn (backward-sexp 1) (setq n (1+ n)))))
- (scan-error nil))
- (when (> n 0)
- (let ((sym (intern-soft
- (buffer-substring
- (point) (progn (forward-sexp 1) (point))))))
- (eq n (or (get sym 'doc-string-elt) 3)))))))
- font-lock-doc-face
- font-lock-string-face)
+ ;; This might be a (doc)string or a |...| symbol.
+ (let ((startpos (nth 8 state)))
+ (if (eq (char-after startpos) ?|)
+ ;; This is not a string, but a |...| symbol.
+ nil
+ (let* ((listbeg (nth 1 state))
+ (firstsym (and listbeg
+ (save-excursion
+ (goto-char listbeg)
+ (and (looking-at "([ \t\n]*\\(\\(\\sw\\|\\s_\\)+\\)")
+ (match-string 1)))))
+ (docelt (and firstsym (get (intern-soft firstsym)
+ lisp-doc-string-elt-property))))
+ (if (and docelt
+ ;; It's a string in a form that can have a docstring.
+ ;; Check whether it's in docstring position.
+ (save-excursion
+ (when (functionp docelt)
+ (goto-char (match-end 1))
+ (setq docelt (funcall docelt)))
+ (goto-char listbeg)
+ (forward-char 1)
+ (condition-case nil
+ (while (and (> docelt 0) (< (point) startpos)
+ (progn (forward-sexp 1) t))
+ (setq docelt (1- docelt)))
+ (error nil))
+ (and (zerop docelt) (<= (point) startpos)
+ (progn (forward-comment (point-max)) t)
+ (= (point) (nth 8 state)))))
+ font-lock-doc-face
+ font-lock-string-face))))
font-lock-comment-face))
;; The LISP-SYNTAX argument is used by code in inf-lisp.el and is
(setq comment-column 40)
;; Don't get confused by `;' in doc strings when paragraph-filling.
(set (make-local-variable 'comment-use-global-state) t)
- (make-local-variable 'comment-indent-function)
- (setq comment-indent-function 'lisp-comment-indent)
(make-local-variable 'imenu-generic-expression)
(setq imenu-generic-expression lisp-imenu-generic-expression)
(make-local-variable 'multibyte-syntax-as-symbol)
(define-key map [byte-compile]
'("Byte-compile This File" . emacs-lisp-byte-compile))
(define-key map [separator-eval] '("--"))
- (define-key map [eval-buffer] '("Evaluate Buffer" . eval-current-buffer))
+ (define-key map [eval-buffer] '("Evaluate Buffer" . eval-buffer))
(define-key map [eval-region] '("Evaluate Region" . eval-region))
(define-key map [eval-sexp] '("Evaluate Last S-expression" . eval-last-sexp))
(define-key map [separator-format] '("--"))
(defun eval-print-last-sexp ()
"Evaluate sexp before point; print value into current buffer.
+If `eval-expression-debug-on-error' is non-nil, which is the default,
+this command arranges for all errors to enter the debugger.
+
Note that printing the result is controlled by the variables
`eval-expression-print-length' and `eval-expression-print-level',
which see."
(point (point)))
(delete-region beg end)
(insert (nth 1 value))
+ (or (= beg point)
+ (setq point (1- (point))))
(last-sexp-setup-props beg (point)
(nth 0 value)
(nth 2 value)
(defun eval-last-sexp (eval-last-sexp-arg-internal)
"Evaluate sexp before point; print value in minibuffer.
-Interactively, with prefix argument, print output into current buffer."
+Interactively, with prefix argument, print output into current buffer.
+
+If `eval-expression-debug-on-error' is non-nil, which is the default,
+this command arranges for all errors to enter the debugger."
(interactive "P")
(if (null eval-expression-debug-on-error)
(eval-last-sexp-1 eval-last-sexp-arg-internal)
- (let ((old-value eval-last-sexp-fake-value) new-value value)
- (let ((debug-on-error old-value))
- (setq value (eval-last-sexp-1 eval-last-sexp-arg-internal))
- (setq new-value debug-on-error))
- (unless (eq old-value new-value)
- (setq debug-on-error new-value))
- value)))
+ (let ((value
+ (let ((debug-on-error eval-last-sexp-fake-value))
+ (cons (eval-last-sexp-1 eval-last-sexp-arg-internal)
+ debug-on-error))))
+ (unless (eq (cdr value) eval-last-sexp-fake-value)
+ (setq debug-on-error (cdr value)))
+ (car value))))
(defun eval-defun-1 (form)
"Treat some expressions specially.
\(Normally `defvar' and `defcustom' do not alter the value if there
already is one.)
+If `eval-expression-debug-on-error' is non-nil, which is the default,
+this command arranges for all errors to enter the debugger.
+
With a prefix argument, instrument the code for Edebug.
If acting on a `defun' for FUNCTION, and the function was
(unless (eq old-value new-value)
(setq debug-on-error new-value))
value)))))
-\f
-;; Used for comment-indent-function in Lisp modes.
-(defun lisp-comment-indent ()
- (if (looking-at "\\s<\\s<\\s<")
- (current-column)
- (if (looking-at "\\s<\\s<")
- (let ((tem (or (calculate-lisp-indent) (current-column))))
- (if (listp tem) (car tem) tem))
- (skip-chars-backward " \t")
- (max (if (bolp) 0 (1+ (current-column)))
- comment-column))))
+
+;; May still be used by some external Lisp-mode variant.
+(define-obsolete-function-alias 'lisp-comment-indent 'comment-indent-default)
;; This function just forces a more costly detection of comments (using
;; parse-partial-sexp from beginning-of-defun). I.e. It avoids the problem of
;; Indent by constant offset
(goto-char containing-sexp)
(+ (current-column) lisp-indent-offset))
+ ;; in this case calculate-lisp-indent-last-sexp is not nil
+ (calculate-lisp-indent-last-sexp
+ (or
+ ;; try to align the parameters of a known function
+ (and lisp-indent-function
+ (not retry)
+ (funcall lisp-indent-function indent-point state))
+ ;; If the function has no special alignment
+ ;; or it does not apply to this argument,
+ ;; try to align a constant-symbol under the last
+ ;; preceding constant symbol, if there is such one of
+ ;; the last 2 preceding symbols, in the previous
+ ;; uncommented line.
+ (and (save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (looking-at ":"))
+ (> calculate-lisp-indent-last-sexp
+ (save-excursion
+ (goto-char (1+ containing-sexp))
+ (parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t)
+ (point)))
+ (let ((parse-sexp-ignore-comments t)
+ indent)
+ (goto-char calculate-lisp-indent-last-sexp)
+ (or (and (looking-at ":")
+ (setq indent (current-column)))
+ (and (< (save-excursion (beginning-of-line) (point))
+ (prog2 (backward-sexp) (point)))
+ (looking-at ":")
+ (setq indent (current-column))))
+ indent))
+ ;; another symbols or constants not preceded by a constant
+ ;; as defined above.
+ normal-indent))
+ ;; in this case calculate-lisp-indent-last-sexp is nil
(desired-indent)
- ((and (boundp 'lisp-indent-function)
- lisp-indent-function
- (not retry))
- (or (funcall lisp-indent-function indent-point state)
- normal-indent))
(t
normal-indent))))))
(make-list (- next-depth) nil))
last-depth (- last-depth next-depth)
next-depth 0)))
- (or outer-loop-done endpos
- (setq outer-loop-done (<= next-depth 0)))
- (if outer-loop-done
- (forward-line 1)
+ (forward-line 1)
+ ;; Decide whether to exit.
+ (if endpos
+ ;; If we have already reached the specified end,
+ ;; give up and do not reindent this line.
+ (if (<= endpos (point))
+ (setq outer-loop-done t))
+ ;; If no specified end, we are done if we have finished one sexp.
+ (if (<= next-depth 0)
+ (setq outer-loop-done t)))
+ (unless outer-loop-done
(while (> last-depth next-depth)
(setq indent-stack (cdr indent-stack)
last-depth (1- last-depth)))
(while (< last-depth next-depth)
(setq indent-stack (cons nil indent-stack)
last-depth (1+ last-depth)))
- ;; Now go to the next line and indent it according
+ ;; Now indent the next line according
;; to what we learned from parsing the previous one.
- (forward-line 1)
(setq bol (point))
(skip-chars-forward " \t")
;; But not if the line is blank, or just a comment
"\\|\\s-*\\([(;:\"]\\|`(\\|#'(\\)"))
(paragraph-separate
(concat paragraph-separate "\\|\\s-*\".*[,\\.]$"))
- (fill-column (if (integerp emacs-lisp-docstring-fill-column)
+ (fill-column (if (and (integerp emacs-lisp-docstring-fill-column)
+ (derived-mode-p 'emacs-lisp-mode))
emacs-lisp-docstring-fill-column
fill-column)))
(fill-paragraph justify))