diff options
| author | Richard M. Stallman | 1998-07-05 23:57:45 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1998-07-05 23:57:45 +0000 |
| commit | 37a3ff5b0ba7c88f2360a2411d501b2e5c16c7a3 (patch) | |
| tree | 1d1ad6c35724c90108565ba5a00652c04a68c5a2 | |
| parent | ad0153e46f323b5e18e7c41690a7a554102ff5cd (diff) | |
| download | emacs-37a3ff5b0ba7c88f2360a2411d501b2e5c16c7a3.tar.gz emacs-37a3ff5b0ba7c88f2360a2411d501b2e5c16c7a3.zip | |
(Info-find-node): Handle cross references to an @anchor.
| -rw-r--r-- | lisp/info.el | 310 |
1 files changed, 169 insertions, 141 deletions
diff --git a/lisp/info.el b/lisp/info.el index 8657186dd4e..8338401fe80 100644 --- a/lisp/info.el +++ b/lisp/info.el | |||
| @@ -331,158 +331,188 @@ In standalone mode, \\<Info-mode-map>\\[Info-exit] exits Emacs itself." | |||
| 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. |
| @@ -637,8 +667,6 @@ In standalone mode, \\<Info-mode-map>\\[Info-exit] exits Emacs itself." | |||
| 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. |