aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/textmodes/bibtex.el508
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.
112numerical-fields Delete delimiters around numeral fields. 112numerical-fields Delete delimiters around numeral fields.
113page-dashes Change double dashes in page field to single dash 113page-dashes Change double dashes in page field to single dash
114 (for scribe compatibility). 114 (for scribe compatibility).
115whitespace Delete whitespace at the beginning and end of fields.
115inherit-booktitle If entry contains a crossref field and the booktitle 116inherit-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,
123delimiters Change delimiters according to variables 124delimiters Change delimiters according to variables
124 `bibtex-field-delimiters' and `bibtex-entry-delimiters'. 125 `bibtex-field-delimiters' and `bibtex-entry-delimiters'.
125unify-case Change case of entry and field names. 126unify-case Change case of entry and field names.
127braces Enclose parts of field entries by braces according to
128 `bibtex-field-braces-alist'.
129strings Replace parts of field entries by string constants
130 according to `bibtex-field-strings-alist'.
126 131
127The value t means do all of the above formatting actions. 132The value t means do all of the above formatting actions.
128The value nil means do no formatting at all." 133The 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.
153Each element has the form (FIELDS REGEXP), where FIELDS is a list
154of BibTeX field names and REGEXP is a regexp.
155Whitespace 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.
163Each element has the form (FIELDS REGEXP TO-STR), where FIELDS is a list
164of BibTeX field names. In FIELDS search for REGEXP, which are replaced
165by the BibTeX string constant TO-STR.
166Whitespace 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.
934Each rule should be of the form (REGEXP . SUBEXP), where SUBEXP
935specifies which parenthesized expression in REGEXP is a cited key.
936Case is significant.
937Used 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'.
1115Created by `bibtex-field-re-init'.
1116It is a an alist with elements (FIELD . REGEXP).")
1117
1118(defvar bibtex-field-strings-opt nil
1119 "Optimized value of `bibtex-field-strings-alist'.
1120Created by `bibtex-field-re-init'.
1121It is a an alist with elements (FIELD RULE1 RULE2 ...),
1122where 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).
1802Optional arg COMMA is as in `bibtex-enclosing-field'." 1857Optional 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.
2167This value is based on bibtex-regexp-TYPE-alist. TYPE is 'braces or 'strings.
2168Return 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."
2519COMPLETIONS is an alist of strings. If point is not after the part 2659COMPLETIONS is an alist of strings. If point is not after the part
2520of a word, all strings are listed. Return completion." 2660of 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.
2567Use `bibtex-summary-function' to generate summary." 2714Use `bibtex-summary-function' to generate summary.
2568 (interactive) 2715If prefix ARG is non-nil push BibTeX entry's URL to kill ring
2569 (save-excursion 2716that 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.
2577Used as default value of `bibtex-summary-function'." 2729Used 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.
2821If 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.
2872MATCHER identifies the cited key, see `bibtex-cite-matcher-alist'.
2873BOUND 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.
3288If `bibtex-files' is non-nil, search all these files. 3456If `bibtex-files' is non-nil, search all these files.
3289Otherwise the search is limited to the current buffer. 3457Otherwise the search is limited to the current buffer.
3290Return position of entry if CROSSREF-KEY is found or nil otherwise. 3458Return position of entry if CROSSREF-KEY is found or nil otherwise.
3291If CROSSREF-KEY is in the same buffer like current entry but before it 3459If CROSSREF-KEY is in the same buffer like current entry but before it
3292an error is signaled. Optional arg PNT is the position of the referencing 3460an error is signaled. If NOERRER is non-nil this error is suppressed.
3293entry. It defaults to position of point. If optional arg SPLIT is non-nil, 3461Optional arg PNT is the position of the referencing entry. It defaults
3294split window so that both the referencing and the crossrefed entry are 3462to position of point. If optional arg SPLIT is non-nil, split window
3295displayed. 3463so that both the referencing and the crossrefed entry are displayed.
3296If called interactively, CROSSREF-KEY defaults to crossref key of current 3464
3297entry and SPLIT is t." 3465If called interactively, CROSSREF-KEY defaults to either the crossref key
3466of current entry or a key matched by `bibtex-cite-matcher-alist',
3467whatever is nearer to the position of point. SPLIT is t. NOERROR is nil
3468for 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.
3334Return position of entry if KEY is found or nil if not found. 3532Return 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
3926Don't call `bibtex-clean-entry' on @Preamble entries. 4124Don't call `bibtex-clean-entry' on @Preamble entries.
3927At end of the cleaning process, the functions in 4125At 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.
4392Optional POS is the location of the BibTeX entry. 4594Optional POS is the location of the BibTeX entry.
4393The URL is generated using the schemes defined in `bibtex-generate-url-list' 4595The 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
4597matches more than once, use the one for which the first step's match is the
4598closest to POS. The URL is passed to `browse-url' unless NO-BROWSE is t.
4395Return the URL or nil if none can be generated." 4599Return 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