+ (error "Found no %S to complete" topic))
+ (let ((completions (info-lookup->completions topic mode))
+ (completion-ignore-case (info-lookup->ignore-case topic mode))
+ completion)
+ (setq completion (try-completion try completions))
+ (cond ((not completion)
+ (ding)
+ (message "No match"))
+ ((stringp completion)
+ (or (assoc completion completions)
+ (setq completion (completing-read
+ (format "Complete %S: " topic)
+ completions nil t completion
+ info-lookup-history)))
+ ;; Find the original symbol and zap it.
+ (end-of-line)
+ (while (and (search-backward try nil t)
+ (< start (point))))
+ (replace-match "")
+ (insert completion))
+ (t
+ (message "%s is complete"
+ (capitalize (prin1-to-string topic))))))))
+
+\f
+;;; Initialize some common modes.
+
+(info-lookup-maybe-add-help
+ :mode 'c-mode :topic 'symbol
+ :regexp "\\(struct \\|union \\|enum \\)?[_a-zA-Z][_a-zA-Z0-9]*"
+ :doc-spec '(("(libc)Function Index" nil
+ "^[ \t]+-+ \\(Function\\|Macro\\): .*\\<" "\\>")
+ ;; prefix/suffix has to match things like
+ ;; " -- Macro: int F_DUPFD"
+ ;; " -- Variable: char * tzname [2]"
+ ;; "`DBL_MAX'" (texinfo @table)
+ ;; suffix "\\>" is not used because that sends DBL_MAX to
+ ;; DBL_MAX_EXP ("_" is a non-word char)
+ ("(libc)Variable Index" nil
+ "^\\([ \t]+-+ \\(Variable\\|Macro\\): .*\\<\\|`\\)"
+ "\\( \\|'?$\\)")
+ ("(libc)Type Index" nil
+ "^[ \t]+-+ Data Type: \\<" "\\>")
+ ("(termcap)Var Index" nil
+ "^[ \t]*`" "'"))
+ :parse-rule 'info-lookup-guess-c-symbol)
+
+(info-lookup-maybe-add-help
+ :mode 'c-mode :topic 'file
+ :regexp "[_a-zA-Z0-9./+-]+"
+ :doc-spec '(("(libc)File Index")))
+
+(info-lookup-maybe-add-help
+ :mode 'bison-mode
+ :regexp "[:;|]\\|%\\([%{}]\\|[_a-z]+\\)\\|YY[_A-Z]+\\|yy[_a-z]+"
+ :doc-spec '(("(bison)Index" nil
+ "`" "'"))
+ :parse-rule "[:;|]\\|%\\([%{}]\\|[_a-zA-Z][_a-zA-Z0-9]*\\)"
+ :other-modes '(c-mode))
+
+(info-lookup-maybe-add-help
+ :mode 'makefile-mode
+ :regexp "\\$[^({]\\|\\.[_A-Z]*\\|[_a-zA-Z][_a-zA-Z0-9-]*"
+ :doc-spec '(("(make)Name Index" nil
+ "^[ \t]*`" "'")
+ ("(automake)Macro and Variable Index" nil
+ "^[ \t]*`" "'"))
+ :parse-rule "\\$[^({]\\|\\.[_A-Z]*\\|[_a-zA-Z0-9-]+"
+ :other-modes '(automake-mode))
+
+(info-lookup-maybe-add-help
+ :mode 'texinfo-mode
+ :regexp "@\\([a-zA-Z]+\\|[^a-zA-Z]\\)"
+ :doc-spec '(("(texinfo)Command and Variable Index"
+ ;; Ignore Emacs commands and prepend a `@'.
+ (lambda (item)
+ (if (string-match "^\\([a-zA-Z]+\\|[^a-zA-Z]\\)\\( .*\\)?$" item)
+ (concat "@" (match-string 1 item))))
+ "`" "[' ]")))
+
+(info-lookup-maybe-add-help
+ :mode 'm4-mode
+ :regexp "[_a-zA-Z][_a-zA-Z0-9]*"
+ :doc-spec '(("(m4)Macro index"))
+ :parse-rule "[_a-zA-Z0-9]+")
+
+(info-lookup-maybe-add-help
+ :mode 'autoconf-mode
+ :regexp "A[CM]_[_A-Z0-9]+"
+ :doc-spec '(;; Autoconf Macro Index entries are without an "AC_" prefix,
+ ;; but with "AH_" or "AU_" for those. So add "AC_" if there
+ ;; isn't already an "A._".
+ ("(autoconf)Autoconf Macro Index"
+ (lambda (item)
+ (if (string-match "^A._" item) item (concat "AC_" item)))
+ "^[ \t]+-+ \\(Macro\\|Variable\\): .*\\<" "\\>")
+ ;; M4 Macro Index entries are without "AS_" prefixes, and
+ ;; mostly without "m4_" prefixes. "dnl" is an exception, not
+ ;; wanting any prefix. So AS_ is added back to upper-case
+ ;; names, m4_ to others which don't already an m4_.
+ ("(autoconf)M4 Macro Index"
+ (lambda (item)
+ (let ((case-fold-search nil))
+ (cond ((or (string-equal item "dnl")
+ (string-match "^m4_" item))
+ item)
+ ((string-match "^[A-Z0-9_]+$" item)
+ (concat "AS_" item))
+ (t
+ (concat "m4_" item)))))
+ "^[ \t]+-+ Macro: .*\\<" "\\>")
+ ;; Autotest Macro Index entries are without "AT_".
+ ("(autoconf)Autotest Macro Index" "AT_"
+ "^[ \t]+-+ Macro: .*\\<" "\\>")
+ ;; This is for older versions (probably pre autoconf 2.5x):
+ ("(autoconf)Macro Index" "AC_"
+ "^[ \t]+-+ \\(Macro\\|Variable\\): .*\\<" "\\>")
+ ;; Automake has index entries for its notes on various autoconf
+ ;; macros (eg. AC_PROG_CC). Ensure this is after the autoconf
+ ;; index, so as to prefer the autoconf docs.
+ ("(automake)Macro and Variable Index" nil
+ "^[ \t]*`" "'"))
+ ;; Autoconf symbols are M4 macros. Thus use M4's parser.
+ :parse-rule 'ignore
+ :other-modes '(m4-mode))
+
+(info-lookup-maybe-add-help
+ :mode 'awk-mode
+ :regexp "[_a-zA-Z]+"
+ :doc-spec '(("(gawk)Index"
+ (lambda (item)
+ (let ((case-fold-search nil))
+ (cond
+ ;; `BEGIN' and `END'.
+ ((string-match "^\\([A-Z]+\\) special pattern\\b" item)
+ (match-string 1 item))
+ ;; `if', `while', `do', ...
+ ((string-match "^\\([a-z]+\\) statement\\b" item)
+ (if (not (string-equal (match-string 1 item) "control"))
+ (match-string 1 item)))
+ ;; `NR', `NF', ...
+ ((string-match "^[A-Z]+$" item)
+ item)
+ ;; Built-in functions (matches to many entries).
+ ((string-match "^[a-z]+$" item)
+ item))))
+ "`" "\\([ \t]*([^)]*)\\)?'")))
+
+(info-lookup-maybe-add-help
+ :mode 'perl-mode
+ :regexp "[$@%][^a-zA-Z]\\|\\$\\^[A-Z]\\|[$@%]?[a-zA-Z][_a-zA-Z0-9]*"
+ :doc-spec '(("(perl5)Function Index"
+ (lambda (item)
+ (if (string-match "^\\([a-zA-Z0-9]+\\)" item)
+ (match-string 1 item)))
+ "^" "\\b")
+ ("(perl5)Variable Index"
+ (lambda (item)
+ ;; Work around bad formatted array variables.
+ (let ((sym (cond ((or (string-match "^\\$\\(.\\|@@\\)$" item)
+ (string-match "^\\$\\^[A-Z]$" item))
+ item)
+ ((string-match
+ "^\\([$%@]\\|@@\\)?[_a-zA-Z0-9]+" item)
+ (match-string 0 item))
+ (t ""))))
+ (if (string-match "@@" sym)
+ (setq sym (concat (substring sym 0 (match-beginning 0))
+ (substring sym (1- (match-end 0))))))
+ (if (string-equal sym "") nil sym)))
+ "^" "\\b"))
+ :parse-rule "[$@%]?\\([_a-zA-Z0-9]+\\|[^a-zA-Z]\\)")
+
+(info-lookup-maybe-add-help
+ :mode 'cperl-mode
+ :regexp "[$@%][^a-zA-Z]\\|\\$\\^[A-Z]\\|[$@%]?[a-zA-Z][_a-zA-Z0-9]*"
+ :other-modes '(perl-mode))
+
+(info-lookup-maybe-add-help
+ :mode 'latex-mode
+ :regexp "\\\\\\([a-zA-Z]+\\|[^a-zA-Z]\\)"
+ :doc-spec '(("(latex)Command Index" nil
+ "`" "\\({[^}]*}\\)?'")))
+
+(info-lookup-maybe-add-help
+ :mode 'emacs-lisp-mode
+ :regexp "[^][()'\" \t\n]+"
+ :doc-spec '(;; Commands with key sequences appear in nodes as `foo' and
+ ;; those without as `M-x foo'.
+ ("(emacs)Command Index" nil "`\\(M-x[ \t\n]+\\)?" "'")
+ ;; Variables normally appear in nodes as just `foo'.
+ ("(emacs)Variable Index" nil "`" "'")
+ ;; Almost all functions, variables, etc appear in nodes as
+ ;; " -- Function: foo" etc. A small number of aliases and
+ ;; symbols appear only as `foo', and will miss out on exact
+ ;; positions. Allowing `foo' would hit too many false matches
+ ;; for things that should go to Function: etc, and those latter
+ ;; are much more important. Perhaps this could change if some
+ ;; sort of fallback match scheme existed.
+ ("(elisp)Index" nil "^ -+ .*: " "\\( \\|$\\)")))
+
+(info-lookup-maybe-add-help
+ :mode 'lisp-interaction-mode
+ :regexp "[^][()'\" \t\n]+"
+ :parse-rule 'ignore
+ :other-modes '(emacs-lisp-mode))
+
+(info-lookup-maybe-add-help
+ :mode 'lisp-mode
+ :regexp "[^()'\" \t\n]+"
+ :parse-rule 'ignore
+ :other-modes '(emacs-lisp-mode))
+
+(info-lookup-maybe-add-help
+ :mode 'scheme-mode
+ :regexp "[^()`',\" \t\n]+"
+ :ignore-case t
+ ;; Aubrey Jaffer's rendition from <URL:ftp://ftp-swiss.ai.mit.edu/pub/scm>
+ :doc-spec '(("(r5rs)Index" nil
+ "^[ \t]+-+ [^:]+:[ \t]*" "\\b")))
+
+(info-lookup-maybe-add-help
+ :mode 'octave-mode
+ :regexp "[_a-zA-Z0-9]+"
+ :doc-spec '(("(octave)Function Index" nil
+ "^ -+ [^:]+:[ ]+\\(\\[[^=]*=[ ]+\\)?" nil)
+ ("(octave)Variable Index" nil "^ -+ [^:]+:[ ]+" nil)
+ ;; Catch lines of the form "xyz statement"
+ ("(octave)Concept Index"
+ (lambda (item)
+ (cond
+ ((string-match "^\\([A-Z]+\\) statement\\b" item)
+ (match-string 1 item))
+ (t nil)))
+ nil; "^ -+ [^:]+:[ ]+" don't think this prefix is useful here.
+ nil)))
+
+(info-lookup-maybe-add-help
+ :mode 'maxima-mode
+ :ignore-case t
+ :regexp "[a-zA-Z_%]+"
+ :doc-spec '( ("(maxima)Function and Variable Index" nil
+ "^ -+ [^:]+:[ ]+\\(\\[[^=]*=[ ]+\\)?" nil)))
+
+(info-lookup-maybe-add-help
+ :mode 'inferior-maxima-mode
+ :other-modes '(maxima-mode))
+
+;; coreutils and bash builtins overlap in places, eg. printf, so there's a
+;; question which should come first. Some of the coreutils descriptions are
+;; more detailed, but if bash is usually /bin/sh on a GNU system then the
+;; builtins will be what's normally run.
+;;
+;; Maybe special variables like $? should be matched as $?, not just ?.
+;; This would avoid a clash between variable $! and negation !, or variable
+;; $# and comment # (though comment # is not currently indexed in bash).
+;; Unfortunately if $? etc is the symbol, then we wouldn't be taken to the
+;; exact spot in the relevant node, since the bash manual has just `?' etc
+;; there. Maybe an extension to the prefix/suffix scheme could help this.
+
+(info-lookup-maybe-add-help
+ :mode 'sh-mode :topic 'symbol
+ ;; bash has "." and ":" in its index, but those chars will probably never
+ ;; work in info, so don't bother matching them in the regexp.
+ :regexp "\\([a-zA-Z0-9_-]+\\|[!{}@*#?$]\\|\\[\\[?\\|]]?\\)"
+ :doc-spec '(("(bash)Builtin Index" nil "^`" "[ .']")
+ ("(bash)Reserved Word Index" nil "^`" "[ .']")
+ ("(bash)Variable Index" nil "^`" "[ .']")
+ ;; coreutils (version 4.5.10) doesn't have a separate program
+ ;; index, so exclude extraneous stuff (most of it) by demanding
+ ;; "[a-z]+" in the trans-func.
+ ("(coreutils)Index"
+ (lambda (item) (if (string-match "\\`[a-z]+\\'" item) item)))
+ ;; diff (version 2.8.1) has only a few programs, index entries
+ ;; are things like "foo invocation".
+ ("(diff)Index"
+ (lambda (item)
+ (if (string-match "\\`\\([a-z]+\\) invocation\\'" item)
+ (match-string 1 item))))
+ ;; there's no plain "sed" index entry as such, mung another
+ ;; hopefully unique one to get to the invocation section
+ ("(sed)Concept Index"
+ (lambda (item)
+ (if (string-equal item "Standard input, processing as input")
+ "sed")))
+ ;; there's no plain "awk" or "gawk" index entries, mung other
+ ;; hopefully unique ones to get to the command line options
+ ("(gawk)Index"
+ (lambda (item)
+ (cond ((string-equal item "gawk, extensions, disabling")
+ "awk")
+ ((string-equal item "gawk, versions of, information about, printing")
+ "gawk"))))))
+
+;; This misses some things which occur as node names but not in the
+;; index. Unfortunately it also picks up the wrong one of multiple
+;; entries for the same term in some cases. --fx
+(info-lookup-maybe-add-help
+ :mode 'cfengine-mode
+ :regexp "[[:alnum:]_]+\\(?:()\\)?"
+ :doc-spec '(("(cfengine-Reference)Variable Index"
+ (lambda (item)
+ ;; Index entries may be like `IsPlain()'
+ (if (string-match "\\([[:alnum:]_]+\\)()" item)
+ (match-string 1 item)
+ item))
+ ;; This gets functions in evaluated classes. Other
+ ;; possible patterns don't seem to work too well.
+ "`" "(")))
+\f