aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2019-04-12 12:37:00 -0400
committerStefan Monnier2019-04-12 12:37:00 -0400
commit896e5802160c2797e689a7565599ebb1bd171295 (patch)
tree537a66725af4b6f8cc64a17003bdeb631f5245f9
parent2bc2a3ecaf3d1992cbc8b14609c16ebd4498b155 (diff)
downloademacs-896e5802160c2797e689a7565599ebb1bd171295.tar.gz
emacs-896e5802160c2797e689a7565599ebb1bd171295.zip
* lisp/help-fns.el (help-fns-describe-variable-functions): New hook
(help-fns--compiler-macro, help-fns--parent-mode, help-fns--obsolete) (help-fns--interactive-only): Indent output by 2 spaces. (help-fns--side-effects): New function extracted from describe-function-1. (help-fns-describe-function-functions): Use it. (help-fns--first-release, help-fns--mention-first-release): New functions. (help-fns-function-description-header): Keymaps and macros can't be interactive. (help-fns--ensure-empty-line): New function. (describe-function-1): Use it. (help-fns--var-safe-local, help-fns--var-risky) (help-fns--var-ignored-local, help-fns--var-file-local) (help-fns--var-watchpoints, help-fns--var-obsolete) (help-fns--var-alias, help-fns--var-bufferlocal): New functions, extacted from describe-variable. (describe-variable): Run help-fns-describe-variable-functions instead.
-rw-r--r--etc/NEWS6
-rw-r--r--etc/NEWS.1-174
-rw-r--r--lisp/help-fns.el414
3 files changed, 254 insertions, 170 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 9e3d993cab0..021d7d01799 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -847,6 +847,9 @@ directories in the destination.
847** Help 847** Help
848 848
849--- 849---
850*** Description of variables and functions give an estimated first release
851
852---
850*** Output format of 'C-h l' ('view-lossage') has changed. 853*** Output format of 'C-h l' ('view-lossage') has changed.
851For convenience, 'view-lossage' now displays the last keystrokes 854For convenience, 'view-lossage' now displays the last keystrokes
852and commands in the same format as the edit buffer of 855and commands in the same format as the edit buffer of
@@ -1497,6 +1500,9 @@ performs (setq-local indent-line-function #'indent-relative).
1497 1500
1498* Lisp Changes in Emacs 27.1 1501* Lisp Changes in Emacs 27.1
1499 1502
1503** New 'help-fns-describe-variable-functions' hook.
1504Makes it possible to add metadata information to describe-variable.
1505
1500** i18n (internationalization) 1506** i18n (internationalization)
1501 1507
1502*** ngettext can be used now to return the right plural form 1508*** ngettext can be used now to return the right plural form
diff --git a/etc/NEWS.1-17 b/etc/NEWS.1-17
index 758ef65ed95..1ce36fe99da 100644
--- a/etc/NEWS.1-17
+++ b/etc/NEWS.1-17
@@ -2339,9 +2339,9 @@ It's Beat CCA Week.
2339 2339
2340** Lisp macros now exist. 2340** Lisp macros now exist.
2341 For example, you can write 2341 For example, you can write
2342 (defmacro cadr (arg) (list 'car (list 'cdr arg))) 2342 (defmacro mycadr (arg) (list 'car (list 'cdr arg)))
2343 and then the expression 2343 and then the expression
2344 (cadr foo) 2344 (mycadr foo)
2345 will expand into 2345 will expand into
2346 (car (cdr foo)) 2346 (car (cdr foo))
2347 2347
diff --git a/lisp/help-fns.el b/lisp/help-fns.el
index 06b4ec8c209..50d69e70de4 100644
--- a/lisp/help-fns.el
+++ b/lisp/help-fns.el
@@ -40,7 +40,21 @@
40 "List of functions to run in help buffer in `describe-function'. 40 "List of functions to run in help buffer in `describe-function'.
41Those functions will be run after the header line and argument 41Those functions will be run after the header line and argument
42list was inserted, and before the documentation will be inserted. 42list was inserted, and before the documentation will be inserted.
43The functions will receive the function name as argument.") 43The functions will receive the function name as argument.
44They can assume that a newline was output just before they were called,
45and they should terminate any of their own output with a newline.
46By convention they should indent their output by 2 spaces.")
47
48(defvar help-fns-describe-variable-functions nil
49 "List of functions to run in help buffer in `describe-variable'.
50Those functions will be run after the header line and value was inserted,
51and before the documentation will be inserted.
52The functions will receive the variable name as argument.
53They can assume that a newline was output just before they were called,
54and they should terminate any of their own output with a newline.
55By convention they should indent their output by 2 spaces.
56Current buffer is the buffer in which we queried the variable,
57and the output should go to `standard-output'.")
44 58
45;; Functions 59;; Functions
46 60
@@ -412,7 +426,7 @@ suitable file is found, return nil."
412(defun help-fns--compiler-macro (function) 426(defun help-fns--compiler-macro (function)
413 (let ((handler (function-get function 'compiler-macro))) 427 (let ((handler (function-get function 'compiler-macro)))
414 (when handler 428 (when handler
415 (insert "\nThis function has a compiler macro") 429 (insert " This function has a compiler macro")
416 (if (symbolp handler) 430 (if (symbolp handler)
417 (progn 431 (progn
418 (insert (format-message " `%s'" handler)) 432 (insert (format-message " `%s'" handler))
@@ -486,7 +500,7 @@ suitable file is found, return nil."
486 (get function 500 (get function
487 'derived-mode-parent)))) 501 'derived-mode-parent))))
488 (when parent-mode 502 (when parent-mode
489 (insert (substitute-command-keys "\nParent mode: `")) 503 (insert (substitute-command-keys " Parent mode: `"))
490 (let ((beg (point))) 504 (let ((beg (point)))
491 (insert (format "%s" parent-mode)) 505 (insert (format "%s" parent-mode))
492 (make-text-button beg (point) 506 (make-text-button beg (point)
@@ -500,15 +514,15 @@ suitable file is found, return nil."
500 (get function 'byte-obsolete-info))) 514 (get function 'byte-obsolete-info)))
501 (use (car obsolete))) 515 (use (car obsolete)))
502 (when obsolete 516 (when obsolete
503 (insert "\nThis " 517 (insert " This "
504 (if (eq (car-safe (symbol-function function)) 'macro) 518 (if (eq (car-safe (symbol-function function)) 'macro)
505 "macro" 519 "macro"
506 "function") 520 "function")
507 " is obsolete") 521 " is obsolete")
508 (when (nth 2 obsolete) 522 (when (nth 2 obsolete)
509 (insert (format " since %s" (nth 2 obsolete)))) 523 (insert (format " since %s" (nth 2 obsolete))))
510 (insert (cond ((stringp use) (concat ";\n" use)) 524 (insert (cond ((stringp use) (concat ";\n " use))
511 (use (format-message ";\nuse `%s' instead." use)) 525 (use (format-message ";\n use `%s' instead." use))
512 (t ".")) 526 (t "."))
513 "\n")))) 527 "\n"))))
514 528
@@ -538,17 +552,65 @@ FILE is the file where FUNCTION was probably defined."
538 (memq function 552 (memq function
539 byte-compile-interactive-only-functions))))) 553 byte-compile-interactive-only-functions)))))
540 (when interactive-only 554 (when interactive-only
541 (insert "\nThis function is for interactive use only" 555 (insert " This function is for interactive use only"
542 ;; Cf byte-compile-form. 556 ;; Cf byte-compile-form.
543 (cond ((stringp interactive-only) 557 (cond ((stringp interactive-only)
544 (format ";\nin Lisp code %s" interactive-only)) 558 (format ";\n in Lisp code %s" interactive-only))
545 ((and (symbolp 'interactive-only) 559 ((and (symbolp 'interactive-only)
546 (not (eq interactive-only t))) 560 (not (eq interactive-only t)))
547 (format-message ";\nin Lisp code use `%s' instead." 561 (format-message ";\n in Lisp code use `%s' instead."
548 interactive-only)) 562 interactive-only))
549 (t ".")) 563 (t "."))
550 "\n"))))) 564 "\n")))))
551 565
566(add-hook 'help-fns-describe-function-functions #'help-fns--side-effects)
567(defun help-fns--side-effects (function)
568 (when (and (symbolp function)
569 (or (function-get function 'pure)
570 (function-get function 'side-effect-free)))
571 (insert " This function does not change global state, "
572 "including the match data.\n")))
573
574(defun help-fns--first-release (symbol)
575 "Return the likely first release that defined SYMBOL."
576 ;; Code below relies on the etc/NEWS* files.
577 ;; FIXME: Maybe we should also use the */ChangeLog* files when available.
578 ;; FIXME: Maybe we should also look for announcements of the addition
579 ;; of the *packages* in which the function is defined.
580 (let* ((name (symbol-name symbol))
581 (re (concat "\\_<" (regexp-quote name) "\\_>"))
582 (news (directory-files data-directory t "\\`NEWS.[1-9]"))
583 (first nil))
584 (with-temp-buffer
585 (dolist (f news)
586 (erase-buffer)
587 (insert-file-contents f)
588 (goto-char (point-min))
589 (search-forward "\n*")
590 (while (re-search-forward re nil t)
591 (save-excursion
592 ;; Almost all entries are of the form "* ... in Emacs NN.MM."
593 ;; but there are also a few in the form "* Emacs NN.MM is a bug
594 ;; fix release ...".
595 (if (not (re-search-backward "^\\*.* Emacs \\([0-9.]+[0-9]\\)"
596 nil t))
597 (message "Ref found in non-versioned section in %S"
598 (file-name-nondirectory f))
599 (let ((version (match-string 1)))
600 (when (or (null first) (version< version first))
601 (setq first version))))))))
602 first))
603
604(add-hook 'help-fns-describe-function-functions
605 #'help-fns--mention-first-release)
606(add-hook 'help-fns-describe-variable-functions
607 #'help-fns--mention-first-release)
608(defun help-fns--mention-first-release (object)
609 (let ((first (if (symbolp object) (help-fns--first-release object))))
610 (when first
611 (princ (format " Probably introduced at or before Emacs version %s.\n"
612 first)))))
613
552(defun help-fns-short-filename (filename) 614(defun help-fns-short-filename (filename)
553 (let* ((abbrev (abbreviate-file-name filename)) 615 (let* ((abbrev (abbreviate-file-name filename))
554 (short abbrev)) 616 (short abbrev))
@@ -611,9 +673,9 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED REAL-DEF)."
611 (memq (car-safe def) '(macro lambda closure))) 673 (memq (car-safe def) '(macro lambda closure)))
612 (stringp file-name) 674 (stringp file-name)
613 (help-fns--autoloaded-p function file-name)) 675 (help-fns--autoloaded-p function file-name))
614 (if (commandp def) 676 (concat
615 "an interactive autoloaded " 677 "an autoloaded " (if (commandp def)
616 "an autoloaded ") 678 "interactive "))
617 (if (commandp def) "an interactive " "a ")))) 679 (if (commandp def) "an interactive " "a "))))
618 680
619 ;; Print what kind of function-like object FUNCTION is. 681 ;; Print what kind of function-like object FUNCTION is.
@@ -627,14 +689,16 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED REAL-DEF)."
627 (aliased 689 (aliased
628 (format-message "an alias for `%s'" real-def)) 690 (format-message "an alias for `%s'" real-def))
629 ((subrp def) 691 ((subrp def)
630 (if (eq 'unevalled (cdr (subr-arity def))) 692 (concat beg (if (eq 'unevalled (cdr (subr-arity def)))
631 (concat beg "special form") 693 "special form"
632 (concat beg "built-in function"))) 694 "built-in function")))
633 ((autoloadp def) 695 ((autoloadp def)
634 (format "%s autoloaded %s" 696 (format "an autoloaded %s"
635 (if (commandp def) "an interactive" "an") 697 (cond
636 (if (eq (nth 4 def) 'keymap) "keymap" 698 ((commandp def) "interactive Lisp function")
637 (if (nth 4 def) "Lisp macro" "Lisp function")))) 699 ((eq (nth 4 def) 'keymap) "keymap")
700 ((nth 4 def) "Lisp macro")
701 (t "Lisp function"))))
638 ((or (eq (car-safe def) 'macro) 702 ((or (eq (car-safe def) 'macro)
639 ;; For advised macros, def is a lambda 703 ;; For advised macros, def is a lambda
640 ;; expression or a byte-code-function-p, so we 704 ;; expression or a byte-code-function-p, so we
@@ -685,6 +749,10 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED REAL-DEF)."
685 (help-xref-button 1 'help-function-def function file-name)))) 749 (help-xref-button 1 'help-function-def function file-name))))
686 (princ ".")))) 750 (princ "."))))
687 751
752(defun help-fns--ensure-empty-line ()
753 (unless (eolp) (insert "\n"))
754 (unless (eq ?\n (char-before (1- (point)))) (insert "\n")))
755
688;;;###autoload 756;;;###autoload
689(defun describe-function-1 (function) 757(defun describe-function-1 (function)
690 (let ((pt1 (with-current-buffer (help-buffer) (point)))) 758 (let ((pt1 (with-current-buffer (help-buffer) (point))))
@@ -722,12 +790,10 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED REAL-DEF)."
722 real-function key-bindings-buffer) 790 real-function key-bindings-buffer)
723 ;; E.g. an alias for a not yet defined function. 791 ;; E.g. an alias for a not yet defined function.
724 ((invalid-function void-function) doc-raw)))) 792 ((invalid-function void-function) doc-raw))))
793 (help-fns--ensure-empty-line)
725 (run-hook-with-args 'help-fns-describe-function-functions function) 794 (run-hook-with-args 'help-fns-describe-function-functions function)
726 (insert "\n" (or doc "Not documented."))) 795 (help-fns--ensure-empty-line)
727 (when (or (function-get function 'pure) 796 (insert (or doc "Not documented.")))
728 (function-get function 'side-effect-free))
729 (insert "\nThis function does not change global state, "
730 "including the match data."))
731 ;; Avoid asking the user annoying questions if she decides 797 ;; Avoid asking the user annoying questions if she decides
732 ;; to save the help buffer, when her locale's codeset 798 ;; to save the help buffer, when her locale's codeset
733 ;; isn't UTF-8. 799 ;; isn't UTF-8.
@@ -830,7 +896,6 @@ it is displayed along with the global value."
830 (message "You did not specify a variable") 896 (message "You did not specify a variable")
831 (save-excursion 897 (save-excursion
832 (let ((valvoid (not (with-current-buffer buffer (boundp variable)))) 898 (let ((valvoid (not (with-current-buffer buffer (boundp variable))))
833 (permanent-local (get variable 'permanent-local))
834 val val-start-pos locus) 899 val val-start-pos locus)
835 ;; Extract the value before setting up the output buffer, 900 ;; Extract the value before setting up the output buffer,
836 ;; in case `buffer' *is* the output buffer. 901 ;; in case `buffer' *is* the output buffer.
@@ -846,26 +911,26 @@ it is displayed along with the global value."
846 (prin1 variable) 911 (prin1 variable)
847 (setq file-name (find-lisp-object-file-name variable 'defvar)) 912 (setq file-name (find-lisp-object-file-name variable 'defvar))
848 913
849 (if file-name 914 (princ (if file-name
850 (progn 915 (progn
851 (princ (format-message 916 (princ (format-message
852 " is a variable defined in `%s'.\n" 917 " is a variable defined in `%s'.\n"
853 (if (eq file-name 'C-source) 918 (if (eq file-name 'C-source)
854 "C source code" 919 "C source code"
855 (file-name-nondirectory file-name)))) 920 (file-name-nondirectory file-name))))
856 (with-current-buffer standard-output 921 (with-current-buffer standard-output
857 (save-excursion 922 (save-excursion
858 (re-search-backward (substitute-command-keys 923 (re-search-backward (substitute-command-keys
859 "`\\([^`']+\\)'") 924 "`\\([^`']+\\)'")
860 nil t) 925 nil t)
861 (help-xref-button 1 'help-variable-def 926 (help-xref-button 1 'help-variable-def
862 variable file-name))) 927 variable file-name)))
863 (if valvoid 928 (if valvoid
864 (princ "It is void as a variable.") 929 "It is void as a variable."
865 (princ "Its "))) 930 "Its "))
866 (if valvoid 931 (if valvoid
867 (princ " is void as a variable.") 932 " is void as a variable."
868 (princ (substitute-command-keys "'s "))))) 933 (substitute-command-keys "'s ")))))
869 (unless valvoid 934 (unless valvoid
870 (with-current-buffer standard-output 935 (with-current-buffer standard-output
871 (setq val-start-pos (point)) 936 (setq val-start-pos (point))
@@ -894,7 +959,7 @@ it is displayed along with the global value."
894 (let* ((sv (get variable 'standard-value)) 959 (let* ((sv (get variable 'standard-value))
895 (origval (and (consp sv) 960 (origval (and (consp sv)
896 (condition-case nil 961 (condition-case nil
897 (eval (car sv)) 962 (eval (car sv) t)
898 (error :help-eval-error)))) 963 (error :help-eval-error))))
899 from) 964 from)
900 (when (and (consp sv) 965 (when (and (consp sv)
@@ -969,132 +1034,17 @@ it is displayed along with the global value."
969 (let* ((alias (condition-case nil 1034 (let* ((alias (condition-case nil
970 (indirect-variable variable) 1035 (indirect-variable variable)
971 (error variable))) 1036 (error variable)))
972 (obsolete (get variable 'byte-obsolete-variable))
973 (watchpoints (get-variable-watchers variable))
974 (use (car obsolete))
975 (safe-var (get variable 'safe-local-variable))
976 (doc (or (documentation-property 1037 (doc (or (documentation-property
977 variable 'variable-documentation) 1038 variable 'variable-documentation)
978 (documentation-property 1039 (documentation-property
979 alias 'variable-documentation))) 1040 alias 'variable-documentation))))
980 (extra-line nil))
981 1041
982 ;; Mention if it's a local variable. 1042 (with-current-buffer buffer
983 (cond 1043 (run-hook-with-args 'help-fns-describe-variable-functions
984 ((and (local-variable-if-set-p variable) 1044 variable))
985 (or (not (local-variable-p variable)) 1045
986 (with-temp-buffer 1046 (with-current-buffer standard-output
987 (local-variable-if-set-p variable)))) 1047 (help-fns--ensure-empty-line))
988 (setq extra-line t)
989 (princ " Automatically becomes ")
990 (if permanent-local
991 (princ "permanently "))
992 (princ "buffer-local when set.\n"))
993 ((not permanent-local))
994 ((bufferp locus)
995 (setq extra-line t)
996 (princ
997 (substitute-command-keys
998 " This variable's buffer-local value is permanent.\n")))
999 (t
1000 (setq extra-line t)
1001 (princ (substitute-command-keys
1002 " This variable's value is permanent \
1003if it is given a local binding.\n"))))
1004
1005 ;; Mention if it's an alias.
1006 (unless (eq alias variable)
1007 (setq extra-line t)
1008 (princ (format-message
1009 " This variable is an alias for `%s'.\n"
1010 alias)))
1011
1012 (when obsolete
1013 (setq extra-line t)
1014 (princ " This variable is obsolete")
1015 (if (nth 2 obsolete)
1016 (princ (format " since %s" (nth 2 obsolete))))
1017 (princ (cond ((stringp use) (concat ";\n " use))
1018 (use (format-message ";\n use `%s' instead."
1019 (car obsolete)))
1020 (t ".")))
1021 (terpri))
1022
1023 (when watchpoints
1024 (setq extra-line t)
1025 (princ " Calls these functions when changed: ")
1026 (princ watchpoints)
1027 (terpri))
1028
1029 (when (member (cons variable val)
1030 (with-current-buffer buffer
1031 file-local-variables-alist))
1032 (setq extra-line t)
1033 (if (member (cons variable val)
1034 (with-current-buffer buffer
1035 dir-local-variables-alist))
1036 (let ((file (and (buffer-file-name buffer)
1037 (not (file-remote-p
1038 (buffer-file-name buffer)))
1039 (dir-locals-find-file
1040 (buffer-file-name buffer))))
1041 (is-directory nil))
1042 (princ (substitute-command-keys
1043 " This variable's value is directory-local"))
1044 (when (consp file) ; result from cache
1045 ;; If the cache element has an mtime, we
1046 ;; assume it came from a file.
1047 (if (nth 2 file)
1048 ;; (car file) is a directory.
1049 (setq file (dir-locals--all-files (car file)))
1050 ;; Otherwise, assume it was set directly.
1051 (setq file (car file)
1052 is-directory t)))
1053 (if (null file)
1054 (princ ".\n")
1055 (princ ", set ")
1056 (princ (substitute-command-keys
1057 (cond
1058 (is-directory "for the directory\n `")
1059 ;; Many files matched.
1060 ((and (consp file) (cdr file))
1061 (setq file (file-name-directory (car file)))
1062 (format "by one of the\n %s files in the directory\n `"
1063 dir-locals-file))
1064 (t (setq file (car file))
1065 "by the file\n `"))))
1066 (with-current-buffer standard-output
1067 (insert-text-button
1068 file 'type 'help-dir-local-var-def
1069 'help-args (list variable file)))
1070 (princ (substitute-command-keys "'.\n"))))
1071 (princ (substitute-command-keys
1072 " This variable's value is file-local.\n"))))
1073
1074 (when (memq variable ignored-local-variables)
1075 (setq extra-line t)
1076 (princ " This variable is ignored as a file-local \
1077variable.\n"))
1078
1079 ;; Can be both risky and safe, eg auto-fill-function.
1080 (when (risky-local-variable-p variable)
1081 (setq extra-line t)
1082 (princ " This variable may be risky if used as a \
1083file-local variable.\n")
1084 (when (assq variable safe-local-variable-values)
1085 (princ (substitute-command-keys
1086 " However, you have added it to \
1087`safe-local-variable-values'.\n"))))
1088
1089 (when safe-var
1090 (setq extra-line t)
1091 (princ " This variable is safe as a file local variable ")
1092 (princ "if its value\n satisfies the predicate ")
1093 (princ (if (byte-code-function-p safe-var)
1094 "which is a byte-compiled expression.\n"
1095 (format-message "`%s'.\n" safe-var))))
1096
1097 (if extra-line (terpri))
1098 (princ "Documentation:\n") 1048 (princ "Documentation:\n")
1099 (with-current-buffer standard-output 1049 (with-current-buffer standard-output
1100 (insert (or doc "Not documented as a variable.")))) 1050 (insert (or doc "Not documented as a variable."))))
@@ -1121,6 +1071,134 @@ file-local variable.\n")
1121 ;; Return the text we displayed. 1071 ;; Return the text we displayed.
1122 (buffer-string)))))))) 1072 (buffer-string))))))))
1123 1073
1074(add-hook 'help-fns-describe-variable-functions #'help-fns--var-safe-local)
1075(defun help-fns--var-safe-local (variable)
1076 (let ((safe-var (get variable 'safe-local-variable)))
1077 (when safe-var
1078 (princ " This variable is safe as a file local variable ")
1079 (princ "if its value\n satisfies the predicate ")
1080 (princ (if (byte-code-function-p safe-var)
1081 "which is a byte-compiled expression.\n"
1082 (format-message "`%s'.\n" safe-var))))))
1083
1084(add-hook 'help-fns-describe-variable-functions #'help-fns--var-risky)
1085(defun help-fns--var-risky (variable)
1086 ;; Can be both risky and safe, eg auto-fill-function.
1087 (when (risky-local-variable-p variable)
1088 (princ " This variable may be risky if used as a \
1089file-local variable.\n")
1090 (when (assq variable safe-local-variable-values)
1091 (princ (substitute-command-keys
1092 " However, you have added it to \
1093`safe-local-variable-values'.\n")))))
1094
1095(add-hook 'help-fns-describe-variable-functions #'help-fns--var-ignored-local)
1096(defun help-fns--var-ignored-local (variable)
1097 (when (memq variable ignored-local-variables)
1098 (princ " This variable is ignored as a file-local \
1099variable.\n")))
1100
1101(add-hook 'help-fns-describe-variable-functions #'help-fns--var-file-local)
1102(defun help-fns--var-file-local (variable)
1103 (when (boundp variable)
1104 (let ((val (symbol-value variable)))
1105 (when (member (cons variable val)
1106 file-local-variables-alist)
1107 (if (member (cons variable val)
1108 dir-local-variables-alist)
1109 (let ((file (and buffer-file-name
1110 (not (file-remote-p buffer-file-name))
1111 (dir-locals-find-file buffer-file-name)))
1112 (is-directory nil))
1113 (princ (substitute-command-keys
1114 " This variable's value is directory-local"))
1115 (when (consp file) ; result from cache
1116 ;; If the cache element has an mtime, we
1117 ;; assume it came from a file.
1118 (if (nth 2 file)
1119 ;; (car file) is a directory.
1120 (setq file (dir-locals--all-files (car file)))
1121 ;; Otherwise, assume it was set directly.
1122 (setq file (car file)
1123 is-directory t)))
1124 (if (null file)
1125 (princ ".\n")
1126 (princ ", set ")
1127 (princ (substitute-command-keys
1128 (cond
1129 (is-directory "for the directory\n `")
1130 ;; Many files matched.
1131 ((and (consp file) (cdr file))
1132 (setq file (file-name-directory (car file)))
1133 (format "by one of the\n %s files in the directory\n `"
1134 dir-locals-file))
1135 (t (setq file (car file))
1136 "by the file\n `"))))
1137 (with-current-buffer standard-output
1138 (insert-text-button
1139 file 'type 'help-dir-local-var-def
1140 'help-args (list variable file)))
1141 (princ (substitute-command-keys "'.\n"))))
1142 (princ (substitute-command-keys
1143 " This variable's value is file-local.\n")))))))
1144
1145(add-hook 'help-fns-describe-variable-functions #'help-fns--var-watchpoints)
1146(defun help-fns--var-watchpoints (variable)
1147 (let ((watchpoints (get-variable-watchers variable)))
1148 (when watchpoints
1149 (princ " Calls these functions when changed: ")
1150 ;; FIXME: Turn function names into hyperlinks.
1151 (princ watchpoints)
1152 (terpri))))
1153
1154(add-hook 'help-fns-describe-variable-functions #'help-fns--var-obsolete)
1155(defun help-fns--var-obsolete (variable)
1156 (let* ((obsolete (get variable 'byte-obsolete-variable))
1157 (use (car obsolete)))
1158 (when obsolete
1159 (princ " This variable is obsolete")
1160 (if (nth 2 obsolete)
1161 (princ (format " since %s" (nth 2 obsolete))))
1162 (princ (cond ((stringp use) (concat ";\n " use))
1163 (use (format-message ";\n use `%s' instead."
1164 (car obsolete)))
1165 (t ".")))
1166 (terpri))))
1167
1168(add-hook 'help-fns-describe-variable-functions #'help-fns--var-alias)
1169(defun help-fns--var-alias (variable)
1170 ;; Mention if it's an alias.
1171 (let ((alias (condition-case nil
1172 (indirect-variable variable)
1173 (error variable))))
1174 (unless (eq alias variable)
1175 (princ (format-message
1176 " This variable is an alias for `%s'.\n"
1177 alias)))))
1178
1179(add-hook 'help-fns-describe-variable-functions #'help-fns--var-bufferlocal)
1180(defun help-fns--var-bufferlocal (variable)
1181 (let ((permanent-local (get variable 'permanent-local))
1182 (locus (variable-binding-locus variable)))
1183 ;; Mention if it's a local variable.
1184 (cond
1185 ((and (local-variable-if-set-p variable)
1186 (or (not (local-variable-p variable))
1187 (with-temp-buffer
1188 (local-variable-if-set-p variable))))
1189 (princ " Automatically becomes ")
1190 (if permanent-local
1191 (princ "permanently "))
1192 (princ "buffer-local when set.\n"))
1193 ((not permanent-local))
1194 ((bufferp locus)
1195 (princ
1196 (substitute-command-keys
1197 " This variable's buffer-local value is permanent.\n")))
1198 (t
1199 (princ (substitute-command-keys
1200 " This variable's value is permanent \
1201if it is given a local binding.\n"))))))
1124 1202
1125(defvar help-xref-stack-item) 1203(defvar help-xref-stack-item)
1126 1204