diff lisp/hyper-apropos.el @ 217:d44af0c54775 r20-4b7

Import from CVS: tag r20-4b7
author cvs
date Mon, 13 Aug 2007 10:08:34 +0200
parents
children 262b8bb4a523
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/hyper-apropos.el	Mon Aug 13 10:08:34 2007 +0200
@@ -0,0 +1,1329 @@
+;;; hyper-apropos.el --- Hypertext emacs lisp documentation interface.
+
+;; Copyright (C) 1994, 1995 Tinker Systems and INS Engineering Corp.
+;; Copyright (C) 1995 Sun Microsystems.
+;; Copyright (C) 1996 Ben Wing.
+
+;; Maintainer: Jonathan Stigelman <Stig@hackvan.com>
+;; Keywords: lisp, tools, help, docs, matching
+
+;; This file is part of XEmacs.
+
+;; XEmacs 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 of the License, or
+;; (at your option) any later version.
+;; 
+;; XEmacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;; 
+;; You should have received a copy of the GNU General Public License
+;; along with XEmacs; if not, write to the Free Software
+;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Synched up with: Not in FSF.
+
+;;; Commentary:
+
+;;  based upon emacs-apropos.el by Frank C. Guida <fcg@philabs.philips.com>
+;;
+;;  Rather than run apropos and print all the documentation at once,
+;;  I find it easier to view a "table of contents" first, then
+;;  get the details for symbols as you need them.
+;;
+;;  This version of apropos prints two lists of symbols matching the
+;;  given regexp:  functions/macros and variables/constants.
+;;
+;;  The user can then do the following:
+;;
+;;      - add an additional regexp to narrow the search
+;;      - display documentation for the current symbol
+;;      - find the tag for the current symbol
+;;      - show any keybindings if the current symbol is a command
+;;	- invoke functions
+;;	- set variables
+;;
+;;  An additional feature is the ability to search the current tags
+;;  table, allowing you to interrogate functions not yet loaded (this
+;;  isn't available with the standard package).
+;;
+;;  Mouse bindings and menus are provided for XEmacs.
+;;
+;; additions by Ben Wing <wing@666.com> July 1995:
+;; added support for function aliases, made programmer's apropos be the
+;; default, various other hacking.
+;; Massive changes by Christoph Wedler <wedler@fmi.uni-passau.de>
+;; Some changes for XEmacs 20.3 by hniksic
+
+;; ### The maintainer is supposed to be stig, but I haven't seen him
+;; around for ages.  The real maintainer for the moment is Hrvoje
+;; Niksic <hniksic@srce.hr>.
+
+;;; Code:
+
+(require 'pp)
+
+(defgroup hyper-apropos nil
+  "Hypertext emacs lisp documentation interface."
+  :group 'docs
+  :group 'lisp
+  :group 'tools
+  :group 'help
+  :group 'matching)
+
+(defcustom hyper-apropos-show-brief-docs t
+  "*If non-nil, display some documentation in the \"*Hyper Apropos*\" buffer.
+Setting this to nil will speed up searches."
+  :type 'boolean
+  :group 'hyper-apropos)
+(define-obsolete-variable-alias
+  'hypropos-show-brief-docs 'hyper-apropos-show-brief-docs)
+;; I changed this to true because I think it's more useful this way. --ben
+
+(defcustom hyper-apropos-programming-apropos t
+  "*If non-nil, list all the functions and variables.
+This will cause more output to be generated, and take a longer time.
+
+Otherwise, only the interactive functions and user variables will be listed."
+  :type 'boolean
+  :group 'hyper-apropos)
+(define-obsolete-variable-alias
+  'hypropos-programming-apropos 'hyper-apropos-programming-apropos)
+
+(defcustom hyper-apropos-shrink-window nil
+  "*If non-nil, shrink *Hyper Help* buffer if possible."
+  :type 'boolean
+  :group 'hyper-apropos)
+(define-obsolete-variable-alias
+  'hypropos-shrink-window 'hyper-apropos-shrink-window)
+
+(defcustom hyper-apropos-prettyprint-long-values t
+  "*If non-nil, then try to beautify the printing of very long values."
+  :type 'boolean
+  :group 'hyper-apropos)
+(define-obsolete-variable-alias
+  'hypropos-prettyprint-long-values 'hyper-apropos-prettyprint-long-values)
+
+(defgroup hyper-apropos-faces nil
+  "Faces defined by hyper-apropos."
+  :prefix "hyper-apropos-"
+  :group 'faces)
+
+(defface hyper-apropos-documentation
+  '((((class color) (background light))
+     (:foreground "darkred"))
+    (((class color) (background dark))
+     (:foreground "gray90")))
+  "Hyper-apropos documentation."
+  :group 'hyper-apropos-faces)
+
+(defface hyper-apropos-hyperlink
+  '((((class color) (background light))
+     (:foreground "blue4"))
+    (((class color) (background dark))
+     (:foreground "lightseagreen"))
+    (t
+     (:bold t)))
+  "Hyper-apropos hyperlinks."
+  :group 'hyper-apropos-faces)
+
+(defface hyper-apropos-major-heading '((t (:bold t)))
+  "Hyper-apropos major heading."
+  :group 'hyper-apropos-faces)
+
+(defface hyper-apropos-section-heading '((t (:bold t :italic t)))
+  "Hyper-apropos section heading."
+  :group 'hyper-apropos-faces)
+
+(defface hyper-apropos-heading '((t (:bold t)))
+  "Hyper-apropos heading."
+  :group 'hyper-apropos-faces)
+
+(defface hyper-apropos-warning '((t (:bold t :foreground "red")))
+  "Hyper-apropos warning."
+  :group 'hyper-apropos-faces)
+
+;;; Internal variables below this point
+
+(defvar hyper-apropos-ref-buffer)
+(defvar hyper-apropos-prev-wconfig)
+
+(defvar hyper-apropos-help-map
+  (let ((map (make-sparse-keymap)))
+    (suppress-keymap map)
+    (set-keymap-name map 'hyper-apropos-help-map)
+    ;; movement
+    (define-key map " "     'scroll-up)
+    (define-key map "b"     'scroll-down)
+    (define-key map [delete] 'scroll-down)
+    (define-key map [backspace] 'scroll-down)
+    (define-key map "/"     'isearch-forward)
+    (define-key map "?"     'isearch-backward)
+    ;; follow links
+    (define-key map [return] 'hyper-apropos-get-doc)
+    (define-key map "s"     'hyper-apropos-set-variable)
+    (define-key map "t"     'hyper-apropos-find-tag)
+    (define-key map "l"     'hyper-apropos-last-help)
+    (define-key map "c"     'hyper-apropos-customize-variable)
+    (define-key map "f"     'hyper-apropos-find-function)
+    (define-key map [button2] 'hyper-apropos-mouse-get-doc)
+    (define-key map [button3] 'hyper-apropos-popup-menu)
+    ;; for the totally hardcore...
+    (define-key map "D"     'hyper-apropos-disassemble)
+    ;; administrativa
+    (define-key map "a"     'hyper-apropos)
+    (define-key map "n"     'hyper-apropos)
+    (define-key map "q"     'hyper-apropos-quit)
+    map)
+  "Keybindings for the *Hyper Help* buffer and the *Hyper Apropos* buffer")
+(define-obsolete-variable-alias
+  'hypropos-help-map 'hyper-apropos-help-map)
+
+(defvar hyper-apropos-map
+  (let ((map (make-sparse-keymap)))
+    (set-keymap-name map 'hyper-apropos-map)
+    (set-keymap-parents map (list hyper-apropos-help-map))
+    ;; slightly different scrolling...
+    (define-key map " "     'hyper-apropos-scroll-up)
+    (define-key map "b"     'hyper-apropos-scroll-down)
+    (define-key map [delete] 'hyper-apropos-scroll-down)
+    (define-key map [backspace] 'hyper-apropos-scroll-down)
+    ;; act on the current line...
+    (define-key map "w"     'hyper-apropos-where-is)
+    (define-key map "i"     'hyper-apropos-invoke-fn)
+;; this is already defined in the parent-keymap above, isn't it?
+;;     (define-key map "s"     'hyper-apropos-set-variable)
+    ;; more administrativa...
+    (define-key map "P"     'hyper-apropos-toggle-programming-flag)
+    (define-key map "k"     'hyper-apropos-add-keyword)
+    (define-key map "e"     'hyper-apropos-eliminate-keyword)
+    map)
+  "Keybindings for the *Hyper Apropos* buffer.
+This map inherits from `hyper-apropos-help-map.'")
+(define-obsolete-variable-alias
+  'hypropos-map 'hyper-apropos-map)
+
+;;(defvar hyper-apropos-mousable-keymap
+;;  (let ((map (make-sparse-keymap)))
+;;    (define-key map [button2] 'hyper-apropos-mouse-get-doc)
+;;    map))
+
+(defvar hyper-apropos-mode-hook nil
+  "*User function run after hyper-apropos mode initialization.  Usage:
+\(setq hyper-apropos-mode-hook '(lambda () ... your init forms ...)).")
+
+;; ---------------------------------------------------------------------- ;;
+
+(defconst hyper-apropos-junk-regexp
+  "^Apropos\\|^Functions\\|^Variables\\|^$")
+
+(defvar hyper-apropos-currently-showing nil)	; symbol documented in
+						; help buffer now
+(defvar hyper-apropos-help-history nil)	; chain of symbols followed as links in
+					; help buffer
+(defvar hyper-apropos-face-history nil)
+;;;(defvar hyper-apropos-variable-history nil)
+;;;(defvar hyper-apropos-function-history nil)
+(defvar hyper-apropos-regexp-history nil)
+(defvar hyper-apropos-last-regexp nil)	; regex used for last apropos
+(defconst hyper-apropos-apropos-buf "*Hyper Apropos*")
+(defconst hyper-apropos-help-buf "*Hyper Help*")
+
+;;;###autoload
+(defun hyper-apropos (regexp toggle-apropos)
+  "Display lists of functions and variables matching REGEXP
+in buffer \"*Hyper Apropos*\".  If optional prefix arg is given, then the
+value of `hyper-apropos-programming-apropos' is toggled for this search.
+See also `hyper-apropos-mode'."
+  (interactive (list (read-from-minibuffer "List symbols matching regexp: "
+					   nil nil nil 'hyper-apropos-regexp-history)
+		     current-prefix-arg))
+  (or (memq major-mode '(hyper-apropos-mode hyper-apropos-help-mode))
+      (setq hyper-apropos-prev-wconfig (current-window-configuration)))
+  (if (string= "" regexp)
+      (if (get-buffer hyper-apropos-apropos-buf)
+	  (if toggle-apropos
+	      (hyper-apropos-toggle-programming-flag)
+	    (message "Using last search results"))
+	(error "Be more specific..."))
+    (set-buffer (get-buffer-create hyper-apropos-apropos-buf))
+    (setq buffer-read-only nil)
+    (erase-buffer)
+    (if toggle-apropos
+	(set (make-local-variable 'hyper-apropos-programming-apropos)
+	     (not (default-value 'hyper-apropos-programming-apropos))))
+    (let ((flist (apropos-internal regexp
+				   (if hyper-apropos-programming-apropos
+				       #'fboundp
+				     #'commandp)))
+	  (vlist (apropos-internal regexp
+				   (if hyper-apropos-programming-apropos
+				       #'boundp
+				     #'user-variable-p))))
+      (insert-face (format "Apropos search for: %S\n\n" regexp)
+		   'hyper-apropos-major-heading)
+      (insert-face "* = command (M-x) or user-variable.\n"
+		   'hyper-apropos-documentation)
+      (insert-face "\
+a = autoloaded, b = byte-compiled, i = internal, l = lambda, m = macro.\n\n"
+		   'hyper-apropos-documentation)
+      (insert-face "Functions and Macros:\n\n" 'hyper-apropos-major-heading)
+      (hyper-apropos-grok-functions flist)
+      (insert-face "\n\nVariables and Constants:\n\n"
+		   'hyper-apropos-major-heading)
+      (hyper-apropos-grok-variables vlist)
+      (goto-char (point-min))))
+  (switch-to-buffer hyper-apropos-apropos-buf)
+  (hyper-apropos-mode regexp))
+
+(defun hyper-apropos-toggle-programming-flag ()
+  (interactive)
+  (with-current-buffer hyper-apropos-apropos-buf
+    (set (make-local-variable 'hyper-apropos-programming-apropos)
+	 (not hyper-apropos-programming-apropos)))
+  (message "Re-running apropos...")
+  (hyper-apropos hyper-apropos-last-regexp nil))
+
+(defun hyper-apropos-grok-functions (fns)
+  (let (bind doc type)
+    (dolist (fn fns)
+      (setq bind (symbol-function fn)
+	    type (cond ((subrp bind) ?i)
+		       ((compiled-function-p bind) ?b)
+		       ((consp bind) (or (cdr
+					  (assq (car bind) '((autoload . ?a)
+							     (lambda . ?l)
+							     (macro . ?m))))
+					 ??))
+		       (t ?\ )))
+      (insert type (if (commandp fn) "* " "  "))
+      (let ((e (insert-face (format "%S" fn) 'hyper-apropos-hyperlink)))
+	(set-extent-property e 'mouse-face 'highlight))
+      (insert-char ?\  (let ((l (- 30 (length (format "%S" fn)))))
+			 (if (natnump l) l 0)))
+      (and hyper-apropos-show-brief-docs
+	   (setq doc
+	   ;; A symbol's function slot can point to an unbound symbol.
+	   ;; In that case, `documentation' will fail.
+		 (ignore-errors
+		   (documentation fn)))
+	   (if  (string-match
+		 "^([^\n\t )]+[\t ]*\\([^\n)]+\\)?)\\(:[\t ]*\\|\n?\\'\\)"
+		 doc)
+	       (setq doc (substring doc (match-end 0) (string-match "\n" doc)))
+	     t)
+	   (insert-face (if doc
+			    (concat " - "
+				    (substring doc 0 (string-match "\n" doc)))
+			  " Not documented.")
+			'hyper-apropos-documentation))
+      (insert ?\n))))
+
+(defun hyper-apropos-grok-variables (vars)
+  (let (doc userp)
+    (dolist (var vars)
+      (setq userp (user-variable-p var))
+      (insert (if userp " * " "   "))
+      (let ((e (insert-face (format "%S" var) 'hyper-apropos-hyperlink)))
+	(set-extent-property e 'mouse-face 'highlight))
+      (insert-char ?\  (let ((l (- 30 (length (format "%S" var)))))
+			 (if (natnump l) l 0)))
+      (and hyper-apropos-show-brief-docs
+	   (setq doc (documentation-property var 'variable-documentation))
+	   (insert-face (if doc
+			    (concat " - " (substring doc (if userp 1 0)
+						     (string-match "\n" doc)))
+			  " - Not documented.")
+			'hyper-apropos-documentation))
+      (insert ?\n))))
+
+;; ---------------------------------------------------------------------- ;;
+
+(defun hyper-apropos-mode (regexp)
+  "Improved apropos mode for displaying Emacs documentation.  Function and
+variable names are displayed in the buffer \"*Hyper Apropos*\".  
+
+Functions are preceded by a single character to indicates their types:
+    a = autoloaded, b = byte-compiled, i = internal, l = lambda, m = macro.
+Interactive functions are also preceded by an asterisk.
+Variables are preceded by an asterisk if they are user variables.
+
+General Commands:
+
+  	SPC	- scroll documentation or apropos window forward
+  	  b	- scroll documentation or apropos window backward
+	  k     - eliminate all hits that don't contain keyword
+	  n	- new search
+  	  /	- isearch-forward
+  	  q	- quit and restore previous window configuration
+  
+  Operations for Symbol on Current Line:
+  
+      	RET 	- toggle display of symbol's documentation
+		  (also on button2 in xemacs)
+  	  w     - show the keybinding if symbol is a command
+  	  i	- invoke function on current line
+  	  s	- set value of variable on current line
+	  t	- display the C or lisp source (find-tag)"
+  (delete-other-windows)
+  (setq mode-name "Hyper-Apropos"
+	major-mode 'hyper-apropos-mode
+	buffer-read-only t
+	truncate-lines t
+	hyper-apropos-last-regexp regexp
+	modeline-buffer-identification
+	(list (cons modeline-buffer-id-left-extent "Hyper Apropos: ")
+	      (cons modeline-buffer-id-right-extent (concat "\"" regexp "\""))))
+  (use-local-map hyper-apropos-map)
+  (run-hooks 'hyper-apropos-mode-hook))
+
+;; ---------------------------------------------------------------------- ;;
+
+;; similar to `describe-key-briefly', copied from prim/help.el by CW
+
+;;;###autoload
+(defun hyper-describe-key (key)
+  (interactive "kDescribe key: ")
+  (hyper-describe-key-briefly key t))
+
+;;;###autoload
+(defun hyper-describe-key-briefly (key &optional show)
+  (interactive "kDescribe key briefly: \nP")
+  (let (menup defn interm final msg)
+    (setq defn (key-or-menu-binding key 'menup))    
+    (if (or (null defn) (integerp defn))
+        (or (numberp show) (message "%s is undefined" (key-description key)))
+      (cond ((stringp defn)
+	     (setq interm defn
+		   final (key-binding defn)))
+	    ((vectorp defn)
+	     (setq interm (append defn nil))
+	     (while (and interm
+			 (member (key-binding (vector (car interm)))
+				 '(universal-argument digit-argument)))
+	       (setq interm (cdr interm)))
+	     (while (and interm
+			 (not (setq final (key-binding (vconcat interm)))))
+	       (setq interm (butlast interm)))
+	     (if final
+		 (setq interm (vconcat interm))
+	       (setq interm defn 
+		     final (key-binding defn)))))
+      (setq msg (format
+		 "%s runs %s%s%s"
+		 ;; This used to say 'This menu item' but it could also
+		 ;; be a scrollbar event.  We can't distinguish at the
+		 ;; moment.
+		 (if menup "This item" (key-description key))
+		 ;;(if (symbolp defn) defn (key-description defn))
+		 (if (symbolp defn) defn (prin1-to-string defn))
+		 (if final (concat ", " (key-description interm) " runs ") "")
+		 (if final
+		     (if (symbolp final) final (prin1-to-string final))
+		   "")))
+      (if (numberp show)
+	  (or (not (symbolp defn))
+	      (memq (symbol-function defn)
+		    '(zkey-init-kbd-macro zkey-init-kbd-fn))
+	      (progn (princ msg) (princ "\n")))
+	(message "%s" msg)
+	(if final (setq defn final))
+	(if (and (or (symbolp defn) (symbolp (setq defn (car-safe defn))))
+		 defn
+		 show)
+	    (hyper-apropos-get-doc defn t))))))
+
+;;;###autoload
+(defun hyper-describe-face (symbol &optional this-ref-buffer)
+  "Describe face..
+See also `hyper-apropos' and `hyper-describe-function'."
+  ;; #### - perhaps a prefix arg should suppress the prompt...
+  (interactive
+   (let (v val)
+     (setq v (hyper-apropos-this-symbol))	; symbol under point
+     (or (find-face v)
+	 (setq v (variable-at-point)))
+     (setq val (let ((enable-recursive-minibuffers t))
+                 (completing-read
+		  (concat (if (hyper-apropos-follow-ref-buffer current-prefix-arg)
+			      "Follow face"
+			    "Describe face")
+			  (if v
+			      (format " (default %s): " v)
+			    ": "))
+		  (mapcar (function (lambda (x) (list (symbol-name x))))
+			  (face-list))
+		  nil t nil 'hyper-apropos-face-history)))
+     (list (if (string= val "")
+	       (progn (push (symbol-name v) hyper-apropos-face-history) v)
+	     (intern-soft val))
+	   current-prefix-arg)))
+  (if (null symbol)
+      (message "Sorry, nothing to describe.")
+    (or (memq major-mode '(hyper-apropos-mode hyper-apropos-help-mode))
+	(setq hyper-apropos-prev-wconfig (current-window-configuration)))
+    (hyper-apropos-get-doc symbol t nil this-ref-buffer)))
+
+;;;###autoload
+(defun hyper-describe-variable (symbol &optional this-ref-buffer)
+  "Hypertext drop-in replacement for `describe-variable'.
+See also `hyper-apropos' and `hyper-describe-function'."
+  ;; #### - perhaps a prefix arg should suppress the prompt...
+  (interactive (list (hyper-apropos-read-variable-symbol
+		      (if (hyper-apropos-follow-ref-buffer current-prefix-arg)
+			  "Follow variable"
+			"Describe variable"))
+		     current-prefix-arg))
+  (if (null symbol)
+      (message "Sorry, nothing to describe.")
+    (or (memq major-mode '(hyper-apropos-mode hyper-apropos-help-mode))
+	(setq hyper-apropos-prev-wconfig (current-window-configuration)))
+    (hyper-apropos-get-doc symbol t nil this-ref-buffer)))
+
+(defun hyper-where-is (symbol)
+  "Print message listing key sequences that invoke specified command."
+  (interactive (list (hyper-apropos-read-function-symbol "Where is function")))
+  (if (null symbol)
+      (message "Sorry, nothing to describe.")
+    (where-is symbol)))
+
+;;;###autoload
+(defun hyper-describe-function (symbol &optional this-ref-buffer)
+  "Hypertext replacement for `describe-function'.  Unlike `describe-function'
+in that the symbol under the cursor is the default if it is a function.
+See also `hyper-apropos' and `hyper-describe-variable'."
+  ;; #### - perhaps a prefix arg should suppress the prompt...
+  (interactive (list (hyper-apropos-read-function-symbol
+		      (if (hyper-apropos-follow-ref-buffer current-prefix-arg)
+			  "Follow function"
+			"Describe function"))
+		     current-prefix-arg))
+  (if (null symbol)
+      (message "Sorry, nothing to describe.")
+    (or (memq major-mode '(hyper-apropos-mode hyper-apropos-help-mode))
+	(setq hyper-apropos-prev-wconfig (current-window-configuration)))
+    (hyper-apropos-get-doc symbol t nil this-ref-buffer)))
+
+;;;###autoload
+(defun hyper-apropos-read-variable-symbol (prompt &optional predicate)
+  "Hypertext drop-in replacement for `describe-variable'.
+See also `hyper-apropos' and `hyper-describe-function'."
+  ;; #### - perhaps a prefix arg should suppress the prompt...
+  (or predicate (setq predicate 'boundp))
+  (let (v val)
+    (setq v (hyper-apropos-this-symbol))	; symbol under point
+    (or (funcall predicate v)
+	(setq v (variable-at-point)))
+    (or (funcall predicate v)
+	(setq v nil))
+    (setq val (let ((enable-recursive-minibuffers t))
+		(completing-read
+		 (concat prompt
+			 (if v
+			     (format " (default %s): " v)
+			   ": "))
+		 obarray predicate t nil 'variable-history)))
+    (if (string= val "")
+	(progn (push (symbol-name v) variable-history) v)
+      (intern-soft val))))
+;;;###autoload
+(define-obsolete-function-alias
+  'hypropos-read-variable-symbol 'hyper-apropos-read-variable-symbol)
+
+(defun hyper-apropos-read-function-symbol (prompt)
+  "Read function symbol from minibuffer."
+  (let ((fn (hyper-apropos-this-symbol))
+	val)
+    (or (fboundp fn)
+	(setq fn (function-at-point)))
+    (setq val (let ((enable-recursive-minibuffers t))
+		(completing-read (if fn
+				     (format "%s (default %s): " prompt fn)
+				   (format "%s: " prompt))
+				 obarray 'fboundp t nil
+				 'function-history)))
+    (if (equal val "")
+	(progn (push (symbol-name fn) function-history) fn)
+      (intern-soft val))))
+
+(defun hyper-apropos-last-help (arg)
+  "Go back to the last symbol documented in the *Hyper Help* buffer."
+  (interactive "P")
+  (let ((win (get-buffer-window hyper-apropos-help-buf)))
+    (or arg (setq arg (if win 1 0)))
+    (cond ((= arg 0))
+	  ((<= (length hyper-apropos-help-history) arg)
+	   ;; go back as far as we can...
+	   (setcdr (nreverse hyper-apropos-help-history) nil))
+	  (t
+	   (setq hyper-apropos-help-history
+		 (nthcdr arg hyper-apropos-help-history))))
+    (if (or win (> arg 0))
+	(hyper-apropos-get-doc (car hyper-apropos-help-history) t)
+      (display-buffer hyper-apropos-help-buf))))
+
+(defun hyper-apropos-insert-face (string &optional face)
+  "Insert STRING and fontify some parts with face `hyper-apropos-hyperlink'."
+  (let ((beg (point)) end)
+    (insert-face string (or face 'hyper-apropos-documentation))
+    (setq end (point))
+    (goto-char beg)
+    (while (re-search-forward
+	    "`\\([-a-zA-Z0-9_][-a-zA-Z0-9_][-a-zA-Z0-9_.]+\\)'"
+	    end 'limit)
+      (let ((e (make-extent (match-beginning 1) (match-end 1))))
+	(set-extent-face e 'hyper-apropos-hyperlink)
+	(set-extent-property e 'mouse-face 'highlight))
+    (goto-char beg)
+    (while (re-search-forward
+	    "M-x \\([-a-zA-Z0-9_][-a-zA-Z0-9_][-a-zA-Z0-9_.]+\\)"
+	    end 'limit)
+      (let ((e (make-extent (match-beginning 1) (match-end 1))))
+	(set-extent-face e 'hyper-apropos-hyperlink)
+	(set-extent-property e 'mouse-face 'highlight))))))
+
+(defun hyper-apropos-insert-keybinding (keys string)
+  (if keys
+      (insert "  (" string " bound to \""
+	      (mapconcat 'key-description
+			 (sort* keys #'< :key #'length)
+			 "\", \"")
+	      "\")\n")))
+
+(defun hyper-apropos-insert-section-heading (alias-desc &optional desc)
+  (or desc (setq desc alias-desc
+		 alias-desc nil))
+  (if alias-desc
+      (setq desc (concat alias-desc
+			 (if (memq (aref desc 0)
+				   '(?a ?e ?i ?o ?u))
+			     ", an " ", a ")
+			 desc)))
+  (aset desc 0 (upcase (aref desc 0))) ; capitalize
+  (goto-char (point-max))
+  (newline 3) (delete-blank-lines) (newline 2)
+  (hyper-apropos-insert-face desc 'hyper-apropos-section-heading))
+
+(defun hyper-apropos-insert-value (string symbol val)
+  (insert-face string 'hyper-apropos-heading)
+  (insert (if (symbol-value symbol)
+	      (if (or (null val) (eq val t) (integerp val))
+		  (prog1
+		      (symbol-value symbol)
+		    (set symbol nil))
+		"see below")
+	    "is void")))
+
+(defun hyper-apropos-follow-ref-buffer (this-ref-buffer) 
+  (and (not this-ref-buffer)
+       (eq major-mode 'hyper-apropos-help-mode)
+       hyper-apropos-ref-buffer
+       (buffer-live-p hyper-apropos-ref-buffer)))
+
+(defun hyper-apropos-get-alias (symbol alias-p next-symbol &optional use)
+  "Return (TERMINAL-SYMBOL . ALIAS-DESC)."
+  (let (aliases)
+    (while (funcall alias-p symbol)
+      (setq aliases (cons (if use (funcall use symbol) symbol) aliases))
+      (setq symbol (funcall next-symbol symbol)))
+    (cons symbol
+	  (and aliases
+	       (concat "an alias for `"
+		       (mapconcat 'symbol-name
+				  (nreverse aliases)
+				  "',\nwhich is an alias for `")
+		       "'")))))
+
+(defun hyper-apropos-get-doc (&optional symbol force type this-ref-buffer)
+  ;; #### - update this docstring
+  "Toggle display of documentation for the symbol on the current line."
+  ;; SYMBOL is the symbol to document.  FORCE, if non-nil, means to
+  ;; regenerate the documentation even if it already seems to be there.  And
+  ;; TYPE, if present, forces the generation of only variable documentation
+  ;; or only function documentation.  Normally, if both are present, then
+  ;; both will be generated.
+  ;;
+  ;; TYPES TO IMPLEMENT: obsolete face
+  ;;
+  (interactive)
+  (or symbol
+      (setq symbol (hyper-apropos-this-symbol)))
+  (or type
+      (setq type '(function variable face)))
+  (if (and (eq hyper-apropos-currently-showing symbol)
+	   (get-buffer hyper-apropos-help-buf)
+	   (get-buffer-window hyper-apropos-help-buf)
+	   (not force))
+      ;; we're already displaying this help, so toggle its display.
+      (delete-windows-on hyper-apropos-help-buf)
+    ;; OK, we've got to refresh and display it...
+    (or (eq symbol (car hyper-apropos-help-history))
+	(setq hyper-apropos-help-history
+	      (if (eq major-mode 'hyper-apropos-help-mode)
+		  ;; if we're following a link in the help buffer, then
+		  ;; record that in the help history.
+		  (cons symbol hyper-apropos-help-history)
+		;; otherwise clear the history because it's a new search.
+		(list symbol))))
+    (save-excursion
+      (if (hyper-apropos-follow-ref-buffer this-ref-buffer)
+	  (set-buffer hyper-apropos-ref-buffer)
+	(setq hyper-apropos-ref-buffer (current-buffer)))
+      (let (standard-output
+	    ok beg
+	    newsym symtype doc obsolete
+	    (local mode-name)
+	    global local-str global-str
+	    font fore back undl
+	    aliases alias-desc desc)
+	(save-excursion
+	  (set-buffer (get-buffer-create hyper-apropos-help-buf))
+	  ;;(setq standard-output (current-buffer))
+	  (setq buffer-read-only nil)
+	  (erase-buffer)
+	  (insert-face (format "`%s'" symbol) 'hyper-apropos-major-heading)
+	  (insert (format " (buffer: %s, mode: %s)\n"
+			  (buffer-name hyper-apropos-ref-buffer)
+			  local)))
+	;; function ----------------------------------------------------------
+	(and (memq 'function type)
+	     (fboundp symbol)
+	     (progn
+	       (setq ok t)
+	       (setq aliases (hyper-apropos-get-alias (symbol-function symbol)
+						 'symbolp
+						 'symbol-function)
+		     newsym (car aliases)
+		     alias-desc (cdr aliases))
+	       (if (eq 'macro (car-safe newsym))
+		   (setq desc "macro"
+			 newsym (cdr newsym))
+		 (setq desc "function"))
+	       (setq symtype (cond ((subrp newsym)                   'subr)
+				   ((compiled-function-p newsym)     'bytecode)
+				   ((eq (car-safe newsym) 'autoload) 'autoload)
+				   ((eq (car-safe newsym) 'lambda)   'lambda))
+		     desc (concat (if (commandp symbol) "interactive ")
+				  (cdr (assq symtype
+					     '((subr     . "built-in ")
+					       (bytecode . "compiled Lisp ")
+					       (autoload . "autoloaded Lisp ")
+					       (lambda   . "Lisp "))))
+				  desc
+				  (if (eq symtype 'autoload)
+				      (format ", (autoloaded from \"%s\")"
+				      (nth 1 newsym))))
+		     local (current-local-map)
+		     global (current-global-map)
+		     obsolete (get symbol 'byte-obsolete-info)
+		     doc (or (documentation symbol) "function not documented"))
+	       (save-excursion
+		 (set-buffer hyper-apropos-help-buf)
+		 (goto-char (point-max))
+		 (setq standard-output (current-buffer))
+		 (hyper-apropos-insert-section-heading alias-desc desc)
+		 (insert ":\n")
+		 (if local
+		     (hyper-apropos-insert-keybinding
+		      (where-is-internal symbol (list local) nil nil nil)
+		      "locally"))
+		 (hyper-apropos-insert-keybinding
+		  (where-is-internal symbol (list global) nil nil nil)
+		  "globally")
+		 (insert "\n")
+		 (if obsolete
+		     (hyper-apropos-insert-face
+		      (format "%s is an obsolete function; %s\n\n" symbol
+			      (if (stringp (car obsolete))
+				  (car obsolete)
+				(format "use `%s' instead." (car obsolete))))
+		      'hyper-apropos-warning))
+		 (setq beg (point))
+		 (insert-face "arguments: " 'hyper-apropos-heading)
+		 (cond ((eq symtype 'lambda)
+			(princ (or (nth 1 newsym) "()")))
+		       ((eq symtype 'bytecode)
+			(princ (or (compiled-function-arglist newsym)
+				   "()")))
+		       ((and (eq symtype 'subr)
+			     (string-match
+			      "[\n\t ]*\narguments: ?\\((.*)\\)\n?\\'"
+			      doc))
+			(insert (substring doc
+					   (match-beginning 1)
+					   (match-end 1)))
+			(setq doc (substring doc 0 (match-beginning 0))))
+		       ((and (eq symtype 'subr)
+			     (string-match
+			      "\
+\[\n\t ]*([^\n\t )]+[\t ]*\\([^\n)]+\\)?)\\(:[\t ]*\\|\n?\\'\\)"
+			      doc))
+			(insert "("
+				(if (match-end 1)
+				    (substring doc
+					       (match-beginning 1)
+					       (match-end 1)))
+				")")
+			(setq doc (substring doc (match-end 0))))
+		       (t (princ "[not available]")))
+		 (insert "\n\n")
+		 (hyper-apropos-insert-face doc)
+		 (insert "\n")
+		 (indent-rigidly beg (point) 2))))
+	;; variable ----------------------------------------------------------
+	(and (memq 'variable type)
+	     (or (boundp symbol) (default-boundp symbol))
+	     (progn 
+	       (setq ok t)
+	       (setq aliases (hyper-apropos-get-alias symbol
+						 'variable-alias
+						 'variable-alias
+						 'variable-alias)
+		     newsym (car aliases)
+		     alias-desc (cdr aliases))
+	       (setq symtype (or (local-variable-p newsym (current-buffer))
+				 (and (local-variable-p newsym
+							(current-buffer) t)
+				      'auto-local))
+		     desc (concat (and (get newsym 'custom-type)
+				       "customizable ")
+				  (if (user-variable-p newsym)
+				      "user variable"
+				    "variable")
+				  (cond ((eq symtype t) ", buffer-local")
+					((eq symtype 'auto-local)
+					 ", local when set")))
+		     local (and (boundp newsym)
+				(symbol-value newsym))
+		     local-str (and (boundp newsym)
+				    (prin1-to-string local))
+		     global (and (eq symtype t)
+				 (default-boundp newsym)
+				 (default-value newsym))
+		     global-str (and (eq symtype t)
+				     (default-boundp newsym)
+				     (prin1-to-string global))
+		     obsolete (get symbol 'byte-obsolete-variable)
+		     doc (or (documentation-property symbol
+						     'variable-documentation)
+			     "variable not documented"))
+	       (save-excursion
+		 (set-buffer hyper-apropos-help-buf)
+		 (goto-char (point-max))
+		 (setq standard-output (current-buffer))
+		 (hyper-apropos-insert-section-heading alias-desc desc)
+		 (when (and (user-variable-p newsym)
+			    (get newsym 'custom-type))
+		   (let ((e (make-extent (point-at-bol) (point))))
+		     (set-extent-property e 'mouse-face 'highlight)
+		     (set-extent-property e 'help-echo
+					  (format "Customize %s" newsym))
+		     (set-extent-property
+		      e 'hyper-apropos-custom
+		      `(lambda () (customize-variable (quote ,newsym))))))
+		 (insert ":\n\n")
+		 (setq beg (point))
+		 (if obsolete
+		     (hyper-apropos-insert-face
+		      (format "%s is an obsolete function; %s\n\n" symbol
+			      (if (stringp obsolete)
+				  obsolete
+				(format "use `%s' instead." obsolete)))
+		      'hyper-apropos-warning))
+		 ;; generally, the value of the variable is short and the
+		 ;; documentation of the variable long, so it's desirable
+		 ;; to see all of the value and the start of the
+		 ;; documentation.  Some variables, though, have huge and
+		 ;; nearly meaningless values that force you to page
+		 ;; forward just to find the doc string.  That is
+		 ;; undesirable.
+		 (if (and (or (null local-str) (< (length local-str) 69))
+			  (or (null global-str) (< (length global-str) 69)))
+					; 80 cols.  docstrings assume this.
+		     (progn (insert-face "value: " 'hyper-apropos-heading)
+			    (insert (or local-str "is void"))
+			    (if (eq symtype t)
+				(progn
+				  (insert "\n")
+				  (insert-face "default value: " 'hyper-apropos-heading)
+				  (insert (or global-str "is void"))))
+			    (insert "\n\n")
+			    (hyper-apropos-insert-face doc))
+		   (hyper-apropos-insert-value "value: " 'local-str local)
+		   (if (eq symtype t)
+		       (progn
+			 (insert ", ")
+			 (hyper-apropos-insert-value "default-value: "
+						'global-str global)))
+		   (insert "\n\n")
+		   (hyper-apropos-insert-face doc)
+		   (if local-str
+		       (progn
+			 (newline 3) (delete-blank-lines) (newline 1)
+			 (insert-face "value: " 'hyper-apropos-heading)
+			 (if hyper-apropos-prettyprint-long-values
+			     (condition-case nil
+				 (let ((pp-print-readably nil)) (pprint local))
+			       (error (insert local-str)))
+			   (insert local-str))))
+		   (if global-str
+		       (progn
+			 (newline 3) (delete-blank-lines) (newline 1)
+			 (insert-face "default value: " 'hyper-apropos-heading)
+			 (if hyper-apropos-prettyprint-long-values
+			     (condition-case nil
+				 (let ((pp-print-readably nil)) (pprint global))
+			       (error (insert global-str)))
+			   (insert global-str)))))
+		 (indent-rigidly beg (point) 2))))
+	;; face --------------------------------------------------------------
+	(and (memq 'face type)
+	     (find-face symbol)
+	     (progn
+	       (setq ok t)
+	       (copy-face symbol 'hyper-apropos-temp-face 'global)
+	       (mapcar (function
+			(lambda (property)
+			  (setq symtype (face-property-instance symbol
+								property))
+			  (if symtype
+			      (set-face-property 'hyper-apropos-temp-face
+						 property
+						 symtype))))
+		       built-in-face-specifiers)
+	       (setq font (cons (face-property-instance symbol 'font nil 0 t)
+				(face-property-instance symbol 'font))
+		     fore (cons (face-foreground-instance symbol nil 0 t)
+				(face-foreground-instance symbol))
+		     back (cons (face-background-instance symbol nil 0 t)
+				(face-background-instance symbol))
+		     undl (cons (face-underline-p symbol nil 0 t)
+				(face-underline-p symbol))
+		     doc  (face-doc-string symbol))
+	       ;; #### - add some code here
+	       (save-excursion
+		 (set-buffer hyper-apropos-help-buf)
+		 (setq standard-output (current-buffer))
+		 (hyper-apropos-insert-section-heading
+		  (concat "Face"
+			  (when (get symbol 'face-defface-spec)
+			    (let* ((str " (customizable)")
+				   (e (make-extent 1 (length str) str)))
+			      (set-extent-property e 'mouse-face 'highlight)
+			      (set-extent-property e 'help-echo
+						   (format "Customize %s" symbol))
+			      (set-extent-property e 'unique t)
+			      (set-extent-property e 'duplicable t)
+			      (set-extent-property
+			       e 'hyper-apropos-custom
+			       `(lambda () (customize-face (quote ,symbol))))
+			      str))
+			  ":\n\n  "))
+		 (insert-face "\
+ABCDEFHIJKLMNOPQRSTUVWXYZ abcdefhijklmnopqrstuvwxyz 0123456789"
+			      'hyper-apropos-temp-face)
+		 (newline 2)
+		 (insert-face "  Font: " 'hyper-apropos-heading)
+		 (insert (format (if (numberp (car font)) "(%s)\n" "%s\n")
+				 (and (cdr font)
+				      (font-instance-name (cdr font)))))
+		 (insert-face "  Foreground: " 'hyper-apropos-heading)
+		 (insert (format (if (numberp (car fore)) "(%s)\n" "%s\n")
+				 (and (cdr fore)
+				      (color-instance-name (cdr fore)))))
+		 (insert-face "  Background: " 'hyper-apropos-heading)
+		 (insert (format (if (numberp (car back)) "(%s)\n" "%s\n")
+				 (and (cdr back)
+				      (color-instance-name (cdr back)))))
+		 (insert-face "  Underline: " 'hyper-apropos-heading)
+		 (insert (format (if (numberp (car undl)) "(%s)\n" "%s\n")
+				 (cdr undl)))
+		 (if doc
+		     (progn
+		       (newline)
+		       (setq beg (point))
+		       (insert doc)
+		       (indent-rigidly beg (point) 2))))))
+	;; not bound & property list -----------------------------------------
+	(or ok
+	    (save-excursion
+	      (set-buffer hyper-apropos-help-buf)
+	      (hyper-apropos-insert-section-heading
+	       "symbol is not currently bound\n")))
+	(if (and (setq symtype (symbol-plist symbol))
+		 (or (> (length symtype) 2)
+		     (not (memq 'variable-documentation symtype))))
+	    (save-excursion
+	      (set-buffer hyper-apropos-help-buf)
+	      (goto-char (point-max))
+	      (setq standard-output (current-buffer))
+	      (hyper-apropos-insert-section-heading "property-list:\n\n")
+	      (while symtype
+		(if (memq (car symtype)
+			  '(variable-documentation byte-obsolete-info))
+		    (setq symtype (cdr symtype))
+		  (insert-face (concat "  " (symbol-name (car symtype))
+				       ": ")
+			       'hyper-apropos-heading)
+		  (setq symtype (cdr symtype))
+		  (indent-to 32)
+		  (insert (prin1-to-string (car symtype)) "\n"))
+		(setq symtype (cdr symtype)))))))
+    (save-excursion
+      (set-buffer hyper-apropos-help-buf)
+      (goto-char (point-min)) 
+      ;; pop up window and shrink it if it's wasting space
+      (if hyper-apropos-shrink-window
+	  (shrink-window-if-larger-than-buffer
+	   (display-buffer (current-buffer)))
+	(display-buffer (current-buffer)))
+      (hyper-apropos-help-mode))
+    (setq hyper-apropos-currently-showing symbol)))
+;;;###autoload
+(define-obsolete-function-alias
+  'hypropos-get-doc 'hyper-apropos-get-doc)
+
+; -----------------------------------------------------------------------------
+
+(defun hyper-apropos-help-mode ()
+  "Major mode for hypertext XEmacs help.  In this mode, you can quickly
+follow links between back and forth between the documentation strings for
+different variables and functions.  Common commands:
+
+\\{hyper-apropos-help-map}"
+  (setq buffer-read-only t
+	major-mode	     'hyper-apropos-help-mode
+	mode-name	     "Hyper-Help")
+  (set-syntax-table emacs-lisp-mode-syntax-table)
+  (hyper-apropos-highlightify)
+  (use-local-map hyper-apropos-help-map))
+
+;; ---------------------------------------------------------------------- ;;
+
+(defun hyper-apropos-highlightify ()
+  (save-excursion
+    (goto-char (point-min))
+    (let ((st (point-min))
+	  sym)
+      (while (not (eobp))
+	(if (zerop (skip-syntax-forward "w_"))
+	    (forward-char 1)
+	  (and (> (- (point) st) 3)
+	       (setq sym (intern-soft (buffer-substring st (point))))
+	       (or (boundp sym)
+		   (fboundp sym))
+	       (set-extent-property (make-extent st (point))
+				    'mouse-face 'highlight)))
+	(setq st (point))))))
+
+;; ---------------------------------------------------------------------- ;;
+
+(defun hyper-apropos-scroll-up ()
+  "Scroll up the \"*Hyper Help*\" buffer if it's visible.
+Otherwise, scroll the selected window up."
+  (interactive)
+  (let ((win (get-buffer-window hyper-apropos-help-buf))
+	(owin (selected-window)))
+    (if win
+	(progn
+	  (select-window win)
+	  (condition-case nil
+	       (scroll-up nil)
+	      (error (goto-char (point-max))))
+	  (select-window owin))
+      (scroll-up nil))))
+
+(defun hyper-apropos-scroll-down ()
+  "Scroll down the \"*Hyper Help*\" buffer if it's visible.
+Otherwise, scroll the selected window down."
+  (interactive)
+  (let ((win (get-buffer-window hyper-apropos-help-buf))
+	(owin (selected-window)))
+    (if win
+	(progn
+	  (select-window win)
+	  (condition-case nil
+	       (scroll-down nil)
+	      (error (goto-char (point-max))))
+	  (select-window owin))
+      (scroll-down nil))))
+
+;; ---------------------------------------------------------------------- ;;
+
+(defun hyper-apropos-mouse-get-doc (event)
+  "Get the documentation for the symbol the mouse is on."
+  (interactive "e")
+  (mouse-set-point event)
+  (let ((e (extent-at (point) nil 'hyper-apropos-custom)))
+    (if e
+	(funcall (extent-property e 'hyper-apropos-custom))
+      (save-excursion
+	(let ((symbol (hyper-apropos-this-symbol)))
+	  (if symbol
+	      (hyper-apropos-get-doc symbol)
+	    (error "Click on a symbol")))))))
+
+;; ---------------------------------------------------------------------- ;;
+
+(defun hyper-apropos-add-keyword (pattern)
+  "Use additional keyword to narrow regexp match.
+Deletes lines which don't match PATTERN."
+  (interactive "sAdditional Keyword: ")
+  (save-excursion
+    (goto-char (point-min))
+    (let (buffer-read-only)
+      (keep-lines (concat pattern "\\|" hyper-apropos-junk-regexp))
+      )))
+
+(defun hyper-apropos-eliminate-keyword (pattern)
+  "Use additional keyword to eliminate uninteresting matches.
+Deletes lines which match PATTERN."
+  (interactive "sKeyword to eliminate: ")
+  (save-excursion
+    (goto-char (point-min))
+    (let (buffer-read-only)
+      (flush-lines pattern))
+      ))
+
+;; ---------------------------------------------------------------------- ;;
+
+(defun hyper-apropos-this-symbol ()
+  (save-excursion
+    (cond ((eq major-mode 'hyper-apropos-mode)
+	   (beginning-of-line)
+	   (if (looking-at hyper-apropos-junk-regexp)
+	       nil
+	     (forward-char 3)
+	     (read (point-marker))))
+	  (t
+	   (let* ((st (progn
+			(skip-syntax-backward "w_")
+			;; !@(*$^%%# stupid backquote implementation!!!
+			(skip-chars-forward "`")
+			(point)))
+		  (en (progn
+			(skip-syntax-forward "w_")
+			(skip-chars-backward ".':") ; : for Local Variables
+			(point))))
+	     (and (not (eq st en))
+		  (intern-soft (buffer-substring st en))))))))
+
+(defun hyper-apropos-where-is (symbol)
+  "Find keybinding for symbol on current line."
+  (interactive (list (hyper-apropos-this-symbol)))
+  (where-is symbol))
+
+(defun hyper-apropos-invoke-fn (fn)
+  "Interactively invoke the function on the current line."
+  (interactive (list (hyper-apropos-this-symbol)))
+  (cond ((not (fboundp fn))
+	 (error "%S is not a function" fn))
+	(t (call-interactively fn))))
+
+;;;###autoload
+(defun hyper-set-variable (var val &optional this-ref-buffer)
+  (interactive
+   (let ((var (hyper-apropos-read-variable-symbol
+	       (if (hyper-apropos-follow-ref-buffer current-prefix-arg)
+		   "In ref buffer, set user option"
+		 "Set user option")
+	       'user-variable-p)))
+     (list var (hyper-apropos-read-variable-value var) current-prefix-arg)))
+  (hyper-apropos-set-variable var val this-ref-buffer))
+
+;;;###autoload
+(defun hyper-apropos-set-variable (var val &optional this-ref-buffer)
+  "Interactively set the variable on the current line."
+  (interactive
+   (let ((var (hyper-apropos-this-symbol)))
+     (or (and var (boundp var))
+	 (and (setq var (and (eq major-mode 'hyper-apropos-help-mode)
+			     (save-excursion
+			       (goto-char (point-min))
+			       (hyper-apropos-this-symbol))))
+	      (boundp var))
+	 (setq var nil))
+     (list var (hyper-apropos-read-variable-value var))))
+  (and var
+       (boundp var)
+       (progn
+	 (if (hyper-apropos-follow-ref-buffer this-ref-buffer)
+	     (save-excursion
+	       (set-buffer hyper-apropos-ref-buffer)
+	       (set var val))
+	   (set var val))
+	 (hyper-apropos-get-doc var t '(variable) this-ref-buffer))))
+;;;###autoload
+(define-obsolete-function-alias
+  'hypropos-set-variable 'hyper-apropos-set-variable)
+
+(defun hyper-apropos-read-variable-value (var &optional this-ref-buffer)
+  (and var
+       (boundp var)
+       (let ((prop (get var 'variable-interactive))
+	     (print-readably t)
+	     val str)
+	 (hyper-apropos-get-doc var t '(variable) current-prefix-arg)
+	 (if prop
+	     (call-interactively (list 'lambda '(arg)
+				       (list 'interactive prop)
+				       'arg))
+	   (setq val (if (hyper-apropos-follow-ref-buffer this-ref-buffer)
+			 (save-excursion
+			   (set-buffer hyper-apropos-ref-buffer)
+			   (symbol-value var))
+		       (symbol-value var))
+		 str (prin1-to-string val))
+	   (eval-minibuffer
+	    (format "Set %s `%s' to value (evaluated): "
+		    (if (user-variable-p var) "user option" "Variable")
+		    var)
+	    (condition-case nil
+		(progn
+		  (read str)
+		  (format (if (or (consp val)
+				  (and (symbolp val)
+				       (not (memq val '(t nil)))))
+			      "'%s" "%s")
+			  str))
+	      (error nil)))))))
+
+(defun hyper-apropos-customize-variable ()
+  (interactive)
+  (let ((var (hyper-apropos-this-symbol)))
+    (customize-variable var)))
+
+;; ---------------------------------------------------------------------- ;;
+
+(defun hyper-apropos-find-tag (&optional tag-name)
+  "Find the tag for the symbol on the current line in other window.  In
+order for this to work properly, the variable `tag-table-alist' or
+`tags-file-name' must be set so that a TAGS file with tags for the emacs
+source is found for the \"*Hyper Apropos*\" buffer."
+  (interactive)
+  ;; there ought to be a default tags file for this...
+  (or tag-name (setq tag-name (symbol-name (hyper-apropos-this-symbol))))
+  (find-tag-other-window (list tag-name)))
+
+;; ---------------------------------------------------------------------- ;;
+
+(defun hyper-apropos-find-function (fn)
+  "Find the function for the symbol on the current line in other
+window.  (See also `find-function'.)"
+  (interactive
+   (let ((fn (hyper-apropos-this-symbol)))
+     (or (fboundp fn)
+	 (and (setq fn (and (eq major-mode 'hyper-apropos-help-mode)
+			    (save-excursion
+			      (goto-char (point-min))
+			      (hyper-apropos-this-symbol))))
+	      (fboundp fn))
+	 (setq fn nil))
+     (list fn)))
+  (if fn
+      (find-function-other-window fn)))
+
+;; ---------------------------------------------------------------------- ;;
+
+(defun hyper-apropos-disassemble (sym)
+  "Disassemble FUN if it is byte-coded.  If it's a lambda, prettyprint it."
+  (interactive (list (hyper-apropos-this-symbol)))
+  (let ((fun sym) (trail nil) macrop)
+    (while (and (symbolp fun) (not (memq fun trail)))
+      (setq trail (cons fun trail)
+	    fun (symbol-function fun)))
+    (and (symbolp fun)
+	 (error "Loop detected in function binding of `%s'" fun))
+    (setq macrop (and  (consp fun)
+		       (eq 'macro (car fun))))
+    (cond ((compiled-function-p (if macrop (cdr fun) fun))
+	   (disassemble fun)
+	   (set-buffer "*Disassemble*")
+	   (goto-char (point-min))
+	   (forward-sexp 2)
+	   (insert (format " for function `%S'" sym))
+	   )
+	  ((consp fun)
+	   (with-output-to-temp-buffer "*Disassemble*"
+	     (pprint (if macrop
+			 (cons 'defmacro (cons sym (cdr (cdr fun))))
+		       (cons 'defun (cons sym (cdr fun))))))
+	   (set-buffer "*Disassemble*")
+	   (emacs-lisp-mode))
+	  ((or (vectorp fun) (stringp fun))
+	   ;; #### - do something fancy here
+	   (with-output-to-temp-buffer "*Disassemble*"
+	     (princ (format "%s is a keyboard macro:\n\n\t" sym))
+	     (prin1 fun)))
+	  (t
+	   (error "Sorry, cannot disassemble `%s'" sym)))))
+
+;; ---------------------------------------------------------------------- ;;
+
+(defun hyper-apropos-quit ()
+  (interactive)
+  "Quit Hyper Apropos and restore original window config."
+  (let ((buf (get-buffer hyper-apropos-apropos-buf)))
+    (and buf (bury-buffer buf)))
+  (set-window-configuration hyper-apropos-prev-wconfig))
+
+;; ---------------------------------------------------------------------- ;;
+
+;;;###autoload
+(defun hyper-apropos-popup-menu (event)
+  (interactive "e")
+  (mouse-set-point event)
+  (let* ((sym (or (hyper-apropos-this-symbol)
+		  (and (eq major-mode 'hyper-apropos-help-mode)
+		       (save-excursion
+			 (goto-char (point-min))
+			 (hyper-apropos-this-symbol)))))
+	 (notjunk (not (null sym)))
+	 (command-p (if (commandp sym) t))
+	 (variable-p (and sym (boundp sym)))
+	 (customizable-p (and variable-p
+			      (get sym 'custom-type)
+			      t))
+	 (function-p (fboundp sym))
+	 (apropos-p (eq 'hyper-apropos-mode
+			(save-excursion (set-buffer (event-buffer event))
+					major-mode)))
+	 (name (if sym (symbol-name sym) ""))
+	 (hyper-apropos-menu
+	  (delete
+	   nil
+	   (list (concat "Hyper-Help: " name)
+	    (vector "Display documentation" 'hyper-apropos-get-doc   notjunk)
+	    (vector "Set variable"	'hyper-apropos-set-variable variable-p)
+	    (vector "Customize variable" 'hyper-apropos-customize-variable
+		    customizable-p)
+	    (vector "Show keys for"     'hyper-apropos-where-is      command-p)
+	    (vector "Invoke command"	'hyper-apropos-invoke-fn     command-p)
+	    (vector "Find function"    'hyper-apropos-find-function function-p)
+	    (vector "Find tag"		'hyper-apropos-find-tag	notjunk)
+	    (and apropos-p
+		 ["Add keyword..." hyper-apropos-add-keyword	t])
+	    (and apropos-p
+		 ["Eliminate keyword..." hyper-apropos-eliminate-keyword  t])
+	    (if apropos-p
+		["Programmers' Apropos" hyper-apropos-toggle-programming-flag
+		 :style toggle :selected hyper-apropos-programming-apropos]
+	      ["Programmers' Help" hyper-apropos-toggle-programming-flag
+	       :style toggle :selected hyper-apropos-programming-apropos])
+	    (and hyper-apropos-programming-apropos
+		 (vector "Disassemble function"
+			 'hyper-apropos-disassemble
+			 function-p))
+	    ["Help"                     describe-mode           t]
+	    ["Quit"			hyper-apropos-quit		t]
+	    ))))
+    (popup-menu hyper-apropos-menu)))
+;;;###autoload
+(define-obsolete-function-alias
+  'hypropos-popup-menu 'hyper-apropos-popup-menu)
+
+(provide 'hyper-apropos)
+
+;; end of hyper-apropos.el