(Info-find-node): Handle cross references to an @anchor.

This commit is contained in:
Richard M. Stallman 1998-07-05 23:57:45 +00:00
parent ad0153e46f
commit 37a3ff5b0b

View file

@ -331,158 +331,188 @@ In standalone mode, \\<Info-mode-map>\\[Info-exit] exits Emacs itself."
;; Expand it.
(if filename
(let (temp temp-downcase found)
(setq filename (substitute-in-file-name filename))
(if (string= (downcase filename) "dir")
(setq found t)
(let ((dirs (if (string-match "^\\./" filename)
;; If specified name starts with `./'
;; then just try current directory.
'("./")
(if (file-name-absolute-p filename)
;; No point in searching for an
;; absolute file name
'(nil)
(if Info-additional-directory-list
(append Info-directory-list
Info-additional-directory-list)
Info-directory-list)))))
;; Search the directory list for file FILENAME.
(while (and dirs (not found))
(setq temp (expand-file-name filename (car dirs)))
(setq temp-downcase
(expand-file-name (downcase filename) (car dirs)))
;; Try several variants of specified name.
(let ((suffix-list Info-suffix-list))
(while (and suffix-list (not found))
(cond ((info-file-exists-p
(info-insert-file-contents-1
temp (car (car suffix-list))))
(setq found temp))
((info-file-exists-p
(info-insert-file-contents-1
temp-downcase (car (car suffix-list))))
(setq found temp-downcase)))
(setq suffix-list (cdr suffix-list))))
(setq dirs (cdr dirs)))))
(if found
(setq filename found)
(error "Info file %s does not exist" filename))))
(setq filename (substitute-in-file-name filename))
(if (string= (downcase filename) "dir")
(setq found t)
(let ((dirs (if (string-match "^\\./" filename)
;; If specified name starts with `./'
;; then just try current directory.
'("./")
(if (file-name-absolute-p filename)
;; No point in searching for an
;; absolute file name
'(nil)
(if Info-additional-directory-list
(append Info-directory-list
Info-additional-directory-list)
Info-directory-list)))))
;; Search the directory list for file FILENAME.
(while (and dirs (not found))
(setq temp (expand-file-name filename (car dirs)))
(setq temp-downcase
(expand-file-name (downcase filename) (car dirs)))
;; Try several variants of specified name.
(let ((suffix-list Info-suffix-list))
(while (and suffix-list (not found))
(cond ((info-file-exists-p
(info-insert-file-contents-1
temp (car (car suffix-list))))
(setq found temp))
((info-file-exists-p
(info-insert-file-contents-1
temp-downcase (car (car suffix-list))))
(setq found temp-downcase)))
(setq suffix-list (cdr suffix-list))))
(setq dirs (cdr dirs)))))
(if found
(setq filename found)
(error "Info file %s does not exist" filename))))
;; Record the node we are leaving.
(if (and Info-current-file (not no-going-back))
(setq Info-history
(cons (list Info-current-file Info-current-node (point))
Info-history)))
;; Go into info buffer.
(or (eq major-mode 'Info-mode) (pop-to-buffer "*info*"))
(buffer-disable-undo (current-buffer))
(or (eq major-mode 'Info-mode)
(Info-mode))
;; Record the node we are leaving.
(if (and Info-current-file (not no-going-back))
(setq Info-history
(cons (list Info-current-file Info-current-node (point))
Info-history)))
(widen)
(setq Info-current-node nil)
(unwind-protect
(progn
;; Switch files if necessary
(or (null filename)
(equal Info-current-file filename)
(let ((buffer-read-only nil))
(setq Info-current-file nil
Info-current-subfile nil
Info-current-file-completions nil
buffer-file-name nil)
(erase-buffer)
(if (eq filename t)
(Info-insert-dir)
(info-insert-file-contents filename t)
(setq default-directory (file-name-directory filename)))
(set-buffer-modified-p nil)
;; See whether file has a tag table. Record the location if yes.
(goto-char (point-max))
(forward-line -8)
;; Use string-equal, not equal, to ignore text props.
(if (not (or (string-equal nodename "*")
(not
(search-forward "\^_\nEnd tag table\n" nil t))))
(let (pos)
;; We have a tag table. Find its beginning.
;; Is this an indirect file?
(search-backward "\nTag table:\n")
(setq pos (point))
(if (save-excursion
(forward-line 2)
(looking-at "(Indirect)\n"))
;; It is indirect. Copy it to another buffer
;; and record that the tag table is in that buffer.
(let ((buf (current-buffer))
(tagbuf
(or Info-tag-table-buffer
(generate-new-buffer " *info tag table*"))))
(setq Info-tag-table-buffer tagbuf)
(save-excursion
(set-buffer tagbuf)
;; Switch files if necessary
(or (null filename)
(equal Info-current-file filename)
(let ((buffer-read-only nil))
(setq Info-current-file nil
Info-current-subfile nil
Info-current-file-completions nil
buffer-file-name nil)
(erase-buffer)
(if (eq filename t)
(Info-insert-dir)
(info-insert-file-contents filename t)
(setq default-directory (file-name-directory filename)))
(set-buffer-modified-p nil)
;; See whether file has a tag table. Record the location if yes.
(goto-char (point-max))
(forward-line -8)
;; Use string-equal, not equal, to ignore text props.
(if (not (or (string-equal nodename "*")
(not
(search-forward "\^_\nEnd tag table\n" nil t))))
(let (pos)
;; We have a tag table. Find its beginning.
;; Is this an indirect file?
(search-backward "\nTag table:\n")
(setq pos (point))
(if (save-excursion
(forward-line 2)
(looking-at "(Indirect)\n"))
;; It is indirect. Copy it to another buffer
;; and record that the tag table is in that buffer.
(let ((buf (current-buffer))
(tagbuf
(or Info-tag-table-buffer
(generate-new-buffer " *info tag table*"))))
(setq Info-tag-table-buffer tagbuf)
(save-excursion
(set-buffer tagbuf)
(buffer-disable-undo (current-buffer))
(setq case-fold-search t)
(erase-buffer)
(insert-buffer-substring buf))
(set-marker Info-tag-table-marker
(match-end 0) tagbuf))
(set-marker Info-tag-table-marker pos)))
(set-marker Info-tag-table-marker nil))
(setq Info-current-file
(if (eq filename t) "dir" filename))))
;; Use string-equal, not equal, to ignore text props.
(if (string-equal nodename "*")
(progn (setq Info-current-node nodename)
(Info-set-mode-line))
;; Search file for a suitable node.
(let ((guesspos (point-min))
(regexp (concat "Node: *" (regexp-quote nodename) " *[,\t\n\177]")))
;; First get advice from tag table if file has one.
;; Also, if this is an indirect info file,
;; read the proper subfile into this buffer.
(if (marker-position Info-tag-table-marker)
(save-excursion
(let ((m Info-tag-table-marker)
found found-mode)
(save-excursion
(set-buffer (marker-buffer m))
(goto-char m)
(beginning-of-line) ;so re-search will work.
(setq found (re-search-forward regexp nil t))
(if found
(setq guesspos (read (current-buffer))))
(setq found-mode major-mode))
(if found
(progn
;; If this is an indirect file, determine
;; which file really holds this node and
;; read it in.
(if (not (eq found-mode 'Info-mode))
;; Note that the current buffer must be
;; the *info* buffer on entry to
;; Info-read-subfile. Thus the hackery
;; above.
(setq guesspos (Info-read-subfile guesspos))))
(error "No such node: %s" nodename)))))
(goto-char (max (point-min) (- (byte-to-position guesspos) 1000)))
;; Now search from our advised position (or from beg of buffer)
;; to find the actual node.
(catch 'foo
(while (search-forward "\n\^_" nil t)
(forward-line 1)
(let ((beg (point)))
(forward-line 1)
(if (re-search-backward regexp beg t)
(throw 'foo t))))
(error "No such node: %s" nodename)))
(Info-select-node)))
(setq case-fold-search t)
(erase-buffer)
(insert-buffer-substring buf))
(set-marker Info-tag-table-marker
(match-end 0) tagbuf))
(set-marker Info-tag-table-marker pos)))
(set-marker Info-tag-table-marker nil))
(setq Info-current-file
(if (eq filename t) "dir" filename))))
;; Use string-equal, not equal, to ignore text props.
(if (string-equal nodename "*")
(progn (setq Info-current-node nodename)
(Info-set-mode-line))
;; Possibilities:
;;
;; 1. Anchor found in tag table
;; 2. Anchor *not* in tag table
;;
;; 3. Node found in tag table
;; 4. Node *not* found in tag table, but found in file
;; 5. Node *not* in tag table, and *not* in file
;;
;; *Or* the same, but in an indirect subfile.
;; Search file for a suitable node.
(let ((guesspos (point-min))
(regexp
(concat "\\(Node:\\|Ref:\\) *"
(regexp-quote nodename)
" *[,\t\n\177]")))
;; First, search a tag table, if any
(if (marker-position Info-tag-table-marker)
(let (found-in-tag-table
found-mode
(m Info-tag-table-marker))
(save-excursion
(set-buffer (marker-buffer m))
(goto-char m)
(beginning-of-line) ; so re-search will work.
;; Search tag table
(setq found-in-tag-table
(re-search-forward regexp nil t))
(if found-in-tag-table
(setq guesspos (read (current-buffer))))
(setq found-mode major-mode))
;; Indirect file among split files
(if found-in-tag-table
(progn
;; If this is an indirect file, determine
;; which file really holds this node and
;; read it in.
(if (not (eq found-mode 'Info-mode))
;; Note that the current buffer must be
;; the *info* buffer on entry to
;; Info-read-subfile. Thus the hackery
;; above.
(setq guesspos (Info-read-subfile guesspos)))))
;; Handle anchor
(if (and found-in-tag-table
(string-equal "Ref:" (match-string 1)))
(goto-char guesspos)
;; Else we may have a node, which we search for:
(goto-char (max (point-min) (- guesspos 1000)))
;; Now search from our advised position
;; (or from beg of buffer)
;; to find the actual node.
(catch 'foo
(while (search-forward "\n\^_" nil t)
(forward-line 1)
(let ((beg (point)))
(forward-line 1)
(if (re-search-backward regexp beg t)
(progn
(beginning-of-line)
(throw 'foo t)))))
(error
"No such anchor in tag table or node in tag table or file: %s"
nodename))))))
(Info-select-node)))
;; 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)))))
(goto-char (point-min)))
(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))))))
;; Cache the contents of the (virtual) dir file, once we have merged
;; it for the first time, so we can save time subsequently.
@ -637,8 +667,6 @@ In standalone mode, \\<Info-mode-map>\\[Info-exit] exits Emacs itself."
;; Note that on entry to this function the current-buffer must be the
;; *info* buffer; not the info tags buffer.
;; nodepos should be a byte-position such as is found in
;; the Info file tags table.
(defun Info-read-subfile (nodepos)
;; NODEPOS is either a position (in the Info file as a whole,
;; not relative to a subfile) or the name of a subfile.