]> code.delx.au - gnu-emacs/blob - lisp/progmodes/elisp-mode.el
(elisp--xref-identifier-file): Skip features that have no sources
[gnu-emacs] / lisp / progmodes / elisp-mode.el
1 ;;; elisp-mode.el --- Emacs Lisp mode -*- lexical-binding:t -*-
2
3 ;; Copyright (C) 1985-1986, 1999-2014 Free Software Foundation, Inc.
4
5 ;; Maintainer: emacs-devel@gnu.org
6 ;; Keywords: lisp, languages
7 ;; Package: emacs
8
9 ;; This file is part of GNU Emacs.
10
11 ;; GNU Emacs is free software: you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation, either version 3 of the License, or
14 ;; (at your option) any later version.
15
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
23
24 ;;; Commentary:
25
26 ;; The major mode for editing Emacs Lisp code.
27 ;; This mode is documented in the Emacs manual.
28
29 ;;; Code:
30
31 (require 'lisp-mode)
32
33 (defvar emacs-lisp-mode-abbrev-table nil)
34 (define-abbrev-table 'emacs-lisp-mode-abbrev-table ()
35 "Abbrev table for Emacs Lisp mode.
36 It has `lisp-mode-abbrev-table' as its parent."
37 :parents (list lisp-mode-abbrev-table))
38
39 (defvar emacs-lisp-mode-syntax-table
40 (let ((table (make-syntax-table lisp--mode-syntax-table)))
41 (modify-syntax-entry ?\[ "(] " table)
42 (modify-syntax-entry ?\] ")[ " table)
43 table)
44 "Syntax table used in `emacs-lisp-mode'.")
45
46 (defvar emacs-lisp-mode-map
47 (let ((map (make-sparse-keymap "Emacs-Lisp"))
48 (menu-map (make-sparse-keymap "Emacs-Lisp"))
49 (lint-map (make-sparse-keymap))
50 (prof-map (make-sparse-keymap))
51 (tracing-map (make-sparse-keymap)))
52 (set-keymap-parent map lisp-mode-shared-map)
53 (define-key map "\e\t" 'completion-at-point)
54 (define-key map "\e\C-x" 'eval-defun)
55 (define-key map "\e\C-q" 'indent-pp-sexp)
56 (bindings--define-key map [menu-bar emacs-lisp]
57 (cons "Emacs-Lisp" menu-map))
58 (bindings--define-key menu-map [eldoc]
59 '(menu-item "Auto-Display Documentation Strings" eldoc-mode
60 :button (:toggle . (bound-and-true-p eldoc-mode))
61 :help "Display the documentation string for the item under cursor"))
62 (bindings--define-key menu-map [checkdoc]
63 '(menu-item "Check Documentation Strings" checkdoc
64 :help "Check documentation strings for style requirements"))
65 (bindings--define-key menu-map [re-builder]
66 '(menu-item "Construct Regexp" re-builder
67 :help "Construct a regexp interactively"))
68 (bindings--define-key menu-map [tracing] (cons "Tracing" tracing-map))
69 (bindings--define-key tracing-map [tr-a]
70 '(menu-item "Untrace All" untrace-all
71 :help "Untrace all currently traced functions"))
72 (bindings--define-key tracing-map [tr-uf]
73 '(menu-item "Untrace Function..." untrace-function
74 :help "Untrace function, and possibly activate all remaining advice"))
75 (bindings--define-key tracing-map [tr-sep] menu-bar-separator)
76 (bindings--define-key tracing-map [tr-q]
77 '(menu-item "Trace Function Quietly..." trace-function-background
78 :help "Trace the function with trace output going quietly to a buffer"))
79 (bindings--define-key tracing-map [tr-f]
80 '(menu-item "Trace Function..." trace-function
81 :help "Trace the function given as an argument"))
82 (bindings--define-key menu-map [profiling] (cons "Profiling" prof-map))
83 (bindings--define-key prof-map [prof-restall]
84 '(menu-item "Remove Instrumentation for All Functions" elp-restore-all
85 :help "Restore the original definitions of all functions being profiled"))
86 (bindings--define-key prof-map [prof-restfunc]
87 '(menu-item "Remove Instrumentation for Function..." elp-restore-function
88 :help "Restore an instrumented function to its original definition"))
89
90 (bindings--define-key prof-map [sep-rem] menu-bar-separator)
91 (bindings--define-key prof-map [prof-resall]
92 '(menu-item "Reset Counters for All Functions" elp-reset-all
93 :help "Reset the profiling information for all functions being profiled"))
94 (bindings--define-key prof-map [prof-resfunc]
95 '(menu-item "Reset Counters for Function..." elp-reset-function
96 :help "Reset the profiling information for a function"))
97 (bindings--define-key prof-map [prof-res]
98 '(menu-item "Show Profiling Results" elp-results
99 :help "Display current profiling results"))
100 (bindings--define-key prof-map [prof-pack]
101 '(menu-item "Instrument Package..." elp-instrument-package
102 :help "Instrument for profiling all function that start with a prefix"))
103 (bindings--define-key prof-map [prof-func]
104 '(menu-item "Instrument Function..." elp-instrument-function
105 :help "Instrument a function for profiling"))
106 ;; Maybe this should be in a separate submenu from the ELP stuff?
107 (bindings--define-key prof-map [sep-natprof] menu-bar-separator)
108 (bindings--define-key prof-map [prof-natprof-stop]
109 '(menu-item "Stop Native Profiler" profiler-stop
110 :help "Stop recording profiling information"
111 :enable (and (featurep 'profiler)
112 (profiler-running-p))))
113 (bindings--define-key prof-map [prof-natprof-report]
114 '(menu-item "Show Profiler Report" profiler-report
115 :help "Show the current profiler report"
116 :enable (and (featurep 'profiler)
117 (profiler-running-p))))
118 (bindings--define-key prof-map [prof-natprof-start]
119 '(menu-item "Start Native Profiler..." profiler-start
120 :help "Start recording profiling information"))
121
122 (bindings--define-key menu-map [lint] (cons "Linting" lint-map))
123 (bindings--define-key lint-map [lint-di]
124 '(menu-item "Lint Directory..." elint-directory
125 :help "Lint a directory"))
126 (bindings--define-key lint-map [lint-f]
127 '(menu-item "Lint File..." elint-file
128 :help "Lint a file"))
129 (bindings--define-key lint-map [lint-b]
130 '(menu-item "Lint Buffer" elint-current-buffer
131 :help "Lint the current buffer"))
132 (bindings--define-key lint-map [lint-d]
133 '(menu-item "Lint Defun" elint-defun
134 :help "Lint the function at point"))
135 (bindings--define-key menu-map [edebug-defun]
136 '(menu-item "Instrument Function for Debugging" edebug-defun
137 :help "Evaluate the top level form point is in, stepping through with Edebug"
138 :keys "C-u C-M-x"))
139 (bindings--define-key menu-map [separator-byte] menu-bar-separator)
140 (bindings--define-key menu-map [disas]
141 '(menu-item "Disassemble Byte Compiled Object..." disassemble
142 :help "Print disassembled code for OBJECT in a buffer"))
143 (bindings--define-key menu-map [byte-recompile]
144 '(menu-item "Byte-recompile Directory..." byte-recompile-directory
145 :help "Recompile every `.el' file in DIRECTORY that needs recompilation"))
146 (bindings--define-key menu-map [emacs-byte-compile-and-load]
147 '(menu-item "Byte-compile and Load" emacs-lisp-byte-compile-and-load
148 :help "Byte-compile the current file (if it has changed), then load compiled code"))
149 (bindings--define-key menu-map [byte-compile]
150 '(menu-item "Byte-compile This File" emacs-lisp-byte-compile
151 :help "Byte compile the file containing the current buffer"))
152 (bindings--define-key menu-map [separator-eval] menu-bar-separator)
153 (bindings--define-key menu-map [ielm]
154 '(menu-item "Interactive Expression Evaluation" ielm
155 :help "Interactively evaluate Emacs Lisp expressions"))
156 (bindings--define-key menu-map [eval-buffer]
157 '(menu-item "Evaluate Buffer" eval-buffer
158 :help "Execute the current buffer as Lisp code"))
159 (bindings--define-key menu-map [eval-region]
160 '(menu-item "Evaluate Region" eval-region
161 :help "Execute the region as Lisp code"
162 :enable mark-active))
163 (bindings--define-key menu-map [eval-sexp]
164 '(menu-item "Evaluate Last S-expression" eval-last-sexp
165 :help "Evaluate sexp before point; print value in echo area"))
166 (bindings--define-key menu-map [separator-format] menu-bar-separator)
167 (bindings--define-key menu-map [comment-region]
168 '(menu-item "Comment Out Region" comment-region
169 :help "Comment or uncomment each line in the region"
170 :enable mark-active))
171 (bindings--define-key menu-map [indent-region]
172 '(menu-item "Indent Region" indent-region
173 :help "Indent each nonblank line in the region"
174 :enable mark-active))
175 (bindings--define-key menu-map [indent-line]
176 '(menu-item "Indent Line" lisp-indent-line))
177 map)
178 "Keymap for Emacs Lisp mode.
179 All commands in `lisp-mode-shared-map' are inherited by this map.")
180
181 (defun emacs-lisp-byte-compile ()
182 "Byte compile the file containing the current buffer."
183 (interactive)
184 (if buffer-file-name
185 (byte-compile-file buffer-file-name)
186 (error "The buffer must be saved in a file first")))
187
188 (defun emacs-lisp-byte-compile-and-load ()
189 "Byte-compile the current file (if it has changed), then load compiled code."
190 (interactive)
191 (or buffer-file-name
192 (error "The buffer must be saved in a file first"))
193 (require 'bytecomp)
194 ;; Recompile if file or buffer has changed since last compilation.
195 (if (and (buffer-modified-p)
196 (y-or-n-p (format "Save buffer %s first? " (buffer-name))))
197 (save-buffer))
198 (byte-recompile-file buffer-file-name nil 0 t))
199
200 (defun emacs-lisp-macroexpand ()
201 "Macroexpand the form after point.
202 Comments in the form will be lost."
203 (interactive)
204 (let* ((start (point))
205 (exp (read (current-buffer)))
206 ;; Compute it before, since it may signal errors.
207 (new (macroexpand-1 exp)))
208 (if (equal exp new)
209 (message "Not a macro call, nothing to expand")
210 (delete-region start (point))
211 (pp new (current-buffer))
212 (if (bolp) (delete-char -1))
213 (indent-region start (point)))))
214
215 (defcustom emacs-lisp-mode-hook nil
216 "Hook run when entering Emacs Lisp mode."
217 :options '(eldoc-mode imenu-add-menubar-index checkdoc-minor-mode)
218 :type 'hook
219 :group 'lisp)
220
221 ;;;###autoload
222 (define-derived-mode emacs-lisp-mode prog-mode "Emacs-Lisp"
223 "Major mode for editing Lisp code to run in Emacs.
224 Commands:
225 Delete converts tabs to spaces as it moves back.
226 Blank lines separate paragraphs. Semicolons start comments.
227
228 \\{emacs-lisp-mode-map}"
229 :group 'lisp
230 (defvar xref-find-function)
231 (defvar xref-identifier-completion-table-function)
232 (lisp-mode-variables nil nil 'elisp)
233 (setq imenu-case-fold-search nil)
234 (setq-local eldoc-documentation-function
235 #'elisp-eldoc-documentation-function)
236 (setq-local xref-find-function #'elisp-xref-find)
237 (setq-local xref-identifier-completion-table-function
238 #'elisp--xref-identifier-completion-table)
239 (add-hook 'completion-at-point-functions
240 #'elisp-completion-at-point nil 'local))
241
242 ;;; Completion at point for Elisp
243
244 (defun elisp--local-variables-1 (vars sexp)
245 "Return the vars locally bound around the witness, or nil if not found."
246 (let (res)
247 (while
248 (unless
249 (setq res
250 (pcase sexp
251 (`(,(or `let `let*) ,bindings)
252 (let ((vars vars))
253 (when (eq 'let* (car sexp))
254 (dolist (binding (cdr (reverse bindings)))
255 (push (or (car-safe binding) binding) vars)))
256 (elisp--local-variables-1
257 vars (car (cdr-safe (car (last bindings)))))))
258 (`(,(or `let `let*) ,bindings . ,body)
259 (let ((vars vars))
260 (dolist (binding bindings)
261 (push (or (car-safe binding) binding) vars))
262 (elisp--local-variables-1 vars (car (last body)))))
263 (`(lambda ,_args)
264 ;; FIXME: Look for the witness inside `args'.
265 (setq sexp nil))
266 (`(lambda ,args . ,body)
267 (elisp--local-variables-1
268 (append (remq '&optional (remq '&rest args)) vars)
269 (car (last body))))
270 (`(condition-case ,_ ,e) (elisp--local-variables-1 vars e))
271 (`(condition-case ,v ,_ . ,catches)
272 (elisp--local-variables-1
273 (cons v vars) (cdr (car (last catches)))))
274 (`(quote . ,_)
275 ;; FIXME: Look for the witness inside sexp.
276 (setq sexp nil))
277 ;; FIXME: Handle `cond'.
278 (`(,_ . ,_)
279 (elisp--local-variables-1 vars (car (last sexp))))
280 (`elisp--witness--lisp (or vars '(nil)))
281 (_ nil)))
282 ;; We didn't find the witness in the last element so we try to
283 ;; backtrack to the last-but-one.
284 (setq sexp (ignore-errors (butlast sexp)))))
285 res))
286
287 (defun elisp--local-variables ()
288 "Return a list of locally let-bound variables at point."
289 (save-excursion
290 (skip-syntax-backward "w_")
291 (let* ((ppss (syntax-ppss))
292 (txt (buffer-substring-no-properties (or (car (nth 9 ppss)) (point))
293 (or (nth 8 ppss) (point))))
294 (closer ()))
295 (dolist (p (nth 9 ppss))
296 (push (cdr (syntax-after p)) closer))
297 (setq closer (apply #'string closer))
298 (let* ((sexp (condition-case nil
299 (car (read-from-string
300 (concat txt "elisp--witness--lisp" closer)))
301 ((invalid-read-syntax end-of-file) nil)))
302 (macroexpand-advice (lambda (expander form &rest args)
303 (condition-case nil
304 (apply expander form args)
305 (error form))))
306 (sexp
307 (unwind-protect
308 (progn
309 (advice-add 'macroexpand :around macroexpand-advice)
310 (macroexpand-all sexp))
311 (advice-remove 'macroexpand macroexpand-advice)))
312 (vars (elisp--local-variables-1 nil sexp)))
313 (delq nil
314 (mapcar (lambda (var)
315 (and (symbolp var)
316 (not (string-match (symbol-name var) "\\`[&_]"))
317 ;; Eliminate uninterned vars.
318 (intern-soft var)
319 var))
320 vars))))))
321
322 (defvar elisp--local-variables-completion-table
323 ;; Use `defvar' rather than `defconst' since defconst would purecopy this
324 ;; value, which would doubly fail: it would fail because purecopy can't
325 ;; handle the recursive bytecode object, and it would fail because it would
326 ;; move `lastpos' and `lastvars' to pure space where they'd be immutable!
327 (let ((lastpos nil) (lastvars nil))
328 (letrec ((hookfun (lambda ()
329 (setq lastpos nil)
330 (remove-hook 'post-command-hook hookfun))))
331 (completion-table-dynamic
332 (lambda (_string)
333 (save-excursion
334 (skip-syntax-backward "_w")
335 (let ((newpos (cons (point) (current-buffer))))
336 (unless (equal lastpos newpos)
337 (add-hook 'post-command-hook hookfun)
338 (setq lastpos newpos)
339 (setq lastvars
340 (mapcar #'symbol-name (elisp--local-variables))))))
341 lastvars)))))
342
343 (defun elisp--expect-function-p (pos)
344 "Return non-nil if the symbol at point is expected to be a function."
345 (or
346 (and (eq (char-before pos) ?')
347 (eq (char-before (1- pos)) ?#))
348 (save-excursion
349 (let ((parent (nth 1 (syntax-ppss pos))))
350 (when parent
351 (goto-char parent)
352 (and
353 (looking-at (concat "(\\(cl-\\)?"
354 (regexp-opt '("declare-function"
355 "function" "defadvice"
356 "callf" "callf2"
357 "defsetf"))
358 "[ \t\r\n]+"))
359 (eq (match-end 0) pos)))))))
360
361 (defun elisp--form-quoted-p (pos)
362 "Return non-nil if the form at POS is not evaluated.
363 It can be quoted, or be inside a quoted form."
364 ;; FIXME: Do some macro expansion maybe.
365 (save-excursion
366 (let ((state (syntax-ppss pos)))
367 (or (nth 8 state) ; Code inside strings usually isn't evaluated.
368 ;; FIXME: The 9th element is undocumented.
369 (let ((nesting (cons (point) (reverse (nth 9 state))))
370 res)
371 (while (and nesting (not res))
372 (goto-char (pop nesting))
373 (cond
374 ((or (eq (char-after) ?\[)
375 (progn
376 (skip-chars-backward " ")
377 (memq (char-before) '(?' ?`))))
378 (setq res t))
379 ((eq (char-before) ?,)
380 (setq nesting nil))))
381 res)))))
382
383 ;; FIXME: Support for Company brings in features which straddle eldoc.
384 ;; We should consolidate this, so that major modes can provide all that
385 ;; data all at once:
386 ;; - a function to extract "the reference at point" (may be more complex
387 ;; than a mere string, to distinguish various namespaces).
388 ;; - a function to jump to such a reference.
389 ;; - a function to show the signature/interface of such a reference.
390 ;; - a function to build a help-buffer about that reference.
391 ;; FIXME: Those functions should also be used by the normal completion code in
392 ;; the *Completions* buffer.
393
394 (defun elisp--company-doc-buffer (str)
395 (let ((symbol (intern-soft str)))
396 ;; FIXME: we really don't want to "display-buffer and then undo it".
397 (save-window-excursion
398 ;; Make sure we don't display it in another frame, otherwise
399 ;; save-window-excursion won't be able to undo it.
400 (let ((display-buffer-overriding-action
401 '(nil . ((inhibit-switch-frame . t)))))
402 (ignore-errors
403 (cond
404 ((fboundp symbol) (describe-function symbol))
405 ((boundp symbol) (describe-variable symbol))
406 ((featurep symbol) (describe-package symbol))
407 ((facep symbol) (describe-face symbol))
408 (t (signal 'user-error nil)))
409 (help-buffer))))))
410
411 (defun elisp--company-doc-string (str)
412 (let* ((symbol (intern-soft str))
413 (doc (if (fboundp symbol)
414 (documentation symbol t)
415 (documentation-property symbol 'variable-documentation t))))
416 (and (stringp doc)
417 (string-match ".*$" doc)
418 (match-string 0 doc))))
419
420 (declare-function find-library-name "find-func" (library))
421 (declare-function find-function-library "find-func" (function &optional l-o v))
422
423 (defun elisp--company-location (str)
424 (let ((sym (intern-soft str)))
425 (cond
426 ((fboundp sym) (find-definition-noselect sym nil))
427 ((boundp sym) (find-definition-noselect sym 'defvar))
428 ((featurep sym)
429 (require 'find-func)
430 (cons (find-file-noselect (find-library-name
431 (symbol-name sym)))
432 0))
433 ((facep sym) (find-definition-noselect sym 'defface)))))
434
435 (defun elisp-completion-at-point ()
436 "Function used for `completion-at-point-functions' in `emacs-lisp-mode'."
437 (with-syntax-table emacs-lisp-mode-syntax-table
438 (let* ((pos (point))
439 (beg (condition-case nil
440 (save-excursion
441 (backward-sexp 1)
442 (skip-syntax-forward "'")
443 (point))
444 (scan-error pos)))
445 (end
446 (unless (or (eq beg (point-max))
447 (member (char-syntax (char-after beg))
448 '(?\s ?\" ?\( ?\))))
449 (condition-case nil
450 (save-excursion
451 (goto-char beg)
452 (forward-sexp 1)
453 (skip-chars-backward "'")
454 (when (>= (point) pos)
455 (point)))
456 (scan-error pos))))
457 ;; t if in function position.
458 (funpos (eq (char-before beg) ?\()))
459 (when (and end (or (not (nth 8 (syntax-ppss)))
460 (eq (char-before beg) ?`)))
461 (let ((table-etc
462 (if (not funpos)
463 ;; FIXME: We could look at the first element of the list and
464 ;; use it to provide a more specific completion table in some
465 ;; cases. E.g. filter out keywords that are not understood by
466 ;; the macro/function being called.
467 (cond
468 ((elisp--expect-function-p beg)
469 (list nil obarray
470 :predicate #'fboundp
471 :company-doc-buffer #'elisp--company-doc-buffer
472 :company-docsig #'elisp--company-doc-string
473 :company-location #'elisp--company-location))
474 ((elisp--form-quoted-p beg)
475 (list nil obarray
476 ;; Don't include all symbols (bug#16646).
477 :predicate (lambda (sym)
478 (or (boundp sym)
479 (fboundp sym)
480 (featurep sym)
481 (symbol-plist sym)))
482 :annotation-function
483 (lambda (str) (if (fboundp (intern-soft str)) " <f>"))
484 :company-doc-buffer #'elisp--company-doc-buffer
485 :company-docsig #'elisp--company-doc-string
486 :company-location #'elisp--company-location))
487 (t
488 (list nil (completion-table-merge
489 elisp--local-variables-completion-table
490 (apply-partially #'completion-table-with-predicate
491 obarray
492 #'boundp
493 'strict))
494 :company-doc-buffer #'elisp--company-doc-buffer
495 :company-docsig #'elisp--company-doc-string
496 :company-location #'elisp--company-location)))
497 ;; Looks like a funcall position. Let's double check.
498 (save-excursion
499 (goto-char (1- beg))
500 (let ((parent
501 (condition-case nil
502 (progn (up-list -1) (forward-char 1)
503 (let ((c (char-after)))
504 (if (eq c ?\() ?\(
505 (if (memq (char-syntax c) '(?w ?_))
506 (read (current-buffer))))))
507 (error nil))))
508 (pcase parent
509 ;; FIXME: Rather than hardcode special cases here,
510 ;; we should use something like a symbol-property.
511 (`declare
512 (list t (mapcar (lambda (x) (symbol-name (car x)))
513 (delete-dups
514 ;; FIXME: We should include some
515 ;; docstring with each entry.
516 (append
517 macro-declarations-alist
518 defun-declarations-alist)))))
519 ((and (or `condition-case `condition-case-unless-debug)
520 (guard (save-excursion
521 (ignore-errors
522 (forward-sexp 2)
523 (< (point) beg)))))
524 (list t obarray
525 :predicate (lambda (sym) (get sym 'error-conditions))))
526 ((and ?\(
527 (guard (save-excursion
528 (goto-char (1- beg))
529 (up-list -1)
530 (forward-symbol -1)
531 (looking-at "\\_<let\\*?\\_>"))))
532 (list t obarray
533 :predicate #'boundp
534 :company-doc-buffer #'elisp--company-doc-buffer
535 :company-docsig #'elisp--company-doc-string
536 :company-location #'elisp--company-location))
537 (_ (list nil obarray
538 :predicate #'fboundp
539 :company-doc-buffer #'elisp--company-doc-buffer
540 :company-docsig #'elisp--company-doc-string
541 :company-location #'elisp--company-location
542 ))))))))
543 (nconc (list beg end)
544 (if (null (car table-etc))
545 (cdr table-etc)
546 (cons
547 (if (memq (char-syntax (or (char-after end) ?\s))
548 '(?\s ?>))
549 (cadr table-etc)
550 (apply-partially 'completion-table-with-terminator
551 " " (cadr table-etc)))
552 (cddr table-etc)))))))))
553
554 (define-obsolete-function-alias
555 'lisp-completion-at-point 'elisp-completion-at-point "25.1")
556
557 ;;; Xref backend
558
559 (declare-function xref-make-elisp-location "xref" (symbol type file))
560 (declare-function xref-make-bogus-location "xref" (message))
561 (declare-function xref-make "xref" (description location))
562
563 (defun elisp-xref-find (action id)
564 (require 'find-func)
565 (pcase action
566 (`definitions
567 (let ((sym (intern-soft id)))
568 (when sym
569 (elisp--xref-find-definitions sym))))
570 (`apropos
571 (elisp--xref-find-apropos id))))
572
573 (defun elisp--xref-identifier-file (type sym)
574 (pcase type
575 (`defun (when (fboundp sym)
576 (find-function-library sym)))
577 (`defvar (when (boundp sym)
578 (or (symbol-file sym 'defvar)
579 (help-C-file-name sym 'var))))
580 (`feature (when (featurep sym)
581 (ignore-errors
582 (find-library-name (symbol-name sym)))))
583 (`defface (when (facep sym)
584 (symbol-file sym 'defface)))))
585
586 (defun elisp--xref-find-definitions (symbol)
587 (save-excursion
588 (let (lst)
589 (dolist (type '(feature defface defvar defun))
590 (let ((loc
591 (condition-case err
592 (let ((file (elisp--xref-identifier-file type symbol)))
593 (when file
594 (when (string-match-p "\\.elc\\'" file)
595 (setq file (substring file 0 -1)))
596 (xref-make-elisp-location symbol type file)))
597 (error
598 (xref-make-bogus-location (error-message-string err))))))
599 (when loc
600 (push
601 (xref-make (format "(%s %s)" type symbol)
602 loc)
603 lst))))
604 lst)))
605
606 (defun elisp--xref-find-apropos (regexp)
607 (apply #'nconc
608 (let (lst)
609 (dolist (sym (apropos-internal regexp))
610 (push (elisp--xref-find-definitions sym) lst))
611 (nreverse lst))))
612
613 (defvar elisp--xref-identifier-completion-table
614 (apply-partially #'completion-table-with-predicate
615 obarray
616 (lambda (sym)
617 (or (boundp sym)
618 (fboundp sym)
619 (featurep sym)
620 (facep sym)))
621 'strict))
622
623 (defun elisp--xref-identifier-completion-table ()
624 elisp--xref-identifier-completion-table)
625
626 ;;; Elisp Interaction mode
627
628 (defvar lisp-interaction-mode-map
629 (let ((map (make-sparse-keymap))
630 (menu-map (make-sparse-keymap "Lisp-Interaction")))
631 (set-keymap-parent map lisp-mode-shared-map)
632 (define-key map "\e\C-x" 'eval-defun)
633 (define-key map "\e\C-q" 'indent-pp-sexp)
634 (define-key map "\e\t" 'completion-at-point)
635 (define-key map "\n" 'eval-print-last-sexp)
636 (bindings--define-key map [menu-bar lisp-interaction]
637 (cons "Lisp-Interaction" menu-map))
638 (bindings--define-key menu-map [eval-defun]
639 '(menu-item "Evaluate Defun" eval-defun
640 :help "Evaluate the top-level form containing point, or after point"))
641 (bindings--define-key menu-map [eval-print-last-sexp]
642 '(menu-item "Evaluate and Print" eval-print-last-sexp
643 :help "Evaluate sexp before point; print value into current buffer"))
644 (bindings--define-key menu-map [edebug-defun-lisp-interaction]
645 '(menu-item "Instrument Function for Debugging" edebug-defun
646 :help "Evaluate the top level form point is in, stepping through with Edebug"
647 :keys "C-u C-M-x"))
648 (bindings--define-key menu-map [indent-pp-sexp]
649 '(menu-item "Indent or Pretty-Print" indent-pp-sexp
650 :help "Indent each line of the list starting just after point, or prettyprint it"))
651 (bindings--define-key menu-map [complete-symbol]
652 '(menu-item "Complete Lisp Symbol" completion-at-point
653 :help "Perform completion on Lisp symbol preceding point"))
654 map)
655 "Keymap for Lisp Interaction mode.
656 All commands in `lisp-mode-shared-map' are inherited by this map.")
657
658 (define-derived-mode lisp-interaction-mode emacs-lisp-mode "Lisp Interaction"
659 "Major mode for typing and evaluating Lisp forms.
660 Like Lisp mode except that \\[eval-print-last-sexp] evals the Lisp expression
661 before point, and prints its value into the buffer, advancing point.
662 Note that printing is controlled by `eval-expression-print-length'
663 and `eval-expression-print-level'.
664
665 Commands:
666 Delete converts tabs to spaces as it moves back.
667 Paragraphs are separated only by blank lines.
668 Semicolons start comments.
669
670 \\{lisp-interaction-mode-map}"
671 :abbrev-table nil)
672
673 ;;; Emacs Lisp Byte-Code mode
674
675 (eval-and-compile
676 (defconst emacs-list-byte-code-comment-re
677 (concat "\\(#\\)@\\([0-9]+\\) "
678 ;; Make sure it's a docstring and not a lazy-loaded byte-code.
679 "\\(?:[^(]\\|([^\"]\\)")))
680
681 (defun elisp--byte-code-comment (end &optional _point)
682 "Try to syntactically mark the #@NNN ....^_ docstrings in byte-code files."
683 (let ((ppss (syntax-ppss)))
684 (when (and (nth 4 ppss)
685 (eq (char-after (nth 8 ppss)) ?#))
686 (let* ((n (save-excursion
687 (goto-char (nth 8 ppss))
688 (when (looking-at emacs-list-byte-code-comment-re)
689 (string-to-number (match-string 2)))))
690 ;; `maxdiff' tries to make sure the loop below terminates.
691 (maxdiff n))
692 (when n
693 (let* ((bchar (match-end 2))
694 (b (position-bytes bchar)))
695 (goto-char (+ b n))
696 (while (let ((diff (- (position-bytes (point)) b n)))
697 (unless (zerop diff)
698 (when (> diff maxdiff) (setq diff maxdiff))
699 (forward-char (- diff))
700 (setq maxdiff (if (> diff 0) diff
701 (max (1- maxdiff) 1)))
702 t))))
703 (if (<= (point) end)
704 (put-text-property (1- (point)) (point)
705 'syntax-table
706 (string-to-syntax "> b"))
707 (goto-char end)))))))
708
709 (defun elisp-byte-code-syntax-propertize (start end)
710 (elisp--byte-code-comment end (point))
711 (funcall
712 (syntax-propertize-rules
713 (emacs-list-byte-code-comment-re
714 (1 (prog1 "< b" (elisp--byte-code-comment end (point))))))
715 start end))
716
717 ;;;###autoload
718 (add-to-list 'auto-mode-alist '("\\.elc\\'" . elisp-byte-code-mode))
719 ;;;###autoload
720 (define-derived-mode elisp-byte-code-mode emacs-lisp-mode
721 "Elisp-Byte-Code"
722 "Major mode for *.elc files."
723 ;; TODO: Add way to disassemble byte-code under point.
724 (setq-local open-paren-in-column-0-is-defun-start nil)
725 (setq-local syntax-propertize-function
726 #'elisp-byte-code-syntax-propertize))
727
728
729 ;;; Globally accessible functionality
730
731 (defun eval-print-last-sexp (&optional eval-last-sexp-arg-internal)
732 "Evaluate sexp before point; print value into current buffer.
733
734 Normally, this function truncates long output according to the value
735 of the variables `eval-expression-print-length' and
736 `eval-expression-print-level'. With a prefix argument of zero,
737 however, there is no such truncation. Such a prefix argument
738 also causes integers to be printed in several additional formats
739 \(octal, hexadecimal, and character).
740
741 If `eval-expression-debug-on-error' is non-nil, which is the default,
742 this command arranges for all errors to enter the debugger."
743 (interactive "P")
744 (let ((standard-output (current-buffer)))
745 (terpri)
746 (eval-last-sexp (or eval-last-sexp-arg-internal t))
747 (terpri)))
748
749
750 (defun last-sexp-setup-props (beg end value alt1 alt2)
751 "Set up text properties for the output of `elisp--eval-last-sexp'.
752 BEG and END are the start and end of the output in current-buffer.
753 VALUE is the Lisp value printed, ALT1 and ALT2 are strings for the
754 alternative printed representations that can be displayed."
755 (let ((map (make-sparse-keymap)))
756 (define-key map "\C-m" 'elisp-last-sexp-toggle-display)
757 (define-key map [down-mouse-2] 'mouse-set-point)
758 (define-key map [mouse-2] 'elisp-last-sexp-toggle-display)
759 (add-text-properties
760 beg end
761 `(printed-value (,value ,alt1 ,alt2)
762 mouse-face highlight
763 keymap ,map
764 help-echo "RET, mouse-2: toggle abbreviated display"
765 rear-nonsticky (mouse-face keymap help-echo
766 printed-value)))))
767
768
769 (defun elisp-last-sexp-toggle-display (&optional _arg)
770 "Toggle between abbreviated and unabbreviated printed representations."
771 (interactive "P")
772 (save-restriction
773 (widen)
774 (let ((value (get-text-property (point) 'printed-value)))
775 (when value
776 (let ((beg (or (previous-single-property-change (min (point-max) (1+ (point)))
777 'printed-value)
778 (point)))
779 (end (or (next-single-char-property-change (point) 'printed-value) (point)))
780 (standard-output (current-buffer))
781 (point (point)))
782 (delete-region beg end)
783 (insert (nth 1 value))
784 (or (= beg point)
785 (setq point (1- (point))))
786 (last-sexp-setup-props beg (point)
787 (nth 0 value)
788 (nth 2 value)
789 (nth 1 value))
790 (goto-char (min (point-max) point)))))))
791
792 (defun prin1-char (char) ;FIXME: Move it, e.g. to simple.el.
793 "Return a string representing CHAR as a character rather than as an integer.
794 If CHAR is not a character, return nil."
795 (and (integerp char)
796 (eventp char)
797 (let ((c (event-basic-type char))
798 (mods (event-modifiers char))
799 string)
800 ;; Prevent ?A from turning into ?\S-a.
801 (if (and (memq 'shift mods)
802 (zerop (logand char ?\S-\^@))
803 (not (let ((case-fold-search nil))
804 (char-equal c (upcase c)))))
805 (setq c (upcase c) mods nil))
806 ;; What string are we considering using?
807 (condition-case nil
808 (setq string
809 (concat
810 "?"
811 (mapconcat
812 (lambda (modif)
813 (cond ((eq modif 'super) "\\s-")
814 (t (string ?\\ (upcase (aref (symbol-name modif) 0)) ?-))))
815 mods "")
816 (cond
817 ((memq c '(?\; ?\( ?\) ?\{ ?\} ?\[ ?\] ?\" ?\' ?\\)) (string ?\\ c))
818 ((eq c 127) "\\C-?")
819 (t
820 (string c)))))
821 (error nil))
822 ;; Verify the string reads a CHAR, not to some other character.
823 ;; If it doesn't, return nil instead.
824 (and string
825 (= (car (read-from-string string)) char)
826 string))))
827
828 (defun elisp--preceding-sexp ()
829 "Return sexp before the point."
830 (let ((opoint (point))
831 ignore-quotes
832 expr)
833 (save-excursion
834 (with-syntax-table emacs-lisp-mode-syntax-table
835 ;; If this sexp appears to be enclosed in `...'
836 ;; then ignore the surrounding quotes.
837 (setq ignore-quotes
838 (or (eq (following-char) ?\')
839 (eq (preceding-char) ?\')))
840 (forward-sexp -1)
841 ;; If we were after `?\e' (or similar case),
842 ;; use the whole thing, not just the `e'.
843 (when (eq (preceding-char) ?\\)
844 (forward-char -1)
845 (when (eq (preceding-char) ??)
846 (forward-char -1)))
847
848 ;; Skip over hash table read syntax.
849 (and (> (point) (1+ (point-min)))
850 (looking-back "#s" (- (point) 2))
851 (forward-char -2))
852
853 ;; Skip over `#N='s.
854 (when (eq (preceding-char) ?=)
855 (let (labeled-p)
856 (save-excursion
857 (skip-chars-backward "0-9#=")
858 (setq labeled-p (looking-at "\\(#[0-9]+=\\)+")))
859 (when labeled-p
860 (forward-sexp -1))))
861
862 (save-restriction
863 (if (and ignore-quotes (eq (following-char) ?`))
864 ;; vladimir@cs.ualberta.ca 30-Jul-1997: Skip ` in `variable' so
865 ;; that the value is returned, not the name.
866 (forward-char))
867 (when (looking-at ",@?") (goto-char (match-end 0)))
868 (narrow-to-region (point-min) opoint)
869 (setq expr (read (current-buffer)))
870 ;; If it's an (interactive ...) form, it's more useful to show how an
871 ;; interactive call would use it.
872 ;; FIXME: Is it really the right place for this?
873 (when (eq (car-safe expr) 'interactive)
874 (setq expr
875 `(call-interactively
876 (lambda (&rest args) ,expr args))))
877 expr)))))
878 (define-obsolete-function-alias 'preceding-sexp 'elisp--preceding-sexp "25.1")
879
880 (defun elisp--eval-last-sexp (eval-last-sexp-arg-internal)
881 "Evaluate sexp before point; print value in the echo area.
882 With argument, print output into current buffer.
883 With a zero prefix arg, print output with no limit on the length
884 and level of lists, and include additional formats for integers
885 \(octal, hexadecimal, and character)."
886 (let ((standard-output (if eval-last-sexp-arg-internal (current-buffer) t)))
887 ;; Setup the lexical environment if lexical-binding is enabled.
888 (elisp--eval-last-sexp-print-value
889 (eval (eval-sexp-add-defvars (elisp--preceding-sexp)) lexical-binding)
890 eval-last-sexp-arg-internal)))
891
892
893 (defun elisp--eval-last-sexp-print-value (value &optional eval-last-sexp-arg-internal)
894 (let ((unabbreviated (let ((print-length nil) (print-level nil))
895 (prin1-to-string value)))
896 (print-length (and (not (zerop (prefix-numeric-value
897 eval-last-sexp-arg-internal)))
898 eval-expression-print-length))
899 (print-level (and (not (zerop (prefix-numeric-value
900 eval-last-sexp-arg-internal)))
901 eval-expression-print-level))
902 (beg (point))
903 end)
904 (prog1
905 (prin1 value)
906 (let ((str (eval-expression-print-format value)))
907 (if str (princ str)))
908 (setq end (point))
909 (when (and (bufferp standard-output)
910 (or (not (null print-length))
911 (not (null print-level)))
912 (not (string= unabbreviated
913 (buffer-substring-no-properties beg end))))
914 (last-sexp-setup-props beg end value
915 unabbreviated
916 (buffer-substring-no-properties beg end))
917 ))))
918
919
920 (defvar elisp--eval-last-sexp-fake-value (make-symbol "t"))
921
922 (defun eval-sexp-add-defvars (exp &optional pos)
923 "Prepend EXP with all the `defvar's that precede it in the buffer.
924 POS specifies the starting position where EXP was found and defaults to point."
925 (setq exp (macroexpand-all exp)) ;Eager macro-expansion.
926 (if (not lexical-binding)
927 exp
928 (save-excursion
929 (unless pos (setq pos (point)))
930 (let ((vars ()))
931 (goto-char (point-min))
932 (while (re-search-forward
933 "(def\\(?:var\\|const\\|custom\\)[ \t\n]+\\([^; '()\n\t]+\\)"
934 pos t)
935 (let ((var (intern (match-string 1))))
936 (and (not (special-variable-p var))
937 (save-excursion
938 (zerop (car (syntax-ppss (match-beginning 0)))))
939 (push var vars))))
940 `(progn ,@(mapcar (lambda (v) `(defvar ,v)) vars) ,exp)))))
941
942 (defun eval-last-sexp (eval-last-sexp-arg-internal)
943 "Evaluate sexp before point; print value in the echo area.
944 Interactively, with prefix argument, print output into current buffer.
945
946 Normally, this function truncates long output according to the value
947 of the variables `eval-expression-print-length' and
948 `eval-expression-print-level'. With a prefix argument of zero,
949 however, there is no such truncation. Such a prefix argument
950 also causes integers to be printed in several additional formats
951 \(octal, hexadecimal, and character).
952
953 If `eval-expression-debug-on-error' is non-nil, which is the default,
954 this command arranges for all errors to enter the debugger."
955 (interactive "P")
956 (if (null eval-expression-debug-on-error)
957 (elisp--eval-last-sexp eval-last-sexp-arg-internal)
958 (let ((value
959 (let ((debug-on-error elisp--eval-last-sexp-fake-value))
960 (cons (elisp--eval-last-sexp eval-last-sexp-arg-internal)
961 debug-on-error))))
962 (unless (eq (cdr value) elisp--eval-last-sexp-fake-value)
963 (setq debug-on-error (cdr value)))
964 (car value))))
965
966 (defun elisp--eval-defun-1 (form)
967 "Treat some expressions specially.
968 Reset the `defvar' and `defcustom' variables to the initial value.
969 \(For `defcustom', use the :set function if there is one.)
970 Reinitialize the face according to the `defface' specification."
971 ;; The code in edebug-defun should be consistent with this, but not
972 ;; the same, since this gets a macroexpanded form.
973 (cond ((not (listp form))
974 form)
975 ((and (eq (car form) 'defvar)
976 (cdr-safe (cdr-safe form))
977 (boundp (cadr form)))
978 ;; Force variable to be re-set.
979 `(progn (defvar ,(nth 1 form) nil ,@(nthcdr 3 form))
980 (setq-default ,(nth 1 form) ,(nth 2 form))))
981 ;; `defcustom' is now macroexpanded to
982 ;; `custom-declare-variable' with a quoted value arg.
983 ((and (eq (car form) 'custom-declare-variable)
984 (default-boundp (eval (nth 1 form) lexical-binding)))
985 ;; Force variable to be bound, using :set function if specified.
986 (let ((setfunc (memq :set form)))
987 (when setfunc
988 (setq setfunc (car-safe (cdr-safe setfunc)))
989 (or (functionp setfunc) (setq setfunc nil)))
990 (funcall (or setfunc 'set-default)
991 (eval (nth 1 form) lexical-binding)
992 ;; The second arg is an expression that evaluates to
993 ;; an expression. The second evaluation is the one
994 ;; normally performed not by normal execution but by
995 ;; custom-initialize-set (for example), which does not
996 ;; use lexical-binding.
997 (eval (eval (nth 2 form) lexical-binding))))
998 form)
999 ;; `defface' is macroexpanded to `custom-declare-face'.
1000 ((eq (car form) 'custom-declare-face)
1001 ;; Reset the face.
1002 (let ((face-symbol (eval (nth 1 form) lexical-binding)))
1003 (setq face-new-frame-defaults
1004 (assq-delete-all face-symbol face-new-frame-defaults))
1005 (put face-symbol 'face-defface-spec nil)
1006 (put face-symbol 'face-override-spec nil))
1007 form)
1008 ((eq (car form) 'progn)
1009 (cons 'progn (mapcar #'elisp--eval-defun-1 (cdr form))))
1010 (t form)))
1011
1012 (defun elisp--eval-defun ()
1013 "Evaluate defun that point is in or before.
1014 The value is displayed in the echo area.
1015 If the current defun is actually a call to `defvar',
1016 then reset the variable using the initial value expression
1017 even if the variable already has some other value.
1018 \(Normally `defvar' does not change the variable's value
1019 if it already has a value.\)
1020
1021 Return the result of evaluation."
1022 ;; FIXME: the print-length/level bindings should only be applied while
1023 ;; printing, not while evaluating.
1024 (let ((debug-on-error eval-expression-debug-on-error)
1025 (print-length eval-expression-print-length)
1026 (print-level eval-expression-print-level))
1027 (save-excursion
1028 ;; Arrange for eval-region to "read" the (possibly) altered form.
1029 ;; eval-region handles recording which file defines a function or
1030 ;; variable.
1031 (let ((standard-output t)
1032 beg end form)
1033 ;; Read the form from the buffer, and record where it ends.
1034 (save-excursion
1035 (end-of-defun)
1036 (beginning-of-defun)
1037 (setq beg (point))
1038 (setq form (read (current-buffer)))
1039 (setq end (point)))
1040 ;; Alter the form if necessary.
1041 (let ((form (eval-sexp-add-defvars
1042 (elisp--eval-defun-1 (macroexpand form)))))
1043 (eval-region beg end standard-output
1044 (lambda (_ignore)
1045 ;; Skipping to the end of the specified region
1046 ;; will make eval-region return.
1047 (goto-char end)
1048 form))))))
1049 (let ((str (eval-expression-print-format (car values))))
1050 (if str (princ str)))
1051 ;; The result of evaluation has been put onto VALUES. So return it.
1052 (car values))
1053
1054 (defun eval-defun (edebug-it)
1055 "Evaluate the top-level form containing point, or after point.
1056
1057 If the current defun is actually a call to `defvar' or `defcustom',
1058 evaluating it this way resets the variable using its initial value
1059 expression (using the defcustom's :set function if there is one), even
1060 if the variable already has some other value. \(Normally `defvar' and
1061 `defcustom' do not alter the value if there already is one.) In an
1062 analogous way, evaluating a `defface' overrides any customizations of
1063 the face, so that it becomes defined exactly as the `defface' expression
1064 says.
1065
1066 If `eval-expression-debug-on-error' is non-nil, which is the default,
1067 this command arranges for all errors to enter the debugger.
1068
1069 With a prefix argument, instrument the code for Edebug.
1070
1071 If acting on a `defun' for FUNCTION, and the function was
1072 instrumented, `Edebug: FUNCTION' is printed in the echo area. If not
1073 instrumented, just FUNCTION is printed.
1074
1075 If not acting on a `defun', the result of evaluation is displayed in
1076 the echo area. This display is controlled by the variables
1077 `eval-expression-print-length' and `eval-expression-print-level',
1078 which see."
1079 (interactive "P")
1080 (cond (edebug-it
1081 (require 'edebug)
1082 (eval-defun (not edebug-all-defs)))
1083 (t
1084 (if (null eval-expression-debug-on-error)
1085 (elisp--eval-defun)
1086 (let (new-value value)
1087 (let ((debug-on-error elisp--eval-last-sexp-fake-value))
1088 (setq value (elisp--eval-defun))
1089 (setq new-value debug-on-error))
1090 (unless (eq elisp--eval-last-sexp-fake-value new-value)
1091 (setq debug-on-error new-value))
1092 value)))))
1093
1094 ;;; ElDoc Support
1095
1096 (defvar elisp--eldoc-last-data (make-vector 3 nil)
1097 "Bookkeeping; elements are as follows:
1098 0 - contains the last symbol read from the buffer.
1099 1 - contains the string last displayed in the echo area for variables,
1100 or argument string for functions.
1101 2 - 'function if function args, 'variable if variable documentation.")
1102
1103 (defun elisp-eldoc-documentation-function ()
1104 "`eldoc-documentation-function' (which see) for Emacs Lisp."
1105 (let ((current-symbol (elisp--current-symbol))
1106 (current-fnsym (elisp--fnsym-in-current-sexp)))
1107 (cond ((null current-fnsym)
1108 nil)
1109 ((eq current-symbol (car current-fnsym))
1110 (or (apply #'elisp--get-fnsym-args-string current-fnsym)
1111 (elisp--get-var-docstring current-symbol)))
1112 (t
1113 (or (elisp--get-var-docstring current-symbol)
1114 (apply #'elisp--get-fnsym-args-string current-fnsym))))))
1115
1116 (defun elisp--get-fnsym-args-string (sym &optional index)
1117 "Return a string containing the parameter list of the function SYM.
1118 If SYM is a subr and no arglist is obtainable from the docstring
1119 or elsewhere, return a 1-line docstring."
1120 (let ((argstring
1121 (cond
1122 ((not (and sym (symbolp sym) (fboundp sym))) nil)
1123 ((and (eq sym (aref elisp--eldoc-last-data 0))
1124 (eq 'function (aref elisp--eldoc-last-data 2)))
1125 (aref elisp--eldoc-last-data 1))
1126 (t
1127 (let* ((advertised (gethash (indirect-function sym)
1128 advertised-signature-table t))
1129 doc
1130 (args
1131 (cond
1132 ((listp advertised) advertised)
1133 ((setq doc (help-split-fundoc (documentation sym t) sym))
1134 (car doc))
1135 (t (help-function-arglist sym)))))
1136 ;; Stringify, and store before highlighting, downcasing, etc.
1137 ;; FIXME should truncate before storing.
1138 (elisp--last-data-store sym (elisp--function-argstring args)
1139 'function))))))
1140 ;; Highlight, truncate.
1141 (if argstring
1142 (elisp--highlight-function-argument sym argstring index))))
1143
1144 (defun elisp--highlight-function-argument (sym args index)
1145 "Highlight argument INDEX in ARGS list for function SYM.
1146 In the absence of INDEX, just call `elisp--docstring-format-sym-doc'."
1147 ;; FIXME: This should probably work on the list representation of `args'
1148 ;; rather than its string representation.
1149 ;; FIXME: This function is much too long, we need to split it up!
1150 (let ((start nil)
1151 (end 0)
1152 (argument-face 'eldoc-highlight-function-argument)
1153 (args-lst (mapcar (lambda (x)
1154 (replace-regexp-in-string
1155 "\\`[(]\\|[)]\\'" "" x))
1156 (split-string args))))
1157 ;; Find the current argument in the argument string. We need to
1158 ;; handle `&rest' and informal `...' properly.
1159 ;;
1160 ;; FIXME: What to do with optional arguments, like in
1161 ;; (defun NAME ARGLIST [DOCSTRING] BODY...) case?
1162 ;; The problem is there is no robust way to determine if
1163 ;; the current argument is indeed a docstring.
1164
1165 ;; When `&key' is used finding position based on `index'
1166 ;; would be wrong, so find the arg at point and determine
1167 ;; position in ARGS based on this current arg.
1168 (when (string-match "&key" args)
1169 (let* (case-fold-search
1170 key-have-value
1171 (sym-name (symbol-name sym))
1172 (cur-w (current-word))
1173 (args-lst-ak (cdr (member "&key" args-lst)))
1174 (limit (save-excursion
1175 (when (re-search-backward sym-name nil t)
1176 (match-end 0))))
1177 (cur-a (if (and cur-w (string-match ":\\([^ ()]*\\)" cur-w))
1178 (substring cur-w 1)
1179 (save-excursion
1180 (let (split)
1181 (when (re-search-backward ":\\([^()\n]*\\)" limit t)
1182 (setq split (split-string (match-string 1) " " t))
1183 (prog1 (car split)
1184 (when (cdr split)
1185 (setq key-have-value t))))))))
1186 ;; If `cur-a' is not one of `args-lst-ak'
1187 ;; assume user is entering an unknown key
1188 ;; referenced in last position in signature.
1189 (other-key-arg (and (stringp cur-a)
1190 args-lst-ak
1191 (not (member (upcase cur-a) args-lst-ak))
1192 (upcase (car (last args-lst-ak))))))
1193 (unless (string= cur-w sym-name)
1194 ;; The last keyword have already a value
1195 ;; i.e :foo a b and cursor is at b.
1196 ;; If signature have also `&rest'
1197 ;; (assume it is after the `&key' section)
1198 ;; go to the arg after `&rest'.
1199 (if (and key-have-value
1200 (save-excursion
1201 (not (re-search-forward ":.*" (point-at-eol) t)))
1202 (string-match "&rest \\([^ ()]*\\)" args))
1203 (setq index nil ; Skip next block based on positional args.
1204 start (match-beginning 1)
1205 end (match-end 1))
1206 ;; If `cur-a' is nil probably cursor is on a positional arg
1207 ;; before `&key', in this case, exit this block and determine
1208 ;; position with `index'.
1209 (when (and cur-a ; A keyword arg (dot removed) or nil.
1210 (or (string-match
1211 (concat "\\_<" (upcase cur-a) "\\_>") args)
1212 (string-match
1213 (concat "\\_<" other-key-arg "\\_>") args)))
1214 (setq index nil ; Skip next block based on positional args.
1215 start (match-beginning 0)
1216 end (match-end 0)))))))
1217 ;; Handle now positional arguments.
1218 (while (and index (>= index 1))
1219 (if (string-match "[^ ()]+" args end)
1220 (progn
1221 (setq start (match-beginning 0)
1222 end (match-end 0))
1223 (let ((argument (match-string 0 args)))
1224 (cond ((string= argument "&rest")
1225 ;; All the rest arguments are the same.
1226 (setq index 1))
1227 ((string= argument "&optional")) ; Skip.
1228 ((string= argument "&allow-other-keys")) ; Skip.
1229 ;; Back to index 0 in ARG1 ARG2 ARG2 ARG3 etc...
1230 ;; like in `setq'.
1231 ((or (and (string-match-p "\\.\\.\\.$" argument)
1232 (string= argument (car (last args-lst))))
1233 (and (string-match-p "\\.\\.\\.$"
1234 (substring args 1 (1- (length args))))
1235 (= (length (remove "..." args-lst)) 2)
1236 (> index 1) (eq (logand index 1) 1)))
1237 (setq index 0))
1238 (t
1239 (setq index (1- index))))))
1240 (setq end (length args)
1241 start (1- end)
1242 argument-face 'font-lock-warning-face
1243 index 0)))
1244 (let ((doc args))
1245 (when start
1246 (setq doc (copy-sequence args))
1247 (add-text-properties start end (list 'face argument-face) doc))
1248 (setq doc (elisp--docstring-format-sym-doc
1249 sym doc (if (functionp sym) 'font-lock-function-name-face
1250 'font-lock-keyword-face)))
1251 doc)))
1252
1253 ;; Return a string containing a brief (one-line) documentation string for
1254 ;; the variable.
1255 (defun elisp--get-var-docstring (sym)
1256 (cond ((not sym) nil)
1257 ((and (eq sym (aref elisp--eldoc-last-data 0))
1258 (eq 'variable (aref elisp--eldoc-last-data 2)))
1259 (aref elisp--eldoc-last-data 1))
1260 (t
1261 (let ((doc (documentation-property sym 'variable-documentation t)))
1262 (when doc
1263 (let ((doc (elisp--docstring-format-sym-doc
1264 sym (elisp--docstring-first-line doc)
1265 'font-lock-variable-name-face)))
1266 (elisp--last-data-store sym doc 'variable)))))))
1267
1268 (defun elisp--last-data-store (symbol doc type)
1269 (aset elisp--eldoc-last-data 0 symbol)
1270 (aset elisp--eldoc-last-data 1 doc)
1271 (aset elisp--eldoc-last-data 2 type)
1272 doc)
1273
1274 ;; Note that any leading `*' in the docstring (which indicates the variable
1275 ;; is a user option) is removed.
1276 (defun elisp--docstring-first-line (doc)
1277 (and (stringp doc)
1278 (substitute-command-keys
1279 (save-match-data
1280 ;; Don't use "^" in the regexp below since it may match
1281 ;; anywhere in the doc-string.
1282 (let ((start (if (string-match "\\`\\*" doc) (match-end 0) 0)))
1283 (cond ((string-match "\n" doc)
1284 (substring doc start (match-beginning 0)))
1285 ((zerop start) doc)
1286 (t (substring doc start))))))))
1287
1288 (defvar eldoc-echo-area-use-multiline-p)
1289
1290 ;; If the entire line cannot fit in the echo area, the symbol name may be
1291 ;; truncated or eliminated entirely from the output to make room for the
1292 ;; description.
1293 (defun elisp--docstring-format-sym-doc (sym doc face)
1294 (save-match-data
1295 (let* ((name (symbol-name sym))
1296 (ea-multi eldoc-echo-area-use-multiline-p)
1297 ;; Subtract 1 from window width since emacs will not write
1298 ;; any chars to the last column, or in later versions, will
1299 ;; cause a wraparound and resize of the echo area.
1300 (ea-width (1- (window-width (minibuffer-window))))
1301 (strip (- (+ (length name) (length ": ") (length doc)) ea-width)))
1302 (cond ((or (<= strip 0)
1303 (eq ea-multi t)
1304 (and ea-multi (> (length doc) ea-width)))
1305 (format "%s: %s" (propertize name 'face face) doc))
1306 ((> (length doc) ea-width)
1307 (substring (format "%s" doc) 0 ea-width))
1308 ((>= strip (length name))
1309 (format "%s" doc))
1310 (t
1311 ;; Show the end of the partial symbol name, rather
1312 ;; than the beginning, since the former is more likely
1313 ;; to be unique given package namespace conventions.
1314 (setq name (substring name strip))
1315 (format "%s: %s" (propertize name 'face face) doc))))))
1316
1317 \f
1318 ;; Return a list of current function name and argument index.
1319 (defun elisp--fnsym-in-current-sexp ()
1320 (save-excursion
1321 (let ((argument-index (1- (elisp--beginning-of-sexp))))
1322 ;; If we are at the beginning of function name, this will be -1.
1323 (when (< argument-index 0)
1324 (setq argument-index 0))
1325 ;; Don't do anything if current word is inside a string.
1326 (if (= (or (char-after (1- (point))) 0) ?\")
1327 nil
1328 (list (elisp--current-symbol) argument-index)))))
1329
1330 ;; Move to the beginning of current sexp. Return the number of nested
1331 ;; sexp the point was over or after.
1332 (defun elisp--beginning-of-sexp ()
1333 (let ((parse-sexp-ignore-comments t)
1334 (num-skipped-sexps 0))
1335 (condition-case _
1336 (progn
1337 ;; First account for the case the point is directly over a
1338 ;; beginning of a nested sexp.
1339 (condition-case _
1340 (let ((p (point)))
1341 (forward-sexp -1)
1342 (forward-sexp 1)
1343 (when (< (point) p)
1344 (setq num-skipped-sexps 1)))
1345 (error))
1346 (while
1347 (let ((p (point)))
1348 (forward-sexp -1)
1349 (when (< (point) p)
1350 (setq num-skipped-sexps (1+ num-skipped-sexps))))))
1351 (error))
1352 num-skipped-sexps))
1353
1354 ;; returns nil unless current word is an interned symbol.
1355 (defun elisp--current-symbol ()
1356 (let ((c (char-after (point))))
1357 (and c
1358 (memq (char-syntax c) '(?w ?_))
1359 (intern-soft (current-word)))))
1360
1361 (defun elisp--function-argstring (arglist)
1362 "Return ARGLIST as a string enclosed by ().
1363 ARGLIST is either a string, or a list of strings or symbols."
1364 (let ((str (cond ((stringp arglist) arglist)
1365 ((not (listp arglist)) nil)
1366 (t (format "%S" (help-make-usage 'toto arglist))))))
1367 (if (and str (string-match "\\`([^ )]+ ?" str))
1368 (replace-match "(" t t str)
1369 str)))
1370
1371 (provide 'elisp-mode)
1372 ;;; elisp-mode.el ends here