comparison lisp/info.el @ 22692:578a6d997580

(Info-find-node): Handle cross references to an @anchor.
author Richard M. Stallman <rms@gnu.org>
date Sun, 05 Jul 1998 23:57:45 +0000
parents 4f99ccb85f3a
children 8d8e664f1f6c
comparison
equal deleted inserted replaced
22691:ff0ed53342b3 22692:578a6d997580
329 (defun Info-find-node (filename nodename &optional no-going-back) 329 (defun Info-find-node (filename nodename &optional no-going-back)
330 ;; Convert filename to lower case if not found as specified. 330 ;; Convert filename to lower case if not found as specified.
331 ;; Expand it. 331 ;; Expand it.
332 (if filename 332 (if filename
333 (let (temp temp-downcase found) 333 (let (temp temp-downcase found)
334 (setq filename (substitute-in-file-name filename)) 334 (setq filename (substitute-in-file-name filename))
335 (if (string= (downcase filename) "dir") 335 (if (string= (downcase filename) "dir")
336 (setq found t) 336 (setq found t)
337 (let ((dirs (if (string-match "^\\./" filename) 337 (let ((dirs (if (string-match "^\\./" filename)
338 ;; If specified name starts with `./' 338 ;; If specified name starts with `./'
339 ;; then just try current directory. 339 ;; then just try current directory.
340 '("./") 340 '("./")
341 (if (file-name-absolute-p filename) 341 (if (file-name-absolute-p filename)
342 ;; No point in searching for an 342 ;; No point in searching for an
343 ;; absolute file name 343 ;; absolute file name
344 '(nil) 344 '(nil)
345 (if Info-additional-directory-list 345 (if Info-additional-directory-list
346 (append Info-directory-list 346 (append Info-directory-list
347 Info-additional-directory-list) 347 Info-additional-directory-list)
348 Info-directory-list))))) 348 Info-directory-list)))))
349 ;; Search the directory list for file FILENAME. 349 ;; Search the directory list for file FILENAME.
350 (while (and dirs (not found)) 350 (while (and dirs (not found))
351 (setq temp (expand-file-name filename (car dirs))) 351 (setq temp (expand-file-name filename (car dirs)))
352 (setq temp-downcase 352 (setq temp-downcase
353 (expand-file-name (downcase filename) (car dirs))) 353 (expand-file-name (downcase filename) (car dirs)))
354 ;; Try several variants of specified name. 354 ;; Try several variants of specified name.
355 (let ((suffix-list Info-suffix-list)) 355 (let ((suffix-list Info-suffix-list))
356 (while (and suffix-list (not found)) 356 (while (and suffix-list (not found))
357 (cond ((info-file-exists-p 357 (cond ((info-file-exists-p
358 (info-insert-file-contents-1 358 (info-insert-file-contents-1
359 temp (car (car suffix-list)))) 359 temp (car (car suffix-list))))
360 (setq found temp)) 360 (setq found temp))
361 ((info-file-exists-p 361 ((info-file-exists-p
362 (info-insert-file-contents-1 362 (info-insert-file-contents-1
363 temp-downcase (car (car suffix-list)))) 363 temp-downcase (car (car suffix-list))))
364 (setq found temp-downcase))) 364 (setq found temp-downcase)))
365 (setq suffix-list (cdr suffix-list)))) 365 (setq suffix-list (cdr suffix-list))))
366 (setq dirs (cdr dirs))))) 366 (setq dirs (cdr dirs)))))
367 (if found 367 (if found
368 (setq filename found) 368 (setq filename found)
369 (error "Info file %s does not exist" filename)))) 369 (error "Info file %s does not exist" filename))))
370 ;; Record the node we are leaving.
371 (if (and Info-current-file (not no-going-back))
372 (setq Info-history
373 (cons (list Info-current-file Info-current-node (point))
374 Info-history)))
370 ;; Go into info buffer. 375 ;; Go into info buffer.
371 (or (eq major-mode 'Info-mode) (pop-to-buffer "*info*")) 376 (or (eq major-mode 'Info-mode) (pop-to-buffer "*info*"))
372 (buffer-disable-undo (current-buffer)) 377 (buffer-disable-undo (current-buffer))
373 (or (eq major-mode 'Info-mode) 378 (or (eq major-mode 'Info-mode)
374 (Info-mode)) 379 (Info-mode))
375 ;; Record the node we are leaving.
376 (if (and Info-current-file (not no-going-back))
377 (setq Info-history
378 (cons (list Info-current-file Info-current-node (point))
379 Info-history)))
380 (widen) 380 (widen)
381 (setq Info-current-node nil) 381 (setq Info-current-node nil)
382 (unwind-protect 382 (unwind-protect
383 (progn 383 (progn
384 ;; Switch files if necessary 384 ;; Switch files if necessary
385 (or (null filename) 385 (or (null filename)
386 (equal Info-current-file filename) 386 (equal Info-current-file filename)
387 (let ((buffer-read-only nil)) 387 (let ((buffer-read-only nil))
388 (setq Info-current-file nil 388 (setq Info-current-file nil
389 Info-current-subfile nil 389 Info-current-subfile nil
390 Info-current-file-completions nil 390 Info-current-file-completions nil
391 buffer-file-name nil) 391 buffer-file-name nil)
392 (erase-buffer) 392 (erase-buffer)
393 (if (eq filename t) 393 (if (eq filename t)
394 (Info-insert-dir) 394 (Info-insert-dir)
395 (info-insert-file-contents filename t) 395 (info-insert-file-contents filename t)
396 (setq default-directory (file-name-directory filename))) 396 (setq default-directory (file-name-directory filename)))
397 (set-buffer-modified-p nil) 397 (set-buffer-modified-p nil)
398 ;; See whether file has a tag table. Record the location if yes. 398 ;; See whether file has a tag table. Record the location if yes.
399 (goto-char (point-max)) 399 (goto-char (point-max))
400 (forward-line -8) 400 (forward-line -8)
401 ;; Use string-equal, not equal, to ignore text props. 401 ;; Use string-equal, not equal, to ignore text props.
402 (if (not (or (string-equal nodename "*") 402 (if (not (or (string-equal nodename "*")
403 (not 403 (not
404 (search-forward "\^_\nEnd tag table\n" nil t)))) 404 (search-forward "\^_\nEnd tag table\n" nil t))))
405 (let (pos) 405 (let (pos)
406 ;; We have a tag table. Find its beginning. 406 ;; We have a tag table. Find its beginning.
407 ;; Is this an indirect file? 407 ;; Is this an indirect file?
408 (search-backward "\nTag table:\n") 408 (search-backward "\nTag table:\n")
409 (setq pos (point)) 409 (setq pos (point))
410 (if (save-excursion 410 (if (save-excursion
411 (forward-line 2) 411 (forward-line 2)
412 (looking-at "(Indirect)\n")) 412 (looking-at "(Indirect)\n"))
413 ;; It is indirect. Copy it to another buffer 413 ;; It is indirect. Copy it to another buffer
414 ;; and record that the tag table is in that buffer. 414 ;; and record that the tag table is in that buffer.
415 (let ((buf (current-buffer)) 415 (let ((buf (current-buffer))
416 (tagbuf 416 (tagbuf
417 (or Info-tag-table-buffer 417 (or Info-tag-table-buffer
418 (generate-new-buffer " *info tag table*")))) 418 (generate-new-buffer " *info tag table*"))))
419 (setq Info-tag-table-buffer tagbuf) 419 (setq Info-tag-table-buffer tagbuf)
420 (save-excursion 420 (save-excursion
421 (set-buffer tagbuf) 421 (set-buffer tagbuf)
422 (buffer-disable-undo (current-buffer)) 422 (buffer-disable-undo (current-buffer))
423 (setq case-fold-search t) 423 (setq case-fold-search t)
424 (erase-buffer) 424 (erase-buffer)
425 (insert-buffer-substring buf)) 425 (insert-buffer-substring buf))
426 (set-marker Info-tag-table-marker 426 (set-marker Info-tag-table-marker
427 (match-end 0) tagbuf)) 427 (match-end 0) tagbuf))
428 (set-marker Info-tag-table-marker pos))) 428 (set-marker Info-tag-table-marker pos)))
429 (set-marker Info-tag-table-marker nil)) 429 (set-marker Info-tag-table-marker nil))
430 (setq Info-current-file 430 (setq Info-current-file
431 (if (eq filename t) "dir" filename)))) 431 (if (eq filename t) "dir" filename))))
432 ;; Use string-equal, not equal, to ignore text props. 432 ;; Use string-equal, not equal, to ignore text props.
433 (if (string-equal nodename "*") 433 (if (string-equal nodename "*")
434 (progn (setq Info-current-node nodename) 434 (progn (setq Info-current-node nodename)
435 (Info-set-mode-line)) 435 (Info-set-mode-line))
436 ;; Search file for a suitable node. 436 ;; Possibilities:
437 (let ((guesspos (point-min)) 437 ;;
438 (regexp (concat "Node: *" (regexp-quote nodename) " *[,\t\n\177]"))) 438 ;; 1. Anchor found in tag table
439 ;; First get advice from tag table if file has one. 439 ;; 2. Anchor *not* in tag table
440 ;; Also, if this is an indirect info file, 440 ;;
441 ;; read the proper subfile into this buffer. 441 ;; 3. Node found in tag table
442 (if (marker-position Info-tag-table-marker) 442 ;; 4. Node *not* found in tag table, but found in file
443 (save-excursion 443 ;; 5. Node *not* in tag table, and *not* in file
444 (let ((m Info-tag-table-marker) 444 ;;
445 found found-mode) 445 ;; *Or* the same, but in an indirect subfile.
446 (save-excursion 446
447 (set-buffer (marker-buffer m)) 447 ;; Search file for a suitable node.
448 (goto-char m) 448 (let ((guesspos (point-min))
449 (beginning-of-line) ;so re-search will work. 449 (regexp
450 (setq found (re-search-forward regexp nil t)) 450 (concat "\\(Node:\\|Ref:\\) *"
451 (if found 451 (regexp-quote nodename)
452 (setq guesspos (read (current-buffer)))) 452 " *[,\t\n\177]")))
453 (setq found-mode major-mode)) 453
454 (if found 454 ;; First, search a tag table, if any
455 (progn 455 (if (marker-position Info-tag-table-marker)
456 ;; If this is an indirect file, determine 456
457 ;; which file really holds this node and 457 (let (found-in-tag-table
458 ;; read it in. 458 found-mode
459 (if (not (eq found-mode 'Info-mode)) 459 (m Info-tag-table-marker))
460 ;; Note that the current buffer must be 460 (save-excursion
461 ;; the *info* buffer on entry to 461 (set-buffer (marker-buffer m))
462 ;; Info-read-subfile. Thus the hackery 462 (goto-char m)
463 ;; above. 463 (beginning-of-line) ; so re-search will work.
464 (setq guesspos (Info-read-subfile guesspos)))) 464
465 (error "No such node: %s" nodename))))) 465 ;; Search tag table
466 (goto-char (max (point-min) (- (byte-to-position guesspos) 1000))) 466 (setq found-in-tag-table
467 ;; Now search from our advised position (or from beg of buffer) 467 (re-search-forward regexp nil t))
468 ;; to find the actual node. 468 (if found-in-tag-table
469 (catch 'foo 469 (setq guesspos (read (current-buffer))))
470 (while (search-forward "\n\^_" nil t) 470 (setq found-mode major-mode))
471 (forward-line 1) 471
472 (let ((beg (point))) 472 ;; Indirect file among split files
473 (forward-line 1) 473 (if found-in-tag-table
474 (if (re-search-backward regexp beg t) 474 (progn
475 (throw 'foo t)))) 475 ;; If this is an indirect file, determine
476 (error "No such node: %s" nodename))) 476 ;; which file really holds this node and
477 (Info-select-node))) 477 ;; read it in.
478 (if (not (eq found-mode 'Info-mode))
479 ;; Note that the current buffer must be
480 ;; the *info* buffer on entry to
481 ;; Info-read-subfile. Thus the hackery
482 ;; above.
483 (setq guesspos (Info-read-subfile guesspos)))))
484
485 ;; Handle anchor
486 (if (and found-in-tag-table
487 (string-equal "Ref:" (match-string 1)))
488 (goto-char guesspos)
489
490 ;; Else we may have a node, which we search for:
491 (goto-char (max (point-min) (- guesspos 1000)))
492 ;; Now search from our advised position
493 ;; (or from beg of buffer)
494 ;; to find the actual node.
495 (catch 'foo
496 (while (search-forward "\n\^_" nil t)
497 (forward-line 1)
498 (let ((beg (point)))
499 (forward-line 1)
500 (if (re-search-backward regexp beg t)
501 (progn
502 (beginning-of-line)
503 (throw 'foo t)))))
504 (error
505 "No such anchor in tag table or node in tag table or file: %s"
506 nodename))))))
507
508 (Info-select-node)))
478 ;; If we did not finish finding the specified node, 509 ;; If we did not finish finding the specified node,
479 ;; go back to the previous one. 510 ;; go back to the previous one.
480 (or Info-current-node no-going-back (null Info-history) 511 (or Info-current-node no-going-back (null Info-history)
481 (let ((hist (car Info-history))) 512 (let ((hist (car Info-history)))
482 (setq Info-history (cdr Info-history)) 513 (setq Info-history (cdr Info-history))
483 (Info-find-node (nth 0 hist) (nth 1 hist) t) 514 (Info-find-node (nth 0 hist) (nth 1 hist) t)
484 (goto-char (nth 2 hist))))) 515 (goto-char (nth 2 hist))))))
485 (goto-char (point-min)))
486 516
487 ;; Cache the contents of the (virtual) dir file, once we have merged 517 ;; Cache the contents of the (virtual) dir file, once we have merged
488 ;; it for the first time, so we can save time subsequently. 518 ;; it for the first time, so we can save time subsequently.
489 (defvar Info-dir-contents nil) 519 (defvar Info-dir-contents nil)
490 520
635 (setq Info-dir-contents (buffer-string))) 665 (setq Info-dir-contents (buffer-string)))
636 (setq default-directory Info-dir-contents-directory)) 666 (setq default-directory Info-dir-contents-directory))
637 667
638 ;; Note that on entry to this function the current-buffer must be the 668 ;; Note that on entry to this function the current-buffer must be the
639 ;; *info* buffer; not the info tags buffer. 669 ;; *info* buffer; not the info tags buffer.
640 ;; nodepos should be a byte-position such as is found in
641 ;; the Info file tags table.
642 (defun Info-read-subfile (nodepos) 670 (defun Info-read-subfile (nodepos)
643 ;; NODEPOS is either a position (in the Info file as a whole, 671 ;; NODEPOS is either a position (in the Info file as a whole,
644 ;; not relative to a subfile) or the name of a subfile. 672 ;; not relative to a subfile) or the name of a subfile.
645 (let (lastfilepos 673 (let (lastfilepos
646 lastfilename) 674 lastfilename)