]> code.delx.au - gnu-emacs/blobdiff - lisp/emacs-lisp/lisp-mode.el
Merge from emacs--rel--22
[gnu-emacs] / lisp / emacs-lisp / lisp-mode.el
index b9a732183221f84bcd8c21e62da8103446790cdc..7eeefd349a97a1f120504952b92dbf845fde7f23 100644 (file)
@@ -1,7 +1,7 @@
 ;;; 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
@@ -10,7 +10,7 @@
 
 ;; 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 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
@@ -56,6 +56,8 @@
        (modify-syntax-entry i "_   " table)
        (setq i (1+ i)))
       (modify-syntax-entry ?\s "    " table)
+      ;; Non-break space acts as whitespace.
+      (modify-syntax-entry ?\x8a0 "    " table)
       (modify-syntax-entry ?\t "    " table)
       (modify-syntax-entry ?\f "    " table)
       (modify-syntax-entry ?\n ">   " 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)
 (put 'define-ibuffer-filter 'doc-string-elt 2)
 (put 'define-ibuffer-op 'doc-string-elt 3)
   (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)
 
 (defvar lisp-mode-shared-map
   (let ((map (make-sparse-keymap)))
-    (define-key map "\t" 'lisp-indent-line)
     (define-key map "\e\C-q" 'indent-sexp)
     (define-key map "\177" 'backward-delete-char-untabify)
     ;; This gets in the way when viewing a Lisp file in view-mode.  As
@@ -291,7 +294,7 @@ All commands in `lisp-mode-shared-map' are inherited by this map.")
     (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] '("--"))
@@ -443,6 +446,9 @@ if that value is non-nil.")
 (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."
@@ -487,6 +493,8 @@ alternative printed representations that can be displayed."
              (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)
@@ -530,62 +538,65 @@ If CHAR is not a character, return nil."
              string))))
 
 
+(defun preceding-sexp ()
+  "Return sexp before the point."
+  (let ((opoint (point))
+       ignore-quotes
+       expr)
+    (save-excursion
+      (with-syntax-table emacs-lisp-mode-syntax-table
+       ;; If this sexp appears to be enclosed in `...'
+       ;; then ignore the surrounding quotes.
+       (setq ignore-quotes
+             (or (eq (following-char) ?\')
+                 (eq (preceding-char) ?\')))
+       (forward-sexp -1)
+       ;; If we were after `?\e' (or similar case),
+       ;; use the whole thing, not just the `e'.
+       (when (eq (preceding-char) ?\\)
+         (forward-char -1)
+         (when (eq (preceding-char) ??)
+           (forward-char -1)))
+
+       ;; Skip over `#N='s.
+       (when (eq (preceding-char) ?=)
+         (let (labeled-p)
+           (save-excursion
+             (skip-chars-backward "0-9#=")
+             (setq labeled-p (looking-at "\\(#[0-9]+=\\)+")))
+           (when labeled-p
+             (forward-sexp -1))))
+
+       (save-restriction
+         ;; vladimir@cs.ualberta.ca 30-Jul-1997: skip ` in
+         ;; `variable' so that the value is returned, not the
+         ;; name
+         (if (and ignore-quotes
+                  (eq (following-char) ?`))
+             (forward-char))
+         (narrow-to-region (point-min) opoint)
+         (setq expr (read (current-buffer)))
+         ;; If it's an (interactive ...) form, it's more
+         ;; useful to show how an interactive call would
+         ;; use it.
+         (and (consp expr)
+              (eq (car expr) 'interactive)
+              (setq expr
+                    (list 'call-interactively
+                          (list 'quote
+                                (list 'lambda
+                                      '(&rest args)
+                                      expr
+                                      'args)))))
+         expr)))))
+
+
 (defun eval-last-sexp-1 (eval-last-sexp-arg-internal)
   "Evaluate sexp before point; print value in minibuffer.
 With argument, print output into current buffer."
   (let ((standard-output (if eval-last-sexp-arg-internal (current-buffer) t)))
-    (let ((value
-          (eval (let ((stab (syntax-table))
-                      (opoint (point))
-                      ignore-quotes
-                      expr)
-                  (save-excursion
-                    (with-syntax-table emacs-lisp-mode-syntax-table
-                      ;; If this sexp appears to be enclosed in `...'
-                      ;; then ignore the surrounding quotes.
-                      (setq ignore-quotes
-                            (or (eq (following-char) ?\')
-                                (eq (preceding-char) ?\')))
-                      (forward-sexp -1)
-                      ;; If we were after `?\e' (or similar case),
-                      ;; use the whole thing, not just the `e'.
-                      (when (eq (preceding-char) ?\\)
-                        (forward-char -1)
-                        (when (eq (preceding-char) ??)
-                          (forward-char -1)))
-
-                      ;; Skip over `#N='s.
-                      (when (eq (preceding-char) ?=)
-                        (let (labeled-p)
-                          (save-excursion
-                            (skip-chars-backward "0-9#=")
-                            (setq labeled-p (looking-at "\\(#[0-9]+=\\)+")))
-                          (when labeled-p
-                            (forward-sexp -1))))
-
-                      (save-restriction
-                        ;; vladimir@cs.ualberta.ca 30-Jul-1997: skip ` in
-                        ;; `variable' so that the value is returned, not the
-                        ;; name
-                        (if (and ignore-quotes
-                                 (eq (following-char) ?`))
-                            (forward-char))
-                        (narrow-to-region (point-min) opoint)
-                        (setq expr (read (current-buffer)))
-                        ;; If it's an (interactive ...) form, it's more
-                        ;; useful to show how an interactive call would
-                        ;; use it.
-                        (and (consp expr)
-                             (eq (car expr) 'interactive)
-                             (setq expr
-                                   (list 'call-interactively
-                                         (list 'quote
-                                               (list 'lambda
-                                                     '(&rest args)
-                                                     expr
-                                                     'args)))))
-                        expr)))))))
-      (eval-last-sexp-print-value value))))
+    (eval-last-sexp-print-value (eval (preceding-sexp)))))
+
 
 (defun eval-last-sexp-print-value (value)
   (let ((unabbreviated (let ((print-length nil) (print-level nil))
@@ -614,17 +625,20 @@ With argument, print output into current buffer."
 
 (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.
@@ -720,7 +734,12 @@ If the current defun is actually a call to `defvar' or `defcustom',
 evaluating it this way resets the variable using its initial value
 expression even if the variable already has some other value.
 \(Normally `defvar' and `defcustom' do not alter the value if there
-already is one.)
+already is one.)  In an analogous way, evaluating a `defface'
+overrides any customizations of the face, so that it becomes
+defined exactly as the `defface' expression says.
+
+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.
 
@@ -746,17 +765,9 @@ which see."
             (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
@@ -773,8 +784,13 @@ which see."
          (let ((comment-start nil) (comment-start-skip nil))
            (do-auto-fill))))))
 
-(defvar lisp-indent-offset nil
-  "If non-nil, indent second line of expressions that many more columns.")
+(defcustom lisp-indent-offset nil
+  "If non-nil, indent second line of expressions that many more columns."
+  :group 'lisp
+  :type '(choice nil integer))
+(put 'lisp-body-indent 'safe-local-variable
+     (lambda (x) (or (null x) (integerp x))))
+
 (defvar lisp-indent-function 'lisp-indent-function)
 
 (defun lisp-indent-line (&optional whole-exp)
@@ -908,12 +924,53 @@ is the buffer position of the start of the containing expression."
                ;; 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 ":"))
+                     ;; The last sexp may not be at the indentation
+                     ;; where it begins, so find that one, instead.
+                     (save-excursion
+                       (goto-char calculate-lisp-indent-last-sexp)
+                       (while (and (not (looking-back "^[ \t]*"))
+                                   (or (not containing-sexp)
+                                       (< (1+ containing-sexp) (point))))
+                         (forward-sexp -1)
+                         (backward-prefix-chars))
+                       (setq calculate-lisp-indent-last-sexp (point)))
+                     (> 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))))))
 
@@ -973,8 +1030,11 @@ This function also returns nil meaning don't specify the indentation."
              (method
                (funcall method indent-point state)))))))
 
-(defvar lisp-body-indent 2
-  "Number of columns to indent the second line of a `(def...)' form.")
+(defcustom lisp-body-indent 2
+  "Number of columns to indent the second line of a `(def...)' form."
+  :group 'lisp
+  :type 'integer)
+(put 'lisp-body-indent 'safe-local-variable 'integerp)
 
 (defun lisp-indent-specform (count state indent-point normal-indent)
   (let ((containing-form-start (elt state 1))
@@ -1125,19 +1185,25 @@ ENDPOS is encountered."
                                         (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
@@ -1238,7 +1304,8 @@ and initial semicolons."
                                     "\\|\\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))