Remove some function declarations, no longer needed or correct
[bpt/emacs.git] / lisp / help-fns.el
CommitLineData
2fbc1934 1;;; help-fns.el --- Complex help functions -*- lexical-binding: t -*-
1113ff44 2
6da8d069 3;; Copyright (C) 1985-1986, 1993-1994, 1998-2014 Free Software Foundation, Inc.
1113ff44 4
34dc21db 5;; Maintainer: emacs-devel@gnu.org
1113ff44 6;; Keywords: help, internal
bd78fa1d 7;; Package: emacs
1113ff44
MR
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;; This file contains those help commands which are complicated, and
27;; which may not be used in every session. For example
28;; `describe-function' will probably be heavily used when doing elisp
29;; programming, but not if just editing C files. Simpler help commands
30;; are in help.el
31
32;;; Code:
33
abb82152
DE
34(defvar help-fns-describe-function-functions nil
35 "List of functions to run in help buffer in `describe-function'.
36Those functions will be run after the header line and argument
37list was inserted, and before the documentation will be inserted.
38The functions will receive the function name as argument.")
39
1113ff44
MR
40;; Functions
41
42;;;###autoload
43(defun describe-function (function)
44 "Display the full documentation of FUNCTION (a symbol)."
45 (interactive
46 (let ((fn (function-called-at-point))
47 (enable-recursive-minibuffers t)
48 val)
49 (setq val (completing-read (if fn
50 (format "Describe function (default %s): " fn)
51 "Describe function: ")
52 obarray 'fboundp t nil nil
53 (and fn (symbol-name fn))))
54 (list (if (equal val "")
55 fn (intern val)))))
56 (if (null function)
57 (message "You didn't specify a function")
32226619
JB
58 (help-setup-xref (list #'describe-function function)
59 (called-interactively-p 'interactive))
1113ff44
MR
60 (save-excursion
61 (with-help-window (help-buffer)
62 (prin1 function)
63 ;; Use " is " instead of a colon so that
64 ;; it is easier to get out the function name using forward-sexp.
65 (princ " is ")
66 (describe-function-1 function)
67 (with-current-buffer standard-output
68 ;; Return the text we displayed.
69 (buffer-string))))))
70
1113ff44
MR
71
72;; Could be this, if we make symbol-file do the work below.
73;; (defun help-C-file-name (subr-or-var kind)
74;; "Return the name of the C file where SUBR-OR-VAR is defined.
75;; KIND should be `var' for a variable or `subr' for a subroutine."
76;; (symbol-file (if (symbolp subr-or-var) subr-or-var
77;; (subr-name subr-or-var))
78;; (if (eq kind 'var) 'defvar 'defun)))
79;;;###autoload
80(defun help-C-file-name (subr-or-var kind)
81 "Return the name of the C file where SUBR-OR-VAR is defined.
82KIND should be `var' for a variable or `subr' for a subroutine."
83 (let ((docbuf (get-buffer-create " *DOC*"))
84 (name (if (eq 'var kind)
85 (concat "V" (symbol-name subr-or-var))
70e5a261 86 (concat "F" (subr-name (advice--cd*r subr-or-var))))))
1113ff44
MR
87 (with-current-buffer docbuf
88 (goto-char (point-min))
89 (if (eobp)
90 (insert-file-contents-literally
91 (expand-file-name internal-doc-file-name doc-directory)))
92 (let ((file (catch 'loop
93 (while t
94 (let ((pnt (search-forward (concat "\1f" name "\n"))))
95 (re-search-backward "\1fS\\(.*\\)")
96 (let ((file (match-string 1)))
97 (if (member file build-files)
98 (throw 'loop file)
99 (goto-char pnt))))))))
100 (if (string-match "^ns.*\\(\\.o\\|obj\\)\\'" file)
101 (setq file (replace-match ".m" t t file 1))
102 (if (string-match "\\.\\(o\\|obj\\)\\'" file)
103 (setq file (replace-match ".c" t t file))))
104 (if (string-match "\\.\\(c\\|m\\)\\'" file)
105 (concat "src/" file)
106 file)))))
107
1659ada0
JB
108(defcustom help-downcase-arguments nil
109 "If non-nil, argument names in *Help* buffers are downcased."
110 :type 'boolean
111 :group 'help
112 :version "23.2")
113
114(defun help-highlight-arg (arg)
115 "Highlight ARG as an argument name for a *Help* buffer.
116Return ARG in face `help-argument-name'; ARG is also downcased
117if the variable `help-downcase-arguments' is non-nil."
118 (propertize (if help-downcase-arguments (downcase arg) arg)
119 'face 'help-argument-name))
1113ff44
MR
120
121(defun help-do-arg-highlight (doc args)
122 (with-syntax-table (make-syntax-table emacs-lisp-mode-syntax-table)
123 (modify-syntax-entry ?\- "w")
2462470b 124 (dolist (arg args)
1113ff44
MR
125 (setq doc (replace-regexp-in-string
126 ;; This is heuristic, but covers all common cases
127 ;; except ARG1-ARG2
128 (concat "\\<" ; beginning of word
129 "\\(?:[a-z-]*-\\)?" ; for xxx-ARG
130 "\\("
131 (regexp-quote arg)
132 "\\)"
133 "\\(?:es\\|s\\|th\\)?" ; for ARGth, ARGs
134 "\\(?:-[a-z0-9-]+\\)?" ; for ARG-xxx, ARG-n
135 "\\(?:-[{([<`\"].*?\\)?"; for ARG-{x}, (x), <x>, [x], `x'
136 "\\>") ; end of word
1659ada0 137 (help-highlight-arg arg)
2462470b
SM
138 doc t t 1)))
139 doc))
1113ff44
MR
140
141(defun help-highlight-arguments (usage doc &rest args)
b9598260 142 (when (and usage (string-match "^(" usage))
1113ff44
MR
143 (with-temp-buffer
144 (insert usage)
145 (goto-char (point-min))
146 (let ((case-fold-search nil)
147 (next (not (or args (looking-at "\\["))))
148 (opt nil))
149 ;; Make a list of all arguments
150 (skip-chars-forward "^ ")
151 (while next
152 (or opt (not (looking-at " &")) (setq opt t))
153 (if (not (re-search-forward " \\([\\[(]*\\)\\([^] &)\.]+\\)" nil t))
154 (setq next nil)
155 (setq args (cons (match-string 2) args))
156 (when (and opt (string= (match-string 1) "("))
157 ;; A pesky CL-style optional argument with default value,
158 ;; so let's skip over it
159 (search-backward "(")
160 (goto-char (scan-sexps (point) 1)))))
91af3942 161 ;; Highlight arguments in the USAGE string
1113ff44
MR
162 (setq usage (help-do-arg-highlight (buffer-string) args))
163 ;; Highlight arguments in the DOC string
164 (setq doc (and doc (help-do-arg-highlight doc args))))))
165 ;; Return value is like the one from help-split-fundoc, but highlighted
166 (cons usage doc))
167
168;; The following function was compiled from the former functions
169;; `describe-simplify-lib-file-name' and `find-source-lisp-file' with
170;; some excerpts from `describe-function-1' and `describe-variable'.
171;; The only additional twists provided are (1) locate the defining file
172;; for autoloaded functions, and (2) give preference to files in the
173;; "install directory" (directories found via `load-path') rather than
174;; to files in the "compile directory" (directories found by searching
175;; the loaddefs.el file). We autoload it because it's also used by
176;; `describe-face' (instead of `describe-simplify-lib-file-name').
177
178;;;###autoload
179(defun find-lisp-object-file-name (object type)
180 "Guess the file that defined the Lisp object OBJECT, of type TYPE.
181OBJECT should be a symbol associated with a function, variable, or face;
182 alternatively, it can be a function definition.
fe4be04c
JB
183If TYPE is `defvar', search for a variable definition.
184If TYPE is `defface', search for a face definition.
1113ff44
MR
185If TYPE is the value returned by `symbol-function' for a function symbol,
186 search for a function definition.
187
188The return value is the absolute name of a readable file where OBJECT is
189defined. If several such files exist, preference is given to a file
190found via `load-path'. The return value can also be `C-source', which
191means that OBJECT is a function or variable defined in C. If no
192suitable file is found, return nil."
7abaf5cc 193 (let* ((autoloaded (autoloadp type))
1113ff44
MR
194 (file-name (or (and autoloaded (nth 1 type))
195 (symbol-file
196 object (if (memq type (list 'defvar 'defface))
197 type
198 'defun)))))
199 (cond
200 (autoloaded
201 ;; An autoloaded function: Locate the file since `symbol-function'
202 ;; has only returned a bare string here.
203 (setq file-name
204 (locate-file file-name load-path '(".el" ".elc") 'readable)))
205 ((and (stringp file-name)
206 (string-match "[.]*loaddefs.el\\'" file-name))
207 ;; An autoloaded variable or face. Visit loaddefs.el in a buffer
208 ;; and try to extract the defining file. The following form is
209 ;; from `describe-function-1' and `describe-variable'.
210 (let ((location
211 (condition-case nil
212 (find-function-search-for-symbol object nil file-name)
213 (error nil))))
6565b5ab 214 (when (cdr location)
1113ff44
MR
215 (with-current-buffer (car location)
216 (goto-char (cdr location))
217 (when (re-search-backward
218 "^;;; Generated autoloads from \\(.*\\)" nil t)
219 (setq file-name
220 (locate-file
273cefaa
GM
221 (file-name-sans-extension
222 (match-string-no-properties 1))
223 load-path '(".el" ".elc") 'readable))))))))
1113ff44
MR
224
225 (cond
226 ((and (not file-name) (subrp type))
227 ;; A built-in function. The form is from `describe-function-1'.
228 (if (get-buffer " *DOC*")
229 (help-C-file-name type 'subr)
230 'C-source))
231 ((and (not file-name) (symbolp object)
232 (integerp (get object 'variable-documentation)))
233 ;; A variable defined in C. The form is from `describe-variable'.
234 (if (get-buffer " *DOC*")
235 (help-C-file-name object 'var)
236 'C-source))
237 ((not (stringp file-name))
238 ;; If we don't have a file-name string by now, we lost.
239 nil)
d78cdcf7 240 ;; Now, `file-name' should have become an absolute file name.
6a378d89
GM
241 ;; For files loaded from ~/.foo.elc, try ~/.foo.
242 ;; This applies to config files like ~/.emacs,
243 ;; which people sometimes compile.
d78cdcf7 244 ((let (fn)
6a378d89
GM
245 (and (string-match "\\`\\..*\\.elc\\'"
246 (file-name-nondirectory file-name))
247 (string-equal (file-name-directory file-name)
248 (file-name-as-directory (expand-file-name "~")))
249 (file-readable-p (setq fn (file-name-sans-extension file-name)))
d78cdcf7
CY
250 fn)))
251 ;; When the Elisp source file can be found in the install
252 ;; directory, return the name of that file.
1113ff44
MR
253 ((let ((lib-name
254 (if (string-match "[.]elc\\'" file-name)
255 (substring-no-properties file-name 0 -1)
256 file-name)))
1113ff44
MR
257 (or (and (file-readable-p lib-name) lib-name)
258 ;; The library might be compressed.
259 (and (file-readable-p (concat lib-name ".gz")) lib-name))))
260 ((let* ((lib-name (file-name-nondirectory file-name))
261 ;; The next form is from `describe-simplify-lib-file-name'.
262 (file-name
263 ;; Try converting the absolute file name to a library
264 ;; name, convert that back to a file name and see if we
265 ;; get the original one. If so, they are equivalent.
266 (if (equal file-name (locate-file lib-name load-path '("")))
267 (if (string-match "[.]elc\\'" lib-name)
268 (substring-no-properties lib-name 0 -1)
269 lib-name)
270 file-name))
271 ;; The next three forms are from `find-source-lisp-file'.
272 (elc-file (locate-file
273 (concat file-name
274 (if (string-match "\\.el\\'" file-name)
275 "c"
276 ".elc"))
277 load-path nil 'readable))
278 (str (when elc-file
279 (with-temp-buffer
280 (insert-file-contents-literally elc-file nil 0 256)
281 (buffer-string))))
282 (src-file (and str
283 (string-match ";;; from file \\(.*\\.el\\)" str)
284 (match-string 1 str))))
285 (and src-file (file-readable-p src-file) src-file))))))
286
f91b35be
SM
287(defun help-fns--key-bindings (function)
288 (when (commandp function)
289 (let ((pt2 (with-current-buffer standard-output (point)))
290 (remapped (command-remapping function)))
291 (unless (memq remapped '(ignore undefined))
292 (let ((keys (where-is-internal
293 (or remapped function) overriding-local-map nil nil))
294 non-modified-keys)
295 (if (and (eq function 'self-insert-command)
296 (vectorp (car-safe keys))
297 (consp (aref (car keys) 0)))
298 (princ "It is bound to many ordinary text characters.\n")
299 ;; Which non-control non-meta keys run this command?
300 (dolist (key keys)
301 (if (member (event-modifiers (aref key 0)) '(nil (shift)))
302 (push key non-modified-keys)))
303 (when remapped
80a51fa0
CS
304 (princ "Its keys are remapped to ")
305 (princ (if (symbolp remapped)
306 (concat "`" (symbol-name remapped) "'")
307 "an anonymous command"))
308 (princ ".\n"))
f91b35be
SM
309
310 (when keys
311 (princ (if remapped
312 "Without this remapping, it would be bound to "
313 "It is bound to "))
314 ;; If lots of ordinary text characters run this command,
315 ;; don't mention them one by one.
316 (if (< (length non-modified-keys) 10)
317 (princ (mapconcat 'key-description keys ", "))
318 (dolist (key non-modified-keys)
319 (setq keys (delq key keys)))
320 (if keys
321 (progn
322 (princ (mapconcat 'key-description keys ", "))
323 (princ ", and many ordinary text characters"))
324 (princ "many ordinary text characters"))))
325 (when (or remapped keys non-modified-keys)
326 (princ ".")
327 (terpri)))))
328
329 (with-current-buffer standard-output
330 (fill-region-as-paragraph pt2 (point))
331 (unless (looking-back "\n\n")
332 (terpri))))))
333
71adb94b 334(defun help-fns--compiler-macro (function)
f91b35be 335 (let ((handler (function-get function 'compiler-macro)))
71adb94b 336 (when handler
f91b35be 337 (insert "\nThis function has a compiler macro")
cf4e5178
SM
338 (if (symbolp handler)
339 (progn
340 (insert (format " `%s'" handler))
341 (save-excursion
342 (re-search-backward "`\\([^`']+\\)'" nil t)
343 (help-xref-button 1 'help-function handler)))
344 ;; FIXME: Obsolete since 24.4.
345 (let ((lib (get function 'compiler-macro-file)))
346 (when (stringp lib)
347 (insert (format " in `%s'" lib))
348 (save-excursion
349 (re-search-backward "`\\([^`']+\\)'" nil t)
350 (help-xref-button 1 'help-function-cmacro function lib)))))
f91b35be
SM
351 (insert ".\n"))))
352
353(defun help-fns--signature (function doc real-def real-function)
354 (unless (keymapp function) ; If definition is a keymap, skip arglist note.
355 (let* ((advertised (gethash real-def advertised-signature-table t))
356 (arglist (if (listp advertised)
357 advertised (help-function-arglist real-def)))
358 (usage (help-split-fundoc doc function)))
359 (if usage (setq doc (cdr usage)))
360 (let* ((use (cond
361 ((and usage (not (listp advertised))) (car usage))
362 ((listp arglist)
363 (format "%S" (help-make-usage function arglist)))
364 ((stringp arglist) arglist)
365 ;; Maybe the arglist is in the docstring of a symbol
366 ;; this one is aliased to.
367 ((let ((fun real-function))
368 (while (and (symbolp fun)
369 (setq fun (symbol-function fun))
370 (not (setq usage (help-split-fundoc
371 (documentation fun)
372 function)))))
373 usage)
374 (car usage))
375 ((or (stringp real-def)
376 (vectorp real-def))
377 (format "\nMacro: %s" (format-kbd-macro real-def)))
378 (t "[Missing arglist. Please make a bug report.]")))
379 (high (help-highlight-arguments use doc)))
380 (let ((fill-begin (point)))
381 (insert (car high) "\n")
382 (fill-region fill-begin (point)))
383 (cdr high)))))
384
385(defun help-fns--parent-mode (function)
386 ;; If this is a derived mode, link to the parent.
387 (let ((parent-mode (and (symbolp function)
388 (get function
389 'derived-mode-parent))))
390 (when parent-mode
391 (insert "\nParent mode: `")
392 (let ((beg (point)))
393 (insert (format "%s" parent-mode))
394 (make-text-button beg (point)
395 'type 'help-function
396 'help-args (list parent-mode)))
397 (insert "'.\n"))))
398
399(defun help-fns--obsolete (function)
863666eb
CY
400 ;; Ignore lambda constructs, keyboard macros, etc.
401 (let* ((obsolete (and (symbolp function)
402 (get function 'byte-obsolete-info)))
f91b35be
SM
403 (use (car obsolete)))
404 (when obsolete
863666eb 405 (insert "\nThis "
c4c0c2df 406 (if (eq (car-safe (symbol-function function)) 'macro)
863666eb
CY
407 "macro"
408 "function")
409 " is obsolete")
f91b35be
SM
410 (when (nth 2 obsolete)
411 (insert (format " since %s" (nth 2 obsolete))))
412 (insert (cond ((stringp use) (concat ";\n" use))
413 (use (format ";\nuse `%s' instead." use))
414 (t "."))
415 "\n"))))
71adb94b 416
c89926a5
CY
417;; We could use `symbol-file' but this is a wee bit more efficient.
418(defun help-fns--autoloaded-p (function file)
419 "Return non-nil if FUNCTION has previously been autoloaded.
420FILE is the file where FUNCTION was probably defined."
421 (let* ((file (file-name-sans-extension (file-truename file)))
422 (load-hist load-history)
423 (target (cons t function))
424 found)
425 (while (and load-hist (not found))
426 (and (caar load-hist)
427 (equal (file-name-sans-extension (caar load-hist)) file)
428 (setq found (member target (cdar load-hist))))
429 (setq load-hist (cdr load-hist)))
430 found))
431
1113ff44
MR
432;;;###autoload
433(defun describe-function-1 (function)
faec28d9
TH
434 (let* ((advised (and (symbolp function)
435 (featurep 'nadvice)
436 (advice--p (advice--symbol-function function))))
1113ff44
MR
437 ;; If the function is advised, use the symbol that has the
438 ;; real definition, if that symbol is already set up.
439 (real-function
440 (or (and advised
70e5a261 441 (advice--cd*r (advice--symbol-function function)))
1113ff44
MR
442 function))
443 ;; Get the real definition.
444 (def (if (symbolp real-function)
445 (symbol-function real-function)
faec28d9
TH
446 real-function))
447 (aliased (or (symbolp def)
448 ;; Advised & aliased function.
449 (and advised (symbolp real-function))))
450 (real-def (cond
451 (aliased (let ((f real-function))
452 (while (and (fboundp f)
453 (symbolp (symbol-function f)))
454 (setq f (symbol-function f)))
455 f))
456 ((subrp def) (intern (subr-name def)))
457 (t def)))
c89926a5 458 (file-name (find-lisp-object-file-name function def))
1113ff44 459 (pt1 (with-current-buffer (help-buffer) (point)))
c89926a5
CY
460 (beg (if (and (or (byte-code-function-p def)
461 (keymapp def)
462 (memq (car-safe def) '(macro lambda closure)))
50f29081 463 (stringp file-name)
c89926a5
CY
464 (help-fns--autoloaded-p function file-name))
465 (if (commandp def)
466 "an interactive autoloaded "
467 "an autoloaded ")
468 (if (commandp def) "an interactive " "a "))))
469
470 ;; Print what kind of function-like object FUNCTION is.
471 (princ (cond ((or (stringp def) (vectorp def))
472 "a keyboard macro")
473 ((subrp def)
474 (if (eq 'unevalled (cdr (subr-arity def)))
475 (concat beg "special form")
476 (concat beg "built-in function")))
faec28d9
TH
477 ;; Aliases are Lisp functions, so we need to check
478 ;; aliases before functions.
c89926a5
CY
479 (aliased
480 (format "an alias for `%s'" real-def))
6da8d069
GM
481 ((autoloadp def)
482 (format "%s autoloaded %s"
483 (if (commandp def) "an interactive" "an")
484 (if (eq (nth 4 def) 'keymap) "keymap"
485 (if (nth 4 def) "Lisp macro" "Lisp function"))))
faec28d9
TH
486 ((or (eq (car-safe def) 'macro)
487 ;; For advised macros, def is a lambda
488 ;; expression or a byte-code-function-p, so we
489 ;; need to check macros before functions.
490 (macrop function))
491 (concat beg "Lisp macro"))
492 ((byte-code-function-p def)
493 (concat beg "compiled Lisp function"))
c89926a5
CY
494 ((eq (car-safe def) 'lambda)
495 (concat beg "Lisp function"))
c89926a5
CY
496 ((eq (car-safe def) 'closure)
497 (concat beg "Lisp closure"))
c89926a5
CY
498 ((keymapp def)
499 (let ((is-full nil)
500 (elts (cdr-safe def)))
501 (while elts
502 (if (char-table-p (car-safe elts))
503 (setq is-full t
504 elts nil))
505 (setq elts (cdr-safe elts)))
506 (concat beg (if is-full "keymap" "sparse keymap"))))
507 (t "")))
508
509 (if (and aliased (not (fboundp real-def)))
1113ff44
MR
510 (princ ",\nwhich is not defined. Please make a bug report.")
511 (with-current-buffer standard-output
512 (save-excursion
513 (save-match-data
514 (when (re-search-backward "alias for `\\([^`']+\\)'" nil t)
c89926a5 515 (help-xref-button 1 'help-function real-def)))))
1113ff44 516
1113ff44
MR
517 (when file-name
518 (princ " in `")
519 ;; We used to add .el to the file name,
520 ;; but that's completely wrong when the user used load-file.
e8e8dbf9
MR
521 (princ (if (eq file-name 'C-source)
522 "C source code"
523 (file-name-nondirectory file-name)))
1113ff44
MR
524 (princ "'")
525 ;; Make a hyperlink to the library.
526 (with-current-buffer standard-output
527 (save-excursion
528 (re-search-backward "`\\([^`']+\\)'" nil t)
cebabb67 529 (help-xref-button 1 'help-function-def function file-name))))
1113ff44
MR
530 (princ ".")
531 (with-current-buffer (help-buffer)
532 (fill-region-as-paragraph (save-excursion (goto-char pt1) (forward-line 0) (point))
533 (point)))
534 (terpri)(terpri)
863666eb 535
06485aa8 536 (let* ((doc-raw (documentation function t))
c89926a5
CY
537 ;; If the function is autoloaded, and its docstring has
538 ;; key substitution constructs, load the library.
539 (doc (progn
d8cc4c00 540 (and (autoloadp real-def) doc-raw
c89926a5
CY
541 help-enable-auto-load
542 (string-match "\\([^\\]=\\|[^=]\\|\\`\\)\\\\[[{<]"
543 doc-raw)
544 (load (cadr real-def) t))
f91b35be
SM
545 (substitute-command-keys doc-raw))))
546
547 (help-fns--key-bindings function)
548 (with-current-buffer standard-output
549 (setq doc (help-fns--signature function doc real-def real-function))
abb82152 550 (run-hook-with-args 'help-fns-describe-function-functions function)
f91b35be
SM
551 (insert "\n"
552 (or doc "Not documented.")))))))
1113ff44 553
abb82152 554;; Add defaults to `help-fns-describe-function-functions'.
70e5a261
SM
555(add-hook 'help-fns-describe-function-functions #'help-fns--obsolete)
556(add-hook 'help-fns-describe-function-functions #'help-fns--parent-mode)
557(add-hook 'help-fns-describe-function-functions #'help-fns--compiler-macro)
abb82152 558
1113ff44
MR
559\f
560;; Variables
561
562;;;###autoload
563(defun variable-at-point (&optional any-symbol)
564 "Return the bound variable symbol found at or before point.
565Return 0 if there is no such symbol.
566If ANY-SYMBOL is non-nil, don't insist the symbol be bound."
567 (with-syntax-table emacs-lisp-mode-syntax-table
568 (or (condition-case ()
569 (save-excursion
047b2bb9 570 (skip-chars-forward "'")
1113ff44
MR
571 (or (not (zerop (skip-syntax-backward "_w")))
572 (eq (char-syntax (following-char)) ?w)
573 (eq (char-syntax (following-char)) ?_)
574 (forward-sexp -1))
575 (skip-chars-forward "'")
576 (let ((obj (read (current-buffer))))
577 (and (symbolp obj) (boundp obj) obj)))
578 (error nil))
579 (let* ((str (find-tag-default))
580 (sym (if str (intern-soft str))))
581 (if (and sym (or any-symbol (boundp sym)))
582 sym
583 (save-match-data
584 (when (and str (string-match "\\`\\W*\\(.*?\\)\\W*\\'" str))
585 (setq sym (intern-soft (match-string 1 str)))
586 (and (or any-symbol (boundp sym)) sym)))))
587 0)))
588
589(defun describe-variable-custom-version-info (variable)
590 (let ((custom-version (get variable 'custom-version))
591 (cpv (get variable 'custom-package-version))
592 (output nil))
593 (if custom-version
594 (setq output
595 (format "This variable was introduced, or its default value was changed, in\nversion %s of Emacs.\n"
596 custom-version))
597 (when cpv
598 (let* ((package (car-safe cpv))
599 (version (if (listp (cdr-safe cpv))
600 (car (cdr-safe cpv))
601 (cdr-safe cpv)))
602 (pkg-versions (assq package customize-package-emacs-version-alist))
603 (emacsv (cdr (assoc version pkg-versions))))
604 (if (and package version)
605 (setq output
606 (format (concat "This variable was introduced, or its default value was changed, in\nversion %s of the %s package"
607 (if emacsv
608 (format " that is part of Emacs %s" emacsv))
609 ".\n")
610 version package))))))
611 output))
612
613;;;###autoload
614(defun describe-variable (variable &optional buffer frame)
615 "Display the full documentation of VARIABLE (a symbol).
616Returns the documentation as a string, also.
617If VARIABLE has a buffer-local value in BUFFER or FRAME
618\(default to the current buffer and current frame),
619it is displayed along with the global value."
620 (interactive
621 (let ((v (variable-at-point))
622 (enable-recursive-minibuffers t)
623 val)
624 (setq val (completing-read (if (symbolp v)
625 (format
626 "Describe variable (default %s): " v)
627 "Describe variable: ")
628 obarray
ba83908c 629 (lambda (vv)
8d17e7ca 630 (or (get vv 'variable-documentation)
6f4e1aed 631 (and (boundp vv) (not (keywordp vv)))))
1113ff44
MR
632 t nil nil
633 (if (symbolp v) (symbol-name v))))
634 (list (if (equal val "")
635 v (intern val)))))
636 (let (file-name)
637 (unless (buffer-live-p buffer) (setq buffer (current-buffer)))
638 (unless (frame-live-p frame) (setq frame (selected-frame)))
639 (if (not (symbolp variable))
640 (message "You did not specify a variable")
641 (save-excursion
642 (let ((valvoid (not (with-current-buffer buffer (boundp variable))))
f0422feb 643 (permanent-local (get variable 'permanent-local))
1113ff44
MR
644 val val-start-pos locus)
645 ;; Extract the value before setting up the output buffer,
646 ;; in case `buffer' *is* the output buffer.
647 (unless valvoid
648 (with-selected-frame frame
649 (with-current-buffer buffer
650 (setq val (symbol-value variable)
651 locus (variable-binding-locus variable)))))
652 (help-setup-xref (list #'describe-variable variable buffer)
32226619 653 (called-interactively-p 'interactive))
1113ff44
MR
654 (with-help-window (help-buffer)
655 (with-current-buffer buffer
656 (prin1 variable)
657 (setq file-name (find-lisp-object-file-name variable 'defvar))
658
659 (if file-name
660 (progn
661 (princ " is a variable defined in `")
e8e8dbf9
MR
662 (princ (if (eq file-name 'C-source)
663 "C source code"
664 (file-name-nondirectory file-name)))
1113ff44
MR
665 (princ "'.\n")
666 (with-current-buffer standard-output
667 (save-excursion
668 (re-search-backward "`\\([^`']+\\)'" nil t)
669 (help-xref-button 1 'help-variable-def
670 variable file-name)))
671 (if valvoid
672 (princ "It is void as a variable.")
673 (princ "Its ")))
674 (if valvoid
675 (princ " is void as a variable.")
676 (princ "'s "))))
3c505d31 677 (unless valvoid
1113ff44
MR
678 (with-current-buffer standard-output
679 (setq val-start-pos (point))
680 (princ "value is ")
6c1e4b46
CY
681 (let ((from (point))
682 (line-beg (line-beginning-position))
6c1e4b46
CY
683 (print-rep
684 (let ((print-quoted t))
685 (prin1-to-string val))))
686 (if (< (+ (length print-rep) (point) (- line-beg)) 68)
687 (insert print-rep)
688 (terpri)
689 (pp val)
690 (if (< (point) (+ 68 (line-beginning-position 0)))
691 (delete-region from (1+ from))
692 (delete-region (1- from) from)))
0097720d
SM
693 (let* ((sv (get variable 'standard-value))
694 (origval (and (consp sv)
695 (condition-case nil
696 (eval (car sv))
697 (error :help-eval-error)))))
698 (when (and (consp sv)
699 (not (equal origval val))
700 (not (equal origval :help-eval-error)))
701 (princ "\nOriginal value was \n")
702 (setq from (point))
703 (pp origval)
704 (if (< (point) (+ from 20))
705 (delete-region (1- from) from)))))))
1113ff44 706 (terpri)
1113ff44 707 (when locus
e2b551c5
SM
708 (cond
709 ((bufferp locus)
f0422feb 710 (princ (format "Local in buffer %s; "
f5733f87 711 (buffer-name buffer))))
e2b551c5
SM
712 ((framep locus)
713 (princ (format "It is a frame-local variable; ")))
714 ((terminal-live-p locus)
715 (princ (format "It is a terminal-local variable; ")))
716 (t
717 (princ (format "It is local to %S" locus))))
1113ff44
MR
718 (if (not (default-boundp variable))
719 (princ "globally void")
f0422feb 720 (let ((global-val (default-value variable)))
1113ff44
MR
721 (with-current-buffer standard-output
722 (princ "global value is ")
f0422feb
CY
723 (if (eq val global-val)
724 (princ "the same.")
725 (terpri)
726 ;; Fixme: pp can take an age if you happen to
727 ;; ask for a very large expression. We should
728 ;; probably print it raw once and check it's a
729 ;; sensible size before prettyprinting. -- fx
730 (let ((from (point)))
731 (pp global-val)
732 ;; See previous comment for this function.
733 ;; (help-xref-on-pp from (point))
734 (if (< (point) (+ from 20))
735 (delete-region (1- from) from)))))))
1113ff44
MR
736 (terpri))
737
738 ;; If the value is large, move it to the end.
739 (with-current-buffer standard-output
740 (when (> (count-lines (point-min) (point-max)) 10)
741 ;; Note that setting the syntax table like below
742 ;; makes forward-sexp move over a `'s' at the end
743 ;; of a symbol.
744 (set-syntax-table emacs-lisp-mode-syntax-table)
745 (goto-char val-start-pos)
746 ;; The line below previously read as
747 ;; (delete-region (point) (progn (end-of-line) (point)))
748 ;; which suppressed display of the buffer local value for
749 ;; large values.
750 (when (looking-at "value is") (replace-match ""))
751 (save-excursion
752 (insert "\n\nValue:")
753 (set (make-local-variable 'help-button-cache)
754 (point-marker)))
755 (insert "value is shown ")
756 (insert-button "below"
757 'action help-button-cache
758 'follow-link t
759 'help-echo "mouse-2, RET: show value")
760 (insert ".\n")))
761 (terpri)
762
763 (let* ((alias (condition-case nil
764 (indirect-variable variable)
765 (error variable)))
766 (obsolete (get variable 'byte-obsolete-variable))
767 (use (car obsolete))
768 (safe-var (get variable 'safe-local-variable))
06485aa8
SM
769 (doc (or (documentation-property
770 variable 'variable-documentation)
771 (documentation-property
772 alias 'variable-documentation)))
1113ff44 773 (extra-line nil))
f0422feb
CY
774
775 ;; Mention if it's a local variable.
776 (cond
777 ((and (local-variable-if-set-p variable)
778 (or (not (local-variable-p variable))
779 (with-temp-buffer
780 (local-variable-if-set-p variable))))
1113ff44 781 (setq extra-line t)
dea31bd3 782 (princ " Automatically becomes ")
f0422feb 783 (if permanent-local
dea31bd3
CY
784 (princ "permanently "))
785 (princ "buffer-local when set.\n"))
f0422feb
CY
786 ((not permanent-local))
787 ((bufferp locus)
05e7ce90 788 (setq extra-line t)
f0422feb
CY
789 (princ " This variable's buffer-local value is permanent.\n"))
790 (t
05e7ce90 791 (setq extra-line t)
f0422feb
CY
792 (princ " This variable's value is permanent \
793if it is given a local binding.\n")))
794
795 ;; Mention if it's an alias.
1113ff44
MR
796 (unless (eq alias variable)
797 (setq extra-line t)
798 (princ (format " This variable is an alias for `%s'.\n" alias)))
799
800 (when obsolete
801 (setq extra-line t)
802 (princ " This variable is obsolete")
2403c841
SM
803 (if (nth 2 obsolete)
804 (princ (format " since %s" (nth 2 obsolete))))
1113ff44
MR
805 (princ (cond ((stringp use) (concat ";\n " use))
806 (use (format ";\n use `%s' instead." (car obsolete)))
807 (t ".")))
808 (terpri))
2ee20f24 809
dd8e49fd
GM
810 (when (member (cons variable val)
811 (with-current-buffer buffer
812 file-local-variables-alist))
2ee20f24 813 (setq extra-line t)
dd8e49fd
GM
814 (if (member (cons variable val)
815 (with-current-buffer buffer
816 dir-local-variables-alist))
817 (let ((file (and (buffer-file-name buffer)
818 (not (file-remote-p
819 (buffer-file-name buffer)))
303f9ae0 820 (dir-locals-find-file
dd8e49fd 821 (buffer-file-name buffer))))
f0422feb
CY
822 (dir-file t))
823 (princ " This variable's value is directory-local")
824 (if (null file)
825 (princ ".\n")
826 (princ ", set ")
303f9ae0
GM
827 (if (consp file) ; result from cache
828 ;; If the cache element has an mtime, we
829 ;; assume it came from a file.
830 (if (nth 2 file)
831 (setq file (expand-file-name
832 dir-locals-file (car file)))
833 ;; Otherwise, assume it was set directly.
7e088b29
IL
834 (setq file (car file)
835 dir-file nil)))
f0422feb
CY
836 (princ (if dir-file
837 "by the file\n `"
838 "for the directory\n `"))
839 (with-current-buffer standard-output
840 (insert-text-button
841 file 'type 'help-dir-local-var-def
842 'help-args (list variable file)))
843 (princ "'.\n")))
844 (princ " This variable's value is file-local.\n")))
2ee20f24 845
589a99f2
GM
846 (when (memq variable ignored-local-variables)
847 (setq extra-line t)
f0422feb 848 (princ " This variable is ignored as a file-local \
589a99f2
GM
849variable.\n"))
850
851 ;; Can be both risky and safe, eg auto-fill-function.
852 (when (risky-local-variable-p variable)
853 (setq extra-line t)
f0422feb
CY
854 (princ " This variable may be risky if used as a \
855file-local variable.\n")
589a99f2
GM
856 (when (assq variable safe-local-variable-values)
857 (princ " However, you have added it to \
858`safe-local-variable-values'.\n")))
859
1113ff44
MR
860 (when safe-var
861 (setq extra-line t)
862 (princ " This variable is safe as a file local variable ")
863 (princ "if its value\n satisfies the predicate ")
864 (princ (if (byte-code-function-p safe-var)
04e8abfa 865 "which is a byte-compiled expression.\n"
1113ff44
MR
866 (format "`%s'.\n" safe-var))))
867
868 (if extra-line (terpri))
869 (princ "Documentation:\n")
870 (with-current-buffer standard-output
871 (insert (or doc "Not documented as a variable."))))
872
873 ;; Make a link to customize if this variable can be customized.
874 (when (custom-variable-p variable)
875 (let ((customize-label "customize"))
876 (terpri)
877 (terpri)
878 (princ (concat "You can " customize-label " this variable."))
879 (with-current-buffer standard-output
880 (save-excursion
881 (re-search-backward
882 (concat "\\(" customize-label "\\)") nil t)
883 (help-xref-button 1 'help-customize-variable variable))))
884 ;; Note variable's version or package version
885 (let ((output (describe-variable-custom-version-info variable)))
886 (when output
887 (terpri)
888 (terpri)
889 (princ output))))
890
7fdbcd83 891 (with-current-buffer standard-output
1113ff44
MR
892 ;; Return the text we displayed.
893 (buffer-string))))))))
894
895
896;;;###autoload
897(defun describe-syntax (&optional buffer)
898 "Describe the syntax specifications in the syntax table of BUFFER.
899The descriptions are inserted in a help buffer, which is then displayed.
900BUFFER defaults to the current buffer."
901 (interactive)
902 (setq buffer (or buffer (current-buffer)))
32226619
JB
903 (help-setup-xref (list #'describe-syntax buffer)
904 (called-interactively-p 'interactive))
1113ff44
MR
905 (with-help-window (help-buffer)
906 (let ((table (with-current-buffer buffer (syntax-table))))
907 (with-current-buffer standard-output
908 (describe-vector table 'internal-describe-syntax-value)
909 (while (setq table (char-table-parent table))
910 (insert "\nThe parent syntax table is:")
911 (describe-vector table 'internal-describe-syntax-value))))))
912
913(defun help-describe-category-set (value)
914 (insert (cond
915 ((null value) "default")
916 ((char-table-p value) "deeper char-table ...")
2fbc1934 917 (t (condition-case nil
1113ff44
MR
918 (category-set-mnemonics value)
919 (error "invalid"))))))
920
921;;;###autoload
922(defun describe-categories (&optional buffer)
923 "Describe the category specifications in the current category table.
924The descriptions are inserted in a buffer, which is then displayed.
925If BUFFER is non-nil, then describe BUFFER's category table instead.
926BUFFER should be a buffer or a buffer name."
927 (interactive)
928 (setq buffer (or buffer (current-buffer)))
32226619
JB
929 (help-setup-xref (list #'describe-categories buffer)
930 (called-interactively-p 'interactive))
1113ff44 931 (with-help-window (help-buffer)
c6ec96f8
KH
932 (let* ((table (with-current-buffer buffer (category-table)))
933 (docs (char-table-extra-slot table 0)))
934 (if (or (not (vectorp docs)) (/= (length docs) 95))
935 (error "Invalid first extra slot in this category table\n"))
1113ff44 936 (with-current-buffer standard-output
c6ec96f8
KH
937 (insert "Legend of category mnemonics (see the tail for the longer description)\n")
938 (let ((pos (point)) (items 0) lines n)
939 (dotimes (i 95)
940 (if (aref docs i) (setq items (1+ items))))
941 (setq lines (1+ (/ (1- items) 4)))
942 (setq n 0)
943 (dotimes (i 95)
944 (let ((elt (aref docs i)))
945 (when elt
946 (string-match ".*" elt)
947 (setq elt (match-string 0 elt))
948 (if (>= (length elt) 17)
949 (setq elt (concat (substring elt 0 14) "...")))
950 (if (< (point) (point-max))
951 (move-to-column (* 20 (/ n lines)) t))
952 (insert (+ i ?\s) ?: elt)
953 (if (< (point) (point-max))
954 (forward-line 1)
955 (insert "\n"))
956 (setq n (1+ n))
957 (if (= (% n lines) 0)
958 (goto-char pos))))))
959 (goto-char (point-max))
960 (insert "\n"
961 "character(s)\tcategory mnemonics\n"
962 "------------\t------------------")
1113ff44 963 (describe-vector table 'help-describe-category-set)
c6ec96f8
KH
964 (insert "Legend of category mnemonics:\n")
965 (dotimes (i 95)
966 (let ((elt (aref docs i)))
967 (when elt
968 (if (string-match "\n" elt)
969 (setq elt (substring elt (match-end 0))))
970 (insert (+ i ?\s) ": " elt "\n"))))
971 (while (setq table (char-table-parent table))
972 (insert "\nThe parent category table is:")
973 (describe-vector table 'help-describe-category-set))))))
1113ff44 974
17284e30
GM
975\f
976;;; Replacements for old lib-src/ programs. Don't seem especially useful.
977
978;; Replaces lib-src/digest-doc.c.
979;;;###autoload
980(defun doc-file-to-man (file)
981 "Produce an nroff buffer containing the doc-strings from the DOC file."
982 (interactive (list (read-file-name "Name of DOC file: " doc-directory
983 internal-doc-file-name t)))
984 (or (file-readable-p file)
985 (error "Cannot read file `%s'" file))
986 (pop-to-buffer (generate-new-buffer "*man-doc*"))
987 (setq buffer-undo-list t)
988 (insert ".TH \"Command Summary for GNU Emacs\"\n"
989 ".AU Richard M. Stallman\n")
990 (insert-file-contents file)
991 (let (notfirst)
992 (while (search-forward "\1f" nil 'move)
993 (if (looking-at "S")
994 (delete-region (1- (point)) (line-end-position))
995 (delete-char -1)
996 (if notfirst
997 (insert "\n.DE\n")
998 (setq notfirst t))
999 (insert "\n.SH ")
1000 (insert (if (looking-at "F") "Function " "Variable "))
1001 (delete-char 1)
1002 (forward-line 1)
1003 (insert ".DS L\n"))))
1004 (insert "\n.DE\n")
1005 (setq buffer-undo-list nil)
1006 (nroff-mode))
1007
1008;; Replaces lib-src/sorted-doc.c.
1009;;;###autoload
1010(defun doc-file-to-info (file)
1011 "Produce a texinfo buffer with sorted doc-strings from the DOC file."
1012 (interactive (list (read-file-name "Name of DOC file: " doc-directory
1013 internal-doc-file-name t)))
1014 (or (file-readable-p file)
1015 (error "Cannot read file `%s'" file))
1016 (let ((i 0) type name doc alist)
1017 (with-temp-buffer
1018 (insert-file-contents file)
1019 ;; The characters "@{}" need special treatment.
1020 (while (re-search-forward "[@{}]" nil t)
1021 (backward-char)
1022 (insert "@")
1023 (forward-char 1))
1024 (goto-char (point-min))
1025 (while (search-forward "\1f" nil t)
1026 (unless (looking-at "S")
1027 (setq type (char-after)
1028 name (buffer-substring (1+ (point)) (line-end-position))
1029 doc (buffer-substring (line-beginning-position 2)
1030 (if (search-forward "\1f" nil 'move)
1031 (1- (point))
1032 (point)))
1033 alist (cons (list name type doc) alist))
1034 (backward-char 1))))
1035 (pop-to-buffer (generate-new-buffer "*info-doc*"))
1036 (setq buffer-undo-list t)
1037 ;; Write the output header.
1038 (insert "\\input texinfo @c -*-texinfo-*-\n"
1039 "@setfilename emacsdoc.info\n"
1040 "@settitle Command Summary for GNU Emacs\n"
1041 "@finalout\n"
1042 "\n@node Top\n"
1043 "@unnumbered Command Summary for GNU Emacs\n\n"
1044 "@table @asis\n\n"
1045 "@iftex\n"
1046 "@global@let@ITEM@item\n"
1047 "@def@item{@filbreak@vskip5pt@ITEM}\n"
1048 "@font@tensy cmsy10 scaled @magstephalf\n"
1049 "@font@teni cmmi10 scaled @magstephalf\n"
1050 "@def\\{{@tensy@char110}}\n" ; this backslash goes with cmr10
1051 "@def|{{@tensy@char106}}\n"
1052 "@def@{{{@tensy@char102}}\n"
1053 "@def@}{{@tensy@char103}}\n"
1054 "@def<{{@teni@char62}}\n"
1055 "@def>{{@teni@char60}}\n"
1056 "@chardef@@64\n"
1057 "@catcode43=12\n"
1058 "@tableindent-0.2in\n"
1059 "@end iftex\n")
1060 ;; Sort the array by name; within each name, by type (functions first).
1061 (setq alist (sort alist (lambda (e1 e2)
1062 (if (string-equal (car e1) (car e2))
1063 (<= (cadr e1) (cadr e2))
1064 (string-lessp (car e1) (car e2))))))
1065 ;; Print each function.
1066 (dolist (e alist)
1067 (insert "\n@item "
1068 (if (char-equal (cadr e) ?\F) "Function" "Variable")
1069 " @code{" (car e) "}\n@display\n"
1070 (nth 2 e)
1071 "\n@end display\n")
1072 ;; Try to avoid a save size overflow in the TeX output routine.
1073 (if (zerop (setq i (% (1+ i) 100)))
1074 (insert "\n@end table\n@table @asis\n")))
1075 (insert "@end table\n"
1076 "@bye\n")
1077 (setq buffer-undo-list nil)
1078 (texinfo-mode)))
1079
1113ff44
MR
1080(provide 'help-fns)
1081
1113ff44 1082;;; help-fns.el ends here