X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/8c4b24b2ab14be6d33d4e979f3de6fb85eff6518..02bf443d2ea21189dc0e8ac0bb741db9fa8fc365:/lisp/info.el diff --git a/lisp/info.el b/lisp/info.el index c276420fb7..78e0dda7cf 100644 --- a/lisp/info.el +++ b/lisp/info.el @@ -1,6 +1,6 @@ ;; info.el --- info package for Emacs -;; Copyright (C) 1985-1986, 1992-2013 Free Software Foundation, Inc. +;; Copyright (C) 1985-1986, 1992-2014 Free Software Foundation, Inc. ;; Maintainer: FSF ;; Keywords: help @@ -59,15 +59,6 @@ to the user." :group 'info :version "24.1") -(defcustom Info-enable-edit nil - "Non-nil means the \\\\[Info-edit] command in Info can edit the current node. -This is convenient if you want to write Info files by hand. -However, we recommend that you not do this. -It is better to write a Texinfo file and generate the Info file from that, -because that gives you a printed manual as well." - :type 'boolean - :group 'info) - (defvar Info-enable-active-nodes nil "Non-nil allows Info to execute Lisp code associated with nodes. The Lisp code is executed when the node is selected.") @@ -167,6 +158,12 @@ A header-line does not scroll with the rest of the buffer." "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 @@ -375,6 +372,9 @@ with wrapping around the current Info node." (defvar Info-edit-mode-hook nil "Hooks run when `Info-edit-mode' is called.") +(make-obsolete-variable 'Info-edit-mode-hook + "editing Info nodes by hand is not recommended." "24.4") + (defvar 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. @@ -732,6 +732,14 @@ in `Info-file-supports-index-cookies-list'." (Info-default-dirs)) (split-string path sep)) (Info-default-dirs)))) + ;; If we are running uninstalled, our own Info files should + ;; always come first. If INFOPATH was set, they might not. + (and path + installation-directory + (let ((dir (expand-file-name "info/" installation-directory))) + (when (file-directory-p dir) + (setq Info-directory-list (delete dir Info-directory-list)) + (push dir Info-directory-list)))) ;; For a self-contained (ie relocatable) NS build, AFAICS we ;; always want the included info directory to be at the head of ;; the search path, unless it's already in INFOPATH somewhere. @@ -790,7 +798,7 @@ See a list of available Info commands in `Info-mode'." (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 @@ -917,23 +925,30 @@ just return nil (no error)." (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) @@ -957,7 +972,7 @@ otherwise, that defaults to `Top'." "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))) @@ -1010,7 +1025,7 @@ which the match was found." (+ (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 @@ -1020,10 +1035,11 @@ FOUND-ANCHOR is non-nil if a `Ref:' was matched, POS is the position 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) @@ -1046,19 +1062,21 @@ Value is the position at which a match was found, or nil if not found." (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) @@ -1167,7 +1185,7 @@ a case-insensitive match is tried." ;; 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). @@ -1194,7 +1212,7 @@ a case-insensitive match is tried." ;; 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))) @@ -1230,12 +1248,14 @@ a case-insensitive match is tried." (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. @@ -1530,11 +1550,14 @@ a case-insensitive match is tried." ;; 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." @@ -1585,17 +1608,20 @@ escaped (\\\",\\\\)." "")) (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))) @@ -1698,7 +1724,7 @@ escaped (\\\",\\\\)." ;; 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 @@ -1708,7 +1734,11 @@ in the Info file FILENAME after the closing parenthesis in (FILENAME). 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 @@ -1727,7 +1757,7 @@ If FORK is a string, it is the name to use for the new buffer." (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) @@ -1891,6 +1921,30 @@ the Top node in FILENAME." (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." @@ -1906,54 +1960,35 @@ 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))) @@ -1994,28 +2029,9 @@ If DIRECTION is `backward', search in the reverse direction." (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 @@ -2151,7 +2167,7 @@ and is not in the header line or a tag table." (let ((backward (< found beg-found))) (not (or - (and (not (eq search-invisible t)) + (and (not search-invisible) (if backward (or (text-property-not-all found beg-found 'invisible nil) (text-property-not-all found beg-found 'display nil)) @@ -2209,7 +2225,7 @@ End of submatch 0, 1, and 3 are the same, so you can safely concat." (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 () @@ -2217,7 +2233,7 @@ End of submatch 0, 1, and 3 are the same, so you can safely concat." (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) @@ -2226,7 +2242,7 @@ If SAME-FILE is non-nil, do not move to a different Info 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) @@ -3063,6 +3079,38 @@ See `Info-scroll-down'." (select-window (posn-window (event-start e)))) (Info-scroll-down))) +(defun Info-next-reference-or-link (pat prop) + "Move point to the next pattern-based cross-reference or property-based link. +The next cross-reference is searched using the regexp PAT, and the next link +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 ((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 pxref (<= pxref plink)) + (goto-char (or (match-beginning 1) (match-beginning 0))) + (goto-char plink)) + (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. +The previous cross-reference is searched using the regexp PAT, and the previous 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 ((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 pxref (>= pxref plink)) + (goto-char (or (match-beginning 1) (match-beginning 0))) + (goto-char plink)) + (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. If COUNT is non-nil (interactively with a prefix arg), jump over @@ -3077,14 +3125,13 @@ COUNT cross-references." (old-pt (point)) (case-fold-search t)) (or (eobp) (forward-char 1)) - (or (re-search-forward pat nil t) + (or (Info-next-reference-or-link pat 'link) (progn (goto-char (point-min)) - (or (re-search-forward pat nil t) + (or (Info-next-reference-or-link pat 'link) (progn (goto-char old-pt) (user-error "No cross references in this node"))))) - (goto-char (or (match-beginning 1) (match-beginning 0))) (if (looking-at "\\* Menu:") (if recur (user-error "No cross references in this node") @@ -3105,14 +3152,13 @@ COUNT cross-references." (let ((pat "\\*note[ \n\t]+\\([^:]+\\):\\|^\\* .*:\\|[hf]t?tps?://") (old-pt (point)) (case-fold-search t)) - (or (re-search-backward pat nil t) + (or (Info-prev-reference-or-link pat 'link) (progn (goto-char (point-max)) - (or (re-search-backward pat nil t) + (or (Info-prev-reference-or-link pat 'link) (progn (goto-char old-pt) (user-error "No cross references in this node"))))) - (goto-char (or (match-beginning 1) (match-beginning 0))) (if (looking-at "\\* Menu:") (if recur (user-error "No cross references in this node") @@ -3252,7 +3298,7 @@ Give an empty topic name to go to the Index node itself." (= (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) @@ -3271,12 +3317,14 @@ Give an empty topic name to go to the Index node itself." (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 @@ -3502,7 +3550,7 @@ MATCHES is a list of index matches found by `Info-apropos-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) @@ -3535,12 +3583,15 @@ Return a list of matches where each element is in the format (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 @@ -3830,6 +3881,24 @@ If FORK is non-nil, it is passed to `Info-goto-node'." ((setq node (Info-get-token (point) "\\*note[ \n\t]+" "\\*note[ \n\t]+\\([^:]*\\):\\(:\\|[ \n\t]*(\\)?")) (Info-follow-reference node fork)) + ;; footnote + ((setq node (Info-get-token (point) "(" "\\(([0-9]+)\\)")) + (let ((old-point (point)) new-point) + (save-excursion + (goto-char (point-min)) + (when (re-search-forward "^[ \t]*-+ Footnotes -+$" nil t) + (setq new-point (if (< old-point (point)) + ;; Go to footnote reference + (and (search-forward node nil t) + ;; Put point at beginning of link + (match-beginning 0)) + ;; Go to footnote definition + (search-backward node nil t))))) + (if new-point + (progn + (goto-char new-point) + (setq node t)) + (setq node nil)))) ;; menu item: node name ((setq node (Info-get-token (point) "\\* +" "\\* +\\([^:]*\\)::")) (Info-goto-node node fork)) @@ -3874,6 +3943,7 @@ If FORK is non-nil, it is passed to `Info-goto-node'." (suppress-keymap map) (define-key map "." 'beginning-of-buffer) (define-key map " " 'Info-scroll-up) + (define-key map [?\S-\ ] 'Info-scroll-down) (define-key map "\C-m" 'Info-follow-nearest-node) (define-key map "\t" 'Info-next-reference) (define-key map "\e\t" 'Info-prev-reference) @@ -4025,7 +4095,7 @@ If FORK is non-nil, it is passed to `Info-goto-node'." (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)) () @@ -4218,8 +4288,7 @@ Advanced commands: '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 'isearch-filter-predicate) #'Info-isearch-filter) (set (make-local-variable 'revert-buffer-function) 'Info-revert-buffer-function) (Info-set-mode-line) @@ -4229,7 +4298,7 @@ Advanced commands: ;; 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))) @@ -4246,39 +4315,45 @@ Advanced commands: (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 + "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) (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") (defun Info-edit () - "Edit the contents of this Info node. -Allowed only if variable `Info-enable-edit' is non-nil." + "Edit the contents of this Info node." (interactive) - (or Info-enable-edit - (error "Editing Info nodes is not enabled")) (Info-edit-mode) (message "%s" (substitute-command-keys "Editing: Type \\\\[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.") + +(make-obsolete 'Info-edit + "editing Info nodes by hand is not recommended." "24.4") + (defun Info-cease-edit () "Finish editing Info node; switch back to Info proper." (interactive) @@ -4286,15 +4361,14 @@ Allowed only if variable `Info-enable-edit' is non-nil." (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) (message "Tags may have changed. Use Info-tagify if necessary"))) + +(make-obsolete 'Info-cease-edit + "editing Info nodes by hand is not recommended." "24.4") (defvar Info-file-list-for-emacs '("ediff" "eudc" "forms" "gnus" "info" ("Info" . "info") ("mh" . "mh-e") @@ -4316,7 +4390,8 @@ Allowed only if variable `Info-enable-edit' is non-nil." ("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. @@ -4399,7 +4474,7 @@ COMMAND must be a symbol or string." ;; 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. @@ -4888,6 +4963,21 @@ first line or header line, and for breadcrumb links.") mouse-face highlight help-echo "mouse-2: go to this URL")))) + ;; Fontify footnotes + (goto-char (point-min)) + (when (and not-fontified-p (re-search-forward "^[ \t]*-+ Footnotes -+$" nil t)) + (let ((limit (point))) + (goto-char (point-min)) + (while (re-search-forward "\\(([0-9]+)\\)" nil t) + (add-text-properties (match-beginning 0) (match-end 0) + `(font-lock-face info-xref + link t + mouse-face highlight + help-echo + ,(if (< (point) limit) + "mouse-2: go to footnote definition" + "mouse-2: go to footnote reference")))))) + ;; Hide empty lines at the end of the node. (goto-char (point-max)) (skip-chars-backward "\n") @@ -4899,7 +4989,7 @@ first line or header line, and for breadcrumb links.") ;;; 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" ()) @@ -4961,6 +5051,10 @@ This will add a speedbar major display mode." (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. @@ -5044,7 +5138,7 @@ INDENT is the current indentation depth." 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))