comparison lisp/packages/info.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ac2d302a0011
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 ;;; info.el --- info package for Emacs.
2 ;; Keywords: help
3
4 ;; Copyright (C) 1985, 1986, 1993 Free Software Foundation, Inc.
5
6 ;; Author: Dave Gillespie <daveg@synaptics.com>
7 ;; Richard Stallman <rms@gnu.ai.mit.edu>
8 ;; Maintainer: Dave Gillespie <daveg@synaptics.com>
9 ;; Version: 1.07 of 7/22/93
10
11 ;; This file is part of XEmacs.
12
13 ;; XEmacs is free software; you can redistribute it and/or modify it
14 ;; under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; any later version.
17
18 ;; XEmacs is distributed in the hope that it will be useful, but
19 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 ;; General Public License for more details.
22
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with XEmacs; see the file COPYING. If not, write to the Free
25 ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26
27 ;;; Synched up with: Not synched with FSF.
28
29 ;; Commentary:
30
31 ;; This is based on an early Emacs 19 info.el file.
32 ;;
33 ;; Note that Info-directory has been replaced by Info-directory-list,
34 ;; a search path of directories in which to find Info files.
35 ;; Also, Info tries adding ".info" to a file name if the name itself
36 ;; is not found.
37 ;;
38 ;; See the change log below for further details.
39
40
41 ;; LCD Archive Entry:
42 ;; info-dg|Dave Gillespie|daveg@synaptics.com
43 ;; |Info reader with many enhancements; replaces standard info.el.
44 ;; |93-07-22|1.07|~/modes/info.el
45
46 ;; Also available from anonymous FTP on csvax.cs.caltech.edu.
47
48
49 ;; Change Log:
50
51 ;; Modified 3/7/1991 by Dave Gillespie:
52 ;; (Author's address: daveg@synaptics.com or daveg@csvax.cs.caltech.edu)
53 ;;
54 ;; Added keys: i, t, <, >, [, ], {, }, 6, 7, 8, 9, 0.
55 ;; Look at help for info-mode (type ? in Info) for descriptions.
56 ;;
57 ;; If Info-directory-list is undefined and there is no INFOPATH
58 ;; in the environment, use value of Info-directory for compatibility
59 ;; with Emacs 18.57.
60 ;;
61 ;; All files named "localdir" found in the path are appended to "dir",
62 ;; the Info directory. For this to work, "dir" should contain only
63 ;; one node (Top), and each "localdir" should contain no ^_ or ^L
64 ;; characters. Generally they will contain only one or several
65 ;; additional lines for the top-level menu. Note that "dir" is
66 ;; modified in memory each time it is loaded, but not on disk.
67 ;;
68 ;; If "dir" contains a line of the form: "* Locals:"
69 ;; then the "localdir"s are inserted there instead of at the end.
70
71
72 ;; Modified 4/3/1991 by Dave Gillespie:
73 ;;
74 ;; Added Info-mode-hook (suggested by Sebastian Kremer).
75 ;; Also added epoch-info-startup/select-hooks from Simon Spero's info.el.
76 ;;
77 ;; Added automatic decoding of compressed Info files.
78 ;; See documentation for the variable Info-suffix-list. Default is to
79 ;; run "uncompress" on ".Z" files and "unyabba" on ".Y" files.
80 ;; (See comp.sources.unix v24i073-076 for yabba/unyabba, a free software
81 ;; alternative to compress/uncompress.)
82 ;; Note: "dir" and "localdir" files should not be compressed.
83 ;;
84 ;; Changed variables like Info-enable-edit to be settable by M-x set-variable.
85 ;;
86 ;; Added Info-auto-advance variable. If t, SPC and DEL will act like
87 ;; } and {, i.e., they advance to the next/previous node if at the end
88 ;; of the buffer.
89 ;;
90 ;; Changed `u' to restore point to most recent location in that node.
91 ;; Added `=' to do this manually at any time. (Suggested by David Fox).
92 ;;
93 ;; Changed `m' and `0-9' to try interpreting menu name as a file name
94 ;; if not found as a node name. This allows (dir) menus of the form,
95 ;; Emacs:: Cool text editor
96 ;; as a shorthand for
97 ;; Emacs:(emacs). Cool text editor
98 ;;
99 ;; Enhanced `i' to use line-number information in the index.
100 ;; Added `,' to move among all matches to a previous `i' command.
101 ;;
102 ;; Added `a' (Info-annotate) for adding personal notes to any Info node.
103 ;; Notes are not stored in the actual Info files, but in the user's own
104 ;; ~/.infonotes file.
105 ;;
106 ;; Added Info-footnote-tag, made default be "Ref" instead of "Note".
107 ;;
108 ;; Got mouse-click stuff to work under Emacs version 18. Check it out!
109 ;; Left and right clicks scroll the Info window.
110 ;; Middle click goes to clicked-on node, e.g., "Next:", a menu, or a note.
111
112
113 ;; Modified 6/29/1991 by Dave Gillespie:
114 ;;
115 ;; Renamed epoch-info-startup/select-hooks to Info-startup/select-hook.
116 ;;
117 ;; Made Info-select-node into a command on the `!' key.
118 ;;
119 ;; Added Info-mouse-support user option.
120 ;;
121 ;; Cleaned up the implementation of some routines.
122 ;;
123 ;; Added special treatment of quoted words in annotations: The `g'
124 ;; command for a nonexistent node name scans for an annotation
125 ;; (in any node of any file) containing that name in quotes: g foo RET
126 ;; looks for an annotation containing: "foo" or: <<foo>>
127 ;; If found, it goes to that file and node.
128 ;;
129 ;; Added a call to set up Info-directory-list in Info-find-node to
130 ;; work around a bug in GNUS where it calls Info-goto-node before info.
131 ;;
132 ;; Added completion for `g' command (inspired by Richard Kim's infox.el).
133 ;; Completion knows all node names for the current file, and all annotation
134 ;; tags (see above). It does not complete file names or node names in
135 ;; other files.
136 ;;
137 ;; Added `k' (Info-emacs-key) and `*' (Info-elisp-ref) commands. You may
138 ;; wish to bind these to global keys outside of Info mode.
139 ;;
140 ;; Allowed localdir files to be full dir-like files; only the menu part
141 ;; of each localdir is copied. Also, redundant menu items are omitted.
142 ;;
143 ;; Changed Info-history to hold only one entry at a time for each node,
144 ;; and to be circular so that multiple `l's come back again to the most
145 ;; recent node. Note that the format of Info-history entries has changed,
146 ;; which may interfere with external programs that try to operate on it.
147 ;; (Also inspired by Kim's infox.el).
148 ;;
149 ;; Changed `n', `]', `l', etc. to accept prefix arguments to move several
150 ;; steps at once. Most accept negative arguments to move oppositely.
151 ;;
152 ;; Changed `?' to bury *Help* buffer afterwards to keep it out of the way.
153 ;;
154 ;; Rearranged `?' key's display to be a little better for new users.
155 ;;
156 ;; Changed `a' to save whole window configuration and restore on C-c C-c.
157 ;;
158 ;; Fixed the bug reported by Bill Reynolds on gnu.emacs.bugs.
159 ;;
160 ;; Changed Info-last to restore window-start as well as cursor position.
161 ;;
162 ;; Changed middle mouse button in space after end of node to do Info-last
163 ;; if we got here by following a cross reference, else do Info-global-next.
164 ;;
165 ;; Added some new mouse bindings: shift-left = Info-global-next,
166 ;; shift-right = Info-global-prev, shift-middle = Info-last.
167 ;;
168 ;; Fixed Info-follow-reference not to make assumptions about length
169 ;; of Info-footnote-tag [Linus Tolke].
170 ;;
171 ;; Changed default for Info-auto-advance mode to be press-twice-for-next-node.
172 ;;
173 ;; Modified x-mouse-ignore to preserve last-command variable, so that
174 ;; press-twice Info-auto-advance mode works with the mouse.
175
176
177 ;; Modified 3/4/1992 by Dave Gillespie:
178 ;;
179 ;; Added an "autoload" command to help autoload.el.
180 ;;
181 ;; Changed `*' command to look for file `elisp' as well as for `lispref'.
182 ;;
183 ;; Fixed a bug involving footnote names containing regexp special characters.
184 ;;
185 ;; Fixed a bug in completion during `f' (or `r') command.
186 ;;
187 ;; Added TAB (Info-next-reference), M-TAB, and RET keys to Info mode.
188 ;;
189 ;; Added new bindings, `C-h C-k' for Info-emacs-key and `C-h C-f' for
190 ;; Info-elisp-ref. These bindings are made when info.el is loaded, and
191 ;; only if those key sequences were previously unbound. These bindings
192 ;; work at any time, not just when Info is already running.
193
194
195 ;; Modified 3/8/1992 by Dave Gillespie:
196 ;;
197 ;; Fixed some long lines that were causing trouble with mailers.
198
199
200 ;; Modified 3/9/1992 by Dave Gillespie:
201 ;;
202 ;; Added `C-h C-i' (Info-query).
203 ;;
204 ;; Added Info-novice mode, warns if the user attempts to switch to
205 ;; a different Info file.
206 ;;
207 ;; Fixed a bug that caused problems using compressed Info files
208 ;; and Info-directory-list at the same time.
209 ;;
210 ;; Disabled Info-mouse-support by default if Epoch or Hyperbole is in use.
211 ;;
212 ;; Added an expand-file-name call to Info-find-node to fix a small bug.
213
214
215 ;; Modified 5/22/1992 by Dave Gillespie:
216 ;;
217 ;; Added "standalone" operation: "emacs -f info" runs Emacs specifically
218 ;; for use as an Info browser. In this mode, the `q' key quits Emacs
219 ;; itself. Also, "emacs -f info arg" starts in Info file "arg" instead
220 ;; of "dir".
221 ;;
222 ;; Changed to prefer "foo.info" over "foo". If both exist, "foo" is
223 ;; probably a directory or executable program!
224 ;;
225 ;; Made control-mouse act like regular-mouse does in other buffers.
226 ;; (In most systems, this will be set-cursor for left-mouse, x-cut
227 ;; for right-mouse, and x-paste, which will be an error, for
228 ;; middle-mouse.)
229 ;;
230 ;; Improved prompting and searching for `,' key.
231 ;;
232 ;; Fixed a bug where some "* Menu:" lines disappeared when "dir"
233 ;; contained several nodes.
234
235
236 ;; Modified 9/10/1992 by Dave Gillespie:
237 ;;
238 ;; Mixed in support for XEmacs. Mouse works the same as in
239 ;; the other Emacs versions by default; added Info-lucid-mouse-style
240 ;; variable, which enables mouse operation similar to XEmacs's default.
241 ;;
242 ;; Fixed a bug where RET couldn't understand "* Foo::" if "Foo" was a
243 ;; file name instead of a node name.
244 ;;
245 ;; Added `x' (Info-bookmark), a simple interface to the annotation
246 ;; tags feature. Added `j' (Info-goto-bookmark), like `g' but only
247 ;; completes bookmarks.
248 ;;
249 ;; Added `<<tag>>' as alternate to `"tag"' in annotations.
250 ;;
251 ;; Added `v' (Info-visit-file), like Info-goto-node but specialized
252 ;; for going to a new Info file (with file name completion).
253 ;;
254 ;; Added recognition of gzip'd ".z" files.
255
256
257 ;; Modified 5/9/1993 by Dave Gillespie:
258 ;;
259 ;; Merged in various things from FSF's latest Emacs 19 info.el.
260 ;; Notably: Added Info-default-directory-list.
261
262
263 ;; Modified 6/2/1993 by Dave Gillespie:
264 ;;
265 ;; Changed to use new suffix ".gz" for gzip files.
266
267
268 ;; Modified 7/22/1993 by Dave Gillespie:
269 ;;
270 ;; Changed Info-footnote-tag to "See" instead of "Ref".
271 ;;
272 ;; Extended Info-fontify-node to work with FSF version of Emacs 19.
273
274 ;; Modified 7/30/1993 by Jamie Zawinski:
275 ;;
276 ;; Commented out the tty and fsf19 mouse support, because why bother.
277 ;; Commented out the politically incorrect version of XEmacs mouse support.
278 ;; Commented out mouse scrolling bindings because the party line on that
279 ;; is "scrollbars are coming soon."
280 ;; Commented out munging of help-for-help's doc; put it in help.el.
281 ;; Did Info-edit-map the modern XEmacs way.
282 ;; Pruned extra cruft from fontification and mouse handling code.
283 ;; Fixed ASCII-centric bogosity in unreading of events.
284
285 ;; Modified 8/11/95 by Chuck Thompson:
286 ;;
287 ;; Removed any pretense of ever referencing Info-directory since it
288 ;; wasn't working anyhow.
289
290 ;; Code:
291
292 (defvar Info-inhibit-toolbar nil
293 "*Non-nil means don't use the specialized Info toolbar.")
294
295 (defvar Info-novice nil
296 "*Non-nil means to ask for confirmation before switching Info files.")
297
298 (defvar Info-history nil
299 "List of info nodes user has visited.
300 Each element of list is a list (\"(FILENAME)NODENAME\" BUFPOS WINSTART).")
301
302 (defvar Info-keeping-history t
303 "Non-nil if Info-find-node should modify Info-history.
304 This is for use only by certain internal Info routines.")
305
306 (defvar Info-enable-edit nil
307 "*Non-nil means the \\<Info-mode-map>\\[Info-edit] command in Info
308 can edit the current node.
309 This is convenient if you want to write info files by hand.
310 However, we recommend that you not do this.
311 It is better to write a Texinfo file and generate the Info file from that,
312 because that gives you a printed manual as well.")
313
314 (defvar Info-enable-active-nodes t
315 "*Non-nil allows Info to execute Lisp code associated with nodes.
316 The Lisp code is executed when the node is selected.")
317
318 (defvar Info-restoring-point t
319 "*Non-nil means to restore the cursor position when re-entering a node.")
320
321 (defvar Info-auto-advance 'twice
322 "*Control what SPC and DEL do when they can't scroll any further.
323 If nil, they beep and remain in the current node.
324 If t, they move to the next node (like Info-global-next/prev).
325 If anything else, they must be pressed twice to move to the next node.")
326
327 (defvar Info-fontify t
328 "*Non-nil enables font features in XEmacs.
329 This variable is ignored unless running under XEmacs.")
330
331 (defvar Info-default-directory-list nil
332 "List of default directories to search for Info documentation files.
333 This value is used as the default for `Info-directory-list'. It is set
334 in startup.el.")
335
336 (defvar Info-directory-list
337 (let ((path (getenv "INFOPATH")))
338 (if path
339 (let ((list nil)
340 idx)
341 (while (> (length path) 0)
342 (setq idx (or (string-match ":" path) (length path))
343 list (cons (substring path 0 idx) list)
344 path (substring path (min (1+ idx)
345 (length path)))))
346 (nreverse list))
347 Info-default-directory-list))
348 "List of directories to search for Info documentation files.
349 Default is to use the environment variable INFOPATH if it exists,
350 else to use Info-default-directory-list.")
351
352 (defvar Info-suffix-list '( (".info" . nil)
353 (".info.gz" . "gzip -dc %s")
354 (".info-z" . "gzip -dc %s")
355 (".info.Z" . "uncompress -c %s")
356 (".gz" . "gzip -dc %s")
357 (".Z" . "uncompress -c %s") )
358 "List of file name suffixes and associated decoding commands.
359 Each entry should be (SUFFIX . STRING); if STRING contains %s, that is
360 changed to name of the file to decode, otherwise the file is given to
361 the command as standard input. If STRING is nil, no decoding is done.")
362
363 (defvar Info-footnote-tag "See"
364 "*Symbol that identifies a footnote or cross-reference.
365 All \"*Note\" references will be changed to use this word instead.")
366
367 (defvar Info-current-file nil
368 "Info file that Info is now looking at, or nil.")
369
370 (defvar Info-current-subfile nil
371 "Info subfile that is actually in the *info* buffer now,
372 or nil if current info file is not split into subfiles.")
373
374 (defvar Info-current-node nil
375 "Name of node that Info is now looking at, or nil.")
376
377 (defvar Info-tag-table-marker (make-marker)
378 "Marker pointing at beginning of current Info file's tag table.
379 Marker points nowhere if file has no tag table.")
380
381 (defvar Info-current-file-completions nil
382 "Cached completion list for current Info file.")
383
384 (defvar Info-current-annotation-completions nil
385 "Cached completion list for current annotation files.")
386
387 (defvar Info-index-alternatives nil
388 "List of possible matches for last Info-index command.")
389 (defvar Info-index-first-alternative nil)
390
391 (defvar Info-annotations-path '("~/.infonotes" "/usr/lib/info.notes")
392 "*Names of files that contain annotations for different Info nodes.
393 By convention, the first one should reside in your personal directory.
394 The last should be a world-writable \"public\" annotations file.")
395
396 (defvar Info-standalone nil
397 "Non-nil if Emacs was started solely as an Info browser.")
398
399 (defvar Info-in-cross-reference nil)
400 (defvar Info-window-configuration nil)
401
402 ;;;###autoload
403 (defun info (&optional file)
404 "Enter Info, the documentation browser.
405 Optional argument FILE specifies the file to examine;
406 the default is the top-level directory of Info.
407
408 In interactive use, a prefix argument directs this command
409 to read a file name from the minibuffer."
410 (interactive (if current-prefix-arg
411 (list (read-file-name "Info file name: " nil nil t))))
412 (let ((p command-line-args))
413 (while p
414 (and (string-match "^-[fe]" (car p))
415 (equal (nth 1 p) "info")
416 (not Info-standalone)
417 (setq Info-standalone t)
418 (= (length p) 3)
419 (not (string-match "^-" (nth 2 p)))
420 (setq file (nth 2 p))
421 (setq command-line-args-left nil))
422 (setq p (cdr p))))
423 ; (Info-setup-x)
424 (if file
425 (unwind-protect
426 (Info-goto-node (concat "(" file ")"))
427 (and Info-standalone (info)))
428 (if (get-buffer "*info*")
429 (switch-to-buffer "*info*")
430 (Info-directory))))
431
432 ;;;###autoload
433 (defun Info-query (file)
434 "Enter Info, the documentation browser. Prompt for name of Info file."
435 (interactive "sInfo topic (default = menu): ")
436 (info)
437 (if (equal file "")
438 (Info-goto-node "(dir)")
439 (Info-goto-node (concat "(" file ")"))))
440
441 (defun Info-setup-initial ()
442 (let ((f Info-annotations-path))
443 (while f
444 (if (and (file-exists-p (car f)) (not (get-file-buffer (car f))))
445 (bury-buffer (find-file-noselect (car f))))
446 (setq f (cdr f)))))
447
448 (defconst Info-emacs-info-file-name "xemacs")
449
450 ;; Go to an info node specified as separate filename and nodename.
451 ;; no-going-back is non-nil if recovering from an error in this function;
452 ;; it says do not attempt further (recursive) error recovery.
453 (defun Info-find-node (filename &optional nodename no-going-back tryfile line)
454 ;; Look for a plausible filename, or if not found then look for URls
455 ;; &c, and dispatch to the appropriate fn.
456
457 (Info-setup-initial)
458
459 (cond
460 ;; empty filename is simple case
461 ((null filename)
462 (Info-find-file-node nil nodename no-going-back tryfile line))
463 ;; Convert filename to lower case if not found as specified.
464 ;; Expand it, look harder...
465 ((let (temp temp-downcase found
466 (fname (substitute-in-file-name filename)))
467 ;; horrible kludge so that I can call the emacs doc
468 ;; "XEmacs" without having to make .../info/dir be ugly.
469 ;; I'd like to do this only if the "emacs" node wasn't
470 ;; found, but this 200+ line function is too hairy for me
471 ;; to want to think about any longer than I have to.
472 (if (equal (downcase fname) "emacs")
473 (setq fname Info-emacs-info-file-name))
474 (let ((dirs (if (string-match "^\\./" fname)
475 ;; If specified name starts with `./'
476 ;; then just try current directory.
477 (list default-directory) ; '("./")
478 Info-directory-list)))
479 ;; Search the directory list for file FNAME.
480 (while (and dirs (not found))
481 (setq temp (expand-file-name fname (car dirs)))
482 (setq temp-downcase
483 (expand-file-name (downcase fname) (car dirs)))
484 (if (equal temp-downcase temp) (setq temp-downcase nil))
485 ;; Try several variants of specified name.
486 ;; Try downcasing, appending a suffix, or both.
487 (setq found (Info-suffixed-file temp temp-downcase))
488 (setq dirs (cdr dirs)))
489 (if found
490 (progn (setq filename (expand-file-name found))
491 t))))
492 (Info-find-file-node filename nodename no-going-back tryfile line))
493 ;; Look for a URL. This pattern is stolen from w3.el to prevent
494 ;; loading it if we won't need it.
495 ((string-match "^\\(wais\\|solo\\|x-exec\\|newspost\\|www\\|mailto\\|news\\|tn3270\\|ftp\\|http\\|file\\|telnet\\|gopher\\):" filename)
496 (w3-fetch filename))
497 (t
498 (error "Info file %s does not exist" filename))))
499
500 (defun Info-find-file-node (filename nodename
501 &optional no-going-back tryfile line)
502 ;; This is the guts of what was Info-find-node. Whoever wrote this
503 ;; should be locked up where they can't do any more harm.
504
505 ;; Go into info buffer.
506 (switch-to-buffer "*info*")
507 (if (fboundp 'buffer-disable-undo)
508 (buffer-disable-undo (current-buffer)))
509 (run-hooks 'Info-startup-hook)
510 (or (eq major-mode 'Info-mode)
511 (Info-mode))
512 (or (null filename)
513 (equal Info-current-file filename)
514 (not Info-novice)
515 (string-match "^dir$" (file-name-nondirectory Info-current-file))
516 (if (y-or-n-p (format "Leave Info file `%s'? "
517 (file-name-nondirectory Info-current-file)))
518 (message "")
519 (keyboard-quit)))
520 ;; Record the node we are leaving.
521 (if (and Info-current-file (not no-going-back))
522 (Info-history-add Info-current-file Info-current-node (point)))
523 (widen)
524 (setq Info-current-node nil
525 Info-in-cross-reference nil)
526 (unwind-protect
527 (progn
528 ;; Switch files if necessary
529 (or (null filename)
530 (equal Info-current-file filename)
531 (let ((buffer-read-only nil))
532 (setq Info-current-file nil
533 Info-current-subfile nil
534 Info-index-alternatives nil
535 Info-current-file-completions nil
536 buffer-file-name nil)
537 (erase-buffer)
538 (Info-insert-file-contents filename t)
539 ;; Add all "localdir" files in search path to "dir" file.
540 (if (string-match "^dir$" (file-name-nondirectory filename))
541 (let ((d Info-directory-list)
542 name (lim -1))
543 (goto-char (point-max))
544 (if (re-search-backward "^ *\\* *Locals *: *\n" nil t)
545 (delete-region (match-beginning 0) (match-end 0))
546 (search-backward "\^L" nil t))
547 (while d
548 (setq name (expand-file-name "localdir" (car d)))
549 (if (or (file-exists-p name)
550 (file-exists-p
551 (setq name (concat name ".info"))))
552 ;; Insert menu part of the file
553 (let* ((pt (point))
554 (len (nth 1 (insert-file-contents name))))
555 ;; be careful to put the local info entries
556 ;; in the buffer in the order they were found
557 ;; in the search path.
558 (goto-char (+ pt len))
559 (save-excursion
560 (goto-char pt)
561 (if (search-forward "* menu:" (+ pt len) t)
562 (progn
563 (forward-line 1)
564 (delete-region pt (point)))))))
565 (setq d (cdr d)))
566 ;; Eliminate redundant menu entries.
567 (goto-char (point-min))
568 (while (re-search-forward "\n\\* \\([^:\n]*\\):" nil t)
569 (let ((str (buffer-substring (match-beginning 1)
570 (match-end 1))))
571 (if (> (point) lim)
572 (save-excursion
573 (setq lim (if (search-forward "\^_" nil t)
574 (point)
575 (point-max)))))
576 (save-excursion
577 (if (search-forward (format "\n* %s:" str) lim t)
578 (let ((pt (- (point) 3 (length str))))
579 (forward-line 1)
580 (delete-region pt (point)))))))))
581 (set-buffer-modified-p nil)
582 (setq default-directory (file-name-directory filename))
583 ;; See whether file has a tag table. Record the location if yes.
584 (set-marker Info-tag-table-marker nil)
585 (goto-char (point-max))
586 (forward-line -8)
587 (or (equal nodename "*")
588 (not (search-forward "\^_\nEnd tag table\n" nil t))
589 (let (pos)
590 ;; We have a tag table. Find its beginning.
591 ;; Is this an indirect file?
592 (search-backward "\nTag table:\n")
593 (setq pos (point))
594 (if (save-excursion
595 (forward-line 2)
596 (looking-at "(Indirect)\n"))
597 ;; It is indirect. Copy it to another buffer
598 ;; and record that the tag table is in that buffer.
599 (save-excursion
600 (let ((buf (current-buffer)))
601 (set-buffer
602 (get-buffer-create " *info tag table*"))
603 (if (fboundp 'buffer-disable-undo)
604 (buffer-disable-undo (current-buffer)))
605 (setq case-fold-search t)
606 (erase-buffer)
607 (insert-buffer-substring buf)
608 (set-marker Info-tag-table-marker
609 (match-end 0))))
610 (set-marker Info-tag-table-marker pos))))
611 (setq Info-current-file
612 (file-name-sans-versions buffer-file-name))))
613 (if (equal nodename "*")
614 (progn (setq Info-current-node nodename)
615 (Info-set-mode-line)
616 (goto-char (point-min)))
617 ;; Search file for a suitable node.
618 (let* ((qnode (regexp-quote nodename))
619 (regexp (concat "Node: *" qnode " *[,\t\n\177]"))
620 (guesspos (point-min))
621 (found t))
622 ;; First get advice from tag table if file has one.
623 ;; Also, if this is an indirect info file,
624 ;; read the proper subfile into this buffer.
625 (if (marker-position Info-tag-table-marker)
626 (save-excursion
627 (set-buffer (marker-buffer Info-tag-table-marker))
628 (goto-char Info-tag-table-marker)
629 (if (re-search-forward regexp nil t)
630 (progn
631 (setq guesspos (read (current-buffer)))
632 ;; If this is an indirect file,
633 ;; determine which file really holds this node
634 ;; and read it in.
635 (if (not (eq (current-buffer) (get-buffer "*info*")))
636 (setq guesspos
637 (Info-read-subfile guesspos)))))))
638 (goto-char (max (point-min) (- guesspos 1000)))
639 ;; Now search from our advised position (or from beg of buffer)
640 ;; to find the actual node.
641 (catch 'foo
642 (while (search-forward "\n\^_" nil t)
643 (forward-line 1)
644 (let ((beg (point)))
645 (forward-line 1)
646 (if (re-search-backward regexp beg t)
647 (throw 'foo t))))
648 (setq found nil)
649 (let ((bufs (delq nil (mapcar 'get-file-buffer
650 Info-annotations-path)))
651 (pattern (if (string-match "\\`<<.*>>\\'" qnode) qnode
652 (format "\"%s\"\\|<<%s>>" qnode qnode)))
653 (pat2 (concat "------ *File: *\\([^ ].*[^ ]\\) *Node: "
654 "*\\([^ ].*[^ ]\\) *Line: *\\([0-9]+\\)"))
655 (afile nil) anode aline)
656 (while (and bufs (not anode))
657 (save-excursion
658 (set-buffer (car bufs))
659 (goto-char (point-min))
660 (if (re-search-forward pattern nil t)
661 (if (re-search-backward pat2 nil t)
662 (setq afile (buffer-substring (match-beginning 1)
663 (match-end 1))
664 anode (buffer-substring (match-beginning 2)
665 (match-end 2))
666 aline (string-to-int
667 (buffer-substring (match-beginning 3)
668 (match-end 3)))))))
669 (setq bufs (cdr bufs)))
670 (if anode
671 (Info-find-node afile anode t nil aline)
672 (if tryfile
673 (condition-case nil
674 (Info-find-node nodename "Top" t)
675 (error nil)))))
676 (or Info-current-node
677 (error "No such node: %s" nodename)))
678 (if found
679 (progn
680 (Info-select-node)
681 (goto-char (point-min))
682 (if line (forward-line line)))))))
683 ;; If we did not finish finding the specified node,
684 ;; go back to the previous one.
685 (or Info-current-node no-going-back
686 (let ((hist (car Info-history)))
687 ;; The following is no longer safe with new Info-history system
688 ;; (setq Info-history (cdr Info-history))
689 (Info-goto-node (car hist) t)
690 (goto-char (+ (point-min) (nth 1 hist)))))))
691
692 (defun Info-history-add (file node point)
693 (if Info-keeping-history
694 (let* ((name (format "(%s)%s" (Info-file-name-only file) node))
695 (found (assoc name Info-history)))
696 (if found
697 (setq Info-history (delq found Info-history)))
698 (setq Info-history (cons (list name (- point (point-min))
699 (and (eq (window-buffer)
700 (current-buffer))
701 (- (window-start) (point-min))))
702 Info-history)))))
703
704 (defun Info-file-name-only (file)
705 (let ((dir (file-name-directory file))
706 (p Info-directory-list))
707 (while (and p (not (equal (car p) dir)))
708 (setq p (cdr p)))
709 (if p (file-name-nondirectory file) file)))
710
711 (defun Info-read-subfile (nodepos)
712 (set-buffer (marker-buffer Info-tag-table-marker))
713 (goto-char (point-min))
714 (search-forward "\n\^_")
715 (let (lastfilepos
716 lastfilename)
717 (forward-line 2)
718 (catch 'foo
719 (while (not (looking-at "\^_"))
720 (if (not (eolp))
721 (let ((beg (point))
722 thisfilepos thisfilename)
723 (search-forward ": ")
724 (setq thisfilename (buffer-substring beg (- (point) 2)))
725 (setq thisfilepos (read (current-buffer)))
726 ;; read in version 19 stops at the end of number.
727 ;; Advance to the next line.
728 (if (eolp)
729 (forward-line 1))
730 (if (> thisfilepos nodepos)
731 (throw 'foo t))
732 (setq lastfilename thisfilename)
733 (setq lastfilepos thisfilepos))
734 (throw 'foo t))))
735 (set-buffer (get-buffer "*info*"))
736 (or (equal Info-current-subfile lastfilename)
737 (let ((buffer-read-only nil))
738 (setq buffer-file-name nil)
739 (widen)
740 (erase-buffer)
741 (Info-insert-file-contents (Info-suffixed-file
742 (expand-file-name lastfilename
743 (file-name-directory
744 Info-current-file)))
745 t)
746 (set-buffer-modified-p nil)
747 (setq Info-current-subfile lastfilename)))
748 (goto-char (point-min))
749 (search-forward "\n\^_")
750 (+ (- nodepos lastfilepos) (point))))
751
752 (defun Info-suffixed-file (name &optional name2)
753 (let ((suff Info-suffix-list)
754 (found nil))
755 (while (and suff (not found))
756 (if (file-exists-p (concat name (car (car suff))))
757 (setq found (concat name (car (car suff))))
758 (if (and name2 (file-exists-p (concat name2 (car (car suff)))))
759 (setq found (concat name2 (car (car suff))))
760 (setq suff (cdr suff)))))
761 (or found
762 (and (file-exists-p name) name)
763 (and name2 (file-exists-p name2) name2))))
764
765 (defun Info-insert-file-contents (file &optional visit)
766 (setq file (expand-file-name file default-directory))
767 (let ((suff Info-suffix-list))
768 (while (and suff (or (<= (length file) (length (car (car suff))))
769 (not (equal (substring file
770 (- (length (car (car suff)))))
771 (car (car suff))))))
772 (setq suff (cdr suff)))
773 (if (stringp (cdr (car suff)))
774 (let ((command (if (string-match "%s" (cdr (car suff)))
775 (format (cdr (car suff)) file)
776 (concat (cdr (car suff)) " < " file))))
777 (message "%s..." command)
778 (if (eq system-type 'vax-vms)
779 (call-process command nil t nil)
780 (call-process shell-file-name nil t nil "-c" command))
781 (message "")
782 (if visit
783 (progn
784 (setq buffer-file-name file)
785 (set-buffer-modified-p nil)
786 (clear-visited-file-modtime))))
787 (insert-file-contents file visit))))
788
789 (defun Info-select-node ()
790 "Select the node that point is in, after using `g *' to select whole file."
791 (interactive)
792 (widen)
793 (save-excursion
794 ;; Find beginning of node.
795 (search-backward "\n\^_")
796 (forward-line 2)
797 ;; Get nodename spelled as it is in the node.
798 (re-search-forward "Node:[ \t]*")
799 (setq Info-current-node
800 (buffer-substring (point)
801 (progn
802 (skip-chars-forward "^,\t\n")
803 (point))))
804 (Info-set-mode-line)
805 ;; Find the end of it, and narrow.
806 (beginning-of-line)
807 (let (active-expression)
808 (narrow-to-region (point)
809 (if (re-search-forward "\n[\^_\f]" nil t)
810 (prog1
811 (1- (point))
812 (if (looking-at "[\n\^_\f]*execute: ")
813 (progn
814 (goto-char (match-end 0))
815 (setq active-expression
816 (read (current-buffer))))))
817 (point-max)))
818 (or (equal Info-footnote-tag "Note")
819 (progn
820 (goto-char (point-min))
821 (let ((buffer-read-only nil)
822 (bufmod (buffer-modified-p))
823 (case-fold-search t))
824 (while (re-search-forward "\\*Note\\([ \n]\\)" nil t)
825 (replace-match (concat "*" Info-footnote-tag "\ ")))
826 (set-buffer-modified-p bufmod))))
827 (Info-reannotate-node)
828 ;; XEmacs: remove v19 test
829 (and Info-fontify
830 (Info-fontify-node))
831 (run-hooks 'Info-select-hook)
832 (if Info-enable-active-nodes (eval active-expression)))))
833
834 (defun Info-set-mode-line ()
835 (setq modeline-buffer-identification
836 (concat
837 "Info: ("
838 (if Info-current-file
839 (let ((name (file-name-nondirectory Info-current-file)))
840 (if (string-match "\\.info$" name)
841 (substring name 0 -5)
842 name))
843 "")
844 ")"
845 (or Info-current-node ""))))
846
847 ;; Go to an info node specified with a filename-and-nodename string
848 ;; of the sort that is found in pointers in nodes.
849
850 ;;;###autoload
851 (defun Info-goto-node (nodename &optional no-going-back tryfile)
852 "Go to info node named NAME. Give just NODENAME or (FILENAME)NODENAME.
853 Actually, the following interpretations of NAME are tried in order:
854 (FILENAME)NODENAME
855 (FILENAME) (using Top node)
856 NODENAME (in current file)
857 TAGNAME (see below)
858 FILENAME (using Top node)
859 where TAGNAME is a string that appears in quotes: \"TAGNAME\", in an
860 annotation for any node of any file. (See `a' and `x' commands.)"
861 (interactive (list (Info-read-node-name "Goto node, file or tag: ")
862 nil t))
863 (let (filename)
864 (string-match "\\s *\\((\\s *\\([^\t)]*\\)\\s *)\\s *\\|\\)\\(.*\\)"
865 nodename)
866 (setq filename (if (= (match-beginning 1) (match-end 1))
867 ""
868 (substring nodename (match-beginning 2) (match-end 2)))
869 nodename (substring nodename (match-beginning 3) (match-end 3)))
870 (let ((trim (string-match "\\s *\\'" filename)))
871 (if trim (setq filename (substring filename 0 trim))))
872 (let ((trim (string-match "\\s *\\'" nodename)))
873 (if trim (setq nodename (substring nodename 0 trim))))
874 (Info-find-node (if (equal filename "") nil filename)
875 (if (equal nodename "") "Top" nodename)
876 no-going-back (and tryfile (equal filename "")))))
877
878 (defun Info-goto-bookmark ()
879 (interactive)
880
881 (let ((completion-ignore-case nil)
882 (tag (completing-read "Goto tag: "
883 (Info-build-annotation-completions)
884 nil t)))
885 (or (equal tag "") (Info-find-node nil (format "<<%s>>" tag)))))
886
887 ;;;###autoload
888 (defun Info-visit-file ()
889 "Directly visit an info file."
890 (interactive)
891 (let* ((insert-default-directory nil)
892 (file (read-file-name "Goto Info file: " "" "")))
893 (or (equal file "") (Info-find-node (expand-file-name file) "Top"))))
894
895 (defun Info-restore-point (&optional always)
896 "Restore point to same location it had last time we were in this node."
897 (interactive "p")
898 (if (or Info-restoring-point always)
899 (let* ((name (format "(%s)%s"
900 (Info-file-name-only Info-current-file)
901 Info-current-node))
902 (p (assoc name Info-history)))
903 (if p (Info-restore-history-entry p)))))
904
905 (defun Info-restore-history-entry (entry)
906 (goto-char (+ (nth 1 entry) (point-min)))
907 (and (nth 2 entry)
908 (get-buffer-window (current-buffer))
909 (set-window-start (get-buffer-window (current-buffer))
910 (+ (nth 2 entry) (point-min)))))
911
912 (defun Info-read-node-name (prompt &optional default)
913 (Info-setup-initial)
914 (let* ((completion-ignore-case t)
915 (nodename (completing-read prompt (Info-build-node-completions))))
916 (if (equal nodename "")
917 (or default
918 (Info-read-node-name prompt))
919 nodename)))
920
921 (defun Info-build-annotation-completions ()
922 (or Info-current-annotation-completions
923 (save-excursion
924 (let ((bufs (delq nil (mapcar 'get-file-buffer
925 Info-annotations-path)))
926 (compl nil))
927 (while bufs
928 (set-buffer (car bufs))
929 (goto-char (point-min))
930 (while (re-search-forward "<<\\(.*\\)>>" nil t)
931 (setq compl (cons (list (buffer-substring (match-beginning 1)
932 (match-end 1)))
933 compl)))
934 (setq bufs (cdr bufs)))
935 (setq Info-current-annotation-completions compl)))))
936
937 (defun Info-build-node-completions ()
938 (or Info-current-file-completions
939 (let ((compl (Info-build-annotation-completions)))
940 (save-excursion
941 (save-restriction
942 (if (marker-buffer Info-tag-table-marker)
943 (progn
944 (set-buffer (marker-buffer Info-tag-table-marker))
945 (goto-char Info-tag-table-marker)
946 (while (re-search-forward "\nNode: \\(.*\\)\177" nil t)
947 (setq compl
948 (cons (list (buffer-substring (match-beginning 1)
949 (match-end 1)))
950 compl))))
951 (widen)
952 (goto-char (point-min))
953 (while (search-forward "\n\^_" nil t)
954 (forward-line 1)
955 (let ((beg (point)))
956 (forward-line 1)
957 (if (re-search-backward "Node: *\\([^,\n]*\\) *[,\n\t]"
958 beg t)
959 (setq compl
960 (cons (list (buffer-substring (match-beginning 1)
961 (match-end 1)))
962 compl))))))))
963 (setq Info-current-file-completions compl))))
964
965 (defvar Info-last-search nil
966 "Default regexp for \\<Info-mode-map>\\[Info-search] command to search for.")
967
968 ;;;###autoload
969 (defun Info-search (regexp)
970 "Search for REGEXP, starting from point, and select node it's found in."
971 (interactive "sSearch (regexp): ")
972 (if (equal regexp "")
973 (setq regexp Info-last-search)
974 (setq Info-last-search regexp))
975 (let ((found ())
976 (onode Info-current-node)
977 (ofile Info-current-file)
978 (opoint (point))
979 (osubfile Info-current-subfile))
980 (save-excursion
981 (save-restriction
982 (widen)
983 (if (null Info-current-subfile)
984 (progn (re-search-forward regexp) (setq found (point)))
985 (condition-case nil
986 (progn (re-search-forward regexp) (setq found (point)))
987 (search-failed nil)))))
988 (if (not found) ;can only happen in subfile case -- else would have erred
989 (unwind-protect
990 (let ((list ()))
991 (set-buffer (marker-buffer Info-tag-table-marker))
992 (goto-char (point-min))
993 (search-forward "\n\^_\nIndirect:")
994 (save-restriction
995 (narrow-to-region (point)
996 (progn (search-forward "\n\^_")
997 (1- (point))))
998 (goto-char (point-min))
999 (search-forward (concat "\n" osubfile ": "))
1000 (beginning-of-line)
1001 (while (not (eobp))
1002 (re-search-forward "\\(^.*\\): [0-9]+$")
1003 (goto-char (+ (match-end 1) 2))
1004 (setq list (cons (cons (read (current-buffer))
1005 (buffer-substring (match-beginning 1)
1006 (match-end 1)))
1007 list))
1008 (goto-char (1+ (match-end 0))))
1009 (setq list (nreverse list)
1010 list (cdr list)))
1011 (while list
1012 (message "Searching subfile %s..." (cdr (car list)))
1013 (Info-read-subfile (car (car list)))
1014 (setq list (cdr list))
1015 (goto-char (point-min))
1016 (if (re-search-forward regexp nil t)
1017 (setq found (point) list ())))
1018 (if found
1019 (message "")
1020 (signal 'search-failed (list regexp))))
1021 (if (not found)
1022 (progn (Info-read-subfile opoint)
1023 (goto-char opoint)
1024 (Info-select-node)))))
1025 (widen)
1026 (goto-char found)
1027 (Info-select-node)
1028 (or (and (equal onode Info-current-node)
1029 (equal ofile Info-current-file))
1030 (Info-history-add ofile onode opoint))))
1031
1032 ;; Extract the value of the node-pointer named NAME.
1033 ;; If there is none, use ERRORNAME in the error message;
1034 ;; if ERRORNAME is nil, just return nil.
1035 (defun Info-extract-pointer (name &optional errorname)
1036 (save-excursion
1037 (goto-char (point-min))
1038 (forward-line 1)
1039 (let ((case-fold-search t))
1040 (if (re-search-backward (concat name ":") nil t)
1041 (progn
1042 (goto-char (match-end 0))
1043 (Info-following-node-name))
1044 (if (eq errorname t)
1045 nil
1046 (error (concat "Node has no " (capitalize (or errorname name)))))))))
1047
1048 ;; Return the node name in the buffer following point.
1049 ;; ALLOWEDCHARS, if non-nil, goes within [...] to make a regexp
1050 ;; saying which chas may appear in the node name.
1051 (defun Info-following-node-name (&optional allowedchars)
1052 (skip-chars-forward " \t")
1053 (buffer-substring
1054 (point)
1055 (progn
1056 (while (looking-at (concat "[" (or allowedchars "^,\t\n") "]"))
1057 (skip-chars-forward (concat (or allowedchars "^,\t\n") "("))
1058 (if (looking-at "(")
1059 (skip-chars-forward "^)")))
1060 (skip-chars-backward " ")
1061 (point))))
1062
1063 (defun Info-next (&optional n)
1064 "Go to the next node of this node.
1065 A positive or negative prefix argument moves by multiple nodes."
1066 (interactive "p")
1067 (or n (setq n 1))
1068 (if (< n 0)
1069 (Info-prev (- n))
1070 (while (>= (setq n (1- n)) 0)
1071 (Info-goto-node (Info-extract-pointer "next")))))
1072
1073 (defun Info-prev (&optional n)
1074 "Go to the previous node of this node.
1075 A positive or negative prefix argument moves by multiple nodes."
1076 (interactive "p")
1077 (or n (setq n 1))
1078 (if (< n 0)
1079 (Info-next (- n))
1080 (while (>= (setq n (1- n)) 0)
1081 (Info-goto-node (Info-extract-pointer "prev[ious]*" "previous")))))
1082
1083 (defun Info-up (&optional n)
1084 "Go to the superior node of this node.
1085 A positive prefix argument moves up several times."
1086 (interactive "p")
1087 (or n (setq n 1))
1088 (while (>= (setq n (1- n)) 0)
1089 (Info-goto-node (Info-extract-pointer "up")))
1090 (if (interactive-p) (Info-restore-point)))
1091
1092 (defun Info-last (&optional n)
1093 "Go back to the last node visited.
1094 With a prefix argument, go to Nth most recently visited node. History is
1095 circular; after oldest node, history comes back around to most recent one.
1096 Argument can be negative to go through the circle in the other direction.
1097 \(In other words, `l' is like \"undo\" and `C-u - l' is like \"redo\".)"
1098 (interactive "p")
1099 (or n (setq n 1))
1100 (or Info-history
1101 (error "This is the first Info node you looked at"))
1102 (let ((len (1+ (length Info-history))))
1103 (setq n (% (+ n (* len 100)) len)))
1104 (if (> n 0)
1105 (let ((entry (nth (1- n) Info-history)))
1106 (Info-history-add Info-current-file Info-current-node (point))
1107 (while (>= (setq n (1- n)) 0)
1108 (setq Info-history (nconc (cdr Info-history)
1109 (list (car Info-history)))))
1110 (setq Info-history (cdr Info-history))
1111 (let ((Info-keeping-history nil))
1112 (Info-goto-node (car entry)))
1113 (Info-restore-history-entry entry))))
1114
1115 (defun Info-directory ()
1116 "Go to the Info directory node."
1117 (interactive)
1118 (Info-find-node "dir" "top"))
1119
1120 (defun Info-follow-reference (footnotename)
1121 "Follow cross reference named NAME to the node it refers to.
1122 NAME may be an abbreviation of the reference name."
1123 (interactive
1124 (let ((completion-ignore-case t)
1125 completions default (start-point (point)) str i)
1126 (save-excursion
1127 (goto-char (point-min))
1128 (while (re-search-forward (format "\\*%s[ \n\t]*\\([^:]*\\):"
1129 Info-footnote-tag)
1130 nil t)
1131 (setq str (buffer-substring
1132 (match-beginning 1)
1133 (1- (point))))
1134 ;; See if this one should be the default.
1135 (and (null default)
1136 (< (match-beginning 0) start-point)
1137 (<= start-point (point))
1138 (setq default t))
1139 (setq i 0)
1140 (while (setq i (string-match "[ \n\t]+" str i))
1141 (setq str (concat (substring str 0 i) " "
1142 (substring str (match-end 0))))
1143 (setq i (1+ i)))
1144 ;; Record as a completion and perhaps as default.
1145 (if (eq default t) (setq default str))
1146 (setq completions
1147 (cons (cons str nil)
1148 completions))))
1149 (if completions
1150 (let ((item (completing-read (if default
1151 (concat "Follow reference named: ("
1152 default ") ")
1153 "Follow reference named: ")
1154 completions nil t)))
1155 (if (and (string= item "") default)
1156 (list default)
1157 (list item)))
1158 (error "No cross-references in this node"))))
1159 (let (target i (str (concat "\\*" Info-footnote-tag " "
1160 (regexp-quote footnotename))))
1161 (while (setq i (string-match " " str i))
1162 (setq str (concat (substring str 0 i) "\\([ \t\n]+\\)"
1163 (substring str (1+ i))))
1164 (setq i (+ i 10)))
1165 (save-excursion
1166 (goto-char (point-min))
1167 (or (re-search-forward str nil t)
1168 (error "No cross-reference named %s" footnotename))
1169 (goto-char (match-end 1))
1170 (setq target
1171 (Info-extract-menu-node-name "Bad format cross reference" t)))
1172 (while (setq i (string-match "[ \t\n]+" target i))
1173 (setq target (concat (substring target 0 i) " "
1174 (substring target (match-end 0))))
1175 (setq i (+ i 1)))
1176 (Info-goto-node target)
1177 (setq Info-in-cross-reference t)))
1178
1179 (defun Info-next-reference (n)
1180 (interactive "p")
1181 (let ((pat (format "\\*%s[ \n\t]*\\([^:]*\\):\\|^\\* .*:\\|<<.*>>"
1182 Info-footnote-tag))
1183 (case-fold-search nil)
1184 (old-pt (point)))
1185 (while (< n 0)
1186 (save-excursion
1187 (goto-char (point-min))
1188 (while (re-search-forward pat nil t)
1189 (setq n (1+ n)))
1190 (goto-char (point-min))
1191 (if (re-search-forward "^\\* Menu:" nil t)
1192 (setq n (1- n)))))
1193 (while (>= (setq n (1- n)) 0)
1194 (or (eobp) (forward-char 1))
1195 (or (re-search-forward pat nil t)
1196 (progn
1197 (goto-char (point-min))
1198 (or (re-search-forward pat nil t)
1199 (progn
1200 (goto-char old-pt)
1201 (error "No cross references in this node")))))
1202 (goto-char (match-beginning 0))
1203 (if (looking-at "\\* Menu:")
1204 (setq n (1+ n))))))
1205
1206 (defun Info-prev-reference (n)
1207 (interactive "p")
1208 (Info-next-reference (- n)))
1209
1210 (defun Info-extract-menu-node-name (&optional errmessage multi-line)
1211 (skip-chars-forward " \t\n")
1212 (let ((beg (point))
1213 str i)
1214 (skip-chars-forward "^:")
1215 (forward-char 1)
1216 (setq str
1217 (if (looking-at ":")
1218 (buffer-substring beg (1- (point)))
1219 (skip-chars-forward " \t\n")
1220 (Info-following-node-name (if multi-line "^.,\t" "^.,\t\n"))))
1221 (while (setq i (string-match "\n" str i))
1222 (aset str i ?\ ))
1223 str))
1224
1225 (defun Info-menu (menu-item)
1226 "Go to node for menu item named (or abbreviated) NAME.
1227 Completion is allowed, and the menu item point is on is the default."
1228 (interactive
1229 (let ((completions '())
1230 ;; If point is within a menu item, use that item as the default
1231 (default nil)
1232 (p (point))
1233 (last nil))
1234 (save-excursion
1235 (goto-char (point-min))
1236 (let ((case-fold-search t))
1237 (if (not (search-forward "\n* menu:" nil t))
1238 (error "No menu in this node")))
1239 (while (re-search-forward
1240 "\n\\* \\([^:\t\n]*\\):" nil t)
1241 (if (and (null default)
1242 (prog1 (if last (< last p) nil)
1243 (setq last (match-beginning 0)))
1244 (<= p last))
1245 (setq default (car (car completions))))
1246 (setq completions (cons (cons (buffer-substring
1247 (match-beginning 1)
1248 (match-end 1))
1249 (match-beginning 1))
1250 completions)))
1251 (if (and (null default) last
1252 (< last p)
1253 (<= p (progn (end-of-line) (point))))
1254 (setq default (car (car completions)))))
1255 (let ((item nil))
1256 (while (null item)
1257 (setq item (let ((completion-ignore-case t))
1258 (completing-read (if default
1259 (format "Menu item (default %s): "
1260 default)
1261 "Menu item: ")
1262 completions nil t)))
1263 ;; we rely on the fact that completing-read accepts an input
1264 ;; of "" even when the require-match argument is true and ""
1265 ;; is not a valid possibility
1266 (if (string= item "")
1267 (if default
1268 (setq item default)
1269 ;; ask again
1270 (setq item nil))))
1271 (list item))))
1272 ;; there is a problem here in that if several menu items have the same
1273 ;; name you can only go to the node of the first with this command.
1274 (Info-goto-node (Info-extract-menu-item menu-item) nil t))
1275
1276 (defun Info-extract-menu-item (menu-item &optional noerror)
1277 (save-excursion
1278 (goto-char (point-min))
1279 (if (let ((case-fold-search t))
1280 (search-forward "\n* menu:" nil t))
1281 (if (or (search-forward (concat "\n* " menu-item ":") nil t)
1282 (search-forward (concat "\n* " menu-item) nil t))
1283 (progn
1284 (beginning-of-line)
1285 (forward-char 2)
1286 (Info-extract-menu-node-name))
1287 (and (not noerror) (error "No such item in menu")))
1288 (and (not noerror) (error "No menu in this node")))))
1289
1290 ;; If COUNT is nil, use the last item in the menu.
1291 (defun Info-extract-menu-counting (count &optional noerror noindex)
1292 (save-excursion
1293 (goto-char (point-min))
1294 (if (let ((case-fold-search t))
1295 (and (search-forward "\n* menu:" nil t)
1296 (or (not noindex)
1297 (not (string-match "\\<Index\\>" Info-current-node)))))
1298 (if (search-forward "\n* " nil t count)
1299 (progn
1300 (or count
1301 (while (search-forward "\n* " nil t)))
1302 (Info-extract-menu-node-name))
1303 (and (not noerror) (error "Too few items in menu")))
1304 (and (not noerror) (error "No menu in this node")))))
1305
1306 (defun Info-nth-menu-item (n)
1307 "Go to the node of the Nth menu item."
1308 (interactive "P")
1309 (or n (setq n (- last-command-char ?0)))
1310 (if (< n 1) (error "Index must be at least 1"))
1311 (Info-goto-node (Info-extract-menu-counting n) nil t))
1312
1313 (defun Info-last-menu-item ()
1314 "Go to the node of the tenth menu item."
1315 (interactive)
1316 (Info-goto-node (Info-extract-menu-counting nil) nil t))
1317
1318 (defun Info-top ()
1319 "Go to the Top node of this file."
1320 (interactive)
1321 (Info-goto-node "Top"))
1322
1323 (defun Info-end ()
1324 "Go to the final node in this file."
1325 (interactive)
1326 (Info-top)
1327 (let ((Info-keeping-history nil)
1328 node)
1329 (Info-last-menu-item)
1330 (while (setq node (or (Info-extract-pointer "next" t)
1331 (Info-extract-menu-counting nil t t)))
1332 (Info-goto-node node))
1333 (or (equal (Info-extract-pointer "up" t) "Top")
1334 (let ((executing-kbd-macro "")) ; suppress messages
1335 (condition-case nil
1336 (Info-global-next 10000)
1337 (error nil))))))
1338
1339 (defun Info-global-next (&optional n)
1340 "Go to the next node in this file, traversing node structure as necessary.
1341 This works only if the Info file is structured as a hierarchy of nodes.
1342 A positive or negative prefix argument moves by multiple nodes."
1343 (interactive "p")
1344 (or n (setq n 1))
1345 (if (< n 0)
1346 (Info-global-prev (- n))
1347 (while (>= (setq n (1- n)) 0)
1348 (let (node)
1349 (cond ((and (string-match "^Top$" Info-current-node)
1350 (setq node (Info-extract-pointer "next" t))
1351 (Info-extract-menu-item node t))
1352 (Info-goto-node node))
1353 ((setq node (Info-extract-menu-counting 1 t t))
1354 (message "Going down...")
1355 (Info-goto-node node))
1356 (t
1357 (let ((Info-keeping-history Info-keeping-history)
1358 (orignode Info-current-node)
1359 (ups ""))
1360 (while (not (Info-extract-pointer "next" t))
1361 (if (and (setq node (Info-extract-pointer "up" t))
1362 (not (equal node "Top")))
1363 (progn
1364 (message "Going%s..." (setq ups (concat ups " up")))
1365 (Info-goto-node node)
1366 (setq Info-keeping-history nil))
1367 (if orignode
1368 (let ((Info-keeping-history nil))
1369 (Info-goto-node orignode)))
1370 (error "Last node in file")))
1371 (Info-next))))))))
1372
1373 (defun Info-page-next (&optional n)
1374 "Scroll forward one screenful, or go to next global node.
1375 A positive or negative prefix argument moves by multiple screenfuls."
1376 (interactive "p")
1377 (or n (setq n 1))
1378 (if (< n 0)
1379 (Info-page-prev (- n))
1380 (while (>= (setq n (1- n)) 0)
1381 (if (pos-visible-in-window-p (point-max))
1382 (progn
1383 (Info-global-next)
1384 (message "Node: %s" Info-current-node))
1385 (scroll-up)))))
1386
1387 (defun Info-scroll-next (arg)
1388 (interactive "P")
1389 (if Info-auto-advance
1390 (if (and (pos-visible-in-window-p (point-max))
1391 (not (eq Info-auto-advance t))
1392 (not (eq last-command this-command)))
1393 (message "Hit %s again to go to next node"
1394 (if (= last-command-char 0)
1395 "mouse button"
1396 (key-description (char-to-string last-command-char))))
1397 (Info-page-next)
1398 (setq this-command 'Info))
1399 (scroll-up arg)))
1400
1401 (defun Info-global-prev (&optional n)
1402 "Go to the previous node in this file, traversing structure as necessary.
1403 This works only if the Info file is structured as a hierarchy of nodes.
1404 A positive or negative prefix argument moves by multiple nodes."
1405 (interactive "p")
1406 (or n (setq n 1))
1407 (if (< n 0)
1408 (Info-global-next (- n))
1409 (while (>= (setq n (1- n)) 0)
1410 (let ((upnode (Info-extract-pointer "up" t))
1411 (prevnode (Info-extract-pointer "prev[ious]*" t)))
1412 (if (or (not prevnode)
1413 (equal prevnode upnode))
1414 (if (string-match "^Top$" Info-current-node)
1415 (error "First node in file")
1416 (message "Going up...")
1417 (Info-up))
1418 (Info-goto-node prevnode)
1419 (let ((downs "")
1420 (Info-keeping-history nil)
1421 node)
1422 (while (setq node (Info-extract-menu-counting nil t t))
1423 (message "Going%s..." (setq downs (concat downs " down")))
1424 (Info-goto-node node))))))))
1425
1426 (defun Info-page-prev (&optional n)
1427 "Scroll backward one screenful, or go to previous global node.
1428 A positive or negative prefix argument moves by multiple screenfuls."
1429 (interactive "p")
1430 (or n (setq n 1))
1431 (if (< n 0)
1432 (Info-page-next (- n))
1433 (while (>= (setq n (1- n)) 0)
1434 (if (pos-visible-in-window-p (point-min))
1435 (progn
1436 (Info-global-prev)
1437 (message "Node: %s" Info-current-node)
1438 (sit-for 0)
1439 ;;(scroll-up 1) ; work around bug in pos-visible-in-window-p
1440 ;;(scroll-down 1)
1441 (while (not (pos-visible-in-window-p (point-max)))
1442 (scroll-up)))
1443 (scroll-down)))))
1444
1445 (defun Info-scroll-prev (arg)
1446 (interactive "P")
1447 (if Info-auto-advance
1448 (if (and (pos-visible-in-window-p (point-min))
1449 (not (eq Info-auto-advance t))
1450 (not (eq last-command this-command)))
1451 (message "Hit %s again to go to previous node"
1452 (if (= last-command-char 0)
1453 "mouse button"
1454 (key-description (char-to-string last-command-char))))
1455 (Info-page-prev)
1456 (setq this-command 'Info))
1457 (scroll-down arg)))
1458
1459 (defun Info-index (topic)
1460 "Look up a string in the index for this file.
1461 The index is defined as the first node in the top-level menu whose
1462 name contains the word \"Index\", plus any immediately following
1463 nodes whose names also contain the word \"Index\".
1464 If there are no exact matches to the specified topic, this chooses
1465 the first match which is a case-insensitive substring of a topic.
1466 Use the `,' command to see the other matches.
1467 Give a blank topic name to go to the Index node itself."
1468 (interactive "sIndex topic: ")
1469 (let ((pattern (format "\n\\* \\([^\n:]*%s[^\n:]*\\):[ \t]*%s"
1470 (regexp-quote topic)
1471 "\\([^.\n]*\\)\\.[ t]*\\([0-9]*\\)"))
1472 node)
1473 (message "Searching index for `%s'..." topic)
1474 (Info-goto-node "Top")
1475 (let ((case-fold-search t))
1476 (or (search-forward "\n* menu:" nil t)
1477 (error "No index"))
1478 (or (re-search-forward "\n\\* \\(.*\\<Index\\>\\)" nil t)
1479 (error "No index")))
1480 (goto-char (match-beginning 1))
1481 (let ((Info-keeping-history nil)
1482 (Info-fontify (and Info-fontify (equal topic ""))))
1483 (Info-goto-node (Info-extract-menu-node-name)))
1484 (or (equal topic "")
1485 (let ((matches nil)
1486 (exact nil)
1487 (Info-keeping-history nil)
1488 found)
1489 (while
1490 (progn
1491 (goto-char (point-min))
1492 (while (re-search-forward pattern nil t)
1493 (setq matches
1494 (cons (list (buffer-substring (match-beginning 1)
1495 (match-end 1))
1496 (buffer-substring (match-beginning 2)
1497 (match-end 2))
1498 Info-current-node
1499 (string-to-int (concat "0"
1500 (buffer-substring
1501 (match-beginning 3)
1502 (match-end 3)))))
1503 matches)))
1504 (and (setq node (Info-extract-pointer "next" t))
1505 (string-match "\\<Index\\>" node)))
1506 (let ((Info-fontify nil))
1507 (Info-goto-node node)))
1508 (or matches
1509 (progn
1510 (Info-last)
1511 (error "No \"%s\" in index" topic)))
1512 ;; Here it is a feature that assoc is case-sensitive.
1513 (while (setq found (assoc topic matches))
1514 (setq exact (cons found exact)
1515 matches (delq found matches)))
1516 (setq Info-index-alternatives (nconc exact (nreverse matches))
1517 Info-index-first-alternative (car Info-index-alternatives))
1518 (Info-index-next 0)))))
1519
1520 (defun Info-index-next (num)
1521 "Go to the next matching index item from the last `i' command."
1522 (interactive "p")
1523 (or Info-index-alternatives
1524 (error "No previous `i' command in this file"))
1525 (while (< num 0)
1526 (setq num (+ num (length Info-index-alternatives))))
1527 (while (> num 0)
1528 (setq Info-index-alternatives
1529 (nconc (cdr Info-index-alternatives)
1530 (list (car Info-index-alternatives)))
1531 num (1- num)))
1532 (Info-goto-node (nth 1 (car Info-index-alternatives)))
1533 (if (> (nth 3 (car Info-index-alternatives)) 0)
1534 (forward-line (nth 3 (car Info-index-alternatives)))
1535 (forward-line 3) ; don't search in headers
1536 (let ((name (car (car Info-index-alternatives))))
1537 (if (or (re-search-forward (format
1538 "\\(Function\\|Command\\): %s\\( \\|$\\)"
1539 (regexp-quote name)) nil t)
1540 (re-search-forward (format "^`%s[ ']" (regexp-quote name)) nil t)
1541 (search-forward (format "`%s'" name) nil t)
1542 (and (string-match "\\`.*\\( (.*)\\)\\'" name)
1543 (search-forward
1544 (format "`%s'" (substring name 0 (match-beginning 1)))
1545 nil t))
1546 (search-forward name nil t))
1547 (beginning-of-line)
1548 (goto-char (point-min)))))
1549 (message "Found \"%s\" in %s. %s"
1550 (car (car Info-index-alternatives))
1551 (nth 2 (car Info-index-alternatives))
1552 (if (cdr Info-index-alternatives)
1553 (if (eq (car (cdr Info-index-alternatives))
1554 Info-index-first-alternative)
1555 "(Press `,' to repeat)"
1556 (format "(Press `,' for %d more)"
1557 (- (1- (length Info-index-alternatives))
1558 (length (memq Info-index-first-alternative
1559 (cdr Info-index-alternatives))))))
1560 "(Only match)")))
1561
1562
1563 ;;;###autoload
1564 (defun Info-emacs-command (command)
1565 "Look up an Emacs command in the Emacs manual in the Info system.
1566 This command is designed to be used whether you are already in Info or not."
1567 (interactive "CLook up command in Emacs manual: ")
1568 (save-window-excursion
1569 (info)
1570 (Info-find-node Info-emacs-info-file-name "Top")
1571 (Info-index (symbol-name command)))
1572 (pop-to-buffer "*info*"))
1573
1574 ;;;###autoload
1575 (defun Info-goto-emacs-command-node (key)
1576 "Look up an Emacs command in the Emacs manual in the Info system.
1577 This command is designed to be used whether you are already in Info or not."
1578 (interactive "CLook up command in Emacs manual: ")
1579 (Info-emacs-command key))
1580
1581 ;;;###autoload
1582 (defun Info-goto-emacs-key-command-node (key)
1583 "Look up an Emacs key sequence in the Emacs manual in the Info system.
1584 This command is designed to be used whether you are already in Info or not."
1585 (interactive "kLook up key in Emacs manual: ")
1586 (let ((command (key-binding key)))
1587 (cond ((eq command 'keyboard-quit)
1588 (keyboard-quit))
1589 ((null command)
1590 (error "%s is undefined" (key-description key)))
1591 ((and (interactive-p) (eq command 'execute-extended-command))
1592 (call-interactively 'Info-goto-emacs-command-node))
1593 (t
1594 (Info-goto-emacs-command-node command)))))
1595
1596 ;;;###autoload
1597 (defun Info-emacs-key (key)
1598 "Look up an Emacs key sequence in the Emacs manual in the Info system.
1599 This command is designed to be used whether you are already in Info or not."
1600 (interactive "kLook up key in Emacs manual: ")
1601 (cond ((eq (key-binding key) 'keyboard-quit)
1602 (keyboard-quit))
1603 ((and (interactive-p) (eq (key-binding key) 'execute-extended-command))
1604 (call-interactively 'Info-goto-emacs-command-node))
1605 (t
1606 (save-window-excursion
1607 (info)
1608 (Info-find-node Info-emacs-info-file-name "Top")
1609 (setq key (key-description key))
1610 (let (p)
1611 (if (setq p (string-match "[@{}]" key))
1612 (setq key (concat (substring key 0 p) "@" (substring key p))))
1613 (if (string-match "^ESC " key)
1614 (setq key (concat "M-" (substring key 4))))
1615 (if (string-match "^M-C-" key)
1616 (setq key (concat "C-M-" (substring key 4)))))
1617 (Info-index key))
1618 (pop-to-buffer "*info*"))))
1619
1620 ;;;###autoload
1621 (defun Info-elisp-ref (func)
1622 "Look up an Emacs Lisp function in the Elisp manual in the Info system.
1623 This command is designed to be used whether you are already in Info or not."
1624 (interactive (let ((fn (function-called-at-point))
1625 (enable-recursive-minibuffers t)
1626 val)
1627 (setq val (completing-read
1628 (format "Look up Emacs Lisp function%s: "
1629 (if fn
1630 (format " (default %s)" fn)
1631 ""))
1632 obarray 'fboundp t))
1633 (list (if (equal val "")
1634 fn (intern val)))))
1635 (save-window-excursion
1636 (info)
1637 (condition-case nil
1638 (Info-find-node "elisp" "Top")
1639 (error (Info-find-node "lispref" "Top")))
1640 (Info-index (symbol-name func)))
1641 (pop-to-buffer "*info*"))
1642
1643 (defun Info-reannotate-node ()
1644 (let ((bufs (delq nil (mapcar 'get-file-buffer Info-annotations-path))))
1645 (if bufs
1646 (let ((ibuf (current-buffer))
1647 (file (concat "\\(" (regexp-quote
1648 (file-name-nondirectory Info-current-file))
1649 "\\|" (regexp-quote Info-current-file) "\\)"))
1650 (node (regexp-quote Info-current-node))
1651 (savept (point)))
1652 (goto-char (point-min))
1653 (if (search-forward "\n------ NOTE:\n" nil t)
1654 (let ((buffer-read-only nil)
1655 (bufmod (buffer-modified-p))
1656 top)
1657 (setq savept (copy-marker savept))
1658 (goto-char (point-min))
1659 (while (search-forward "\n------ NOTE:" nil t)
1660 (setq top (1+ (match-beginning 0)))
1661 (if (search-forward "\n------\n" nil t)
1662 (delete-region top (point)))
1663 (backward-char 1))
1664 (set-buffer-modified-p bufmod)))
1665 (save-excursion
1666 (while bufs
1667 (set-buffer (car bufs))
1668 (goto-char (point-min))
1669 (while (re-search-forward
1670 (format
1671 "------ *File: *%s *Node: *%s *Line: *\\([0-9]+\\) *\n"
1672 file node)
1673 nil t)
1674 (let ((line (string-to-int
1675 (buffer-substring (match-beginning 2)
1676 (match-end 2))))
1677 (top (point))
1678 bot)
1679 (search-forward "\n------\n" nil t)
1680 (setq bot (point))
1681 (save-excursion
1682 (set-buffer ibuf)
1683 (if (integerp savept) (setq savept (copy-marker savept)))
1684 (if (= line 0)
1685 (goto-char (point-max))
1686 (goto-char (point-min))
1687 (forward-line line))
1688 (let ((buffer-read-only nil)
1689 (bufmod (buffer-modified-p)))
1690 (insert "------ NOTE:\n")
1691 (insert-buffer-substring (car bufs) top bot)
1692 (set-buffer-modified-p bufmod)))))
1693 (setq bufs (cdr bufs))))
1694 (goto-char savept)))))
1695
1696 (defvar Info-annotate-map nil
1697 "Local keymap used within `a' command of Info.")
1698 (if Info-annotate-map
1699 nil
1700 ;; (setq Info-annotate-map (nconc (make-sparse-keymap) text-mode-map))
1701 (setq Info-annotate-map (copy-keymap text-mode-map))
1702 (define-key Info-annotate-map "\C-c\C-c" 'Info-cease-annotate))
1703
1704 (defun Info-annotate-mode ()
1705 "Major mode for adding an annotation to an Info node.
1706 Like text mode with the addition of Info-cease-annotate
1707 which returns to Info mode for browsing.
1708 \\{Info-annotate-map}")
1709
1710 (defun Info-annotate (arg)
1711 "Add a personal annotation to the current Info node.
1712 Only you will be able to see this annotation.
1713 Annotations are stored in the file ~/.infonotes by default.
1714 If point is inside an existing annotation, edit that annotation.
1715 A prefix argument specifies which annotations file (from
1716 Info-annotations-path) is to be edited; default is 1."
1717 (interactive "p")
1718 (setq arg (1- arg))
1719 (if (or (< arg 0) (not (nth arg Info-annotations-path)))
1720 (if (= arg 0)
1721 (setq Info-annotations-path
1722 (list (read-file-name
1723 "Annotations file: " "~/" "~/.infonotes")))
1724 (error "File number must be in the range from 1 to %d"
1725 (length Info-annotations-path))))
1726 (let ((which nil)
1727 (file (file-name-nondirectory Info-current-file))
1728 (d Info-directory-list)
1729 where pt)
1730 (while (and d (not (equal (expand-file-name file (car d))
1731 Info-current-file)))
1732 (setq d (cdr d)))
1733 (or d (setq file Info-current-file))
1734 (if (and (save-excursion
1735 (goto-char (min (point-max) (+ (point) 13)))
1736 (and (search-backward "------ NOTE:\n" nil t)
1737 (setq pt (match-end 0))
1738 (search-forward "\n------\n" nil t)))
1739 (< (point) (match-end 0)))
1740 (setq which (format "File: *%s *Node: *%s *Line:.*\n%s"
1741 (regexp-quote file)
1742 (regexp-quote Info-current-node)
1743 (regexp-quote
1744 (buffer-substring pt (match-beginning 0))))
1745 where (max (- (point) pt) 0)))
1746 (let ((node Info-current-node)
1747 (line (if (looking-at "[ \n]*\\'") 0
1748 (count-lines (point-min) (point)))))
1749 (or which
1750 (let ((buffer-read-only nil)
1751 (bufmod (buffer-modified-p)))
1752 (beginning-of-line)
1753 (if (bobp) (goto-char (point-max)))
1754 (insert "------ NOTE:\n------\n")
1755 (backward-char 20)
1756 (set-buffer-modified-p bufmod)))
1757 ;; (setq Info-window-start (window-start))
1758 (setq Info-window-configuration (current-window-configuration))
1759 (pop-to-buffer (find-file-noselect (nth arg Info-annotations-path)))
1760 (use-local-map Info-annotate-map)
1761 (setq major-mode 'Info-annotate-mode)
1762 (setq mode-name "Info Annotate")
1763 (if which
1764 (if (save-excursion
1765 (goto-char (point-min))
1766 (re-search-forward which nil t))
1767 (progn
1768 (goto-char (match-beginning 0))
1769 (forward-line 1)
1770 (forward-char where)))
1771 (let ((bufmod (buffer-modified-p)))
1772 (goto-char (point-max))
1773 (insert (format "\n------ File: %s Node: %s Line: %d\n"
1774 file node line))
1775 (setq pt (point))
1776 (insert "\n------\n"
1777 "\nPress C-c C-c to save and return to Info.\n")
1778 (goto-char pt)
1779 (set-buffer-modified-p bufmod))))))
1780
1781 (defun Info-cease-annotate ()
1782 (interactive)
1783 (let ((bufmod (buffer-modified-p)))
1784 (while (save-excursion
1785 (goto-char (point-min))
1786 (re-search-forward "\n\n?Press .* to save and return to Info.\n"
1787 nil t))
1788 (delete-region (1+ (match-beginning 0)) (match-end 0)))
1789 (while (save-excursion
1790 (goto-char (point-min))
1791 (re-search-forward "\n------ File:.*Node:.*Line:.*\n+------\n"
1792 nil t))
1793 (delete-region (match-beginning 0) (match-end 0)))
1794 (set-buffer-modified-p bufmod))
1795 (save-buffer)
1796 (fundamental-mode)
1797 (bury-buffer)
1798 (or (one-window-p) (delete-window))
1799 (info)
1800 (setq Info-current-annotation-completions nil)
1801 (set-window-configuration Info-window-configuration)
1802 (Info-reannotate-node))
1803
1804 (defun Info-bookmark (arg tag)
1805 (interactive "p\nsBookmark name: ")
1806 (Info-annotate arg)
1807 (if (or (string-match "^\"\\(.*\\)\"$" tag)
1808 (string-match "^<<\\(.*\\)>>$" tag))
1809 (setq tag (substring tag (match-beginning 1) (match-end 1))))
1810 (let ((pt (point)))
1811 (search-forward "\n------\n")
1812 (let ((end (- (point) 8)))
1813 (goto-char pt)
1814 (if (re-search-forward "<<[^>\n]*>>" nil t)
1815 (delete-region (match-beginning 0) (match-end 0))
1816 (goto-char end))
1817 (or (equal tag "")
1818 (insert "<<" tag ">>"))))
1819 (Info-cease-annotate))
1820
1821 (defun Info-exit ()
1822 "Exit Info by selecting some other buffer."
1823 (interactive)
1824 (if Info-standalone
1825 (save-buffers-kill-emacs)
1826 (switch-to-buffer (prog1 (other-buffer (current-buffer))
1827 (bury-buffer (current-buffer))))))
1828
1829 (defun Info-undefined ()
1830 "Make command be undefined in Info."
1831 (interactive)
1832 (ding))
1833
1834 (defun Info-help ()
1835 "Enter the Info tutorial."
1836 (interactive)
1837 (delete-other-windows)
1838 (Info-find-node "info"
1839 (if (< (window-height) 23)
1840 "Help-Small-Screen"
1841 "Help")))
1842
1843 (defun Info-summary ()
1844 "Display a brief summary of all Info commands."
1845 (interactive)
1846 (save-window-excursion
1847 (switch-to-buffer "*Help*")
1848 (erase-buffer)
1849 (insert (documentation 'Info-mode))
1850 (goto-char (point-min))
1851 (let (flag)
1852 (while (progn (setq flag (not (pos-visible-in-window-p (point-max))))
1853 (message (if flag "Type Space to see more"
1854 "Type Space to return to Info"))
1855 (let ((e (next-command-event)))
1856 (if (/= ?\ (event-to-character e))
1857 (progn (setq unread-command-event e) nil)
1858 flag)))
1859 (scroll-up)))
1860 (message "")
1861 (bury-buffer "*Help*")))
1862
1863 (defun Info-get-token (pos start all &optional errorstring)
1864 "Return the token around POS,
1865 POS must be somewhere inside the token
1866 START is a regular expression which will match the
1867 beginning of the tokens delimited string
1868 ALL is a regular expression with a single
1869 parenthized subpattern which is the token to be
1870 returned. E.g. '{\(.*\)}' would return any string
1871 enclosed in braces around POS.
1872 SIG optional fourth argument, controls action on no match
1873 nil: return nil
1874 t: beep
1875 a string: signal an error, using that string."
1876 (save-excursion
1877 (goto-char (point-min))
1878 (re-search-backward "\\`") ; Bug fix due to Nicholas J. Foskett.
1879 (goto-char pos)
1880 (re-search-backward start (max (point-min) (- pos 200)) 'yes)
1881 (let (found)
1882 (while (and (re-search-forward all (min (point-max) (+ pos 200)) 'yes)
1883 (not (setq found (and (<= (match-beginning 0) pos)
1884 (> (match-end 0) pos))))))
1885 (if (and found (<= (match-beginning 0) pos)
1886 (> (match-end 0) pos))
1887 (buffer-substring (match-beginning 1) (match-end 1))
1888 (cond ((null errorstring)
1889 nil)
1890 ((eq errorstring t)
1891 (beep)
1892 nil)
1893 (t
1894 (error "No %s around position %d" errorstring pos)))))))
1895
1896 (defun Info-follow-clicked-node (event)
1897 "Follow a node reference near clicked point. Like M, F, N, P or U command.
1898 At end of the node's text, moves to the next node."
1899 (interactive "@e")
1900 (or (and (event-point event)
1901 (Info-follow-nearest-node
1902 (max (progn
1903 (select-window (event-window event))
1904 (event-point event))
1905 (1+ (point-min)))))
1906 (error "click on a cross-reference to follow")))
1907
1908 (defun Info-maybe-follow-clicked-node (event &optional click-count)
1909 "Follow a node reference (if any) near clicked point.
1910 Like M, F, N, P or U command. At end of the node's text, moves to the
1911 next node. No error is given if there is no node to follow."
1912 (interactive "@e")
1913 (and (event-point event)
1914 (Info-follow-nearest-node
1915 (max (progn
1916 (select-window (event-window event))
1917 (event-point event))
1918 (1+ (point-min))))))
1919
1920 (defun Info-find-nearest-node (point)
1921 (let (node)
1922 (cond
1923 ((= point (point-min)) nil) ; don't trigger on accidental RET.
1924 ((setq node (Info-get-token point
1925 (format "\\*%s[ \n]" Info-footnote-tag)
1926 (format "\\*%s[ \n]\\([^:]*\\):"
1927 Info-footnote-tag)))
1928 (list "Following cross-reference %s..."
1929 (list 'Info-follow-reference node)))
1930 ((setq node (Info-get-token point "\\* " "\\* \\([^:]*\\)::"))
1931 (list "Selecting menu item %s..."
1932 (list 'Info-goto-node node nil t)))
1933 ((setq node (Info-get-token point "\\* " "\\* \\([^:]*\\):"))
1934 (list "Selecting menu item %s..."
1935 (list 'Info-menu node)))
1936 ((setq node (Info-get-token point "Up: " "Up: \\([^,\n\t]*\\)"))
1937 (list "Going up..."
1938 (list 'Info-goto-node node)))
1939 ((setq node (Info-get-token point "Next: " "Next: \\([^,\n\t]*\\)"))
1940 (list "Next node..."
1941 (list 'Info-goto-node node)))
1942 ((setq node (Info-get-token point "File: " "File: \\([^,\n\t]*\\)"))
1943 (list "Top node..."
1944 (list 'Info-goto-node "Top")))
1945 ((setq node (Info-get-token point "Prev[ious]*: "
1946 "Prev[ious]*: \\([^,\n\t]*\\)"))
1947 (list "Previous node..."
1948 (list 'Info-goto-node node)))
1949 ((setq node (Info-get-token point "Node: " "Node: \\([^,\n\t]*\\)"))
1950 (list "Reselecting %s..."
1951 (list 'Info-goto-node node)))
1952 ((save-excursion (goto-char point) (looking-at "[ \n]*\\'"))
1953 (if Info-in-cross-reference
1954 (list "Back to last node..."
1955 '(Info-last))
1956 (list "Next node..."
1957 '(Info-global-next)))))
1958 ))
1959
1960 (defun Info-follow-nearest-node (point)
1961 "Follow a node reference near point. Like M, F, N, P or U command.
1962 At end of the node's text, moves to the next node."
1963 (interactive "d")
1964 (let ((data (Info-find-nearest-node point)))
1965 (if (null data)
1966 nil
1967 (let ((msg (format (car data) (nth 1 (nth 1 data)))))
1968 (message "%s" msg)
1969 (eval (nth 1 data))
1970 (message "%sdone" msg))
1971 t)))
1972
1973 (defun Info-indicated-node (event)
1974 (condition-case ()
1975 (save-excursion
1976 (cond ((eventp event)
1977 (set-buffer (event-buffer event))
1978 (setq event (event-point event))))
1979 (let* ((data (Info-find-nearest-node event))
1980 (name (nth 1 (nth 1 data))))
1981 (and name (nth 1 data))))
1982 (error nil)))
1983
1984
1985 (defvar Info-mode-map nil
1986 "Keymap containing Info commands.")
1987 (if Info-mode-map
1988 nil
1989 (setq Info-mode-map (make-keymap))
1990 (suppress-keymap Info-mode-map)
1991 (define-key Info-mode-map "." 'beginning-of-buffer)
1992 (define-key Info-mode-map " " 'Info-scroll-next)
1993 (define-key Info-mode-map "1" 'Info-nth-menu-item)
1994 (define-key Info-mode-map "2" 'Info-nth-menu-item)
1995 (define-key Info-mode-map "3" 'Info-nth-menu-item)
1996 (define-key Info-mode-map "4" 'Info-nth-menu-item)
1997 (define-key Info-mode-map "5" 'Info-nth-menu-item)
1998 (define-key Info-mode-map "6" 'Info-nth-menu-item)
1999 (define-key Info-mode-map "7" 'Info-nth-menu-item)
2000 (define-key Info-mode-map "8" 'Info-nth-menu-item)
2001 (define-key Info-mode-map "9" 'Info-nth-menu-item)
2002 (define-key Info-mode-map "0" 'Info-last-menu-item)
2003 (define-key Info-mode-map "?" 'Info-summary)
2004 (define-key Info-mode-map "a" 'Info-annotate)
2005 (define-key Info-mode-map "b" 'beginning-of-buffer)
2006 (define-key Info-mode-map "d" 'Info-directory)
2007 (define-key Info-mode-map "e" 'Info-edit)
2008 (define-key Info-mode-map "f" 'Info-follow-reference)
2009 (define-key Info-mode-map "g" 'Info-goto-node)
2010 (define-key Info-mode-map "h" 'Info-help)
2011 (define-key Info-mode-map "i" 'Info-index)
2012 (define-key Info-mode-map "j" 'Info-goto-bookmark)
2013 (define-key Info-mode-map "k" 'Info-emacs-key)
2014 (define-key Info-mode-map "l" 'Info-last)
2015 (define-key Info-mode-map "m" 'Info-menu)
2016 (define-key Info-mode-map "n" 'Info-next)
2017 (define-key Info-mode-map "p" 'Info-prev)
2018 (define-key Info-mode-map "q" 'Info-exit)
2019 (define-key Info-mode-map "r" 'Info-follow-reference)
2020 (define-key Info-mode-map "s" 'Info-search)
2021 (define-key Info-mode-map "t" 'Info-top)
2022 (define-key Info-mode-map "u" 'Info-up)
2023 (define-key Info-mode-map "v" 'Info-visit-file)
2024 (define-key Info-mode-map "x" 'Info-bookmark)
2025 (define-key Info-mode-map "<" 'Info-top)
2026 (define-key Info-mode-map ">" 'Info-end)
2027 (define-key Info-mode-map "[" 'Info-global-prev)
2028 (define-key Info-mode-map "]" 'Info-global-next)
2029 (define-key Info-mode-map "{" 'Info-page-prev)
2030 (define-key Info-mode-map "}" 'Info-page-next)
2031 (define-key Info-mode-map "=" 'Info-restore-point)
2032 (define-key Info-mode-map "!" 'Info-select-node)
2033 (define-key Info-mode-map "@" 'Info-follow-nearest-node)
2034 (define-key Info-mode-map "," 'Info-index-next)
2035 (define-key Info-mode-map "*" 'Info-elisp-ref)
2036 (define-key Info-mode-map "\t" 'Info-next-reference)
2037 (define-key Info-mode-map "\e\t" 'Info-prev-reference)
2038 (define-key Info-mode-map "\r" 'Info-follow-nearest-node)
2039 (define-key Info-mode-map "\177" 'Info-scroll-prev)
2040 ;; XEmacs addition
2041 (define-key Info-mode-map [backspace] 'Info-scroll-prev)
2042
2043 (define-key Info-mode-map 'button2 'Info-follow-clicked-node)
2044 (define-key Info-mode-map 'button3 'Info-select-node-menu))
2045
2046
2047 ;; Info mode is suitable only for specially formatted data.
2048 (put 'info-mode 'mode-class 'special)
2049
2050 (defun Info-mode ()
2051 "Info mode is for browsing through the Info documentation tree.
2052 Documentation in Info is divided into \"nodes\", each of which
2053 discusses one topic and contains references to other nodes
2054 which discuss related topics. Info has commands to follow
2055 the references and show you other nodes.
2056
2057 h Invoke the Info tutorial.
2058 q Quit Info: return to the previously selected file or buffer.
2059
2060 Selecting other nodes:
2061 n Move to the \"next\" node of this node.
2062 p Move to the \"previous\" node of this node.
2063 m Pick menu item specified by name (or abbreviation).
2064 1-9, 0 Pick first..ninth, last item in node's menu.
2065 Menu items select nodes that are \"subsections\" of this node.
2066 u Move \"up\" from this node (i.e., from a subsection to a section).
2067 f or r Follow a cross reference by name (or abbrev). Type `l' to get back.
2068 RET Follow cross reference or menu item indicated by cursor.
2069 i Look up a topic in this file's Index and move to that node.
2070 , (comma) Move to the next match from a previous `i' command.
2071 l (letter L) Move back to the last node you were in.
2072
2073 Moving within a node:
2074 Space Scroll forward a full screen. DEL Scroll backward.
2075 b Go to beginning of node. Meta-> Go to end of node.
2076 TAB Go to next cross-reference. Meta-TAB Go to previous ref.
2077
2078 Mouse commands:
2079 Left Button Set point.
2080 Middle Button Click on a highlighted node reference to go to it.
2081 Right Button Pop up a menu of applicable Info commands.
2082
2083 Advanced commands:
2084 g Move to node, file, or annotation tag specified by name.
2085 Examples: `g Rectangles' `g (Emacs)Rectangles' `g Emacs'.
2086 v Move to file, with filename completion.
2087 k Look up a key sequence in Emacs manual (also C-h C-k at any time).
2088 * Look up a function name in Emacs Lisp manual (also C-h C-f).
2089 d Go to the main directory of Info files.
2090 < or t Go to Top (first) node of this file.
2091 > Go to last node in this file.
2092 \[ Go to previous node, treating file as one linear document.
2093 \] Go to next node, treating file as one linear document.
2094 { Scroll backward, or go to previous node if at top.
2095 } Scroll forward, or go to next node if at bottom.
2096 = Restore cursor position from last time in this node.
2097 a Add a private note (annotation) to the current node.
2098 x, j Add, jump to a bookmark (annotation tag).
2099 s Search this Info file for a node containing the specified regexp.
2100 e Edit the contents of the current node."
2101 (kill-all-local-variables)
2102 (setq major-mode 'Info-mode)
2103 (setq mode-name "Info")
2104 (use-local-map Info-mode-map)
2105 (set-syntax-table text-mode-syntax-table)
2106 (setq local-abbrev-table text-mode-abbrev-table)
2107 (setq case-fold-search t)
2108 (setq buffer-read-only t)
2109 ; (setq buffer-mouse-map Info-mode-mouse-map)
2110 (make-local-variable 'Info-current-file)
2111 (make-local-variable 'Info-current-subfile)
2112 (make-local-variable 'Info-current-node)
2113 (make-local-variable 'Info-tag-table-marker)
2114 (make-local-variable 'Info-current-file-completions)
2115 (make-local-variable 'Info-current-annotation-completions)
2116 (make-local-variable 'Info-index-alternatives)
2117 (make-local-variable 'Info-history)
2118 (if t ;; XEmacs: remove v19 test
2119 (progn
2120 (or (and (fboundp 'find-face) (find-face 'info-node))
2121 (make-face 'info-node "used for node links in info"))
2122 (or (and (fboundp 'find-face) (find-face 'info-xref))
2123 (make-face 'info-xref "used for cross-references in info"))
2124 (or (face-differs-from-default-p 'info-node)
2125 (if (face-differs-from-default-p 'bold-italic)
2126 (copy-face 'bold-italic 'info-node)
2127 (copy-face 'bold 'info-node)))
2128 (or (face-differs-from-default-p 'info-xref)
2129 (copy-face 'bold 'info-xref))))
2130 (make-local-variable 'mouse-track-click-hook)
2131 (add-hook 'mouse-track-click-hook 'Info-maybe-follow-clicked-node)
2132 ;; #### The console-on-window-system-p check is to allow this to
2133 ;; work on tty's. The real problem here is that featurep really
2134 ;; needs to have some device/console domain knowledge added to it.
2135 (if (and (featurep 'toolbar)
2136 (console-on-window-system-p)
2137 (not Info-inhibit-toolbar))
2138 (set-specifier default-toolbar (cons (current-buffer) info::toolbar)))
2139 (if (featurep 'menubar)
2140 (progn
2141 ;; make a local copy of the menubar, so our modes don't
2142 ;; change the global menubar
2143 (set-buffer-menubar current-menubar)
2144 (add-submenu nil '("Info"
2145 :filter Info-menu-filter))))
2146 (run-hooks 'Info-mode-hook)
2147 (Info-set-mode-line))
2148
2149 (defvar Info-edit-map nil
2150 "Local keymap used within `e' command of Info.")
2151 (if Info-edit-map
2152 nil
2153 ;; XEmcas: remove FSF stuff
2154 (setq Info-edit-map (make-sparse-keymap))
2155 (set-keymap-name Info-edit-map 'Info-edit-map)
2156 (set-keymap-parents Info-edit-map (list text-mode-map))
2157 (define-key Info-edit-map "\C-c\C-c" 'Info-cease-edit))
2158
2159 ;; Info-edit mode is suitable only for specially formatted data.
2160 (put 'info-edit-mode 'mode-class 'special)
2161
2162 (defun Info-edit-mode ()
2163 "Major mode for editing the contents of an Info node.
2164 Like text mode with the addition of `Info-cease-edit'
2165 which returns to Info mode for browsing.
2166 \\{Info-edit-map}"
2167 )
2168
2169 (defun Info-edit ()
2170 "Edit the contents of this Info node.
2171 Allowed only if variable `Info-enable-edit' is non-nil."
2172 (interactive)
2173 (or Info-enable-edit
2174 (error "Editing info nodes is not enabled"))
2175 (use-local-map Info-edit-map)
2176 (setq major-mode 'Info-edit-mode)
2177 (setq mode-name "Info Edit")
2178 (kill-local-variable 'modeline-buffer-identification)
2179 (setq buffer-read-only nil)
2180 ;; Make mode line update.
2181 (set-buffer-modified-p (buffer-modified-p))
2182 (message (substitute-command-keys
2183 "Editing: Type \\[Info-cease-edit] to return to info")))
2184
2185 (defun Info-cease-edit ()
2186 "Finish editing Info node; switch back to Info proper."
2187 (interactive)
2188 ;; Do this first, so nothing has changed if user C-g's at query.
2189 (and (buffer-modified-p)
2190 (y-or-n-p "Save the file? ")
2191 (save-buffer))
2192 (use-local-map Info-mode-map)
2193 (setq major-mode 'Info-mode)
2194 (setq mode-name "Info")
2195 (Info-set-mode-line)
2196 (setq buffer-read-only t)
2197 ;; Make mode line update.
2198 (set-buffer-modified-p (buffer-modified-p))
2199 (and (marker-position Info-tag-table-marker)
2200 (buffer-modified-p)
2201 (message "Tags may have changed. Use Info-tagify if necessary")))
2202
2203 (defun Info-find-emacs-command-nodes (command)
2204 "Return a list of locations documenting COMMAND in the XEmacs Info manual.
2205 The locations are of the format used in Info-history, i.e.
2206 \(FILENAME NODENAME BUFFERPOS\)."
2207 (let ((where '())
2208 (cmd-desc (concat "^\\* " (regexp-quote (symbol-name command))
2209 ":\\s *\\(.*\\)\\.$")))
2210 (save-excursion
2211 (Info-find-node "XEmacs" "Command Index")
2212 ;; Take the index node off the Info history.
2213 (setq Info-history (cdr Info-history))
2214 (goto-char (point-max))
2215 (while (re-search-backward cmd-desc nil t)
2216 (setq where (cons (list Info-current-file
2217 (buffer-substring
2218 (match-beginning 1)
2219 (match-end 1))
2220 0)
2221 where)))
2222 where)))
2223
2224
2225 ;;; fontification and mousability for info
2226
2227 (defun Info-highlight-region (start end face)
2228 (let ((extent (make-extent start end)))
2229 (set-extent-face extent face)
2230 (set-extent-property extent 'info t)
2231 (set-extent-property extent 'highlight t)))
2232
2233 (defun Info-fontify-node ()
2234 (save-excursion
2235 (let (;(lucid (string-match "Lucid" emacs-version))
2236 (case-fold-search t)
2237 (xref-regexp (concat "\\*"
2238 (regexp-quote Info-footnote-tag)
2239 "[ \n\t]*\\([^:]*\\):")))
2240 ; (if lucid
2241 (map-extents (function (lambda (x y) (delete-extent x)))
2242 (current-buffer) (point-min) (point-max) nil)
2243 ; )
2244 (goto-char (point-min))
2245 (if (looking-at "^File: [^,: \t]+,?[ \t]+")
2246 (progn
2247 (goto-char (match-end 0))
2248 (while
2249 (looking-at "[ \t]*[^:, \t\n]+:[ \t]+\\([^:,\t\n]+\\),?")
2250 (goto-char (match-end 0))
2251 (Info-highlight-region (match-beginning 1) (match-end 1)
2252 'info-xref ;lucid
2253 ))))
2254 (goto-char (point-min))
2255 (while (re-search-forward xref-regexp nil t)
2256 (if (= (char-after (1- (match-beginning 0))) ?\") ; hack
2257 nil
2258 (Info-highlight-region (match-beginning 1) (match-end 1)
2259 'info-xref ;lucid
2260 )))
2261 (goto-char (point-min))
2262 (if (and (search-forward "\n* menu:" nil t)
2263 ;; principle of least astonishment, dude...
2264 ;; (Also, in xemacs this is fast even on indexes, and without it, nodes don't
2265 ;; highlight when you move over them.)
2266 ;; (not (string-match "\\<Index\\>" Info-current-node))
2267 ;; (< (- (point-max) (point)) 10000)
2268 )
2269 (while (re-search-forward "^\\* \\([^:\t\n]*\\):" nil t)
2270 (Info-highlight-region (match-beginning 1) (match-end 1)
2271 'info-node ;lucid
2272 )))
2273 (set-buffer-modified-p nil))))
2274
2275 (defun Info-construct-menu (&optional event)
2276 "Construct a menu of Info commands.
2277 Adds an entry for the node at EVENT, or under point if EVENT is omitted.
2278 Used to construct the menubar submenu and popup menu."
2279 (or event (setq event (point)))
2280 (let ((case-fold-search t)
2281 (xref-regexp (concat "\\*"
2282 (regexp-quote Info-footnote-tag)
2283 "[ \n\t]*\\([^:]*\\):"))
2284 up-p prev-p next-p menu
2285 i text xrefs subnodes in)
2286 (save-excursion
2287 (goto-char (point-min))
2288 (if (looking-at ".*\\bNext:") (setq next-p t))
2289 (if (looking-at ".*\\bPrev:") (setq prev-p t))
2290 (if (looking-at ".*Up:") (setq up-p t))
2291 (setq menu (nconc
2292 (if (setq in (Info-indicated-node event))
2293 (list (vector (car (cdr in)) in t)))
2294 (list
2295 ["Goto Info Top-level" Info-directory t]
2296 (vector "Next Node" 'Info-next next-p)
2297 (vector "Previous Node" 'Info-prev prev-p)
2298 (vector "Parent Node (Up)" 'Info-up up-p)
2299 ["Goto Node..." Info-goto-node t]
2300 ["Goto Last Visited Node" Info-last t])))
2301 (while (re-search-forward xref-regexp nil t)
2302 (setq text (buffer-substring (match-beginning 1) (match-end 1)))
2303 (while (setq i (string-match "[ \n\t]+" text i))
2304 (setq text (concat (substring text 0 i) " "
2305 (substring text (match-end 0))))
2306 (setq i (1+ i)))
2307 (setq xrefs (cons text xrefs)))
2308 (setq xrefs (nreverse xrefs))
2309 (if (> (length xrefs) 21) (setcdr (nthcdr 20 xrefs) '(more)))
2310 (goto-char (point-min))
2311 (if (search-forward "\n* menu:" nil t)
2312 (while (re-search-forward "^\\* \\([^:\t\n]*\\):" nil t)
2313 (setq text (buffer-substring (match-beginning 1) (match-end 1)))
2314 (setq subnodes (cons text subnodes))))
2315 (setq subnodes (nreverse subnodes))
2316 (if (> (length subnodes) 21) (setcdr (nthcdr 20 subnodes) '(more)))
2317 )
2318 (if xrefs
2319 (nconc menu (list "----" "Cross-References:" "----")
2320 (mapcar (function (lambda (xref)
2321 (if (eq xref 'more)
2322 "...more..."
2323 (vector xref
2324 (list 'Info-follow-reference xref)
2325 t))))
2326 xrefs)))
2327 (if subnodes
2328 (nconc menu (list "----" "Sub-Nodes:" "----")
2329 (mapcar (function (lambda (node)
2330 (if (eq node 'more)
2331 "...more..."
2332 (vector node (list 'Info-menu node)
2333 t))))
2334 subnodes)))
2335 menu))
2336
2337 (defun Info-menu-filter (menu)
2338 "This is the menu filter for the \"Info\" submenu."
2339 (Info-construct-menu))
2340
2341 (defun Info-select-node-menu (event)
2342 "Pops up a menu of applicable Info commands."
2343 (interactive "e")
2344 (select-window (event-window event))
2345 (let ((menu (Info-construct-menu event)))
2346 (setq menu (nconc (list "Info" ; title: not shown
2347 "Info Commands:" "----")
2348 menu))
2349 (let ((popup-menu-titles nil))
2350 (popup-menu menu))))
2351
2352 ;;; Info toolbar support
2353
2354 ;; exit icon taken from GNUS
2355 (defvar info::toolbar-exit-icon
2356 (if (featurep 'toolbar)
2357 (toolbar-make-button-list
2358 (expand-file-name (if (featurep 'xpm) "info-exit.xpm" "info-exit.xbm")
2359 toolbar-icon-directory)))
2360 "Exit Info icon")
2361
2362 (defvar info::toolbar-up-icon
2363 (if (featurep 'toolbar)
2364 (toolbar-make-button-list
2365 (expand-file-name (if (featurep 'xpm) "info-up.xpm" "info-up.xbm")
2366 toolbar-icon-directory)))
2367 "Up icon")
2368
2369 (defvar info::toolbar-next-icon
2370 (if (featurep 'toolbar)
2371 (toolbar-make-button-list
2372 (expand-file-name (if (featurep 'xpm) "info-next.xpm" "info-next.xbm")
2373 toolbar-icon-directory)))
2374 "Next icon")
2375
2376 (defvar info::toolbar-prev-icon
2377 (if (featurep 'toolbar)
2378 (toolbar-make-button-list
2379 (expand-file-name (if (featurep 'xpm) "info-prev.xpm" "info-prev.xbm")
2380 toolbar-icon-directory)))
2381 "Prev icon")
2382
2383 (defvar info::toolbar
2384 (if (featurep 'toolbar)
2385 ; disabled until we get the next/prev-win icons working again.
2386 ; (cons (first initial-toolbar-spec)
2387 ; (cons (second initial-toolbar-spec)
2388 '([info::toolbar-exit-icon
2389 Info-exit
2390 t
2391 "Exit info"]
2392 [info::toolbar-prev-icon
2393 Info-prev
2394 t
2395 "Prev entry in same section"]
2396 [info::toolbar-next-icon
2397 Info-next
2398 t
2399 "Next entry in same section"]
2400 [info::toolbar-up-icon
2401 Info-up
2402 t
2403 "Up entry to enclosing section"]
2404 )))
2405 ;))
2406
2407
2408 (provide 'info)
2409
2410 (run-hooks 'Info-load-hook)
2411
2412 ;;; info.el ends here