(add-log-current-defun): Check major-mode for `cperl-mode' as well.
[bpt/emacs.git] / lisp / info-look.el
CommitLineData
5a79736d
RS
1;;; info-look.el --- major-mode-sensitive Info index lookup facility.
2;; An older version of this was known as libc.el.
3
e35ccb9e 4;; Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
5a79736d 5
3b361901 6;; Author: Ralph Schleicher <rs@nunatak.allgaeu.org>
5a79736d
RS
7;; Keywords: help languages
8
9;; This file is part of GNU Emacs.
10
11;; GNU Emacs is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
13;; the Free Software Foundation; either version 2, or (at your option)
14;; any later version.
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
22;; along with GNU Emacs; see the file COPYING. If not, write to the
23;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24;; Boston, MA 02111-1307, USA.
25
26;;; Code:
27
28(require 'info)
d2c2b883
RS
29
30(defgroup info-lookup nil
31 "Major mode sensitive help agent."
32 :group 'help :group 'languages)
5a79736d
RS
33
34(defvar info-lookup-mode nil
d2c2b883
RS
35 "Symbol of the current buffer's help mode.
36Help is provided according to the buffer's major mode if value is nil.
5a79736d
RS
37Automatically becomes buffer local when set in any fashion.")
38(make-variable-buffer-local 'info-lookup-mode)
39
d2c2b883
RS
40(defcustom info-lookup-other-window-flag t
41 "Non-nil means pop up the Info buffer in another window."
42 :group 'info-lookup :type 'boolean)
5a79736d 43
d2c2b883
RS
44(defcustom info-lookup-highlight-face 'highlight
45 "Face for highlighting looked up help items.
46Setting this variable to nil disables highlighting."
47 :group 'info-lookup :type 'face)
5a79736d
RS
48
49(defvar info-lookup-highlight-overlay nil
50 "Overlay object used for highlighting.")
51
9d37318d
KH
52(defcustom info-lookup-file-name-alist
53 '(("\\`configure\\.in\\'" . autoconf-mode)
54 ("\\`aclocal\\.m4\\'" . autoconf-mode)
55 ("\\`acsite\\.m4\\'" . autoconf-mode)
56 ("\\`acinclude\\.m4\\'" . autoconf-mode))
57 "Alist of file names handled specially.
58List elements are cons cells of the form
59
60 (REGEXP . MODE)
61
62If a file name matches REGEXP, then use help mode MODE instead of the
63buffer's major mode."
64 :group 'info-lookup :type '(repeat (cons (string :tag "Regexp")
65 (symbol :tag "Mode"))))
66
5a79736d
RS
67(defvar info-lookup-history nil
68 "History of previous input lines.")
69
d2c2b883
RS
70(defvar info-lookup-alist nil
71 "Alist of known help topics.
5a79736d
RS
72Cons cells are of the form
73
d2c2b883 74 (HELP-TOPIC . HELP-DATA)
5a79736d
RS
75
76HELP-TOPIC is the symbol of a help topic.
d2c2b883 77HELP-DATA is a HELP-TOPIC's public data set.
5a79736d
RS
78 Value is an alist with elements of the form
79
80 (HELP-MODE REGEXP IGNORE-CASE DOC-SPEC PARSE-RULE OTHER-MODES)
81
82HELP-MODE is a mode's symbol.
83REGEXP is a regular expression matching those help items whose
84 documentation can be looked up via DOC-SPEC.
85IGNORE-CASE is non-nil if help items are case insensitive.
86DOC-SPEC is a list of documentation specifications of the form
87
88 (INFO-NODE TRANS-FUNC PREFIX SUFFIX)
89
90INFO-NODE is the name (including file name part) of an Info index.
91TRANS-FUNC is a function translating index entries into help items;
92 nil means add only those index entries matching REGEXP, a string
93 means prepend string to the first word of all index entries.
94PREFIX and SUFFIX are parts of a regular expression. If one of
95 them is non-nil then search the help item's Info node for the
96 first occurrence of the regular expression `PREFIX ITEM SUFFIX'.
97 ITEM will be highlighted with `info-lookup-highlight-face' if this
98 variable is not nil.
99PARSE-RULE is either the symbol name of a function or a regular
100 expression for guessing the default help item at point. Fuzzy
101 regular expressions like \"[_a-zA-Z0-9]+\" do a better job if
102 there are no clear delimiters; do not try to write too complex
103 expressions. PARSE-RULE defaults to REGEXP.
104OTHER-MODES is a list of cross references to other help modes.")
105
106(defsubst info-lookup->topic-value (topic)
d2c2b883 107 (cdr (assoc topic info-lookup-alist)))
5a79736d
RS
108
109(defsubst info-lookup->mode-value (topic mode)
110 (assoc mode (info-lookup->topic-value topic)))
111
112(defsubst info-lookup->regexp (topic mode)
113 (nth 1 (info-lookup->mode-value topic mode)))
114
115(defsubst info-lookup->ignore-case (topic mode)
116 (nth 2 (info-lookup->mode-value topic mode)))
117
118(defsubst info-lookup->doc-spec (topic mode)
119 (nth 3 (info-lookup->mode-value topic mode)))
120
121(defsubst info-lookup->parse-rule (topic mode)
122 (nth 4 (info-lookup->mode-value topic mode)))
123
124(defsubst info-lookup->other-modes (topic mode)
125 (nth 5 (info-lookup->mode-value topic mode)))
126
d2c2b883
RS
127(eval-and-compile
128 (mapcar (lambda (keyword)
129 (or (boundp keyword)
130 (set keyword keyword)))
131 '(:topic :mode :regexp :ignore-case
132 :doc-spec :parse-rule :other-modes)))
133
134(defun info-lookup-add-help (&rest arg)
135 "Add or update a help specification.
136Function arguments are one or more options of the form
137
138 KEYWORD ARGUMENT
139
140KEYWORD is either `:topic', `:mode', `:regexp', `:ignore-case',
141 `:doc-spec', `:parse-rule', or `:other-modes'.
142ARGUMENT has a value as explained in the documentation of the
143 variable `info-lookup-alist'.
144
145If no topic or mode option has been specified, then the help topic defaults
146to `symbol', and the help mode defaults to the current major mode."
147 (apply 'info-lookup-add-help* nil arg))
148
149(defun info-lookup-maybe-add-help (&rest arg)
150 "Add a help specification iff no one is defined.
151See the documentation of the function `info-lookup-add-help'
152for more details."
153 (apply 'info-lookup-add-help* t arg))
154
155(defun info-lookup-add-help* (maybe &rest arg)
156 (let (topic mode regexp ignore-case doc-spec
157 parse-rule other-modes keyword value)
158 (setq topic 'symbol
159 mode major-mode
160 regexp "\\w+")
161 (while arg
162 (setq keyword (car arg))
163 (or (symbolp keyword)
164 (error "Junk in argument list \"%S\"" arg))
165 (setq arg (cdr arg))
166 (and (null arg)
167 (error "Keyword \"%S\" is missing an argument" keyword))
168 (setq value (car arg)
169 arg (cdr arg))
170 (cond ((eq keyword :topic)
171 (setq topic value))
172 ((eq keyword :mode)
173 (setq mode value))
174 ((eq keyword :regexp)
175 (setq regexp value))
176 ((eq keyword :ignore-case)
177 (setq ignore-case value))
178 ((eq keyword :doc-spec)
179 (setq doc-spec value))
180 ((eq keyword :parse-rule)
181 (setq parse-rule value))
182 ((eq keyword :other-modes)
183 (setq other-modes value))
184 (t
185 (error "Unknown keyword \"%S\"" keyword))))
186 (or (and maybe (info-lookup->mode-value topic mode))
187 (let* ((data (list regexp ignore-case doc-spec parse-rule other-modes))
188 (topic-cell (or (assoc topic info-lookup-alist)
189 (car (setq info-lookup-alist
190 (cons (cons topic nil)
191 info-lookup-alist)))))
192 (mode-cell (assoc mode topic-cell)))
193 (if (null mode-cell)
194 (setcdr topic-cell (cons (cons mode data) (cdr topic-cell)))
195 (setcdr mode-cell data))))
196 nil))
197
5a79736d
RS
198(defvar info-lookup-cache nil
199 "Cache storing data maintained automatically by the program.
200Value is an alist with cons cell of the form
201
202 (HELP-TOPIC . ((HELP-MODE INITIALIZED COMPLETIONS REFER-MODES) ...))
203
204HELP-TOPIC is the symbol of a help topic.
205HELP-MODE is a mode's symbol.
206INITIALIZED is nil if HELP-MODE is uninitialized, t if
207 HELP-MODE is initialized, and `0' means HELP-MODE is
208 initialized but void.
209COMPLETIONS is an alist of documented help items.
210REFER-MODES is a list of other help modes to use.")
211
212(defsubst info-lookup->cache (topic)
213 (or (assoc topic info-lookup-cache)
214 (car (setq info-lookup-cache
215 (cons (cons topic nil)
216 info-lookup-cache)))))
217
0c10ee28 218(defun info-lookup->topic-cache (topic)
5a79736d
RS
219 (cdr (info-lookup->cache topic)))
220
0c10ee28 221(defun info-lookup->mode-cache (topic mode)
5a79736d
RS
222 (assoc mode (info-lookup->topic-cache topic)))
223
0c10ee28 224(defun info-lookup->initialized (topic mode)
5a79736d
RS
225 (nth 1 (info-lookup->mode-cache topic mode)))
226
0c10ee28 227(defun info-lookup->completions (topic mode)
5a79736d
RS
228 (or (info-lookup->initialized topic mode)
229 (info-lookup-setup-mode topic mode))
230 (nth 2 (info-lookup->mode-cache topic mode)))
231
0c10ee28 232(defun info-lookup->refer-modes (topic mode)
5a79736d
RS
233 (or (info-lookup->initialized topic mode)
234 (info-lookup-setup-mode topic mode))
235 (nth 3 (info-lookup->mode-cache topic mode)))
236
0c10ee28 237(defun info-lookup->all-modes (topic mode)
5a79736d
RS
238 (cons mode (info-lookup->refer-modes topic mode)))
239
0c10ee28
RS
240(defun info-lookup-quick-all-modes (topic mode)
241 (cons mode (info-lookup->other-modes topic mode)))
242
5a79736d
RS
243;;;###autoload
244(defun info-lookup-reset ()
245 "Throw away all cached data.
246This command is useful if the user wants to start at the beginning without
247quitting Emacs, for example, after some Info documents were updated on the
248system."
249 (interactive)
250 (setq info-lookup-cache nil))
251
252;;;###autoload
253(defun info-lookup-symbol (symbol &optional mode)
3481a5c0
KH
254 "Display the definition of SYMBOL, as found in the relevant manual.
255When this command is called interactively, it reads SYMBOL from the minibuffer.
256In the minibuffer, use M-n to yank the default argument value
257into the minibuffer so you can edit it.
b108eac2
KH
258The default symbol is the one found at point.
259
260With prefix arg a query for the symbol help mode is offered."
5a79736d 261 (interactive
b108eac2 262 (info-lookup-interactive-arguments 'symbol current-prefix-arg))
5a79736d
RS
263 (info-lookup 'symbol symbol mode))
264
265;;;###autoload
266(defun info-lookup-file (file &optional mode)
267 "Display the documentation of a file.
3481a5c0
KH
268When this command is called interactively, it reads FILE from the minibuffer.
269In the minibuffer, use M-n to yank the default file name
270into the minibuffer so you can edit it.
b108eac2
KH
271The default file name is the one found at point.
272
273With prefix arg a query for the file help mode is offered."
5a79736d 274 (interactive
b108eac2 275 (info-lookup-interactive-arguments 'file current-prefix-arg))
5a79736d
RS
276 (info-lookup 'file file mode))
277
b108eac2
KH
278(defun info-lookup-interactive-arguments (topic &optional query)
279 "Read and return argument value (and help mode) for help topic TOPIC.
280If optional argument QUERY is non-nil, query for the help mode."
281 (let* ((mode (cond (query
282 (info-lookup-change-mode topic))
283 ((info-lookup->mode-value topic (info-lookup-select-mode))
284 info-lookup-mode)
285 ((info-lookup-change-mode topic))))
5a79736d
RS
286 (completions (info-lookup->completions topic mode))
287 (default (info-lookup-guess-default topic mode))
5a79736d
RS
288 (completion-ignore-case (info-lookup->ignore-case topic mode))
289 (enable-recursive-minibuffers t)
290 (value (completing-read
3481a5c0 291 (if default
5a79736d
RS
292 (format "Describe %s (default %s): " topic default)
293 (format "Describe %s: " topic))
3481a5c0 294 completions nil nil nil 'info-lookup-history default)))
5a79736d
RS
295 (list (if (equal value "") default value) mode)))
296
9d37318d
KH
297(defun info-lookup-select-mode ()
298 (when (and (not info-lookup-mode) (buffer-file-name))
299 (let ((file-name (file-name-nondirectory (buffer-file-name)))
300 (file-name-alist info-lookup-file-name-alist))
301 (while (and (not info-lookup-mode) file-name-alist)
302 (when (string-match (caar file-name-alist) file-name)
303 (setq info-lookup-mode (cdar file-name-alist)))
304 (setq file-name-alist (cdr file-name-alist)))))
305 (or info-lookup-mode (setq info-lookup-mode major-mode)))
306
5a79736d
RS
307(defun info-lookup-change-mode (topic)
308 (let* ((completions (mapcar (lambda (arg)
309 (cons (symbol-name (car arg)) (car arg)))
310 (info-lookup->topic-value topic)))
311 (mode (completing-read
312 (format "Use %s help mode: " topic)
313 completions nil t nil 'info-lookup-history)))
314 (or (setq mode (cdr (assoc mode completions)))
315 (error "No %s help available" topic))
316 (or (info-lookup->mode-value topic mode)
317 (error "No %s help available for `%s'" topic mode))
318 (setq info-lookup-mode mode)))
319
320(defun info-lookup (topic item mode)
321 "Display the documentation of a help item."
9d37318d 322 (or mode (setq mode (info-lookup-select-mode)))
5a79736d
RS
323 (or (info-lookup->mode-value topic mode)
324 (error "No %s help available for `%s'" topic mode))
325 (let ((entry (or (assoc (if (info-lookup->ignore-case topic mode)
326 (downcase item) item)
327 (info-lookup->completions topic mode))
328 (error "Not documented as a %s: %s" topic (or item ""))))
329 (modes (info-lookup->all-modes topic mode))
330 (window (selected-window))
1d010333 331 found doc-spec node prefix suffix doc-found)
b108eac2
KH
332 (if (or (not info-lookup-other-window-flag)
333 (eq (current-buffer) (get-buffer "*info*")))
5a79736d 334 (info)
f457975a
GM
335 (progn
336 (save-window-excursion (info))
337 ;; Determine whether or not the Info buffer is visible in
338 ;; another frame on the same display. If it is, simply raise
339 ;; that frame. Otherwise, display it in another window.
340 (let* ((window (get-buffer-window "*info*" t))
341 (info-frame (and window (window-frame window))))
342 (if (and info-frame
343 (display-multi-frame-p)
344 (memq info-frame (frames-on-display-list)))
345 (select-frame info-frame)
346 (switch-to-buffer-other-window "*info*")))))
5a79736d
RS
347 (while (and (not found) modes)
348 (setq doc-spec (info-lookup->doc-spec topic (car modes)))
349 (while (and (not found) doc-spec)
350 (setq node (nth 0 (car doc-spec))
351 prefix (nth 2 (car doc-spec))
352 suffix (nth 3 (car doc-spec)))
1d010333 353 (when (condition-case error-data
e35ccb9e 354 (progn
1d010333
RS
355 (Info-goto-node node)
356 (setq doc-found t))
e35ccb9e 357 (error
1d010333
RS
358 (message "Cannot access Info node %s" node)
359 (sit-for 1)
360 nil))
361 (condition-case nil
362 (progn
363 (Info-menu (or (cdr entry) item))
364 (setq found t)
365 (if (or prefix suffix)
366 (let ((case-fold-search
367 (info-lookup->ignore-case topic (car modes)))
368 (buffer-read-only nil))
369 (goto-char (point-min))
370 (re-search-forward
371 (concat prefix (regexp-quote item) suffix))
372 (goto-char (match-beginning 0))
141d2f67 373 (and (display-color-p) info-lookup-highlight-face
1d010333
RS
374 ;; Search again for ITEM so that the first
375 ;; occurence of ITEM will be highlighted.
376 (re-search-forward (regexp-quote item))
377 (let ((start (match-beginning 0))
378 (end (match-end 0)))
379 (if (overlayp info-lookup-highlight-overlay)
380 (move-overlay info-lookup-highlight-overlay
381 start end (current-buffer))
382 (setq info-lookup-highlight-overlay
383 (make-overlay start end))))
384 (overlay-put info-lookup-highlight-overlay
385 'face info-lookup-highlight-face)))))
386 (error nil)))
5a79736d
RS
387 (setq doc-spec (cdr doc-spec)))
388 (setq modes (cdr modes)))
1d010333
RS
389 (or doc-found
390 (error "Info documentation for lookup was not found"))
5a79736d
RS
391 ;; Don't leave the Info buffer if the help item couldn't be looked up.
392 (if (and info-lookup-other-window-flag found)
393 (select-window window))))
394
395(defun info-lookup-setup-mode (topic mode)
396 "Initialize the internal data structure."
397 (or (info-lookup->initialized topic mode)
398 (let (cell data (initialized 0) completions refer-modes)
399 (if (not (info-lookup->mode-value topic mode))
400 (message "No %s help available for `%s'" topic mode)
401 ;; Recursively setup cross references.
402 ;; But refer only to non-void modes.
403 (mapcar (lambda (arg)
404 (or (info-lookup->initialized topic arg)
405 (info-lookup-setup-mode topic arg))
406 (and (eq (info-lookup->initialized topic arg) t)
407 (setq refer-modes (cons arg refer-modes))))
408 (info-lookup->other-modes topic mode))
409 (setq refer-modes (nreverse refer-modes))
410 ;; Build the full completion alist.
411 (setq completions
e12fcc41
KH
412 (nconc (condition-case nil
413 (info-lookup-make-completions topic mode)
414 (error nil))
5a79736d
RS
415 (apply 'append
416 (mapcar (lambda (arg)
417 (info-lookup->completions topic arg))
418 refer-modes))))
419 (setq initialized t))
420 ;; Update `info-lookup-cache'.
421 (setq cell (info-lookup->mode-cache topic mode)
422 data (list initialized completions refer-modes))
423 (if (not cell)
424 (setcdr (info-lookup->cache topic)
425 (cons (cons mode data) (info-lookup->topic-cache topic)))
426 (setcdr cell data))
427 initialized)))
428
429(defun info-lookup-make-completions (topic mode)
430 "Create a unique alist from all index entries."
1eff0ba1
RS
431 (let ((doc-spec (info-lookup->doc-spec topic mode))
432 (regexp (concat "^\\(" (info-lookup->regexp topic mode)
433 "\\)\\([ \t].*\\)?$"))
1d010333 434 node trans entry item prefix result doc-found
1eff0ba1
RS
435 (buffer (get-buffer-create " temp-info-look")))
436 (with-current-buffer buffer
437 (Info-mode))
438 (while doc-spec
439 (setq node (nth 0 (car doc-spec))
440 trans (cond ((eq (nth 1 (car doc-spec)) nil)
441 (lambda (arg)
442 (if (string-match regexp arg)
443 (match-string 1 arg))))
444 ((stringp (nth 1 (car doc-spec)))
445 (setq prefix (nth 1 (car doc-spec)))
446 (lambda (arg)
447 (if (string-match "^\\([^: \t\n]+\\)" arg)
448 (concat prefix (match-string 1 arg)))))
449 (t (nth 1 (car doc-spec)))))
1d010333
RS
450 (with-current-buffer buffer
451 (message "Processing Info node `%s'..." node)
452 (when (condition-case error-data
e35ccb9e 453 (progn
1d010333
RS
454 (Info-goto-node node)
455 (setq doc-found t))
e35ccb9e 456 (error
1d010333
RS
457 (message "Cannot access Info node `%s'" node)
458 (sit-for 1)
459 nil))
460 (condition-case nil
461 (progn
462 (goto-char (point-min))
463 (and (search-forward "\n* Menu:" nil t)
464 (while (re-search-forward "\n\\* \\([^:\t\n]*\\):" nil t)
465 (setq entry (match-string 1)
466 item (funcall trans entry))
6480a693
DL
467 ;; `trans' can return nil if the regexp doesn't match.
468 (when (and item
469 ;; Sometimes there's more than one Menu:
e35ccb9e 470 (not (string= entry "Menu")))
6480a693
DL
471 (and (info-lookup->ignore-case topic mode)
472 (setq item (downcase item)))
473 (and (string-equal entry item)
474 (setq entry nil))
475 (and (or (assoc item result)
476 (setq result (cons (cons item entry)
477 result))))))))
1d010333 478 (error nil))))
1eff0ba1
RS
479 (message "Processing Info node `%s'...done" node)
480 (setq doc-spec (cdr doc-spec)))
1d010333
RS
481 (or doc-found
482 (error "Info documentation for lookup was not found"))
1eff0ba1 483 result))
5a79736d
RS
484
485(defun info-lookup-guess-default (topic mode)
ce288cb6
KH
486 "Return a guess for a symbol to look up, based on text around point.
487Try all related modes applicable to TOPIC and MODE.
488Return nil if there is nothing appropriate in the buffer near point."
5a79736d 489 (let ((modes (info-lookup->all-modes topic mode))
ce288cb6 490 guess)
5a79736d
RS
491 (while (and (not guess) modes)
492 (setq guess (info-lookup-guess-default* topic (car modes))
ce288cb6 493 modes (cdr modes)))
5a79736d 494 ;; Collapse whitespace characters.
ce288cb6
KH
495 (when guess
496 (let ((pos 0))
497 (while (string-match "[ \t\n]+" guess pos)
498 (setq pos (1+ (match-beginning 0)))
499 (setq guess (replace-match " " t t guess)))))
500 guess))
5a79736d
RS
501
502(defun info-lookup-guess-default* (topic mode)
503 (let ((case-fold-search (info-lookup->ignore-case topic mode))
504 (rule (or (info-lookup->parse-rule topic mode)
505 (info-lookup->regexp topic mode)))
506 (start (point)) end regexp subexp result)
ce288cb6
KH
507 (save-excursion
508 (if (symbolp rule)
509 (setq result (funcall rule))
510 (if (consp rule)
511 (setq regexp (car rule)
512 subexp (cdr rule))
513 (setq regexp rule
514 subexp 0))
e35ccb9e
DL
515 ;; If at start of symbol, don't go back to end of previous one.
516 (if (save-match-data
517 (looking-at "[ \t\n]"))
518 (skip-chars-backward " \t\n"))
519 (setq end (point))
ce288cb6
KH
520 (while (and (re-search-backward regexp nil t)
521 (looking-at regexp)
522 (>= (match-end 0) end))
523 (setq result (match-string subexp)))
524 (if (not result)
525 (progn
526 (goto-char start)
527 (skip-chars-forward " \t\n")
528 (and (looking-at regexp)
529 (setq result (match-string subexp)))))))
5a79736d
RS
530 result))
531
532(defun info-lookup-guess-c-symbol ()
533 "Get the C symbol at point."
534 (condition-case nil
535 (progn
ce288cb6 536 (skip-syntax-backward "w_")
5a79736d
RS
537 (let ((start (point)) prefix name)
538 ;; Test for a leading `struct', `union', or `enum' keyword
539 ;; but ignore names like `foo_struct'.
540 (setq prefix (and (< (skip-chars-backward " \t\n") 0)
541 (< (skip-chars-backward "_a-zA-Z0-9") 0)
542 (looking-at "\\(struct\\|union\\|enum\\)\\s ")
543 (concat (match-string 1) " ")))
544 (goto-char start)
545 (and (looking-at "[_a-zA-Z][_a-zA-Z0-9]*")
546 (setq name (match-string 0)))
547 ;; Caveat! Look forward if point is at `struct' etc.
548 (and (not prefix)
549 (or (string-equal name "struct")
550 (string-equal name "union")
551 (string-equal name "enum"))
552 (looking-at "[a-z]+\\s +\\([_a-zA-Z][_a-zA-Z0-9]*\\)")
553 (setq prefix (concat name " ")
554 name (match-string 1)))
555 (and (or prefix name)
556 (concat prefix name))))
557 (error nil)))
558
559;;;###autoload
560(defun info-complete-symbol (&optional mode)
561 "Perform completion on symbol preceding point."
82fb111c
RS
562 (interactive)
563 (info-complete 'symbol
564 (or mode
565 (if (info-lookup->mode-value
9d37318d
KH
566 'symbol (info-lookup-select-mode))
567 info-lookup-mode
82fb111c 568 (info-lookup-change-mode 'symbol)))))
5a79736d
RS
569
570;;;###autoload
571(defun info-complete-file (&optional mode)
572 "Perform completion on file preceding point."
a1fee1bc
KH
573 (interactive)
574 (info-complete 'file
575 (or mode
576 (if (info-lookup->mode-value
9d37318d
KH
577 'file (info-lookup-select-mode))
578 info-lookup-mode
a1fee1bc 579 (info-lookup-change-mode 'file)))))
5a79736d
RS
580
581(defun info-complete (topic mode)
582 "Try to complete a help item."
583 (barf-if-buffer-read-only)
9d37318d 584 (or mode (setq mode (info-lookup-select-mode)))
5a79736d
RS
585 (or (info-lookup->mode-value topic mode)
586 (error "No %s completion available for `%s'" topic mode))
0c10ee28
RS
587 (let ((modes (info-lookup-quick-all-modes topic mode))
588 (start (point))
589 try)
5a79736d
RS
590 (while (and (not try) modes)
591 (setq mode (car modes)
592 modes (cdr modes)
593 try (info-lookup-guess-default* topic mode))
594 (goto-char start))
595 (and (not try)
d2c2b883 596 (error "Found no %S to complete" topic))
0c10ee28
RS
597 (let ((completions (info-lookup->completions topic mode))
598 (completion-ignore-case (info-lookup->ignore-case topic mode))
599 completion)
600 (setq completion (try-completion try completions))
601 (cond ((not completion)
602 (ding)
603 (message "No match"))
604 ((stringp completion)
605 (or (assoc completion completions)
606 (setq completion (completing-read
607 (format "Complete %S: " topic)
608 completions nil t completion
609 info-lookup-history)))
e35ccb9e
DL
610 ;; Find the original symbol and zap it.
611 (end-of-line)
612 (while (and (search-backward try nil t)
613 (< start (point))))
614 (replace-match "")
0c10ee28
RS
615 (insert completion))
616 (t
617 (message "%s is complete"
618 (capitalize (prin1-to-string topic))))))))
d2c2b883
RS
619
620\f
d2c2b883
RS
621;;; Initialize some common modes.
622
623(info-lookup-maybe-add-help
624 :mode 'c-mode :topic 'symbol
625 :regexp "\\(struct \\|union \\|enum \\)?[_a-zA-Z][_a-zA-Z0-9]*"
626 :doc-spec '(("(libc)Function Index" nil
627 "^[ \t]+- \\(Function\\|Macro\\): .*\\<" "\\>")
628 ("(libc)Variable Index" nil
629 "^[ \t]+- \\(Variable\\|Macro\\): .*\\<" "\\>")
630 ("(libc)Type Index" nil
631 "^[ \t]+- Data Type: \\<" "\\>")
632 ("(termcap)Var Index" nil
633 "^[ \t]*`" "'"))
634 :parse-rule 'info-lookup-guess-c-symbol)
635
636(info-lookup-maybe-add-help
637 :mode 'c-mode :topic 'file
638 :regexp "[_a-zA-Z0-9./+-]+"
639 :doc-spec '(("(libc)File Index")))
640
641(info-lookup-maybe-add-help
642 :mode 'bison-mode
643 :regexp "[:;|]\\|%\\([%{}]\\|[_a-z]+\\)\\|YY[_A-Z]+\\|yy[_a-z]+"
644 :doc-spec '(("(bison)Index" nil
645 "`" "'"))
646 :parse-rule "[:;|]\\|%\\([%{}]\\|[_a-zA-Z][_a-zA-Z0-9]*\\)"
647 :other-modes '(c-mode))
648
649(info-lookup-maybe-add-help
650 :mode 'makefile-mode
651 :regexp "\\$[^({]\\|\\.[_A-Z]*\\|[_a-zA-Z][_a-zA-Z0-9-]*"
652 :doc-spec '(("(make)Name Index" nil
653 "^[ \t]*`" "'"))
654 :parse-rule "\\$[^({]\\|\\.[_A-Z]*\\|[_a-zA-Z0-9-]+")
655
656(info-lookup-maybe-add-help
657 :mode 'texinfo-mode
658 :regexp "@\\([a-zA-Z]+\\|[^a-zA-Z]\\)"
659 :doc-spec '(("(texinfo)Command and Variable Index"
660 ;; Ignore Emacs commands and prepend a `@'.
661 (lambda (item)
662 (if (string-match "^\\([a-zA-Z]+\\|[^a-zA-Z]\\)\\( .*\\)?$" item)
663 (concat "@" (match-string 1 item))))
664 "`" "'")))
665
666(info-lookup-maybe-add-help
667 :mode 'm4-mode
668 :regexp "[_a-zA-Z][_a-zA-Z0-9]*"
669 :doc-spec '(("(m4)Macro index"))
670 :parse-rule "[_a-zA-Z0-9]+")
671
672(info-lookup-maybe-add-help
673 :mode 'autoconf-mode
674 :regexp "A[CM]_[_A-Z0-9]+"
675 :doc-spec '(("(autoconf)Macro Index" "AC_"
676 "^[ \t]+- \\(Macro\\|Variable\\): .*\\<" "\\>")
677 ("(automake)Index" nil
678 "^[ \t]*`" "'"))
679 ;; Autoconf symbols are M4 macros. Thus use M4's parser.
680 :parse-rule 'ignore
681 :other-modes '(m4-mode))
682
683(info-lookup-maybe-add-help
684 :mode 'awk-mode
685 :regexp "[_a-zA-Z]+"
686 :doc-spec '(("(gawk)Index"
687 (lambda (item)
688 (let ((case-fold-search nil))
689 (cond
690 ;; `BEGIN' and `END'.
691 ((string-match "^\\([A-Z]+\\) special pattern\\b" item)
692 (match-string 1 item))
693 ;; `if', `while', `do', ...
694 ((string-match "^\\([a-z]+\\) statement\\b" item)
695 (if (not (string-equal (match-string 1 item) "control"))
696 (match-string 1 item)))
697 ;; `NR', `NF', ...
698 ((string-match "^[A-Z]+$" item)
699 item)
700 ;; Built-in functions (matches to many entries).
701 ((string-match "^[a-z]+$" item)
702 item))))
703 "`" "\\([ \t]*([^)]*)\\)?'")))
704
705(info-lookup-maybe-add-help
706 :mode 'perl-mode
707 :regexp "[$@%][^a-zA-Z]\\|\\$\\^[A-Z]\\|[$@%]?[a-zA-Z][_a-zA-Z0-9]*"
708 :doc-spec '(("(perl5)Function Index"
709 (lambda (item)
710 (if (string-match "^\\([a-zA-Z0-9]+\\)" item)
711 (match-string 1 item)))
712 "^" "\\b")
713 ("(perl5)Variable Index"
714 (lambda (item)
715 ;; Work around bad formatted array variables.
716 (let ((sym (cond ((or (string-match "^\\$\\(.\\|@@\\)$" item)
717 (string-match "^\\$\\^[A-Z]$" item))
718 item)
719 ((string-match
720 "^\\([$%@]\\|@@\\)?[_a-zA-Z0-9]+" item)
721 (match-string 0 item))
722 (t ""))))
723 (if (string-match "@@" sym)
724 (setq sym (concat (substring sym 0 (match-beginning 0))
725 (substring sym (1- (match-end 0))))))
726 (if (string-equal sym "") nil sym)))
727 "^" "\\b"))
728 :parse-rule "[$@%]?\\([_a-zA-Z0-9]+\\|[^a-zA-Z]\\)")
729
730(info-lookup-maybe-add-help
731 :mode 'latex-mode
732 :regexp "\\\\\\([a-zA-Z]+\\|[^a-zA-Z]\\)"
e12fcc41 733 :doc-spec '(("(latex)Command Index" nil
d2c2b883
RS
734 "`" "\\({[^}]*}\\)?'")))
735
736(info-lookup-maybe-add-help
737 :mode 'emacs-lisp-mode
738 :regexp "[^()' \t\n]+"
739 :doc-spec '(("(emacs)Command Index")
a1fee1bc
KH
740 ("(emacs)Variable Index")
741 ("(elisp)Index"
742 (lambda (item)
743 (let ((sym (intern-soft item)))
744 (cond ((null sym)
745 (if (string-equal item "nil") item))
746 ((or (boundp sym) (fboundp sym))
747 item))))
748 "^[ \t]+- [^:]+:[ \t]*" "\\b")))
d2c2b883
RS
749
750(info-lookup-maybe-add-help
751 :mode 'lisp-interaction-mode
752 :regexp "[^()' \t\n]+"
753 :parse-rule 'ignore
754 :other-modes '(emacs-lisp-mode))
755
0c10ee28
RS
756(info-lookup-maybe-add-help
757 :mode 'lisp-mode
758 :regexp "[^()' \t\n]+"
759 :parse-rule 'ignore
760 :other-modes '(emacs-lisp-mode))
761
9d37318d
KH
762(info-lookup-maybe-add-help
763 :mode 'scheme-mode
764 :regexp "[^()' \t\n]+"
765 :ignore-case t
6480a693 766 ;; Aubrey Jaffer's rendition from <URL:ftp://ftp-swiss.ai.mit.edu/pub/scm>
9d37318d
KH
767 :doc-spec '(("(r5rs)Index" nil
768 "^[ \t]+- [^:]+:[ \t]*" "\\b")))
769
054e5c20
SE
770(info-lookup-maybe-add-help
771 :mode 'octave-mode
772 :regexp "[_a-zA-Z0-9]+"
57f3e9c9
SE
773 :doc-spec '(("(octave)Function Index" nil
774 "^ - [^:]+:[ ]+\\(\\[[^=]*=[ ]+\\)?" nil)
054e5c20
SE
775 ("(octave)Variable Index" nil "^ - [^:]+:[ ]+" nil)
776 ;; Catch lines of the form "xyz statement"
e35ccb9e 777 ("(octave)Concept Index"
054e5c20
SE
778 (lambda (item)
779 (cond
780 ((string-match "^\\([A-Z]+\\) statement\\b" item)
781 (match-string 1 item))
782 (t nil)))
783 nil; "^ - [^:]+:[ ]+" don't think this prefix is useful here.
784 nil)))
d2c2b883 785\f
5a79736d
RS
786(provide 'info-look)
787
788;;; info-look.el ends here