;;; bibtex.el --- BibTeX mode for GNU Emacs -*- lexical-binding: t -*-
-;; Copyright (C) 1992, 1994-1999, 2001-2011 Free Software Foundation, Inc.
+;; Copyright (C) 1992, 1994-1999, 2001-2014 Free Software Foundation,
+;; Inc.
;; Author: Stefan Schoef <schoef@offis.uni-oldenburg.de>
;; Bengt Martensson <bengt@mathematik.uni-Bremen.de>
ALTERNATIVE if non-nil is an integer that numbers sets of
alternatives, starting from zero."
:group 'BibTeX
+ :version "24.1"
:type 'bibtex-entry-alist)
(put 'bibtex-BibTeX-entry-alist 'risky-local-variable t)
nil
(("editor") ("editora") ("editorb") ("editorc")
("translator") ("annotator") ("commentator")
- ("introduction") ("foreword") ("afterword") ("titleaddon")
+ ("introduction") ("foreword") ("afterword") ("subtitle") ("titleaddon")
("maintitle") ("mainsubtitle") ("maintitleaddon")
("language") ("origlanguage") ("volume") ("part") ("edition") ("volumes")
("series") ("number") ("note") ("publisher") ("location") ("isbn")
("location") ("isbn") ("pagetotal") ("addendum") ("pubstate") ("doi")
("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate")))
("InCollection" "Article in a Collection"
- (("author") ("editor") ("title") ("year" nil nil 0) ("date" nil nil 0))
+ (("author") ("title") ("year" nil nil 0) ("date" nil nil 0))
(("booktitle"))
- (("editora") ("editorb") ("editorc") ("translator") ("annotator")
+ (("editor") ("editora") ("editorb") ("editorc") ("translator") ("annotator")
("commentator") ("introduction") ("foreword") ("afterword")
("subtitle") ("titleaddon") ("maintitle") ("mainsubtitle")
("maintitleaddon") ("booksubtitle") ("booktitleaddon")
("addendum") ("pubstate") ("doi") ("eprint") ("eprintclass")
("eprinttype") ("url") ("urldate")))
("Proceedings" "Single-Volume Conference Proceedings"
- (("editor") ("title") ("year" nil nil 0) ("date" nil nil 0))
+ (("title") ("year" nil nil 0) ("date" nil nil 0))
nil
(("subtitle") ("titleaddon") ("maintitle") ("mainsubtitle")
("maintitleaddon") ("eventtitle") ("eventdate") ("venue") ("language")
+ ("editor")
("volume") ("part") ("volumes") ("series") ("number") ("note")
("organization") ("publisher") ("location") ("month")
("isbn") ("chapter") ("pages") ("pagetotal") ("addendum") ("pubstate")
("isbn") ("pagetotal") ("addendum") ("pubstate")
("doi") ("eprint") ("eprintclass") ("eprinttype") ("url") ("urldate")))
("InProceedings" "Article in Conference Proceedings"
- (("author") ("editor") ("title") ("year" nil nil 0) ("date" nil nil 0))
+ (("author") ("title") ("year" nil nil 0) ("date" nil nil 0))
(("booktitle"))
- (("subtitle") ("titleaddon") ("maintitle") ("mainsubtitle")
+ (("editor") ("subtitle") ("titleaddon") ("maintitle") ("mainsubtitle")
("maintitleaddon") ("booksubtitle") ("booktitleaddon")
("eventtitle") ("eventdate") ("venue") ("language")
("volume") ("part") ("volumes") ("series") ("number") ("note")
"Alist of biblatex entry types and their associated fields.
It has the same format as `bibtex-BibTeX-entry-alist'."
:group 'bibtex
+ :version "24.1"
:type 'bibtex-entry-alist)
(put 'bibtex-biblatex-entry-alist 'risky-local-variable t)
Each element is a list (FIELD COMMENT). COMMENT is used as a default
if `bibtex-BibTeX-entry-alist' does not define a comment for FIELD."
:group 'bibtex
+ :version "24.1"
:type 'bibtex-field-alist)
(defcustom bibtex-biblatex-field-alist
"Alist of biblatex fields.
It has the same format as `bibtex-BibTeX-entry-alist'."
:group 'bibtex
+ :version "24.1"
:type 'bibtex-field-alist)
(defcustom bibtex-dialect-list '(BibTeX biblatex)
the allowed entries and bibtex-DIALECT-field-alist defines known field types.
Predefined dialects include BibTeX and biblatex."
:group 'bibtex
+ :version "24.1"
:type '(repeat (symbol :tag "Dialect")))
(defcustom bibtex-dialect 'BibTeX
"Current BibTeX dialect. For allowed values see `bibtex-dialect-list'.
-During a session change it via `bibtex-set-dialect'."
+To interactively change the dialect use the command `bibtex-set-dialect'."
:group 'bibtex
+ :version "24.1"
:set '(lambda (symbol value)
(set-default symbol value)
;; `bibtex-set-dialect' is undefined during loading (no problem)
:type '(choice (const BibTeX)
(const biblatex)
(symbol :tag "Custom")))
+(put 'bibtex-dialect 'safe-local-variable 'symbolp)
(defcustom bibtex-no-opt-remove-re "\\`option"
"If a field name matches this regexp, the prefix OPT is not removed.
If nil prefix OPT is always removed"
:group 'bibtex
+ :version "24.1"
:type '(choice (regexp) (const nil)))
(defcustom bibtex-comment-start "@Comment"
:group 'bibtex
:type '(repeat file))
-(defvar bibtex-string-file-path (getenv "BIBINPUTS")
- "*Colon separated list of paths to search for `bibtex-string-files'.")
+(defcustom bibtex-string-file-path (getenv "BIBINPUTS")
+ "Colon-separated list of paths to search for `bibtex-string-files'."
+ :group 'bibtex
+ :type 'string)
(defcustom bibtex-files nil
"List of BibTeX files that are searched for entry keys.
:type '(repeat (choice (const :tag "bibtex-file-path" bibtex-file-path)
directory file)))
-(defvar bibtex-file-path (getenv "BIBINPUTS")
- "*Colon separated list of paths to search for `bibtex-files'.")
+(defcustom bibtex-file-path (getenv "BIBINPUTS")
+ "Colon separated list of paths to search for `bibtex-files'."
+ :group 'bibtex
+ :type 'string)
(defcustom bibtex-search-entry-globally nil
"If non-nil, interactive calls of `bibtex-search-entry' search globally.
A global search includes all files in `bibtex-files'."
:group 'bibtex
+ :version "24.1"
:type 'boolean)
(defcustom bibtex-help-message t
("\\\\`\\|\\\\'\\|\\\\\\^\\|\\\\~\\|\\\\=\\|\\\\\\.\\|\\\\u\\|\\\\v\\|\\\\H\\|\\\\t\\|\\\\c\\|\\\\d\\|\\\\b" . "")
;; braces, quotes, concatenation.
("[`'\"{}#]" . "")
+ ("\\\\-" . "") ; \- ->
;; spaces
("\\\\?[ \t\n]+\\|~" . " "))
"Alist of (OLD-REGEXP . NEW-STRING) pairs.
(function :tag "Personalized function")))
(defcustom bibtex-generate-url-list
- '((("url" . ".*:.*")))
+ '((("url" . ".*:.*"))
+ (("doi" . "10\\.[0-9]+/.+")
+ "http://dx.doi.org/%s"
+ ("doi" ".*" 0)))
"List of schemes for generating the URL of a BibTeX entry.
These schemes are used by `bibtex-url'.
(\"volume\" \".*\" 0)
(\"pages\" \"\\`[A-Z]?[0-9]+\" 0)))"
:group 'bibtex
+ :version "24.4"
:type '(repeat
(cons :tag "Scheme"
(cons :tag "Matcher" :extra-offset 4
(defcustom bibtex-search-buffer "*BibTeX Search*"
"Buffer for BibTeX search results."
:group 'bibtex
+ :version "24.1"
:type 'string)
;; `bibtex-font-lock-keywords' is a user option, too. But since the
\f
;; Internal Variables
-(defvar bibtex-entry-alist bibtex-BibTeX-entry-alist
- "Alist of currently active entry types.")
+(defvar bibtex-entry-alist nil
+ "Alist of currently active entry types.
+Initialized by `bibtex-set-dialect'.")
-(defvar bibtex-field-alist bibtex-BibTeX-field-alist
- "Alist of currently active field types.")
+(defvar bibtex-field-alist nil
+ "Alist of currently active field types.
+Initialized by `bibtex-set-dialect'.")
(defvar bibtex-field-braces-opt nil
"Optimized value of `bibtex-field-braces-alist'.
Created by `bibtex-field-re-init'.
-It is a an alist with elements (FIELD . REGEXP).")
+It is an alist with elements (FIELD . REGEXP).")
(defvar bibtex-field-strings-opt nil
"Optimized value of `bibtex-field-strings-alist'.
Created by `bibtex-field-re-init'.
-It is a an alist with elements (FIELD RULE1 RULE2 ...),
+It is an alist with elements (FIELD RULE1 RULE2 ...),
where each RULE is (REGEXP . TO-STR).")
(defvar bibtex-pop-previous-search-point nil
,@(mapcar (lambda (matcher)
`((lambda (bound) (bibtex-font-lock-cite ',matcher bound))))
bibtex-cite-matcher-alist))
- "*Default expressions to highlight in BibTeX mode.")
+ "Default expressions to highlight in BibTeX mode.")
(defvar bibtex-font-lock-url-regexp
;; Assume that field names begin at the beginning of a line.
(let ((fun (lambda (kryp kr) ; adapted from `current-kill'
(car (set kryp (nthcdr (mod (- n (length (eval kryp)))
(length kr)) kr))))))
+ ;; We put the mark at the beginning of the inserted field or entry
+ ;; and point at its end - a behavior similar to what `yank' does.
+ ;; The mark is then used by `bibtex-yank-pop', which needs to know
+ ;; what we have inserted.
(if (eq bibtex-last-kill-command 'field)
(progn
;; insert past the current field
(aset vec idx (cons newelt (aref vec idx))))
(defsubst bibtex-vec-incr (vec idx)
- "Add NEWELT to the list stored in VEC at index IDX."
+ "Increment by 1 the counter which is stored in VEC at index IDX."
(aset vec idx (1+ (aref vec idx))))
(defun bibtex-format-entry ()
Visit the BibTeX files defined by `bibtex-files' and return a list
of corresponding buffers.
Initialize in these buffers `bibtex-reference-keys' if not yet set.
-List of BibTeX buffers includes current buffer if CURRENT is non-nil.
+List of BibTeX buffers includes current buffer if CURRENT is non-nil
+and the current buffer visits a file using `bibtex-mode'.
If FORCE is non-nil, (re)initialize `bibtex-reference-keys' even if
already set. If SELECT is non-nil interactively select a BibTeX buffer.
-When called interactively, FORCE is t, CURRENT is t if current buffer uses
-`bibtex-mode', and SELECT is t if current buffer does not use `bibtex-mode',"
+
+When called interactively, FORCE is t, CURRENT is t if current buffer
+visits a file using `bibtex-mode', and SELECT is t if current buffer
+does not use `bibtex-mode',"
(interactive (list (eq major-mode 'bibtex-mode) t
(not (eq major-mode 'bibtex-mode))))
(let ((file-path (split-string (or bibtex-file-path default-directory) ":+"))
(if (file-readable-p file)
(push (find-file-noselect file) buffer-list)))
;; Include current buffer iff we want it.
- ;; Exclude current buffer if it doesn't use `bibtex-mode'.
- ;; Thus calling `bibtex-initialize' gives meaningful results for
- ;; any current buffer.
- (unless (and current (eq major-mode 'bibtex-mode)) (setq current nil))
+ ;; Exclude current buffer if it does not visit a file using `bibtex-mode'.
+ ;; This way we exclude BibTeX buffers such as `bibtex-search-buffer'
+ ;; that are not visiting a BibTeX file. Also, calling `bibtex-initialize'
+ ;; gives meaningful results for any current buffer.
+ (unless (and current (eq major-mode 'bibtex-mode) buffer-file-name)
+ (setq current nil))
(cond ((and current (not (memq (current-buffer) buffer-list)))
(push (current-buffer) buffer-list))
((and (not current) (memq (current-buffer) buffer-list))
(set (make-local-variable 'syntax-propertize-function)
(syntax-propertize-via-font-lock
bibtex-font-lock-syntactic-keywords))
- (setq imenu-generic-expression
- (list (list nil bibtex-entry-head bibtex-key-in-head))
- imenu-case-fold-search t)
- (bibtex-set-dialect bibtex-dialect))
-
-(defun bibtex-set-dialect (dialect)
- "Select BibTeX mode DIALECT.
-This sets the variable `bibtex-dialect' which holds the currently active
-dialect. Dialects are listed in `bibtex-dialect-list'."
+ ;; Allow `bibtex-dialect' as a file-local variable.
+ (add-hook 'hack-local-variables-hook 'bibtex-set-dialect nil t))
+
+(defun bibtex-entry-alist (dialect)
+ "Return entry-alist for DIALECT."
+ (let ((var (intern (format "bibtex-%s-entry-alist" dialect)))
+ entry-alist)
+ (if (boundp var)
+ (setq entry-alist (symbol-value var))
+ (error "BibTeX dialect `%s' undefined" dialect))
+ (if (not (consp (nth 1 (car entry-alist))))
+ ;; new format
+ entry-alist
+ ;; Convert old format of `bibtex-entry-field-alist'
+ (unless (get var 'entry-list-format)
+ (put var 'entry-list-format "pre-24")
+ (message "Old format of `%s' (pre GNU Emacs 24).
+Please convert to the new format."
+ (if (eq (indirect-variable 'bibtex-entry-field-alist) var)
+ 'bibtex-entry-field-alist var))
+ (sit-for 3))
+ (let (lst)
+ (dolist (entry entry-alist)
+ (let ((fl (nth 1 entry)) req xref opt)
+ (dolist (field (copy-tree (car fl)))
+ (if (nth 3 field) (setcar (nthcdr 3 field) 0))
+ (if (or (not (nth 2 entry))
+ (assoc-string (car field) (car (nth 2 entry)) t))
+ (push field req)
+ (push field xref)))
+ (dolist (field (nth 1 fl))
+ (push field opt))
+ (push (list (car entry) nil (nreverse req)
+ (nreverse xref) (nreverse opt))
+ lst)))
+ (nreverse lst)))))
+
+(defun bibtex-set-dialect (&optional dialect local)
+ "Select BibTeX DIALECT for editing BibTeX files.
+This sets the user variable `bibtex-dialect' as well as the dialect-dependent
+internal variables. Allowed dialects are listed in `bibtex-dialect-list'.
+If DIALECT is nil use current value of `bibtex-dialect'.
+If LOCAL is non-nil make buffer-local bindings for these variables rather than
+setting the global values. The dialect-dependent internal variables
+are also bound buffer-locally if `bibtex-dialect' is already buffer-local
+in the current buffer (for example, as a file-local variable).
+LOCAL is t for interactive calls."
(interactive (list (intern (completing-read "Dialect: "
(mapcar 'list bibtex-dialect-list)
- nil t))))
- (unless (eq dialect (get 'bibtex-dialect 'dialect))
- (put 'bibtex-dialect 'dialect dialect)
- (setq bibtex-dialect dialect)
-
- ;; Bind variables
- (setq bibtex-entry-alist
- (let ((var (intern (format "bibtex-%s-entry-alist" dialect)))
- entry-alist)
- (if (boundp var)
- (setq entry-alist (symbol-value var))
- (error "BibTeX dialect `%s' undefined" dialect))
- (if (not (consp (nth 1 (car entry-alist))))
- ;; new format
- entry-alist
- ;; Convert old format
- (unless (get var 'entry-list-format)
- (put var 'entry-list-format "pre-24")
- (message "Old format of `%s' (pre GNU Emacs 24).
-Please convert to the new format."
- (if (eq (indirect-variable 'bibtex-entry-field-alist) var)
- 'bibtex-entry-field-alist var))
- (sit-for 3))
- (let (lst)
- (dolist (entry entry-alist)
- (let ((fl (nth 1 entry)) req xref opt)
- (dolist (field (copy-tree (car fl)))
- (if (nth 3 field) (setcar (nthcdr 3 field) 0))
- (if (or (not (nth 2 entry))
- (assoc-string (car field) (car (nth 2 entry)) t))
- (push field req)
- (push field xref)))
- (dolist (field (nth 1 fl))
- (push field opt))
- (push (list (car entry) nil (nreverse req)
- (nreverse xref) (nreverse opt))
- lst)))
- (nreverse lst))))
- bibtex-field-alist
- (let ((var (intern (format "bibtex-%s-field-alist" dialect))))
- (if (boundp var)
- (symbol-value var)
- (error "Field types for BibTeX dialect `%s' undefined" dialect)))
- bibtex-entry-type
- (concat "@[ \t]*\\(?:"
- (regexp-opt (mapcar 'car bibtex-entry-alist)) "\\)")
- bibtex-entry-head (concat "^[ \t]*\\("
- bibtex-entry-type
- "\\)[ \t]*[({][ \t\n]*\\("
- bibtex-reference-key
- "\\)")
- bibtex-entry-maybe-empty-head (concat bibtex-entry-head "?")
- bibtex-any-valid-entry-type
- (concat "^[ \t]*@[ \t]*\\(?:"
- (regexp-opt (append '("String" "Preamble")
- (mapcar 'car bibtex-entry-alist))) "\\)"))
- ;; Define entry commands
- (dolist (elt bibtex-entry-alist)
- (let* ((entry (car elt))
- (fname (intern (concat "bibtex-" entry))))
- (unless (fboundp fname)
- (eval (list 'defun fname nil
- (format "Insert a new BibTeX @%s entry; see also `bibtex-entry'."
- entry)
- '(interactive "*")
- `(bibtex-entry ,entry))))))
- ;; Define menu
- ;; We use the same keymap for all BibTeX buffers. So all these buffers
- ;; have the same BibTeX dialect. To define entry types buffer-locally,
- ;; it would be necessary to give each BibTeX buffer a new keymap that
- ;; becomes a child of `bibtex-mode-map'. Useful??
- (easy-menu-define
- nil bibtex-mode-map "Entry-Types Menu in BibTeX mode"
- (apply 'list "Entry-Types"
- (append
- (mapcar (lambda (entry)
- (vector (or (nth 1 entry) (car entry))
- (intern (format "bibtex-%s" (car entry))) t))
- bibtex-entry-alist)
- `("---"
- ["String" bibtex-String t]
- ["Preamble" bibtex-Preamble t]
- "---"
- ,(append '("BibTeX dialect")
- (mapcar (lambda (dialect)
- (vector (symbol-name dialect)
- `(lambda () (interactive)
- (bibtex-set-dialect ',dialect))
- t))
- bibtex-dialect-list))))))))
+ nil t)) t))
+ (let ((setfun (if (or local (local-variable-p 'bibtex-dialect))
+ (lambda (var val) (set (make-local-variable var) val))
+ 'set)))
+ (if dialect (funcall setfun 'bibtex-dialect dialect))
+
+ ;; Set internal variables
+ (funcall setfun 'bibtex-entry-alist (bibtex-entry-alist bibtex-dialect))
+ (funcall setfun 'bibtex-field-alist
+ (let ((var (intern (format "bibtex-%s-field-alist"
+ bibtex-dialect))))
+ (if (boundp var)
+ (symbol-value var)
+ (error "Field types for BibTeX dialect `%s' undefined"
+ bibtex-dialect))))
+ (funcall setfun 'bibtex-entry-type
+ (concat "@[ \t]*\\(?:"
+ (regexp-opt (mapcar 'car bibtex-entry-alist)) "\\)"))
+ (funcall setfun 'bibtex-entry-head
+ (concat "^[ \t]*\\(" bibtex-entry-type "\\)[ \t]*[({][ \t\n]*\\("
+ bibtex-reference-key "\\)"))
+ (funcall setfun 'bibtex-entry-maybe-empty-head
+ (concat bibtex-entry-head "?"))
+ (funcall setfun 'bibtex-any-valid-entry-type
+ (concat "^[ \t]*@[ \t]*\\(?:"
+ (regexp-opt
+ (append '("String" "Preamble")
+ (mapcar 'car bibtex-entry-alist))) "\\)"))
+ (setq imenu-generic-expression
+ (list (list nil bibtex-entry-head bibtex-key-in-head))
+ imenu-case-fold-search t)))
+
+;; Entry commands and menus for BibTeX dialects
+;; We do not use `easy-menu-define' here because this gets confused
+;; if we want to have multiple versions of the "same" menu.
+(let ((select-map (make-sparse-keymap)))
+ ;; Submenu for selecting the dialect
+ (dolist (dialect (reverse bibtex-dialect-list))
+ (define-key select-map (vector dialect)
+ `(menu-item ,(symbol-name dialect)
+ (lambda () (interactive) (bibtex-set-dialect ',dialect t))
+ :button (:radio . (eq bibtex-dialect ',dialect)))))
+ ;; We define a menu for each dialect.
+ ;; Then we select the menu we want via the :visible keyword
+ (dolist (dialect bibtex-dialect-list)
+ (let ((entry-alist (bibtex-entry-alist dialect))
+ (menu-map (make-sparse-keymap)))
+ (define-key menu-map [select]
+ `(menu-item "BibTeX dialect" ,select-map))
+ (define-key menu-map [nil-2] '(menu-item "--"))
+ (define-key menu-map [bibtex-preamble]
+ '(menu-item "Preamble" bibtex-Preamble))
+ (define-key menu-map [bibtex-String]
+ '(menu-item "String" bibtex-String))
+ (define-key menu-map [nil-1] '(menu-item "--"))
+ (dolist (elt (reverse entry-alist))
+ ;; Entry commands
+ (let* ((entry (car elt))
+ (fname (intern (format "bibtex-%s" entry))))
+ (unless (fboundp fname)
+ (eval (list 'defun fname nil
+ (format "Insert a template for a @%s entry; see also `bibtex-entry'."
+ entry)
+ '(interactive "*")
+ `(bibtex-entry ,entry))))
+ ;; Menu entries
+ (define-key menu-map (vector fname)
+ `(menu-item ,(or (nth 1 elt) (car elt)) ,fname))))
+ (define-key bibtex-mode-map
+ (vector 'menu-bar dialect)
+ `(menu-item "Entry-Types" ,menu-map
+ :visible (eq bibtex-dialect ',dialect))))))
(defun bibtex-field-list (entry-type)
"Return list of allowed fields for entry ENTRY-TYPE.
(cons required optional)))
(defun bibtex-entry (entry-type)
- "Insert a new BibTeX entry of type ENTRY-TYPE.
+ "Insert a template for a BibTeX entry of type ENTRY-TYPE.
After insertion call the value of `bibtex-add-entry-hook' if that value
is non-nil."
(interactive
(defun bibtex-autofill-entry ()
"Try to fill fields of current BibTeX entry based on neighboring entries.
The current entry must have a key. Determine the neighboring entry
-\(previouse or next\) whose key is more similar to the key of the current
+\(previous or next\) whose key is more similar to the key of the current
entry. For all empty fields of the current entry insert the corresponding
field contents of the neighboring entry. Finally try to update the text
based on the difference between the keys of the neighboring and the current
Otherwise the search is limited to the current buffer.
Return position of entry if CROSSREF-KEY is found or nil otherwise.
If CROSSREF-KEY is in the same buffer like current entry but before it
-an error is signaled. If NOERRER is non-nil this error is suppressed.
+an error is signaled. If NOERROR is non-nil this error is suppressed.
Optional arg PNT is the position of the referencing entry. It defaults
to position of point. If optional arg SPLIT is non-nil, split window
so that both the referencing and the crossrefed entry are displayed.
(if use-previous-options
bibtex-reformat-previous-options
(setq bibtex-reformat-previous-options
- (mapcar (lambda (option)
- (if (y-or-n-p (car option)) (cdr option)))
- `(("Realign entries (recommended)? " . 'realign)
- ("Remove empty optional and alternative fields? " . 'opts-or-alts)
- ("Remove delimiters around pure numerical fields? " . 'numerical-fields)
- (,(concat (if bibtex-comma-after-last-field "Insert" "Remove")
- " comma at end of entry? ") . 'last-comma)
- ("Replace double page dashes by single ones? " . 'page-dashes)
- ("Delete whitespace at the beginning and end of fields? " . 'whitespace)
- ("Inherit booktitle? " . 'inherit-booktitle)
- ("Force delimiters? " . 'delimiters)
- ("Unify case of entry types and field names? " . 'unify-case)
- ("Enclose parts of field entries by braces? " . 'braces)
- ("Replace parts of field entries by string constants? " . 'strings)
- ("Sort fields? " . 'sort-fields))))))
+ (delq nil
+ (mapcar (lambda (option)
+ (if (y-or-n-p (car option)) (cdr option)))
+ `(("Realign entries (recommended)? " . realign)
+ ("Remove empty optional and alternative fields? " . opts-or-alts)
+ ("Remove delimiters around pure numerical fields? " . numerical-fields)
+ (,(concat (if bibtex-comma-after-last-field "Insert" "Remove")
+ " comma at end of entry? ") . last-comma)
+ ("Replace double page dashes by single ones? " . page-dashes)
+ ("Delete whitespace at the beginning and end of fields? " . whitespace)
+ ("Inherit booktitle? " . inherit-booktitle)
+ ("Force delimiters? " . delimiters)
+ ("Unify case of entry types and field names? " . unify-case)
+ ("Enclose parts of field entries by braces? " . braces)
+ ("Replace parts of field entries by string constants? " . strings)
+ ("Sort fields? " . sort-fields)))))))
;; Do not include required-fields because `bibtex-reformat'
;; cannot handle the error messages of `bibtex-format-entry'.
;; Use `bibtex-validate' to check for required fields.
(if (stringp (car scheme))
(setq fmt (pop scheme)))
(dolist (step scheme)
+ ;; In the first STEP, if the field contains multiple
+ ;; matches, we want the match the closest to point.
+ ;; (if (eq step (car scheme))
(setq text (cdr (assoc-string (car step) fields-alist t)))
(if (string-match (nth 1 step) text)
(push (cond ((functionp (nth 2 step))
(message "No URL known."))
url)))
-;; We could combine multiple seach results with set operations
+;; We could combine multiple search results with set operations
;; AND, OR, MINUS, and NOT. Would this be useful?
;; How complicated are searches in real life?
;; We could also have other searches such as "publication year newer than...".
(if (string= "" field)
;; Unrestricted search.
(while (re-search-forward regexp nil t)
- (let ((beg (bibtex-beginning-of-entry))
- (end (bibtex-end-of-entry))
- key)
- (if (and (<= beg (match-beginning 0))
- (<= (match-end 0) end)
- (save-excursion
- (goto-char beg)
- (and (looking-at bibtex-entry-head)
- (setq key (bibtex-key-in-head))))
- (not (assoc key entries)))
- (push (list key file
- (buffer-substring-no-properties beg end))
- entries))))
+ (save-excursion
+ (let ((mbeg (match-beginning 0))
+ (mend (match-end 0))
+ (beg (bibtex-beginning-of-entry))
+ (end (bibtex-end-of-entry))
+ key)
+ (if (and (<= beg mbeg)
+ (<= mend end)
+ (progn
+ (goto-char beg)
+ (looking-at bibtex-entry-head))
+ (setq key (bibtex-key-in-head))
+ (not (assoc key entries)))
+ (push (list key file
+ (buffer-substring-no-properties beg end))
+ entries)))))
;; The following is slow. But it works reliably even in more
;; complicated cases with BibTeX string constants and crossrefed
;; entries. If you prefer speed over reliability, perform an