comparison lisp/info.el @ 51735:204ae43066d1

(Info-following-node-name-re): New fun. (Info-following-node-name): Remove. (Info-insert-dir): Use the new fun. (Info-extract-pointer): Don't save restriction; use new fun. (Info-menu-entry-name-re): New const. (Info-menu-entry-name-re): Use it along with new fun. (Info-node-spec-re): Use new fun. (Info-complete-menu-item, Info-fontify-node): Use new const. (Info-goto-node, Info-follow-reference, Info-menu-update): Use match-string. (Info-follow-reference): Use assoc-string. Use a list of strings for the completion table. (Info-fontify-node): Use match-string, line-end-position. Limit the search for `node:' to the first line.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Fri, 04 Jul 2003 23:05:35 +0000
parents 6b3b6b76e307
children fbd12905244b
comparison
equal deleted inserted replaced
51734:400a9c7868fd 51735:204ae43066d1
908 (while (and (zerop (forward-line 1)) (eolp))) 908 (while (and (zerop (forward-line 1)) (eolp)))
909 (let ((beg (point)) 909 (let ((beg (point))
910 nodename end) 910 nodename end)
911 (re-search-backward "^\^_") 911 (re-search-backward "^\^_")
912 (search-forward "Node: ") 912 (search-forward "Node: ")
913 (setq nodename (Info-following-node-name)) 913 (setq nodename
914 (and (looking-at (Info-following-node-name-re))
915 (match-string 1)))
914 (search-forward "\n\^_" nil 'move) 916 (search-forward "\n\^_" nil 'move)
915 (beginning-of-line) 917 (beginning-of-line)
916 (setq end (point)) 918 (setq end (point))
917 (push (list nodename other beg end) this-buffer-nodes))) 919 (push (list nodename other beg end) this-buffer-nodes)))
918 (if (assoc-ignore-case "top" this-buffer-nodes) 920 (if (assoc-ignore-case "top" this-buffer-nodes)
1207 (let (filename) 1209 (let (filename)
1208 (string-match "\\s *\\((\\s *\\([^\t)]*\\)\\s *)\\s *\\|\\)\\(.*\\)" 1210 (string-match "\\s *\\((\\s *\\([^\t)]*\\)\\s *)\\s *\\|\\)\\(.*\\)"
1209 nodename) 1211 nodename)
1210 (setq filename (if (= (match-beginning 1) (match-end 1)) 1212 (setq filename (if (= (match-beginning 1) (match-end 1))
1211 "" 1213 ""
1212 (substring nodename (match-beginning 2) (match-end 2))) 1214 (match-string 2 nodename))
1213 nodename (substring nodename (match-beginning 3) (match-end 3))) 1215 nodename (match-string 3 nodename))
1214 (let ((trim (string-match "\\s *\\'" filename))) 1216 (let ((trim (string-match "\\s *\\'" filename)))
1215 (if trim (setq filename (substring filename 0 trim)))) 1217 (if trim (setq filename (substring filename 0 trim))))
1216 (let ((trim (string-match "\\s *\\'" nodename))) 1218 (let ((trim (string-match "\\s *\\'" nodename)))
1217 (if trim (setq nodename (substring nodename 0 trim)))) 1219 (if trim (setq nodename (substring nodename 0 trim))))
1218 (if transient-mark-mode (deactivate-mark)) 1220 (if transient-mark-mode (deactivate-mark))
1391 Info-history)))))) 1393 Info-history))))))
1392 1394
1393 (defun Info-extract-pointer (name &optional errorname) 1395 (defun Info-extract-pointer (name &optional errorname)
1394 "Extract the value of the node-pointer named NAME. 1396 "Extract the value of the node-pointer named NAME.
1395 If there is none, use ERRORNAME in the error message; 1397 If there is none, use ERRORNAME in the error message;
1396 if ERRORNAME is nil, just return nil. 1398 if ERRORNAME is nil, just return nil."
1397 Bind this in case the user sets it to nil." 1399 ;; Bind this in case the user sets it to nil.
1398 (let ((case-fold-search t)) 1400 (let ((case-fold-search t))
1399 (save-excursion 1401 (save-excursion
1400 (save-restriction 1402 (goto-char (point-min))
1401 (goto-char (point-min)) 1403 (let ((bound (point)))
1402 (let ((bound (point))) 1404 (forward-line 1)
1403 (forward-line 1) 1405 (cond ((re-search-backward
1404 (cond ((re-search-backward (concat name ":") bound t) 1406 (concat name ":" (Info-following-node-name-re)) bound t)
1405 (goto-char (match-end 0)) 1407 (match-string 1))
1406 (Info-following-node-name)) 1408 ((not (eq errorname t))
1407 ((not (eq errorname t)) 1409 (error "Node has no %s"
1408 (error "Node has no %s" 1410 (capitalize (or errorname name)))))))))
1409 (capitalize (or errorname name)))))))))) 1411
1410 1412 (defun Info-following-node-name-re (&optional allowedchars)
1411 (defun Info-following-node-name (&optional allowedchars) 1413 "Return a regexp matching a node name.
1412 "Return the node name in the buffer following point.
1413 ALLOWEDCHARS, if non-nil, goes within [...] to make a regexp 1414 ALLOWEDCHARS, if non-nil, goes within [...] to make a regexp
1414 saying which chars may appear in the node name." 1415 saying which chars may appear in the node name.
1415 (skip-chars-forward " \t") 1416 Submatch 1 is the complete node name.
1416 (buffer-substring-no-properties 1417 Submatch 2 if non-nil is the parenthesized file name part of the node name.
1417 (point) 1418 Submatch 3 is the local part of the node name.
1418 (progn 1419 End of submatch 0, 1, and 3 are the same, so you can safely concat."
1419 (while (looking-at (concat "[" (or allowedchars "^,\t\n") "]")) 1420 (concat "[ \t]*" ;Skip leading space.
1420 (skip-chars-forward (concat (or allowedchars "^,\t\n") "(")) 1421 "\\(\\(([^)]+)\\)?" ;Node name can start with a file name.
1421 (if (looking-at "(") 1422 "\\([" (or allowedchars "^,\t\n") "]*" ;Any number of allowed chars.
1422 (skip-chars-forward "^)"))) 1423 "[" (or allowedchars "^,\t\n") " ]" ;The last char can't be a space.
1423 (skip-chars-backward " ") 1424 "\\|\\)\\)")) ;Allow empty node names.
1424 (point))))
1425 1425
1426 (defun Info-next () 1426 (defun Info-next ()
1427 "Go to the next node of this node." 1427 "Go to the next node of this node."
1428 (interactive) 1428 (interactive)
1429 (Info-goto-node (Info-extract-pointer "next"))) 1429 (Info-goto-node (Info-extract-pointer "next")))
1478 (beginning-of-line) 1478 (beginning-of-line)
1479 (setq bol (point)) 1479 (setq bol (point))
1480 1480
1481 (goto-char (point-min)) 1481 (goto-char (point-min))
1482 (while (re-search-forward "\\*note[ \n\t]*\\([^:]*\\):" nil t) 1482 (while (re-search-forward "\\*note[ \n\t]*\\([^:]*\\):" nil t)
1483 (setq str (buffer-substring-no-properties 1483 (setq str (match-string-no-properties 1))
1484 (match-beginning 1)
1485 (1- (point))))
1486 ;; See if this one should be the default. 1484 ;; See if this one should be the default.
1487 (and (null default) 1485 (and (null default)
1488 (<= (match-beginning 0) start-point) 1486 (<= (match-beginning 0) start-point)
1489 (<= start-point (point)) 1487 (<= start-point (point))
1490 (setq default t)) 1488 (setq default t))
1500 (setq i (1+ i))) 1498 (setq i (1+ i)))
1501 ;; Record as a completion and perhaps as default. 1499 ;; Record as a completion and perhaps as default.
1502 (if (eq default t) (setq default str)) 1500 (if (eq default t) (setq default str))
1503 (if (eq alt-default t) (setq alt-default str)) 1501 (if (eq alt-default t) (setq alt-default str))
1504 ;; Don't add this string if it's a duplicate. 1502 ;; Don't add this string if it's a duplicate.
1505 ;; We use a loop instead of "(assoc str completions)" because 1503 (or (assoc-string str completions t)
1506 ;; we want to do a case-insensitive compare. 1504 (push str completions))))
1507 (let ((tail completions)
1508 (tem (downcase str)))
1509 (while (and tail
1510 (not (string-equal tem (downcase (car (car tail))))))
1511 (setq tail (cdr tail)))
1512 (or tail
1513 (setq completions
1514 (cons (cons str nil)
1515 completions))))))
1516 ;; If no good default was found, try an alternate. 1505 ;; If no good default was found, try an alternate.
1517 (or default 1506 (or default
1518 (setq default alt-default)) 1507 (setq default alt-default))
1519 ;; If only one cross-reference found, then make it default. 1508 ;; If only one cross-reference found, then make it default.
1520 (if (eq (length completions) 1) 1509 (if (eq (length completions) 1)
1521 (setq default (car (car completions)))) 1510 (setq default (car completions)))
1522 (if completions 1511 (if completions
1523 (let ((input (completing-read (if default 1512 (let ((input (completing-read (if default
1524 (concat 1513 (concat
1525 "Follow reference named: (default " 1514 "Follow reference named: (default "
1526 default ") ") 1515 default ") ")
1549 (setq target (concat (substring target 0 i) " " 1538 (setq target (concat (substring target 0 i) " "
1550 (substring target (match-end 0)))) 1539 (substring target (match-end 0))))
1551 (setq i (+ i 1))) 1540 (setq i (+ i 1)))
1552 (Info-goto-node target))) 1541 (Info-goto-node target)))
1553 1542
1543 (defconst Info-menu-entry-name-re "\\(?:[^:\n]+\\|:[^,.;() \t\n]\\)*"
1544 "Regexp that matches a menu entry name upto but not including the colon.
1545 Because of ambiguities, this should be concatenated with something like
1546 `:' and `Info-following-node-name-re'.")
1547
1554 (defun Info-extract-menu-node-name (&optional multi-line) 1548 (defun Info-extract-menu-node-name (&optional multi-line)
1555 (skip-chars-forward " \t\n") 1549 (skip-chars-forward " \t\n")
1556 (let ((beg (point)) 1550 (when (looking-at (concat Info-menu-entry-name-re ":\\(:\\|"
1557 str) 1551 (Info-following-node-name-re
1558 (while (progn 1552 (if multi-line "^.,\t" "^.,\t\n")) "\\)"))
1559 (skip-chars-forward "^:") 1553 (replace-regexp-in-string
1560 (forward-char 1) 1554 "[ \n]+" " "
1561 (not (looking-at ":*[,.;() \t\n]")))) 1555 (or (match-string 2)
1562 (setq str 1556 ;; If the node name is the menu entry name (using `entry::').
1563 (if (looking-at ":") 1557 (buffer-substring (match-beginning 0) (1- (match-beginning 1)))))))
1564 (buffer-substring-no-properties beg (1- (point)))
1565 (skip-chars-forward " \t\n")
1566 (Info-following-node-name (if multi-line "^.,\t" "^.,\t\n"))))
1567 (replace-regexp-in-string "[ \n]+" " " str)))
1568 1558
1569 ;; No one calls this. 1559 ;; No one calls this.
1570 ;;(defun Info-menu-item-sequence (list) 1560 ;;(defun Info-menu-item-sequence (list)
1571 ;; (while list 1561 ;; (while list
1572 ;; (Info-menu (car list)) 1562 ;; (Info-menu (car list))
1574 1564
1575 (defvar Info-complete-menu-buffer) 1565 (defvar Info-complete-menu-buffer)
1576 (defvar Info-complete-next-re nil) 1566 (defvar Info-complete-next-re nil)
1577 (defvar Info-complete-cache nil) 1567 (defvar Info-complete-cache nil)
1578 1568
1579 (defconst Info-node-spec-re "[^.,:(]*\\(([^)]*)[^.,:]*\\)?[,:.]" 1569 (defconst Info-node-spec-re
1570 (concat (Info-following-node-name-re "^.,:") "[,:.]")
1580 "Regexp to match the text after a : until the terminating `.'.") 1571 "Regexp to match the text after a : until the terminating `.'.")
1581 1572
1582 (defun Info-complete-menu-item (string predicate action) 1573 (defun Info-complete-menu-item (string predicate action)
1583 ;; This uses two dynamically bound variables: 1574 ;; This uses two dynamically bound variables:
1584 ;; - `Info-complete-menu-buffer' which contains the buffer in which 1575 ;; - `Info-complete-menu-buffer' which contains the buffer in which
1601 (if (not (memq action '(nil t))) 1592 (if (not (memq action '(nil t)))
1602 (re-search-forward 1593 (re-search-forward
1603 (concat "\n\\* +" (regexp-quote string) ":") nil t) 1594 (concat "\n\\* +" (regexp-quote string) ":") nil t)
1604 (let ((pattern (concat "\n\\* +\\(" 1595 (let ((pattern (concat "\n\\* +\\("
1605 (regexp-quote string) 1596 (regexp-quote string)
1606 "[^\t\n]*?\\):" Info-node-spec-re)) 1597 Info-menu-entry-name-re "\\):" Info-node-spec-re))
1607 completions) 1598 completions)
1608 ;; Check the cache. 1599 ;; Check the cache.
1609 (if (and (equal (nth 0 Info-complete-cache) Info-current-file) 1600 (if (and (equal (nth 0 Info-complete-cache) Info-current-file)
1610 (equal (nth 1 Info-complete-cache) Info-current-node) 1601 (equal (nth 1 Info-complete-cache) Info-current-node)
1611 (equal (nth 2 Info-complete-cache) Info-complete-next-re) 1602 (equal (nth 2 Info-complete-cache) Info-complete-next-re)
2380 (number 0) 2371 (number 0)
2381 (case-fold-search t)) 2372 (case-fold-search t))
2382 (save-excursion 2373 (save-excursion
2383 (goto-char (point-min)) 2374 (goto-char (point-min))
2384 (while (re-search-forward "\\*note[ \n\t]*\\([^:]*\\):" nil t) 2375 (while (re-search-forward "\\*note[ \n\t]*\\([^:]*\\):" nil t)
2385 (setq str (buffer-substring 2376 (setq str (match-string 1))
2386 (match-beginning 1)
2387 (1- (point))))
2388 (setq i 0) 2377 (setq i 0)
2389 (while (setq i (string-match "[ \n\t]+" str i)) 2378 (while (setq i (string-match "[ \n\t]+" str i))
2390 (setq str (concat (substring str 0 i) " " 2379 (setq str (concat (substring str 0 i) " "
2391 (substring str (match-end 0)))) 2380 (substring str (match-end 0))))
2392 (setq i (1+ i))) 2381 (setq i (1+ i)))
2805 (while (looking-at "[ \t]*\\([^:, \t\n]+\\):[ \t]+\\([^:,\t\n]+\\),?") 2794 (while (looking-at "[ \t]*\\([^:, \t\n]+\\):[ \t]+\\([^:,\t\n]+\\),?")
2806 (goto-char (match-end 0)) 2795 (goto-char (match-end 0))
2807 (let* ((nbeg (match-beginning 2)) 2796 (let* ((nbeg (match-beginning 2))
2808 (nend (match-end 2)) 2797 (nend (match-end 2))
2809 (tbeg (match-beginning 1)) 2798 (tbeg (match-beginning 1))
2810 (tag (buffer-substring tbeg (match-end 1)))) 2799 (tag (match-string 1)))
2811 (if (string-equal tag "Node") 2800 (if (string-equal tag "Node")
2812 (put-text-property nbeg nend 'font-lock-face 'info-header-node) 2801 (put-text-property nbeg nend 'font-lock-face 'info-header-node)
2813 (put-text-property nbeg nend 'font-lock-face 'info-header-xref) 2802 (put-text-property nbeg nend 'font-lock-face 'info-header-xref)
2814 (put-text-property tbeg nend 'mouse-face 'highlight) 2803 (put-text-property tbeg nend 'mouse-face 'highlight)
2815 (put-text-property tbeg nend 2804 (put-text-property tbeg nend
2824 ((equal tag "Prev") Info-prev-link-keymap) 2813 ((equal tag "Prev") Info-prev-link-keymap)
2825 ((equal tag "Next") Info-next-link-keymap) 2814 ((equal tag "Next") Info-next-link-keymap)
2826 ((equal tag "Up") Info-up-link-keymap)))))) 2815 ((equal tag "Up") Info-up-link-keymap))))))
2827 (when Info-use-header-line 2816 (when Info-use-header-line
2828 (goto-char (point-min)) 2817 (goto-char (point-min))
2829 (let ((header-end (save-excursion (end-of-line) (point))) 2818 (let ((header-end (line-end-position))
2830 header) 2819 header)
2831 ;; If we find neither Next: nor Prev: link, show the entire 2820 ;; If we find neither Next: nor Prev: link, show the entire
2832 ;; node header. Otherwise, don't show the File: and Node: 2821 ;; node header. Otherwise, don't show the File: and Node:
2833 ;; parts, to avoid wasting precious space on information that 2822 ;; parts, to avoid wasting precious space on information that
2834 ;; is available in the mode line. 2823 ;; is available in the mode line.
2836 "\\(next\\|up\\|prev[ious]*\\): " 2825 "\\(next\\|up\\|prev[ious]*\\): "
2837 header-end t) 2826 header-end t)
2838 (progn 2827 (progn
2839 (goto-char (match-beginning 1)) 2828 (goto-char (match-beginning 1))
2840 (setq header (buffer-substring (point) header-end))) 2829 (setq header (buffer-substring (point) header-end)))
2841 (if (re-search-forward "node:[ \t]*[^ \t]+[ \t]*" nil t) 2830 (if (re-search-forward "node:[ \t]*[^ \t]+[ \t]*" header-end t)
2842 (setq header 2831 (setq header
2843 (concat "No next, prev or up links -- " 2832 (concat "No next, prev or up links -- "
2844 (buffer-substring (point) header-end))) 2833 (buffer-substring (point) header-end)))
2845 (setq header (buffer-substring (point) header-end)))) 2834 (setq header (buffer-substring (point) header-end))))
2846 2835
2943 (not (string-match "\\<Index\\>" Info-current-node)) 2932 (not (string-match "\\<Index\\>" Info-current-node))
2944 ;; Don't take time to annotate huge menus 2933 ;; Don't take time to annotate huge menus
2945 (< (- (point-max) (point)) Info-fontify-maximum-menu-size)) 2934 (< (- (point-max) (point)) Info-fontify-maximum-menu-size))
2946 (let ((n 0) 2935 (let ((n 0)
2947 cont) 2936 cont)
2948 (while (re-search-forward (concat "^\\* +\\([^:\t\n]*\\)\\(:" 2937 (while (re-search-forward
2949 Info-node-spec-re 2938 (concat "^\\* +\\(" Info-menu-entry-name-re "\\)\\(:"
2950 "\\([ \t]*\\)\\)") 2939 Info-node-spec-re "\\([ \t]*\\)\\)")
2951 nil t) 2940 nil t)
2952 (setq n (1+ n)) 2941 (setq n (1+ n))
2953 (if (and (<= n 9) (zerop (% n 3))) ; visual aids to help with 1-9 keys 2942 (if (and (<= n 9) (zerop (% n 3))) ; visual aids to help with 1-9 keys
2954 (put-text-property (match-beginning 0) 2943 (put-text-property (match-beginning 0)
2955 (1+ (match-beginning 0)) 2944 (1+ (match-beginning 0))
2956 'font-lock-face 'info-menu-5)) 2945 'font-lock-face 'info-menu-5))
2962 (concat "mouse-2: go to " (match-string 3)) 2951 (concat "mouse-2: go to " (match-string 3))
2963 "mouse-2: go to this node") 2952 "mouse-2: go to this node")
2964 '(font-lock-face info-xref 2953 '(font-lock-face info-xref
2965 mouse-face highlight)))) 2954 mouse-face highlight))))
2966 (when (eq Info-hide-note-references t) 2955 (when (eq Info-hide-note-references t)
2967 (put-text-property (match-beginning 2) (1- (match-end 4)) 2956 (put-text-property (match-beginning 2) (1- (match-end 6))
2968 'invisible t) 2957 'invisible t)
2969 ;; We need a stretchable space like :align-to but with 2958 ;; We need a stretchable space like :align-to but with
2970 ;; a minimum value. 2959 ;; a minimum value.
2971 (put-text-property (1- (match-end 4)) (match-end 4) 'display 2960 (put-text-property (1- (match-end 6)) (match-end 6) 'display
2972 (if (>= 22 (- (match-end 1) 2961 (if (>= 22 (- (match-end 1)
2973 (match-beginning 0))) 2962 (match-beginning 0)))
2974 '(space :align-to 24) 2963 '(space :align-to 24)
2975 '(space :width 2))) 2964 '(space :width 2)))
2976 (setq cont (looking-at ".")) 2965 (setq cont (looking-at "."))