Replace Lisp calls to delete-backward-char by delete-char.
[bpt/emacs.git] / lisp / textmodes / bibtex.el
index e5e3f4d..e17cd9e 100644 (file)
@@ -1,7 +1,7 @@
 ;;; bibtex.el --- BibTeX mode for GNU Emacs
 
 ;; Copyright (C) 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2002,
-;;   2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;;   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
 ;; Author: Stefan Schoef <schoef@offis.uni-oldenburg.de>
 ;;      Bengt Martensson <bengt@mathematik.uni-Bremen.de>
@@ -163,7 +163,7 @@ The value nil means do no formatting at all."
  "Alist of field regexps that \\[bibtex-clean-entry] encloses by braces.
 Each element has the form (FIELDS REGEXP), where FIELDS is a list
 of BibTeX field names and REGEXP is a regexp.
-Whitespace in REGEXP will be replaced by \"[ \\t\\n]+\"."
+Space characters in REGEXP will be replaced by \"[ \\t\\n]+\"."
   :group 'bibtex
   :type '(repeat (list (repeat (string :tag "field name"))
                        (choice (regexp :tag "regexp")
@@ -174,7 +174,7 @@ Whitespace in REGEXP will be replaced by \"[ \\t\\n]+\"."
 Each element has the form (FIELDS REGEXP TO-STR), where FIELDS is a list
 of BibTeX field names.  In FIELDS search for REGEXP, which are replaced
 by the BibTeX string constant TO-STR.
-Whitespace in REGEXP will be replaced by \"[ \\t\\n]+\"."
+Space characters in REGEXP will be replaced by \"[ \\t\\n]+\"."
   :group 'bibtex
   :type '(repeat (list (repeat (string :tag "field name"))
                        (regexp :tag "From regexp")
@@ -216,7 +216,7 @@ If value of `bibtex-maintain-sorted-entries' is `entry-class'
 entries are ordered according to the classes they belong to.  Each
 class contains a list of entry types.  An entry `catch-all' applies
 to all entries not explicitly mentioned."
-  :group 'BibTeX
+  :group 'bibtex
   :type '(repeat (choice :tag "Class"
                          (const :tag "catch-all" (catch-all))
                          (repeat :tag "Entry type" string))))
@@ -746,11 +746,11 @@ See `bibtex-generate-autokey' for details."
 
 (defcustom bibtex-autokey-titleword-ignore
   '("A" "An" "On" "The" "Eine?" "Der" "Die" "Das"
-    "[^[:upper:]].*" ".*[^[:upper:]0-9].*")
+    "[^[:upper:]].*" ".*[^[:upper:][:lower:]0-9].*")
   "Determines words from the title that are not to be used in the key.
 Each item of the list is a regexp.  If a word of the title matches a
 regexp from that list, it is not included in the title part of the key.
-See `bibtex-generate-autokey' for details."
+Case is significant.  See `bibtex-generate-autokey' for details."
   :group 'bibtex-autokey
   :type '(repeat regexp))
 
@@ -907,8 +907,9 @@ and with the `match-data' properly set.
 Case is always ignored.  Always remove the field delimiters.
 If `bibtex-expand-strings' is non-nil, BibTeX strings are expanded
 for generating the URL.
+Set this variable before loading BibTeX mode.
 
-The following is a complex example, see http://link.aps.org/linkfaq.html.
+The following is a complex example, see URL `http://link.aps.org/'.
 
    (((\"journal\" . \"\\\\=<\\(PR[ABCDEL]?\\|RMP\\)\\\\=>\")
      \"http://link.aps.org/abstract/%s/v%s/p%s\"
@@ -945,10 +946,12 @@ The following is a complex example, see http://link.aps.org/linkfaq.html.
 Each rule should be of the form (REGEXP . SUBEXP), where SUBEXP
 specifies which parenthesized expression in REGEXP is a cited key.
 Case is significant.
-Used by `bibtex-search-crossref' and for font-locking."
+Used by `bibtex-search-crossref' and for font-locking.
+Set this variable before loading BibTeX mode."
   :group 'bibtex
   :type '(repeat (cons (regexp :tag "Regexp")
-                       (integer :tag "Number"))))
+                       (integer :tag "Number")))
+  :version "23.1")
 
 (defcustom bibtex-expand-strings nil
   "If non-nil, expand strings when extracting the content of a BibTeX field."
@@ -1512,8 +1515,8 @@ If `bibtex-expand-strings' is non-nil, also expand BibTeX strings."
       (save-excursion
         (goto-char (bibtex-start-of-text-in-field bounds))
         (let ((epoint (bibtex-end-of-text-in-field bounds))
-              content opoint)
-          (while (< (setq opoint (point)) epoint)
+              content)
+          (while (< (point) epoint)
             (if (looking-at bibtex-field-const)
                 (let ((mtch (match-string-no-properties 0)))
                   (push (or (if bibtex-expand-strings
@@ -1724,13 +1727,18 @@ entry and `match-data' corresponds to the header of the entry,
 see regexp `bibtex-entry-head'.  If `bibtex-sort-ignore-string-entries'
 is non-nil, FUN is not called for @String entries."
   (let ((case-fold-search t)
+        (end-marker (make-marker))
         found)
+    ;; Use marker to keep track of the buffer position of the end of
+    ;; a BibTeX entry as this position may change during reformatting.
+    (set-marker-insertion-type end-marker t)
     (save-excursion
       (goto-char (point-min))
       (while (setq found (bibtex-skip-to-valid-entry))
+        (set-marker end-marker (cdr found))
         (looking-at bibtex-any-entry-maybe-empty-head)
-        (funcall fun (bibtex-key-in-head "") (car found) (cdr found))
-        (goto-char (cdr found))))))
+        (funcall fun (bibtex-key-in-head "") (car found) end-marker)
+        (goto-char end-marker)))))
 
 (defun bibtex-progress-message (&optional flag interval)
   "Echo a message about progress of current buffer.
@@ -1828,13 +1836,16 @@ are ignored.  Return point"
   "Search for BibTeX field enclosing point.
 For `bibtex-mode''s internal algorithms, a field begins at the comma
 following the preceding field.  Usually, this is not what the user expects.
-Thus if COMMA is non-nil, the \"current field\" includes the terminating comma.
+Thus if COMMA is non-nil, the \"current field\" includes the terminating comma
+as well as the entry delimiter if it appears on the same line.
 Unless NOERR is non-nil, signal an error if no enclosing field is found.
 On success return bounds, nil otherwise.  Do not move point."
   (save-excursion
     (when comma
       (end-of-line)
       (skip-chars-backward " \t")
+      ;; Ignore entry delimiter and comma at end of line.
+      (if (memq (preceding-char) '(?} ?\))) (forward-char -1))
       (if (= (preceding-char) ?,) (forward-char -1)))
 
     (let ((bounds (bibtex-search-backward-field bibtex-field-name t)))
@@ -1870,7 +1881,14 @@ Optional arg COMMA is as in `bibtex-enclosing-field'."
       (bibtex-skip-to-valid-entry)
       (push-mark)
       (insert (funcall fun 'bibtex-entry-kill-ring-yank-pointer
-                       bibtex-entry-kill-ring)))))
+                       bibtex-entry-kill-ring))
+      (unless (functionp bibtex-reference-keys)
+        ;; update `bibtex-reference-keys'
+        (save-excursion
+          (goto-char (mark t))
+          (looking-at bibtex-any-entry-maybe-empty-head)
+          (let ((key (bibtex-key-in-head)))
+            (if key (push (cons key t) bibtex-reference-keys))))))))
 
 (defun bibtex-format-entry ()
   "Helper function for `bibtex-clean-entry'.
@@ -1891,6 +1909,7 @@ Formats current entry according to variable `bibtex-entry-format'."
                               last-comma delimiters unify-case braces
                               strings)
                   bibtex-entry-format))
+        (left-delim-re (regexp-quote (bibtex-field-left-delimiter)))
         bounds crossref-key req-field-list default-field-list field-list
         alt-fields error-field-name)
     (unwind-protect
@@ -1930,7 +1949,8 @@ Formats current entry according to variable `bibtex-entry-format'."
 
                 ;; Do we have a crossref key?
                 (goto-char (point-min))
-                (if (setq bounds (bibtex-search-forward-field "crossref"))
+                (if (setq bounds (bibtex-search-forward-field
+                                  "\\(OPT\\)?crossref"))
                     (let ((text (bibtex-text-in-field-bounds bounds t)))
                       (unless (equal "" text)
                         (setq crossref-key text))))
@@ -1985,6 +2005,17 @@ Formats current entry according to variable `bibtex-entry-format'."
                   (unless deleted
                     (push field-name field-list)
 
+                    ;; Remove whitespace at beginning and end of field.
+                    ;; We do not look at individual parts of the field
+                    ;; as {foo } # bar # { baz} is a fine field.
+                    (when (memq 'whitespace format)
+                      (goto-char beg-text)
+                      (if (looking-at "\\([{\"]\\)[ \t\n]+")
+                          (replace-match "\\1"))
+                      (goto-char end-text)
+                      (if (looking-back "[ \t\n]+\\([}\"]\\)" beg-text t)
+                          (replace-match "\\1")))
+
                     ;; remove delimiters from purely numerical fields
                     (when (and (memq 'numerical-fields format)
                                (progn (goto-char beg-text)
@@ -1997,13 +2028,21 @@ Formats current entry according to variable `bibtex-entry-format'."
                     ;; update delimiters
                     (when (memq 'delimiters format)
                       (goto-char beg-text)
-                      (when (looking-at "[{\"]")
-                        (delete-char 1)
-                        (insert (bibtex-field-left-delimiter)))
-                      (goto-char (1- (marker-position end-text)))
-                      (when (looking-at "[}\"]")
-                        (delete-char 1)
-                        (insert (bibtex-field-right-delimiter))))
+                      ;; simplified from `bibtex-parse-field-text', as we
+                      ;; already checked that the field format is correct
+                      (while (< (point) end-text)
+                        (if (looking-at bibtex-field-const)
+                            (goto-char (match-end 0))
+                          (let ((boundaries (bibtex-parse-field-string)))
+                            (if (looking-at left-delim-re)
+                                (goto-char (cdr boundaries))
+                              (delete-char 1)
+                              (insert (bibtex-field-left-delimiter))
+                              (goto-char (1- (cdr boundaries)))
+                              (delete-char 1)
+                              (insert (bibtex-field-right-delimiter)))))
+                        (if (looking-at "[ \t\n]*#[ \t\n]*")
+                            (goto-char (match-end 0)))))
 
                     ;; update page dashes
                     (if (and (memq 'page-dashes format)
@@ -2013,15 +2052,6 @@ Formats current entry according to variable `bibtex-entry-format'."
                                      "\\([\"{][0-9]+\\)[ \t\n]*--?[ \t\n]*\\([0-9]+[\"}]\\)")))
                         (replace-match "\\1-\\2"))
 
-                    ;; remove whitespace at beginning and end of field
-                    (when (memq 'whitespace format)
-                      (goto-char beg-text)
-                      (if (looking-at "\\([{\"]\\)[ \t\n]+")
-                          (replace-match "\\1"))
-                      (goto-char end-text)
-                      (if (looking-back "[ \t\n]+\\([}\"]\\)" beg-text t)
-                          (replace-match "\\1")))
-
                     ;; enclose field text by braces according to
                     ;; `bibtex-field-braces-alist'.
                     (let (case-fold-search temp) ; Case-sensitive search
@@ -2064,7 +2094,7 @@ Formats current entry according to variable `bibtex-entry-format'."
                                 ;; if match not at left subfield boundary...
                                 (if (< (1+ (nth 1 bounds)) (match-beginning 0))
                                     (insert (bibtex-field-right-delimiter) " # ")
-                                  (delete-backward-char 1))))))))
+                                  (delete-char -1))))))))
 
                     ;; use book title of crossref'd entry
                     (if (and (memq 'inherit-booktitle format)
@@ -2151,7 +2181,7 @@ Formats current entry according to variable `bibtex-entry-format'."
               (if (memq 'realign format)
                   (bibtex-fill-entry)))))
 
-      ;; Unwindform: move point to location where error occured if possible
+      ;; Unwindform: move point to location where error occurred if possible
       (if error-field-name
           (let (bounds)
             (when (save-excursion
@@ -2171,7 +2201,7 @@ Return optimized value to be used by `bibtex-format-entry'."
   (setq regexp-alist
         (mapcar (lambda (e)
                   (list (car e)
-                        (replace-regexp-in-string "[ \t\n]+" "[ \t\n]+" (nth 1 e))
+                        (replace-regexp-in-string " +" "[ \t\n]+" (nth 1 e))
                         (nth 2 e))) ; nil for 'braces'.
                 regexp-alist))
   (let (opt-list)
@@ -2295,6 +2325,10 @@ Return the result as a string"
     ;; gather words from titlestring into a list.  Ignore
     ;; specific words and use only a specific amount of words.
     (let ((counter 0)
+         (ignore-re (concat "\\`\\(?:"
+                             (mapconcat 'identity
+                                        bibtex-autokey-titleword-ignore "\\|")
+                             "\\)\\'"))
           titlewords titlewords-extra word)
       (while (and (or (not (numberp bibtex-autokey-titlewords))
                       (< counter (+ bibtex-autokey-titlewords
@@ -2303,13 +2337,9 @@ Return the result as a string"
         (setq word (match-string 0 titlestring)
               titlestring (substring titlestring (match-end 0)))
         ;; Ignore words matched by one of the elements of
-        ;; `bibtex-autokey-titleword-ignore'
-        (unless (let ((lst bibtex-autokey-titleword-ignore))
-                  (while (and lst
-                              (not (string-match (concat "\\`\\(?:" (car lst)
-                                                         "\\)\\'") word)))
-                    (setq lst (cdr lst)))
-                  lst)
+        ;; `bibtex-autokey-titleword-ignore'.  Case is significant.
+        (unless (let (case-fold-search)
+                 (string-match ignore-re word))
           (setq counter (1+ counter))
           (if (or (not (numberp bibtex-autokey-titlewords))
                   (<= counter bibtex-autokey-titlewords))
@@ -2428,8 +2458,10 @@ Concatenate the key:
       (apply 'append
              (mapcar (lambda (buf)
                        (with-current-buffer buf bibtex-reference-keys))
-                     (bibtex-initialize t)))
-    bibtex-reference-keys))
+                     ;; include current buffer only if it uses `bibtex-mode'
+                     (bibtex-initialize (eq major-mode 'bibtex-mode))))
+    (if (eq major-mode 'bibtex-mode)
+        bibtex-reference-keys)))
 
 (defun bibtex-read-key (prompt &optional key global)
   "Read BibTeX key from minibuffer using PROMPT and default KEY.
@@ -2519,8 +2551,7 @@ Return alist of strings if parsing was completed, `aborted' otherwise."
   (save-excursion
     (save-match-data
       (goto-char (point-min))
-      (let ((strings (if (and add
-                              (listp bibtex-strings))
+      (let ((strings (if (and add (not (functionp bibtex-strings)))
                          bibtex-strings))
             bounds key)
         (if (listp add)
@@ -2543,8 +2574,9 @@ Return alist of strings if parsing was completed, `aborted' otherwise."
 
 (defun bibtex-strings ()
   "Return `bibtex-strings'.  Initialize this variable if necessary."
-  (if (listp bibtex-strings) bibtex-strings
-    (bibtex-parse-strings (bibtex-string-files-init))))
+  (if (functionp bibtex-strings)
+      (bibtex-parse-strings (bibtex-string-files-init))
+    bibtex-strings))
 
 (defun bibtex-string-files-init ()
   "Return initialization for `bibtex-strings'.
@@ -2656,7 +2688,11 @@ When called interactively, FORCE is t, CURRENT is t if current buffer uses
     (dolist (file file-list)
       (if (file-readable-p file)
         (push (find-file-noselect file) buffer-list)))
-    ;; include current buffer iff we want it
+    ;; 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))
     (cond ((and current (not (memq (current-buffer) buffer-list)))
            (push (current-buffer) buffer-list))
           ((and (not current) (memq (current-buffer) buffer-list))
@@ -2664,8 +2700,10 @@ When called interactively, FORCE is t, CURRENT is t if current buffer uses
     ;; parse keys
     (dolist (buffer buffer-list)
       (with-current-buffer buffer
-        (if (or force (nlistp bibtex-reference-keys))
-            (bibtex-parse-keys))))
+        (if (or force (functionp bibtex-reference-keys))
+            (bibtex-parse-keys))
+        (unless (functionp bibtex-strings)
+          (bibtex-parse-strings (bibtex-string-files-init)))))
     ;; select BibTeX buffer
     (if select
         (if buffer-list
@@ -2683,35 +2721,13 @@ COMPLETIONS is an alist of strings.  If point is not after the part
 of a word, all strings are listed.  Return completion."
   ;; Return value is used by cleanup functions.
   ;; Code inspired by `lisp-complete-symbol'.
-  (let* ((case-fold-search t)
-         (beg (save-excursion
+  (let ((beg (save-excursion
                 (re-search-backward "[ \t{\"]")
                 (forward-char)
                 (point)))
-         (end (point))
-         (pattern (buffer-substring-no-properties beg end))
-         (completion (try-completion pattern completions)))
-    (cond ((not completion)
-           (error "Can't find completion for `%s'" pattern))
-          ((eq completion t)
-           pattern)
-          ((not (string= pattern completion))
-           (delete-region beg end)
-           (insert completion)
-           ;; Don't leave around a completions buffer that's out of date.
-           (let ((win (get-buffer-window "*Completions*" 0)))
-             (if win (with-selected-window win (bury-buffer))))
-           completion)
-          (t
-           (let ((minibuf-is-in-use
-                  (eq (minibuffer-window) (selected-window))))
-             (unless minibuf-is-in-use (message "Making completion list..."))
-             (with-output-to-temp-buffer "*Completions*"
-               (display-completion-list
-                (sort (all-completions pattern completions) 'string<) pattern))
-             (unless minibuf-is-in-use
-               (message "Making completion list...done")))
-           nil))))
+        (end (point)))
+    (when (completion-in-region beg end completions)
+      (buffer-substring beg (point)))))
 
 (defun bibtex-complete-string-cleanup (str compl)
   "Cleanup after inserting string STR.
@@ -2931,7 +2947,7 @@ BOUND limits the search."
 
 General information on working with BibTeX mode:
 
-Use commands such as \\[bibtex-Book] to get a template for a specific entry.
+Use commands such as \\<bibtex-mode-map>\\[bibtex-Book] to get a template for a specific entry.
 Then fill in all desired fields using \\[bibtex-next-field] to jump from field
 to field.  After having filled in all desired fields in the entry, clean the
 new entry with the command \\[bibtex-clean-entry].
@@ -3315,7 +3331,8 @@ Return the new location of point."
           ((looking-at bibtex-any-valid-entry-type)
            ;; Parsing of entry failed
            (error "Syntactically incorrect BibTeX entry starts here"))
-          (t (if (interactive-p) (message "Not on a known BibTeX entry."))
+          (t (if (called-interactively-p 'interactive)
+                (message "Not on a known BibTeX entry."))
              (goto-char pnt)))
     (point)))
 
@@ -3472,7 +3489,7 @@ are ignored."
   (bibtex-beginning-of-first-entry)     ; Needed by `sort-subr'
   (bibtex-init-sort-entry-class-alist)  ; Needed by `bibtex-lessp'.
   (if (and (eq bibtex-maintain-sorted-entries 'crossref)
-           (nlistp bibtex-reference-keys))
+           (functionp bibtex-reference-keys))
       (bibtex-parse-keys))              ; Needed by `bibtex-lessp'.
   (sort-subr nil
              'bibtex-skip-to-valid-entry   ; NEXTREC function
@@ -3503,7 +3520,7 @@ for a crossref key, t otherwise."
             (end (cdr (bibtex-valid-entry t)))
             (_ (unless end (error "Not inside valid entry")))
             (beg (match-end 0)) ; set by `bibtex-valid-entry'
-            (bounds (bibtex-search-forward-field "crossref" end))
+            (bounds (bibtex-search-forward-field "\\(OPT\\)?crossref" end))
             case-fold-search best temp crossref-key)
        (if bounds
            (setq crossref-key (bibtex-text-in-field-bounds bounds t)
@@ -3579,8 +3596,7 @@ mode is not `bibtex-mode', START is nil, and DISPLAY is t."
         (while (and (not found)
                     (setq buffer (pop buffer-list)))
           (with-current-buffer buffer
-            (if (and (listp bibtex-reference-keys)
-                     (cdr (assoc-string key bibtex-reference-keys)))
+            (if (cdr (assoc-string key bibtex-reference-keys))
                 ;; `bibtex-search-entry' moves point if key found
                 (setq found (bibtex-search-entry key)))))
         (cond ((and found display)
@@ -3620,7 +3636,7 @@ see `bibtex-validate'.
 Return t if preparation was successful or nil if entry KEY already exists."
   (bibtex-init-sort-entry-class-alist)  ; Needed by `bibtex-lessp'.
   (if (and (eq bibtex-maintain-sorted-entries 'crossref)
-           (nlistp bibtex-reference-keys))
+           (functionp bibtex-reference-keys))
       (bibtex-parse-keys))              ; Needed by `bibtex-lessp'.
   (let ((key (nth 0 index))
         key-exist)
@@ -3827,7 +3843,8 @@ Return t if test was successful, nil otherwise."
               (insert (format "%s:%d: %s\n" file (car err) (cdr err))))
             (set-buffer-modified-p nil)
             (toggle-read-only 1)
-            (goto-line 3)) ; first error message
+            (goto-char (point-min))
+            (forward-line 2)) ; first error message
           (display-buffer err-buf)
           nil) ; return `nil' (i.e., buffer is invalid)
       (message "%s is syntactically correct"
@@ -3843,8 +3860,7 @@ Return t if test was successful, nil otherwise."
         buffer-key-list current-buf current-keys error-list)
     ;; Check for duplicate keys within BibTeX buffer
     (dolist (buffer buffer-list)
-      (save-excursion
-        (set-buffer buffer)
+      (with-current-buffer buffer
         (let (entry-type key key-list)
           (goto-char (point-min))
           (while (re-search-forward bibtex-entry-head nil t)
@@ -3884,7 +3900,8 @@ Return t if test was successful, nil otherwise."
             (dolist (err (sort error-list 'string-lessp)) (insert err))
             (set-buffer-modified-p nil)
             (toggle-read-only 1)
-            (goto-line 3)) ; first error message
+            (goto-char (point-min))
+            (forward-line 2)) ; first error message
           (display-buffer err-buf)
           nil) ; return `nil' (i.e., buffer is invalid)
       (message "No duplicate keys.")
@@ -4055,7 +4072,11 @@ but do not actually kill it.  Optional arg COMMA is as in
            (end (bibtex-end-of-field bounds))
            (beg (bibtex-start-of-field bounds)))
       (goto-char end)
-      (skip-chars-forward ",")
+      ;; Preserve white space at end of BibTeX entry
+      (if (looking-at "[ \t\n]*[)}]")
+          (progn (skip-chars-backward " \t\n")
+                 (setq end (point)))
+        (skip-chars-forward ","))
       (push (list (bibtex-name-in-field bounds) nil
                   (bibtex-text-in-field-bounds bounds))
             bibtex-field-kill-ring)
@@ -4069,7 +4090,7 @@ but do not actually kill it.  Optional arg COMMA is as in
   (setq bibtex-last-kill-command 'field))
 
 (defun bibtex-copy-field-as-kill (&optional comma)
-  "Copy the BibTeX field at point to the kill ring.
+  "Copy the BibTeX field at point to `bibtex-field-kill-ring'.
 Optional arg COMMA is as in `bibtex-enclosing-field'.  It is t for
 interactive calls."
   (interactive (list t))
@@ -4083,6 +4104,8 @@ but do not actually kill it."
   (save-excursion
     (let* ((case-fold-search t)
            (beg (bibtex-beginning-of-entry))
+           (key (progn (looking-at bibtex-any-entry-maybe-empty-head)
+                       (bibtex-key-in-head)))
            (end (progn (bibtex-end-of-entry)
                        (if (re-search-forward
                             bibtex-any-entry-maybe-empty-head nil 'move)
@@ -4096,7 +4119,11 @@ but do not actually kill it."
                   nil))
       (setq bibtex-entry-kill-ring-yank-pointer bibtex-entry-kill-ring)
       (unless copy-only
-        (delete-region beg end))))
+        (delete-region beg end)
+        ;; remove key from `bibtex-reference-keys'.
+        (unless (functionp bibtex-reference-keys)
+          (setq bibtex-reference-keys
+                (delete (cons key t) bibtex-reference-keys))))))
   (setq bibtex-last-kill-command 'entry))
 
 (defun bibtex-copy-entry-as-kill ()
@@ -4130,7 +4157,16 @@ comes the newest one."
   (unless (eq last-command 'bibtex-yank)
     (error "Previous command was not a BibTeX yank"))
   (setq this-command 'bibtex-yank)
-  (let ((inhibit-read-only t))
+  (let ((inhibit-read-only t) key)
+    ;; point is at end of yanked entry
+    (unless (functionp bibtex-reference-keys)
+      ;; remove key of yanked entry from `bibtex-reference-keys'
+      (save-excursion
+        (goto-char (mark t))
+        (if (and (looking-at bibtex-any-entry-maybe-empty-head)
+                 (setq key (bibtex-key-in-head)))
+            (setq bibtex-reference-keys
+                  (delete (cons key t) bibtex-reference-keys)))))
     (delete-region (point) (mark t))
     (bibtex-insert-kill n t)))
 
@@ -4235,23 +4271,27 @@ At end of the cleaning process, the functions in
             (if (cdr (assoc-string key bibtex-reference-keys))
                 (error "Duplicate key in %s" (buffer-file-name)))))
 
-        ;; Only update the list of keys if it has been built already.
+        ;; Only update `bibtex-strings' and `bibtex-reference-keys'
+        ;; if they have been built already.
         (cond ((eq entry-type 'string)
-               (if (and (listp bibtex-strings)
-                        (not (assoc key bibtex-strings)))
-                   (push (cons key (bibtex-text-in-string
-                                    (bibtex-parse-string) t))
-                           bibtex-strings)))
+               ;; We have a @String entry.
+               (unless (or (functionp bibtex-strings)
+                           (assoc key bibtex-strings))
+                 (push (cons key (bibtex-text-in-string
+                                  (bibtex-parse-string) t))
+                       bibtex-strings)))
               ;; We have a normal entry.
-              ((listp bibtex-reference-keys)
-               (cond ((not (assoc key bibtex-reference-keys))
-                      (push (cons key t) bibtex-reference-keys))
-                     ((not (cdr (assoc key bibtex-reference-keys)))
-                      ;; Turn a crossref key into a header key
-                      (setq bibtex-reference-keys
-                            (cons (cons key t)
-                                  (delete (list key) bibtex-reference-keys)))))
-               ;; Handle crossref key.
+              ((not (functionp bibtex-reference-keys))
+               (let ((found (assoc key bibtex-reference-keys)))
+                 (cond ((not found)
+                        (push (cons key t) bibtex-reference-keys))
+                       ((not (cdr found))
+                        ;; Turn a crossref key into a header key
+                        (setq bibtex-reference-keys
+                              (cons (cons key t)
+                                    (delete (list key) bibtex-reference-keys))))))
+               ;; If entry has a crossref key, it goes into the list
+               ;; `bibtex-reference-keys', too.
                (if (and (nth 1 index)
                         (not (assoc (nth 1 index) bibtex-reference-keys)))
                    (push (list (nth 1 index)) bibtex-reference-keys)))))
@@ -4388,7 +4428,7 @@ If mark is active reformat entries in region, if not in whole buffer."
                            last-comma page-dashes unify-case inherit-booktitle
                            whitespace braces strings))
                 (t
-                 (remove 'required-fields (push 'realign bibtex-entry-format)))))
+                 (cons 'realign (remove 'required-fields bibtex-entry-format)))))
          (reformat-reference-keys
           (if read-options
               (if use-previous-options
@@ -4502,9 +4542,9 @@ An error is signaled if point is outside key or BibTeX field."
            ;; is requested.
            (let (completion-ignore-case)
              (setq choose-completion-string-functions
-                   (lambda (choice buffer mini-p base-size)
+                   (lambda (choice buffer base-position &rest ignored)
                      (setq choose-completion-string-functions nil)
-                     (choose-completion-string choice buffer base-size)
+                     (choose-completion-string choice buffer base-position)
                      (bibtex-complete-crossref-cleanup choice)
                      t)) ; needed by choose-completion-string-functions
              (bibtex-complete-crossref-cleanup
@@ -4520,9 +4560,9 @@ An error is signaled if point is outside key or BibTeX field."
            ;; string completion
            (let ((completion-ignore-case t))
              (setq choose-completion-string-functions
-                   `(lambda (choice buffer mini-p base-size)
+                   `(lambda (choice buffer base-position &rest ignored)
                       (setq choose-completion-string-functions nil)
-                      (choose-completion-string choice buffer base-size)
+                      (choose-completion-string choice buffer base-position)
                       (bibtex-complete-string-cleanup choice ',compl)
                       t)) ; needed by `choose-completion-string-functions'
              (bibtex-complete-string-cleanup (bibtex-complete-internal compl)
@@ -4725,9 +4765,10 @@ Return the URL or nil if none can be generated."
                         (error "Match failed: %s" text)))
                     (if fmt (apply 'format fmt (nreverse obj))
                       (apply 'concat (nreverse obj)))))
-        (if (interactive-p) (message "%s" url))
+        (if (called-interactively-p 'interactive) (message "%s" url))
         (unless no-browse (browse-url url)))
-      (if (and (not url) (interactive-p)) (message "No URL known."))
+      (if (and (not url) (called-interactively-p 'interactive))
+         (message "No URL known."))
       url)))
 
 \f