view lisp/help-fns.el @ 47576:b31c8ab7336a

Sync with version 2.0.20. Lengthy ChangeLog follows: 2002-09-22 Kai Gro?ohann <grossjoh@ls6.informatik.uni-dortmund.de> Version 2.0.20 released. 2002-09-20 Kai Gro?ohann <grossjoh@ls6.informatik.uni-dortmund.de> * net/tramp.el (tramp-completion-function-alist): Escape open paren in docstring. (tramp-user-regexp, tramp-host-regexp): Allow empty strings. (tramp-handle-insert-file-contents): Call tramp-message-for-buffer instead of tramp-message. (tramp-open-connection-rsh): Handle empty string as user name. (tramp-open-connection-su): Handle empty string as host name. Handle nil user name. (tramp-handle-file-local-copy, tramp-handle-write-region) (tramp-completion-handle-file-name-all-completions) (tramp-open-connection-telnet, tramp-open-connection-rsh) (tramp-open-connection-su, tramp-post-connection) (tramp-maybe-open-connection, tramp-method-out-of-band-p) (tramp-get-connection-function, tramp-get-remote-sh) (tramp-get-rsh-program, tramp-get-rsh-args) (tramp-get-rcp-program, tramp-get-rcp-args) (tramp-get-rcp-keep-date-arg, tramp-get-su-program) (tramp-get-su-args, tramp-get-telnet-program) (tramp-get-telnet-args): Use `tramp-find-method', perhaps require additional args USER, HOST. (tramp-action-password, tramp-open-connection-telnet) (tramp-open-connection-su, tramp-open-connection-multi) (tramp-method-out-of-band-p): `tramp-method-out-of-band-p' now takes USER and HOST arguments, to be able to use `tramp-find-method'. Update callers. (tramp-find-method): New function. 2002-09-20 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> * net/tramp.el (tramp-handle-insert-directory): Handle "--dired" in SWITCHES (by removing it). 2002-09-18 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> * net/tramp.el (tramp-file-name-handler): Add `file-remote-p' property. 2002-09-17 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> * net/tramp.el (top-level): Maybe autoload uudecode-decode-region. 2002-09-16 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> * net/tramp.el (tramp-bug): Add tramp-methods. 2002-09-16 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> * net/tramp.el (tramp-methods): Update docstring: tramp-encoding-command, tramp-decoding-command, tramp-encoding-function and tramp-decoding-function are not parameters anymore. (tramp-uuencode-region): Autoload it. 2002-09-13 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> Version 2.0.19 released. * net/tramp-uu.el: New file, implements uuencode in Lisp. * net/tramp.el (tramp-coding-commands): Use `tramp-uuencode-region' as local encoder for the uuencode based entries. 2002-09-13 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> * net/tramp.el (tramp-handle-write-region): Wrong parens. 2002-09-13 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> Version 2.0.18 released. * net/tramp.el (tramp-perl-decode): Perl changes to accomodate older versions of Perl. Now tested with 5.004. Suggestion from Michael Albinus. 2002-09-12 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> * net/tramp.el (tramp-find-inline-encoding): Call tramp-call-local-coding-command with nil for INPUT and OUTPUT. (tramp-call-local-coding-command): OUTPUT equals nil means to discard the output. INPUT equals nil means /dev/null. 2002-09-12 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> * net/tramp.el (tramp-encoding-shell): Default to environment variable COMSPEC on Windows. (tramp-handle-write-region): More debugging output. (tramp-find-inline-encoding): Ditto. 2002-09-11 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-completion-handle-file-name-all-completions): Define `result1'. (tramp-parse-hosts-group): Discard IPv6 entries. 2002-09-11 Kai Gro?ohann <grossjoh@ls6.informatik.uni-dortmund.de> * net/tramp.el (tramp-post-connection): Only send Perl mime-encode/decode implementations when using inline method. (tramp-handle-file-local-copy) (tramp-handle-write-region, tramp-post-connection) (tramp-coding-commands, tramp-find-inline-encoding): For the inline encodings, distinguish between local and remote commands, instead of between commands and functions. (The local commands can be functions, too.) If the local host is a Windows machine, we can't expect the same commands to work there as on the remote host. (tramp-call-local-coding-command): New function for calling local encoding and decoding commands. (tramp-set-remote-encoding, tramp-get-remote-encoding) (tramp-set-remote-decoding, tramp-get-remote-decoding) (tramp-set-local-encoding, tramp-get-local-encoding) (tramp-set-local-decoding, tramp-get-local-decoding): New functions. (tramp-get-encoding-command, tramp-set-encoding-command) (tramp-get-decoding-command, tramp-set-decoding-command) (tramp-get-encoding-function, tramp-set-encoding-function) (tramp-get-decoding-function, tramp-set-decoding-function): Old functions, removed. 2002-09-10 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> * net/tramp.el (tramp-open-connection-setup-interactive-shell): Change command to invoke /bin/sh slightly to make it compatible with the `rc' shell. Suggested by Daniel Pittman. 2002-09-10 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-handle-write-region): Added missing `)'. Hope it's the right place. 2002-09-09 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> * net/tramp.el (tramp-open-connection-setup-interactive-shell): Do "exec env PS1='$ ' /bin/sh" instead of just "exec /bin/sh" in order to get a sane shell prompt. If people have ${CWD}, say, in their shell prompt, then the default login shell might display something harmless, but the /bin/sh will display a dollar sign which confused the subsequent prompt recognition. (tramp-multi-action-password): More debugging output. (tramp-encoding-shell): Renamed from tramp-sh-program. More documentation. Default to cmd.exe on Windows NT. (tramp-encoding-command-switch): New variable. Use instead of hard-wired "-c" which is only good for /bin/sh. (tramp-encoding-reads-stdin): New variable. If t, commands are called like "/bin/sh -c COMMAND <INPUT", if nil, they are called like "/bin/sh -c COMMAND INPUT", ie the input file is the last argument. (tramp-multi-sh-program): Always default to tramp-encoding-shell. (tramp-handle-file-local-copy, tramp-handle-write-region): Respect tramp-encoding-shell and friends. (tramp-find-inline-encoding): Use new-style calls for checking if the local commands work. 2002-09-07 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-methods): Remove `tramp-completion-function' entries. They are handled now by `tramp-completion-function-alist'. (tramp-completion-function): Defvar removed. I've never used it. Hmm. (tramp-get-completion-function) (tramp-get-completion-rsh, tramp-get-completion-ssh) (tramp-get-completion-telnet, tramp-get-completion-su): Functions removed as well. Not necessary any longer due to extended customization means. (tramp-completion-function-alist): New defcustom. Holds all FUNCTION FILE pairs used for user and host name completion relevant for METHOD. (tramp-completion-function-alist-rsh) (tramp-completion-function-alist-ssh) (tramp-completion-function-alist-telnet) (tramp-completion-function-alist-su): Defconst for initializing `tramp-completion-function-alist'. Unfortunately, mainly UNIX-like values are known for me until now. Needs to be completed for at least VMS++ like operating systems. (tramp-set-completion-function) (tramp-get-completion-function): New functions for configuration of `tramp-completion-function-alist'. The old definition of `tramp-get-completion-function' has been discarded. (tramp-completion-handle-file-name-all-completions): Change function call for user/host completion according to definition in `tramp-completion-function-alist'. (tramp-parse-passwd): Added exception handling for "root", because `tramp-get-completion-su' (the previous place for this stuff) doesn't exist any longer. 2002-09-07 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> * net/tramp.el (tramp-enter-password): Use `tramp-password-end-of-line' to terminate the line. (tramp-bug): Include new variable `tramp-password-end-of-line'. (tramp-password-end-of-line): New variable. People who use plink under Windows might have to issue "\r\n" after the password, but they need to send just "\n" after the other commands. So this variable was introduced to complement `tramp-rsh-end-of-line'. (tramp-wait-for-output, tramp-post-connection): Allow "\r" at end of line of the output delimiter. 2002-09-06 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> * net/tramp.el (tramp-handle-file-local-copy, tramp-find-shell) (tramp-open-connection-setup-interactive-shell): Add some comments about Douglas Grey Stephen's suggestions to make Tramp work better with plink under Windows. I'm not sure what to think of them, but now I have a guinea pig to try it out on. Said guinea pig is having other problems, though... Also remove some commented-out code. 2002-09-06 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-get-completion-methods): Algorithm slightly tuned. (tramp-get-completion-user-host): Accept user names as they are if typed until "@". (tramp-completion-mode): Replace `last-input-char' by modern `last-input-event'. Check for `event-modifiers'. 2002-09-06 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> * net/tramp.el (file-expand-wildcards): Corrected check to see if advising is necessary. 2002-09-05 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-postfix-single-method-format) (tramp-postfix-multi-method-format) (tramp-postfix-multi-hop-format) (tramp-postfix-user-format): New format strings. (tramp-postfix-single-method-regexp) (tramp-postfix-multi-method-regexp) (tramp-postfix-multi-hop-regexp) (tramp-postfix-user-regexp) (tramp-make-multi-tramp-file-format) (tramp-make-tramp-file-name): Apply them. (tramp-completion-handle-file-name-all-completions): Fix for invoking ange-ftp in case of "/ftp:xxx" file names. 2002-09-04 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-prefix-format) (tramp-postfix-host-format): New format strings. (tramp-prefix-regexp, tramp-method-regexp) (tramp-postfix-single-method-regexp) (tramp-postfix-multi-method-regexp) (tramp-postfix-multi-hop-regexp) (tramp-user-regexp, tramp-postfix-user-regexp) (tramp-host-regexp, tramp-postfix-host-regexp) (tramp-path-regexp): New atomar regular expressions. If corresponding format strings exist, derived from them. (tramp-file-name-structure) (tramp-multi-file-name-structure) (tramp-multi-file-name-hop-structure) (tramp-make-multi-tramp-file-format) (tramp-completion-mode) (tramp-completion-dissect-file-name) (tramp-parse-rhosts-group) (tramp-parse-shosts-group) (tramp-parse-hosts-group) (tramp-parse-passwd-group): Apply these expressions. (tramp-file-name-structure-unified) (tramp-file-name-structure-separate) (tramp-make-tramp-file-format-unified) (tramp-make-tramp-file-format-separate) (tramp-make-tramp-file-format) (tramp-make-tramp-file-user-nil-format-unified) (tramp-make-tramp-file-user-nil-format-separate) (tramp-make-tramp-file-user-nil-format) (tramp-multi-file-name-structure-unified) (tramp-multi-file-name-structure-separate) (tramp-multi-file-name-hop-structure-unified) (tramp-multi-file-name-hop-structure-separate) (tramp-make-multi-tramp-file-format-unified) (tramp-make-multi-tramp-file-format-separate): Removed. (tramp-make-tramp-file-name): Allow partial tramp file names. Generate tramp file format on-the-fly depending on parameters. Apply atomar format strings resp expressions. (tramp-get-completion-methods) (tramp-get-completion-user-host): Apply `tramp-make-tramp-file-name'. (tramp-parse-hosts-group): Take all host names and IP addresses into account. (tramp-bug): Remove `tramp-make-tramp-file-format'. 2002-09-01 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-methods): Add `tramp-completion-function' for "su" and "sudo". (tramp-get-completion-telnet): Implement it. (tramp-parse-hosts) (tramp-parse-hosts-group) (tramp-get-completion-su) (tramp-parse-passwd) (tramp-parse-passwd-group): New functions. 2002-08-31 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-completion-mode): Check for `last-input-char'. (tramp-completion-file-name-handler-alist): Add handler for `file-exists-p. (tramp-completion-handle-file-exists-p): New function. (tramp-completion-handle-file-name-completion): Simplified. (tramp-completion-dissect-file-name): Regexp's reorganised. (tramp-completion-handle-file-name-all-completions): Call completion-function only if `user' or `host' is given. (tramp-get-completion-user-host): New function. (tramp-get-completion-rsh) (tramp-get-completion-ssh): Apply it. 2002-08-29 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-completion-file-name-handler-alist): Add handler for `expand-file-name'. (tramp-completion-handle-expand-file-name): New function. 2002-08-26 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-completion-mode): New function. (tramp-completion-handle-file-name-directory) (tramp-completion-handle-file-name-all-completions): Apply it. (tramp-methods): Remove double definition of `ssh1-old' and `ssh2-old'. (tramp-point-at-eol): New defalias. (tramp-parse-rhosts-group) (tramp-parse-shosts-group):: Apply it. 2002-08-25 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-get-completion-methods) (tramp-get-completion-rsh) (tramp-get-completion-ssh): Add "[" for Xemacs. (tramp-completion-file-name-regexp-separate): Expression adapted. (tramp-completion-file-name-handler-alist): Add handler for `file-name-directory' and `file-name-nondirectory'. (tramp-completion-handle-file-name-directory) (tramp-completion-handle-file-name-nondirectory) (tramp-completion-run-real-handler): New functions. (tramp-completion-file-name-handler) (tramp-completion-handle-file-name-all-completions): Apply `tramp-completion-run-real-handler'. (tramp-parse-rhosts) (tramp-parse-shosts): Use `with-temp-buffer'. `result? renamed to `res' (otherwise side effects in XEmacs). 2002-08-24 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-completion-file-name-regexp) (tramp-completion-file-name-handler-alist) (tramp-flatten-list) (tramp-completion-dissect-file-name) (tramp-get-completion-rsh) (tramp-parse-rhosts) (tramp-parse-rhosts-group) (tramp-get-completion-ssh): Doc string tuned. (tramp-methods): Doc string and custom type extended for `tramp-completion-function'. (tramp-completion-function): Variable added. Is it really used? Other variables like `tramp-completion-function' aren't used. (tramp-completion-file-name-handler-alist): Add handler for `file-name-completion'. (tramp-completion-handle-file-name-completion): New function. 2002-08-18 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-parse-rhosts) (tramp-parse-rhosts-group) (tramp-parse-shosts) (tramp-parse-shosts-group): New functions. 2002-08-17 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-completion-dissect-file-name) (tramp-completion-dissect-file-name1): New functions. 2002-08-16 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-get-completion-function) (tramp-get-completion-rsh) (tramp-get-completion-ssh) (tramp-get-completion-telnet): New functions. (tramp-methods): Add `tramp-completion-function' for all methods. 2002-08-15 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-get-completion-methods): New function. (tramp-find-default-method): Allow host to be nil (like user). 2002-08-14 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-completion-file-name-regexp-unified) (tramp-completion-file-name-regexp-separate) (tramp-completion-file-name-regexp) (tramp-completion-file-name-handler-alist): New defcustoms. (tramp-completion-file-name-handler): New function. Add `tramp-completion-file-name-handler' to `file-name-handler-alist'. (tramp-run-real-handler): Add `tramp-completion-file-name-handler' to `inhibit-file-name-handlers'. (tramp-completion-handle-file-name-all-completions) (tramp-completion-handle-file-name-completion): New functions. 2002-08-12 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-invoke-ange-ftp): `tramp-disable-ange-ftp' must be called again after activating `ange-ftp'. (tramp-ange-ftp-file-name-p): Check for Xemacs. 2002-08-08 Michael Albinus <Michael.Albinus@alcatel.de> * net/tramp.el (tramp-do-copy-or-rename-file): Don't pass KEEP-DATE to tramp-invoke-ange-ftp 'rename. (tramp-handle-write-region): Don't pass LOCKNAME and CONFIRM to tramp-invoke-ange-ftp 'write-region. (tramp-handle-set-file-modes): Change order of FILENAME and MODE passing to tramp-invoke-ange-ftp 'set-file-modes. (tramp-flatten-list): New function. Maybe this functionality does exist already elsewhere in the libraries. (tramp-invoke-ange-ftp): Apply `tramp-flatten-list' to parameter list in order to avoid nested lists, f.e. when invoked from `tramp-handle-dired-call-process'. 2002-09-05 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> * net/tramp.el (tramp-chunksize): New kluge variable. (tramp-send-region): If tramp-chunksize is non-nil, send region in parts and sleep 0.1 seconds between chunks. 2002-09-03 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> * net/tramp.el (tramp-handle-insert-directory): Use `insert-buffer-substring' instead of `insert-buffer', which is not supposed to be used from Lisp. Remember old point in a variable instead of using `mark'. Suggestion from Stefan Monnier. (tramp-unified-filenames): New variable. Use it in default value of other filename variables. (file-expand-wildcards): Don't advise unless "[" and "]" are used in the filename format. 2002-09-01 Kai Gro?ohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> * net/tramp.el (tramp-methods): Remove duplicate definition of ssh1-old and ssh2-old.
author Kai Großjohann <kgrossjo@eu.uu.net>
date Sun, 22 Sep 2002 13:23:36 +0000
parents debd2b1e4d08
children e9121795960f
line wrap: on
line source

;;; help-fns.el --- Complex help functions

;; Copyright (C) 1985, 1986, 1993, 1994, 1998, 1999, 2000, 2001, 2002
;;   Free Software Foundation, Inc.

;; Maintainer: FSF
;; Keywords: help, internal

;; This file is part of GNU Emacs.

;; 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)
;; any later version.

;; GNU Emacs 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 GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;; Commentary:

;; This file contains those help commands which are complicated, and
;; which may not be used in every session.  For example
;; `describe-function' will probably be heavily used when doing elisp
;; programming, but not if just editing C files.  Simpler help commands
;; are in help.el

;;; Code:

(require 'help-mode)


;;;###autoload
(defun help-with-tutorial (&optional arg)
  "Select the Emacs learn-by-doing tutorial.
If there is a tutorial version written in the language
of the selected language environment, that version is used.
If there's no tutorial in that language, `TUTORIAL' is selected.
With arg, you are asked to choose which language."
  (interactive "P")
  (let ((lang (if arg
		  (let (completion-buffer)
		    ;; Display a completion list right away
		    ;; to guide the user.
		    (with-output-to-temp-buffer "*Completions*"
		      (display-completion-list
		       (all-completions "" language-info-alist
					(lambda (elm)
					  (and (listp elm) (assq 'tutorial elm)))))
		      (setq completion-buffer standard-output))
		    ;; Arrange to set completion-reference-buffer
		    ;; in *Completions* to point to the minibuffer,
		    ;; after entering the minibuffer.
		    (let ((minibuffer-setup-hook minibuffer-setup-hook))
		      (add-hook 'minibuffer-setup-hook
				(lambda ()
				  (let ((mini (current-buffer)))
				    (with-current-buffer completion-buffer
				      (make-local-variable 'completion-reference-buffer)
				      (setq completion-reference-buffer 
					    mini)))))
		      (read-language-name 'tutorial "Language: " "English")))
		(if (get-language-info current-language-environment 'tutorial)
		    current-language-environment
		  "English")))
	file filename)
    (setq filename (get-language-info lang 'tutorial))
    (setq file (expand-file-name (concat "~/" filename)))
    (delete-other-windows)
    (if (get-file-buffer file)
	(switch-to-buffer (get-file-buffer file))
      (switch-to-buffer (create-file-buffer file))
      (setq buffer-file-name file)
      (setq default-directory (expand-file-name "~/"))
      (setq buffer-auto-save-file-name nil)
      (insert-file-contents (expand-file-name filename data-directory))
      (goto-char (point-min))
      (search-forward "\n<<")
      (beginning-of-line)
      ;; Convert the <<...>> line to the proper [...] line,
      ;; or just delete the <<...>> line if a [...] line follows.
      (cond ((save-excursion
	       (forward-line 1)
	       (looking-at "\\["))
	     (delete-region (point) (progn (forward-line 1) (point))))
	    ((looking-at "<<Blank lines inserted.*>>")
	     (replace-match "[Middle of page left blank for didactic purposes.   Text continues below]"))
	    (t
	     (looking-at "<<")
	     (replace-match "[")
	     (search-forward ">>")
	     (replace-match "]")))
      (beginning-of-line)
      (let ((n (- (window-height (selected-window))
		  (count-lines (point-min) (point))
		  6)))
	(if (< n 8)
	    (progn
	      ;; For a short gap, we don't need the [...] line,
	      ;; so delete it.
	      (delete-region (point) (progn (end-of-line) (point)))
	      (newline n))
	  ;; Some people get confused by the large gap.
	  (newline (/ n 2))
	  
	  ;; Skip the [...] line (don't delete it).
	  (forward-line 1)
	  (newline (- n (/ n 2)))))
      (goto-char (point-min))
      (set-buffer-modified-p nil))))

;;;###autoload
(defun locate-library (library &optional nosuffix path interactive-call)
  "Show the precise file name of Emacs library LIBRARY.
This command searches the directories in `load-path' like `\\[load-library]'
to find the file that `\\[load-library] RET LIBRARY RET' would load.
Optional second arg NOSUFFIX non-nil means don't add suffixes `load-suffixes'
to the specified name LIBRARY.

If the optional third arg PATH is specified, that list of directories
is used instead of `load-path'.

When called from a program, the file name is normaly returned as a
string.  When run interactively, the argument INTERACTIVE-CALL is t,
and the file name is displayed in the echo area."
  (interactive (list (completing-read "Locate library: "
				      'locate-file-completion
				      (cons load-path load-suffixes))
		     nil nil
		     t))
  (let ((file (locate-file library
			   (or path load-path)
			   (append (unless nosuffix load-suffixes) '("")))))
    (if interactive-call
	(if file
	    (message "Library is file %s" (abbreviate-file-name file))
	  (message "No library %s in search path" library)))
    file))


;; Functions

;;;###autoload
(defun describe-function (function)
  "Display the full documentation of FUNCTION (a symbol)."
  (interactive
   (let ((fn (function-called-at-point))
	 (enable-recursive-minibuffers t)
	 val)
     (setq val (completing-read (if fn
				    (format "Describe function (default %s): " fn)
				  "Describe function: ")
				obarray 'fboundp t nil nil (symbol-name fn)))
     (list (if (equal val "")
	       fn (intern val)))))
  (if (null function)
      (message "You didn't specify a function")
    (help-setup-xref (list #'describe-function function) (interactive-p))
    (save-excursion
      (with-output-to-temp-buffer (help-buffer)
	(prin1 function)
	;; Use " is " instead of a colon so that
	;; it is easier to get out the function name using forward-sexp.
	(princ " is ")
	(describe-function-1 function)
	(print-help-return-message)
	(with-current-buffer standard-output
	  ;; Return the text we displayed.
	  (buffer-string))))))

(defun help-split-fundoc (doc def)
  "Split a function docstring DOC into the actual doc and the usage info.
Return (USAGE . DOC) or nil if there's no usage info.
DEF is the function whose usage we're looking for in DOC."
  ;; Functions can get the calling sequence at the end of the doc string.
  ;; In cases where `function' has been fset to a subr we can't search for
  ;; function's name in the doc string so we use `fn' as the anonymous
  ;; function name instead.
  (when doc
    (let* ((rep (prin1-to-string (indirect-function def)))
	   (name (if (string-match " \\([^ ]+\\)>$" rep)
		     (match-string 1 rep) (prin1-to-string def))))
      (if (string-match (format "\n\n(\\(fn\\|%s\\)\\(\\( .*\\)?)\\)\\'"
				(regexp-quote name))
			doc)
	  (cons (format "(%s%s"
			;; Replace `fn' with the actual function name.
			(if (consp def) "anonymous" def)
			(match-string 2 doc))
		(substring doc 0 (match-beginning 0)))))))

(defun help-function-arglist (def)
  ;; Handle symbols aliased to other symbols.
  (if (and (symbolp def) (fboundp def)) (setq def (indirect-function def)))
  ;; If definition is a macro, find the function inside it.
  (if (eq (car-safe def) 'macro) (setq def (cdr def)))
  (cond
   ((byte-code-function-p def) (aref def 0))
   ((eq (car-safe def) 'lambda) (nth 1 def))
   ((and (eq (car-safe def) 'autoload) (not (eq (nth 4 def) 'keymap)))
    "[Arg list not available until function definition is loaded.]")
   (t t)))

(defun help-make-usage (function arglist)
  (cons (if (symbolp function) function 'anonymous)
	(mapcar (lambda (arg)
		  (if (not (symbolp arg))
		      (if (and (consp arg) (symbolp (car arg)))
			  ;; CL style default values for optional args.
			  (cons (intern (upcase (symbol-name (car arg))))
				(cdr arg))
			arg)
		    (let ((name (symbol-name arg)))
		      (if (string-match "\\`&" name) arg
			(intern (upcase name))))))
		arglist)))

;;;###autoload
(defun describe-function-1 (function)
  (let* ((def (if (symbolp function)
		  (symbol-function function)
		function))
	 file-name string
	 (beg (if (commandp def) "an interactive " "a ")))
    (setq string
	  (cond ((or (stringp def)
		     (vectorp def))
		 "a keyboard macro")
		((subrp def)
		 (if (eq 'unevalled (cdr (subr-arity def)))
		     (concat beg "special form")
		   (concat beg "built-in function")))
		((byte-code-function-p def)
		 (concat beg "compiled Lisp function"))
		((symbolp def)
		 (while (symbolp (symbol-function def))
		   (setq def (symbol-function def)))
		 (format "an alias for `%s'" def))
		((eq (car-safe def) 'lambda)
		 (concat beg "Lisp function"))
		((eq (car-safe def) 'macro)
		 "a Lisp macro")
		((eq (car-safe def) 'autoload)
		 (setq file-name (nth 1 def))
		 (format "%s autoloaded %s"
			 (if (commandp def) "an interactive" "an")
			 (if (eq (nth 4 def) 'keymap) "keymap"
			   (if (nth 4 def) "Lisp macro" "Lisp function"))
			 ))
                ((keymapp def)
                 (let ((is-full nil)
                       (elts (cdr-safe def)))
                   (while elts
                     (if (char-table-p (car-safe elts))
                         (setq is-full t
                               elts nil))
                     (setq elts (cdr-safe elts)))
                   (if is-full
                       "a full keymap"
                     "a sparse keymap")))
		(t "")))
    (princ string)
    (with-current-buffer standard-output
      (save-excursion
	(save-match-data
	  (if (re-search-backward "alias for `\\([^`']+\\)'" nil t)
	      (help-xref-button 1 'help-function def)))))
    (or file-name
	(setq file-name (symbol-file function)))
    (when (equal file-name "loaddefs.el")
      ;; Find the real def site of the preloaded function.
      ;; This is necessary only for defaliases.
      (let ((location
	     (condition-case nil
		 (find-function-search-for-symbol function nil "loaddefs.el")
	       (error nil))))
	(when location
	  (with-current-buffer (car location)
	    (goto-char (cdr location))
	    (when (re-search-backward
		   "^;;; Generated autoloads from \\(.*\\)" nil t)
	      (setq file-name (match-string 1)))))))
    (cond
     (file-name
      (princ " in `")
      ;; We used to add .el to the file name,
      ;; but that's completely wrong when the user used load-file.
      (princ file-name)
      (princ "'")
      ;; 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)))))
    (princ ".")
    (terpri)
    (when (commandp function)
      (let* ((remapped (remap-command function))
	     (keys (where-is-internal
		   (or remapped function) overriding-local-map nil nil)))
	(when remapped
	  (princ "It is remapped to `")
	  (princ (symbol-name remapped))
	  (princ "'"))
	(when keys
	  (princ (if remapped " which is bound to " "It is bound to "))
	  ;; FIXME: This list can be very long (f.ex. for self-insert-command).
	  (princ (mapconcat 'key-description keys ", ")))
	(when (or remapped keys)
	  (princ ".")
	  (terpri))))
    (let* ((arglist (help-function-arglist def))
	   (doc (documentation function))
	   (usage (help-split-fundoc doc function)))
      ;; If definition is a keymap, skip arglist note.
      (unless (keymapp def)
	(princ (cond
		(usage (setq doc (cdr usage)) (car usage))
		((listp arglist) (help-make-usage function arglist))
		((stringp arglist) arglist)
		;; Maybe the arglist is in the docstring of the alias.
		((let ((fun function))
		   (while (and (symbolp fun)
			       (setq fun (symbol-function fun))
			       (not (setq usage (help-split-fundoc
						 (documentation fun)
						 function)))))
		   usage)
		 (car usage))
		(t "[Missing arglist.  Please make a bug report.]")))
	(terpri))
      (let ((obsolete (and
		       ;; function might be a lambda construct.
		       (symbolp function)
		       (get function 'byte-obsolete-info))))
	(when obsolete
	  (terpri)
	  (princ "This function is obsolete")
	  (if (nth 2 obsolete) (princ (format " since %s" (nth 2 obsolete))))
	  (princ ";") (terpri)
	  (princ (if (stringp (car obsolete)) (car obsolete)
		   (format "use `%s' instead." (car obsolete))))
	  (terpri)))
      (terpri)
      (princ (or doc "Not documented.")))))


;; Variables

;;;###autoload
(defun variable-at-point ()
  "Return the bound variable symbol found around point.
Return 0 if there is no such symbol."
  (condition-case ()
      (with-syntax-table emacs-lisp-mode-syntax-table
	(save-excursion
	  (or (not (zerop (skip-syntax-backward "_w")))
	      (eq (char-syntax (following-char)) ?w)
	      (eq (char-syntax (following-char)) ?_)
	      (forward-sexp -1))
	  (skip-chars-forward "'")
	  (let ((obj (read (current-buffer))))
	    (or (and (symbolp obj) (boundp obj) obj)
		0))))
    (error 0)))

;;;###autoload
(defun describe-variable (variable &optional buffer)
  "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),
it is displayed along with the global value."
  (interactive
   (let ((v (variable-at-point))
	 (enable-recursive-minibuffers t)
	 val)
     (setq val (completing-read (if (symbolp v)
				    (format
				     "Describe variable (default %s): " v)
				  "Describe variable: ")
				obarray 'boundp t nil nil
				(if (symbolp v) (symbol-name v))))
     (list (if (equal val "")
	       v (intern val)))))
  (unless (buffer-live-p buffer) (setq buffer (current-buffer)))
  (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))))
	(help-setup-xref (list #'describe-variable variable buffer)
			 (interactive-p))
	(with-output-to-temp-buffer (help-buffer)
	  (with-current-buffer buffer
	    (prin1 variable)
	    (if valvoid
		(princ " is void")
	      (with-current-buffer standard-output
		(princ "'s value is ")
		(terpri)
		(let ((from (point)))
		  (pp val)
		  (help-xref-on-pp from (point))
		  (if (< (point) (+ from 20))
		      (delete-region (1- from) from)))))
	    (terpri)
	    (when (local-variable-p variable)
	      (princ (format "Local in buffer %s; " (buffer-name)))
	      (if (not (default-boundp variable))
		  (princ "globally void")
		(let ((val (default-value variable)))
		  (with-current-buffer standard-output
		    (princ "global value is ")
		    (terpri)
		    ;; Fixme: pp can take an age if you happen to
		    ;; ask for a very large expression.  We should
		    ;; probably print it raw once and check it's a
		    ;; sensible size before prettyprinting.  -- fx
		    (let ((from (point)))
		      (pp val)
		      (help-xref-on-pp from (point))
		      (if (< (point) (+ from 20))
			(delete-region (1- from) from))))))
	      (terpri))
	    (terpri)
	    (with-current-buffer standard-output
	      (when (> (count-lines (point-min) (point-max)) 10)
		;; Note that setting the syntax table like below
		;; makes forward-sexp move over a `'s' at the end
		;; of a symbol.
		(set-syntax-table emacs-lisp-mode-syntax-table)
		(goto-char (point-min))
		(if valvoid
		    (forward-line 1)
		  (forward-sexp 1)
		  (delete-region (point) (progn (end-of-line) (point)))
		  (insert " value is shown below.\n\n")
		  (save-excursion
		    (insert "\n\nValue:"))))
	      ;; 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))))
		(save-excursion
		  (forward-line -1)
		  (insert "Automatically becomes buffer-local when set in any fashion.\n"))))
 	    ;; Mention if it's an alias
            (let* ((alias (condition-case nil
                             (indirect-variable variable)
                           (error variable)))
                   (obsolete (get variable 'byte-obsolete-variable))
                   (doc (or (documentation-property variable 'variable-documentation)
                            (documentation-property alias 'variable-documentation))))
              (unless (eq alias variable)
                (princ (format "This variable is an alias for `%s'." alias))
                (terpri)
                (terpri))
              (when obsolete
                (princ "This variable is obsolete")
                (if (cdr obsolete) (princ (format " since %s" (cdr obsolete))))
                (princ ";") (terpri)
                (princ (if (stringp (car obsolete)) (car obsolete)
                         (format "use `%s' instead." (car obsolete))))
                (terpri)
                (terpri))
              (princ (or doc "Not documented as a variable.")))
	    ;; Make a link to customize if this variable can be customized.
	    ;; Note, it is not reliable to test only for a custom-type property
	    ;; because those are only present after the var's definition
	    ;; has been loaded.
	    (if (or (get variable 'custom-type) ; after defcustom
		    (get variable 'custom-loads) ; from loaddefs.el
		    (get variable 'standard-value)) ; from cus-start.el
		(let ((customize-label "customize"))
		  (terpri)
		  (terpri)
		  (princ (concat "You can " customize-label " this variable."))
		  (with-current-buffer standard-output
		    (save-excursion
		      (re-search-backward
		       (concat "\\(" customize-label "\\)") nil t)
		      (help-xref-button 1 'help-customize-variable variable)))))
	    ;; Make a hyperlink to the library if appropriate.  (Don't
	    ;; change the format of the buffer's initial line in case
	    ;; anything expects the current format.)
	    (let ((file-name (symbol-file variable)))
	      (when (equal file-name "loaddefs.el")
		;; Find the real def site of the preloaded variable.
		(let ((location
		       (condition-case nil
			   (find-variable-noselect variable file-name)
			 (error nil))))
		  (when location
		    (with-current-buffer (car location)
		      (goto-char (cdr location))
		      (when (re-search-backward
			     "^;;; Generated autoloads from \\(.*\\)" nil t)
			(setq file-name (match-string 1)))))))
	      (when file-name
		(princ "\n\nDefined in `")
		(princ file-name)
		(princ "'.")
		(with-current-buffer standard-output
		  (save-excursion
		    (re-search-backward "`\\([^`']+\\)'" nil t)
		    (help-xref-button 1 'help-variable-def
				      variable file-name)))))

	    (print-help-return-message)
	    (save-excursion
	      (set-buffer standard-output)
	      ;; Return the text we displayed.
	      (buffer-string))))))))


;;;###autoload
(defun describe-syntax (&optional buffer)
  "Describe the syntax specifications in the syntax table of BUFFER.
The descriptions are inserted in a help buffer, which is then displayed.
BUFFER defaults to the current buffer."
  (interactive)
  (setq buffer (or buffer (current-buffer)))
  (help-setup-xref (list #'describe-syntax buffer) (interactive-p))
  (with-output-to-temp-buffer (help-buffer)
    (let ((table (with-current-buffer buffer (syntax-table))))
      (with-current-buffer standard-output
	(describe-vector table 'internal-describe-syntax-value)
	(while (setq table (char-table-parent table))
	  (insert "\nThe parent syntax table is:")
	  (describe-vector table 'internal-describe-syntax-value))))))

(defun help-describe-category-set (value)
  (insert (cond
	   ((null value) "default")
	   ((char-table-p value) "deeper char-table ...")
	   (t (condition-case err
		  (category-set-mnemonics value)
		(error "invalid"))))))

;;;###autoload
(defun describe-categories (&optional buffer)
  "Describe the category specifications in the current category table.
The descriptions are inserted in a buffer, which is then displayed."
  (interactive)
  (setq buffer (or buffer (current-buffer)))
  (help-setup-xref (list #'describe-categories buffer) (interactive-p))
  (with-output-to-temp-buffer (help-buffer)
    (let ((table (with-current-buffer buffer (category-table))))
      (with-current-buffer standard-output
	(describe-vector table 'help-describe-category-set)
	(let ((docs (char-table-extra-slot table 0)))
	  (if (or (not (vectorp docs)) (/= (length docs) 95))
	      (insert "Invalid first extra slot in this char table\n")
	    (insert "Meanings of mnemonic characters are:\n")
	    (dotimes (i 95)
	      (let ((elt (aref docs i)))
		(when elt
		  (insert (+ i ?\ ) ": " elt "\n"))))
	    (while (setq table (char-table-parent table))
	      (insert "\nThe parent category table is:")
	      (describe-vector table 'help-describe-category-set))))))))

(provide 'help-fns)

;;; help-fns.el ends here