diff options
| author | Roland Winkler | 2007-06-23 22:00:03 +0000 |
|---|---|---|
| committer | Roland Winkler | 2007-06-23 22:00:03 +0000 |
| commit | f2dfa899a4676ca39d3b016c17bbbcabf8043b14 (patch) | |
| tree | 605bb7147b7ef3d1248218838fd6e25f53b324cc | |
| parent | 3b9795200fbc11c5b136b62b9ac1a70b2565da18 (diff) | |
| download | emacs-f2dfa899a4676ca39d3b016c17bbbcabf8043b14.tar.gz emacs-f2dfa899a4676ca39d3b016c17bbbcabf8043b14.zip | |
(bibtex-entry-format): New options `whitespace', `braces', and `string'.
(bibtex-field-braces-alist, bibtex-field-strings-alist)
(bibtex-field-braces-opt, bibtex-field-strings-opt)
(bibtex-cite-matcher-alist): New variables.
(bibtex-font-lock-keywords): Use bibtex-cite-matcher-alist.
(bibtex-flash-head): Use blink-matching-delay.
(bibtex-insert-kill, bibtex-mark-entry): Use push-mark.
(bibtex-format-entry, bibtex-reformat): Handle new options of
bibtex-entry-format.
(bibtex-field-re-init, bibtex-font-lock-cite, bibtex-dist): New
functions.
(bibtex-complete-internal): Do not display messages while
minibuffer is used. Do not leave around a completions buffer
that is out of date.
(bibtex-copy-summary-as-kill): New optional arg.
(bibtex-font-lock-url): New optional arg no-button.
(bibtex-find-crossref): Use `bibtex-cite-matcher-alist'.
(bibtex-url): Allow multiple URLs per entry.
| -rw-r--r-- | lisp/textmodes/bibtex.el | 508 |
1 files changed, 380 insertions, 128 deletions
diff --git a/lisp/textmodes/bibtex.el b/lisp/textmodes/bibtex.el index 0b413e3b7ab..377c90b7bed 100644 --- a/lisp/textmodes/bibtex.el +++ b/lisp/textmodes/bibtex.el | |||
| @@ -34,7 +34,7 @@ | |||
| 34 | ;; Major mode for editing and validating BibTeX files. | 34 | ;; Major mode for editing and validating BibTeX files. |
| 35 | 35 | ||
| 36 | ;; Usage: | 36 | ;; Usage: |
| 37 | ;; See documentation for function bibtex-mode or type "\M-x describe-mode" | 37 | ;; See documentation for `bibtex-mode' or type "M-x describe-mode" |
| 38 | ;; when you are in BibTeX mode. | 38 | ;; when you are in BibTeX mode. |
| 39 | 39 | ||
| 40 | ;; Todo: | 40 | ;; Todo: |
| @@ -112,6 +112,7 @@ required-fields Signal an error if a required field is missing. | |||
| 112 | numerical-fields Delete delimiters around numeral fields. | 112 | numerical-fields Delete delimiters around numeral fields. |
| 113 | page-dashes Change double dashes in page field to single dash | 113 | page-dashes Change double dashes in page field to single dash |
| 114 | (for scribe compatibility). | 114 | (for scribe compatibility). |
| 115 | whitespace Delete whitespace at the beginning and end of fields. | ||
| 115 | inherit-booktitle If entry contains a crossref field and the booktitle | 116 | inherit-booktitle If entry contains a crossref field and the booktitle |
| 116 | field is empty, set the booktitle field to the content | 117 | field is empty, set the booktitle field to the content |
| 117 | of the title field of the crossreferenced entry. | 118 | of the title field of the crossreferenced entry. |
| @@ -123,6 +124,10 @@ last-comma Add or delete comma on end of last field in entry, | |||
| 123 | delimiters Change delimiters according to variables | 124 | delimiters Change delimiters according to variables |
| 124 | `bibtex-field-delimiters' and `bibtex-entry-delimiters'. | 125 | `bibtex-field-delimiters' and `bibtex-entry-delimiters'. |
| 125 | unify-case Change case of entry and field names. | 126 | unify-case Change case of entry and field names. |
| 127 | braces Enclose parts of field entries by braces according to | ||
| 128 | `bibtex-field-braces-alist'. | ||
| 129 | strings Replace parts of field entries by string constants | ||
| 130 | according to `bibtex-field-strings-alist'. | ||
| 126 | 131 | ||
| 127 | The value t means do all of the above formatting actions. | 132 | The value t means do all of the above formatting actions. |
| 128 | The value nil means do no formatting at all." | 133 | The value nil means do no formatting at all." |
| @@ -134,11 +139,35 @@ The value nil means do no formatting at all." | |||
| 134 | (const required-fields) | 139 | (const required-fields) |
| 135 | (const numerical-fields) | 140 | (const numerical-fields) |
| 136 | (const page-dashes) | 141 | (const page-dashes) |
| 142 | (const whitespace) | ||
| 137 | (const inherit-booktitle) | 143 | (const inherit-booktitle) |
| 138 | (const realign) | 144 | (const realign) |
| 139 | (const last-comma) | 145 | (const last-comma) |
| 140 | (const delimiters) | 146 | (const delimiters) |
| 141 | (const unify-case)))) | 147 | (const unify-case) |
| 148 | (const braces) | ||
| 149 | (const strings)))) | ||
| 150 | |||
| 151 | (defcustom bibtex-field-braces-alist nil | ||
| 152 | "Alist of field regexps that \\[bibtex-clean-entry] encloses by braces. | ||
| 153 | Each element has the form (FIELDS REGEXP), where FIELDS is a list | ||
| 154 | of BibTeX field names and REGEXP is a regexp. | ||
| 155 | Whitespace in REGEXP will be replaced by \"[ \\t\\n]+\"." | ||
| 156 | :group 'bibtex | ||
| 157 | :type '(repeat (list (repeat (string :tag "field name")) | ||
| 158 | (choice (regexp :tag "regexp") | ||
| 159 | (sexp :tag "sexp"))))) | ||
| 160 | |||
| 161 | (defcustom bibtex-field-strings-alist nil | ||
| 162 | "Alist of regexps that \\[bibtex-clean-entry] replaces by string constants. | ||
| 163 | Each element has the form (FIELDS REGEXP TO-STR), where FIELDS is a list | ||
| 164 | of BibTeX field names. In FIELDS search for REGEXP, which are replaced | ||
| 165 | by the BibTeX string constant TO-STR. | ||
| 166 | Whitespace in REGEXP will be replaced by \"[ \\t\\n]+\"." | ||
| 167 | :group 'bibtex | ||
| 168 | :type '(repeat (list (repeat (string :tag "field name")) | ||
| 169 | (regexp :tag "From regexp") | ||
| 170 | (regexp :tag "To string constant")))) | ||
| 142 | 171 | ||
| 143 | (defcustom bibtex-clean-entry-hook nil | 172 | (defcustom bibtex-clean-entry-hook nil |
| 144 | "List of functions to call when entry has been cleaned. | 173 | "List of functions to call when entry has been cleaned. |
| @@ -899,6 +928,17 @@ The following is a complex example, see http://link.aps.org/linkfaq.html. | |||
| 899 | (function :tag "Filter")))))))) | 928 | (function :tag "Filter")))))))) |
| 900 | (put 'bibtex-generate-url-list 'risky-local-variable t) | 929 | (put 'bibtex-generate-url-list 'risky-local-variable t) |
| 901 | 930 | ||
| 931 | (defcustom bibtex-cite-matcher-alist | ||
| 932 | '(("\\\\cite[ \t\n]*{\\([^}]+\\)}" . 1)) | ||
| 933 | "Alist of rules to identify cited keys in a BibTeX entry. | ||
| 934 | Each rule should be of the form (REGEXP . SUBEXP), where SUBEXP | ||
| 935 | specifies which parenthesized expression in REGEXP is a cited key. | ||
| 936 | Case is significant. | ||
| 937 | Used by `bibtex-find-crossref' and for font-locking." | ||
| 938 | :group 'bibtex | ||
| 939 | :type '(repeat (cons (regexp :tag "Regexp") | ||
| 940 | (integer :tag "Number")))) | ||
| 941 | |||
| 902 | (defcustom bibtex-expand-strings nil | 942 | (defcustom bibtex-expand-strings nil |
| 903 | "If non-nil, expand strings when extracting the content of a BibTeX field." | 943 | "If non-nil, expand strings when extracting the content of a BibTeX field." |
| 904 | :group 'bibtex | 944 | :group 'bibtex |
| @@ -1070,6 +1110,17 @@ The following is a complex example, see http://link.aps.org/linkfaq.html. | |||
| 1070 | 1110 | ||
| 1071 | ;; Internal Variables | 1111 | ;; Internal Variables |
| 1072 | 1112 | ||
| 1113 | (defvar bibtex-field-braces-opt nil | ||
| 1114 | "Optimized value of `bibtex-field-braces-alist'. | ||
| 1115 | Created by `bibtex-field-re-init'. | ||
| 1116 | It is a an alist with elements (FIELD . REGEXP).") | ||
| 1117 | |||
| 1118 | (defvar bibtex-field-strings-opt nil | ||
| 1119 | "Optimized value of `bibtex-field-strings-alist'. | ||
| 1120 | Created by `bibtex-field-re-init'. | ||
| 1121 | It is a an alist with elements (FIELD RULE1 RULE2 ...), | ||
| 1122 | where each RULE is (REGEXP . TO-STR).") | ||
| 1123 | |||
| 1073 | (defvar bibtex-pop-previous-search-point nil | 1124 | (defvar bibtex-pop-previous-search-point nil |
| 1074 | "Next point where `bibtex-pop-previous' starts looking for a similar entry.") | 1125 | "Next point where `bibtex-pop-previous' starts looking for a similar entry.") |
| 1075 | 1126 | ||
| @@ -1215,7 +1266,11 @@ The CDRs of the elements are t for header keys and nil for crossref keys.") | |||
| 1215 | (,(concat "^[ \t]*\\(" bibtex-field-name "\\)[ \t]*=") | 1266 | (,(concat "^[ \t]*\\(" bibtex-field-name "\\)[ \t]*=") |
| 1216 | 1 font-lock-variable-name-face) | 1267 | 1 font-lock-variable-name-face) |
| 1217 | ;; url | 1268 | ;; url |
| 1218 | (bibtex-font-lock-url) (bibtex-font-lock-crossref)) | 1269 | (bibtex-font-lock-url) (bibtex-font-lock-crossref) |
| 1270 | ;; cite | ||
| 1271 | ,@(mapcar (lambda (matcher) | ||
| 1272 | `((lambda (bound) (bibtex-font-lock-cite ',matcher bound)))) | ||
| 1273 | bibtex-cite-matcher-alist)) | ||
| 1219 | "*Default expressions to highlight in BibTeX mode.") | 1274 | "*Default expressions to highlight in BibTeX mode.") |
| 1220 | 1275 | ||
| 1221 | (defvar bibtex-font-lock-url-regexp | 1276 | (defvar bibtex-font-lock-url-regexp |
| @@ -1223,7 +1278,7 @@ The CDRs of the elements are t for header keys and nil for crossref keys.") | |||
| 1223 | (concat "^[ \t]*" | 1278 | (concat "^[ \t]*" |
| 1224 | (regexp-opt (delete-dups (mapcar 'caar bibtex-generate-url-list)) t) | 1279 | (regexp-opt (delete-dups (mapcar 'caar bibtex-generate-url-list)) t) |
| 1225 | "[ \t]*=[ \t]*") | 1280 | "[ \t]*=[ \t]*") |
| 1226 | "Regexp for `bibtex-font-lock-url'.") | 1281 | "Regexp for `bibtex-font-lock-url' derived from `bibtex-generate-url-list'.") |
| 1227 | 1282 | ||
| 1228 | (defvar bibtex-string-empty-key nil | 1283 | (defvar bibtex-string-empty-key nil |
| 1229 | "If non-nil, `bibtex-parse-string' accepts empty key.") | 1284 | "If non-nil, `bibtex-parse-string' accepts empty key.") |
| @@ -1553,7 +1608,7 @@ If EMPTY-KEY is non-nil, key may be empty. Do not move point." | |||
| 1553 | bounds)))) | 1608 | bounds)))) |
| 1554 | 1609 | ||
| 1555 | (defun bibtex-reference-key-in-string (bounds) | 1610 | (defun bibtex-reference-key-in-string (bounds) |
| 1556 | "Return the key part of a BibTeX string defined via BOUNDS" | 1611 | "Return the key part of a BibTeX string defined via BOUNDS." |
| 1557 | (buffer-substring-no-properties (nth 1 (car bounds)) | 1612 | (buffer-substring-no-properties (nth 1 (car bounds)) |
| 1558 | (nth 2 (car bounds)))) | 1613 | (nth 2 (car bounds)))) |
| 1559 | 1614 | ||
| @@ -1626,8 +1681,8 @@ of the entry, see regexp `bibtex-entry-head'." | |||
| 1626 | (if (save-excursion | 1681 | (if (save-excursion |
| 1627 | (goto-char (match-end bibtex-type-in-head)) | 1682 | (goto-char (match-end bibtex-type-in-head)) |
| 1628 | (looking-at "[ \t]*(")) | 1683 | (looking-at "[ \t]*(")) |
| 1629 | ",?[ \t\n]*)" ;; entry opened with `(' | 1684 | ",?[ \t\n]*)" ; entry opened with `(' |
| 1630 | ",?[ \t\n]*}")) ;; entry opened with `{' | 1685 | ",?[ \t\n]*}")) ; entry opened with `{' |
| 1631 | bounds) | 1686 | bounds) |
| 1632 | (skip-chars-forward " \t\n") | 1687 | (skip-chars-forward " \t\n") |
| 1633 | ;; loop over all BibTeX fields | 1688 | ;; loop over all BibTeX fields |
| @@ -1736,7 +1791,7 @@ If FLAG is nil, a message is echoed if point was incremented at least | |||
| 1736 | (< (point) pnt)) | 1791 | (< (point) pnt)) |
| 1737 | (goto-char (match-beginning bibtex-type-in-head)) | 1792 | (goto-char (match-beginning bibtex-type-in-head)) |
| 1738 | (if (pos-visible-in-window-p (point)) | 1793 | (if (pos-visible-in-window-p (point)) |
| 1739 | (sit-for 1) | 1794 | (sit-for blink-matching-delay) |
| 1740 | (message "%s%s" prompt (buffer-substring-no-properties | 1795 | (message "%s%s" prompt (buffer-substring-no-properties |
| 1741 | (point) (match-end bibtex-key-in-head)))))))) | 1796 | (point) (match-end bibtex-key-in-head)))))))) |
| 1742 | 1797 | ||
| @@ -1801,21 +1856,19 @@ Optional arg BEG is beginning of entry." | |||
| 1801 | "Reinsert the Nth stretch of killed BibTeX text (field or entry). | 1856 | "Reinsert the Nth stretch of killed BibTeX text (field or entry). |
| 1802 | Optional arg COMMA is as in `bibtex-enclosing-field'." | 1857 | Optional arg COMMA is as in `bibtex-enclosing-field'." |
| 1803 | (unless bibtex-last-kill-command (error "BibTeX kill ring is empty")) | 1858 | (unless bibtex-last-kill-command (error "BibTeX kill ring is empty")) |
| 1804 | (let ((fun (lambda (kryp kr) ;; adapted from `current-kill' | 1859 | (let ((fun (lambda (kryp kr) ; adapted from `current-kill' |
| 1805 | (car (set kryp (nthcdr (mod (- n (length (eval kryp))) | 1860 | (car (set kryp (nthcdr (mod (- n (length (eval kryp))) |
| 1806 | (length kr)) kr)))))) | 1861 | (length kr)) kr)))))) |
| 1807 | (if (eq bibtex-last-kill-command 'field) | 1862 | (if (eq bibtex-last-kill-command 'field) |
| 1808 | (progn | 1863 | (progn |
| 1809 | ;; insert past the current field | 1864 | ;; insert past the current field |
| 1810 | (goto-char (bibtex-end-of-field (bibtex-enclosing-field comma))) | 1865 | (goto-char (bibtex-end-of-field (bibtex-enclosing-field comma))) |
| 1811 | (set-mark (point)) | 1866 | (push-mark) |
| 1812 | (message "Mark set") | ||
| 1813 | (bibtex-make-field (funcall fun 'bibtex-field-kill-ring-yank-pointer | 1867 | (bibtex-make-field (funcall fun 'bibtex-field-kill-ring-yank-pointer |
| 1814 | bibtex-field-kill-ring) t nil t)) | 1868 | bibtex-field-kill-ring) t nil t)) |
| 1815 | ;; insert past the current entry | 1869 | ;; insert past the current entry |
| 1816 | (bibtex-skip-to-valid-entry) | 1870 | (bibtex-skip-to-valid-entry) |
| 1817 | (set-mark (point)) | 1871 | (push-mark) |
| 1818 | (message "Mark set") | ||
| 1819 | (insert (funcall fun 'bibtex-entry-kill-ring-yank-pointer | 1872 | (insert (funcall fun 'bibtex-entry-kill-ring-yank-pointer |
| 1820 | bibtex-entry-kill-ring))))) | 1873 | bibtex-entry-kill-ring))))) |
| 1821 | 1874 | ||
| @@ -1835,6 +1888,15 @@ Formats current entry according to variable `bibtex-entry-format'." | |||
| 1835 | crossref-key bounds alternatives-there non-empty-alternative | 1888 | crossref-key bounds alternatives-there non-empty-alternative |
| 1836 | entry-list req-field-list field-list) | 1889 | entry-list req-field-list field-list) |
| 1837 | 1890 | ||
| 1891 | ;; Initialize `bibtex-field-braces-opt' and `bibtex-field-strings-opt' | ||
| 1892 | ;; if necessary. | ||
| 1893 | (unless bibtex-field-braces-opt | ||
| 1894 | (setq bibtex-field-braces-opt | ||
| 1895 | (bibtex-field-re-init bibtex-field-braces-alist 'braces))) | ||
| 1896 | (unless bibtex-field-strings-opt | ||
| 1897 | (setq bibtex-field-strings-opt | ||
| 1898 | (bibtex-field-re-init bibtex-field-strings-alist 'strings))) | ||
| 1899 | |||
| 1838 | ;; identify entry type | 1900 | ;; identify entry type |
| 1839 | (goto-char (point-min)) | 1901 | (goto-char (point-min)) |
| 1840 | (or (re-search-forward bibtex-entry-type nil t) | 1902 | (or (re-search-forward bibtex-entry-type nil t) |
| @@ -1904,7 +1966,7 @@ Formats current entry according to variable `bibtex-entry-format'." | |||
| 1904 | deleted) | 1966 | deleted) |
| 1905 | 1967 | ||
| 1906 | ;; We have more elegant high-level functions for several | 1968 | ;; We have more elegant high-level functions for several |
| 1907 | ;; tasks done by bibtex-format-entry. However, they contain | 1969 | ;; tasks done by `bibtex-format-entry'. However, they contain |
| 1908 | ;; quite some redundancy compared with what we need to do | 1970 | ;; quite some redundancy compared with what we need to do |
| 1909 | ;; anyway. So for speed-up we avoid using them. | 1971 | ;; anyway. So for speed-up we avoid using them. |
| 1910 | 1972 | ||
| @@ -1957,6 +2019,59 @@ Formats current entry according to variable `bibtex-entry-format'." | |||
| 1957 | "\\([\"{][0-9]+\\)[ \t\n]*--?[ \t\n]*\\([0-9]+[\"}]\\)"))) | 2019 | "\\([\"{][0-9]+\\)[ \t\n]*--?[ \t\n]*\\([0-9]+[\"}]\\)"))) |
| 1958 | (replace-match "\\1-\\2")) | 2020 | (replace-match "\\1-\\2")) |
| 1959 | 2021 | ||
| 2022 | ;; remove whitespace at beginning and end of field | ||
| 2023 | (when (memq 'whitespace format) | ||
| 2024 | (goto-char beg-text) | ||
| 2025 | (if (looking-at "\\([{\"]\\)[ \t\n]+") | ||
| 2026 | (replace-match "\\1")) | ||
| 2027 | (goto-char end-text) | ||
| 2028 | (if (looking-back "[ \t\n]+\\([}\"]\\)" beg-text t) | ||
| 2029 | (replace-match "\\1"))) | ||
| 2030 | |||
| 2031 | ;; enclose field text by braces according to | ||
| 2032 | ;; `bibtex-field-braces-alist'. | ||
| 2033 | (let (case-fold-search temp) ; Case-sensitive search | ||
| 2034 | (when (and (memq 'braces format) | ||
| 2035 | (setq temp (cdr (assoc-string field-name | ||
| 2036 | bibtex-field-braces-opt t)))) | ||
| 2037 | (goto-char beg-text) | ||
| 2038 | (while (re-search-forward temp end-text t) | ||
| 2039 | (let ((beg (match-beginning 0)) | ||
| 2040 | (bounds (bibtex-find-text-internal nil t))) | ||
| 2041 | (unless (or (nth 4 bounds) ; string constant | ||
| 2042 | ;; match already surrounded by braces | ||
| 2043 | ;; (braces are inside field delimiters) | ||
| 2044 | (and (< (point) (1- (nth 2 bounds))) | ||
| 2045 | (< (1+ (nth 1 bounds)) beg) | ||
| 2046 | (looking-at "}") | ||
| 2047 | (save-excursion (goto-char (1- beg)) | ||
| 2048 | (looking-at "{")))) | ||
| 2049 | (insert "}") | ||
| 2050 | (goto-char beg) | ||
| 2051 | (insert "{"))))) | ||
| 2052 | |||
| 2053 | ;; replace field text by BibTeX string constants according to | ||
| 2054 | ;; `bibtex-field-strings-alist'. | ||
| 2055 | (when (and (memq 'strings format) | ||
| 2056 | (setq temp (cdr (assoc-string field-name | ||
| 2057 | bibtex-field-strings-opt t)))) | ||
| 2058 | (goto-char beg-text) | ||
| 2059 | (dolist (re temp) | ||
| 2060 | (while (re-search-forward (car re) end-text t) | ||
| 2061 | (let ((bounds (save-match-data | ||
| 2062 | (bibtex-find-text-internal nil t)))) | ||
| 2063 | (unless (nth 4 bounds) | ||
| 2064 | ;; if match not at right subfield boundary... | ||
| 2065 | (if (< (match-end 0) (1- (nth 2 bounds))) | ||
| 2066 | (insert " # " (bibtex-field-left-delimiter)) | ||
| 2067 | (delete-char 1)) | ||
| 2068 | (replace-match (cdr re)) | ||
| 2069 | (goto-char (match-beginning 0)) | ||
| 2070 | ;; if match not at left subfield boundary... | ||
| 2071 | (if (< (1+ (nth 1 bounds)) (match-beginning 0)) | ||
| 2072 | (insert (bibtex-field-right-delimiter) " # ") | ||
| 2073 | (delete-backward-char 1)))))))) | ||
| 2074 | |||
| 1960 | ;; use book title of crossref'd entry | 2075 | ;; use book title of crossref'd entry |
| 1961 | (if (and (memq 'inherit-booktitle format) | 2076 | (if (and (memq 'inherit-booktitle format) |
| 1962 | empty-field | 2077 | empty-field |
| @@ -2047,6 +2162,31 @@ Formats current entry according to variable `bibtex-entry-format'." | |||
| 2047 | (if (memq 'realign format) | 2162 | (if (memq 'realign format) |
| 2048 | (bibtex-fill-entry)))))) | 2163 | (bibtex-fill-entry)))))) |
| 2049 | 2164 | ||
| 2165 | (defun bibtex-field-re-init (regexp-alist type) | ||
| 2166 | "Calculate optimized value for bibtex-regexp-TYPE-opt. | ||
| 2167 | This value is based on bibtex-regexp-TYPE-alist. TYPE is 'braces or 'strings. | ||
| 2168 | Return optimized value to be used by `bibtex-format-entry'." | ||
| 2169 | (setq regexp-alist | ||
| 2170 | (mapcar (lambda (e) | ||
| 2171 | (list (car e) | ||
| 2172 | (replace-regexp-in-string "[ \t\n]+" "[ \t\n]+" (nth 1 e)) | ||
| 2173 | (nth 2 e))) ; nil for 'braces'. | ||
| 2174 | regexp-alist)) | ||
| 2175 | (let (opt-list) | ||
| 2176 | ;; Loop over field names | ||
| 2177 | (dolist (field (delete-dups (apply 'append (mapcar 'car regexp-alist)))) | ||
| 2178 | (let (rules) | ||
| 2179 | ;; Collect all matches we have for this field name | ||
| 2180 | (dolist (e regexp-alist) | ||
| 2181 | (if (assoc-string field (car e) t) | ||
| 2182 | (push (cons (nth 1 e) (nth 2 e)) rules))) | ||
| 2183 | (if (eq type 'braces) | ||
| 2184 | ;; concatenate all regexps to a single regexp | ||
| 2185 | (setq rules (concat "\\(?:" (mapconcat 'car rules "\\|") "\\)"))) | ||
| 2186 | ;; create list of replacement rules. | ||
| 2187 | (push (cons field rules) opt-list))) | ||
| 2188 | opt-list)) | ||
| 2189 | |||
| 2050 | 2190 | ||
| 2051 | (defun bibtex-autokey-abbrev (string len) | 2191 | (defun bibtex-autokey-abbrev (string len) |
| 2052 | "Return an abbreviation of STRING with at least LEN characters. | 2192 | "Return an abbreviation of STRING with at least LEN characters. |
| @@ -2099,7 +2239,7 @@ and `bibtex-autokey-names-stretch'." | |||
| 2099 | (<= (length name-list) | 2239 | (<= (length name-list) |
| 2100 | (+ bibtex-autokey-names | 2240 | (+ bibtex-autokey-names |
| 2101 | bibtex-autokey-names-stretch))) | 2241 | bibtex-autokey-names-stretch))) |
| 2102 | ;; Take bibtex-autokey-names elements from beginning of name-list | 2242 | ;; Take `bibtex-autokey-names' elements from beginning of name-list |
| 2103 | (setq name-list (nreverse (nthcdr (- (length name-list) | 2243 | (setq name-list (nreverse (nthcdr (- (length name-list) |
| 2104 | bibtex-autokey-names) | 2244 | bibtex-autokey-names) |
| 2105 | (nreverse name-list))) | 2245 | (nreverse name-list))) |
| @@ -2161,7 +2301,7 @@ Return the result as a string" | |||
| 2161 | (setq word (match-string 0 titlestring) | 2301 | (setq word (match-string 0 titlestring) |
| 2162 | titlestring (substring titlestring (match-end 0))) | 2302 | titlestring (substring titlestring (match-end 0))) |
| 2163 | ;; Ignore words matched by one of the elements of | 2303 | ;; Ignore words matched by one of the elements of |
| 2164 | ;; bibtex-autokey-titleword-ignore | 2304 | ;; `bibtex-autokey-titleword-ignore' |
| 2165 | (unless (let ((lst bibtex-autokey-titleword-ignore)) | 2305 | (unless (let ((lst bibtex-autokey-titleword-ignore)) |
| 2166 | (while (and lst | 2306 | (while (and lst |
| 2167 | (not (string-match (concat "\\`\\(?:" (car lst) | 2307 | (not (string-match (concat "\\`\\(?:" (car lst) |
| @@ -2173,9 +2313,9 @@ Return the result as a string" | |||
| 2173 | (<= counter bibtex-autokey-titlewords)) | 2313 | (<= counter bibtex-autokey-titlewords)) |
| 2174 | (push word titlewords) | 2314 | (push word titlewords) |
| 2175 | (push word titlewords-extra)))) | 2315 | (push word titlewords-extra)))) |
| 2176 | ;; Obey bibtex-autokey-titlewords-stretch: | 2316 | ;; Obey `bibtex-autokey-titlewords-stretch': |
| 2177 | ;; If by now we have processed all words in titlestring, we include | 2317 | ;; If by now we have processed all words in titlestring, we include |
| 2178 | ;; titlewords-extra in titlewords. Otherwise, we ignore titlewords-extra. | 2318 | ;; titlewords-extra in titlewords. Otherwise, we ignore titlewords-extra. |
| 2179 | (unless (string-match "\\b\\w+" titlestring) | 2319 | (unless (string-match "\\b\\w+" titlestring) |
| 2180 | (setq titlewords (append titlewords-extra titlewords))) | 2320 | (setq titlewords (append titlewords-extra titlewords))) |
| 2181 | (mapconcat 'bibtex-autokey-demangle-title (nreverse titlewords) | 2321 | (mapconcat 'bibtex-autokey-demangle-title (nreverse titlewords) |
| @@ -2343,7 +2483,7 @@ for parsing BibTeX keys. If parsing fails, try to set this variable to nil." | |||
| 2343 | (push (cons key t) ref-keys))))))) | 2483 | (push (cons key t) ref-keys))))))) |
| 2344 | 2484 | ||
| 2345 | (let (;; ignore @String entries because they are handled | 2485 | (let (;; ignore @String entries because they are handled |
| 2346 | ;; separately by bibtex-parse-strings | 2486 | ;; separately by `bibtex-parse-strings' |
| 2347 | (bibtex-sort-ignore-string-entries t) | 2487 | (bibtex-sort-ignore-string-entries t) |
| 2348 | bounds) | 2488 | bounds) |
| 2349 | (bibtex-map-entries | 2489 | (bibtex-map-entries |
| @@ -2399,7 +2539,7 @@ Return alist of strings if parsing was completed, `aborted' otherwise." | |||
| 2399 | (setq bibtex-strings strings)))))) | 2539 | (setq bibtex-strings strings)))))) |
| 2400 | 2540 | ||
| 2401 | (defun bibtex-strings () | 2541 | (defun bibtex-strings () |
| 2402 | "Return `bibtex-strings'. Initialize this variable if necessary." | 2542 | "Return `bibtex-strings'. Initialize this variable if necessary." |
| 2403 | (if (listp bibtex-strings) bibtex-strings | 2543 | (if (listp bibtex-strings) bibtex-strings |
| 2404 | (bibtex-parse-strings (bibtex-string-files-init)))) | 2544 | (bibtex-parse-strings (bibtex-string-files-init)))) |
| 2405 | 2545 | ||
| @@ -2456,10 +2596,10 @@ Parsing initializes `bibtex-reference-keys' and `bibtex-strings'." | |||
| 2456 | bibtex-buffer-last-parsed-tick))) | 2596 | bibtex-buffer-last-parsed-tick))) |
| 2457 | (save-restriction | 2597 | (save-restriction |
| 2458 | (widen) | 2598 | (widen) |
| 2459 | ;; Output no progress messages in bibtex-parse-keys | 2599 | ;; Output no progress messages in `bibtex-parse-keys' |
| 2460 | ;; because when in y-or-n-p that can hide the question. | 2600 | ;; because when in `y-or-n-p' that can hide the question. |
| 2461 | (if (and (listp (bibtex-parse-keys t)) | 2601 | (if (and (listp (bibtex-parse-keys t)) |
| 2462 | ;; update bibtex-strings | 2602 | ;; update `bibtex-strings' |
| 2463 | (listp (bibtex-parse-strings strings-init t))) | 2603 | (listp (bibtex-parse-strings strings-init t))) |
| 2464 | 2604 | ||
| 2465 | ;; remember that parsing was successful | 2605 | ;; remember that parsing was successful |
| @@ -2519,28 +2659,35 @@ already set." | |||
| 2519 | COMPLETIONS is an alist of strings. If point is not after the part | 2659 | COMPLETIONS is an alist of strings. If point is not after the part |
| 2520 | of a word, all strings are listed. Return completion." | 2660 | of a word, all strings are listed. Return completion." |
| 2521 | ;; Return value is used by cleanup functions. | 2661 | ;; Return value is used by cleanup functions. |
| 2662 | ;; Code inspired by `lisp-complete-symbol'. | ||
| 2522 | (let* ((case-fold-search t) | 2663 | (let* ((case-fold-search t) |
| 2523 | (beg (save-excursion | 2664 | (beg (save-excursion |
| 2524 | (re-search-backward "[ \t{\"]") | 2665 | (re-search-backward "[ \t{\"]") |
| 2525 | (forward-char) | 2666 | (forward-char) |
| 2526 | (point))) | 2667 | (point))) |
| 2527 | (end (point)) | 2668 | (end (point)) |
| 2528 | (part-of-word (buffer-substring-no-properties beg end)) | 2669 | (pattern (buffer-substring-no-properties beg end)) |
| 2529 | (completion (try-completion part-of-word completions))) | 2670 | (completion (try-completion pattern completions))) |
| 2530 | (cond ((not completion) | 2671 | (cond ((not completion) |
| 2531 | (error "Can't find completion for `%s'" part-of-word)) | 2672 | (error "Can't find completion for `%s'" pattern)) |
| 2532 | ((eq completion t) | 2673 | ((eq completion t) |
| 2533 | part-of-word) | 2674 | pattern) |
| 2534 | ((not (string= part-of-word completion)) | 2675 | ((not (string= pattern completion)) |
| 2535 | (delete-region beg end) | 2676 | (delete-region beg end) |
| 2536 | (insert completion) | 2677 | (insert completion) |
| 2678 | ;; Don't leave around a completions buffer that's out of date. | ||
| 2679 | (let ((win (get-buffer-window "*Completions*" 0))) | ||
| 2680 | (if win (with-selected-window win (bury-buffer)))) | ||
| 2537 | completion) | 2681 | completion) |
| 2538 | (t | 2682 | (t |
| 2539 | (message "Making completion list...") | 2683 | (let ((minibuf-is-in-use |
| 2540 | (with-output-to-temp-buffer "*Completions*" | 2684 | (eq (minibuffer-window) (selected-window)))) |
| 2541 | (display-completion-list (all-completions part-of-word completions) | 2685 | (unless minibuf-is-in-use (message "Making completion list...")) |
| 2542 | part-of-word)) | 2686 | (with-output-to-temp-buffer "*Completions*" |
| 2543 | (message "Making completion list...done") | 2687 | (display-completion-list |
| 2688 | (sort (all-completions pattern completions) 'string<) pattern)) | ||
| 2689 | (unless minibuf-is-in-use | ||
| 2690 | (message "Making completion list...done"))) | ||
| 2544 | nil)))) | 2691 | nil)))) |
| 2545 | 2692 | ||
| 2546 | (defun bibtex-complete-string-cleanup (str compl) | 2693 | (defun bibtex-complete-string-cleanup (str compl) |
| @@ -2562,20 +2709,25 @@ Use `bibtex-summary-function' to generate summary." | |||
| 2562 | (bibtex-find-entry key t)) | 2709 | (bibtex-find-entry key t)) |
| 2563 | (message "Ref: %s" (funcall bibtex-summary-function))))) | 2710 | (message "Ref: %s" (funcall bibtex-summary-function))))) |
| 2564 | 2711 | ||
| 2565 | (defun bibtex-copy-summary-as-kill () | 2712 | (defun bibtex-copy-summary-as-kill (&optional arg) |
| 2566 | "Push summery of current BibTeX entry to kill ring. | 2713 | "Push summery of current BibTeX entry to kill ring. |
| 2567 | Use `bibtex-summary-function' to generate summary." | 2714 | Use `bibtex-summary-function' to generate summary. |
| 2568 | (interactive) | 2715 | If prefix ARG is non-nil push BibTeX entry's URL to kill ring |
| 2569 | (save-excursion | 2716 | that is generated by calling `bibtex-url'." |
| 2570 | (bibtex-beginning-of-entry) | 2717 | (interactive "P") |
| 2571 | (if (looking-at bibtex-entry-maybe-empty-head) | 2718 | (if arg (let ((url (bibtex-url nil t))) |
| 2572 | (kill-new (message "%s" (funcall bibtex-summary-function))) | 2719 | (if url (kill-new (message "%s" url)) |
| 2573 | (error "No entry found")))) | 2720 | (message "No URL known"))) |
| 2721 | (save-excursion | ||
| 2722 | (bibtex-beginning-of-entry) | ||
| 2723 | (if (looking-at bibtex-entry-maybe-empty-head) | ||
| 2724 | (kill-new (message "%s" (funcall bibtex-summary-function))) | ||
| 2725 | (error "No entry found"))))) | ||
| 2574 | 2726 | ||
| 2575 | (defun bibtex-summary () | 2727 | (defun bibtex-summary () |
| 2576 | "Return summary of current BibTeX entry. | 2728 | "Return summary of current BibTeX entry. |
| 2577 | Used as default value of `bibtex-summary-function'." | 2729 | Used as default value of `bibtex-summary-function'." |
| 2578 | ;; It would be neat to customize this function. How? | 2730 | ;; It would be neat to make this function customizable. How? |
| 2579 | (if (looking-at bibtex-entry-maybe-empty-head) | 2731 | (if (looking-at bibtex-entry-maybe-empty-head) |
| 2580 | (let* ((bibtex-autokey-name-case-convert-function 'identity) | 2732 | (let* ((bibtex-autokey-name-case-convert-function 'identity) |
| 2581 | (bibtex-autokey-name-length 'infty) | 2733 | (bibtex-autokey-name-length 'infty) |
| @@ -2664,16 +2816,17 @@ begins at the beginning of a line. We use this function for font-locking." | |||
| 2664 | (unless (looking-at field-reg) | 2816 | (unless (looking-at field-reg) |
| 2665 | (re-search-backward field-reg nil t)))) | 2817 | (re-search-backward field-reg nil t)))) |
| 2666 | 2818 | ||
| 2667 | (defun bibtex-font-lock-url (bound) | 2819 | (defun bibtex-font-lock-url (bound &optional no-button) |
| 2668 | "Font-lock for URLs. BOUND limits the search." | 2820 | "Font-lock for URLs. BOUND limits the search. |
| 2821 | If NO-BUTTON is non-nil do not generate buttons." | ||
| 2669 | (let ((case-fold-search t) | 2822 | (let ((case-fold-search t) |
| 2670 | (pnt (point)) | 2823 | (pnt (point)) |
| 2671 | field bounds start end found) | 2824 | name bounds start end found) |
| 2672 | (bibtex-beginning-of-field) | 2825 | (bibtex-beginning-of-field) |
| 2673 | (while (and (not found) | 2826 | (while (and (not found) |
| 2674 | (<= (point) bound) | 2827 | (<= (point) bound) |
| 2675 | (prog1 (re-search-forward bibtex-font-lock-url-regexp bound t) | 2828 | (prog1 (re-search-forward bibtex-font-lock-url-regexp bound t) |
| 2676 | (setq field (match-string-no-properties 1))) | 2829 | (setq name (match-string-no-properties 1))) |
| 2677 | (setq bounds (bibtex-parse-field-text)) | 2830 | (setq bounds (bibtex-parse-field-text)) |
| 2678 | (progn | 2831 | (progn |
| 2679 | (setq start (car bounds) end (nth 1 bounds)) | 2832 | (setq start (car bounds) end (nth 1 bounds)) |
| @@ -2682,17 +2835,18 @@ begins at the beginning of a line. We use this function for font-locking." | |||
| 2682 | (setq end (1- end))) | 2835 | (setq end (1- end))) |
| 2683 | (if (memq (char-after start) '(?\{ ?\")) | 2836 | (if (memq (char-after start) '(?\{ ?\")) |
| 2684 | (setq start (1+ start))) | 2837 | (setq start (1+ start))) |
| 2685 | (>= bound start))) | 2838 | (if (< start pnt) (setq start (min pnt end))) |
| 2686 | (let ((lst bibtex-generate-url-list) url) | 2839 | (<= start bound))) |
| 2687 | (goto-char start) | 2840 | (if (<= pnt start) |
| 2688 | (while (and (not found) | 2841 | (let ((lst bibtex-generate-url-list) url) |
| 2689 | (setq url (car (pop lst)))) | 2842 | (while (and (not found) (setq url (car (pop lst)))) |
| 2690 | (setq found (and (bibtex-string= field (car url)) | 2843 | (goto-char start) |
| 2691 | (re-search-forward (cdr url) end t) | 2844 | (setq found (and (bibtex-string= name (car url)) |
| 2692 | (>= (match-beginning 0) pnt))))) | 2845 | (re-search-forward (cdr url) end t)))))) |
| 2693 | (goto-char end)) | 2846 | (unless found (goto-char end))) |
| 2694 | (if found (bibtex-button (match-beginning 0) (match-end 0) | 2847 | (if (and found (not no-button)) |
| 2695 | 'bibtex-url (match-beginning 0))) | 2848 | (bibtex-button (match-beginning 0) (match-end 0) |
| 2849 | 'bibtex-url (match-beginning 0))) | ||
| 2696 | found)) | 2850 | found)) |
| 2697 | 2851 | ||
| 2698 | (defun bibtex-font-lock-crossref (bound) | 2852 | (defun bibtex-font-lock-crossref (bound) |
| @@ -2713,6 +2867,19 @@ begins at the beginning of a line. We use this function for font-locking." | |||
| 2713 | start t)) | 2867 | start t)) |
| 2714 | found)) | 2868 | found)) |
| 2715 | 2869 | ||
| 2870 | (defun bibtex-font-lock-cite (matcher bound) | ||
| 2871 | "Font-lock for cited keys. | ||
| 2872 | MATCHER identifies the cited key, see `bibtex-cite-matcher-alist'. | ||
| 2873 | BOUND limits the search." | ||
| 2874 | (let (case-fold-search) | ||
| 2875 | (if (re-search-forward (car matcher) bound t) | ||
| 2876 | (let ((start (match-beginning (cdr matcher))) | ||
| 2877 | (end (match-end (cdr matcher)))) | ||
| 2878 | (bibtex-button start end 'bibtex-find-crossref | ||
| 2879 | (buffer-substring-no-properties start end) | ||
| 2880 | start t t) | ||
| 2881 | t)))) | ||
| 2882 | |||
| 2716 | (defun bibtex-button-action (button) | 2883 | (defun bibtex-button-action (button) |
| 2717 | "Call BUTTON's BibTeX function." | 2884 | "Call BUTTON's BibTeX function." |
| 2718 | (apply (button-get button 'bibtex-function) | 2885 | (apply (button-get button 'bibtex-function) |
| @@ -2831,7 +2998,7 @@ if that value is non-nil. | |||
| 2831 | (list (list nil bibtex-entry-head bibtex-key-in-head)) | 2998 | (list (list nil bibtex-entry-head bibtex-key-in-head)) |
| 2832 | imenu-case-fold-search t) | 2999 | imenu-case-fold-search t) |
| 2833 | (make-local-variable 'choose-completion-string-functions) | 3000 | (make-local-variable 'choose-completion-string-functions) |
| 2834 | ;; XEmacs needs easy-menu-add, Emacs does not care | 3001 | ;; XEmacs needs `easy-menu-add', Emacs does not care |
| 2835 | (easy-menu-add bibtex-edit-menu) | 3002 | (easy-menu-add bibtex-edit-menu) |
| 2836 | (easy-menu-add bibtex-entry-menu) | 3003 | (easy-menu-add bibtex-entry-menu) |
| 2837 | (run-mode-hooks 'bibtex-mode-hook)) | 3004 | (run-mode-hooks 'bibtex-mode-hook)) |
| @@ -3125,7 +3292,7 @@ Return the new location of point." | |||
| 3125 | (goto-char (bibtex-end-of-string bounds))) | 3292 | (goto-char (bibtex-end-of-string bounds))) |
| 3126 | ((looking-at bibtex-any-valid-entry-type) | 3293 | ((looking-at bibtex-any-valid-entry-type) |
| 3127 | ;; Parsing of entry failed | 3294 | ;; Parsing of entry failed |
| 3128 | (error "Syntactically incorrect BibTeX entry starts here.")) | 3295 | (error "Syntactically incorrect BibTeX entry starts here")) |
| 3129 | (t (if (interactive-p) (message "Not on a known BibTeX entry.")) | 3296 | (t (if (interactive-p) (message "Not on a known BibTeX entry.")) |
| 3130 | (goto-char pnt))) | 3297 | (goto-char pnt))) |
| 3131 | (point))) | 3298 | (point))) |
| @@ -3163,7 +3330,7 @@ Otherwise display the beginning of entry." | |||
| 3163 | (defun bibtex-mark-entry () | 3330 | (defun bibtex-mark-entry () |
| 3164 | "Put mark at beginning, point at end of current BibTeX entry." | 3331 | "Put mark at beginning, point at end of current BibTeX entry." |
| 3165 | (interactive) | 3332 | (interactive) |
| 3166 | (set-mark (bibtex-beginning-of-entry)) | 3333 | (push-mark (bibtex-beginning-of-entry)) |
| 3167 | (bibtex-end-of-entry)) | 3334 | (bibtex-end-of-entry)) |
| 3168 | 3335 | ||
| 3169 | (defun bibtex-count-entries (&optional count-string-entries) | 3336 | (defun bibtex-count-entries (&optional count-string-entries) |
| @@ -3227,6 +3394,7 @@ of the head of the entry found. Return nil if no entry found." | |||
| 3227 | (list key nil entry-name)))))) | 3394 | (list key nil entry-name)))))) |
| 3228 | 3395 | ||
| 3229 | (defun bibtex-init-sort-entry-class-alist () | 3396 | (defun bibtex-init-sort-entry-class-alist () |
| 3397 | "Initialize `bibtex-sort-entry-class-alist' (buffer-local)." | ||
| 3230 | (unless (local-variable-p 'bibtex-sort-entry-class-alist) | 3398 | (unless (local-variable-p 'bibtex-sort-entry-class-alist) |
| 3231 | (set (make-local-variable 'bibtex-sort-entry-class-alist) | 3399 | (set (make-local-variable 'bibtex-sort-entry-class-alist) |
| 3232 | (let ((i -1) alist) | 3400 | (let ((i -1) alist) |
| @@ -3283,27 +3451,49 @@ are ignored." | |||
| 3283 | nil ; ENDKEY function | 3451 | nil ; ENDKEY function |
| 3284 | 'bibtex-lessp)) ; PREDICATE | 3452 | 'bibtex-lessp)) ; PREDICATE |
| 3285 | 3453 | ||
| 3286 | (defun bibtex-find-crossref (crossref-key &optional pnt split) | 3454 | (defun bibtex-find-crossref (crossref-key &optional pnt split noerror) |
| 3287 | "Move point to the beginning of BibTeX entry CROSSREF-KEY. | 3455 | "Move point to the beginning of BibTeX entry CROSSREF-KEY. |
| 3288 | If `bibtex-files' is non-nil, search all these files. | 3456 | If `bibtex-files' is non-nil, search all these files. |
| 3289 | Otherwise the search is limited to the current buffer. | 3457 | Otherwise the search is limited to the current buffer. |
| 3290 | Return position of entry if CROSSREF-KEY is found or nil otherwise. | 3458 | Return position of entry if CROSSREF-KEY is found or nil otherwise. |
| 3291 | If CROSSREF-KEY is in the same buffer like current entry but before it | 3459 | If CROSSREF-KEY is in the same buffer like current entry but before it |
| 3292 | an error is signaled. Optional arg PNT is the position of the referencing | 3460 | an error is signaled. If NOERRER is non-nil this error is suppressed. |
| 3293 | entry. It defaults to position of point. If optional arg SPLIT is non-nil, | 3461 | Optional arg PNT is the position of the referencing entry. It defaults |
| 3294 | split window so that both the referencing and the crossrefed entry are | 3462 | to position of point. If optional arg SPLIT is non-nil, split window |
| 3295 | displayed. | 3463 | so that both the referencing and the crossrefed entry are displayed. |
| 3296 | If called interactively, CROSSREF-KEY defaults to crossref key of current | 3464 | |
| 3297 | entry and SPLIT is t." | 3465 | If called interactively, CROSSREF-KEY defaults to either the crossref key |
| 3466 | of current entry or a key matched by `bibtex-cite-matcher-alist', | ||
| 3467 | whatever is nearer to the position of point. SPLIT is t. NOERROR is nil | ||
| 3468 | for a crossref key, t otherwise." | ||
| 3298 | (interactive | 3469 | (interactive |
| 3299 | (let ((crossref-key | 3470 | (save-excursion |
| 3300 | (save-excursion | 3471 | (let* ((pnt (point)) |
| 3301 | (bibtex-beginning-of-entry) | 3472 | (_ (bibtex-beginning-of-entry)) |
| 3302 | (let ((bounds (bibtex-search-forward-field "crossref" t))) | 3473 | (end (cdr (bibtex-valid-entry t))) |
| 3303 | (if bounds | 3474 | (_ (unless end (error "Not inside valid entry"))) |
| 3304 | (bibtex-text-in-field-bounds bounds t)))))) | 3475 | (beg (match-end 0)) ; set by `bibtex-valid-entry' |
| 3305 | (list (bibtex-read-key "Find crossref key: " crossref-key t) | 3476 | (bounds (bibtex-search-forward-field "crossref" end)) |
| 3306 | (point) t))) | 3477 | case-fold-search best temp crossref-key) |
| 3478 | (if bounds | ||
| 3479 | (setq crossref-key (bibtex-text-in-field-bounds bounds t) | ||
| 3480 | best (cons (bibtex-dist pnt (bibtex-end-of-field bounds) | ||
| 3481 | (bibtex-start-of-field bounds)) | ||
| 3482 | crossref-key))) | ||
| 3483 | (dolist (matcher bibtex-cite-matcher-alist) | ||
| 3484 | (goto-char beg) | ||
| 3485 | (while (re-search-forward (car matcher) end t) | ||
| 3486 | (setq temp (bibtex-dist pnt (match-end (cdr matcher)) | ||
| 3487 | (match-beginning (cdr matcher)))) | ||
| 3488 | ;; Accept the key closest to the position of point. | ||
| 3489 | (if (or (not best) (< temp (car best))) | ||
| 3490 | (setq best (cons temp (match-string-no-properties | ||
| 3491 | (cdr matcher))))))) | ||
| 3492 | (goto-char pnt) | ||
| 3493 | (setq temp (bibtex-read-key "Find crossref key: " (cdr best) t)) | ||
| 3494 | (list temp (point) t (not (and crossref-key | ||
| 3495 | (string= temp crossref-key))))))) | ||
| 3496 | |||
| 3307 | (let (buffer pos eqb) | 3497 | (let (buffer pos eqb) |
| 3308 | (save-excursion | 3498 | (save-excursion |
| 3309 | (setq pos (bibtex-find-entry crossref-key t) | 3499 | (setq pos (bibtex-find-entry crossref-key t) |
| @@ -3314,13 +3504,15 @@ entry and SPLIT is t." | |||
| 3314 | (split ; called (quasi) interactively | 3504 | (split ; called (quasi) interactively |
| 3315 | (unless pnt (setq pnt (point))) | 3505 | (unless pnt (setq pnt (point))) |
| 3316 | (goto-char pnt) | 3506 | (goto-char pnt) |
| 3317 | (if eqb (select-window (split-window)) | 3507 | (if (and eqb (= pos (save-excursion (bibtex-beginning-of-entry)))) |
| 3318 | (pop-to-buffer buffer)) | 3508 | (message "Key `%s' is current entry" crossref-key) |
| 3319 | (goto-char pos) | 3509 | (if eqb (select-window (split-window)) |
| 3320 | (bibtex-reposition-window) | 3510 | (pop-to-buffer buffer)) |
| 3321 | (beginning-of-line) | 3511 | (goto-char pos) |
| 3322 | (if (and eqb (> pnt pos)) | 3512 | (bibtex-reposition-window) |
| 3323 | (error "The referencing entry must precede the crossrefed entry!"))) | 3513 | (beginning-of-line) |
| 3514 | (if (and eqb (> pnt pos) (not noerror)) | ||
| 3515 | (error "The referencing entry must precede the crossrefed entry!")))) | ||
| 3324 | ;; `bibtex-find-crossref' is called noninteractively during | 3516 | ;; `bibtex-find-crossref' is called noninteractively during |
| 3325 | ;; clean-up of an entry. Then it is not possible to check | 3517 | ;; clean-up of an entry. Then it is not possible to check |
| 3326 | ;; whether the current entry and the crossrefed entry have | 3518 | ;; whether the current entry and the crossrefed entry have |
| @@ -3329,6 +3521,12 @@ entry and SPLIT is t." | |||
| 3329 | (t (set-buffer buffer) (goto-char pos))) | 3521 | (t (set-buffer buffer) (goto-char pos))) |
| 3330 | pos)) | 3522 | pos)) |
| 3331 | 3523 | ||
| 3524 | (defun bibtex-dist (pos beg end) | ||
| 3525 | "Return distance between POS and region delimited by BEG and END." | ||
| 3526 | (cond ((and (<= beg pos) (<= pos end)) 0) | ||
| 3527 | ((< pos beg) (- beg pos)) | ||
| 3528 | (t (- pos end)))) | ||
| 3529 | |||
| 3332 | (defun bibtex-find-entry (key &optional global start display) | 3530 | (defun bibtex-find-entry (key &optional global start display) |
| 3333 | "Move point to the beginning of BibTeX entry named KEY. | 3531 | "Move point to the beginning of BibTeX entry named KEY. |
| 3334 | Return position of entry if KEY is found or nil if not found. | 3532 | Return position of entry if KEY is found or nil if not found. |
| @@ -3394,7 +3592,7 @@ Return t if preparation was successful or nil if entry KEY already exists." | |||
| 3394 | ;; if key-exist is non-nil due to the previous cond clause | 3592 | ;; if key-exist is non-nil due to the previous cond clause |
| 3395 | ;; then point will be at beginning of entry named key. | 3593 | ;; then point will be at beginning of entry named key. |
| 3396 | (key-exist) | 3594 | (key-exist) |
| 3397 | (t ; bibtex-maintain-sorted-entries is non-nil | 3595 | (t ; `bibtex-maintain-sorted-entries' is non-nil |
| 3398 | (let* ((case-fold-search t) | 3596 | (let* ((case-fold-search t) |
| 3399 | (left (save-excursion (bibtex-beginning-of-first-entry))) | 3597 | (left (save-excursion (bibtex-beginning-of-first-entry))) |
| 3400 | (bounds (save-excursion (goto-char (point-max)) | 3598 | (bounds (save-excursion (goto-char (point-max)) |
| @@ -3576,7 +3774,7 @@ Return t if test was successful, nil otherwise." | |||
| 3576 | (delete-region (point-min) (point-max)) | 3774 | (delete-region (point-min) (point-max)) |
| 3577 | (insert "BibTeX mode command `bibtex-validate'\n" | 3775 | (insert "BibTeX mode command `bibtex-validate'\n" |
| 3578 | (if syntax-error | 3776 | (if syntax-error |
| 3579 | "Maybe undetected errors due to syntax errors. Correct and validate again.\n" | 3777 | "Maybe undetected errors due to syntax errors. Correct and validate again.\n" |
| 3580 | "\n")) | 3778 | "\n")) |
| 3581 | (dolist (err error-list) | 3779 | (dolist (err error-list) |
| 3582 | (insert (format "%s:%d: %s\n" file (car err) (cdr err)))) | 3780 | (insert (format "%s:%d: %s\n" file (car err) (cdr err)))) |
| @@ -3737,7 +3935,7 @@ Optional arg COMMA is as in `bibtex-enclosing-field'." | |||
| 3737 | end-text (or (match-end bibtex-key-in-head) | 3935 | end-text (or (match-end bibtex-key-in-head) |
| 3738 | (match-end 0)) | 3936 | (match-end 0)) |
| 3739 | end end-text | 3937 | end end-text |
| 3740 | no-sub t) ;; subfields do not make sense | 3938 | no-sub t) ; subfields do not make sense |
| 3741 | (setq failure t))) | 3939 | (setq failure t))) |
| 3742 | (t (setq failure t))) | 3940 | (t (setq failure t))) |
| 3743 | (when (and subfield (not failure)) | 3941 | (when (and subfield (not failure)) |
| @@ -3926,8 +4124,8 @@ begin on separate lines prior to calling `bibtex-clean-entry' or if | |||
| 3926 | Don't call `bibtex-clean-entry' on @Preamble entries. | 4124 | Don't call `bibtex-clean-entry' on @Preamble entries. |
| 3927 | At end of the cleaning process, the functions in | 4125 | At end of the cleaning process, the functions in |
| 3928 | `bibtex-clean-entry-hook' are called with region narrowed to entry." | 4126 | `bibtex-clean-entry-hook' are called with region narrowed to entry." |
| 3929 | ;; Opt. arg called-by-reformat is t if bibtex-clean-entry | 4127 | ;; Opt. arg CALLED-BY-REFORMAT is t if `bibtex-clean-entry' |
| 3930 | ;; is called by bibtex-reformat | 4128 | ;; is called by `bibtex-reformat' |
| 3931 | (interactive "P") | 4129 | (interactive "P") |
| 3932 | (let ((case-fold-search t) | 4130 | (let ((case-fold-search t) |
| 3933 | (start (bibtex-beginning-of-entry)) | 4131 | (start (bibtex-beginning-of-entry)) |
| @@ -3946,7 +4144,7 @@ At end of the cleaning process, the functions in | |||
| 3946 | ;; set key | 4144 | ;; set key |
| 3947 | (when (or new-key (not key)) | 4145 | (when (or new-key (not key)) |
| 3948 | (setq key (bibtex-generate-autokey)) | 4146 | (setq key (bibtex-generate-autokey)) |
| 3949 | ;; Sometimes bibtex-generate-autokey returns an empty string | 4147 | ;; Sometimes `bibtex-generate-autokey' returns an empty string |
| 3950 | (if (or bibtex-autokey-edit-before-use (string= "" key)) | 4148 | (if (or bibtex-autokey-edit-before-use (string= "" key)) |
| 3951 | (setq key (if (eq entry-type 'string) | 4149 | (setq key (if (eq entry-type 'string) |
| 3952 | (bibtex-read-string-key key) | 4150 | (bibtex-read-string-key key) |
| @@ -4027,7 +4225,7 @@ If optional arg MOVE is non-nil move point to end of field." | |||
| 4027 | (if (not justify) | 4225 | (if (not justify) |
| 4028 | (goto-char (bibtex-start-of-text-in-field bounds)) | 4226 | (goto-char (bibtex-start-of-text-in-field bounds)) |
| 4029 | (goto-char (bibtex-start-of-field bounds)) | 4227 | (goto-char (bibtex-start-of-field bounds)) |
| 4030 | (forward-char) ;; leading comma | 4228 | (forward-char) ; leading comma |
| 4031 | (bibtex-delete-whitespace) | 4229 | (bibtex-delete-whitespace) |
| 4032 | (open-line 1) | 4230 | (open-line 1) |
| 4033 | (forward-char) | 4231 | (forward-char) |
| @@ -4045,7 +4243,7 @@ If optional arg MOVE is non-nil move point to end of field." | |||
| 4045 | (if bibtex-align-at-equal-sign | 4243 | (if bibtex-align-at-equal-sign |
| 4046 | (insert " ") | 4244 | (insert " ") |
| 4047 | (indent-to-column bibtex-text-indentation))) | 4245 | (indent-to-column bibtex-text-indentation))) |
| 4048 | ;; Paragraphs within fields are not preserved. Bother? | 4246 | ;; Paragraphs within fields are not preserved. Bother? |
| 4049 | (fill-region-as-paragraph (line-beginning-position) end-field | 4247 | (fill-region-as-paragraph (line-beginning-position) end-field |
| 4050 | default-justification nil (point)) | 4248 | default-justification nil (point)) |
| 4051 | (if move (goto-char end-field)))) | 4249 | (if move (goto-char end-field)))) |
| @@ -4130,15 +4328,19 @@ If mark is active reformat entries in region, if not in whole buffer." | |||
| 4130 | (,(concat (if bibtex-comma-after-last-field "Insert" "Remove") | 4328 | (,(concat (if bibtex-comma-after-last-field "Insert" "Remove") |
| 4131 | " comma at end of entry? ") . 'last-comma) | 4329 | " comma at end of entry? ") . 'last-comma) |
| 4132 | ("Replace double page dashes by single ones? " . 'page-dashes) | 4330 | ("Replace double page dashes by single ones? " . 'page-dashes) |
| 4331 | ("Delete whitespace at the beginning and end of fields? " . 'whitespace) | ||
| 4133 | ("Inherit booktitle? " . 'inherit-booktitle) | 4332 | ("Inherit booktitle? " . 'inherit-booktitle) |
| 4134 | ("Force delimiters? " . 'delimiters) | 4333 | ("Force delimiters? " . 'delimiters) |
| 4135 | ("Unify case of entry types and field names? " . 'unify-case)))))) | 4334 | ("Unify case of entry types and field names? " . 'unify-case) |
| 4335 | ("Enclose parts of field entries by braces? " . 'braces) | ||
| 4336 | ("Replace parts of field entries by string constants? " . 'strings)))))) | ||
| 4136 | ;; Do not include required-fields because `bibtex-reformat' | 4337 | ;; Do not include required-fields because `bibtex-reformat' |
| 4137 | ;; cannot handle the error messages of `bibtex-format-entry'. | 4338 | ;; cannot handle the error messages of `bibtex-format-entry'. |
| 4138 | ;; Use `bibtex-validate' to check for required fields. | 4339 | ;; Use `bibtex-validate' to check for required fields. |
| 4139 | ((eq t bibtex-entry-format) | 4340 | ((eq t bibtex-entry-format) |
| 4140 | '(realign opts-or-alts numerical-fields delimiters | 4341 | '(realign opts-or-alts numerical-fields delimiters |
| 4141 | last-comma page-dashes unify-case inherit-booktitle)) | 4342 | last-comma page-dashes unify-case inherit-booktitle |
| 4343 | whitespace braces strings)) | ||
| 4142 | (t | 4344 | (t |
| 4143 | (remove 'required-fields (push 'realign bibtex-entry-format))))) | 4345 | (remove 'required-fields (push 'realign bibtex-entry-format))))) |
| 4144 | (reformat-reference-keys | 4346 | (reformat-reference-keys |
| @@ -4178,7 +4380,7 @@ entries from minibuffer." | |||
| 4178 | (message "Starting to validate buffer...") | 4380 | (message "Starting to validate buffer...") |
| 4179 | (sit-for 1 nil t) | 4381 | (sit-for 1 nil t) |
| 4180 | (bibtex-realign) | 4382 | (bibtex-realign) |
| 4181 | (deactivate-mark) ; So bibtex-validate works on the whole buffer. | 4383 | (deactivate-mark) ; So `bibtex-validate' works on the whole buffer. |
| 4182 | (if (not (let (bibtex-maintain-sorted-entries) | 4384 | (if (not (let (bibtex-maintain-sorted-entries) |
| 4183 | (bibtex-validate))) | 4385 | (bibtex-validate))) |
| 4184 | (message "Correct errors and call `bibtex-convert-alien' again") | 4386 | (message "Correct errors and call `bibtex-convert-alien' again") |
| @@ -4186,7 +4388,7 @@ entries from minibuffer." | |||
| 4186 | (sit-for 2 nil t) | 4388 | (sit-for 2 nil t) |
| 4187 | (bibtex-reformat read-options) | 4389 | (bibtex-reformat read-options) |
| 4188 | (goto-char (point-max)) | 4390 | (goto-char (point-max)) |
| 4189 | (message "Buffer is now parsable. Please save it."))) | 4391 | (message "Buffer is now parsable. Please save it."))) |
| 4190 | 4392 | ||
| 4191 | (defun bibtex-complete () | 4393 | (defun bibtex-complete () |
| 4192 | "Complete word fragment before point according to context. | 4394 | "Complete word fragment before point according to context. |
| @@ -4249,7 +4451,7 @@ An error is signaled if point is outside key or BibTeX field." | |||
| 4249 | ;; | 4451 | ;; |
| 4250 | ;; If we quit the *Completions* buffer without requesting | 4452 | ;; If we quit the *Completions* buffer without requesting |
| 4251 | ;; a completion, `choose-completion-string-functions' is still | 4453 | ;; a completion, `choose-completion-string-functions' is still |
| 4252 | ;; non-nil. Therefore, `choose-completion-string-functions' is | 4454 | ;; non-nil. Therefore, `choose-completion-string-functions' is |
| 4253 | ;; always set (either to non-nil or nil) when a new completion | 4455 | ;; always set (either to non-nil or nil) when a new completion |
| 4254 | ;; is requested. | 4456 | ;; is requested. |
| 4255 | (let (completion-ignore-case) | 4457 | (let (completion-ignore-case) |
| @@ -4276,7 +4478,7 @@ An error is signaled if point is outside key or BibTeX field." | |||
| 4276 | (setq choose-completion-string-functions nil) | 4478 | (setq choose-completion-string-functions nil) |
| 4277 | (choose-completion-string choice buffer base-size) | 4479 | (choose-completion-string choice buffer base-size) |
| 4278 | (bibtex-complete-string-cleanup choice ',compl) | 4480 | (bibtex-complete-string-cleanup choice ',compl) |
| 4279 | t)) ; needed by choose-completion-string-functions | 4481 | t)) ; needed by `choose-completion-string-functions' |
| 4280 | (bibtex-complete-string-cleanup (bibtex-complete-internal compl) | 4482 | (bibtex-complete-string-cleanup (bibtex-complete-internal compl) |
| 4281 | compl))) | 4483 | compl))) |
| 4282 | 4484 | ||
| @@ -4391,44 +4593,94 @@ An error is signaled if point is outside key or BibTeX field." | |||
| 4391 | "Browse a URL for the BibTeX entry at point. | 4593 | "Browse a URL for the BibTeX entry at point. |
| 4392 | Optional POS is the location of the BibTeX entry. | 4594 | Optional POS is the location of the BibTeX entry. |
| 4393 | The URL is generated using the schemes defined in `bibtex-generate-url-list' | 4595 | The URL is generated using the schemes defined in `bibtex-generate-url-list' |
| 4394 | \(see there\). Then the URL is passed to `browse-url' unless NO-BROWSE is nil. | 4596 | \(see there\). If multiple schemes match for this entry, or the same scheme |
| 4597 | matches more than once, use the one for which the first step's match is the | ||
| 4598 | closest to POS. The URL is passed to `browse-url' unless NO-BROWSE is t. | ||
| 4395 | Return the URL or nil if none can be generated." | 4599 | Return the URL or nil if none can be generated." |
| 4396 | (interactive) | 4600 | (interactive) |
| 4601 | (unless pos (setq pos (point))) | ||
| 4397 | (save-excursion | 4602 | (save-excursion |
| 4398 | (if pos (goto-char pos)) | 4603 | (goto-char pos) |
| 4399 | (bibtex-beginning-of-entry) | 4604 | (bibtex-beginning-of-entry) |
| 4400 | ;; Always remove field delimiters | 4605 | (let ((end (save-excursion (bibtex-end-of-entry))) |
| 4401 | (let ((fields-alist (bibtex-parse-entry t)) | 4606 | (fields-alist (save-excursion (bibtex-parse-entry t))) |
| 4402 | ;; Always ignore case, | 4607 | ;; Always ignore case, |
| 4403 | (case-fold-search t) | 4608 | (case-fold-search t) |
| 4404 | (lst bibtex-generate-url-list) | 4609 | text url scheme obj fmt fl-match step) |
| 4405 | field url scheme obj fmt) | 4610 | ;; The return value of `bibtex-parse-entry' (i.e., FIELDS-ALIST) |
| 4406 | (while (setq scheme (pop lst)) | 4611 | ;; is always used to generate the URL. However, if the BibTeX |
| 4407 | (when (and (setq field (cdr (assoc-string (caar scheme) | 4612 | ;; entry contains more than one URL, we have multiple matches |
| 4408 | fields-alist t))) | 4613 | ;; for the first step defining the generation of the URL. |
| 4409 | (string-match (cdar scheme) field)) | 4614 | ;; Therefore, we try to initiate the generation of the URL |
| 4410 | (setq lst nil | 4615 | ;; based on the match of `bibtex-font-lock-url' that is the |
| 4411 | scheme (cdr scheme) | 4616 | ;; closest to POS. If that fails (no match found) we try to |
| 4412 | url (if (null scheme) (match-string 0 field) | 4617 | ;; initiate the generation of the URL based on the properly |
| 4413 | (if (stringp (car scheme)) | 4618 | ;; concatenated CONTENT of the field as returned by |
| 4414 | (setq fmt (pop scheme))) | 4619 | ;; `bibtex-text-in-field-bounds'. The latter approach can |
| 4415 | (dolist (step scheme) | 4620 | ;; differ from the former because `bibtex-font-lock-url' uses |
| 4416 | (setq field (cdr (assoc-string (car step) fields-alist t))) | 4621 | ;; the buffer itself. |
| 4417 | (if (string-match (nth 1 step) field) | 4622 | (while (bibtex-font-lock-url end t) |
| 4418 | (push (cond ((functionp (nth 2 step)) | 4623 | (push (list (bibtex-dist pos (match-beginning 0) (match-end 0)) |
| 4419 | (funcall (nth 2 step) field)) | 4624 | (match-beginning 0) |
| 4420 | ((numberp (nth 2 step)) | 4625 | (buffer-substring-no-properties |
| 4421 | (match-string (nth 2 step) field)) | 4626 | (match-beginning 0) (match-end 0))) |
| 4422 | (t | 4627 | fl-match) |
| 4423 | (replace-match (nth 2 step) t nil field))) | 4628 | ;; `bibtex-font-lock-url' moves point to end of match. |
| 4424 | obj) | 4629 | (forward-char)) |
| 4425 | ;; If the scheme is set up correctly, | 4630 | (when fl-match |
| 4426 | ;; we should never reach this point | 4631 | (setq fl-match (car (sort fl-match (lambda (x y) (< (car x) (car y)))))) |
| 4427 | (error "Match failed: %s" field))) | 4632 | (goto-char (nth 1 fl-match)) |
| 4428 | (if fmt (apply 'format fmt (nreverse obj)) | 4633 | (bibtex-beginning-of-field) (re-search-backward ",") |
| 4429 | (apply 'concat (nreverse obj))))) | 4634 | (let* ((bounds (bibtex-parse-field)) |
| 4430 | (if (interactive-p) (message "%s" url)) | 4635 | (name (bibtex-name-in-field bounds)) |
| 4431 | (unless no-browse (browse-url url)))) | 4636 | (content (bibtex-text-in-field-bounds bounds t)) |
| 4637 | (lst bibtex-generate-url-list)) | ||
| 4638 | ;; This match can fail when CONTENT differs from text in buffer. | ||
| 4639 | (when (string-match (regexp-quote (nth 2 fl-match)) content) | ||
| 4640 | ;; TEXT is the part of CONTENT that starts with the match | ||
| 4641 | ;; of `bibtex-font-lock-url' we are looking for. | ||
| 4642 | (setq text (substring content (match-beginning 0))) | ||
| 4643 | (while (and (not url) (setq scheme (pop lst))) | ||
| 4644 | ;; Verify the match of `bibtex-font-lock-url' by | ||
| 4645 | ;; comparing with TEXT. | ||
| 4646 | (when (and (bibtex-string= (caar scheme) name) | ||
| 4647 | (string-match (cdar scheme) text)) | ||
| 4648 | (setq url t scheme (cdr scheme))))))) | ||
| 4649 | |||
| 4650 | ;; If the match of `bibtex-font-lock-url' was not approved | ||
| 4651 | ;; parse FIELDS-ALIST, i.e., the output of `bibtex-parse-entry'. | ||
| 4652 | (unless url | ||
| 4653 | (let ((lst bibtex-generate-url-list)) | ||
| 4654 | (while (and (not url) (setq scheme (pop lst))) | ||
| 4655 | (when (and (setq text (cdr (assoc-string (caar scheme) | ||
| 4656 | fields-alist t))) | ||
| 4657 | (string-match (cdar scheme) text)) | ||
| 4658 | (setq url t scheme (cdr scheme)))))) | ||
| 4659 | |||
| 4660 | (when url | ||
| 4661 | (setq url (if (null scheme) (match-string 0 text) | ||
| 4662 | (if (stringp (car scheme)) | ||
| 4663 | (setq fmt (pop scheme))) | ||
| 4664 | (dotimes (i (length scheme)) | ||
| 4665 | (setq step (nth i scheme)) | ||
| 4666 | ;; The first step shall use TEXT as obtained earlier. | ||
| 4667 | (unless (= i 0) | ||
| 4668 | (setq text (cdr (assoc-string (car step) fields-alist t)))) | ||
| 4669 | (if (string-match (nth 1 step) text) | ||
| 4670 | (push (cond ((functionp (nth 2 step)) | ||
| 4671 | (funcall (nth 2 step) text)) | ||
| 4672 | ((numberp (nth 2 step)) | ||
| 4673 | (match-string (nth 2 step) text)) | ||
| 4674 | (t | ||
| 4675 | (replace-match (nth 2 step) t nil text))) | ||
| 4676 | obj) | ||
| 4677 | ;; If SCHEME is set up correctly, | ||
| 4678 | ;; we should never reach this point | ||
| 4679 | (error "Match failed: %s" text))) | ||
| 4680 | (if fmt (apply 'format fmt (nreverse obj)) | ||
| 4681 | (apply 'concat (nreverse obj))))) | ||
| 4682 | (if (interactive-p) (message "%s" url)) | ||
| 4683 | (unless no-browse (browse-url url))) | ||
| 4432 | (if (and (not url) (interactive-p)) (message "No URL known.")) | 4684 | (if (and (not url) (interactive-p)) (message "No URL known.")) |
| 4433 | url))) | 4685 | url))) |
| 4434 | 4686 | ||