(eshell-du-prefer-over-ange): Doc fix.
[bpt/emacs.git] / lisp / word-help.el
CommitLineData
ec3fac5e
RS
1;;; word-help.el --- keyword help for any language doc'd in TeXinfo.
2
3;; Copyright (c) 1996 Free Software Foundation, Inc.
4
0acdb863 5;; Author: Jens T. Berger Thielemann <jensthi@ifi.uio.no>
e8dd2298 6;; Keywords: help, keyword, languages, completion
ec3fac5e
RS
7
8;; This file is part of GNU Emacs.
9
10;; This program is free software; you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation; either version 2, or (at your option)
13;; any later version.
14
15;; This program is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs; see the file COPYING. If not, write to the
22;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23;; Boston, MA 02111-1307, USA.
24
25;;; Commentary:
26
27;; This package provides a rather general interface for doing keyword
e8dd2298 28;; help in most languages. In short, it'll determine which TeXinfo
ec3fac5e
RS
29;; file which is relevant for the current mode; cache the index and
30;; use regexps to give you help on the keyword you're looking at.
31
32;; Installation
33;; ************
34
35;; For the default setup to work for all supported modes, make sure
36;; the Texinfo files from the following packages are installed:
37
38;; Texinfo file | Available in archive or URL | Notes
39;; autoconf.info | autoconf-2.10.tar.gz | -
40;; bison.info | bison-1.25.tar.gz | -
41;; libc.info | glibc-1.09.1.tar.gz | -
42;; elisp.info | elisp-manual-19-2.4.tar.gz | -
43;; latex.info | ftp://ftp.dante.de/pub/tex/info/latex2e-help-texinfo/latex2e.texi
44;; groff.info | groff-1.10.tar.gz | -
45;; m4.info | m4-1.4.tar.gz | -
46;; make.info | make-3.75.tar.gz | -
47;; perl.info | http://www.perl.com/CPAN/doc/manual/info/
48;; simula.info | Mail bjort@ifi.uio.no | Written in Norwegian
49;; texinfo.info | texinfo-3.9.tar.gz | -
50
51;; BTW: We refer to Texinfo files by just their last component, not
52;; with an absolute file name. You must thus set up
53;; `Info-directory-list' and `Info-default-directory-list' so that
54;; these can automatically be located.
55
56;; Usage
57;; *****
58;;
59;; Place the cursor over the function/variable/type/whatever you want
60;; help on. Type "C-h C-i". `word-help' will then make a suggestion
61;; to an index topic; press return to accept this. If not, you may use
62;; tab-completion to find the topic you're interested in.
63
e8dd2298
RS
64;; `word-help' is also able to do symbol completion via the
65;; `word-help-complete' function. Bind this function to C-TAB by
66;; adding the following line to your .emacs file:
67;;
68;; (global-set-key [?\M-\t] 'word-help-complete)
69;;
70;; Note that some modes automatically override this key; you may
71;; therefore wish to either put the above statement in a hook or
72;; associate the function with an other key.
73
ec3fac5e
RS
74;; Usually, `word-help' is able to determine the relevant Texinfo
75;; file from looking at the buffer's `mode-name'; if not, you can use
76;; the interactive function `set-help-file' to set this.
77
78;; Customizing
79;; ***********
80;;
81;; User interface
82;; --------------
83;;
84;; Two variables control the behaviour of the user-interface of
85;; `word-help': `word-help-split-window' and
86;; `word-help-magic-index'. Do C-h v to get more information on
87;; these.
88
89;; Adding more Texinfo files
90;; -------------------------
91;;
92;; Associations between mode-names and Texinfo files can be done
93;; through the `word-help-mode-alist' variable, which defines an
94;; `alist' making `set-help-file' able to initialize the necessary
95;; variable.
96
e8dd2298
RS
97;; NOTE: If you have to customize the regexps, it is *CRUCIAL* that
98;; none of your regexps match the empty string! Not adhering to this
99;; restriction will make `word-help' enter an infinite loop.
100
ec3fac5e
RS
101;; Contacting the author
102;; *********************
103;;
104;; If you wish to contact me for any reason, please feel free to write
105;; to:
106
107;; Jens Berger
108;; Spektrumveien 4
109;; N-0666 Oslo
110;; Norway
111;;
112;; E-mail: <jensthi@ifi.uio.no>
113
114;; Have fun.
115
116;;
117;;; Code:
118;;
119
120(require 'info)
121
122;;;--------------------
123;;; USER OPTIONS
124;;;--------------------
125
126(defvar word-help-split-window t
127 "*Non-nil means that the info buffer will pop up in a separate window.
128If nil, we will just switch to it.")
129
130(defvar word-help-magic-index t
e8dd2298 131 "*Non-nil means that the keyword will be searched for in the requested node.
ec3fac5e
RS
132This is done by determining whether the line the point is positioned
133on after using `Info-goto-node', actually contains the keyword. If
134not, we will search for the first occurence of the keyword. This may
135help when the info file isn't correctly indexed.")
136
137;;; ---- end of user configurable variables
138
139;;;-------------------------
140;;; ADVANCED USER OPTIONS
141;;;-------------------------
142
143(defvar word-help-mode-alist
e8dd2298
RS
144 '(
145 ("autoconf"
ec3fac5e
RS
146 (("autoconf" "Macro Index") ("m4" "Macro index"))
147 (("AC_\\([A-Za-z0-9_]+\\)" 1)
e8dd2298
RS
148 ("[a-z]+"))
149 nil
150 nil
151 (("AC_\\([A-Za-z0-9_]+\\)" 1 nil (("^[A-Z_]+$")))
152 ("[a-z_][a-z_]*" 0 nil (("^[a-z_]+$")))))
ec3fac5e
RS
153
154 ("Bison"
155 (("bison" "Index")
156 ("libc" "Type Index" "Function Index" "Variable Index"))
e8dd2298
RS
157 (("%[A-Za-z]*")
158 ("[A-Za-z_][A-Za-z0-9_]*"))
159 nil
160 nil
161 (("%[A-Za-z]*" nil nil (("^%")))
162 ("[A-Za-z_][A-Za-z0-9_]*" nil nil (("[A-Za-z_][A-Za-z0-9_]*")))))
163
ec3fac5e
RS
164 ("YACC" . "Bison")
165
166 ("C" (("libc" "Type Index" "Function Index" "Variable Index")))
167 ("C++" . "C")
168
169 ("Emacs-Lisp"
170 (("elisp" "Index"))
e8dd2298
RS
171 (("[^][ ()\n\t.\"'#]+"))
172 nil
173 nil
174 lisp-complete-symbol)
ec3fac5e
RS
175
176 ("LaTeX"
177 (("latex" "Command Index"))
178 (("\\\\\\(begin\\|end\\){\\([^}\n]+\\)}" 2 0)
179 ("\\\\[A-Za-z]+")
180 ("\\\\[^A-Za-z]")
e8dd2298
RS
181 ("[A-Za-z]+"))
182 nil
183 nil
184 (("\\\\begin{\\([A-Za-z]*\\)" 1 "}" (("^[A-Za-z]+$")))
185 ("\\\\end{\\([A-Za-z]*\\)" 1 "}" (("^[A-Za-z]+$")))
186 ("\\\\renewcommand{\\(\\\\?[A-Za-z]*\\)" 1 "}" (("^\\\\[A-Za-z]+")))
187 ("\\\\renewcommand\\(\\\\?[A-Za-z]*\\)" 1 "" (("^\\\\[A-Za-z]+")))
188 ("\\\\renewenvironment{?\\([A-Za-z]*\\)" 1 "}"(("^[A-Za-z]+$")))
189 ("\\\\[A-Za-z]*" 0 "" (("^\\\\[A-Za-z]+")))))
190
191 ("latex" . "LaTeX")
ec3fac5e
RS
192
193 ("Nroff"
194 (("groff" "Macro Index" "Register Index" "Request Index"))
e8dd2298
RS
195 (("\\.[^A-Za-z]")
196 ("\\.[A-Za-z]+")
197 ("\\.\\([A-Za-z]+\\)" 1))
198 nil
199 nil
200 (("\\.[A-Za-z]*" nil nil (("^\\.[A-Za-z]+$")))
201 ("\\.\\([A-Za-z]*\\)" 1 nil (("^[A-Za-z]+$")))))
202
ec3fac5e
RS
203 ("Groff" . "Nroff")
204
e8dd2298
RS
205 ("m4"
206 (("m4" "Macro index"))
207 (("\\([mM]4_\\)?\\([A-Za-z_][A-Za-z_0-9]*\\)" 2))
208 nil
209 nil
210 (("[mM]4_\\([A-Za-z_]?[A-Za-z_0-9]*\\)" 1)
211 ("[A-Za-z_][A-Za-z_0-9]*")))
ec3fac5e
RS
212
213 ("Makefile"
e8dd2298
RS
214 (("make" "Name Index"))
215 (("\\.[A-Za-z]+") ;; .SUFFIXES
216 ("\\$[^()]") ;; $@
217 ("\\$([^A-Za-z].)") ;; $(<@)
218 ("\\$[\(\{]\\([a-zA-Z+]\\)" 1) ;; $(wildcard)
219 ("[A-Za-z]+")) ;; foreach
220 nil
221 nil
222 (("\\.[A-Za-z]*" nil ":" (("^\\.[A-Za-z]+$")))
223 ("\\$(\\([A-Z]*\\)" 1 ")" (("^[A-Z]")))
224 ("[a-z]+" nil nil (("^[a-z]+$")))))
ec3fac5e
RS
225
226 ("Perl"
227 (("perl" "Variable Index" "Function Index"))
e8dd2298
RS
228 (("\\$[^A-Za-z^]") ;; $@
229 ("\\$\\^[A-Za-z]?") ;; $^D
230 ("\\$[A-Za-z][A-Za-z_0-9]+") ;; $foobar
231 ("[A-Za-z_][A-Za-z_0-9]+")) ;; dbmopen
ec3fac5e 232 nil
e8dd2298
RS
233 nil
234 (("\\$[A-Za-z]*" nil nil (("^\\$[A-Za-z]+$"))) ;; $variable
235 ("[A-Za-z_][A-Za-z_0-9]*" nil nil
236 (("^[A-Za-z_][A-Za-z_0-9]*$"))))) ;; function
ec3fac5e
RS
237
238 ("Simula" (("simula" "Index")) nil t)
239 ("Ifi Simula" . "Simula")
240 ("SIMULA" . "Simula")
241
242 ("Texinfo"
243 (("texinfo" "Command and Variable Index"))
e8dd2298
RS
244 (("@\\([A-Za-z]+\\)" 1))
245 nil
246 nil
247 (("@\\([A-Za-z]*\\)" 1)))
ec3fac5e
RS
248
249 )
250 "Assoc list between `mode-name' and Texinfo files.
251The variable should be initialized with a list of elements with the
252following form:
253
254\(mode-name (word-help-info-files) (word-help-keyword-regexps)
e8dd2298
RS
255 word-help-ignore-case word-help-index-mapper
256 word-help-complete-list)
ec3fac5e
RS
257
258where `word-help-info-files', `word-help-keyword-regexps' and so
259forth of course are the values which should be put in these variables
260for this mode. Note that `mode-name' doesn't have to be a legal
261mode-name; the user may use the call `set-help-file', where
262`mode-name' will be used in the `completing-read'.
263
264Example entry (for C):
265
266\(\"C\" ((\"libc\" \"Type Index\" \"Function Index\" \"Variable Index\"))
267 ((\"[A-Za-z_][A-Za-z0-9]+\")))
268
269The two first variables must be initialized; the two remaining will
270get default values if you omit them or set them to nil. The default
271values are:
272
273word-help-keyword-regexps: (\"[A-Za-z_][A-Za-z0-9]+\")
274word-help-ignore-case: nil
275
276More settings may be defined in the future.
277
278You may also define aliases, if there are several relevant mode-names
279to a single entry. These should be of the form:
280
281\(MODE-NAME-ALIAS . MODE-NAME-REAL)
282
283For C++, you would use the alias
284
285\(\"C++\" . \"C\")
286
287to make C++ mode use the same help files as C files do. Please note
288that you can shoot yourself in the foot with this possibility, by
289defining recursive aliases.")
290
291;;; --- end of advanced user options
292
293(defvar word-help-ignore-case nil
294 "Non-nil means that case is ignored when doing lookup.")
295(make-variable-buffer-local 'word-help-ignore-case)
296
297(defvar word-help-info-files nil
e8dd2298 298 "List of info files with respective nodes, for the current mode.
ec3fac5e
RS
299
300This should be a list of the following form:
301
302\((INFO-FILE-1 NODE-NAME-1 NODE-NAME-2 ...)
303 (INFO-FILE-1 NODE-NAME-1 NODE-NAME-2 ...)
304 : : :
305 (INFO-FILE-1 NODE-NAME-1 NODE-NAME-2 ...))
306
307An example entry for e.g. C would be:
308
309\((\"/local/share/gnu/info/libc\" \"Function Index\" \"Type Index\"
310 \"Variable Index\"))
311
312The files and nodes will be searched/cached in the order specified.
313This variable is usually set by the `word-help-switch-help-file'
314function, which utilizes the `word-help-mode-alist'.")
315(make-variable-buffer-local 'word-help-info-files)
316
317(defvar word-help-keyword-regexps nil
318 "Regexps for finding keywords in the current mode.
319
320This is constructed as a list of the following form:
321
322\((REGEXP SUBMATCH-LOOKUP SUBMATCH-CURSOR)
323 (REGEXP SUBMATCH-LOOKUP SUBMATCH-CURSOR)
324 : : :
325 (REGEXP SUBMATCH-LOOKUP SUBMATCH-CURSOR))
326
327The regexps will be searched in order for a match which the cursor is
328within.
329
330submatch-lookup is the submatch number which will be looked for in the
331index. May be omitted; defaults to 0 (e.g. the entire pattern). This is
332useful in for instance configure lookup; each command is there prefixed
333with 'AC_', which must be ignored when doing a lookup. Example regexp
334entry for this:
335
336\(\"AC_\\\\([A-Za-z0-9]+\\\\)\" 1)
337
338submatch-cursor is the part of the match which the cursor must be within.
339May be omitted; defaults to 0 (e.g. the entire pattern).")
340(make-variable-buffer-local 'word-help-keyword-regexps)
341(set-default 'word-help-keyword-regexps '(("[A-Za-z_][A-Za-z_0-9]*")))
342
343(defvar word-help-index-mapper nil
344 "Regexps to use for massaging index-entries into keywords.
345This variable should contain a list of regexps with sub-expressions,
346where we will only look for the sub-expression in the user text.
347
348The regexp list should be formatted as:
349
350 ((REGEXP SUBEXP) (REGEXP SUBEXP) ... )
351
352If the index entry does not match any of the regexps, it will be ignored.
353
354Example:
355
356Perl has index entries of the following form:
357
358* abs VALUE: perlfunc.
359* accept NEWSOCKET,GENERICSOCKET: perlfunc.
360* alarm SECONDS: perlfunc.
361* atan2 Y,X: perlfunc.
362* bind SOCKET,NAME: perlfunc.
363 : : :
364
365We will thus try to extract the first word in the index entry -
366\"abs\" from \"abs VALUE\", etc. This is done by the following entry:
367
e8dd2298
RS
368\((\"^\\\\([^ \\t\\n]+\\\\)\" 1))
369
370This value is btw. the default one, and works with most Texinfo files")
ec3fac5e 371(make-variable-buffer-local 'word-help-index-mapper)
e8dd2298
RS
372(set-default 'word-help-index-mapper '(("^\\([^ \t\n]+\\)" 1)))
373
374
375(defvar word-help-complete-list nil
376 "Regexps or function to use for completion of symbols.
377The list should have the following format:
378
379 ((REGEXP SUBMATCH TEXT-APPEND (RE-FILTER-1 REG-FILTER-2 ...)
380 : : : : :
381 (REGEXP SUBMATCH TEXT-APPEND (RE-FILTER-1 REG-FILTER-2 ...))
382
383The two first entries are similar to `word-help-keyword-regexps',
384REGEXP is a regular expression which should match any relevant
385expression, and where SUBMATCH should be used for look up. By
386specifying non-nil REGEXP-FILTERs, we'll only include entries in the
387index which matches the regexp specified.
388
389If the contents of this variable is a symbol of a function, this
390function will be called instead. This is useful for modes providing
391a more intelligent function (like `lisp-complete-symbol' in Emacs Lisp mode).
392
393If you would like to use another function instead, you may.
394
395Non-nil TEXT-APPEND means that this text will be inserted after the
396completion, if we manage to do make a completion.")
397(make-variable-buffer-local 'word-help-complete-list)
398(set-default 'word-help-complete-list '(("[A-Za-z_][A-Za-z_0-9]*")))
399
400;;; Work variables
401
ec3fac5e
RS
402
403(defvar word-help-main-index nil
e8dd2298 404 "List of all index entries.
ec3fac5e
RS
405
406See `word-help-process-indexes' for structure formatting.
407
408Minor note: This variable is a list if it is initialized, t if
409initializing failed and nil if uninitialized.")
410(make-variable-buffer-local 'word-help-main-index)
411
e8dd2298
RS
412(defvar word-help-complete-index nil
413 "List of regexps for completion, with matching index entries.
414Value is nil if uninitialized, t if initialized but not accessible,
415a list if we're feeling ok.")
416(make-variable-buffer-local 'word-help-complete-index)
417
ec3fac5e 418(defvar word-help-main-obarray nil
e8dd2298 419 "Global work variable for `word-help' system.
ec3fac5e
RS
420Do Not mess with this!")
421
422(defvar word-help-history nil
423 "History for `word-help' minibuffer queries.")
424(make-local-variable 'word-help-history)
425
426(defvar word-help-current-help-file nil
427 "Current help file active for this mode.")
428
429(defvar word-help-index-alist nil
430 "An assoc list mapping help files to info indexes.
431This means that `word-help-mode-index' can be init'ed faster.")
432
433(defvar word-help-help-mode nil
434 "Which mode the help system is bound to for the current mode.")
435(make-variable-buffer-local 'word-help-help-mode)
436
e8dd2298
RS
437;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
438;;;;;;;;;;;;;;;;;;;;;;;;;;; User Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
439;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ec3fac5e
RS
440
441;;; Debugging
442
443;;;###autoload
444(defun reset-word-help ()
445 "Clear all cached indexes in the `word-help' system.
446You should only need this when installing new info files, and/or
447adding more Texinfo files to the `word-help' system."
448 (interactive)
449 (setq word-help-index-alist nil
e8dd2298
RS
450 word-help-main-index nil
451 word-help-info-files nil
452 word-help-complete-index nil))
ec3fac5e
RS
453
454
455;;; Changing help file
456
457;;;###autoload
64d7731d 458(defun set-word-help-file ()
e8dd2298 459 "Change which set of Texinfo files used for word-help.
ec3fac5e
RS
460
461`word-help' maintains a list over which Texinfo files which are
462relevant for each programming language (`word-help-mode-alist'). It
463usually selects the correct one, based upon the value of `mode-name'.
464If this guess is incorrect, you may also use this function manually to
465instruct future `word-help' calls which Texinfo files to use."
466 (interactive)
e8dd2298
RS
467 (let (helpfile helpguess (completion-ignore-case t))
468;; Try to make a guess
ec3fac5e
RS
469 (setq helpguess (cond
470 (word-help-current-help-file)
471 ((word-help-guess-help-file))))
e8dd2298
RS
472;; Ask the user
473 (setq helpfile (completing-read
ec3fac5e
RS
474 (if helpguess
475 (format "Select help mode (default %s): " helpguess)
476 "Select help mode: ")
477 word-help-mode-alist
478 nil t nil nil))
ec3fac5e
RS
479 (if (equal "" helpfile)
480 (setq helpfile helpguess))
481 (if helpfile
e8dd2298 482 (word-help-switch-help-file helpfile))))
ec3fac5e
RS
483
484;;; Main user interface
485
486;;;###autoload
487(defun word-help ()
488 "Find documentation on the keyword under the cursor.
489The determination of which language the keyword belongs to, is based upon
490The relevant info file is selected by matching `mode-name' (the major
491mode) against the assoc list `word-help-mode-alist'.
492
493If this is not possible, `set-help-file' will be invoked for selecting
494the relevant info file. `set-help-file' may also be invoked
495interactively by the user.
496
497If the keyword you are looking at is not available in any index, no
498default suggestion will be presented. "
499 (interactive)
e8dd2298
RS
500 (let (myguess guess index-info
501 (completion-ignore-case word-help-ignore-case))
ec3fac5e 502;; Set necessary variables for later lookup
e8dd2298 503 (word-help-find-help-file)
ec3fac5e
RS
504;; Have we previously cached datas?
505 (word-help-process-indexes)
506 (if
507 (atom word-help-main-index)
508 (message "No help file available for this mode.")
509;; First make a guess at what the user is looking for
510 (setq myguess (word-help-guess
511 (point)
512 (cond
513 ((not (atom word-help-main-index))
514 (car word-help-main-index)))
515 word-help-keyword-regexps))
516;; Ask the user himself
ec3fac5e
RS
517 (setq guess (completing-read
518 ; Format string
519 (if myguess
520 (format "Look up keyword (default %s): " myguess)
521 "Look up keyword: ")
522 ; Collection
523 (car word-help-main-index)
524 nil t nil 'word-help-history))
ec3fac5e
RS
525 (if (equal guess "")
526 (setq guess myguess))
527;; If we've got anything meaningful to lookup, do so
528 (if (not guess)
529 (message "Help aborted.")
530 (setq index-info (word-help-find-index-node
531 guess
532 word-help-main-index))
533 (if (not index-info)
534 (message "Oops, I could not find \"%s\" anyway! Bug?" guess)
e8dd2298
RS
535 (word-help-goto-index-node (nconc index-info (list guess))))))))
536
537;;;###autoload
538(defun word-help-complete ()
539 "Perform completion on the symbol preceding the point.
540The determination of which language the keyword belongs to, is based upon
541The relevant info file is selected by matching `mode-name' (the major
542mode) against the assoc list `word-help-mode-alist'.
543
544If this is not possible, `set-help-file' will be invoked for selecting
545the relevant info file. `set-help-file' may also be invoked
546interactively by the user.
547
548The keywords are extracted from the index of the info file defined for
549this mode, by using the `word-help-complete-list' variable."
550 (interactive)
551 (word-help-make-complete)
552 (cond
553 ((not word-help-complete-index)
554 (message "No completion available for this mode."))
555 ((symbolp word-help-complete-index)
556 (call-interactively word-help-complete-index))
557 ((listp word-help-complete-index)
558 (let ((all-match (word-help-guess-all (point)
559 word-help-complete-index t))
560 (completion-ignore-case word-help-ignore-case)
561 (c-list word-help-complete-index)
562 c-entry word-match completion completed)
563;; Loop over and try to find a match
564 (while (and all-match (not completed))
565 (setq word-match (car all-match)
566 c-entry (car c-list)
567 c-list (cdr c-list)
568 all-match (cdr all-match))
569;; Check whether the current pattern matched
570 (if word-match
571 (let ((close (nth 3 c-entry))
572 (words (nth 4 c-entry)))
573;; Find the maximum completion for this word
574; (print word-match)
575; (print c-entry)
576; (print close)
577 (setq completion (try-completion word-match words))
578;; Was the match exact
579 (cond ((eq completion t)
580 (and close
581 (not (looking-at (regexp-quote close)))
582 (insert close))
583 (setq completed t))
584;; Silently ignore non-matches
585 ((not completion))
586;; May we complete more unambiguously
587 ((not (string-equal completion word-match))
588 (delete-region (- (point) (length word-match))
589 (point))
590 (insert completion)
591 (if (eq t (try-completion completion words))
592 (progn
593 (and close
594 (not (looking-at (regexp-quote close)))
595 (insert close))))
596 (setq completed t))
597 (t
598 (message "Making completion list...")
599 (let ((list (all-completions word-match words nil)))
600 (setq completed list)
601 (with-output-to-temp-buffer "*Completions*"
602 (display-completion-list list)))
603 (message "Making completion list...done"))))))
604 (if (not completed) (message "No match."))))
605 (t (message "No completion available for this mode."))))
606
607;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
608;;;;;;;;;;;;;;;;;;;;;;;;;;; Index mapping ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
609;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ec3fac5e 610
ec3fac5e
RS
611
612(defun word-help-map-index-entries (str re-list)
e8dd2298
RS
613 "Transform an Info index entry into a programming keyword.
614Uses this by mapping the entries through `word-help-index-mapper'."
ec3fac5e
RS
615 (let ((regexp (car (car re-list)))
616 (subexp (car (cdr (car re-list))))
617 (next (cdr re-list)))
618 (cond
619 ((string-match regexp str)
620 (substring str (match-beginning subexp) (match-end subexp)))
621 (next
622 (word-help-map-index-entries str next)))))
623
e8dd2298
RS
624;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
625;;;;;;;;;;;;;;;;;;;;;;;;; Switch mode files ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
626;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ec3fac5e
RS
627
628;;; Mode lookup
629
630(defun word-help-guess-help-file ()
631 "Guesses a relevant help file based on mode name.
632Returns nil if no guess could be made. Uses `word-help-mode-alist'."
633 (let (guess)
634 (cond
635 ((setq guess (assoc mode-name word-help-mode-alist))
636 (car guess)))))
637
638
639(defun word-help-switch-help-file (helpfile)
640 "Changes the help-file to the mode name given.
641Uses `word-help-mode-alist'."
642 (if helpfile
643 (let (helpdesc)
644 (if (not (setq helpdesc (assoc helpfile word-help-mode-alist)))
645 (message "No help defined for \"%s\"." helpfile)
646 (if (stringp (cdr helpdesc))
647 (word-help-switch-help-file (cdr helpdesc))
648 (word-help-make-default-map
649 helpdesc
650 (list 'word-help-help-mode
651 'word-help-info-files
652 'word-help-keyword-regexps
653 'word-help-ignore-case
e8dd2298
RS
654 'word-help-index-mapper
655 'word-help-complete-list))))
656 (setq word-help-main-index nil
657 word-help-complete-index nil))))
ec3fac5e 658
e8dd2298
RS
659;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
660;;;;;;;;;;;;;;;;;;;;;;;;;; Index collection ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
661;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ec3fac5e 662
ec3fac5e
RS
663
664(defun word-help-extract-index (file-name index-list index-map ignore-case)
665 "Extract index from filename and the first node name in index list.
666`file-name' is the name of the info file, while `index-list' is a list
667of node-names to search."
e8dd2298 668 (let (cmd1 cmdlow nodename ob-array next (case-fold-search word-help-ignore-case))
ec3fac5e
RS
669 (setq nodename (car index-list))
670 (setq ob-array (make-vector 211 0))
671 (message "Processing \"%s\" in %s..." nodename file-name)
672 (save-window-excursion
673 (Info-goto-node (concat "(" file-name ")" nodename))
674 (end-of-buffer)
675 (while (re-search-backward "\\* \\([^\n:]+\\):" nil t)
676 (setq cmd1 (buffer-substring (match-beginning 1) (match-end 1)))
677 (setq cmdlow (if ignore-case (downcase cmd1) cmd1))
678 (if index-map
679 (setq cmdlow (word-help-map-index-entries cmdlow
680 index-map)))
681;; We have to do this workaround to support case-insensitive matching
682 (cond
683 (cmdlow
684 (put (intern cmdlow ob-array) 'word-help-real-name cmd1)
685 (intern cmdlow word-help-main-obarray)))))
686 (setq next (cond
687 ((cdr index-list)
688 (word-help-extract-index file-name (cdr index-list)
689 index-map ignore-case))))
690 (nconc (list (list nodename ob-array)) next)))
691
692
693(defun word-help-collect-indexes (info-file)
694 "Process all the indexes in an info file.
695
696Uses `word-help-extract-index' on each node, and returns an entry
697suitable for merging into `word-help-process-indexes'. `info-file'
698is an entry of the form
699
700\(FILE-NAME INDEX-NAME-1 INDEX-NAME-2 ...)"
701 (let ((file (car info-file))
702 (nodes (cdr info-file)))
703 (nconc (list file) (word-help-extract-index file nodes
704 word-help-index-mapper
e8dd2298 705 word-help-ignore-case))))
ec3fac5e
RS
706
707(defun word-help-process-indexes ()
708 "Process all the entries in the global variable `word-help-info-files'.
709Returns a list formatted as follows:
710
711\(all-entries-ob
712 (file-name-1 (node-name-1 this-node-entries-ob)
713 (node-name-2 this-node-entries-ob)
714 : : :
715 (node-name-n this-node-entries-ob))
716 (file-name-2 (node-name-1 this-node-entries-ob)
717 (node-name-2 this-node-entries-ob)
718 : : :
719 (node-name-n this-node-entries-ob))
720 : : : : : : : : :
721 (file-name-n (node-name-1 this-node-entries-ob)
722 (node-name-2 this-node-entries-ob)
723 : : :
724 (node-name-n this-node-entries-ob)))
725
726The symbols in the obarrays may contain the additional property
727`word-help-real-name', which tells the *real* node to go to.
728
729Note that we use `word-help-index-alist' to speed up the process. Note
730that `word-help-switch-help-file' must have been called before this function.
731
732This structure is then later searched by `word-help-find-index-node'."
733 (let (index-words old-index)
734 (if (not word-help-main-index)
735 (cond
736 ((setq old-index
737 (assoc word-help-help-mode word-help-index-alist))
738 (setq word-help-main-index (nth 1 old-index)))
739 (word-help-info-files
740 (setq word-help-main-obarray (make-vector 307 0)
741 index-words (mapcar 'word-help-collect-indexes
742 word-help-info-files)
743 word-help-main-index
744 (append (list word-help-main-obarray) index-words))
745 (setq word-help-index-alist (cons (list word-help-help-mode
746 word-help-main-index)
747 word-help-index-alist)))
748 (t (setq word-help-main-index t))))))
749
e8dd2298
RS
750(defun word-help-find-help-file ()
751 "Tries to find and set a relevant help file for the current mode."
752 (let (helpguess)
753 (if (not word-help-info-files)
754 (if (setq helpguess (word-help-guess-help-file))
755 (word-help-switch-help-file helpguess)
756 (set-help-file)))))
ec3fac5e 757
ec3fac5e 758
e8dd2298
RS
759;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
760;;;;;;;;;;;;;;;;;;;;;;;;;;; Keyword guess ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
761;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
762
763(defun word-help-guess-all (cur-point re-list
764 &optional copy-to-point)
765 "Guesses *all* keywords the user possibly may be looking at.
766Returns a list of all possible keywords. "
767 (let ((regexp (car (car re-list)))
768 (submatch (cond ((nth 1 (car re-list))) (0)))
769 (cursmatch (cond ((nth 2 (car re-list))) (0)))
770 (guess nil)
771 (next-guess nil)
772 (case-fold-search word-help-ignore-case)
773 (end-point nil))
ec3fac5e
RS
774 (save-excursion
775 (end-of-line)
ec3fac5e 776 (setq end-point (point))
e8dd2298 777 ;; Start at the beginning
ec3fac5e 778 (beginning-of-line)
ec3fac5e 779 (while (and (not guess) (re-search-forward regexp end-point t))
e8dd2298 780 ;; Look whether the cursor is within the match
ec3fac5e 781 (if (and (<= (match-beginning cursmatch) cur-point)
e8dd2298
RS
782 (>= (match-end cursmatch) cur-point))
783 (if (or (not copy-to-point) (<= cur-point (match-end submatch)))
784 (setq guess (buffer-substring (match-beginning submatch)
785 (if copy-to-point
786 cur-point
787 (match-end submatch)))))))
788 ;; If we found anything, return it and call ourselves again
789 (if (cdr re-list)
790 (setq next-guess (word-help-guess-all cur-point (cdr re-list)
791 copy-to-point))))
792 (cons guess next-guess)))
793
794(defun word-help-guess-match (all-match cmd-array)
795 (let ((sym (car all-match)))
796 (cond
797 ((and sym (intern-soft (if word-help-ignore-case
798 (downcase sym)
799 sym) cmd-array)
800 sym))
801 ((cdr all-match)
802 (word-help-guess-match (cdr all-match) cmd-array)))))
803
804
805(defun word-help-guess (cur-point cmd-array re-list)
806 "Guesses what keyword the user is looking at, and returns that.
807CUR-POINT should be the current value of `point', CMD-ARRAY an obarray
808of all the keywords which are defined for the current mode, and
809RE-LIST a list of regexps use for the hunt. See also
810`word-help-keyword-regexps'."
811 (let ((all-matches (word-help-guess-all cur-point re-list)))
812; (print all-matches)
813 (word-help-guess-match all-matches cmd-array)))
814
815;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
816;;;;;;;;;;;;;;;;;;;;;;; Show node for keyword ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
817;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ec3fac5e
RS
818
819;;; Find an index entry
820
821(defun word-help-find-index-node (node index-reg)
822 "Finds the node named `node' in the index-register `index-reg'.
823`index-reg' has the format as returned (and documented) by the
824`word-help-process-indexes' call. In most cases, this will be equal to
825`word-help-main-index'.
826
827Returns a list with format
828 (file-name index-node-name index-entry)
829which contains the file and index where the entry can be found.
830Returns nil if the entry can't be found."
831 (let (file-info node-name)
832 (setq node-name (cond (word-help-ignore-case (downcase node)) (node)))
833 (if (intern-soft node-name (car index-reg))
834 (setq file-info (word-help-index-search-file node-name
835 (cdr index-reg))))
e8dd2298 836 file-info))
ec3fac5e
RS
837
838(defun word-help-index-search-file (entry file-data)
839 "Searches a cached file for the index-entry `entry'."
840 (let (this-file next-files file-name node node-infos)
841 (setq this-file (car file-data)
842 next-files (cdr file-data)
843 file-name (car this-file)
844 node-infos (cdr this-file)
845 node (word-help-index-search-nodes entry node-infos))
846 (cond
847 (node
848 (cons file-name node))
e8dd2298 849 (next-files (word-help-index-search-file entry next-files)))))
ec3fac5e
RS
850
851(defun word-help-index-search-nodes (entry node-info)
852 "Searches a cached list of nodes for the entry `entry'."
853 (let (this-node next-nodes node-name node-ob node-sym)
854 (setq this-node (car node-info)
855 next-nodes (cdr node-info)
856 node-name (car this-node)
857 node-ob (car (cdr this-node))
858 node-sym (intern-soft entry node-ob))
859 (cond
860 (node-sym
861 (list node-name (get node-sym 'word-help-real-name)))
862 (next-nodes (word-help-index-search-nodes entry next-nodes)))))
863
864;;; Switch to a node in an index
865
866(defun word-help-goto-index-node (index-info)
867 "Jumps to an index node.
868`index-info' should be a list with the following format:
869
e8dd2298 870\(FILE-NAME INDEX-NODE-NAME INDEX-ENTRY KEYWORD)"
ec3fac5e
RS
871
872 (let* ((file-name (car index-info))
873 (node-name (nth 1 index-info))
874 (entry-name (nth 2 index-info))
e8dd2298
RS
875 (kw-name (nth 3 index-info))
876 (buffer (current-buffer)))
ec3fac5e
RS
877 (if word-help-split-window
878 (pop-to-buffer nil))
879 (Info-goto-node (concat "(" file-name ")" node-name))
880 (Info-menu entry-name)
881;; Do magic keyword search
e8dd2298
RS
882 (if word-help-magic-index
883 (let (end-point regs this-re found entry-re)
884 (setq entry-re (regexp-quote kw-name)
885 regs (list (concat
886 (if (string-match "^[A-Za-z]" entry-name)
887 "\\<" "")
888 entry-re
889 (if (string-match "[A-Za-z]$" entry-name)
890 "\\>" ""))
891 (concat "[`\"\(]" entry-re)
892 (concat "^" entry-re
893 (if (string-match "[A-Za-z]$" entry-name)
894 "\\>" ""))))
895 (end-of-line)
896 (setq end-point (point))
897 (beginning-of-line)
898 (if (not (re-search-forward (car regs) end-point t))
899 (while (and (not found) (car regs))
900 (setq this-re (car regs)
901 regs (cdr regs)
902 found (re-search-forward this-re nil t))))
903 (recenter 0)))
ec3fac5e
RS
904 (if word-help-split-window
905 (pop-to-buffer buffer))))
906
e8dd2298
RS
907
908;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
909;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Completion ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
910;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
911
912
913
914(defun word-help-extract-matches (from-ob dest-ob re-list)
915 "Takes atoms from from-ob, and puts them in dest-ob if they match re-list."
916 (let ((regexp (car (car re-list))))
917 (mapatoms (lambda (x)
918 (if (or (not regexp) (string-match regexp (symbol-name x)))
919 (intern (symbol-name x) dest-ob)))
920 from-ob)
921 (if (cdr re-list)
922 (word-help-extract-matches from-ob dest-ob (cdr re-list))))
923 dest-ob)
924
925(defun word-help-make-complete ()
926 "Generates the `word-help-complete-index'."
927 (if word-help-complete-index
928 nil
929 (word-help-find-help-file)
930 (cond
931 ((symbolp word-help-complete-list)
932 (setq word-help-complete-index word-help-complete-list))
933 (t
934 (word-help-process-indexes)
935 (if (not (atom word-help-main-index))
936 (let ((from-ob (car word-help-main-index)))
937 (message "Processing keywords...")
938 (setq word-help-complete-index
939 (mapcar
940 (lambda (cmpl)
941 (let
942 ((regexp (car cmpl))
943 (subm (cond ((nth 1 cmpl)) (0)))
944 (app (cond ((nth 2 cmpl)) ("")))
945 (re-list (cond ((nth 3 cmpl)) ('((".")))))
946 (obarr (make-vector 47 0)))
947 (list regexp subm subm app
948 (word-help-extract-matches from-ob obarr
949 re-list))))
950 word-help-complete-list))))))))
951
952;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
953;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Misc. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
954;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
955
956
957;;; Default mapping
958
959(defun word-help-make-default-map (list vars)
960 "Makes a default mapping for `vars', which must be listed in order.
961vars is a list of quoted symbols. If the nth entry in the list is
962non-nil, the nth variable will be given this value. If nil, the var
963will be given the global default value."
964 (set (car vars) (cond ((car list)) ((default-value (car vars)))))
965 (if (cdr vars)
966 (word-help-make-default-map (cdr list) (cdr vars))))
967
ec3fac5e
RS
968(provide 'word-help)
969
970;;; word-help.el ends here