;;; elisp-mode.el --- Emacs Lisp mode -*- 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
\\{emacs-lisp-mode-map}"
:group 'lisp
- (defvar xref-find-function)
- (defvar xref-identifier-completion-table-function)
- (defvar project-search-path-function)
+ (defvar project-vc-external-roots-function)
(lisp-mode-variables nil nil 'elisp)
(add-hook 'after-load-functions #'elisp--font-lock-flush-elisp-buffers)
(setq-local electric-pair-text-pairs
(append '((?\` . ?\') (?‘ . ?’)) electric-pair-text-pairs))
(setq-local electric-quote-string t)
(setq imenu-case-fold-search nil)
- (add-function :before-until (local 'eldoc-documentation-function)
- #'elisp-eldoc-documentation-function)
- (setq-local xref-find-function #'elisp-xref-find)
- (setq-local xref-identifier-completion-table-function
- #'elisp--xref-identifier-completion-table)
- (setq-local project-search-path-function #'elisp-search-path)
+ (add-hook 'eldoc-documentation-functions
+ #'elisp-eldoc-documentation-function nil t)
+ (add-hook 'xref-backend-functions #'elisp--xref-backend nil t)
+ (setq-local project-vc-external-roots-function #'elisp-load-path-roots)
(add-hook 'completion-at-point-functions
#'elisp-completion-at-point nil 'local))
;; Font-locking support.
(defun elisp--font-lock-flush-elisp-buffers (&optional file)
- ;; FIXME: Aren't we only ever called from after-load-functions?
- ;; Don't flush during load unless called from after-load-functions.
- ;; In that case, FILE is non-nil. It's somehow strange that
- ;; load-in-progress is t when an after-load-function is called since
- ;; that should run *after* the load...
+ ;; We're only ever called from after-load-functions, load-in-progress can
+ ;; still be t in case of nested loads.
(when (or (not load-in-progress) file)
;; FIXME: If the loaded file did not define any macros, there shouldn't
;; be any need to font-lock-flush all the Elisp buffers.
" " (cadr table-etc)))
(cddr table-etc)))))))))
-(define-obsolete-function-alias
- 'lisp-completion-at-point 'elisp-completion-at-point "25.1")
+(defun lisp-completion-at-point (&optional _predicate)
+ (declare (obsolete elisp-completion-at-point "25.1"))
+ (elisp-completion-at-point))
;;; Xref backend
(declare-function xref-make "xref" (summary location))
(declare-function xref-collect-references "xref" (symbol dir))
-(defun elisp-xref-find (action id)
- (require 'find-func)
- ;; FIXME: use information in source near point to filter results:
- ;; (dvc-log-edit ...) - exclude 'feature
- ;; (require 'dvc-log-edit) - only 'feature
- ;; Semantic may provide additional information
- (pcase action
- (`definitions
- (let ((sym (intern-soft id)))
- (when sym
- (elisp--xref-find-definitions sym))))
- (`references
- (elisp--xref-find-references id))
- (`apropos
- (elisp--xref-find-apropos id))))
+(defun elisp--xref-backend () 'elisp)
;; WORKAROUND: This is nominally a constant, but the text properties
;; are not preserved thru dump if use defconst. See bug#21237.
non-nil result supercedes the xrefs produced by
`elisp--xref-find-definitions'.")
-;; FIXME: name should be singular; match xref-find-definition
+(cl-defmethod xref-backend-definitions ((_backend (eql elisp)) identifier)
+ (require 'find-func)
+ ;; FIXME: use information in source near point to filter results:
+ ;; (dvc-log-edit ...) - exclude 'feature
+ ;; (require 'dvc-log-edit) - only 'feature
+ ;; Semantic may provide additional information
+ ;;
+ (let ((sym (intern-soft identifier)))
+ (when sym
+ (elisp--xref-find-definitions sym))))
+
(defun elisp--xref-find-definitions (symbol)
;; The file name is not known when `symbol' is defined via interactive eval.
(let (xrefs)
;; alphabetical by result type symbol
;; FIXME: advised function; list of advice functions
+ ;; FIXME: aliased variable
;; Coding system symbols do not appear in ‘load-history’,
;; so we can’t get a location for them.
(dolist (method (cl--generic-method-table generic))
(let* ((info (cl--generic-method-info method));; qual-string combined-args doconly
(specializers (cl--generic-method-specializers method))
+ (non-default nil)
(met-name (cons symbol specializers))
(file (find-lisp-object-file-name met-name 'cl-defmethod)))
+ (dolist (item specializers)
+ ;; default method has all 't' in specializers
+ (setq non-default (or non-default (not (equal t item)))))
+
(when (and file
- (or specializers ;; default method has null specializers
+ (or non-default
(nth 2 info))) ;; assuming only co-located default has null doc string
(if specializers
(let ((summary (format elisp--xref-format-extra 'cl-defmethod symbol (nth 1 info))))
xrefs))
-(declare-function project-search-path "project")
-(declare-function project-current "project")
-
-(defun elisp--xref-find-references (symbol)
- (cl-mapcan
- (lambda (dir)
- (xref-collect-references symbol dir))
- (project-search-path (project-current))))
+(declare-function project-external-roots "project")
-(defun elisp--xref-find-apropos (regexp)
+(cl-defmethod xref-backend-apropos ((_backend (eql elisp)) regexp)
(apply #'nconc
(let (lst)
(dolist (sym (apropos-internal regexp))
(facep sym)))
'strict))
-(defun elisp--xref-identifier-completion-table ()
+(cl-defmethod xref-backend-identifier-completion-table ((_backend (eql elisp)))
elisp--xref-identifier-completion-table)
(cl-defstruct (xref-elisp-location
(pcase-let (((cl-struct xref-elisp-location symbol type file) l))
(let ((buffer-point (find-function-search-for-symbol symbol type file)))
(with-current-buffer (car buffer-point)
- (goto-char (or (cdr buffer-point) (point-min)))
- (point-marker)))))
+ (save-excursion
+ (goto-char (or (cdr buffer-point) (point-min)))
+ (point-marker))))))
(cl-defmethod xref-location-group ((l xref-elisp-location))
(xref-elisp-location-file l))
-(defun elisp-search-path ()
- (defvar package-user-dir)
- (cons package-user-dir load-path))
+(defun elisp-load-path-roots ()
+ (if (boundp 'package-user-dir)
+ (cons package-user-dir load-path)
+ load-path))
;;; Elisp Interaction mode
((or (eq (following-char) ?\')
(eq (preceding-char) ?\'))
(setq left-quote ?\`)))
+
+ ;; When after a named character literal, skip over the entire
+ ;; literal, not only its last word.
+ (when (= (preceding-char) ?})
+ (let ((begin (save-excursion
+ (backward-char)
+ (skip-syntax-backward "w-")
+ (backward-char 3)
+ (when (looking-at-p "\\\\N{") (point)))))
+ (when begin (goto-char begin))))
+
(forward-sexp -1)
;; If we were after `?\e' (or similar case),
;; use the whole thing, not just the `e'.
(eval (eval-sexp-add-defvars (elisp--preceding-sexp)) lexical-binding)
eval-last-sexp-arg-internal)))
-
(defun elisp--eval-last-sexp-print-value (value &optional eval-last-sexp-arg-internal)
(let ((unabbreviated (let ((print-length nil) (print-level nil))
(prin1-to-string value)))
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.\)
+if it already has a value.)
Return the result of evaluation."
;; FIXME: the print-length/level bindings should only be applied while
ARGLIST is either a string, or a list of strings or symbols."
(let ((str (cond ((stringp arglist) arglist)
((not (listp arglist)) nil)
- (t (help--make-usage-docstring 'toto arglist)))))
+ (t (substitute-command-keys
+ (help--make-usage-docstring 'toto arglist))))))
(if (and str (string-match "\\`([^ )]+ ?" str))
(replace-match "(" t t str)
str)))