summaryrefslogtreecommitdiff
path: root/lisp/emacs-lisp/lisp-mode.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/emacs-lisp/lisp-mode.el')
-rw-r--r--lisp/emacs-lisp/lisp-mode.el607
1 files changed, 324 insertions, 283 deletions
diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el
index cbf2e0ccb71..fc1cfe7afd1 100644
--- a/lisp/emacs-lisp/lisp-mode.el
+++ b/lisp/emacs-lisp/lisp-mode.el
@@ -1,10 +1,10 @@
;;; lisp-mode.el --- Lisp mode, and its idiosyncratic commands
-;; Copyright (C) 1985, 1986, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-;; 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+;; Copyright (C) 1985-1986, 1999-2013 Free Software Foundation, Inc.
;; Maintainer: FSF
;; Keywords: lisp, languages
+;; Package: emacs
;; This file is part of GNU Emacs.
@@ -34,50 +34,56 @@
(defvar font-lock-string-face)
(defvar lisp-mode-abbrev-table nil)
+(define-abbrev-table 'lisp-mode-abbrev-table ()
+ "Abbrev table for Lisp mode.")
-(define-abbrev-table 'lisp-mode-abbrev-table ())
+(defvar emacs-lisp-mode-abbrev-table nil)
+(define-abbrev-table 'emacs-lisp-mode-abbrev-table ()
+ "Abbrev table for Emacs Lisp mode.
+It has `lisp-mode-abbrev-table' as its parent."
+ :parents (list lisp-mode-abbrev-table))
(defvar emacs-lisp-mode-syntax-table
- (let ((table (make-syntax-table)))
- (let ((i 0))
- (while (< i ?0)
- (modify-syntax-entry i "_ " table)
- (setq i (1+ i)))
- (setq i (1+ ?9))
- (while (< i ?A)
- (modify-syntax-entry i "_ " table)
- (setq i (1+ i)))
- (setq i (1+ ?Z))
- (while (< i ?a)
- (modify-syntax-entry i "_ " table)
- (setq i (1+ i)))
- (setq i (1+ ?z))
- (while (< i 128)
- (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)
- ;; 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)
- (modify-syntax-entry ?, "' " table)
- (modify-syntax-entry ?@ "' " table)
- ;; Used to be singlequote; changed for flonums.
- (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))
+ (let ((table (make-syntax-table))
+ (i 0))
+ (while (< i ?0)
+ (modify-syntax-entry i "_ " table)
+ (setq i (1+ i)))
+ (setq i (1+ ?9))
+ (while (< i ?A)
+ (modify-syntax-entry i "_ " table)
+ (setq i (1+ i)))
+ (setq i (1+ ?Z))
+ (while (< i ?a)
+ (modify-syntax-entry i "_ " table)
+ (setq i (1+ i)))
+ (setq i (1+ ?z))
+ (while (< i 128)
+ (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)
+ ;; 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)
+ (modify-syntax-entry ?, "' " table)
+ (modify-syntax-entry ?@ "' " table)
+ ;; Used to be singlequote; changed for flonums.
+ (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)
"Syntax table used in `emacs-lisp-mode'.")
@@ -85,7 +91,7 @@
(let ((table (copy-syntax-table emacs-lisp-mode-syntax-table)))
(modify-syntax-entry ?\[ "_ " table)
(modify-syntax-entry ?\] "_ " table)
- (modify-syntax-entry ?# "' 14b" table)
+ (modify-syntax-entry ?# "' 14" table)
(modify-syntax-entry ?| "\" 23bn" table)
table)
"Syntax table used in `lisp-mode'.")
@@ -111,10 +117,15 @@
(purecopy (concat "^\\s-*("
(eval-when-compile
(regexp-opt
- '("defvar" "defconst" "defconstant" "defcustom"
+ '("defconst" "defconstant" "defcustom"
"defparameter" "define-symbol-macro") t))
"\\s-+\\(\\(\\sw\\|\\s_\\)+\\)"))
2)
+ ;; For `defvar', we ignore (defvar FOO) constructs.
+ (list (purecopy "Variables")
+ (purecopy (concat "^\\s-*(defvar\\s-+\\(\\(\\sw\\|\\s_\\)+\\)"
+ "[[:space:]\n]+[^)]"))
+ 1)
(list (purecopy "Types")
(purecopy (concat "^\\s-*("
(eval-when-compile
@@ -129,34 +140,12 @@
;; 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 'defmethod 'doc-string-elt 3)
(put 'defvar 'doc-string-elt 3)
-(put 'defcustom 'doc-string-elt 3)
-(put 'deftheme 'doc-string-elt 2)
-(put 'deftype 'doc-string-elt 3)
(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 'defstruct 'doc-string-elt 2)
-(put 'define-skeleton 'doc-string-elt 2)
-(put 'define-derived-mode 'doc-string-elt 4)
-(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)
-(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)
-(put 'define-overloadable-function 'doc-string-elt 3)
(defvar lisp-doc-string-elt-property 'doc-string-elt
"The symbol property that holds the docstring position info.")
@@ -174,7 +163,8 @@
(goto-char listbeg)
(and (looking-at "([ \t\n]*\\(\\(\\sw\\|\\s_\\)+\\)")
(match-string 1)))))
- (docelt (and firstsym (get (intern-soft firstsym)
+ (docelt (and firstsym
+ (function-get (intern-soft firstsym)
lisp-doc-string-elt-property))))
(if (and docelt
;; It's a string in a form that can have a docstring.
@@ -205,7 +195,6 @@ score-mode.el. KEYWORDS-CASE-INSENSITIVE non-nil means that for
font-lock keywords will not be case sensitive."
(when lisp-syntax
(set-syntax-table lisp-mode-syntax-table))
- (setq local-abbrev-table lisp-mode-abbrev-table)
(make-local-variable 'paragraph-ignore-fill-prefix)
(setq paragraph-ignore-fill-prefix t)
(make-local-variable 'fill-paragraph-function)
@@ -221,8 +210,6 @@ font-lock keywords will not be case sensitive."
;;(set (make-local-variable 'adaptive-fill-mode) nil)
(make-local-variable 'indent-line-function)
(setq indent-line-function 'lisp-indent-line)
- (make-local-variable 'parse-sexp-ignore-comments)
- (setq parse-sexp-ignore-comments t)
(make-local-variable 'outline-regexp)
(setq outline-regexp ";;;\\(;* [^ \t\n]\\|###autoload\\)\\|(")
(make-local-variable 'outline-level)
@@ -283,110 +270,111 @@ font-lock keywords will not be case sensitive."
(define-key map "\e\t" 'completion-at-point)
(define-key map "\e\C-x" 'eval-defun)
(define-key map "\e\C-q" 'indent-pp-sexp)
- (define-key map [menu-bar emacs-lisp] (cons (purecopy "Emacs-Lisp") menu-map))
- (define-key menu-map [eldoc]
- `(menu-item ,(purecopy "Auto-Display Documentation Strings") eldoc-mode
+ (bindings--define-key map [menu-bar emacs-lisp]
+ (cons "Emacs-Lisp" menu-map))
+ (bindings--define-key menu-map [eldoc]
+ '(menu-item "Auto-Display Documentation Strings" eldoc-mode
:button (:toggle . (bound-and-true-p eldoc-mode))
- :help ,(purecopy "Display the documentation string for the item under cursor")))
- (define-key menu-map [checkdoc]
- `(menu-item ,(purecopy "Check Documentation Strings") checkdoc
- :help ,(purecopy "Check documentation strings for style requirements")))
- (define-key menu-map [re-builder]
- `(menu-item ,(purecopy "Construct Regexp") re-builder
- :help ,(purecopy "Construct a regexp interactively")))
- (define-key menu-map [tracing] (cons (purecopy "Tracing") tracing-map))
- (define-key tracing-map [tr-a]
- `(menu-item ,(purecopy "Untrace All") untrace-all
- :help ,(purecopy "Untrace all currently traced functions")))
- (define-key tracing-map [tr-uf]
- `(menu-item ,(purecopy "Untrace function...") untrace-function
- :help ,(purecopy "Untrace function, and possibly activate all remaining advice")))
- (define-key tracing-map [tr-sep] menu-bar-separator)
- (define-key tracing-map [tr-q]
- `(menu-item ,(purecopy "Trace Function Quietly...") trace-function-background
- :help ,(purecopy "Trace the function with trace output going quietly to a buffer")))
- (define-key tracing-map [tr-f]
- `(menu-item ,(purecopy "Trace Function...") trace-function
- :help ,(purecopy "Trace the function given as an argument")))
- (define-key menu-map [profiling] (cons (purecopy "Profiling") prof-map))
- (define-key prof-map [prof-restall]
- `(menu-item ,(purecopy "Remove Instrumentation for All Functions") elp-restore-all
- :help ,(purecopy "Restore the original definitions of all functions being profiled")))
- (define-key prof-map [prof-restfunc]
- `(menu-item ,(purecopy "Remove Instrumentation for Function...") elp-restore-function
- :help ,(purecopy "Restore an instrumented function to its original definition")))
-
- (define-key prof-map [sep-rem] menu-bar-separator)
- (define-key prof-map [prof-resall]
- `(menu-item ,(purecopy "Reset Counters for All Functions") elp-reset-all
- :help ,(purecopy "Reset the profiling information for all functions being profiled")))
- (define-key prof-map [prof-resfunc]
- `(menu-item ,(purecopy "Reset Counters for Function...") elp-reset-function
- :help ,(purecopy "Reset the profiling information for a function")))
- (define-key prof-map [prof-res]
- `(menu-item ,(purecopy "Show Profiling Results") elp-results
- :help ,(purecopy "Display current profiling results")))
- (define-key prof-map [prof-pack]
- `(menu-item ,(purecopy "Instrument Package...") elp-instrument-package
- :help ,(purecopy "Instrument for profiling all function that start with a prefix")))
- (define-key prof-map [prof-func]
- `(menu-item ,(purecopy "Instrument Function...") elp-instrument-function
- :help ,(purecopy "Instrument a function for profiling")))
- (define-key menu-map [lint] (cons (purecopy "Linting") lint-map))
- (define-key lint-map [lint-di]
- `(menu-item ,(purecopy "Lint Directory...") elint-directory
- :help ,(purecopy "Lint a directory")))
- (define-key lint-map [lint-f]
- `(menu-item ,(purecopy "Lint File...") elint-file
- :help ,(purecopy "Lint a file")))
- (define-key lint-map [lint-b]
- `(menu-item ,(purecopy "Lint Buffer") elint-current-buffer
- :help ,(purecopy "Lint the current buffer")))
- (define-key lint-map [lint-d]
- `(menu-item ,(purecopy "Lint Defun") elint-defun
- :help ,(purecopy "Lint the function at point")))
- (define-key menu-map [edebug-defun]
- `(menu-item ,(purecopy "Instrument Function for Debugging") edebug-defun
- :help ,(purecopy "Evaluate the top level form point is in, stepping through with Edebug")
- :keys ,(purecopy "C-u C-M-x")))
- (define-key menu-map [separator-byte] menu-bar-separator)
- (define-key menu-map [disas]
- `(menu-item ,(purecopy "Disassemble Byte Compiled Object...") disassemble
- :help ,(purecopy "Print disassembled code for OBJECT in a buffer")))
- (define-key menu-map [byte-recompile]
- `(menu-item ,(purecopy "Byte-recompile Directory...") byte-recompile-directory
- :help ,(purecopy "Recompile every `.el' file in DIRECTORY that needs recompilation")))
- (define-key menu-map [emacs-byte-compile-and-load]
- `(menu-item ,(purecopy "Byte-compile and Load") emacs-lisp-byte-compile-and-load
- :help ,(purecopy "Byte-compile the current file (if it has changed), then load compiled code")))
- (define-key menu-map [byte-compile]
- `(menu-item ,(purecopy "Byte-compile this File") emacs-lisp-byte-compile
- :help ,(purecopy "Byte compile the file containing the current buffer")))
- (define-key menu-map [separator-eval] menu-bar-separator)
- (define-key menu-map [ielm]
- `(menu-item ,(purecopy "Interactive Expression Evaluation") ielm
- :help ,(purecopy "Interactively evaluate Emacs Lisp expressions")))
- (define-key menu-map [eval-buffer]
- `(menu-item ,(purecopy "Evaluate Buffer") eval-buffer
- :help ,(purecopy "Execute the current buffer as Lisp code")))
- (define-key menu-map [eval-region]
- `(menu-item ,(purecopy "Evaluate Region") eval-region
- :help ,(purecopy "Execute the region as Lisp code")
+ :help "Display the documentation string for the item under cursor"))
+ (bindings--define-key menu-map [checkdoc]
+ '(menu-item "Check Documentation Strings" checkdoc
+ :help "Check documentation strings for style requirements"))
+ (bindings--define-key menu-map [re-builder]
+ '(menu-item "Construct Regexp" re-builder
+ :help "Construct a regexp interactively"))
+ (bindings--define-key menu-map [tracing] (cons "Tracing" tracing-map))
+ (bindings--define-key tracing-map [tr-a]
+ '(menu-item "Untrace All" untrace-all
+ :help "Untrace all currently traced functions"))
+ (bindings--define-key tracing-map [tr-uf]
+ '(menu-item "Untrace Function..." untrace-function
+ :help "Untrace function, and possibly activate all remaining advice"))
+ (bindings--define-key tracing-map [tr-sep] menu-bar-separator)
+ (bindings--define-key tracing-map [tr-q]
+ '(menu-item "Trace Function Quietly..." trace-function-background
+ :help "Trace the function with trace output going quietly to a buffer"))
+ (bindings--define-key tracing-map [tr-f]
+ '(menu-item "Trace Function..." trace-function
+ :help "Trace the function given as an argument"))
+ (bindings--define-key menu-map [profiling] (cons "Profiling" prof-map))
+ (bindings--define-key prof-map [prof-restall]
+ '(menu-item "Remove Instrumentation for All Functions" elp-restore-all
+ :help "Restore the original definitions of all functions being profiled"))
+ (bindings--define-key prof-map [prof-restfunc]
+ '(menu-item "Remove Instrumentation for Function..." elp-restore-function
+ :help "Restore an instrumented function to its original definition"))
+
+ (bindings--define-key prof-map [sep-rem] menu-bar-separator)
+ (bindings--define-key prof-map [prof-resall]
+ '(menu-item "Reset Counters for All Functions" elp-reset-all
+ :help "Reset the profiling information for all functions being profiled"))
+ (bindings--define-key prof-map [prof-resfunc]
+ '(menu-item "Reset Counters for Function..." elp-reset-function
+ :help "Reset the profiling information for a function"))
+ (bindings--define-key prof-map [prof-res]
+ '(menu-item "Show Profiling Results" elp-results
+ :help "Display current profiling results"))
+ (bindings--define-key prof-map [prof-pack]
+ '(menu-item "Instrument Package..." elp-instrument-package
+ :help "Instrument for profiling all function that start with a prefix"))
+ (bindings--define-key prof-map [prof-func]
+ '(menu-item "Instrument Function..." elp-instrument-function
+ :help "Instrument a function for profiling"))
+ (bindings--define-key menu-map [lint] (cons "Linting" lint-map))
+ (bindings--define-key lint-map [lint-di]
+ '(menu-item "Lint Directory..." elint-directory
+ :help "Lint a directory"))
+ (bindings--define-key lint-map [lint-f]
+ '(menu-item "Lint File..." elint-file
+ :help "Lint a file"))
+ (bindings--define-key lint-map [lint-b]
+ '(menu-item "Lint Buffer" elint-current-buffer
+ :help "Lint the current buffer"))
+ (bindings--define-key lint-map [lint-d]
+ '(menu-item "Lint Defun" elint-defun
+ :help "Lint the function at point"))
+ (bindings--define-key menu-map [edebug-defun]
+ '(menu-item "Instrument Function for Debugging" edebug-defun
+ :help "Evaluate the top level form point is in, stepping through with Edebug"
+ :keys "C-u C-M-x"))
+ (bindings--define-key menu-map [separator-byte] menu-bar-separator)
+ (bindings--define-key menu-map [disas]
+ '(menu-item "Disassemble Byte Compiled Object..." disassemble
+ :help "Print disassembled code for OBJECT in a buffer"))
+ (bindings--define-key menu-map [byte-recompile]
+ '(menu-item "Byte-recompile Directory..." byte-recompile-directory
+ :help "Recompile every `.el' file in DIRECTORY that needs recompilation"))
+ (bindings--define-key menu-map [emacs-byte-compile-and-load]
+ '(menu-item "Byte-compile and Load" emacs-lisp-byte-compile-and-load
+ :help "Byte-compile the current file (if it has changed), then load compiled code"))
+ (bindings--define-key menu-map [byte-compile]
+ '(menu-item "Byte-compile This File" emacs-lisp-byte-compile
+ :help "Byte compile the file containing the current buffer"))
+ (bindings--define-key menu-map [separator-eval] menu-bar-separator)
+ (bindings--define-key menu-map [ielm]
+ '(menu-item "Interactive Expression Evaluation" ielm
+ :help "Interactively evaluate Emacs Lisp expressions"))
+ (bindings--define-key menu-map [eval-buffer]
+ '(menu-item "Evaluate Buffer" eval-buffer
+ :help "Execute the current buffer as Lisp code"))
+ (bindings--define-key menu-map [eval-region]
+ '(menu-item "Evaluate Region" eval-region
+ :help "Execute the region as Lisp code"
:enable mark-active))
- (define-key menu-map [eval-sexp]
- `(menu-item ,(purecopy "Evaluate Last S-expression") eval-last-sexp
- :help ,(purecopy "Evaluate sexp before point; print value in minibuffer")))
- (define-key menu-map [separator-format] menu-bar-separator)
- (define-key menu-map [comment-region]
- `(menu-item ,(purecopy "Comment Out Region") comment-region
- :help ,(purecopy "Comment or uncomment each line in the region")
+ (bindings--define-key menu-map [eval-sexp]
+ '(menu-item "Evaluate Last S-expression" eval-last-sexp
+ :help "Evaluate sexp before point; print value in minibuffer"))
+ (bindings--define-key menu-map [separator-format] menu-bar-separator)
+ (bindings--define-key menu-map [comment-region]
+ '(menu-item "Comment Out Region" comment-region
+ :help "Comment or uncomment each line in the region"
:enable mark-active))
- (define-key menu-map [indent-region]
- `(menu-item ,(purecopy "Indent Region") indent-region
- :help ,(purecopy "Indent each nonblank line in the region")
+ (bindings--define-key menu-map [indent-region]
+ '(menu-item "Indent Region" indent-region
+ :help "Indent each nonblank line in the region"
:enable mark-active))
- (define-key menu-map [indent-line]
- `(menu-item ,(purecopy "Indent Line") lisp-indent-line))
+ (bindings--define-key menu-map [indent-line]
+ '(menu-item "Indent Line" lisp-indent-line))
map)
"Keymap for Emacs Lisp mode.
All commands in `lisp-mode-shared-map' are inherited by this map.")
@@ -408,10 +396,7 @@ All commands in `lisp-mode-shared-map' are inherited by this map.")
(if (and (buffer-modified-p)
(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))))
+ (byte-recompile-file buffer-file-name nil 0 t))
(defcustom emacs-lisp-mode-hook nil
"Hook run when entering Emacs Lisp mode."
@@ -431,7 +416,7 @@ All commands in `lisp-mode-shared-map' are inherited by this map.")
:type 'hook
:group 'lisp)
-(define-derived-mode emacs-lisp-mode nil "Emacs-Lisp"
+(define-derived-mode emacs-lisp-mode prog-mode "Emacs-Lisp"
"Major mode for editing Lisp code to run in Emacs.
Commands:
Delete converts tabs to spaces as it moves back.
@@ -446,27 +431,82 @@ if that value is non-nil."
(add-hook 'completion-at-point-functions
'lisp-completion-at-point nil 'local))
+;;; Emacs Lisp Byte-Code mode
+
+(eval-and-compile
+ (defconst emacs-list-byte-code-comment-re
+ (concat "\\(#\\)@\\([0-9]+\\) "
+ ;; Make sure it's a docstring and not a lazy-loaded byte-code.
+ "\\(?:[^(]\\|([^\"]\\)")))
+
+(defun emacs-lisp-byte-code-comment (end &optional _point)
+ "Try to syntactically mark the #@NNN ....^_ docstrings in byte-code files."
+ (let ((ppss (syntax-ppss)))
+ (when (and (nth 4 ppss)
+ (eq (char-after (nth 8 ppss)) ?#))
+ (let* ((n (save-excursion
+ (goto-char (nth 8 ppss))
+ (when (looking-at emacs-list-byte-code-comment-re)
+ (string-to-number (match-string 2)))))
+ ;; `maxdiff' tries to make sure the loop below terminates.
+ (maxdiff n))
+ (when n
+ (let* ((bchar (match-end 2))
+ (b (position-bytes bchar)))
+ (goto-char (+ b n))
+ (while (let ((diff (- (position-bytes (point)) b n)))
+ (unless (zerop diff)
+ (when (> diff maxdiff) (setq diff maxdiff))
+ (forward-char (- diff))
+ (setq maxdiff (if (> diff 0) diff
+ (max (1- maxdiff) 1)))
+ t))))
+ (if (<= (point) end)
+ (put-text-property (1- (point)) (point)
+ 'syntax-table
+ (string-to-syntax "> b"))
+ (goto-char end)))))))
+
+(defun emacs-lisp-byte-code-syntax-propertize (start end)
+ (emacs-lisp-byte-code-comment end (point))
+ (funcall
+ (syntax-propertize-rules
+ (emacs-list-byte-code-comment-re
+ (1 (prog1 "< b" (emacs-lisp-byte-code-comment end (point))))))
+ start end))
+
+(add-to-list 'auto-mode-alist '("\\.elc\\'" . emacs-lisp-byte-code-mode))
+(define-derived-mode emacs-lisp-byte-code-mode emacs-lisp-mode
+ "Elisp-Byte-Code"
+ "Major mode for *.elc files."
+ ;; TODO: Add way to disassemble byte-code under point.
+ (setq-local open-paren-in-column-0-is-defun-start nil)
+ (setq-local syntax-propertize-function
+ #'emacs-lisp-byte-code-syntax-propertize))
+
+;;; Generic Lisp mode.
+
(defvar lisp-mode-map
(let ((map (make-sparse-keymap))
(menu-map (make-sparse-keymap "Lisp")))
(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)
- (define-key map [menu-bar lisp] (cons (purecopy "Lisp") menu-map))
- (define-key menu-map [run-lisp]
- `(menu-item ,(purecopy "Run inferior Lisp") run-lisp
- :help ,(purecopy "Run an inferior Lisp process, input and output via buffer `*inferior-lisp*'")))
- (define-key menu-map [ev-def]
- `(menu-item ,(purecopy "Eval defun") lisp-eval-defun
- :help ,(purecopy "Send the current defun to the Lisp process made by M-x run-lisp")))
- (define-key menu-map [ind-sexp]
- `(menu-item ,(purecopy "Indent sexp") indent-sexp
- :help ,(purecopy "Indent each line of the list starting just after point")))
+ (bindings--define-key map [menu-bar lisp] (cons "Lisp" menu-map))
+ (bindings--define-key menu-map [run-lisp]
+ '(menu-item "Run inferior Lisp" run-lisp
+ :help "Run an inferior Lisp process, input and output via buffer `*inferior-lisp*'"))
+ (bindings--define-key menu-map [ev-def]
+ '(menu-item "Eval defun" lisp-eval-defun
+ :help "Send the current defun to the Lisp process made by M-x run-lisp"))
+ (bindings--define-key menu-map [ind-sexp]
+ '(menu-item "Indent sexp" indent-sexp
+ :help "Indent each line of the list starting just after point"))
map)
"Keymap for ordinary Lisp mode.
All commands in `lisp-mode-shared-map' are inherited by this map.")
-(defun lisp-mode ()
+(define-derived-mode lisp-mode prog-mode "Lisp"
"Major mode for editing Lisp code for Lisps other than GNU Emacs Lisp.
Commands:
Delete converts tabs to spaces as it moves back.
@@ -478,19 +518,12 @@ or to switch back to an existing one.
Entry to this mode calls the value of `lisp-mode-hook'
if that value is non-nil."
- (interactive)
- (kill-all-local-variables)
- (use-local-map lisp-mode-map)
- (setq major-mode 'lisp-mode)
- (setq mode-name "Lisp")
(lisp-mode-variables nil t)
+ (set (make-local-variable 'find-tag-default-function) 'lisp-find-tag-default)
(make-local-variable 'comment-start-skip)
(setq comment-start-skip
"\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\)\\(;+\\|#|\\) *")
- (setq imenu-case-fold-search t)
- (set-syntax-table lisp-mode-syntax-table)
- (run-mode-hooks 'lisp-mode-hook))
-(put 'lisp-mode 'find-tag-default-function 'lisp-find-tag-default)
+ (setq imenu-case-fold-search t))
(defun lisp-find-tag-default ()
(let ((default (find-tag-default)))
@@ -516,28 +549,28 @@ if that value is non-nil."
(define-key map "\e\C-q" 'indent-pp-sexp)
(define-key map "\e\t" 'completion-at-point)
(define-key map "\n" 'eval-print-last-sexp)
- (define-key map [menu-bar lisp-interaction] (cons (purecopy "Lisp-Interaction") menu-map))
- (define-key menu-map [eval-defun]
- `(menu-item ,(purecopy "Evaluate Defun") eval-defun
- :help ,(purecopy "Evaluate the top-level form containing point, or after point")))
- (define-key menu-map [eval-print-last-sexp]
- `(menu-item ,(purecopy "Evaluate and print") eval-print-last-sexp
- :help ,(purecopy "Evaluate sexp before point; print value into current buffer")))
- (define-key menu-map [edebug-defun-lisp-interaction]
- `(menu-item ,(purecopy "Instrument Function for Debugging") edebug-defun
- :help ,(purecopy "Evaluate the top level form point is in, stepping through with Edebug")
- :keys ,(purecopy "C-u C-M-x")))
- (define-key menu-map [indent-pp-sexp]
- `(menu-item ,(purecopy "Indent or Pretty-Print") indent-pp-sexp
- :help ,(purecopy "Indent each line of the list starting just after point, or prettyprint it")))
- (define-key menu-map [complete-symbol]
- `(menu-item ,(purecopy "Complete Lisp Symbol") completion-at-point
- :help ,(purecopy "Perform completion on Lisp symbol preceding point")))
+ (bindings--define-key map [menu-bar lisp-interaction]
+ (cons "Lisp-Interaction" menu-map))
+ (bindings--define-key menu-map [eval-defun]
+ '(menu-item "Evaluate Defun" eval-defun
+ :help "Evaluate the top-level form containing point, or after point"))
+ (bindings--define-key menu-map [eval-print-last-sexp]
+ '(menu-item "Evaluate and Print" eval-print-last-sexp
+ :help "Evaluate sexp before point; print value into current buffer"))
+ (bindings--define-key menu-map [edebug-defun-lisp-interaction]
+ '(menu-item "Instrument Function for Debugging" edebug-defun
+ :help "Evaluate the top level form point is in, stepping through with Edebug"
+ :keys "C-u C-M-x"))
+ (bindings--define-key menu-map [indent-pp-sexp]
+ '(menu-item "Indent or Pretty-Print" indent-pp-sexp
+ :help "Indent each line of the list starting just after point, or prettyprint it"))
+ (bindings--define-key menu-map [complete-symbol]
+ '(menu-item "Complete Lisp Symbol" completion-at-point
+ :help "Perform completion on Lisp symbol preceding point"))
map)
"Keymap for Lisp Interaction mode.
All commands in `lisp-mode-shared-map' are inherited by this map.")
-(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
@@ -552,7 +585,8 @@ 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.")
+if that value is non-nil."
+ :abbrev-table nil)
(defun eval-print-last-sexp ()
"Evaluate sexp before point; print value into current buffer.
@@ -711,7 +745,9 @@ If CHAR is not a character, return nil."
"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)))
- (eval-last-sexp-print-value (eval (preceding-sexp)))))
+ ;; Setup the lexical environment if lexical-binding is enabled.
+ (eval-last-sexp-print-value
+ (eval (eval-sexp-add-defvars (preceding-sexp)) lexical-binding))))
(defun eval-last-sexp-print-value (value)
@@ -739,6 +775,25 @@ With argument, print output into current buffer."
(defvar eval-last-sexp-fake-value (make-symbol "t"))
+(defun eval-sexp-add-defvars (exp &optional pos)
+ "Prepend EXP with all the `defvar's that precede it in the buffer.
+POS specifies the starting position where EXP was found and defaults to point."
+ (if (not lexical-binding)
+ exp
+ (save-excursion
+ (unless pos (setq pos (point)))
+ (let ((vars ()))
+ (goto-char (point-min))
+ (while (re-search-forward
+ "(def\\(?:var\\|const\\|custom\\)[ \t\n]+\\([^; '()\n\t]+\\)"
+ pos t)
+ (let ((var (intern (match-string 1))))
+ (and (not (special-variable-p var))
+ (save-excursion
+ (zerop (car (syntax-ppss (match-beginning 0)))))
+ (push var vars))))
+ `(progn ,@(mapcar (lambda (v) `(defvar ,v)) vars) ,exp)))))
+
(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.
@@ -763,7 +818,7 @@ this command arranges for all errors to enter the debugger."
Reset the `defvar' and `defcustom' variables to the initial value.
Reinitialize the face according to the `defface' specification."
;; The code in edebug-defun should be consistent with this, but not
- ;; the same, since this gets a macroexpended form.
+ ;; the same, since this gets a macroexpanded form.
(cond ((not (listp form))
form)
((and (eq (car form) 'defvar)
@@ -775,30 +830,38 @@ Reinitialize the face according to the `defface' specification."
;; `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))))
+ (default-boundp (eval (nth 1 form) lexical-binding)))
;; Force variable to be bound.
- (set-default (eval (nth 1 form)) (eval (nth 1 (nth 2 form))))
+ (set-default (eval (nth 1 form) lexical-binding)
+ ;; The second arg is an expression that evaluates to
+ ;; an expression. The second evaluation is the one
+ ;; normally performed not be normal execution but by
+ ;; custom-initialize-set (for example), which does not
+ ;; use lexical-binding.
+ (eval (eval (nth 2 form) lexical-binding)))
form)
;; `defface' is macroexpanded to `custom-declare-face'.
((eq (car form) 'custom-declare-face)
;; Reset the face.
- (setq face-new-frame-defaults
- (assq-delete-all (eval (nth 1 form)) face-new-frame-defaults))
- (put (eval (nth 1 form)) 'face-defface-spec nil)
- ;; Setting `customized-face' to the new spec after calling
- ;; the form, but preserving the old saved spec in `saved-face',
- ;; imitates the situation when the new face spec is set
- ;; temporarily for the current session in the customize
- ;; buffer, thus allowing `face-user-default-spec' to use the
- ;; new customized spec instead of the saved spec.
- ;; Resetting `saved-face' temporarily to nil is needed to let
- ;; `defface' change the spec, regardless of a saved spec.
- (prog1 `(prog1 ,form
- (put ,(nth 1 form) 'saved-face
- ',(get (eval (nth 1 form)) 'saved-face))
- (put ,(nth 1 form) 'customized-face
- ,(nth 2 form)))
- (put (eval (nth 1 form)) 'saved-face nil)))
+ (let ((face-symbol (eval (nth 1 form) lexical-binding)))
+ (setq face-new-frame-defaults
+ (assq-delete-all face-symbol face-new-frame-defaults))
+ (put face-symbol 'face-defface-spec nil)
+ (put face-symbol 'face-documentation (nth 3 form))
+ ;; Setting `customized-face' to the new spec after calling
+ ;; the form, but preserving the old saved spec in `saved-face',
+ ;; imitates the situation when the new face spec is set
+ ;; temporarily for the current session in the customize
+ ;; buffer, thus allowing `face-user-default-spec' to use the
+ ;; new customized spec instead of the saved spec.
+ ;; Resetting `saved-face' temporarily to nil is needed to let
+ ;; `defface' change the spec, regardless of a saved spec.
+ (prog1 `(prog1 ,form
+ (put ,(nth 1 form) 'saved-face
+ ',(get face-symbol 'saved-face))
+ (put ,(nth 1 form) 'customized-face
+ ,(nth 2 form)))
+ (put face-symbol 'saved-face nil))))
((eq (car form) 'progn)
(cons 'progn (mapcar 'eval-defun-1 (cdr form))))
(t form)))
@@ -814,7 +877,6 @@ if it already has a value.\)
With argument, insert value in current buffer after the defun.
Return the result of evaluation."
- (interactive "P")
;; FIXME: the print-length/level bindings should only be applied while
;; printing, not while evaluating.
(let ((debug-on-error eval-expression-debug-on-error)
@@ -837,7 +899,7 @@ Return the result of evaluation."
(setq form (read (current-buffer)))
(setq end (point)))
;; Alter the form if necessary.
- (setq form (eval-defun-1 (macroexpand form)))
+ (setq form (eval-sexp-add-defvars (eval-defun-1 (macroexpand form))))
(list beg end standard-output
`(lambda (ignore)
;; Skipping to the end of the specified region
@@ -919,6 +981,7 @@ rigidly along with this one."
(if (or (null indent) (looking-at "\\s<\\s<\\s<"))
;; Don't alter indentation of a ;;; comment line
;; or a line that starts in a string.
+ ;; FIXME: inconsistency: comment-indent moves ;;; to column 0.
(goto-char (- (point-max) pos))
(if (and (looking-at "\\s<") (not (looking-at "\\s<\\s<")))
;; Single-semicolon comment lines should be indented
@@ -933,18 +996,7 @@ rigidly along with this one."
;; If initial point was within line's indentation,
;; position after the indentation. Else stay at same point in text.
(if (> (- (point-max) pos) (point))
- (goto-char (- (point-max) pos)))
- ;; If desired, shift remaining lines of expression the same amount.
- (and whole-exp (not (zerop shift-amt))
- (save-excursion
- (goto-char beg)
- (forward-sexp 1)
- (setq end (point))
- (goto-char beg)
- (forward-line 1)
- (setq beg (point))
- (> end beg))
- (indent-code-rigidly beg end shift-amt)))))
+ (goto-char (- (point-max) pos))))))
(defvar calculate-lisp-indent-last-sexp)
@@ -1078,7 +1130,7 @@ is the buffer position of the start of the containing expression."
(goto-char calculate-lisp-indent-last-sexp)
(or (and (looking-at ":")
(setq indent (current-column)))
- (and (< (save-excursion (beginning-of-line) (point))
+ (and (< (line-beginning-position)
(prog2 (backward-sexp) (point)))
(looking-at ":")
(setq indent (current-column))))
@@ -1093,25 +1145,31 @@ is the buffer position of the start of the containing expression."
(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.
+The function `calculate-lisp-indent' calls this to determine
+if the arguments of a Lisp function call should be indented specially.
-INDENT-POINT is the position where the user typed TAB, or equivalent.
+INDENT-POINT is the position at which the line being indented begins.
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;
+If the current line is in a call to a Lisp function that has a non-nil
+property `lisp-indent-function' (or the deprecated `lisp-indent-hook'),
+it specifies how to indent. The property value can be:
+
+* `defun', meaning indent `defun'-style
+ \(this is also the case if there is no property and the function
+ has a name that begins with \"def\", and three or more arguments);
+
* an integer N, meaning indent the first N arguments specially
- like ordinary function arguments and then indent any further
+ (like ordinary function arguments), and then indent any further
arguments 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."
+* a function to call that returns the indentation (or nil).
+ `lisp-indent-function' calls this function with the same two arguments
+ that it itself received.
+
+This function returns either the indentation to use, or nil if the
+Lisp function does not specify a special indentation."
(let ((normal-indent (current-column)))
(goto-char (1+ (elt state 1)))
(parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t)
@@ -1134,7 +1192,8 @@ This function also returns nil meaning don't specify the indentation."
(let ((function (buffer-substring (point)
(progn (forward-sexp 1) (point))))
method)
- (setq method (or (get (intern-soft function) 'lisp-indent-function)
+ (setq method (or (function-get (intern-soft function)
+ 'lisp-indent-function)
(get (intern-soft function) 'lisp-indent-hook)))
(cond ((or (eq method 'defun)
(and (null method)
@@ -1211,38 +1270,21 @@ This function also returns nil meaning don't specify the indentation."
;; 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 'lambda 'lisp-indent-function 'defun)
(put 'autoload 'lisp-indent-function 'defun)
(put 'progn 'lisp-indent-function 0)
(put 'prog1 'lisp-indent-function 1)
(put 'prog2 'lisp-indent-function 2)
(put 'save-excursion 'lisp-indent-function 0)
-(put 'save-window-excursion 'lisp-indent-function 0)
-(put 'save-selected-window 'lisp-indent-function 0)
(put 'save-restriction 'lisp-indent-function 0)
-(put 'save-match-data 'lisp-indent-function 0)
(put 'save-current-buffer 'lisp-indent-function 0)
-(put 'with-current-buffer 'lisp-indent-function 1)
-(put 'combine-after-change-calls 'lisp-indent-function 0)
-(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.
@@ -1454,5 +1496,4 @@ means don't indent that line."
(provide 'lisp-mode)
-;; arch-tag: 414c7f93-c245-4b77-8ed5-ed05ef7ff1bf
;;; lisp-mode.el ends here