X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/6aaa489dc112f51f6045f79b37cb78dd513e398f..8833692b29ba11c34413d6793cf6d222ccdd930b:/lisp/emacs-lisp/lisp-mode.el diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el index 6facf57605..74aebc0a66 100644 --- a/lisp/emacs-lisp/lisp-mode.el +++ b/lisp/emacs-lisp/lisp-mode.el @@ -1,6 +1,6 @@ ;;; lisp-mode.el --- Lisp mode, and its idiosyncratic commands -*- lexical-binding:t -*- -;; Copyright (C) 1985-1986, 1999-2015 Free Software Foundation, Inc. +;; Copyright (C) 1985-1986, 1999-2016 Free Software Foundation, Inc. ;; Maintainer: emacs-devel@gnu.org ;; Keywords: lisp, languages @@ -28,6 +28,8 @@ ;;; Code: +(eval-when-compile (require 'cl-lib)) + (defvar font-lock-comment-face) (defvar font-lock-doc-face) (defvar font-lock-keywords-case-fold-search) @@ -87,6 +89,9 @@ table) "Syntax table used in `lisp-mode'.") +(eval-and-compile + (defconst lisp-mode-symbol-regexp "\\(?:\\sw\\|\\s_\\|\\\\.\\)+")) + (defvar lisp-imenu-generic-expression (list (list nil @@ -95,14 +100,16 @@ (regexp-opt '("defun" "defmacro" ;; Elisp. - "defun*" "defsubst" + "defun*" "defsubst" "define-inline" "define-advice" "defadvice" "define-skeleton" "define-compilation-mode" "define-minor-mode" "define-global-minor-mode" "define-globalized-minor-mode" "define-derived-mode" "define-generic-mode" + "ert-deftest" "cl-defun" "cl-defsubst" "cl-defmacro" - "cl-define-compiler-macro" + "cl-define-compiler-macro" "cl-defgeneric" + "cl-defmethod" ;; CL. "define-compiler-macro" "define-modify-macro" "defsetf" "define-setf-expander" @@ -110,7 +117,7 @@ ;; CLOS and EIEIO "defgeneric" "defmethod") t)) - "\\s-+\\(\\(\\sw\\|\\s_\\)+\\)")) + "\\s-+\\(" lisp-mode-symbol-regexp "\\)")) 2) (list (purecopy "Variables") (purecopy (concat "^\\s-*(" @@ -122,11 +129,12 @@ "defconstant" "defparameter" "define-symbol-macro") t)) - "\\s-+\\(\\(\\sw\\|\\s_\\)+\\)")) + "\\s-+\\(" lisp-mode-symbol-regexp "\\)")) 2) - ;; For `defvar', we ignore (defvar FOO) constructs. + ;; For `defvar'/`defvar-local', we ignore (defvar FOO) constructs. (list (purecopy "Variables") - (purecopy (concat "^\\s-*(defvar\\s-+\\(\\(\\sw\\|\\s_\\)+\\)" + (purecopy (concat "^\\s-*(defvar\\(?:-local\\)?\\s-+\\(" + lisp-mode-symbol-regexp "\\)" "[[:space:]\n]+[^)]")) 1) (list (purecopy "Types") @@ -143,7 +151,7 @@ ;; CLOS and EIEIO "defclass") t)) - "\\s-+'?\\(\\(\\sw\\|\\s_\\)+\\)")) + "\\s-+'?\\(" lisp-mode-symbol-regexp "\\)")) 2)) "Imenu generic expression for Lisp mode. See `imenu-generic-expression'.") @@ -160,6 +168,8 @@ (defvar lisp-doc-string-elt-property 'doc-string-elt "The symbol property that holds the docstring position info.") +(defconst lisp-prettify-symbols-alist '(("lambda" . ?λ)) + "Alist of symbol/\"pretty\" characters to be displayed.") ;;;; Font-lock support. @@ -220,7 +230,10 @@ (defun lisp--el-match-keyword (limit) ;; FIXME: Move to elisp-mode.el. (catch 'found - (while (re-search-forward "(\\(\\(?:\\sw\\|\\s_\\)+\\)\\_>" limit t) + (while (re-search-forward + (eval-when-compile + (concat "(\\(" lisp-mode-symbol-regexp "\\)\\_>")) + limit t) (let ((sym (intern-soft (match-string 1)))) (when (or (special-form-p sym) (and (macrop sym) @@ -229,8 +242,25 @@ (match-beginning 0))))) (throw 'found t)))))) +(defmacro let-when-compile (bindings &rest body) + "Like `let*', but allow for compile time optimization. +Use BINDINGS as in regular `let*', but in BODY each usage should +be wrapped in `eval-when-compile'. +This will generate compile-time constants from BINDINGS." + (declare (indent 1) (debug let)) + (letrec ((loop + (lambda (bindings) + (if (null bindings) + (macroexpand-all (macroexp-progn body) + macroexpand-all-environment) + (let ((binding (pop bindings))) + (cl-progv (list (car binding)) + (list (eval (nth 1 binding) t)) + (funcall loop bindings))))))) + (funcall loop bindings))) + (let-when-compile - ((lisp-fdefs '("defmacro" "defsubst" "defun")) + ((lisp-fdefs '("defmacro" "defun")) (lisp-vdefs '("defvar")) (lisp-kw '("cond" "if" "while" "let" "let*" "progn" "prog1" "prog2" "lambda" "unwind-protect" "condition-case" @@ -240,47 +270,22 @@ ;; Elisp constructs. Now they are update dynamically ;; from obarray but they are also used for setting up ;; the keywords for Common Lisp. - (el-fdefs '("define-advice" "defadvice" "defalias" + (el-fdefs '("defsubst" "cl-defsubst" "define-inline" + "define-advice" "defadvice" "defalias" "define-derived-mode" "define-minor-mode" "define-generic-mode" "define-global-minor-mode" "define-globalized-minor-mode" "define-skeleton" - "define-widget")) + "define-widget" "ert-deftest")) (el-vdefs '("defconst" "defcustom" "defvaralias" "defvar-local" "defface")) (el-tdefs '("defgroup" "deftheme")) - (el-kw '("while-no-input" "letrec" "pcase" "pcase-exhaustive" - "pcase-lambda" "pcase-let" "pcase-let*" "save-restriction" - "save-excursion" "save-selected-window" - ;; "eval-after-load" "eval-next-after-load" - "save-window-excursion" "save-current-buffer" - "save-match-data" "combine-after-change-calls" - "condition-case-unless-debug" "track-mouse" - "eval-and-compile" "eval-when-compile" "with-case-table" - "with-category-table" "with-coding-priority" - "with-current-buffer" "with-demoted-errors" - "with-electric-help" "with-eval-after-load" - "with-file-modes" - "with-local-quit" "with-no-warnings" - "with-output-to-temp-buffer" "with-selected-window" - "with-selected-frame" "with-silent-modifications" - "with-syntax-table" "with-temp-buffer" "with-temp-file" - "with-temp-message" "with-timeout" - "with-timeout-handler")) (el-errs '("user-error")) ;; Common-Lisp constructs supported by EIEIO. FIXME: namespace. (eieio-fdefs '("defgeneric" "defmethod")) (eieio-tdefs '("defclass")) - (eieio-kw '("with-slots")) ;; Common-Lisp constructs supported by cl-lib. - (cl-lib-fdefs '("defmacro" "defsubst" "defun" "defmethod")) + (cl-lib-fdefs '("defmacro" "defsubst" "defun" "defmethod" "defgeneric")) (cl-lib-tdefs '("defstruct" "deftype")) - (cl-lib-kw '("progv" "eval-when" "case" "ecase" "typecase" - "etypecase" "ccase" "ctypecase" "loop" "do" "do*" - "the" "locally" "proclaim" "declaim" "letf" "go" - ;; "lexical-let" "lexical-let*" - "symbol-macrolet" "flet" "flet*" "destructuring-bind" - "labels" "macrolet" "tagbody" "multiple-value-bind" - "block" "return" "return-from")) (cl-lib-errs '("assert" "check-type")) ;; Common-Lisp constructs not supported by cl-lib. (cl-fdefs '("defsetf" "define-method-combination" @@ -289,14 +294,20 @@ "define-compiler-macro" "define-modify-macro")) (cl-vdefs '("define-symbol-macro" "defconstant" "defparameter")) (cl-tdefs '("defpackage" "defstruct" "deftype")) - (cl-kw '("prog" "prog*" "handler-case" "handler-bind" - "in-package" "restart-case" ;; "inline" - "restart-bind" "break" "multiple-value-prog1" - "compiler-let" "with-accessors" "with-compilation-unit" + (cl-kw '("block" "break" "case" "ccase" "compiler-let" "ctypecase" + "declaim" "destructuring-bind" "do" "do*" + "ecase" "etypecase" "eval-when" "flet" "flet*" + "go" "handler-case" "handler-bind" "in-package" ;; "inline" + "labels" "letf" "locally" "loop" + "macrolet" "multiple-value-bind" "multiple-value-prog1" + "proclaim" "prog" "prog*" "progv" + "restart-case" "restart-bind" "return" "return-from" + "symbol-macrolet" "tagbody" "the" "typecase" + "with-accessors" "with-compilation-unit" "with-condition-restarts" "with-hash-table-iterator" "with-input-from-string" "with-open-file" "with-open-stream" "with-package-iterator" - "with-simple-restart" "with-standard-io-syntax")) + "with-simple-restart" "with-slots" "with-standard-io-syntax")) (cl-errs '("abort" "cerror"))) (let ((vdefs (eval-when-compile (append lisp-vdefs el-vdefs cl-vdefs))) @@ -317,16 +328,9 @@ eieio-fdefs eieio-tdefs cl-fdefs cl-vdefs cl-tdefs) t))) - ;; Elisp and Common Lisp keywords. - ;; (el-kws-re (eval-when-compile - ;; (regexp-opt (append - ;; lisp-kw el-kw eieio-kw - ;; (cons "go" (mapcar (lambda (s) (concat "cl-" s)) - ;; (remove "go" cl-lib-kw)))) - ;; t))) + ;; Common Lisp keywords (Elisp keywords are handled dynamically). (cl-kws-re (eval-when-compile - (regexp-opt (append lisp-kw cl-kw eieio-kw cl-lib-kw) - t))) + (regexp-opt (append lisp-kw cl-kw) t))) ;; Elisp and Common Lisp "errors". (el-errs-re (eval-when-compile (regexp-opt (append (mapcar (lambda (s) (concat "cl-" s)) @@ -348,7 +352,8 @@ ;; Any whitespace and defined object. "[ \t']*" "\\(([ \t']*\\)?" ;; An opening paren. - "\\(\\(setf\\)[ \t]+\\(?:\\sw\\|\\s_\\)+\\|\\(?:\\sw\\|\\s_\\)+\\)?") + "\\(\\(setf\\)[ \t]+" lisp-mode-symbol-regexp + "\\|" lisp-mode-symbol-regexp "\\)?") (1 font-lock-keyword-face) (3 (let ((type (get (intern-soft (match-string 1)) 'lisp-define-type))) (cond ((eq type 'var) font-lock-variable-name-face) @@ -359,7 +364,8 @@ ;; defmethod with (setf foo) as name. ((or (not (match-string 2)) ;; Normal defun. (and (match-string 2) ;; Setf method. - (match-string 4))) font-lock-function-name-face))) + (match-string 4))) + font-lock-function-name-face))) nil t)) ;; Emacs Lisp autoload cookies. Supports the slightly different ;; forms used by mh-e, calendar, etc. @@ -372,14 +378,16 @@ ;; Any whitespace and defined object. "[ \t']*" "\\(([ \t']*\\)?" ;; An opening paren. - "\\(\\(setf\\)[ \t]+\\(?:\\sw\\|\\s_\\)+\\|\\(?:\\sw\\|\\s_\\)+\\)?") + "\\(\\(setf\\)[ \t]+" lisp-mode-symbol-regexp + "\\|" lisp-mode-symbol-regexp "\\)?") (1 font-lock-keyword-face) (3 (let ((type (get (intern-soft (match-string 1)) 'lisp-define-type))) (cond ((eq type 'var) font-lock-variable-name-face) ((eq type 'type) font-lock-type-face) ((or (not (match-string 2)) ;; Normal defun. (and (match-string 2) ;; Setf function. - (match-string 4))) font-lock-function-name-face))) + (match-string 4))) + font-lock-function-name-face))) nil t))) "Subdued level highlighting for Lisp modes.") @@ -390,26 +398,29 @@ lisp-el-font-lock-keywords-1 `( ;; Regexp negated char group. ("\\[\\(\\^\\)" 1 font-lock-negation-char-face prepend) + ;; Erroneous structures. + (,(concat "(" el-errs-re "\\_>") + (1 font-lock-warning-face)) ;; Control structures. Common Lisp forms. (lisp--el-match-keyword . 1) ;; Exit/Feature symbols as constants. (,(concat "(\\(catch\\|throw\\|featurep\\|provide\\|require\\)\\_>" - "[ \t']*\\(\\(?:\\sw\\|\\s_\\)+\\)?") + "[ \t']*\\(" lisp-mode-symbol-regexp "\\)?") (1 font-lock-keyword-face) (2 font-lock-constant-face nil t)) - ;; Erroneous structures. - (,(concat "(" el-errs-re "\\_>") - (1 font-lock-warning-face)) ;; Words inside \\[] tend to be for `substitute-command-keys'. - ("\\\\\\\\\\[\\(\\(?:\\sw\\|\\s_\\)+\\)\\]" + (,(concat "\\\\\\\\\\[\\(" lisp-mode-symbol-regexp "\\)\\]") (1 font-lock-constant-face prepend)) - ;; Words inside `' tend to be symbol names. - ("`\\(\\(?:\\sw\\|\\s_\\)\\(?:\\sw\\|\\s_\\)+\\)'" + ;; Words inside ‘’ and `' tend to be symbol names. + (,(concat "[`‘]\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)" + lisp-mode-symbol-regexp "\\)['’]") (1 font-lock-constant-face prepend)) ;; Constant values. - ("\\_<:\\(?:\\sw\\|\\s_\\)+\\_>" 0 font-lock-builtin-face) + (,(concat "\\_<:" lisp-mode-symbol-regexp "\\_>") + (0 font-lock-builtin-face)) ;; ELisp and CLisp `&' keywords as types. - ("\\_<\\&\\(?:\\sw\\|\\s_\\)+\\_>" . font-lock-type-face) + (,(concat "\\_<\\&" lisp-mode-symbol-regexp "\\_>") + . font-lock-type-face) ;; ELisp regexp grouping constructs (,(lambda (bound) (catch 'found @@ -446,19 +457,22 @@ (,(concat "(" cl-kws-re "\\_>") . 1) ;; Exit/Feature symbols as constants. (,(concat "(\\(catch\\|throw\\|provide\\|require\\)\\_>" - "[ \t']*\\(\\(?:\\sw\\|\\s_\\)+\\)?") + "[ \t']*\\(" lisp-mode-symbol-regexp "\\)?") (1 font-lock-keyword-face) (2 font-lock-constant-face nil t)) ;; Erroneous structures. (,(concat "(" cl-errs-re "\\_>") (1 font-lock-warning-face)) - ;; Words inside `' tend to be symbol names. - ("`\\(\\(?:\\sw\\|\\s_\\)\\(?:\\sw\\|\\s_\\)+\\)'" + ;; Words inside ‘’ and `' tend to be symbol names. + (,(concat "[`‘]\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)" + lisp-mode-symbol-regexp "\\)['’]") (1 font-lock-constant-face prepend)) ;; Constant values. - ("\\_<:\\(?:\\sw\\|\\s_\\)+\\_>" 0 font-lock-builtin-face) + (,(concat "\\_<:" lisp-mode-symbol-regexp "\\_>") + (0 font-lock-builtin-face)) ;; ELisp and CLisp `&' keywords as types. - ("\\_<\\&\\(?:\\sw\\|\\s_\\)+\\_>" . font-lock-type-face) + (,(concat "\\_<\\&" lisp-mode-symbol-regexp "\\_>") + . font-lock-type-face) ;; This is too general -- rms. ;; A user complained that he has functions whose names start with `do' ;; and that they get the wrong color. @@ -478,10 +492,16 @@ "Default expressions to highlight in Lisp modes.") (defun lisp-string-in-doc-position-p (listbeg startpos) + "Return true if a doc string may occur at STARTPOS inside a list. +LISTBEG is the position of the start of the innermost list +containing STARTPOS." (let* ((firstsym (and listbeg (save-excursion (goto-char listbeg) - (and (looking-at "([ \t\n]*\\(\\(\\sw\\|\\s_\\)+\\)") + (and (looking-at + (eval-when-compile + (concat "([ \t\n]*\\(" + lisp-mode-symbol-regexp "\\)"))) (match-string 1))))) (docelt (and firstsym (function-get (intern-soft firstsym) @@ -505,6 +525,9 @@ (= (point) startpos)))))) (defun lisp-string-after-doc-keyword-p (listbeg startpos) + "Return true if `:documentation' symbol ends at STARTPOS inside a list. +LISTBEG is the position of the start of the innermost list +containing STARTPOS." (and listbeg ; We are inside a Lisp form. (save-excursion (goto-char startpos) @@ -513,6 +536,9 @@ (looking-at ":documentation\\_>")))))) (defun lisp-font-lock-syntactic-face-function (state) + "Return syntactic face function for the position represented by STATE. +STATE is a `parse-partial-sexp' state, and the returned function is the +Lisp font lock syntactic face function." (if (nth 3 state) ;; This might be a (doc)string or a |...| symbol. (let ((startpos (nth 8 state))) @@ -570,7 +596,7 @@ font-lock keywords will not be case sensitive." (font-lock-extra-managed-props help-echo) (font-lock-syntactic-face-function . lisp-font-lock-syntactic-face-function))) - (setq-local prettify-symbols-alist lisp--prettify-symbols-alist) + (setq-local prettify-symbols-alist lisp-prettify-symbols-alist) (setq-local electric-pair-skip-whitespace 'chomp) (setq-local electric-pair-open-newline-between-pairs nil)) @@ -631,9 +657,6 @@ font-lock keywords will not be case sensitive." :type 'hook :group 'lisp) -(defconst lisp--prettify-symbols-alist - '(("lambda" . ?λ))) - ;;; Generic Lisp mode. (defvar lisp-mode-map @@ -897,7 +920,7 @@ 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 + (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