- (let ((completion-ignore-case t)
- (case-fold-search t))
- (cond ((eq action nil)
- (let (completions
- (pattern (concat "\n\\* +\\("
- (regexp-quote string)
- "[^:\t\n]*\\):")))
- (save-excursion
- (set-buffer Info-complete-menu-buffer)
- (goto-char (point-min))
- (search-forward "\n* Menu:")
- (while (re-search-forward pattern nil t)
- (setq completions
- (cons (cons (match-string-no-properties 1)
- (match-beginning 1))
- completions))))
- (try-completion string completions predicate)))
- ((eq action t)
- (let (completions
- (pattern (concat "\n\\* +\\("
- (regexp-quote string)
- "[^:\t\n]*\\):")))
- (save-excursion
- (set-buffer Info-complete-menu-buffer)
- (goto-char (point-min))
- (search-forward "\n* Menu:")
- (while (re-search-forward pattern nil t)
- (setq completions (cons (cons
- (match-string-no-properties 1)
- (match-beginning 1))
- completions))))
- (all-completions string completions predicate)))
- (t
- (save-excursion
- (set-buffer Info-complete-menu-buffer)
- (goto-char (point-min))
- (search-forward "\n* Menu:")
- (re-search-forward (concat "\n\\* +"
- (regexp-quote string)
- ":")
- nil t))))))
+ ;; This uses two dynamically bound variables:
+ ;; - `Info-complete-menu-buffer' which contains the buffer in which
+ ;; is the menu of items we're trying to complete.
+ ;; - `Info-complete-next-re' which, if non-nil, indicates that we should
+ ;; also look for menu items in subsequent nodes as long as those
+ ;; nodes' names match `Info-complete-next-re'. This feature is currently
+ ;; only used for completion in Info-index.
+
+ ;; Note that `Info-complete-menu-buffer' could be current already,
+ ;; so we want to save point.
+ (save-excursion
+ (set-buffer Info-complete-menu-buffer)
+ (let ((completion-ignore-case t)
+ (case-fold-search t)
+ (orignode Info-current-node)
+ nextnode)
+ (goto-char (point-min))
+ (search-forward "\n* Menu:")
+ (if (not (memq action '(nil t)))
+ (re-search-forward
+ (concat "\n\\* +" (regexp-quote string) ":") nil t)
+ (let ((pattern (concat "\n\\* +\\("
+ (regexp-quote string)
+ "[^\t\n]*?\\):" Info-node-spec-re))
+ completions)
+ ;; Check the cache.
+ (if (and (equal (nth 0 Info-complete-cache) Info-current-file)
+ (equal (nth 1 Info-complete-cache) Info-current-node)
+ (equal (nth 2 Info-complete-cache) Info-complete-next-re)
+ (let ((prev (nth 3 Info-complete-cache)))
+ (eq t (compare-strings string 0 (length prev)
+ prev 0 nil t))))
+ ;; We can reuse the previous list.
+ (setq completions (nth 4 Info-complete-cache))
+ ;; The cache can't be used.
+ (while
+ (progn
+ (while (re-search-forward pattern nil t)
+ (push (match-string-no-properties 1)
+ completions))
+ ;; Check subsequent nodes if applicable.
+ (and Info-complete-next-re
+ (setq nextnode (Info-extract-pointer "next" t))
+ (string-match Info-complete-next-re nextnode)))
+ (Info-goto-node nextnode))
+ ;; Go back to the start node (for the next completion).
+ (unless (equal Info-current-node orignode)
+ (Info-goto-node orignode))
+ ;; Update the cache.
+ (set (make-local-variable 'Info-complete-cache)
+ (list Info-current-file Info-current-node
+ Info-complete-next-re string completions)))
+ (if action
+ (all-completions string completions predicate)
+ (try-completion string completions predicate)))))))