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