-(defun Info-next-reference (&optional recur)
- "Move cursor to the next cross-reference or menu item in the node."
- (interactive)
- (let ((pat "\\*note[ \n\t]+\\([^:]+\\):\\|^\\* .*:\\|[hf]t?tps?://")
- (old-pt (point))
- (case-fold-search t))
- (or (eobp) (forward-char 1))
- (or (re-search-forward pat nil t)
- (progn
- (goto-char (point-min))
- (or (re-search-forward pat nil t)
- (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")
- (Info-next-reference t))
- (if (looking-at "^\\* ")
- (forward-char 2)))))
-
-(defun Info-prev-reference (&optional recur)
- "Move cursor to the previous cross-reference or menu item in the node."
- (interactive)
- (let ((pat "\\*note[ \n\t]+\\([^:]+\\):\\|^\\* .*:\\|[hf]t?tps?://")
- (old-pt (point))
- (case-fold-search t))
- (or (re-search-backward pat nil t)
- (progn
- (goto-char (point-max))
- (or (re-search-backward pat nil t)
- (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")
- (Info-prev-reference t))
- (if (looking-at "^\\* ")
- (forward-char 2)))))
+(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
+COUNT cross-references."
+ (interactive "i\np")
+ (unless count
+ (setq count 1))
+ (if (< count 0)
+ (Info-prev-reference recur (- count))
+ (while (unless (zerop count) (setq count (1- count)))
+ (let ((pat "\\*note[ \n\t]+\\([^:]+\\):\\|^\\* .*:\\|[hf]t?tps?://")
+ (old-pt (point))
+ (case-fold-search t))
+ (or (eobp) (forward-char 1))
+ (or (Info-next-reference-or-link pat 'link)
+ (progn
+ (goto-char (point-min))
+ (or (Info-next-reference-or-link pat 'link)
+ (progn
+ (goto-char old-pt)
+ (user-error "No cross references in this node")))))
+ (if (looking-at "\\* Menu:")
+ (if recur
+ (user-error "No cross references in this node")
+ (Info-next-reference t))
+ (if (looking-at "^\\* ")
+ (forward-char 2)))))))
+
+(defun Info-prev-reference (&optional recur count)
+ "Move cursor to the previous cross-reference or menu item in the node.
+If COUNT is non-nil (interactively with a prefix arg), jump over
+COUNT cross-references."
+ (interactive "i\np")
+ (unless count
+ (setq count 1))
+ (if (< count 0)
+ (Info-next-reference recur (- count))
+ (while (unless (zerop count) (setq count (1- count)))
+ (let ((pat "\\*note[ \n\t]+\\([^:]+\\):\\|^\\* .*:\\|[hf]t?tps?://")
+ (old-pt (point))
+ (case-fold-search t))
+ (or (Info-prev-reference-or-link pat 'link)
+ (progn
+ (goto-char (point-max))
+ (or (Info-prev-reference-or-link pat 'link)
+ (progn
+ (goto-char old-pt)
+ (user-error "No cross references in this node")))))
+ (if (looking-at "\\* Menu:")
+ (if recur
+ (user-error "No cross references in this node")
+ (Info-prev-reference t))
+ (if (looking-at "^\\* ")
+ (forward-char 2)))))))