Merge from emacs--devo--0
[bpt/emacs.git] / lisp / help-fns.el
index e4d77e3..f62fadc 100644 (file)
@@ -1,7 +1,7 @@
 ;;; help-fns.el --- Complex help functions
 
 ;; Copyright (C) 1985, 1986, 1993, 1994, 1998, 1999, 2000, 2001,
-;;   2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+;;   2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: help, internal
@@ -10,7 +10,7 @@
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
@@ -232,10 +232,37 @@ face (according to `face-differs-from-default-p')."
              libname)
          file))))
 
+(defun find-source-lisp-file (file-name)
+  (let* ((elc-file (locate-file (concat file-name
+                                (if (string-match "\\.el" file-name)
+                                    "c"
+                                  ".elc"))
+                                load-path))
+        (str (if (and elc-file (file-readable-p elc-file))
+                 (with-temp-buffer
+                   (insert-file-contents-literally elc-file nil 0 256)
+                   (buffer-string))))
+        (src-file (and str
+                       (string-match ";;; from file \\(.*\\.el\\)" str)
+                       (match-string 1 str))))
+    (if (and src-file (file-readable-p src-file))
+       src-file
+      file-name)))
+
 ;;;###autoload
 (defun describe-function-1 (function)
-  (let* ((def (if (symbolp function)
-                 (symbol-function function)
+  (let* ((advised (and (featurep 'advice) (ad-get-advice-info function)))
+        ;; If the function is advised, use the symbol that has the
+        ;; real definition, if that symbol is already set up.
+        (real-function
+         (or (and advised
+                  (cdr (assq 'origname advised))
+                  (fboundp (cdr (assq 'origname advised)))
+                  (cdr (assq 'origname advised)))
+             function))
+        ;; Get the real definition.
+        (def (if (symbolp real-function)
+                 (symbol-function real-function)
                function))
         file-name string
         (beg (if (commandp def) "an interactive " "a ")))
@@ -309,11 +336,15 @@ face (according to `face-differs-from-default-p')."
       ;; but that's completely wrong when the user used load-file.
       (princ (if (eq file-name 'C-source) "C source code" file-name))
       (princ "'")
+      ;; See if lisp files are present where they where installed from.
+      (if (not (eq file-name 'C-source))
+         (setq file-name (find-source-lisp-file file-name)))
+
       ;; Make a hyperlink to the library.
       (with-current-buffer standard-output
         (save-excursion
          (re-search-backward "`\\([^`']+\\)'" nil t)
-         (help-xref-button 1 'help-function-def function file-name))))
+         (help-xref-button 1 'help-function-def real-function file-name))))
     (princ ".")
     (terpri)
     (when (commandp function)
@@ -362,8 +393,9 @@ face (according to `face-differs-from-default-p')."
                         ((listp arglist)
                          (format "%S" (help-make-usage function arglist)))
                         ((stringp arglist) arglist)
-                        ;; Maybe the arglist is in the docstring of the alias.
-                        ((let ((fun function))
+                        ;; Maybe the arglist is in the docstring of a symbol
+                       ;; this one is aliased to.
+                        ((let ((fun real-function))
                            (while (and (symbolp fun)
                                        (setq fun (symbol-function fun))
                                        (not (setq usage (help-split-fundoc
@@ -425,10 +457,11 @@ If ANY-SYMBOL is non-nil, don't insist the symbol be bound."
       0))
 
 ;;;###autoload
-(defun describe-variable (variable &optional buffer)
+(defun describe-variable (variable &optional buffer frame)
   "Display the full documentation of VARIABLE (a symbol).
 Returns the documentation as a string, also.
-If VARIABLE has a buffer-local value in BUFFER (default to the current buffer),
+If VARIABLE has a buffer-local value in BUFFER or FRAME
+\(default to the current buffer and current frame),
 it is displayed along with the global value."
   (interactive
    (let ((v (variable-at-point))
@@ -447,14 +480,19 @@ it is displayed along with the global value."
      (list (if (equal val "")
               v (intern val)))))
   (unless (buffer-live-p buffer) (setq buffer (current-buffer)))
+  (unless (frame-live-p frame) (setq frame (selected-frame)))
   (if (not (symbolp variable))
       (message "You did not specify a variable")
     (save-excursion
-      (let* ((valvoid (not (with-current-buffer buffer (boundp variable))))
-            ;; Extract the value before setting up the output buffer,
-            ;; in case `buffer' *is* the output buffer.
-            (val (unless valvoid (buffer-local-value variable buffer)))
-            val-start-pos)
+      (let ((valvoid (not (with-current-buffer buffer (boundp variable))))
+           val val-start-pos locus)
+       ;; Extract the value before setting up the output buffer,
+       ;; in case `buffer' *is* the output buffer.
+       (unless valvoid
+         (with-selected-frame frame
+           (with-current-buffer buffer
+             (setq val (symbol-value variable)
+                   locus (variable-binding-locus variable)))))
        (help-setup-xref (list #'describe-variable variable buffer)
                         (interactive-p))
        (with-output-to-temp-buffer (help-buffer)
@@ -516,11 +554,13 @@ it is displayed along with the global value."
                      (delete-region (1- from) from)))))
            (terpri)
 
-           (when (local-variable-p variable)
-             (princ (format "%socal in buffer %s; "
-                            (if (get variable 'permanent-local)
-                                "Permanently l" "L")
-                            (buffer-name)))
+           (when locus
+             (if (bufferp locus)
+                 (princ (format "%socal in buffer %s; "
+                                (if (get variable 'permanent-local)
+                                    "Permanently l" "L")
+                                (buffer-name)))
+               (princ (format "It is a frame-local variable; ")))
              (if (not (default-boundp variable))
                  (princ "globally void")
                (let ((val (default-value variable)))
@@ -536,14 +576,8 @@ it is displayed along with the global value."
                      ;; See previous comment for this function.
                      ;; (help-xref-on-pp from (point))
                      (if (< (point) (+ from 20))
-                         (delete-region (1- from) from)))))))
-           ;; Add a note for variables that have been make-var-buffer-local.
-           (when (and (local-variable-if-set-p variable)
-                      (or (not (local-variable-p variable))
-                          (with-temp-buffer
-                            (local-variable-if-set-p variable))))
-             (princ "\nAutomatically becomes buffer-local when set in any fashion.\n"))
-           (terpri)
+                         (delete-region (1- from) from))))))
+              (terpri))
 
            ;; If the value is large, move it to the end.
            (with-current-buffer standard-output
@@ -553,7 +587,11 @@ it is displayed along with the global value."
                ;; of a symbol.
                (set-syntax-table emacs-lisp-mode-syntax-table)
                (goto-char val-start-pos)
-               (delete-region (point) (progn (end-of-line) (point)))
+               ;; The line below previously read as
+               ;; (delete-region (point) (progn (end-of-line) (point)))
+               ;; which suppressed display of the buffer local value for
+               ;; large values.
+               (when (looking-at "value is") (replace-match ""))
                (save-excursion
                  (insert "\n\nValue:")
                  (set (make-local-variable 'help-button-cache)
@@ -563,34 +601,50 @@ it is displayed along with the global value."
                               'action help-button-cache
                               'follow-link t
                               'help-echo "mouse-2, RET: show value")
-               (insert ".\n\n")))
+               (insert ".\n")))
+            (terpri)
 
-           ;; Mention if it's an alias
             (let* ((alias (condition-case nil
                              (indirect-variable variable)
                            (error variable)))
                    (obsolete (get variable 'byte-obsolete-variable))
                   (safe-var (get variable 'safe-local-variable))
                    (doc (or (documentation-property variable 'variable-documentation)
-                            (documentation-property alias 'variable-documentation))))
+                            (documentation-property alias 'variable-documentation)))
+                   (extra-line nil))
+              ;; Add a note for variables that have been make-var-buffer-local.
+              (when (and (local-variable-if-set-p variable)
+                         (or (not (local-variable-p variable))
+                             (with-temp-buffer
+                               (local-variable-if-set-p variable))))
+                (setq extra-line t)
+                (princ "  Automatically becomes buffer-local when set in any fashion.\n"))
+
+              ;; Mention if it's an alias
               (unless (eq alias variable)
-                (princ (format "\nThis variable is an alias for `%s'.\n" alias)))
+                (setq extra-line t)
+                (princ (format "  This variable is an alias for `%s'.\n" alias)))
+
               (when obsolete
-                (princ "\nThis variable is obsolete")
+                (setq extra-line t)
+                (princ "  This variable is obsolete")
                 (if (cdr obsolete) (princ (format " since %s" (cdr obsolete))))
-                (princ ";") (terpri)
+                (princ ";\n  ")
                 (princ (if (stringp (car obsolete)) (car obsolete)
                          (format "use `%s' instead." (car obsolete))))
                 (terpri))
              (when safe-var
-               (princ "This variable is safe as a file local variable ")
-               (princ "if its value\nsatisfies the predicate ")
+                (setq extra-line t)
+               (princ "  This variable is safe as a file local variable ")
+               (princ "if its value\n  satisfies the predicate ")
                (princ (if (byte-code-function-p safe-var)
                           "which is byte-compiled expression.\n"
-                        (format "`%s'.\n" safe-var)))
-               (terpri))
+                        (format "`%s'.\n" safe-var))))
+
+              (if extra-line (terpri))
              (princ "Documentation:\n")
-              (princ (or doc "Not documented as a variable.")))
+             (with-current-buffer standard-output
+               (insert (or doc "Not documented as a variable."))))
            ;; Make a link to customize if this variable can be customized.
            (if (custom-variable-p variable)
                (let ((customize-label "customize"))