-;; info.el --- info package for Emacs
+;; info.el --- Info package for Emacs -*- lexical-binding:t -*-
-;; Copyright (C) 1985-1986, 1992-2013 Free Software Foundation, Inc.
+;; Copyright (C) 1985-1986, 1992-2014 Free Software Foundation, Inc.
-;; Maintainer: FSF
+;; Maintainer: emacs-devel@gnu.org
;; Keywords: help
;; This file is part of GNU Emacs.
;;; Code:
+(eval-when-compile (require 'cl-lib))
+
(defgroup info nil
"Info subsystem."
:group 'help
:group 'docs)
-(defvar Info-history nil
+(defvar-local Info-history nil
"Stack of Info nodes user has visited.
Each element of the stack is a list (FILENAME NODENAME BUFFERPOS).")
-(defvar Info-history-forward nil
+(defvar-local Info-history-forward nil
"Stack of Info nodes user has visited with `Info-history-back' command.
Each element of the stack is a list (FILENAME NODENAME BUFFERPOS).")
"Face for Info nodes in a node header."
:group 'info)
+(defface info-index-match
+ '((t :inherit match))
+ "Face used to highlight matches in an index entry."
+ :group 'info
+ :version "24.4")
+
;; This is a defcustom largely so that we can get the benefit
;; of custom-initialize-delay. Perhaps it would work to make it a
;; defvar and explicitly give it a standard-value property, and
(make-obsolete-variable 'Info-edit-mode-hook
"editing Info nodes by hand is not recommended." "24.4")
-(defvar Info-current-file nil
+(defvar-local Info-current-file nil
"Info file that Info is now looking at, or nil.
This is the name that was specified in Info, not the actual file name.
It doesn't contain directory names or file name extensions added by Info.")
-(defvar Info-current-subfile nil
+(defvar-local Info-current-subfile nil
"Info subfile that is actually in the *info* buffer now.
It is nil if current Info file is not split into subfiles.")
-(defvar Info-current-node nil
+(defvar-local Info-current-node nil
"Name of node that Info is now looking at, or nil.")
-(defvar Info-tag-table-marker nil
+(defvar-local Info-tag-table-marker nil
"Marker pointing at beginning of current Info file's tag table.
Marker points nowhere if file has no tag table.")
-(defvar Info-tag-table-buffer nil
+(defvar-local Info-tag-table-buffer nil
"Buffer used for indirect tag tables.")
-(defvar Info-current-file-completions nil
+(defvar-local Info-current-file-completions nil
"Cached completion list for current Info file.")
(defvar Info-file-completions nil
"Cached completion alist of visited Info files.
Each element of the alist is (FILE . COMPLETIONS)")
-(defvar Info-file-supports-index-cookies nil
+(defvar-local Info-file-supports-index-cookies nil
"Non-nil if current Info file supports index cookies.")
(defvar Info-file-supports-index-cookies-list nil
Each element of the list is a list (FILENAME SUPPORTS-INDEX-COOKIES)
where SUPPORTS-INDEX-COOKIES can be either t or nil.")
-(defvar Info-index-alternatives nil
+(defvar-local Info-index-alternatives nil
"List of possible matches for last `Info-index' command.")
(defvar Info-point-loc nil
symbols `find-node' that define what HANDLER function to call instead
of calling the default corresponding function to override it.")
-(defvar Info-current-node-virtual nil
+(defvar-local Info-current-node-virtual nil
"Non-nil if the current Info node is virtual.")
(defun Info-virtual-file-p (filename)
(defun info-setup (file-or-node buffer)
"Display Info node FILE-OR-NODE in BUFFER."
- (if (and buffer (not (eq major-mode 'Info-mode)))
+ (if (and buffer (not (derived-mode-p 'Info-mode)))
(Info-mode))
(if file-or-node
;; If argument already contains parentheses, don't add another set
(setq filename found)
(if noerror
(setq filename nil)
- (error "Info file %s does not exist" filename)))
+ ;; If there is no previous Info file, go to the directory.
+ (unless Info-current-file
+ (Info-directory))
+ (user-error "Info file %s does not exist" filename)))
filename))))
-(defun Info-find-node (filename nodename &optional no-going-back)
+(defun Info-find-node (filename nodename &optional no-going-back strict-case)
"Go to an Info node specified as separate FILENAME and NODENAME.
NO-GOING-BACK is non-nil if recovering from an error in this function;
-it says do not attempt further (recursive) error recovery."
+it says do not attempt further (recursive) error recovery.
+
+This function first looks for a case-sensitive match for NODENAME;
+if none is found it then tries a case-insensitive match (unless
+STRICT-CASE is non-nil)."
(info-initialize)
(setq filename (Info-find-file filename))
;; Go into Info buffer.
- (or (eq major-mode 'Info-mode) (switch-to-buffer "*info*"))
+ (or (derived-mode-p 'Info-mode) (switch-to-buffer "*info*"))
;; Record the node we are leaving, if we were in one.
(and (not no-going-back)
Info-current-file
(push (list Info-current-file Info-current-node (point))
Info-history))
- (Info-find-node-2 filename nodename no-going-back))
+ (Info-find-node-2 filename nodename no-going-back strict-case))
;;;###autoload
(defun Info-on-current-buffer (&optional nodename)
(unless nodename (setq nodename "Top"))
(info-initialize)
(Info-mode)
- (set (make-local-variable 'Info-current-file)
- (or buffer-file-name
- ;; If called on a non-file buffer, make a fake file name.
- (concat default-directory (buffer-name))))
+ (setq Info-current-file
+ (or buffer-file-name
+ ;; If called on a non-file buffer, make a fake file name.
+ (concat default-directory (buffer-name))))
(Info-find-node-2 nil nodename))
(defun Info-revert-find-node (filename nodename)
"Go to an Info node FILENAME and NODENAME, re-reading disk contents.
When *info* is already displaying FILENAME and NODENAME, the window position
is preserved, if possible."
- (or (eq major-mode 'Info-mode) (switch-to-buffer "*info*"))
+ (or (derived-mode-p 'Info-mode) (switch-to-buffer "*info*"))
(let ((old-filename Info-current-file)
(old-nodename Info-current-node)
(window-selected (eq (selected-window) (get-buffer-window)))
(+ (point-min) (read (current-buffer)))
major-mode)))))
-(defun Info-find-in-tag-table (marker regexp)
+(defun Info-find-in-tag-table (marker regexp &optional strict-case)
"Find a node in a tag table.
MARKER specifies the buffer and position to start searching at.
REGEXP is a regular expression matching nodes or references. Its first
where the match was found, and MODE is `major-mode' of the buffer in
which the match was found.
This function tries to find a case-sensitive match first, then a
-case-insensitive match is tried."
+case-insensitive match is tried (unless optional argument STRICT-CASE
+is non-nil)."
(let ((result (Info-find-in-tag-table-1 marker regexp nil)))
- (when (null (car result))
- (setq result (Info-find-in-tag-table-1 marker regexp t)))
+ (or strict-case (car result)
+ (setq result (Info-find-in-tag-table-1 marker regexp t)))
result))
(defun Info-find-node-in-buffer-1 (regexp case-fold)
(setq found (line-beginning-position)))))))
found))
-(defun Info-find-node-in-buffer (regexp)
+(defun Info-find-node-in-buffer (regexp &optional strict-case)
"Find a node or anchor in the current buffer.
REGEXP is a regular expression matching nodes or references. Its first
group should match `Node:' or `Ref:'.
Value is the position at which a match was found, or nil if not found.
This function looks for a case-sensitive match first. If none is found,
-a case-insensitive match is tried."
+a case-insensitive match is tried (unless optional argument STRICT-CASE
+is non-nil)."
(or (Info-find-node-in-buffer-1 regexp nil)
- (Info-find-node-in-buffer-1 regexp t)))
+ (and (not strict-case)
+ (Info-find-node-in-buffer-1 regexp t))))
-(defun Info-find-node-2 (filename nodename &optional no-going-back)
+(defun Info-find-node-2 (filename nodename &optional no-going-back strict-case)
(buffer-disable-undo (current-buffer))
- (or (eq major-mode 'Info-mode)
+ (or (derived-mode-p 'Info-mode)
(Info-mode))
(widen)
(setq Info-current-node nil)
(set-marker Info-tag-table-marker nil)
(setq buffer-read-only t)
(set-buffer-modified-p nil)
- (set (make-local-variable 'Info-current-node-virtual) t)))
+ (setq Info-current-node-virtual t)))
((not (and
;; Reread a file when moving from a virtual node.
(not Info-current-node-virtual)
(let ((inhibit-read-only t))
(when Info-current-node-virtual
;; When moving from a virtual node.
- (set (make-local-variable 'Info-current-node-virtual) nil)
+ (setq Info-current-node-virtual nil)
(if (null filename)
(setq filename Info-current-file)))
(setq Info-current-file nil
(info-insert-file-contents filename nil)
(setq default-directory (file-name-directory filename))
(set-buffer-modified-p nil)
- (set (make-local-variable 'Info-file-supports-index-cookies)
+ (setq Info-file-supports-index-cookies
(Info-file-supports-index-cookies filename))
;; See whether file has a tag table. Record the location if yes.
;; First, search a tag table, if any
(when (marker-position Info-tag-table-marker)
(let* ((m Info-tag-table-marker)
- (found (Info-find-in-tag-table m regexp)))
+ (found (Info-find-in-tag-table m regexp strict-case)))
(when found
;; FOUND is (ANCHOR POS MODE).
;; buffer) to find the actual node. First, check
;; whether the node is right where we are, in case the
;; buffer begins with a node.
- (let ((pos (Info-find-node-in-buffer regexp)))
+ (let ((pos (Info-find-node-in-buffer regexp strict-case)))
(when pos
(goto-char pos)
(throw 'foo t)))
(Info-find-index-name Info-point-loc)
(setq Info-point-loc nil))))))
;; If we did not finish finding the specified node,
- ;; go back to the previous one.
- (or Info-current-node no-going-back (null Info-history)
- (let ((hist (car Info-history)))
- (setq Info-history (cdr Info-history))
- (Info-find-node (nth 0 hist) (nth 1 hist) t)
- (goto-char (nth 2 hist))))))
+ ;; go back to the previous one or to the Top node.
+ (unless (or Info-current-node no-going-back)
+ (if Info-history
+ (let ((hist (car Info-history)))
+ (setq Info-history (cdr Info-history))
+ (Info-find-node (nth 0 hist) (nth 1 hist) t)
+ (goto-char (nth 2 hist)))
+ (Info-find-node Info-current-file "Top" t)))))
;; Cache the contents of the (virtual) dir file, once we have merged
;; it for the first time, so we can save time subsequently.
-(defvar Info-dir-contents nil)
+(defvar-local Info-dir-contents nil)
;; Cache for the directory we decided to use for the default-directory
;; of the merged dir text.
-(defvar Info-dir-contents-directory nil)
+(defvar-local Info-dir-contents-directory nil)
;; Record the file attributes of all the files from which we
;; constructed Info-dir-contents.
-(defvar Info-dir-file-attributes nil)
+(defvar-local Info-dir-file-attributes nil)
-(defvar Info-dir-file-name nil)
+(defvar-local Info-dir-file-name nil)
;; Construct the Info directory node by merging the files named `dir'
;; from various directories. Set the *info* buffer's
;; knows...
(let ((inhibit-null-byte-detection t))
(insert-file-contents file)
- (set (make-local-variable 'Info-dir-file-name)
- file)
+ (setq Info-dir-file-name file)
(push (current-buffer) buffers)
(push (cons file attrs) dir-file-attrs))
(error (kill-buffer (current-buffer))))))))
(unless (cdr dirs)
- (set (make-local-variable 'Info-dir-contents-directory)
+ (setq Info-dir-contents-directory
(file-name-as-directory (car dirs))))
(setq dirs (cdr dirs))))
(if problems
(message "Composing main Info directory...problems encountered, see `*Messages*'")
(message "Composing main Info directory...done"))
- (set (make-local-variable 'Info-dir-contents) (buffer-string))
- (set (make-local-variable 'Info-dir-file-attributes) dir-file-attrs)))
+ (setq Info-dir-contents (buffer-string))
+ (setq Info-dir-file-attributes dir-file-attrs)))
(setq default-directory Info-dir-contents-directory))
(defvar Info-streamline-headings
;; Widen in case we are in the same subfile as before.
(widen)
(goto-char (point-min))
+ ;; Skip the summary segment for `Info-search'.
(if (looking-at "\^_")
(forward-char 1)
(search-forward "\n\^_"))
+ ;; Don't add the length of the skipped summary segment to
+ ;; the value returned to `Info-find-node-2'. (Bug#14125)
(if (numberp nodepos)
- (+ (- nodepos lastfilepos) (point)))))
+ (+ (- nodepos lastfilepos) (point-min)))))
(defun Info-unescape-quotes (value)
"Unescape double quotes and backslashes in VALUE."
""))
(image (if (file-exists-p image-file)
(create-image image-file)
- "[broken image]")))
+ (or (cdr (assoc-string "text" parameter-alist))
+ (and src (concat "[broken image:" src "]"))
+ "[broken image]"))))
(if (not (get-text-property start 'display))
(add-text-properties
- start (point) `(display ,image rear-nonsticky (display)))))
+ start (point)
+ `(display ,image rear-nonsticky (display)
+ help-echo ,(cdr (assoc-string "alt" parameter-alist))))))
;; text-only display, show alternative text if provided, or
;; otherwise a clue that there's meant to be a picture
(delete-region start (point))
(insert (or (cdr (assoc-string "text" parameter-alist))
(cdr (assoc-string "alt" parameter-alist))
- (and src
- (concat "[image:" src "]"))
+ (and src (concat "[image:" src "]"))
"[image]"))))))
(set-buffer-modified-p nil)))
;; Don't autoload this function: the correct entry point for other packages
;; to use is `info'. --Stef
;; ;;;###autoload
-(defun Info-goto-node (nodename &optional fork)
+(defun Info-goto-node (nodename &optional fork strict-case)
"Go to Info node named NODENAME. Give just NODENAME or (FILENAME)NODENAME.
If NODENAME is of the form (FILENAME)NODENAME, the node is in the Info file
FILENAME; otherwise, NODENAME should be in the current Info file (or one of
Empty NODENAME in (FILENAME) defaults to the Top node.
If FORK is non-nil (interactively with a prefix arg), show the node in
a new Info buffer.
-If FORK is a string, it is the name to use for the new buffer."
+If FORK is a string, it is the name to use for the new buffer.
+
+This function first looks for a case-sensitive match for the node part
+of NODENAME; if none is found it then tries a case-insensitive match
+\(unless STRICT-CASE is non-nil)."
(interactive (list (Info-read-node-name "Go to node: ") current-prefix-arg))
(info-initialize)
(if fork
(if trim (setq nodename (substring nodename 0 trim))))
(if transient-mark-mode (deactivate-mark))
(Info-find-node (if (equal filename "") nil filename)
- (if (equal nodename "") "Top" nodename))))
+ (if (equal nodename "") "Top" nodename) nil strict-case)))
(defvar Info-read-node-completion-table)
(cons (list (match-string-no-properties 1))
compl))))))))
(setq compl (cons '("*") (nreverse compl)))
- (set (make-local-variable 'Info-current-file-completions) compl)
+ (setq Info-current-file-completions compl)
compl))
\f
(defvar Info-search-case-fold nil
"The value of `case-fold-search' from previous `Info-search' command.")
+(defun Info--search-loop (regexp bound backward)
+ (when backward
+ ;; Hide Info file header for backward search.
+ (narrow-to-region (save-excursion
+ (goto-char (point-min))
+ (search-forward "\n\^_")
+ (1- (point)))
+ (point-max)))
+ (let ((give-up nil)
+ (found nil)
+ (beg-found nil))
+ (while (not (or give-up
+ (and found
+ (funcall isearch-filter-predicate
+ beg-found found))))
+ (let ((search-spaces-regexp Info-search-whitespace-regexp))
+ (if (funcall
+ (if backward #'re-search-backward #'re-search-forward)
+ regexp bound t)
+ (setq found (point) beg-found (if backward (match-end 0)
+ (match-beginning 0)))
+ (setq give-up t found nil))))
+ found))
+
(defun Info-search (regexp &optional bound _noerror _count direction)
"Search for REGEXP, starting from point, and select node it's found in.
If DIRECTION is `backward', search in the reverse direction."
(when (equal regexp "")
(setq regexp (car Info-search-history)))
(when regexp
- (let (found beg-found give-up
- (backward (eq direction 'backward))
- (onode Info-current-node)
- (ofile Info-current-file)
- (opoint (point))
- (opoint-min (point-min))
- (opoint-max (point-max))
- (ostart (window-start))
- (osubfile Info-current-subfile))
- (setq Info-search-case-fold case-fold-search)
- (save-excursion
- (save-restriction
- (widen)
- (when backward
- ;; Hide Info file header for backward search
- (narrow-to-region (save-excursion
- (goto-char (point-min))
- (search-forward "\n\^_")
- (1- (point)))
- (point-max)))
- (while (and (not give-up)
- (or (null found)
- (not (funcall isearch-filter-predicate beg-found found))))
- (let ((search-spaces-regexp Info-search-whitespace-regexp))
- (if (if backward
- (re-search-backward regexp bound t)
- (re-search-forward regexp bound t))
- (setq found (point) beg-found (if backward (match-end 0)
- (match-beginning 0)))
- (setq give-up t))))))
-
- (when (and isearch-mode Info-isearch-search
- (not Info-isearch-initial-node)
- (not bound)
- (or give-up (and found (not (and (> found opoint-min)
- (< found opoint-max))))))
+ (setq Info-search-case-fold case-fold-search)
+ (let* ((backward (eq direction 'backward))
+ (onode Info-current-node)
+ (ofile Info-current-file)
+ (opoint (point))
+ (opoint-min (point-min))
+ (opoint-max (point-max))
+ (ostart (window-start))
+ (osubfile Info-current-subfile)
+ (found
+ (save-excursion
+ (save-restriction
+ (widen)
+ (Info--search-loop regexp bound backward)))))
+
+ (unless (or (not isearch-mode) (not Info-isearch-search)
+ Info-isearch-initial-node
+ bound
+ (and found (> found opoint-min) (< found opoint-max)))
(signal 'search-failed (list regexp "end of node")))
;; If no subfiles, give error now.
- (if give-up
- (if (null Info-current-subfile)
- (if isearch-mode
- (signal 'search-failed (list regexp "end of manual"))
- (let ((search-spaces-regexp Info-search-whitespace-regexp))
- (if backward
- (re-search-backward regexp)
- (re-search-forward regexp))))
- (setq found nil)))
+ (unless (or found Info-current-subfile)
+ (if isearch-mode
+ (signal 'search-failed (list regexp "end of manual"))
+ (let ((search-spaces-regexp Info-search-whitespace-regexp))
+ (if backward
+ (re-search-backward regexp)
+ (re-search-forward regexp)))))
(if (and bound (not found))
(signal 'search-failed (list regexp)))
(while list
(message "Searching subfile %s..." (cdr (car list)))
(Info-read-subfile (car (car list)))
- (when backward
- ;; Hide Info file header for backward search
- (narrow-to-region (save-excursion
- (goto-char (point-min))
- (search-forward "\n\^_")
- (1- (point)))
- (point-max))
- (goto-char (point-max)))
+ (when backward (goto-char (point-max)))
(setq list (cdr list))
- (setq give-up nil found nil)
- (while (and (not give-up)
- (or (null found)
- (not (funcall isearch-filter-predicate beg-found found))))
- (let ((search-spaces-regexp Info-search-whitespace-regexp))
- (if (if backward
- (re-search-backward regexp nil t)
- (re-search-forward regexp nil t))
- (setq found (point) beg-found (if backward (match-end 0)
- (match-beginning 0)))
- (setq give-up t))))
- (if give-up
- (setq found nil))
+ (setq found (Info--search-loop regexp nil backward))
(if found
(setq list nil)))
(if found
"[" (or allowedchars "^,\t\n") " ]" ;The last char can't be a space.
"\\|\\)\\)")) ;Allow empty node names.
-;;; For compatibility; other files have used this name.
+;; For compatibility; other files have used this name.
(defun Info-following-node-name ()
(and (looking-at (Info-following-node-name-re))
(match-string-no-properties 1)))
(interactive)
;; In case another window is currently selected
(save-window-excursion
- (or (eq major-mode 'Info-mode) (switch-to-buffer "*info*"))
+ (or (derived-mode-p 'Info-mode) (switch-to-buffer "*info*"))
(Info-goto-node (Info-extract-pointer "next"))))
(defun Info-prev ()
(interactive)
;; In case another window is currently selected
(save-window-excursion
- (or (eq major-mode 'Info-mode) (switch-to-buffer "*info*"))
+ (or (derived-mode-p 'Info-mode) (switch-to-buffer "*info*"))
(Info-goto-node (Info-extract-pointer "prev[ious]*" "previous"))))
(defun Info-up (&optional same-file)
(interactive)
;; In case another window is currently selected
(save-window-excursion
- (or (eq major-mode 'Info-mode) (switch-to-buffer "*info*"))
+ (or (derived-mode-p 'Info-mode) (switch-to-buffer "*info*"))
(let ((old-node Info-current-node)
(old-file Info-current-file)
(node (Info-extract-pointer "up")) p)
(defvar Info-complete-menu-buffer)
(defvar Info-complete-next-re nil)
(defvar Info-complete-nodes nil)
-(defvar Info-complete-cache nil)
+(defvar-local Info-complete-cache nil)
(defconst Info-node-spec-re
(concat (Info-following-node-name-re "^.,:") "[,:.]")
(unless (equal Info-current-node orignode)
(Info-goto-node orignode))
;; Update the cache.
- (set (make-local-variable 'Info-complete-cache)
+ (setq Info-complete-cache
(list Info-current-file Info-current-node
Info-complete-next-re string completions
Info-complete-nodes)))
is searched using the text property PROP. Move point to the closest found position
of either a cross-reference found by `re-search-forward' or a link found by
`next-single-char-property-change'. Return the new position of point, or nil."
- (let ((pcref (save-excursion (re-search-forward pat nil t)))
+ (let ((pxref (save-excursion (re-search-forward pat nil t)))
(plink (next-single-char-property-change (point) prop)))
(when (and (< plink (point-max)) (not (get-char-property plink prop)))
(setq plink (next-single-char-property-change plink prop)))
(if (< plink (point-max))
- (if (and pcref (<= pcref plink))
+ (if (and pxref (<= pxref plink))
(goto-char (or (match-beginning 1) (match-beginning 0)))
(goto-char plink))
- (if pcref (goto-char (or (match-beginning 1) (match-beginning 0)))))))
+ (if pxref (goto-char (or (match-beginning 1) (match-beginning 0)))))))
(defun Info-prev-reference-or-link (pat prop)
"Move point to the previous pattern-based cross-reference or property-based link.
is searched using the text property PROP. Move point to the closest found position
of either a cross-reference found by `re-search-backward' or a link found by
`previous-single-char-property-change'. Return the new position of point, or nil."
- (let ((pcref (save-excursion (re-search-backward pat nil t)))
+ (let ((pxref (save-excursion (re-search-backward pat nil t)))
(plink (previous-single-char-property-change (point) prop)))
(when (and (> plink (point-min)) (not (get-char-property plink prop)))
(setq plink (previous-single-char-property-change plink prop)))
(if (> plink (point-min))
- (if (and pcref (>= pcref plink))
+ (if (and pxref (>= pxref plink))
(goto-char (or (match-beginning 1) (match-beginning 0)))
(goto-char plink))
- (if pcref (goto-char (or (match-beginning 1) (match-beginning 0)))))))
+ (if pxref (goto-char (or (match-beginning 1) (match-beginning 0)))))))
(defun Info-next-reference (&optional recur count)
"Move cursor to the next cross-reference or menu item in the node.
(= (aref topic 0) ?:))
(setq topic (substring topic 1)))
(let ((orignode Info-current-node)
- (pattern (format "\n\\* +\\([^\n]*%s[^\n]*\\):[ \t]+\\([^\n]*\\)\\.\\(?:[ \t\n]*(line +\\([0-9]+\\))\\)?"
+ (pattern (format "\n\\* +\\([^\n]*\\(%s\\)[^\n]*\\):[ \t]+\\([^\n]*\\)\\.\\(?:[ \t\n]*(line +\\([0-9]+\\))\\)?"
(regexp-quote topic)))
node (nodes (Info-index-nodes))
(ohist-list Info-history-list)
(progn
(goto-char (point-min))
(while (re-search-forward pattern nil t)
- (push (list (match-string-no-properties 1)
- (match-string-no-properties 2)
- Info-current-node
- (string-to-number (concat "0"
- (match-string 3))))
- matches))
+ (let ((entry (match-string-no-properties 1))
+ (nodename (match-string-no-properties 3))
+ (line (string-to-number (concat "0" (match-string 4)))))
+ (add-text-properties
+ (- (match-beginning 2) (match-beginning 1))
+ (- (match-end 2) (match-beginning 1))
+ '(face info-index-match) entry)
+ (push (list entry nodename Info-current-node line) matches)))
(setq nodes (cdr nodes) node (car nodes)))
(Info-goto-node node))
(or matches
Return a list of matches where each element is in the format
\((FILENAME INDEXTEXT NODENAME LINENUMBER))."
(unless (string= string "")
- (let ((pattern (format "\n\\* +\\([^\n]*%s[^\n]*\\):[ \t]+\\([^\n]+\\)\\.\\(?:[ \t\n]*(line +\\([0-9]+\\))\\)?"
+ (let ((pattern (format "\n\\* +\\([^\n]*\\(%s\\)[^\n]*\\):[ \t]+\\([^\n]+\\)\\.\\(?:[ \t\n]*(line +\\([0-9]+\\))\\)?"
(regexp-quote string)))
(ohist Info-history)
(ohist-list Info-history-list)
(goto-char (point-min))
(re-search-forward "\\* Menu: *\n" nil t)
(while (re-search-forward "\\*.*: *(\\([^)]+\\))" nil t)
- ;; add-to-list makes sure we don't have duplicates in `manuals',
+ ;; Make sure we don't have duplicates in `manuals',
;; so that the following dolist loop runs faster.
- (add-to-list 'manuals (match-string 1)))
+ (cl-pushnew (match-string 1) manuals :test #'equal))
(dolist (manual (nreverse manuals))
(message "Searching %s" manual)
(condition-case err
(progn
(goto-char (point-min))
(while (re-search-forward pattern nil t)
- (setq matches
- (cons (list manual
- (match-string-no-properties 1)
- (match-string-no-properties 2)
- (match-string-no-properties 3))
- matches)))
+ (let ((entry (match-string-no-properties 1))
+ (nodename (match-string-no-properties 3))
+ (line (match-string-no-properties 4)))
+ (add-text-properties
+ (- (match-beginning 2) (match-beginning 1))
+ (- (match-end 2) (match-beginning 1))
+ '(face info-index-match) entry)
+ (setq matches (cons (list manual entry nodename line)
+ matches))))
(setq nodes (cdr nodes) node (car nodes)))
(Info-goto-node node))))
(error
(defvar finder-keywords-hash)
(defvar package--builtins) ; finder requires package
+(defun info--prettify-description (desc)
+ (if (stringp desc)
+ (with-temp-buffer
+ (insert desc)
+ (if (equal ?. (char-before))
+ (delete-char -1))
+ (goto-char (point-min))
+ (or (let (case-fold-search) (looking-at-p "\\.\\|[[:upper:]]"))
+ (capitalize-word 1))
+ (buffer-string))
+ desc))
+
(defun Info-finder-find-node (_filename nodename &optional _no-going-back)
"Finder-specific implementation of `Info-find-node-2'."
(require 'finder)
(insert (format "* %s %s.\n"
(concat (symbol-name keyword) ": "
"Keyword " (symbol-name keyword) ".")
- (cdr assoc))))))
+ (info--prettify-description (cdr assoc)))))))
((equal nodename "Keyword unknown")
;; Display unknown keywords
(insert (format "\n\^_\nFile: %s, Node: %s, Up: Top\n\n"
(when (vectorp desc)
(insert (format "* %-16s %s.\n"
(concat (symbol-name (car package)) "::")
- (aref desc 2)))))))
+ (info--prettify-description (aref desc 2))))))))
((string-match "\\`Keyword " nodename)
(setq nodename (substring nodename (match-end 0)))
;; Display packages that match the keyword
hits desc)
(dolist (keyword keywords)
(push (copy-tree (gethash keyword finder-keywords-hash)) hits))
- (setq hits (delete-dups (apply 'append hits)))
+ (setq hits (delete-dups (apply 'append hits))
+ ;; Not a meaningful package.
+ hits (delete 'emacs hits)
+ hits (sort hits (lambda (a b) (string< (symbol-name a)
+ (symbol-name b)))))
(dolist (package hits)
(setq desc (cdr-safe (assq package package--builtins)))
(when (vectorp desc)
(insert (format "* %-16s %s.\n"
(concat (symbol-name package) "::")
- (aref desc 2)))))))
+ (info--prettify-description (aref desc 2))))))))
(t
;; Display commentary section
(insert (format "\n\^_\nFile: %s, Node: %s, Up: Top\n\n"
Info-finder-file nodename))
- (insert "Finder Commentary\n")
- (insert "*****************\n\n")
+ (insert "Package Description\n")
+ (insert "*******************\n\n")
(insert
- "Commentary section of the package `" nodename "':\n\n")
- (let ((str (lm-commentary (find-library-name nodename))))
+ "Description of the package `" nodename "':\n\n")
+ ;; This assumes that a file named package.el exists,
+ ;; which is not always true. E.g. for the nxml package,
+ ;; there is no "nxml.el" (it's nxml-mode.el).
+ ;; But package.el makes the same assumption.
+ ;; I think nxml is the only exception - maybe it should be just be renamed.
+ (let ((str (ignore-errors (lm-commentary (find-library-name nodename)))))
(if (null str)
- (insert "Can't find any Commentary section\n\n")
+ (insert "Can't find package description.\n\n")
(insert
(with-temp-buffer
(insert str)
((setq node (Info-get-token (point) "\\*note[ \n\t]+"
"\\*note[ \n\t]+\\([^:]*\\):\\(:\\|[ \n\t]*(\\)?"))
(Info-follow-reference node fork))
- ;; menu item: node name
- ((setq node (Info-get-token (point) "\\* +" "\\* +\\([^:]*\\)::"))
- (Info-goto-node node fork))
- ;; menu item: node name or index entry
- ((Info-get-token (point) "\\* +" "\\* +\\(.*\\): ")
- (beginning-of-line)
- (forward-char 2)
- (setq node (Info-extract-menu-node-name nil (Info-index-node)))
- (Info-goto-node node fork))
- ((setq node (Info-get-token (point) "Up: " "Up: \\([^,\n\t]*\\)"))
- (Info-goto-node node fork))
- ((setq node (Info-get-token (point) "Next: " "Next: \\([^,\n\t]*\\)"))
- (Info-goto-node node fork))
- ((setq node (Info-get-token (point) "File: " "File: \\([^,\n\t]*\\)"))
- (Info-goto-node "Top" fork))
- ((setq node (Info-get-token (point) "Prev: " "Prev: \\([^,\n\t]*\\)"))
- (Info-goto-node node fork))
;; footnote
((setq node (Info-get-token (point) "(" "\\(([0-9]+)\\)"))
(let ((old-point (point)) new-point)
(progn
(goto-char new-point)
(setq node t))
- (setq node nil)))))
+ (setq node nil))))
+ ;; menu item: node name
+ ((setq node (Info-get-token (point) "\\* +" "\\* +\\([^:]*\\)::"))
+ (Info-goto-node node fork))
+ ;; menu item: node name or index entry
+ ((Info-get-token (point) "\\* +" "\\* +\\(.*\\): ")
+ (beginning-of-line)
+ (forward-char 2)
+ (setq node (Info-extract-menu-node-name nil (Info-index-node)))
+ (Info-goto-node node fork))
+ ((setq node (Info-get-token (point) "Up: " "Up: \\([^,\n\t]*\\)"))
+ (Info-goto-node node fork))
+ ((setq node (Info-get-token (point) "Next: " "Next: \\([^,\n\t]*\\)"))
+ (Info-goto-node node fork))
+ ((setq node (Info-get-token (point) "File: " "File: \\([^,\n\t]*\\)"))
+ (Info-goto-node "Top" fork))
+ ((setq node (Info-get-token (point) "Prev: " "Prev: \\([^,\n\t]*\\)"))
+ (Info-goto-node node fork)))
node))
(defun Info-mouse-follow-link (click)
(define-key map "f" 'Info-follow-reference)
(define-key map "g" 'Info-goto-node)
(define-key map "h" 'Info-help)
+ ;; This is for compatibility with standalone info (>~ version 5.2).
+ ;; Though for some time, standalone info had H and h reversed.
+ ;; See <http://debbugs.gnu.org/16455>.
+ (define-key map "H" 'describe-mode)
(define-key map "i" 'Info-index)
(define-key map "I" 'Info-virtual-index)
(define-key map "l" 'Info-history-back)
(defun Info-menu-update ()
"Update the Info menu for the current node."
(condition-case nil
- (if (or (not (eq major-mode 'Info-mode))
+ (if (or (not (derived-mode-p 'Info-mode))
(equal (list Info-current-file Info-current-node)
Info-menu-last-node))
()
st)
"Syntax table used in `Info-mode'.")
+(defface Info-quoted
+ '((t :family "courier"))
+ "Face used for quoted elements.")
+
+(defvar Info-mode-font-lock-keywords
+ '(("‘\\([^’]*\\)’" (1 'Info-quoted))))
+
;; Autoload cookie needed by desktop.el
;;;###autoload
-(define-derived-mode Info-mode nil "Info"
+(define-derived-mode Info-mode nil "Info" ;FIXME: Derive from special-mode?
"Info mode provides commands for browsing through the Info documentation tree.
Documentation in Info is divided into \"nodes\", each of which discusses
one topic and contains references to other nodes which discuss related
(add-hook 'activate-menubar-hook 'Info-menu-update nil t)
(setq case-fold-search t)
(setq buffer-read-only t)
- (make-local-variable 'Info-current-file)
- (make-local-variable 'Info-current-subfile)
- (make-local-variable 'Info-current-node)
- (set (make-local-variable 'Info-tag-table-marker) (make-marker))
- (set (make-local-variable 'Info-tag-table-buffer) nil)
- (make-local-variable 'Info-history)
- (make-local-variable 'Info-history-forward)
- (make-local-variable 'Info-index-alternatives)
+ (setq Info-tag-table-marker (make-marker))
(if Info-use-header-line ; do not override global header lines
(setq header-line-format
'(:eval (get-text-property (point-min) 'header-line))))
- (set (make-local-variable 'tool-bar-map) info-tool-bar-map)
+ (setq-local tool-bar-map info-tool-bar-map)
;; This is for the sake of the invisible text we use handling titles.
- (set (make-local-variable 'line-move-ignore-invisible) t)
- (set (make-local-variable 'desktop-save-buffer)
- 'Info-desktop-buffer-misc-data)
- (set (make-local-variable 'widen-automatically) nil)
+ (setq-local line-move-ignore-invisible t)
+ (setq-local desktop-save-buffer 'Info-desktop-buffer-misc-data)
+ (setq-local widen-automatically nil)
(add-hook 'kill-buffer-hook 'Info-kill-buffer nil t)
(add-hook 'clone-buffer-hook 'Info-clone-buffer nil t)
(add-hook 'change-major-mode-hook 'font-lock-defontify nil t)
(add-hook 'isearch-mode-hook 'Info-isearch-start nil t)
- (set (make-local-variable 'isearch-search-fun-function)
- 'Info-isearch-search)
- (set (make-local-variable 'isearch-wrap-function)
- 'Info-isearch-wrap)
- (set (make-local-variable 'isearch-push-state-function)
- 'Info-isearch-push-state)
- (set (make-local-variable 'isearch-filter-predicate)
- 'Info-isearch-filter)
- (set (make-local-variable 'revert-buffer-function)
- 'Info-revert-buffer-function)
+ (setq-local isearch-search-fun-function #'Info-isearch-search)
+ (setq-local isearch-wrap-function #'Info-isearch-wrap)
+ (setq-local isearch-push-state-function #'Info-isearch-push-state)
+ (setq-local isearch-filter-predicate #'Info-isearch-filter)
+ (setq-local revert-buffer-function #'Info-revert-buffer-function)
+ (setq-local font-lock-defaults '(Info-mode-font-lock-keywords t t))
(Info-set-mode-line)
- (set (make-local-variable 'bookmark-make-record-function)
- 'Info-bookmark-make-record))
+ (setq-local bookmark-make-record-function #'Info-bookmark-make-record))
;; When an Info buffer is killed, make sure the associated tags buffer
;; is killed too.
(defun Info-kill-buffer ()
- (and (eq major-mode 'Info-mode)
+ (and (derived-mode-p 'Info-mode)
Info-tag-table-buffer
(kill-buffer Info-tag-table-buffer)))
(copy-marker (marker-position m)))
(make-marker))))))
-(defvar Info-edit-map (let ((map (make-sparse-keymap)))
- (set-keymap-parent map text-mode-map)
- (define-key map "\C-c\C-c" 'Info-cease-edit)
- map)
+(define-obsolete-variable-alias 'Info-edit-map 'Info-edit-mode-map "24.1")
+(defvar Info-edit-mode-map (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map text-mode-map)
+ (define-key map "\C-c\C-c" 'Info-cease-edit)
+ map)
"Local keymap used within `e' command of Info.")
-(make-obsolete-variable 'Info-edit-map
+(make-obsolete-variable 'Info-edit-mode-map
"editing Info nodes by hand is not recommended."
"24.4")
;; Info-edit mode is suitable only for specially formatted data.
(put 'Info-edit-mode 'mode-class 'special)
-(defun Info-edit-mode ()
+(define-derived-mode Info-edit-mode text-mode "Info Edit"
"Major mode for editing the contents of an Info node.
Like text mode with the addition of `Info-cease-edit'
-which returns to Info mode for browsing.
-\\{Info-edit-map}"
- (use-local-map Info-edit-map)
- (setq major-mode 'Info-edit-mode)
- (setq mode-name "Info Edit")
- (kill-local-variable 'mode-line-buffer-identification)
+which returns to Info mode for browsing."
(setq buffer-read-only nil)
(force-mode-line-update)
- (buffer-enable-undo (current-buffer))
- (run-mode-hooks 'Info-edit-mode-hook))
+ (buffer-enable-undo (current-buffer)))
(make-obsolete 'Info-edit-mode
"editing Info nodes by hand is not recommended." "24.4")
(interactive)
(Info-edit-mode)
(message "%s" (substitute-command-keys
- "Editing: Type \\<Info-edit-map>\\[Info-cease-edit] to return to info")))
+ "Editing: Type \\<Info-edit-mode-map>\\[Info-cease-edit] to return to info")))
(put 'Info-edit 'disabled "Editing Info nodes by hand is not recommended.
This feature will be removed in future.")
(and (buffer-modified-p)
(y-or-n-p "Save the file? ")
(save-buffer))
- (use-local-map Info-mode-map)
- (setq major-mode 'Info-mode)
- (setq mode-name "Info")
- (Info-set-mode-line)
- (setq buffer-read-only t)
+ (Info-mode)
(force-mode-line-update)
(and (marker-position Info-tag-table-marker)
(buffer-modified-p)
("ietf-drums" . "emacs-mime") ("quoted-printable" . "emacs-mime")
("binhex" . "emacs-mime") ("uudecode" . "emacs-mime")
("mailcap" . "emacs-mime") ("mm" . "emacs-mime")
- ("mml" . "emacs-mime"))
+ ("mml" . "emacs-mime")
+ "tramp" "dbus")
"List of Info files that describe Emacs commands.
An element can be a file name, or a list of the form (PREFIX . FILE)
where PREFIX is a name prefix and FILE is the file to look in.
;; Get Info running, and pop to it in another window.
(save-window-excursion
(info))
- (or (eq major-mode 'Info-mode) (pop-to-buffer "*info*"))
+ (or (derived-mode-p 'Info-mode) (pop-to-buffer "*info*"))
;; Bind Info-history to nil, to prevent the last Index node
;; visited by Info-find-emacs-command-nodes from being
;; pushed onto the history.
;;; Speedbar support:
;; These functions permit speedbar to display the "tags" in the
;; current Info node.
-(eval-when-compile (require 'speedbar))
+(eval-when-compile (require 'speedbar)) ; for speedbar-with-writable
(declare-function speedbar-add-expansion-list "speedbar" (new-list))
(declare-function speedbar-center-buffer-smartly "speedbar" ())
(speedbar-change-initial-expansion-list "Info")
)
+;; speedbar loads dframe at runtime.
+(declare-function dframe-select-attached-frame "dframe" (&optional frame))
+(declare-function dframe-current-frame "dframe" (frame-var desired-major-mode))
+
(defun Info-speedbar-hierarchy-buttons (_directory depth &optional node)
"Display an Info directory hierarchy in speedbar.
DIRECTORY is the current directory in the attached frame.
NODESPEC is a string of the form: (file)node."
;; Set up a buffer we can use to fake-out Info.
(with-current-buffer (get-buffer-create " *info-browse-tmp*")
- (if (not (equal major-mode 'Info-mode))
+ (if (not (derived-mode-p 'Info-mode))
(Info-mode))
;; Get the node into this buffer
(if (not (string-match "^(\\([^)]+\\))\\([^.]+\\)$" nodespec))