X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/56388398e7a1251497f002072c061002ec9d9e81..cf38dd429888fc992408716922ecab1c39242944:/lisp/textmodes/bibtex.el diff --git a/lisp/textmodes/bibtex.el b/lisp/textmodes/bibtex.el index ddc9b32ba9..0662acf2c5 100644 --- a/lisp/textmodes/bibtex.el +++ b/lisp/textmodes/bibtex.el @@ -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 ;; Bengt Martensson @@ -9,15 +9,15 @@ ;; Mike Newton ;; Aaron Larson ;; Dirk Herrmann -;; Maintainer: Roland Winkler +;; Maintainer: Roland Winkler ;; Keywords: BibTeX, LaTeX, TeX ;; This file is part of GNU Emacs. -;; GNU Emacs is free software; you can redistribute it and/or modify +;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 3, or (at your option) -;; any later version. +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -25,9 +25,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. +;; along with GNU Emacs. If not, see . ;;; Commentary: @@ -148,12 +146,24 @@ The value nil means do no formatting at all." (const unify-case) (const braces) (const strings)))) +(put 'bibtex-entry-format 'safe-local-variable + (lambda (x) + (or (eq x t) + (let ((OK t)) + (while (consp x) + (unless (memq (pop x) + '(opts-or-alts required-fields numerical-fields + page-dashes whitespace inherit-booktitle realign + last-comma delimiters unify-case braces strings)) + (setq OK nil))) + (unless (null x) (setq OK nil)) + OK)))) (defcustom bibtex-field-braces-alist nil "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") @@ -164,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") @@ -206,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)))) @@ -736,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)) @@ -797,7 +807,7 @@ See `bibtex-generate-autokey' for details." :type 'string) (defcustom bibtex-autokey-year-title-separator ":_" - "String to be put between name part and year part of key. + "String to be put between year part and title part of key. See `bibtex-generate-autokey' for details." :group 'bibtex-autokey :type 'string) @@ -897,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\" @@ -935,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." @@ -1502,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 @@ -1714,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. @@ -1818,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))) @@ -1860,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'. @@ -1881,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 @@ -1920,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)))) @@ -1975,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) @@ -1987,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) @@ -2003,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 @@ -2054,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) @@ -2141,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 @@ -2161,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) @@ -2285,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 @@ -2293,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)) @@ -2418,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. @@ -2509,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) @@ -2533,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'. @@ -2646,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)) @@ -2654,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 @@ -2673,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. @@ -2921,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-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]. @@ -3001,12 +3027,14 @@ if that value is non-nil. ;; brace-delimited ones ) nil - (font-lock-syntactic-keywords . bibtex-font-lock-syntactic-keywords) (font-lock-extra-managed-props . (category)) (font-lock-mark-block-function . (lambda () (set-mark (bibtex-end-of-entry)) (bibtex-beginning-of-entry))))) + (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) @@ -3305,7 +3333,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))) @@ -3462,7 +3491,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 @@ -3493,7 +3522,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) @@ -3569,8 +3598,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) @@ -3610,7 +3638,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) @@ -3817,7 +3845,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" @@ -3833,8 +3862,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) @@ -3874,7 +3902,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.") @@ -4045,7 +4074,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) @@ -4059,7 +4092,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)) @@ -4073,6 +4106,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) @@ -4086,7 +4121,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 () @@ -4120,7 +4159,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))) @@ -4152,7 +4200,7 @@ intermixed with \\[bibtex-pop-previous] (bibtex-pop-previous)." (defun bibtex-clean-entry (&optional new-key called-by-reformat) "Finish editing the current BibTeX entry and clean it up. -Check that no required fields are empty and formats entry dependent +Check that no required fields are empty and format entry dependent on the value of `bibtex-entry-format'. If the reference key of the entry is empty or a prefix argument is given, calculate a new reference key. (Note: this works only if fields in entry @@ -4225,23 +4273,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))))) @@ -4378,7 +4430,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 @@ -4492,9 +4544,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 @@ -4510,9 +4562,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) @@ -4715,9 +4767,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)))