X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/5a79736d825eda659f66df87459ba02ff30dd59d..4d8ae757b2662eca9e0d49c3fb27e69fb85cab85:/lisp/info-look.el diff --git a/lisp/info-look.el b/lisp/info-look.el index c798bb769b..e7aedf47f5 100644 --- a/lisp/info-look.el +++ b/lisp/info-look.el @@ -1,9 +1,10 @@ -;;; info-look.el --- major-mode-sensitive Info index lookup facility. +;;; info-look.el --- major-mode-sensitive Info index lookup facility ;; An older version of this was known as libc.el. -;; Copyright (C) 1995, 1996, 1997 Ralph Schleicher. +;; Copyright (C) 1995,96,97,98,99,2001 Free Software Foundation, Inc. -;; Author: Ralph Schleicher +;; Author: Ralph Schleicher +;; (did not show signs of life (Nov 2001) -stef) ;; Keywords: help languages ;; This file is part of GNU Emacs. @@ -23,38 +24,61 @@ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. +;;; Commentary: + +;; Really cool code to lookup info indexes. +;; Try especially info-lookup-symbol (aka C-h TAB). + ;;; Code: (require 'info) +(defgroup info-lookup nil + "Major mode sensitive help agent." + :group 'help :group 'languages) + (defvar info-lookup-mode nil - "*Symbol of the current buffer's help mode. -Provide help according to the buffer's major mode if value is nil. + "Symbol of the current buffer's help mode. +Help is provided according to the buffer's major mode if value is nil. Automatically becomes buffer local when set in any fashion.") (make-variable-buffer-local 'info-lookup-mode) -(defvar info-lookup-other-window-flag t - "*Non-nil means pop up the Info buffer in another window.") +(defcustom info-lookup-other-window-flag t + "Non-nil means pop up the Info buffer in another window." + :group 'info-lookup :type 'boolean) -(defvar info-lookup-highlight-face 'highlight - "*Face for highlighting looked up help items. -Setting this variable to nil disables highlighting.") +(defcustom info-lookup-highlight-face 'highlight + "Face for highlighting looked up help items. +Setting this variable to nil disables highlighting." + :group 'info-lookup :type 'face) (defvar info-lookup-highlight-overlay nil "Overlay object used for highlighting.") +(defcustom info-lookup-file-name-alist + '(("\\`configure\\.in\\'" . autoconf-mode) ;already covered by auto-mode-alist + ("\\`ac\\(local\\|site\\|include\\)\\.m4\\'" . autoconf-mode)) + "Alist of file names handled specially. +List elements are cons cells of the form + + (REGEXP . MODE) + +If a file name matches REGEXP, then use help mode MODE instead of the +buffer's major mode." + :group 'info-lookup :type '(repeat (cons (string :tag "Regexp") + (symbol :tag "Mode")))) + (defvar info-lookup-history nil "History of previous input lines.") -(defvar info-lookup-alist '((symbol . info-lookup-symbol-alist) - (file . info-lookup-file-alist)) - "*Alist of known help topics. +(defvar info-lookup-alist nil + "Alist of known help topics. Cons cells are of the form - (HELP-TOPIC . VARIABLE) + (HELP-TOPIC . HELP-DATA) HELP-TOPIC is the symbol of a help topic. -VARIABLE is a variable storing HELP-TOPIC's public data. +HELP-DATA is a HELP-TOPIC's public data set. Value is an alist with elements of the form (HELP-MODE REGEXP IGNORE-CASE DOC-SPEC PARSE-RULE OTHER-MODES) @@ -84,7 +108,7 @@ PARSE-RULE is either the symbol name of a function or a regular OTHER-MODES is a list of cross references to other help modes.") (defsubst info-lookup->topic-value (topic) - (symbol-value (cdr (assoc topic info-lookup-alist)))) + (cdr (assoc topic info-lookup-alist))) (defsubst info-lookup->mode-value (topic mode) (assoc mode (info-lookup->topic-value topic))) @@ -104,6 +128,70 @@ OTHER-MODES is a list of cross references to other help modes.") (defsubst info-lookup->other-modes (topic mode) (nth 5 (info-lookup->mode-value topic mode))) +(defun info-lookup-add-help (&rest arg) + "Add or update a help specification. +Function arguments are one or more options of the form + + KEYWORD ARGUMENT + +KEYWORD is either `:topic', `:mode', `:regexp', `:ignore-case', + `:doc-spec', `:parse-rule', or `:other-modes'. +ARGUMENT has a value as explained in the documentation of the + variable `info-lookup-alist'. + +If no topic or mode option has been specified, then the help topic defaults +to `symbol', and the help mode defaults to the current major mode." + (apply 'info-lookup-add-help* nil arg)) + +(defun info-lookup-maybe-add-help (&rest arg) + "Add a help specification iff none is defined. +See the documentation of the function `info-lookup-add-help' +for more details." + (apply 'info-lookup-add-help* t arg)) + +(defun info-lookup-add-help* (maybe &rest arg) + (let (topic mode regexp ignore-case doc-spec + parse-rule other-modes keyword value) + (setq topic 'symbol + mode major-mode + regexp "\\w+") + (while arg + (setq keyword (car arg)) + (or (symbolp keyword) + (error "Junk in argument list \"%S\"" arg)) + (setq arg (cdr arg)) + (and (null arg) + (error "Keyword \"%S\" is missing an argument" keyword)) + (setq value (car arg) + arg (cdr arg)) + (cond ((eq keyword :topic) + (setq topic value)) + ((eq keyword :mode) + (setq mode value)) + ((eq keyword :regexp) + (setq regexp value)) + ((eq keyword :ignore-case) + (setq ignore-case value)) + ((eq keyword :doc-spec) + (setq doc-spec value)) + ((eq keyword :parse-rule) + (setq parse-rule value)) + ((eq keyword :other-modes) + (setq other-modes value)) + (t + (error "Unknown keyword \"%S\"" keyword)))) + (or (and maybe (info-lookup->mode-value topic mode)) + (let* ((data (list regexp ignore-case doc-spec parse-rule other-modes)) + (topic-cell (or (assoc topic info-lookup-alist) + (car (setq info-lookup-alist + (cons (cons topic nil) + info-lookup-alist))))) + (mode-cell (assoc mode topic-cell))) + (if (null mode-cell) + (setcdr topic-cell (cons (cons mode data) (cdr topic-cell))) + (setcdr mode-cell data)))) + nil)) + (defvar info-lookup-cache nil "Cache storing data maintained automatically by the program. Value is an alist with cons cell of the form @@ -124,81 +212,30 @@ REFER-MODES is a list of other help modes to use.") (cons (cons topic nil) info-lookup-cache))))) -(defsubst info-lookup->topic-cache (topic) +(defun info-lookup->topic-cache (topic) (cdr (info-lookup->cache topic))) -(defsubst info-lookup->mode-cache (topic mode) +(defun info-lookup->mode-cache (topic mode) (assoc mode (info-lookup->topic-cache topic))) -(defsubst info-lookup->initialized (topic mode) +(defun info-lookup->initialized (topic mode) (nth 1 (info-lookup->mode-cache topic mode))) -(defsubst info-lookup->completions (topic mode) +(defun info-lookup->completions (topic mode) (or (info-lookup->initialized topic mode) (info-lookup-setup-mode topic mode)) (nth 2 (info-lookup->mode-cache topic mode))) -(defsubst info-lookup->refer-modes (topic mode) +(defun info-lookup->refer-modes (topic mode) (or (info-lookup->initialized topic mode) (info-lookup-setup-mode topic mode)) (nth 3 (info-lookup->mode-cache topic mode))) -(defsubst info-lookup->all-modes (topic mode) +(defun info-lookup->all-modes (topic mode) (cons mode (info-lookup->refer-modes topic mode))) -(defvar info-lookup-symbol-alist - '((autoconf-mode - "A[CM]_[_A-Z0-9]+" nil - (("(autoconf)Macro Index" "AC_" - "^[ \t]+- \\(Macro\\|Variable\\): .*\\<" "\\>") - ("(automake)Index" nil - "^[ \t]*`" "'")) - ;; Autoconf symbols are M4 macros. Thus use M4's parser. - ignore - (m4-mode)) - (bison-mode - "[:;|]\\|%\\([%{}]\\|[_a-z]+\\)\\|YY[_A-Z]+\\|yy[_a-z]+" nil - (("(bison)Index" nil - "`" "'")) - "[:;|]\\|%\\([%{}]\\|[_a-zA-Z][_a-zA-Z0-9]*\\)" - (c-mode)) - (c-mode - "\\(struct \\|union \\|enum \\)?[_a-zA-Z][_a-zA-Z0-9]*" nil - (("(libc)Function Index" nil - "^[ \t]+- \\(Function\\|Macro\\): .*\\<" "\\>") - ("(libc)Variable Index" nil - "^[ \t]+- \\(Variable\\|Macro\\): .*\\<" "\\>") - ("(libc)Type Index" nil - "^[ \t]+- Data Type: \\<" "\\>") - ("(termcap)Var Index" nil - "^[ \t]*`" "'")) - info-lookup-guess-c-symbol) - (m4-mode - "[_a-zA-Z][_a-zA-Z0-9]*" nil - (("(m4)Macro index")) - "[_a-zA-Z0-9]+") - (makefile-mode - "\\$[^({]\\|\\.[_A-Z]*\\|[_a-zA-Z][_a-zA-Z0-9-]*" nil - (("(make)Name Index" nil - "^[ \t]*`" "'")) - "\\$[^({]\\|\\.[_A-Z]*\\|[_a-zA-Z0-9-]+") - (texinfo-mode - "@\\([a-zA-Z]+\\|[^a-zA-Z]\\)" nil - (("(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)))) - "`" "'")))) - "*Alist of help specifications for symbol names. -See the documentation of the variable `info-lookup-alist' for more details.") - -(defvar info-lookup-file-alist - '((c-mode - "[_a-zA-Z0-9./+-]+" nil - (("(libc)File Index")))) - "*Alist of help specifications for file names. -See the documentation of the variable `info-lookup-alist' for more details.") +(defun info-lookup-quick-all-modes (topic mode) + (cons mode (info-lookup->other-modes topic mode))) ;;;###autoload (defun info-lookup-reset () @@ -211,45 +248,59 @@ system." ;;;###autoload (defun info-lookup-symbol (symbol &optional mode) - "Display the documentation of a symbol. -If called interactively, SYMBOL will be read from the mini-buffer. -Prefix argument means unconditionally insert the default symbol name -into the mini-buffer so that it can be edited. -The default symbol is the one found at point." + "Display the definition of SYMBOL, as found in the relevant manual. +When this command is called interactively, it reads SYMBOL from the minibuffer. +In the minibuffer, use M-n to yank the default argument value +into the minibuffer so you can edit it. +The default symbol is the one found at point. + +With prefix arg a query for the symbol help mode is offered." (interactive - (info-lookup-interactive-arguments 'symbol)) + (info-lookup-interactive-arguments 'symbol current-prefix-arg)) (info-lookup 'symbol symbol mode)) ;;;###autoload (defun info-lookup-file (file &optional mode) "Display the documentation of a file. -If called interactively, FILE will be read from the mini-buffer. -Prefix argument means unconditionally insert the default file name -into the mini-buffer so that it can be edited. -The default file name is the one found at point." +When this command is called interactively, it reads FILE from the minibuffer. +In the minibuffer, use M-n to yank the default file name +into the minibuffer so you can edit it. +The default file name is the one found at point. + +With prefix arg a query for the file help mode is offered." (interactive - (info-lookup-interactive-arguments 'file)) + (info-lookup-interactive-arguments 'file current-prefix-arg)) (info-lookup 'file file mode)) -(defun info-lookup-interactive-arguments (topic) - "Return default value and help mode for help topic TOPIC." - (let* ((mode (if (info-lookup->mode-value - topic (or info-lookup-mode major-mode)) - (or info-lookup-mode major-mode) - (info-lookup-change-mode topic))) +(defun info-lookup-interactive-arguments (topic &optional query) + "Read and return argument value (and help mode) for help topic TOPIC. +If optional argument QUERY is non-nil, query for the help mode." + (let* ((mode (cond (query + (info-lookup-change-mode topic)) + ((info-lookup->mode-value topic (info-lookup-select-mode)) + info-lookup-mode) + ((info-lookup-change-mode topic)))) (completions (info-lookup->completions topic mode)) (default (info-lookup-guess-default topic mode)) - (input (if (or current-prefix-arg (not (assoc default completions))) - default)) (completion-ignore-case (info-lookup->ignore-case topic mode)) (enable-recursive-minibuffers t) (value (completing-read - (if (and default (not input)) + (if default (format "Describe %s (default %s): " topic default) (format "Describe %s: " topic)) - completions nil nil input 'info-lookup-history))) + completions nil nil nil 'info-lookup-history default))) (list (if (equal value "") default value) mode))) +(defun info-lookup-select-mode () + (when (and (not info-lookup-mode) (buffer-file-name)) + (let ((file-name (file-name-nondirectory (buffer-file-name))) + (file-name-alist info-lookup-file-name-alist)) + (while (and (not info-lookup-mode) file-name-alist) + (when (string-match (caar file-name-alist) file-name) + (setq info-lookup-mode (cdar file-name-alist))) + (setq file-name-alist (cdr file-name-alist))))) + (or info-lookup-mode (setq info-lookup-mode major-mode))) + (defun info-lookup-change-mode (topic) (let* ((completions (mapcar (lambda (arg) (cons (symbol-name (car arg)) (car arg))) @@ -265,8 +316,7 @@ The default file name is the one found at point." (defun info-lookup (topic item mode) "Display the documentation of a help item." - (if (not mode) - (setq mode (or info-lookup-mode major-mode))) + (or mode (setq mode (info-lookup-select-mode))) (or (info-lookup->mode-value topic mode) (error "No %s help available for `%s'" topic mode)) (let ((entry (or (assoc (if (info-lookup->ignore-case topic mode) @@ -275,46 +325,66 @@ The default file name is the one found at point." (error "Not documented as a %s: %s" topic (or item "")))) (modes (info-lookup->all-modes topic mode)) (window (selected-window)) - found doc-spec node prefix suffix) - (if (not info-lookup-other-window-flag) + found doc-spec node prefix suffix doc-found) + (if (or (not info-lookup-other-window-flag) + (eq (current-buffer) (get-buffer "*info*"))) (info) - (save-window-excursion (info)) - (switch-to-buffer-other-window "*info*")) + (progn + (save-window-excursion (info)) + ;; Determine whether or not the Info buffer is visible in + ;; another frame on the same display. If it is, simply raise + ;; that frame. Otherwise, display it in another window. + (let* ((window (get-buffer-window "*info*" t)) + (info-frame (and window (window-frame window)))) + (if (and info-frame + (display-multi-frame-p) + (memq info-frame (frames-on-display-list))) + (select-frame info-frame) + (switch-to-buffer-other-window "*info*"))))) (while (and (not found) modes) (setq doc-spec (info-lookup->doc-spec topic (car modes))) (while (and (not found) doc-spec) (setq node (nth 0 (car doc-spec)) prefix (nth 2 (car doc-spec)) suffix (nth 3 (car doc-spec))) - (condition-case nil - (progn - (Info-goto-node node) - (Info-menu (or (cdr entry) item)) - (setq found t) - (if (or prefix suffix) - (let ((case-fold-search - (info-lookup->ignore-case topic (car modes))) - (buffer-read-only nil)) - (goto-char (point-min)) - (re-search-forward - (concat prefix (regexp-quote item) suffix)) - (goto-char (match-beginning 0)) - (and window-system info-lookup-highlight-face - ;; Search again for ITEM so that the first - ;; occurence of ITEM will be highlighted. - (re-search-forward (regexp-quote item)) - (let ((start (match-beginning 0)) - (end (match-end 0))) - (if (overlayp info-lookup-highlight-overlay) - (move-overlay info-lookup-highlight-overlay - start end (current-buffer)) - (setq info-lookup-highlight-overlay - (make-overlay start end)))) - (overlay-put info-lookup-highlight-overlay - 'face info-lookup-highlight-face))))) - (error nil)) + (when (condition-case error-data + (progn + (Info-goto-node node) + (setq doc-found t)) + (error + (message "Cannot access Info node %s" node) + (sit-for 1) + nil)) + (condition-case nil + (progn + (Info-menu (or (cdr entry) item)) + (setq found t) + (if (or prefix suffix) + (let ((case-fold-search + (info-lookup->ignore-case topic (car modes))) + (buffer-read-only nil)) + (goto-char (point-min)) + (re-search-forward + (concat prefix (regexp-quote item) suffix)) + (goto-char (match-beginning 0)) + (and (display-color-p) info-lookup-highlight-face + ;; Search again for ITEM so that the first + ;; occurence of ITEM will be highlighted. + (re-search-forward (regexp-quote item)) + (let ((start (match-beginning 0)) + (end (match-end 0))) + (if (overlayp info-lookup-highlight-overlay) + (move-overlay info-lookup-highlight-overlay + start end (current-buffer)) + (setq info-lookup-highlight-overlay + (make-overlay start end)))) + (overlay-put info-lookup-highlight-overlay + 'face info-lookup-highlight-face))))) + (error nil))) (setq doc-spec (cdr doc-spec))) (setq modes (cdr modes))) + (or doc-found + (error "Info documentation for lookup was not found")) ;; Don't leave the Info buffer if the help item couldn't be looked up. (if (and info-lookup-other-window-flag found) (select-window window)))) @@ -336,7 +406,9 @@ The default file name is the one found at point." (setq refer-modes (nreverse refer-modes)) ;; Build the full completion alist. (setq completions - (nconc (info-lookup-make-completions topic mode) + (nconc (condition-case nil + (info-lookup-make-completions topic mode) + (error nil)) (apply 'append (mapcar (lambda (arg) (info-lookup->completions topic arg)) @@ -353,93 +425,112 @@ The default file name is the one found at point." (defun info-lookup-make-completions (topic mode) "Create a unique alist from all index entries." - (condition-case nil - (let ((doc-spec (info-lookup->doc-spec topic mode)) - (regexp (concat "^\\(" (info-lookup->regexp topic mode) - "\\)\\([ \t].*\\)?$")) - node trans entry item prefix result) - (save-window-excursion - (info) - (while doc-spec - (setq node (nth 0 (car doc-spec)) - trans (cond ((eq (nth 1 (car doc-spec)) nil) - (lambda (arg) - (if (string-match regexp arg) - (match-string 1 arg)))) - ((stringp (nth 1 (car doc-spec))) - (setq prefix (nth 1 (car doc-spec))) - (lambda (arg) - (if (string-match "^\\([^: \t\n]+\\)" arg) - (concat prefix (match-string 1 arg))))) - (t (nth 1 (car doc-spec))))) - (message "Processing Info node \"%s\"..." node) - (Info-goto-node node) - (goto-char (point-min)) - (and (search-forward "\n* Menu:" nil t) - (while (re-search-forward "\n\\* \\([^:\t\n]*\\):" nil t) - (setq entry (match-string 1) - item (funcall trans entry)) - (and (info-lookup->ignore-case topic mode) - (setq item (downcase item))) - (and (string-equal entry item) - (setq entry nil)) - (or (assoc item result) - (setq result (cons (cons item entry) result))))) - (message "Processing Info node \"%s\"... done" node) - (setq doc-spec (cdr doc-spec))) - (Info-directory)) - result) - (error nil))) + (let ((doc-spec (info-lookup->doc-spec topic mode)) + (regexp (concat "^\\(" (info-lookup->regexp topic mode) + "\\)\\([ \t].*\\)?$")) + node trans entry item prefix result doc-found + (buffer (get-buffer-create " temp-info-look"))) + (with-current-buffer buffer + (Info-mode)) + (while doc-spec + (setq node (nth 0 (car doc-spec)) + trans (cond ((eq (nth 1 (car doc-spec)) nil) + (lambda (arg) + (if (string-match regexp arg) + (match-string 1 arg)))) + ((stringp (nth 1 (car doc-spec))) + (setq prefix (nth 1 (car doc-spec))) + (lambda (arg) + (if (string-match "^\\([^: \t\n]+\\)" arg) + (concat prefix (match-string 1 arg))))) + (t (nth 1 (car doc-spec))))) + (with-current-buffer buffer + (message "Processing Info node `%s'..." node) + (when (condition-case error-data + (progn + (Info-goto-node node) + (setq doc-found t)) + (error + (message "Cannot access Info node `%s'" node) + (sit-for 1) + nil)) + (condition-case nil + (progn + (goto-char (point-min)) + (and (search-forward "\n* Menu:" nil t) + (while (re-search-forward "\n\\* \\([^:\t\n]*\\):" nil t) + (setq entry (match-string 1) + item (funcall trans entry)) + ;; `trans' can return nil if the regexp doesn't match. + (when (and item + ;; Sometimes there's more than one Menu: + (not (string= entry "Menu"))) + (and (info-lookup->ignore-case topic mode) + (setq item (downcase item))) + (and (string-equal entry item) + (setq entry nil)) + (and (or (assoc item result) + (setq result (cons (cons item entry) + result)))))))) + (error nil)))) + (message "Processing Info node `%s'...done" node) + (setq doc-spec (cdr doc-spec))) + (or doc-found + (error "Info documentation for lookup was not found")) + result)) (defun info-lookup-guess-default (topic mode) - "Pick up default item at point (with favor to look back). -Return nil if there is nothing appropriate." + "Return a guess for a symbol to look up, based on text around point. +Try all related modes applicable to TOPIC and MODE. +Return nil if there is nothing appropriate in the buffer near point." (let ((modes (info-lookup->all-modes topic mode)) - (start (point)) guess whitespace) + guess) (while (and (not guess) modes) (setq guess (info-lookup-guess-default* topic (car modes)) - modes (cdr modes)) - (goto-char start)) + modes (cdr modes))) ;; Collapse whitespace characters. - (and guess (concat (delete nil (mapcar (lambda (ch) - (if (or (char-equal ch ? ) - (char-equal ch ?\t) - (char-equal ch ?\n)) - (if (not whitespace) - (setq whitespace ? )) - (setq whitespace nil) ch)) - guess)))))) + (when guess + (let ((pos 0)) + (while (string-match "[ \t\n]+" guess pos) + (setq pos (1+ (match-beginning 0))) + (setq guess (replace-match " " t t guess))))) + guess)) (defun info-lookup-guess-default* (topic mode) (let ((case-fold-search (info-lookup->ignore-case topic mode)) (rule (or (info-lookup->parse-rule topic mode) (info-lookup->regexp topic mode))) (start (point)) end regexp subexp result) - (if (symbolp rule) - (setq result (funcall rule)) - (if (consp rule) - (setq regexp (car rule) - subexp (cdr rule)) - (setq regexp rule - subexp 0)) - (skip-chars-backward " \t\n") (setq end (point)) - (while (and (re-search-backward regexp nil t) - (looking-at regexp) - (>= (match-end 0) end)) - (setq result (match-string subexp))) - (if (not result) - (progn - (goto-char start) - (skip-chars-forward " \t\n") - (and (looking-at regexp) - (setq result (match-string subexp)))))) + (save-excursion + (if (symbolp rule) + (setq result (funcall rule)) + (if (consp rule) + (setq regexp (car rule) + subexp (cdr rule)) + (setq regexp rule + subexp 0)) + ;; If at start of symbol, don't go back to end of previous one. + (if (save-match-data + (looking-at "[ \t\n]")) + (skip-chars-backward " \t\n")) + (setq end (point)) + (while (and (re-search-backward regexp nil t) + (looking-at regexp) + (>= (match-end 0) end)) + (setq result (match-string subexp))) + (if (not result) + (progn + (goto-char start) + (skip-chars-forward " \t\n") + (and (looking-at regexp) + (setq result (match-string subexp))))))) result)) (defun info-lookup-guess-c-symbol () "Get the C symbol at point." (condition-case nil (progn - (backward-sexp) + (skip-syntax-backward "w_") (let ((start (point)) prefix name) ;; Test for a leading `struct', `union', or `enum' keyword ;; but ignore names like `foo_struct'. @@ -465,47 +556,231 @@ Return nil if there is nothing appropriate." ;;;###autoload (defun info-complete-symbol (&optional mode) "Perform completion on symbol preceding point." - (interactive - (list (if (info-lookup->mode-value - 'symbol (or info-lookup-mode major-mode)) - (or info-lookup-mode major-mode) - (info-lookup-change-mode 'symbol)))) - (info-complete 'symbol mode)) + (interactive) + (info-complete 'symbol + (or mode + (if (info-lookup->mode-value + 'symbol (info-lookup-select-mode)) + info-lookup-mode + (info-lookup-change-mode 'symbol))))) ;;;###autoload (defun info-complete-file (&optional mode) "Perform completion on file preceding point." - (interactive - (list (if (info-lookup->mode-value - 'file (or info-lookup-mode major-mode)) - (or info-lookup-mode major-mode) - (info-lookup-change-mode 'file)))) - (info-complete 'file mode)) + (interactive) + (info-complete 'file + (or mode + (if (info-lookup->mode-value + 'file (info-lookup-select-mode)) + info-lookup-mode + (info-lookup-change-mode 'file))))) (defun info-complete (topic mode) "Try to complete a help item." (barf-if-buffer-read-only) - (if (not mode) - (setq mode (or info-lookup-mode major-mode))) + (or mode (setq mode (info-lookup-select-mode))) (or (info-lookup->mode-value topic mode) (error "No %s completion available for `%s'" topic mode)) - (let ((modes (info-lookup->all-modes topic mode)) - (start (point)) try completion) + (let ((modes (info-lookup-quick-all-modes topic mode)) + (start (point)) + try) (while (and (not try) modes) (setq mode (car modes) modes (cdr modes) try (info-lookup-guess-default* topic mode)) (goto-char start)) (and (not try) - (error "Found no %s to complete" topic)) - (setq completion (try-completion - try (info-lookup->completions topic mode))) - (cond ((not completion) - (ding)) - ((stringp completion) - (delete-region (- start (length try)) start) - (insert completion))))) - + (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)))))))) + + +;;; 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\\): .*\\<" "\\>") + ("(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" "AC_" + "^[ \t]+- \\(Macro\\|Variable\\): .*\\<" "\\>") + ("(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 '(("(emacs)Command Index") + ("(emacs)Variable Index") + ("(elisp)Index"))) + +(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 + :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))) + (provide 'info-look) ;;; info-look.el ends here