Mercurial > emacs
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) |