-;;; lisp-mode.el --- Lisp mode, and its idiosyncratic commands.
+;;; lisp-mode.el --- Lisp mode, and its idiosyncratic commands
-;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
+;; Copyright (C) 1985,86,1999,2000,01,03,2004 Free Software Foundation, Inc.
;; Maintainer: FSF
;; Keywords: lisp, languages
;;; Commentary:
;; The base major mode for editing Lisp code (used also for Emacs Lisp).
-;; This mode is documented in the Emacs manual
+;; This mode is documented in the Emacs manual.
;;; Code:
-(defvar lisp-mode-syntax-table nil "")
-(defvar emacs-lisp-mode-syntax-table nil "")
-(defvar lisp-mode-abbrev-table nil "")
+(defvar lisp-mode-abbrev-table nil)
-(if (not emacs-lisp-mode-syntax-table)
+(defvar emacs-lisp-mode-syntax-table
+ (let ((table (make-syntax-table)))
(let ((i 0))
- (setq emacs-lisp-mode-syntax-table (make-syntax-table))
(while (< i ?0)
- (modify-syntax-entry i "_ " emacs-lisp-mode-syntax-table)
+ (modify-syntax-entry i "_ " table)
(setq i (1+ i)))
(setq i (1+ ?9))
(while (< i ?A)
- (modify-syntax-entry i "_ " emacs-lisp-mode-syntax-table)
+ (modify-syntax-entry i "_ " table)
(setq i (1+ i)))
(setq i (1+ ?Z))
(while (< i ?a)
- (modify-syntax-entry i "_ " emacs-lisp-mode-syntax-table)
+ (modify-syntax-entry i "_ " table)
(setq i (1+ i)))
(setq i (1+ ?z))
(while (< i 128)
- (modify-syntax-entry i "_ " emacs-lisp-mode-syntax-table)
+ (modify-syntax-entry i "_ " table)
(setq i (1+ i)))
- (modify-syntax-entry ? " " emacs-lisp-mode-syntax-table)
- (modify-syntax-entry ?\t " " emacs-lisp-mode-syntax-table)
- (modify-syntax-entry ?\n "> " emacs-lisp-mode-syntax-table)
+ (modify-syntax-entry ? " " table)
+ (modify-syntax-entry ?\t " " table)
+ (modify-syntax-entry ?\f " " table)
+ (modify-syntax-entry ?\n "> " table)
;; Give CR the same syntax as newline, for selective-display.
- (modify-syntax-entry ?\^m "> " emacs-lisp-mode-syntax-table)
- (modify-syntax-entry ?\; "< " emacs-lisp-mode-syntax-table)
- (modify-syntax-entry ?` "' " emacs-lisp-mode-syntax-table)
- (modify-syntax-entry ?' "' " emacs-lisp-mode-syntax-table)
- (modify-syntax-entry ?, "' " emacs-lisp-mode-syntax-table)
+ (modify-syntax-entry ?\^m "> " table)
+ (modify-syntax-entry ?\; "< " table)
+ (modify-syntax-entry ?` "' " table)
+ (modify-syntax-entry ?' "' " table)
+ (modify-syntax-entry ?, "' " table)
+ (modify-syntax-entry ?@ "' " table)
;; Used to be singlequote; changed for flonums.
- (modify-syntax-entry ?. "_ " emacs-lisp-mode-syntax-table)
- (modify-syntax-entry ?# "' " emacs-lisp-mode-syntax-table)
- (modify-syntax-entry ?\" "\" " emacs-lisp-mode-syntax-table)
- (modify-syntax-entry ?\\ "\\ " emacs-lisp-mode-syntax-table)
- (modify-syntax-entry ?\( "() " emacs-lisp-mode-syntax-table)
- (modify-syntax-entry ?\) ")( " emacs-lisp-mode-syntax-table)
- (modify-syntax-entry ?\[ "(] " emacs-lisp-mode-syntax-table)
- (modify-syntax-entry ?\] ")[ " emacs-lisp-mode-syntax-table)))
-
-(if (not lisp-mode-syntax-table)
- (progn (setq lisp-mode-syntax-table
- (copy-syntax-table emacs-lisp-mode-syntax-table))
- (modify-syntax-entry ?\| "\" " lisp-mode-syntax-table)
- (modify-syntax-entry ?\[ "_ " lisp-mode-syntax-table)
- (modify-syntax-entry ?\] "_ " lisp-mode-syntax-table)))
+ (modify-syntax-entry ?. "_ " table)
+ (modify-syntax-entry ?# "' " table)
+ (modify-syntax-entry ?\" "\" " table)
+ (modify-syntax-entry ?\\ "\\ " table)
+ (modify-syntax-entry ?\( "() " table)
+ (modify-syntax-entry ?\) ")( " table)
+ (modify-syntax-entry ?\[ "(] " table)
+ (modify-syntax-entry ?\] ")[ " table))
+ table))
+
+(defvar lisp-mode-syntax-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)
+ table))
(define-abbrev-table 'lisp-mode-abbrev-table ())
(defvar lisp-imenu-generic-expression
- '(
- (nil
- "^\\s-*(def\\(un\\|subst\\|macro\\|advice\\)\\s-+\\([-A-Za-z0-9+*|:]+\\)" 2)
- ("Variables"
- "^\\s-*(def\\(var\\|const\\)\\s-+\\([-A-Za-z0-9+*|:]+\\)" 2)
- ("Types"
- "^\\s-*(def\\(type\\|struct\\|class\\|ine-condition\\)\\s-+\\([-A-Za-z0-9+*|:]+\\)"
+ (list
+ (list nil
+ (purecopy (concat "^\\s-*("
+ (eval-when-compile
+ (regexp-opt
+ '("defun" "defun*" "defsubst" "defmacro"
+ "defadvice" "define-skeleton"
+ "define-minor-mode" "define-derived-mode"
+ "define-compiler-macro" "define-modify-macro"
+ "defsetf" "define-setf-expander"
+ "define-method-combination"
+ "defgeneric" "defmethod") t))
+ "\\s-+\\(\\sw\\(\\sw\\|\\s_\\)+\\)"))
+ 2)
+ (list (purecopy "Variables")
+ (purecopy (concat "^\\s-*("
+ (eval-when-compile
+ (regexp-opt
+ '("defvar" "defconst" "defconstant" "defcustom"
+ "defparameter" "define-symbol-macro") t))
+ "\\s-+\\(\\sw\\(\\sw\\|\\s_\\)+\\)"))
+ 2)
+ (list (purecopy "Types")
+ (purecopy (concat "^\\s-*("
+ (eval-when-compile
+ (regexp-opt
+ '("defgroup" "deftheme" "deftype" "defstruct"
+ "defclass" "define-condition" "define-widget"
+ "defface" "defpackage") t))
+ "\\s-+'?\\(\\sw\\(\\sw\\|\\s_\\)+\\)"))
2))
"Imenu generic expression for Lisp mode. See `imenu-generic-expression'.")
-(defun lisp-mode-variables (lisp-syntax)
- (cond (lisp-syntax
- (set-syntax-table lisp-mode-syntax-table)))
+;; This was originally in autoload.el and is still used there.
+(put 'autoload 'doc-string-elt 3)
+(put 'defun 'doc-string-elt 3)
+(put 'defun* 'doc-string-elt 3)
+(put 'defvar 'doc-string-elt 3)
+(put 'defcustom 'doc-string-elt 3)
+(put 'deftheme 'doc-string-elt 2)
+(put 'defconst 'doc-string-elt 3)
+(put 'defmacro 'doc-string-elt 3)
+(put 'defmacro* 'doc-string-elt 3)
+(put 'defsubst 'doc-string-elt 3)
+(put 'define-skeleton 'doc-string-elt 2)
+(put 'define-derived-mode 'doc-string-elt 4)
+(put 'easy-mmode-define-minor-mode 'doc-string-elt 2)
+(put 'define-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)
+
+(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)
+ font-lock-comment-face))
+
+;; The LISP-SYNTAX argument is used by code in inf-lisp.el and is
+;; (uselessly) passed from pp.el, chistory.el, gnus-kill.el and score-mode.el
+(defun lisp-mode-variables (&optional lisp-syntax)
+ (when lisp-syntax
+ (set-syntax-table lisp-mode-syntax-table))
(setq local-abbrev-table lisp-mode-abbrev-table)
- (make-local-variable 'paragraph-start)
- (setq paragraph-start (concat page-delimiter "\\|$" ))
- (make-local-variable 'paragraph-separate)
- (setq paragraph-separate paragraph-start)
(make-local-variable 'paragraph-ignore-fill-prefix)
(setq paragraph-ignore-fill-prefix t)
(make-local-variable 'fill-paragraph-function)
;; Adaptive fill mode gets in the way of auto-fill,
;; and should make no difference for explicit fill
;; because lisp-fill-paragraph should do the job.
- (make-local-variable 'adaptive-fill-mode)
- (setq adaptive-fill-mode nil)
+ ;; I believe that newcomment's auto-fill code properly deals with it -stef
+ ;;(set (make-local-variable 'adaptive-fill-mode) nil)
(make-local-variable 'indent-line-function)
(setq indent-line-function 'lisp-indent-line)
(make-local-variable 'indent-region-function)
(make-local-variable 'parse-sexp-ignore-comments)
(setq parse-sexp-ignore-comments t)
(make-local-variable 'outline-regexp)
- (setq outline-regexp ";;; \\|(....")
+ (setq outline-regexp ";;;;* [^ \t\n]\\|(")
+ (make-local-variable 'outline-level)
+ (setq outline-level 'lisp-outline-level)
(make-local-variable 'comment-start)
(setq comment-start ";")
(make-local-variable 'comment-start-skip)
;; Look within the line for a ; following an even number of backslashes
;; after either a non-backslash or the line beginning.
(setq comment-start-skip "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\);+ *")
+ (make-local-variable 'comment-add)
+ (setq comment-add 1) ;default to `;;' in comment-region
(make-local-variable 'comment-column)
(setq comment-column 40)
- (make-local-variable 'comment-indent-function)
- (setq comment-indent-function 'lisp-comment-indent)
+ ;; Don't get confused by `;' in doc strings when paragraph-filling.
+ (set (make-local-variable 'comment-use-global-state) t)
(make-local-variable 'imenu-generic-expression)
- (setq imenu-generic-expression lisp-imenu-generic-expression))
-\f
-(defvar shared-lisp-mode-map ()
- "Keymap for commands shared by all sorts of Lisp modes.")
+ (setq imenu-generic-expression lisp-imenu-generic-expression)
+ (make-local-variable 'multibyte-syntax-as-symbol)
+ (setq multibyte-syntax-as-symbol t)
+ (set (make-local-variable 'syntax-begin-function) 'beginning-of-defun)
+ (setq font-lock-defaults
+ '((lisp-font-lock-keywords
+ lisp-font-lock-keywords-1 lisp-font-lock-keywords-2)
+ nil nil (("+-*/.<>=!?$%_&~^:" . "w")) nil
+ (font-lock-mark-block-function . mark-defun)
+ (font-lock-syntactic-face-function
+ . lisp-font-lock-syntactic-face-function))))
-(if shared-lisp-mode-map
- ()
- (setq shared-lisp-mode-map (make-sparse-keymap))
- (define-key shared-lisp-mode-map "\e\C-q" 'indent-sexp)
- (define-key shared-lisp-mode-map "\177" 'backward-delete-char-untabify))
+(defun lisp-outline-level ()
+ "Lisp mode `outline-level' function."
+ (if (looking-at "(\\|;;;###autoload")
+ 1000
+ (looking-at outline-regexp)
+ (- (match-end 0) (match-beginning 0))))
+
+
+(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
+ ;; long as [backspace] is mapped into DEL via the
+ ;; function-key-map, this should remain disabled!!
+ ;;;(define-key map [backspace] 'backward-delete-char-untabify)
+ map)
+ "Keymap for commands shared by all sorts of Lisp modes.")
(defvar emacs-lisp-mode-map ()
"Keymap for Emacs Lisp mode.
-All commands in `shared-lisp-mode-map' are inherited by this map.")
+All commands in `lisp-mode-shared-map' are inherited by this map.")
(if emacs-lisp-mode-map
()
(let ((map (make-sparse-keymap "Emacs-Lisp")))
- (setq emacs-lisp-mode-map
- (nconc (make-sparse-keymap) shared-lisp-mode-map))
+ (setq emacs-lisp-mode-map (make-sparse-keymap))
+ (set-keymap-parent emacs-lisp-mode-map lisp-mode-shared-map)
(define-key emacs-lisp-mode-map "\e\t" 'lisp-complete-symbol)
(define-key emacs-lisp-mode-map "\e\C-x" 'eval-defun)
(define-key emacs-lisp-mode-map [menu-bar] (make-sparse-keymap))
(require 'bytecomp)
;; Recompile if file or buffer has changed since last compilation.
(if (and (buffer-modified-p)
- (y-or-n-p (format "save buffer %s first? " (buffer-name))))
+ (y-or-n-p (format "Save buffer %s first? " (buffer-name))))
(save-buffer))
(let ((compiled-file-name (byte-compile-dest-file buffer-file-name)))
(if (file-newer-than-file-p compiled-file-name buffer-file-name)
(load-file compiled-file-name)
(byte-compile-file buffer-file-name t))))
+(defcustom emacs-lisp-mode-hook nil
+ "Hook run when entering Emacs Lisp mode."
+ :options '(turn-on-eldoc-mode imenu-add-menubar-index checkdoc-minor-mode)
+ :type 'hook
+ :group 'lisp)
+
+(defcustom lisp-mode-hook nil
+ "Hook run when entering Lisp mode."
+ :options '(imenu-add-menubar-index)
+ :type 'hook
+ :group 'lisp)
+
+(defcustom lisp-interaction-mode-hook nil
+ "Hook run when entering Lisp Interaction mode."
+ :options '(turn-on-eldoc-mode)
+ :type 'hook
+ :group 'lisp)
+
(defun emacs-lisp-mode ()
"Major mode for editing Lisp code to run in Emacs.
Commands:
(set-syntax-table emacs-lisp-mode-syntax-table)
(setq major-mode 'emacs-lisp-mode)
(setq mode-name "Emacs-Lisp")
- (lisp-mode-variables nil)
- (run-hooks 'emacs-lisp-mode-hook))
+ (lisp-mode-variables)
+ (setq imenu-case-fold-search nil)
+ (run-mode-hooks 'emacs-lisp-mode-hook))
+(put 'emacs-lisp-mode 'custom-mode-group 'lisp)
-(defvar lisp-mode-map ()
+(defvar lisp-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map lisp-mode-shared-map)
+ (define-key map "\e\C-x" 'lisp-eval-defun)
+ (define-key map "\C-c\C-z" 'run-lisp)
+ map)
"Keymap for ordinary Lisp mode.
-All commands in `shared-lisp-mode-map' are inherited by this map.")
-
-(if lisp-mode-map
- ()
- (setq lisp-mode-map
- (nconc (make-sparse-keymap) shared-lisp-mode-map))
- (define-key lisp-mode-map "\e\C-x" 'lisp-eval-defun)
- (define-key lisp-mode-map "\C-c\C-z" 'run-lisp))
+All commands in `lisp-mode-shared-map' are inherited by this map.")
(defun lisp-mode ()
"Major mode for editing Lisp code for Lisps other than GNU Emacs Lisp.
(use-local-map lisp-mode-map)
(setq major-mode 'lisp-mode)
(setq mode-name "Lisp")
- (lisp-mode-variables t)
+ (lisp-mode-variables)
+ (make-local-variable 'comment-start-skip)
+ (setq comment-start-skip
+ "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\)\\(;+\\|#|\\) *")
+ (make-local-variable 'font-lock-keywords-case-fold-search)
+ (setq font-lock-keywords-case-fold-search t)
+ (setq imenu-case-fold-search t)
(set-syntax-table lisp-mode-syntax-table)
- (run-hooks 'lisp-mode-hook))
+ (run-mode-hooks 'lisp-mode-hook))
-;; This will do unless shell.el is loaded.
-(defun lisp-eval-defun nil
+;; Used in old LispM code.
+(defalias 'common-lisp-mode 'lisp-mode)
+
+;; This will do unless inf-lisp.el is loaded.
+(defun lisp-eval-defun (&optional and-go)
"Send the current defun to the Lisp process made by \\[run-lisp]."
(interactive)
(error "Process lisp does not exist"))
-(defvar lisp-interaction-mode-map ()
- "Keymap for Lisp Interaction moe.
-All commands in `shared-lisp-mode-map' are inherited by this map.")
-
-(if lisp-interaction-mode-map
- ()
- (setq lisp-interaction-mode-map
- (nconc (make-sparse-keymap) shared-lisp-mode-map))
- (define-key lisp-interaction-mode-map "\e\C-x" 'eval-defun)
- (define-key lisp-interaction-mode-map "\e\t" 'lisp-complete-symbol)
- (define-key lisp-interaction-mode-map "\n" 'eval-print-last-sexp))
+(defvar lisp-interaction-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map lisp-mode-shared-map)
+ (define-key map "\e\C-x" 'eval-defun)
+ (define-key map "\e\t" 'lisp-complete-symbol)
+ (define-key map "\n" 'eval-print-last-sexp)
+ map)
+ "Keymap for Lisp Interaction mode.
+All commands in `lisp-mode-shared-map' are inherited by this map.")
-(defun lisp-interaction-mode ()
+(defvar lisp-interaction-mode-abbrev-table lisp-mode-abbrev-table)
+(define-derived-mode lisp-interaction-mode emacs-lisp-mode "Lisp Interaction"
"Major mode for typing and evaluating Lisp forms.
Like Lisp mode except that \\[eval-print-last-sexp] evals the Lisp expression
before point, and prints its value into the buffer, advancing point.
+Note that printing is controlled by `eval-expression-print-length'
+and `eval-expression-print-level'.
Commands:
Delete converts tabs to spaces as it moves back.
Semicolons start comments.
\\{lisp-interaction-mode-map}
Entry to this mode calls the value of `lisp-interaction-mode-hook'
-if that value is non-nil."
- (interactive)
- (kill-all-local-variables)
- (use-local-map lisp-interaction-mode-map)
- (setq major-mode 'lisp-interaction-mode)
- (setq mode-name "Lisp Interaction")
- (set-syntax-table emacs-lisp-mode-syntax-table)
- (lisp-mode-variables nil)
- (run-hooks 'lisp-interaction-mode-hook))
+if that value is non-nil.")
(defun eval-print-last-sexp ()
- "Evaluate sexp before point; print value into current buffer."
+ "Evaluate sexp before point; print value into current buffer.
+
+Note that printing the result is controlled by the variables
+`eval-expression-print-length' and `eval-expression-print-level',
+which see."
(interactive)
(let ((standard-output (current-buffer)))
(terpri)
(eval-last-sexp t)
(terpri)))
-\f
-(defun eval-last-sexp (eval-last-sexp-arg-internal)
+
+
+(defun last-sexp-setup-props (beg end value alt1 alt2)
+ "Set up text properties for the output of `eval-last-sexp-1'.
+BEG and END are the start and end of the output in current-buffer.
+VALUE is the Lisp value printed, ALT1 and ALT2 are strings for the
+alternative printed representations that can be displayed."
+ (let ((map (make-sparse-keymap)))
+ (define-key map "\C-m" 'last-sexp-toggle-display)
+ (define-key map [down-mouse-2] 'mouse-set-point)
+ (define-key map [mouse-2] 'last-sexp-toggle-display)
+ (add-text-properties
+ beg end
+ `(printed-value (,value ,alt1 ,alt2)
+ mouse-face highlight
+ keymap ,map
+ help-echo "RET, mouse-2: toggle abbreviated display"
+ rear-nonsticky (mouse-face keymap help-echo
+ printed-value)))))
+
+
+(defun last-sexp-toggle-display (&optional arg)
+ "Toggle between abbreviated and unabbreviated printed representations."
+ (interactive "P")
+ (save-restriction
+ (widen)
+ (let ((value (get-text-property (point) 'printed-value)))
+ (when value
+ (let ((beg (or (previous-single-property-change (min (point-max) (1+ (point)))
+ 'printed-value)
+ (point)))
+ (end (or (next-single-char-property-change (point) 'printed-value) (point)))
+ (standard-output (current-buffer))
+ (point (point)))
+ (delete-region beg end)
+ (insert (nth 1 value))
+ (last-sexp-setup-props beg (point)
+ (nth 0 value)
+ (nth 2 value)
+ (nth 1 value))
+ (goto-char (min (point-max) point)))))))
+
+(defun prin1-char (char)
+ "Return a string representing CHAR as a character rather than as an integer.
+If CHAR is not a character, return nil."
+ (and (integerp char)
+ (char-valid-p (event-basic-type char))
+ (let ((c (event-basic-type char)))
+ (concat
+ "?"
+ (mapconcat
+ (lambda (modif)
+ (cond ((eq modif 'super) "\\s-")
+ (t (string ?\\ (upcase (aref (symbol-name modif) 0)) ?-))))
+ (event-modifiers char) "")
+ (cond
+ ((memq c '(?\; ?\( ?\) ?\{ ?\} ?\[ ?\] ?\" ?\' ?\\)) (string ?\\ c))
+ ((eq c 127) "\\C-?")
+ (t (string c)))))))
+
+(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."
- (interactive "P")
(let ((standard-output (if eval-last-sexp-arg-internal (current-buffer) t)))
- (prin1 (eval (let ((stab (syntax-table))
+ (let ((value
+ (eval (let ((stab (syntax-table))
(opoint (point))
ignore-quotes
expr)
- (unwind-protect
- (save-excursion
- (set-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)
- (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))
- (set-syntax-table stab)))))))
-
-(defun eval-defun (eval-defun-arg-internal)
+ (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))))
+
+(defun eval-last-sexp-print-value (value)
+ (let ((unabbreviated (let ((print-length nil) (print-level nil))
+ (prin1-to-string value)))
+ (print-length eval-expression-print-length)
+ (print-level eval-expression-print-level)
+ (char-string (prin1-char value))
+ (beg (point))
+ end)
+ (prog1
+ (prin1 value)
+ (if (and (eq standard-output t) char-string)
+ (princ (concat " = " char-string)))
+ (setq end (point))
+ (when (and (bufferp standard-output)
+ (or (not (null print-length))
+ (not (null print-level)))
+ (not (string= unabbreviated
+ (buffer-substring-no-properties beg end))))
+ (last-sexp-setup-props beg end value
+ unabbreviated
+ (buffer-substring-no-properties beg end))
+ ))))
+
+
+(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."
+ (interactive "P")
+ (if (null eval-expression-debug-on-error)
+ (eval-last-sexp-1 eval-last-sexp-arg-internal)
+ (let ((old-value (make-symbol "t")) 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)))
+
+(defun eval-defun-1 (form)
+ "Change defvar into defconst within FORM.
+Likewise for other constructs as necessary."
+ ;; The code in edebug-defun should be consistent with this, but not
+ ;; the same, since this gets a macroexpended form.
+ (cond ((not (listp form))
+ form)
+ ((and (eq (car form) 'defvar)
+ (cdr-safe (cdr-safe form))
+ (boundp (cadr form)))
+ ;; Force variable to be re-set.
+ `(progn (defvar ,(nth 1 form) nil ,@(nthcdr 3 form))
+ (setq ,(nth 1 form) ,(nth 2 form))))
+ ;; `defcustom' is now macroexpanded to
+ ;; `custom-declare-variable' with a quoted value arg.
+ ((and (eq (car form) 'custom-declare-variable)
+ (default-boundp (eval (nth 1 form))))
+ ;; Force variable to be bound.
+ (set-default (eval (nth 1 form)) (eval (nth 1 (nth 2 form))))
+ form)
+ ((eq (car form) 'progn)
+ (cons 'progn (mapcar 'eval-defun-1 (cdr form))))
+ (t form)))
+
+(defun eval-defun-2 ()
"Evaluate defun that point is in or before.
-Print value in minibuffer.
-With argument, insert value in current buffer after the defun."
+The value is displayed in the minibuffer.
+If the current defun is actually a call to `defvar',
+then reset the variable using the initial value expression
+even if the variable already has some other value.
+\(Normally `defvar' does not change the variable's value
+if it already has a value.\)
+
+With argument, insert value in current buffer after the defun.
+Return the result of evaluation."
+ (interactive "P")
+ (let ((debug-on-error eval-expression-debug-on-error)
+ (print-length eval-expression-print-length)
+ (print-level eval-expression-print-level))
+ (save-excursion
+ ;; Arrange for eval-region to "read" the (possibly) altered form.
+ ;; eval-region handles recording which file defines a function or
+ ;; variable. Re-written using `apply' to avoid capturing
+ ;; variables like `end'.
+ (apply
+ #'eval-region
+ (let ((standard-output t)
+ beg end form)
+ ;; Read the form from the buffer, and record where it ends.
+ (save-excursion
+ (end-of-defun)
+ (beginning-of-defun)
+ (setq beg (point))
+ (setq form (read (current-buffer)))
+ (setq end (point)))
+ ;; Alter the form if necessary, changing defvar into defconst, etc.
+ (setq form (eval-defun-1 (macroexpand form)))
+ (list beg end standard-output
+ `(lambda (ignore)
+ ;; Skipping to the end of the specified region
+ ;; will make eval-region return.
+ (goto-char ,end)
+ ',form))))))
+ ;; The result of evaluation has been put onto VALUES. So return it.
+ (car values))
+
+(defun eval-defun (edebug-it)
+ "Evaluate the top-level form containing point, or after point.
+
+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.)
+
+With a prefix argument, instrument the code for Edebug.
+
+If acting on a `defun' for FUNCTION, and the function was
+instrumented, `Edebug: FUNCTION' is printed in the minibuffer. If not
+instrumented, just FUNCTION is printed.
+
+If not acting on a `defun', the result of evaluation is displayed in
+the minibuffer. This display is controlled by the variables
+`eval-expression-print-length' and `eval-expression-print-level',
+which see."
(interactive "P")
- (let ((standard-output (if eval-defun-arg-internal (current-buffer) t))
- (form (save-excursion
- (end-of-defun)
- (beginning-of-defun)
- (read (current-buffer)))))
- (cond ((and (eq (car form) 'defvar)
- (cdr-safe (cdr-safe form)))
- ;; Force variable to be bound.
- (setq form (cons 'defconst (cdr form))))
- ((and (eq (car form) 'defcustom)
- (default-boundp (nth 1 form)))
- ;; Force variable to be bound.
- (set-default (nth 1 form) (eval (nth 2 form)))))
- (prin1 (eval form))))
+ (cond (edebug-it
+ (require 'edebug)
+ (eval-defun (not edebug-all-defs)))
+ (t
+ (if (null eval-expression-debug-on-error)
+ (eval-defun-2)
+ (let ((old-value (make-symbol "t")) new-value value)
+ (let ((debug-on-error old-value))
+ (setq value (eval-defun-2))
+ (setq new-value debug-on-error))
+ (unless (eq old-value new-value)
+ (setq debug-on-error new-value))
+ value)))))
\f
+
(defun lisp-comment-indent ()
(if (looking-at "\\s<\\s<\\s<")
(current-column)
(max (if (bolp) 0 (1+ (current-column)))
comment-column))))
-(defvar lisp-indent-offset nil "")
-(defvar lisp-indent-function 'lisp-indent-function "")
+;; 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
+;; taking a `;' inside a string started on another line for a comment starter.
+;; Note: `newcomment' gets it right now since we set comment-use-global-state
+;; so we could get rid of it. -stef
+(defun lisp-mode-auto-fill ()
+ (if (> (current-column) (current-fill-column))
+ (if (save-excursion
+ (nth 4 (syntax-ppss (point))))
+ (do-auto-fill)
+ (unless (and (boundp 'comment-auto-fill-only-comments)
+ comment-auto-fill-only-comments)
+ (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.")
+(defvar lisp-indent-function 'lisp-indent-function)
(defun lisp-indent-line (&optional whole-exp)
"Indent current line as Lisp code.
With argument, indent any additional lines of the same expression
rigidly along with this one."
(interactive "P")
- (let ((indent (calculate-lisp-indent)) shift-amt beg end
- (pos (- (point-max) (point))))
- (beginning-of-line)
- (setq beg (point))
+ (let ((indent (calculate-lisp-indent)) shift-amt end
+ (pos (- (point-max) (point)))
+ (beg (progn (beginning-of-line) (point))))
(skip-chars-forward " \t")
(if (or (null indent) (looking-at "\\s<\\s<\\s<"))
;; Don't alter indentation of a ;;; comment line
(backward-prefix-chars))
(t
;; Indent beneath first sexp on same line as
- ;; calculate-lisp-indent-last-sexp. Again, it's
+ ;; `calculate-lisp-indent-last-sexp'. Again, it's
;; almost certainly a function call.
(goto-char calculate-lisp-indent-last-sexp)
(beginning-of-line)
normal-indent))))))
(defun lisp-indent-function (indent-point state)
+ "This function is the normal value of the variable `lisp-indent-function'.
+It is used when indenting a line within a function call, to see if the
+called function says anything special about how to indent the line.
+
+INDENT-POINT is the position where the user typed TAB, or equivalent.
+Point is located at the point to indent under (for default indentation);
+STATE is the `parse-partial-sexp' state for that position.
+
+If the current line is in a call to a Lisp function
+which has a non-nil property `lisp-indent-function',
+that specifies how to do the indentation. The property value can be
+* `defun', meaning indent `defun'-style;
+* an integer N, meaning indent the first N arguments specially
+like ordinary function arguments and then indent any further
+aruments like a body;
+* a function to call just as this function was called.
+If that function returns nil, that means it doesn't specify
+the indentation.
+
+This function also returns nil meaning don't specify the indentation."
(let ((normal-indent (current-column)))
(goto-char (1+ (elt state 1)))
(parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t)
(if (and (elt state 2)
(not (looking-at "\\sw\\|\\s_")))
- ;; car of form doesn't seem to be a a symbol
+ ;; car of form doesn't seem to be a symbol
(progn
(if (not (> (save-excursion (forward-line 1) (point))
calculate-lisp-indent-last-sexp))
- (progn (goto-char calculate-lisp-indent-last-sexp)
- (beginning-of-line)
- (parse-partial-sexp (point)
- calculate-lisp-indent-last-sexp 0 t)))
- ;; Indent under the list or under the first sexp on the same
- ;; line as calculate-lisp-indent-last-sexp. Note that first
- ;; thing on that line has to be complete sexp since we are
+ (progn (goto-char calculate-lisp-indent-last-sexp)
+ (beginning-of-line)
+ (parse-partial-sexp (point)
+ calculate-lisp-indent-last-sexp 0 t)))
+ ;; Indent under the list or under the first sexp on the same
+ ;; line as calculate-lisp-indent-last-sexp. Note that first
+ ;; thing on that line has to be complete sexp since we are
;; inside the innermost containing sexp.
(backward-prefix-chars)
(current-column))
(goto-char (car (cdr state)))
(+ lisp-body-indent (current-column)))))
-\f
+
;; (put 'progn 'lisp-indent-function 0), say, causes progn to be indented
;; like defun if the first form is placed on the next line, otherwise
;; it is indented like any other form (i.e. forms line up under first).
(put 'with-output-to-string 'lisp-indent-function 0)
(put 'with-temp-file 'lisp-indent-function 1)
(put 'with-temp-buffer 'lisp-indent-function 0)
+(put 'with-temp-message 'lisp-indent-function 1)
+(put 'with-syntax-table 'lisp-indent-function 1)
(put 'let 'lisp-indent-function 1)
(put 'let* 'lisp-indent-function 1)
(put 'while 'lisp-indent-function 1)
(put 'if 'lisp-indent-function 2)
+(put 'read-if 'lisp-indent-function 2)
(put 'catch 'lisp-indent-function 1)
(put 'condition-case 'lisp-indent-function 2)
(put 'unwind-protect 'lisp-indent-function 1)
(put 'with-output-to-temp-buffer 'lisp-indent-function 1)
(put 'eval-after-load 'lisp-indent-function 1)
+(put 'dolist 'lisp-indent-function 1)
+(put 'dotimes 'lisp-indent-function 1)
+(put 'when 'lisp-indent-function 1)
+(put 'unless 'lisp-indent-function 1)
(defun indent-sexp (&optional endpos)
"Indent each line of the list starting just after point.
(and endpos
(<= next-depth 0)
(progn
- (setq indent-stack (append indent-stack
- (make-list (- next-depth) nil))
+ (setq indent-stack (nconc indent-stack
+ (make-list (- next-depth) nil))
last-depth (- last-depth next-depth)
next-depth 0)))
(or outer-loop-done endpos
(setq outer-loop-done (= (point) last-point))
(setq last-point (point)))))))
-;; Indent every line whose first char is between START and END inclusive.
(defun lisp-indent-region (start end)
+ "Indent every line whose first char is between START and END inclusive."
(save-excursion
(let ((endmark (copy-marker end)))
(goto-char start)
(lisp-indent-line))
(indent-sexp endmark)
(set-marker endmark nil))))
-\f
+
;;;; Lisp paragraph filling commands.
+(defcustom emacs-lisp-docstring-fill-column 65
+ "Value of `fill-column' to use when filling a docstring.
+Any non-integer value means do not use a different value of
+`fill-column' when filling docstrings."
+ :type '(choice (integer)
+ (const :tag "Use the current `fill-column'" t))
+ :group 'lisp)
+
(defun lisp-fill-paragraph (&optional justify)
- "Like \\[fill-paragraph], but handle Emacs Lisp comments.
+ "Like \\[fill-paragraph], but handle Emacs Lisp comments and docstrings.
If any of the current line is a comment, fill the comment or the
paragraph of it that point is in, preserving the comment's indentation
and initial semicolons."
(interactive "P")
- (let (
- ;; Non-nil if the current line contains a comment.
- has-comment
-
- ;; Non-nil if the current line contains code and a comment.
- has-code-and-comment
-
- ;; If has-comment, the appropriate fill-prefix for the comment.
- comment-fill-prefix
- )
+ (or (fill-comment-paragraph justify)
+ ;; Point is on a program line (a line no comment); we are interested
+ ;; particularly in docstring lines.
+ ;;
+ ;; We bind `paragraph-start' and `paragraph-separate' temporarily. They
+ ;; are buffer-local, but we avoid changing them so that they can be set
+ ;; to make `forward-paragraph' and friends do something the user wants.
+ ;;
+ ;; `paragraph-start': The `(' in the character alternative and the
+ ;; left-singlequote plus `(' sequence after the \\| alternative prevent
+ ;; sexps and backquoted sexps that follow a docstring from being filled
+ ;; with the docstring. This setting has the consequence of inhibiting
+ ;; filling many program lines that are not docstrings, which is sensible,
+ ;; because the user probably asked to fill program lines by accident, or
+ ;; expecting indentation (perhaps we should try to do indenting in that
+ ;; case). The `;' and `:' stop the paragraph being filled at following
+ ;; comment lines and at keywords (e.g., in `defcustom'). Left parens are
+ ;; escaped to keep font-locking, filling, & paren matching in the source
+ ;; file happy.
+ ;;
+ ;; `paragraph-separate': A clever regexp distinguishes the first line of
+ ;; a docstring and identifies it as a paragraph separator, so that it
+ ;; won't be filled. (Since the first line of documentation stands alone
+ ;; in some contexts, filling should not alter the contents the author has
+ ;; chosen.) Only the first line of a docstring begins with whitespace
+ ;; and a quotation mark and ends with a period or (rarely) a comma.
+ ;;
+ ;; The `fill-column' is temporarily bound to
+ ;; `emacs-lisp-docstring-fill-column' if that value is an integer.
+ (let ((paragraph-start (concat paragraph-start
+ "\\|\\s-*\\([\(;:\"]\\|`\(\\)"))
+ (paragraph-separate
+ (concat paragraph-separate "\\|\\s-*\".*[,\\.]$"))
+ (fill-column (if (integerp emacs-lisp-docstring-fill-column)
+ emacs-lisp-docstring-fill-column
+ fill-column)))
+ (fill-paragraph justify))
+ ;; Never return nil.
+ t))
- ;; Figure out what kind of comment we are looking at.
- (save-excursion
- (beginning-of-line)
- (cond
-
- ;; A line with nothing but a comment on it?
- ((looking-at "[ \t]*;[; \t]*")
- (setq has-comment t
- comment-fill-prefix (buffer-substring (match-beginning 0)
- (match-end 0))))
-
- ;; A line with some code, followed by a comment? Remember that the
- ;; semi which starts the comment shouldn't be part of a string or
- ;; character.
- ((condition-case nil
- (save-restriction
- (narrow-to-region (point-min)
- (save-excursion (end-of-line) (point)))
- (while (not (looking-at ";\\|$"))
- (skip-chars-forward "^;\n\"\\\\?")
- (cond
- ((eq (char-after (point)) ?\\) (forward-char 2))
- ((memq (char-after (point)) '(?\" ??)) (forward-sexp 1))))
- (looking-at ";+[\t ]*"))
- (error nil))
- (setq has-comment t has-code-and-comment t)
- (setq comment-fill-prefix
- (concat (make-string (/ (current-column) 8) ?\t)
- (make-string (% (current-column) 8) ?\ )
- (buffer-substring (match-beginning 0) (match-end 0)))))))
-
- (if (not has-comment)
- (fill-paragraph justify)
-
- ;; Narrow to include only the comment, and then fill the region.
- (save-excursion
- (save-restriction
- (beginning-of-line)
- (narrow-to-region
- ;; Find the first line we should include in the region to fill.
- (save-excursion
- (while (and (zerop (forward-line -1))
- (looking-at "^[ \t]*;")))
- ;; We may have gone too far. Go forward again.
- (or (looking-at ".*;")
- (forward-line 1))
- (point))
- ;; Find the beginning of the first line past the region to fill.
- (save-excursion
- (while (progn (forward-line 1)
- (looking-at "^[ \t]*;")))
- (point)))
-
- ;; Lines with only semicolons on them can be paragraph boundaries.
- (let* ((paragraph-start (concat paragraph-start "\\|[ \t;]*$"))
- (paragraph-separate (concat paragraph-start "\\|[ \t;]*$"))
- (paragraph-ignore-fill-prefix nil)
- (fill-prefix comment-fill-prefix)
- (after-line (if has-code-and-comment
- (save-excursion
- (forward-line 1) (point))))
- (end (progn
- (forward-paragraph)
- (or (bolp) (newline 1))
- (point)))
- ;; If this comment starts on a line with code,
- ;; include that like in the filling.
- (beg (progn (backward-paragraph)
- (if (eq (point) after-line)
- (forward-line -1))
- (point))))
- (fill-region-as-paragraph beg end
- justify nil
- (save-excursion
- (goto-char beg)
- (if (looking-at fill-prefix)
- nil
- (re-search-forward comment-start-skip)
- (point))))))))
- t))
-\f
(defun indent-code-rigidly (start end arg &optional nochange-regexp)
"Indent all lines of code, starting in the region, sideways by ARG columns.
Does not affect lines starting inside comments or strings, assuming that
(provide 'lisp-mode)
+;;; arch-tag: 414c7f93-c245-4b77-8ed5-ed05ef7ff1bf
;;; lisp-mode.el ends here