Mercurial > emacs
changeset 2602:2465861025cd
Installed Aaron Larson's new bibtex.el. See the header comment for
details.
author | Eric S. Raymond <esr@snark.thyrsus.com> |
---|---|
date | Wed, 28 Apr 1993 21:19:21 +0000 |
parents | c6fef1c54d00 |
children | f80a342fd945 |
files | lisp/textmodes/bibtex.el |
diffstat | 1 files changed, 544 insertions(+), 228 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/textmodes/bibtex.el Wed Apr 28 20:31:02 1993 +0000 +++ b/lisp/textmodes/bibtex.el Wed Apr 28 21:19:21 1993 +0000 @@ -6,7 +6,9 @@ ;; Mark Shapiro <shapiro@corto.inria.fr> ;; Mike Newton <newton@gumby.cs.caltech.edu> ;; Aaron Larson <alarson@src.honeywell.com> -;; Maintainer: Mark Shapiro <shapiro@corto.inria.fr> +;; Version: 1.3.1 +;; Maintainer:Aaron Larson <alarson@src.honeywell.com> +;; Adapted-By: ESR ;; Keywords: tex, bib ;; This file is part of GNU Emacs. @@ -25,15 +27,105 @@ ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;;; TODO distribute texinfo file. + +;;; LCD Archive Entry: +;;; bibtex-mode|Bengt Martensson, Marc Shapiro, Aaron Larson| +;;; alarson@src.honeywell.com| +;;; Support for maintaining BibTeX format bibliography databases| +;;; 93-03-29|version 1.3|~/modes/bibtex-mode.el.Z| + ;;; Commentary: -;; A major mode for entering and editing BibTex files, validating -;; them, canonicalizing them, and sorting them. Includes entry -;; commands tailored to many different formats (book, master's this, -;; journal article, etc). Has loads of options. +;;; BUGS: +;;; 1. using regular expressions to match the entire bibtex entry dies +;;; on long bibtex entires (e.g. those containing abstracts) since +;;; the length of regular expression matches is fairly limited. +;;; 2. When inserting a string (with \C-C\C-E\s) hitting a TAB results +;;; in the error message "Can't find enclosing Bibtex field" instead +;;; of moving to the empty string. [reported by gernot@cs.unsw.oz.au] +;;; 3. Function string-equalp should be in a library file, not in this +;;; file. + +;;; (current keeper: alarson@src.honeywell.com +;;; previous: shapiro@corto.inria.fr) ;;; Change Log: +;; Mon Mar 29 14:06:06 1993 Aaron Larson (alarson at gendibal) +;; +;; * bibtex.el: V1.3 released Mar 30, 1993 +;; (bibtex-field-name): Fix to match definition if latex manual, +;; specifically letters, digits, and punctuation other than comma. +;; Underscore is retained for historical reasons. +;; (bibtex-make-field): Fix to work around bug in Lucid prin1-to-string +;; function as reported by Martin Sjolin <marsj@ida.liu.se>. +;; (bibtex-entry): minor code cleanup. +;; (bibtex-mode-map): Remove key binding (C-c n) for +;; narrow-to-bibtex-entry, previous binding violated emacs policy of +;; reserving C-c followed by a letter for user customization. +;; revise modification history to better conform to FSF changelog +;; standards. +;; (bibtex-refile-entry): Removed. Would need disclaimer papers to +;; incorporate it into official sources, and unable to contact author. +;; Fix minor "syntax" errors in documentation strings and such found +;; by new byte compiler. Funs bibtex-mode, bibtex-remove-double-quotes +;; +;; +;; Fri Jan 15 14:06:06 1993 Aaron Larson (alarson at gendibal) +;; +;; * bibtex.el: V1.2 released Feb 15 1993 +;; (find-bibtex-entry-location bibtex-make-field): Fixed placement of +;; "interactive specification". [Bug report from +;; mernst@theory.lcs.mit.edu] +;; Fixed problem where bibtex-entry would fail if user typed entry +;; name in wrong case. +;; (bibtex-inside-field) Position the cursor _before_ the last comma +;; on a line (the comma is not necessarily "inside" the field); this +;; does not seem to break any existing code. ref sct@dcs.edinburgh.ac.uk +;; (bibtex-enclosing-field, bibtex-enclosing-reference): leave +;; point unmoved if no enclosing field/reference is found. As a +;; result of changes (3) and (4) bibtex-next-field works properly, +;; even when called from the entry key position. +;; (bibtex-remove-OPT): realign the '=' after removing the 'opt'. +;; (bibtex-clean-entry): always remove any trailing comma from the +;; end of a bibtex entry (these commas get stripped automatically when +;; optional fields are killed by bibtex-kill-optional-field, but can be +;; left if optional fields are removed by other means). +;; (bibtex-x-help) Replace tab with spaces in X menu as noted by +;; khera@cs.duke.edu +;; (bibtex-refile-entry): Added (from brannon@jove.cs.caltech.edu) +;; (bibtex-sort-ignore-string-entries sort-bibtex-entries, +;; map-bibtex-entries): Added variable as requested by +;; gernot@cs.unsw.oz.au, required changes to funs. +;; (bibtex-current-entry-label): Added at request of +;; yasuro@maekawa.is.uec.ac.jp +;; (bibtex-DEAthesis:) Deleted along with corresponding entry from +;; bibtex-x-help per shapiro@corto.inria.fr +;; Moved narrow-to-bibtex-entry from C-c C-n to C-c n (the previous +;; binding was in conflict with the binding for bibtex-pop-next. +;; bug report from [shapiro@corto.inria.fr] +;; + +;;; +;;; alarson@src.honeywell.com 92-Feb-13 +;;; 1. Made bibtex-entry user callable, now prompts for entry type (e.g. +;;; Article), with completion, and bound it to a key. This is now my +;;; preferred way to add most entries. +;;; 2. Made fields of a bibtex entry derived from the alist bibtex-entry- +;;; field-alist. +;;; 3. Fixed handling of escaped double quotes, e.g. "Schr{\"o}dinger". +;;; 4. Fixed bug where unhiding bibtex entries moved point. +;;; 5. Made "field name" specs permit (name . value) for defaulting. E.g. +;;; (setq bibtex-mode-user-optional-fields '(("library" . "alarson"))) +;;; will generate the field: +;;; library = "alarson", +;;; 6. Added binding for narrow-to-bibtex-entry +;;; 7. Adding a bibtex entry now runs hook: bibtex-add-entry-hook +;;; 8. Made bibtex-clean-entry fixup text alignment, and eliminated the +;;; dependency on bibtex-enclosing-reference which has a problem with +;;; long entries (e.g. those containing abstracts). +;;; ;;; alarson@src.honeywell.com 92-Jan-31 ;;; Added support for: ispell, beginning/end of entry movement, a simple ;;; outline like mode (hide the bodies of bibtex entries), support for @@ -129,35 +221,43 @@ ;;; Bengt Martensson <bengt@mathematik.uni-Bremen.de> 87-06-28 ;;; Original version +;;; Code: + ;;; NOTE by Marc Shapiro, 14-dec-87: ;;; (bibtex-x-environment) binds an X menu for bibtex mode to x-button-c-right. ;;; Trouble is, in Emacs 18.44 you can't have a mode-specific mouse binding, ;;; so it will remain active in all windows. Yuck! -;;; Code: - (provide 'bibtex) ;;; these guys typically don't have autoloads...[alarson:19920131.1548CST] +;;; Check for fboundp first so that if user autoloads them from non standard +;;; places, the users bindings will take precedence. (if (not (fboundp 'TeX-insert-quote)) (autoload 'TeX-insert-quote "tex-mode")) (if (not (fboundp 'sort-subr)) (autoload 'sort-subr "sort")) +;;; These should be in a more generally accessible location. + +(defun string-equalp (s1 s2) + "Like string= except differences in case are ignored." + (let ((ss1 (if (symbolp s1) (symbol-name s1) s1)) + (ss2 (if (symbolp s2) (symbol-name s2) s2))) + (and (= (length ss1) (length ss2)) + (string-equal (upcase ss1) (upcase ss2))))) + +;;; This should be moved into simple.el, and the functions there modified +;;; to call it rather than doing it themselves. +(defun put-string-on-kill-ring (string) + "Make STRING be the first element of the kill ring." + (setq kill-ring (cons string kill-ring)) + (if (> (length kill-ring) kill-ring-max) + (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)) + (setq kill-ring-yank-pointer kill-ring)) -(defvar bibtex-mode-syntax-table nil "") -(defvar bibtex-mode-abbrev-table nil "") -(define-abbrev-table 'bibtex-mode-abbrev-table ()) -(defvar bibtex-mode-map (make-sparse-keymap) "") -(defvar bibtex-pop-previous-search-point nil - "Next point where bibtex-pop-previous should start looking for a similar -entry.") - -(defvar bibtex-pop-next-search-point nil - "Next point where bibtex-pop-next should start looking for a similar -entry.") (defvar bibtex-clean-entry-zap-empty-opts t "*If non-nil, bibtex-clean-entry will delete all empty optional fields.") @@ -174,7 +274,148 @@ (defvar bibtex-mode-user-optional-fields nil ;no default value "*List of optional fields that user want to have as always present -when making a bibtex entry. One possibility is for ``keywords''") +when making a bibtex entry. One possibility is for ``keywords''. +Entries can be either strings or conses, in which case the car should be +string and the cdr the value to be inserted.") + +(defvar bibtex-mode-syntax-table + (let ((st (make-syntax-table))) + ;; [alarson:19920214.1004CST] make double quote a string quote + (modify-syntax-entry ?\" "\"" st) + (modify-syntax-entry ?$ "$$ " st) + (modify-syntax-entry ?% "< " st) + (modify-syntax-entry ?' "w " st) + (modify-syntax-entry ?@ "w " st) + (modify-syntax-entry ?\\ "\\" st) + (modify-syntax-entry ?\f "> " st) + (modify-syntax-entry ?\n "> " st) + (modify-syntax-entry ?~ " " st) + st)) + +(defvar bibtex-mode-abbrev-table nil "") +(define-abbrev-table 'bibtex-mode-abbrev-table ()) +(defvar bibtex-mode-map + (let ((km (make-sparse-keymap))) + + (define-key km "\t" 'bibtex-find-text) + (define-key km "\n" 'bibtex-next-field) + (define-key km "\C-c\"" 'bibtex-remove-double-quotes) + (define-key km "\C-c\C-c" 'bibtex-clean-entry) + (define-key km "\C-c?" 'describe-mode) + (define-key km "\C-c\C-p" 'bibtex-pop-previous) + (define-key km "\C-c\C-n" 'bibtex-pop-next) + (define-key km "\C-c\C-k" 'bibtex-kill-optional-field) + (define-key km "\C-c\C-d" 'bibtex-empty-field) + + ;; [alarson:19920131.1543CST] + (define-key km "\"" 'TeX-insert-quote) + (define-key km "\C-c$" 'ispell-bibtex-entry) + (define-key km "\M-\C-a" 'beginning-of-bibtex-entry) + (define-key km "\M-\C-e" 'end-of-bibtex-entry) + (define-key km "\C-ce" 'bibtex-entry) +; (define-key km "\C-cn" 'narrow-to-bibtex-entry) + + (define-key km "\C-c\C-e\C-a" 'bibtex-Article) + (define-key km "\C-c\C-e\C-b" 'bibtex-Book) +; (define-key km "\C-c\C-e\C-d" 'bibtex-DEAthesis) + (define-key km "\C-c\C-e\C-c" 'bibtex-InProceedings) + (define-key km "\C-c\C-e\C-i" 'bibtex-InBook) + (define-key km "\C-c\C-ei" 'bibtex-InCollection) + (define-key km "\C-c\C-eI" 'bibtex-InProceedings) + (define-key km "\C-c\C-e\C-m" 'bibtex-Manual) + (define-key km "\C-c\C-em" 'bibtex-MastersThesis) + (define-key km "\C-c\C-eM" 'bibtex-Misc) + (define-key km "\C-c\C-o" 'bibtex-remove-OPT) + (define-key km "\C-c\C-e\C-p" 'bibtex-PhdThesis) + (define-key km "\C-c\C-ep" 'bibtex-Proceedings) + (define-key km "\C-c\C-eP" 'bibtex-preamble) + (define-key km "\C-c\C-e\C-t" 'bibtex-TechReport) + (define-key km "\C-c\C-e\C-s" 'bibtex-string) + (define-key km "\C-c\C-e\C-u" 'bibtex-Unpublished) + km)) + +(defvar bibtex-pop-previous-search-point nil + "Next point where bibtex-pop-previous should start looking for a similar +entry.") + +(defvar bibtex-pop-next-search-point nil + "Next point where bibtex-pop-next should start looking for a similar +entry.") + +(defvar bibtex-entry-field-alist + '( + ("Article" . ((("author" "title" "journal" "year") + ("volume" "number" "pages" "month" "note")) + (("author" "title") + ("journal" "year" "volume" "number" "pages" + "month" "note")))) + ("Book" . ((("author" "title" "publisher" "year") + ("editor" "volume" "number" "series" "address" + "edition" "month" "note")))) + ("Booklet" . ((("title") + ("author" "howpublished" "address" "month" "year" "note")))) + + ;; France: Dipl\^{o}me d'Etudes Approfondies (similar to Master's) +; ("DEAthesis" . ((("author" "title" "school" "year") +; ("address" "month" "note")))) + + ("InBook" . ((("author" "title" "chapter" "publisher" "year") + ("editor" "pages" "volume" "number" "series" "address" + "edition" "month" "type" "note")) + (("author" "title" "chapter") + ("publisher" "year" "editor" "pages" "volume" "number" + "series" "address" "edition" "month" "type" "note")))) + + + ("InCollection" . ((("author" "title" + "booktitle" "publisher" "year") + ("editor" "volume" "number" "series" "type" "chapter" + "pages" "address" "edition" "month" "note")) + (("author" "title") + ("booktitle" "publisher" "year" + "editor" "volume" "number" "series" "type" "chapter" + "pages" "address" "edition" "month" "note")))) + + + ("InProceedings" . ((("author" "title" "booktitle" "year") + ("editor" "volume" "number" "series" "pages" + "organization" "publisher" "address" "month" "note")) + (("author" "title") + ("editor" "volume" "number" "series" "pages" + "booktitle" "year" + "organization" "publisher" "address" "month" "note")))) + + + ("Manual" . ((("title") + ("author" "organization" "address" "edition" "year" + "month" "note")))) + + ("MastersThesis" . ((("author" "title" "school" "year") + ("address" "month" "note" "type")))) + + ("Misc" . ((() + ("author" "title" "howpublished" "year" "month" "note")))) + + ("PhdThesis" . ((("author" "title" "school" "year") + ("address" "month" "type" "note")))) + + ("Proceedings" . ((("title" "year") + ("editor" "volume" "number" "series" "publisher" + "organization" "address" "month" "note")))) + + ("TechReport" . ((("author" "title" "institution" "year") + ("type" "number" "address" "month" "note")))) + + ("Unpublished" . ((("author" "title" "note") + ("year" "month")))) + ) + + "List of (entry-name (required optional) (crossref-required crossref-optional)) +tripples. If the third element is nil, then the first pair can be used. Required +and optional are lists of strings. All entry creation functions use this variable +to generate entries, and bibtex-entry ensures the entry type is valid. This +variable can be used for example to make bibtex manipulate a different set of entry +types, e.g. a crossreference document of organization types.") ;;; A bibtex file is a sequence of entries, either string definitions @@ -198,7 +439,24 @@ (defconst bibtex-text-in-cfield 2 "The regexp subexpression number of the text part in bibtex-cfield.") -(defconst bibtex-field-name "[A-Za-z][---A-Za-z0-9:_+]*" +;;; KAWATA Yasuro <yasuro@qqqq.maekawa.is.uec.ac.jp> reported bug that "/" +;;; was not premitted in field names. The old value of this var was: +;;; "[A-Za-z][---A-Za-z0-9:_+]*" +;;; According to the LaTeX manual, page 71, the legal values are letters, +;;; digits, and punctuation other than comma. Section 2.1 defines +;;; punctuation as: +;;; .:;,?!`'()[]-/*@ +;;; and says that += can be used in normal text. Specifically #$%&~_^\{} +;;; are called out as special chars. Some experimentation with LaTeX +;;; indicates that # and ~ definitely don't work, but that the following +;;; citation does! \cite{a0.:;?!`'()[]-/*@_&$^+=|<>}. I chose here to +;;; permit _ since it was previously allowed, but otherwise to only handle +;;; punc and += +;;; Amendment: I couldn't get a regexp with both "[]"'s and hyphen to +;;; work. It looks like you need them both to be the first entries in a +;;; regexp pattern. [alarson:19930315.0900CST] + +(defconst bibtex-field-name "[A-Za-z][---A-Za-z0-9.:;?!`'()/*@_+=]*" "Regexp defining the name part of a bibtex field.") ;; bibtex-field-text must be able to handle @@ -294,6 +552,33 @@ "Alignment for the text part in BibTeX fields. Equal to the space needed for the longest name part.") +(defun bibtex-current-entry-label (&optional include-cite kill) + "Return the label of the bibtex entry containing, or preceeding point. +Optional argument INCLUDE-CITE, if true means put a '\\cite{}' around the +returned value. Second optional argument KILL, if true, means place the +returned value in the kill buffer. Interactively; providing prefix +argument makes INCLUDE-CITE true, and kill is true by default. + +Rationale: +The intention is that someone will write a function that can be bound to +a mouse key so that people entering TeX can just mouse on the bibtex entry +and have the citation key inserted at the current point (which will almost +certainly be in some other bufer). In the interim this function is +marginally useful for keyboard binding and is not bound by default. +Suggested binding is ^C-k." + (interactive (list current-prefix-arg t)) + (save-excursion + (beginning-of-bibtex-entry) + (re-search-forward bibtex-reference-head (save-excursion (end-of-bibtex-entry) (point))) + (let* ((key (buffer-substring (match-beginning bibtex-key-in-head) + (match-end bibtex-key-in-head))) + (val (if include-cite + (format "\\cite{%s}" key) + key))) + (if kill + (put-string-on-kill-ring val)) + val))) + ;;; bibtex mode: (defun bibtex-mode () @@ -323,6 +608,24 @@ \\[bibtex-sun-environment] binds a mode-specific Sun menu to right mouse button. +The following may be of interest as well: + + Functions: + find-bibtex-duplicates + find-bibtex-entry-location + hide-bibtex-entry-bodies + sort-bibtex-entries + validate-bibtex-buffer + + Variables: + bibtex-clean-entry-zap-empty-opts + bibtex-entry-field-alist + bibtex-include-OPTannote + bibtex-include-OPTcrossref + bibtex-include-OPTkey + bibtex-maintain-sorted-entries + bibtex-mode-user-optional-fields + Fields: address Publisher's address @@ -338,7 +641,7 @@ crossref The database key of the entry being cross referenced. edition - Edition of a book (e.g., ""second"") + Edition of a book (e.g., \"second\") editor Name(s) of editor(s), in BibTeX name format. If there is also an author field, then the editor field should be @@ -371,8 +674,8 @@ title The title of the thing being referenced type - Type of a technical report (e.g., ""Research Note"") to be used - instead of the default ""Technical Report"" + Type of a technical report (e.g., \"Research Note\") to be used + instead of the default \"Technical Report\" volume Volume of a journal or multivolume work year @@ -382,63 +685,14 @@ non-nil." (interactive) (kill-all-local-variables) - (if bibtex-mode-syntax-table - (set-syntax-table bibtex-mode-syntax-table) - (setq bibtex-mode-syntax-table (make-syntax-table)) - (set-syntax-table bibtex-mode-syntax-table) - (modify-syntax-entry ?\" ".") - (modify-syntax-entry ?$ "$$ ") - (modify-syntax-entry ?% "< ") - (modify-syntax-entry ?' "w ") - (modify-syntax-entry ?@ "w ") - (modify-syntax-entry ?\\ "\\") - (modify-syntax-entry ?\f "> ") - (modify-syntax-entry ?\n "> ") - (modify-syntax-entry ?~ " ")) + (set-syntax-table bibtex-mode-syntax-table) (use-local-map bibtex-mode-map) (setq major-mode 'bibtex-mode) - - (setq mode-name "BibTeX") (set-syntax-table bibtex-mode-syntax-table) (setq local-abbrev-table bibtex-mode-abbrev-table) (make-local-variable 'paragraph-start) (setq paragraph-start "^[ \f\n\t]*$") - - (define-key bibtex-mode-map "\t" 'bibtex-find-text) - (define-key bibtex-mode-map "\n" 'bibtex-next-field) - (define-key bibtex-mode-map "\C-c\"" 'bibtex-remove-double-quotes) - (define-key bibtex-mode-map "\C-c\C-c" 'bibtex-clean-entry) - (define-key bibtex-mode-map "\C-c?" 'describe-mode) - (define-key bibtex-mode-map "\C-c\C-p" 'bibtex-pop-previous) - (define-key bibtex-mode-map "\C-c\C-n" 'bibtex-pop-next) - (define-key bibtex-mode-map "\C-c\C-k" 'bibtex-kill-optional-field) - (define-key bibtex-mode-map "\C-c\C-d" 'bibtex-empty-field) - - ;; [alarson:19920131.1543CST] - (define-key bibtex-mode-map "\"" 'TeX-insert-quote) - (define-key bibtex-mode-map "\C-c$" 'ispell-bibtex-entry) - (define-key bibtex-mode-map "\M-\C-a" 'beginning-of-bibtex-entry) - (define-key bibtex-mode-map "\M-\C-e" 'end-of-bibtex-entry) - - (define-key bibtex-mode-map "\C-c\C-e\C-a" 'bibtex-Article) - (define-key bibtex-mode-map "\C-c\C-e\C-b" 'bibtex-Book) - (define-key bibtex-mode-map "\C-c\C-e\C-d" 'bibtex-DEAthesis) - (define-key bibtex-mode-map "\C-c\C-e\C-c" 'bibtex-InProceedings) - (define-key bibtex-mode-map "\C-c\C-e\C-i" 'bibtex-InBook) - (define-key bibtex-mode-map "\C-c\C-ei" 'bibtex-InCollection) - (define-key bibtex-mode-map "\C-c\C-eI" 'bibtex-InProceedings) - (define-key bibtex-mode-map "\C-c\C-e\C-m" 'bibtex-Manual) - (define-key bibtex-mode-map "\C-c\C-em" 'bibtex-MastersThesis) - (define-key bibtex-mode-map "\C-c\C-eM" 'bibtex-Misc) - (define-key bibtex-mode-map "\C-c\C-o" 'bibtex-remove-OPT) - (define-key bibtex-mode-map "\C-c\C-e\C-p" 'bibtex-PhdThesis) - (define-key bibtex-mode-map "\C-c\C-ep" 'bibtex-Proceedings) - (define-key bibtex-mode-map "\C-c\C-eP" 'bibtex-preamble) - (define-key bibtex-mode-map "\C-c\C-e\C-t" 'bibtex-TechReport) - (define-key bibtex-mode-map "\C-c\C-e\C-s" 'bibtex-string) - (define-key bibtex-mode-map "\C-c\C-e\C-u" 'bibtex-Unpublished) - (auto-fill-mode 1) ; nice alignements (setq left-margin (+ bibtex-text-alignment 1)) @@ -468,9 +722,49 @@ (interactive) (re-search-backward "^@" nil 'move)) +(defun skip-whitespace-and-comments () + ;; It might be a good idea to have forward-sexp with argument 0 do what + ;; this function tries to do, namely skip whitespace and comments. + ;; Maybe a better name for this would be skip-to-next-sexp. + ;; alternative implementation: + ;; (let ((parse-sexp-ignore-comments t)) + ;; (forward-sexp 1) + ;; (forward-sexp -1)) + ;; but I've had problems with this not getting the parse of comments + ;; right going backward if they contain unbalanced expressions or string + ;; quotes. [alarson:19920217.1021CST] + (let ((md (match-data))) + (unwind-protect + (while (cond ((looking-at "\\s>+\\|\\s +") + ;; was whitespace + ;; NOTE: also checked end-comment. In latex and + ;; lisp modes, newline is an end comment, but it + ;; should also be a whitespace char. + (goto-char (match-end 0))) + ;; If looking at beginning of comment, skip to end. + ((looking-at "\\s<") + (re-search-forward "\\s>")))) + (store-match-data md)))) + +;;; [alarson:19920214.1007CST] (defun end-of-bibtex-entry () + "If inside an entry, move to the end of it, otherwise move to the end +of the next entry." (interactive) - (re-search-forward "}$" nil 'move)) + ;; if point was previously at the end of an entry, this puts us + ;; inside the next entry, otherwise we remain in the current one. + (progn + (skip-whitespace-and-comments) +;;; (skip-chars-forward " \t\n") + (end-of-line)) + (beginning-of-bibtex-entry) + (let ((parse-sexp-ignore-comments t)) + (forward-sexp) ; skip entry type + (forward-sexp) ; skip entry body + )) +;(defun end-of-bibtex-entry () +; (interactive) +; (re-search-forward "}$" nil 'move)) (defun ispell-bibtex-entry () (interactive) @@ -498,21 +792,29 @@ "Hide all lines between first and last bibtex entries not beginning with @. With argument, show all text." (interactive "P") - (beginning-of-first-bibtex-entry) - ;; subst-char-in-region modifies the buffer, despite what the - ;; documentation says... - (let ((modifiedp (buffer-modified-p)) - (buffer-read-only nil)) - (if arg - (subst-char-in-region (point) (point-max) ?\r ?\n t) + (save-excursion + (beginning-of-first-bibtex-entry) + ;; subst-char-in-region modifies the buffer, despite what the + ;; documentation says... + (let ((modifiedp (buffer-modified-p)) + (buffer-read-only nil)) + (if arg + (subst-char-in-region (point) (point-max) ?\r ?\n t) (while (save-excursion (re-search-forward "\n[^@]" (point-max) t)) (save-excursion (replace-regexp "\n\\([^@]\\)" "\r\\1")))) - (setq selective-display (not arg)) - (set-buffer-modified-p modifiedp))) + (setq selective-display (not arg)) + (set-buffer-modified-p modifiedp)))) + +(defvar bibtex-sort-ignore-string-entries nil + "*If true, bibtex @STRING entries are ignored when determining ordering +of the buffer (e.g. sorting, locating alphabetical position for new entries, +etc.)") (defun sort-bibtex-entries () "Sort bibtex entries alphabetically by key. -Text before the first bibtex entry, and following the last is not effected. +Text before the first bibtex entry, and following the last is not affected. +If bibtex-sort-ignore-string-entries is true, @string entries will be ignored. + Bugs: 1. Text between the closing brace ending one bibtex entry, and the @ starting the next, is considered part of the PRECEEDING entry. Perhaps it should be @@ -530,27 +832,40 @@ ;; begining of record function 'forward-line ;; end of record function - (function (lambda () (and (re-search-forward "}[ \t]*\n[\n \t]*@" nil 'move) + (function (lambda () (and (re-search-forward "}\\s-*\n[\n \t]*@" nil 'move) (forward-char -2)))) ;; start of key function - (function (lambda () (re-search-forward "{[ \t]*") nil)) + (if bibtex-sort-ignore-string-entries + (function (lambda () + (while (and (re-search-forward "^\\s-*\\([@a-zA-Z]*\\)\\s-*{\\s-*") + (string-equalp "@string" + (buffer-substring (match-beginning 1) + (match-end 1))))) + nil)) + (function (lambda () (re-search-forward "{\\s-*") nil))) ;; end of key function (function (lambda () (search-forward ","))) ))) (defun map-bibtex-entries (fun) "Call FUN for each bibtex entry starting with the current, to the end of the file. -FUN is called with one argument, the key of the entry, and with point inside the entry." +FUN is called with one argument, the key of the entry, and with point inside the entry. +If bibtex-sort-ignore-string-entries is true, FUN will not be called for @string entries." (beginning-of-bibtex-entry) - (while (re-search-forward "^@[^{]*{[ \t]*\\([^,]*\\)" nil t) - (funcall fun (buffer-substring (match-beginning 1) (match-end 1))))) + (while (re-search-forward "^@[^{]*{[ \t]*\\([^, ]*\\)" nil t) + (if (and bibtex-sort-ignore-string-entries + (string-equalp "@string{" + (buffer-substring (match-beginning 0) + (match-beginning 1)))) + nil ; ignore the @string entry. + (funcall fun (buffer-substring (match-beginning 1) (match-end 1)))))) (defun find-bibtex-entry-location (entry-name) - (interactive "sBibtex entry key: ") "Searches from beginning of current buffer looking for place to put the bibtex entry named ENTRY-NAME. Buffer is assumed to be in sorted order, without duplicates (see \\[sort-bibtex-entries]), if it is not, an error will be signalled." + (interactive "sBibtex entry key: ") (let ((previous nil) point) (beginning-of-first-bibtex-entry) @@ -600,6 +915,7 @@ (goto-char point) (while (search-forward "\"" nil t) (or (looking-at "[,}][ \t]*$") + (char-equal (preceding-char) ?\") ;; some versions put closing brace on separate line. (looking-at "[ \t]*\n}") (save-excursion @@ -628,43 +944,60 @@ (message "No duplicates found!"))) +;;; assoc doesn't ignore case, so we need an assoc that does... +(defun assoc-string-equalp (thing alist) + (or (assoc thing alist) + (while (and alist + (not (string-equalp thing (car (car alist))))) + (setq alist (cdr alist))) + (car alist))) + (defvar bibtex-maintain-sorted-entries nil "*If true, bibtex-mode will attempt to maintain all bibtex entries in -sorted order.") +sorted order. + +Note that this is more a property of a file than a personal preference and +as such should normally be set via a file local variable entry.") -;; -;; note: this should really take lists of strings OR of lists. in the -;; second case, one can use either list. (ie: -;; "name" (("crossref") ("journal" "year")) ) -;; - -(defun bibtex-entry (entry-type required optional) - (let (key) - (if bibtex-maintain-sorted-entries - (progn - (setq key (read-string (format "%s key: " entry-type))) - (find-bibtex-entry-location key))) +(defun bibtex-entry (entry-type &optional required optional) + (interactive (let* ((completion-ignore-case t) + (e-t (completing-read "Entry Type: " bibtex-entry-field-alist + nil t))) + (list e-t))) + (if (and (null required) (null optional)) + (let* ((e (assoc-string-equalp entry-type bibtex-entry-field-alist)) + (r-n-o (elt e 1)) + (c-ref (elt e 2))) + (if (null e) + (error "Bibtex entry type %s not defined!")) + (if (and bibtex-include-OPTcrossref c-ref) + (setq required (elt c-ref 0) + optional (elt c-ref 1)) + (setq required (elt r-n-o 0) + optional (elt r-n-o 1))))) + (let ((key (if bibtex-maintain-sorted-entries + (read-string (format "%s key: " entry-type))))) + (if key + (find-bibtex-entry-location key)) (bibtex-move-outside-of-entry) (insert "@" entry-type "{") - (mapcar 'bibtex-make-field required) - (if bibtex-include-OPTcrossref - (bibtex-make-optional-field "crossref")) - (if bibtex-include-OPTkey - (bibtex-make-optional-field "key")) - (mapcar 'bibtex-make-optional-field optional) - (if bibtex-mode-user-optional-fields ;MON... - (mapcar 'bibtex-make-optional-field - bibtex-mode-user-optional-fields)) - (if bibtex-include-OPTannote - (bibtex-make-optional-field "annote")) - (insert "\n}\n\n") - (forward-char -3) - (up-list -1) - (forward-char 1) (if key - (progn - (insert key) - (bibtex-next-field t))))) + (insert key)) + (save-excursion + (mapcar 'bibtex-make-field required) + (if bibtex-include-OPTcrossref + (bibtex-make-optional-field "crossref")) + (if bibtex-include-OPTkey + (bibtex-make-optional-field "key")) + (mapcar 'bibtex-make-optional-field optional) + (mapcar 'bibtex-make-optional-field + bibtex-mode-user-optional-fields) + (if bibtex-include-OPTannote + (bibtex-make-optional-field "annote")) + (insert "\n}\n\n")) + (if key + (bibtex-next-field t)) + (run-hooks 'bibtex-add-entry-hook))) ;; (defun bibtex-entry (entry-type required optional) ;; (bibtex-move-outside-of-entry) @@ -686,125 +1019,88 @@ ;; (forward-char 1)) -(defun bibtex-make-field (str) +(defun bibtex-make-field (e-t) (interactive "sBibTeX entry type: ") - (insert ",\n") - (indent-to-column bibtex-name-alignement) - (insert str " = ") - (indent-to-column bibtex-text-alignment) - (insert "\"\"") - nil) + (let ((name (if (consp e-t) (car e-t) e-t)) + (value (if (consp e-t) (cdr e-t) ""))) + (insert ",\n") + (indent-to-column bibtex-name-alignement) + (insert name " = ") + (indent-to-column bibtex-text-alignment) + ;; lucid emacs prin1-to-string breaks the undo chain. When they fix + ;; that, the hack can be removed. [alarson:19930316.0805CST] +; (insert (prin1-to-string value)) + ;; begin hack + (insert (format (if (stringp value) "\"%s\"" "%s") + value)) + ;; end hack + nil)) -(defun bibtex-make-optional-field (str) +(defun bibtex-make-optional-field (e-t) (interactive "sOptional BibTeX entry type: ") - (insert ",\n") - (indent-to-column bibtex-name-alignement) - (insert "OPT" str " = ") - (indent-to-column bibtex-text-alignment) - (insert "\"\"") - nil) + (if (consp e-t) + (setq e-t (cons (concat "OPT" (car e-t)) (cdr e-t))) + (setq e-t (concat "OPT" e-t))) + (bibtex-make-field e-t)) ;; What to do about crossref? if present, journal and year are ;; both optional. Due to this, i move all of them into optional. -- MON (defun bibtex-Article () (interactive) - (if bibtex-include-OPTcrossref - (bibtex-entry "Article" '("author" "title") - '("journal" "year" "volume" "number" "pages" - "month" "note")) - (bibtex-entry "Article" '("author" "title" "journal" "year") - '("volume" "number" "pages" "month" "note")))) - + (bibtex-entry "Article")) (defun bibtex-Book () (interactive) - (bibtex-entry "Book" '("author" "title" "publisher" "year") - '("editor" "volume" "number" "series" "address" - "edition" "month" "note"))) + (bibtex-entry "Book")) (defun bibtex-Booklet () (interactive) - (bibtex-entry "Booklet" '("title") - '("author" "howpublished" "address" "month" "year" "note"))) + (bibtex-entry "Booklet")) -;; France: Dipl\^{o}me d'Etudes Approfondies (similar to Master's) -(defun bibtex-DEAthesis () - (interactive) - (bibtex-entry "DEAthesis" '("author" "title" "school" "year") - '("address" "month" "note"))) +;(defun bibtex-DEAthesis () +; (interactive) +; (bibtex-entry "DEAthesis")) (defun bibtex-InBook () (interactive) - (if bibtex-include-OPTcrossref - (bibtex-entry "InBook" '("author" "title" "chapter") - '("publisher" "year" "editor" "pages" "volume" "number" - "series" "address" "edition" "month" "type" "note")) - (bibtex-entry "InBook" '("author" "title" "chapter" "publisher" "year") - '("editor" "pages" "volume" "number" "series" "address" - "edition" "month" "type" "note")))) + (bibtex-entry "InBook")) (defun bibtex-InCollection () (interactive) - (if bibtex-include-OPTcrossref - (bibtex-entry "InCollection" '("author" "title") - '("booktitle" "publisher" "year" - "editor" "volume" "number" "series" "type" "chapter" - "pages" "address" "edition" "month" "note")) - (bibtex-entry "InCollection" '("author" "title" - "booktitle" "publisher" "year") - '("editor" "volume" "number" "series" "type" "chapter" - "pages" "address" "edition" "month" "note")))) - + (bibtex-entry "InCollection")) (defun bibtex-InProceedings () (interactive) - (if bibtex-include-OPTcrossref - (bibtex-entry "InProceedings" '("author" "title") - '("editor" "volume" "number" "series" "pages" - "booktitle" "year" - "organization" "publisher" "address" "month" "note")) - (bibtex-entry "InProceedings" '("author" "title" "booktitle" "year") - '("editor" "volume" "number" "series" "pages" - "organization" "publisher" "address" "month" "note")))) - + (bibtex-entry "InProceedings")) (defun bibtex-Manual () (interactive) - (bibtex-entry "Manual" '("title") - '("author" "organization" "address" "edition" "year" - "month" "note"))) + (bibtex-entry "Manual")) (defun bibtex-MastersThesis () (interactive) - (bibtex-entry "MastersThesis" '("author" "title" "school" "year") - '("address" "month" "note" "type"))) + (bibtex-entry "MastersThesis")) (defun bibtex-Misc () (interactive) - (bibtex-entry "Misc" '() - '("author" "title" "howpublished" "year" "month" "note"))) + (bibtex-entry "Misc")) (defun bibtex-PhdThesis () (interactive) - (bibtex-entry "PhdThesis" '("author" "title" "school" "year") - '("address" "month" "type" "note"))) + (bibtex-entry "PhdThesis")) (defun bibtex-Proceedings () (interactive) - (bibtex-entry "Proceedings" '("title" "year") - '("editor" "volume" "number" "series" "publisher" - "organization" "address" "month" "note"))) + (bibtex-entry "Proceedings")) (defun bibtex-TechReport () (interactive) - (bibtex-entry "TechReport" '("author" "title" "institution" "year") - '("type" "number" "address" "month" "note"))) + (bibtex-entry "TechReport")) (defun bibtex-Unpublished () (interactive) - (bibtex-entry "Unpublished" '("author" "title" "note") - '("year" "month"))) + (bibtex-entry "Unpublished")) (defun bibtex-string () (interactive) @@ -880,7 +1176,12 @@ (save-excursion (goto-char (match-beginning bibtex-name-in-field)) (if (looking-at "OPT") - (delete-char (length "OPT")))) + ;; sct@dcs.edinburgh.ac.uk + (progn + (delete-char (length "OPT")) + (search-forward "=") + (delete-horizontal-space) + (indent-to-column bibtex-text-alignment)))) (bibtex-inside-field)) (defun bibtex-inside-field () @@ -889,12 +1190,12 @@ (end-of-line) (skip-chars-backward " \t") ;MON - maybe delete these chars? (cond ((= (preceding-char) ?,) - (forward-char -1))) + (forward-char -2))) ; -1 --> -2 sct@dcs.edinburgh.ac.uk (cond ((= (preceding-char) ?\") (forward-char -1)))) ;MON - only go back if quote (defun bibtex-remove-double-quotes () - "Removes """" around string." + "Removes \"\" around string." (interactive) (save-excursion (bibtex-inside-field) @@ -1067,19 +1368,25 @@ "Search for BibTeX field enclosing point. Point moves to end of field; also, use match-beginning and match-end to parse the field." - (condition-case errname - (bibtex-enclosing-regexp bibtex-field) - (search-failed - (error "Can't find enclosing BibTeX field.")))) + ;; sct@dcs.edinburgh.ac.uk + (let ((old-point (point))) + (condition-case errname + (bibtex-enclosing-regexp bibtex-field) + (search-failed + (goto-char old-point) + (error "Can't find enclosing BibTeX field."))))) (defun bibtex-enclosing-reference () "Search for BibTeX reference enclosing point. Point moves to end of reference; also, use match-beginning and match-end to parse the reference." - (condition-case errname - (bibtex-enclosing-regexp bibtex-reference) - (search-failed - (error "Can't find enclosing BibTeX reference.")))) + ;; sct@dcs.edinburgh.ac.uk + (let ((old-point (point))) + (condition-case errname + (bibtex-enclosing-regexp bibtex-reference) + (search-failed + (goto-char old-point) + (error "Can't find enclosing BibTeX reference."))))) (defun bibtex-enclosing-regexp (regexp) "Search for REGEXP enclosing point. @@ -1115,11 +1422,10 @@ (defun bibtex-clean-entry () "For all optional fields of current BibTeX entry: if empty, kill the whole field; otherwise, remove the \"OPT\" string in the name; if text numerical, remove double-quotes. For all mandatory fields: if empty, signal error." (interactive) - (bibtex-enclosing-reference) - (goto-char (match-beginning 0)) + (beginning-of-bibtex-entry) (let ((start (point))) (save-restriction - (narrow-to-region start (match-end 0)) + (narrow-to-region start (save-excursion (end-of-bibtex-entry) (point))) (while (re-search-forward bibtex-field (point-max) t 1) (let ((begin-field (match-beginning 0)) (end-field (match-end 0)) @@ -1138,6 +1444,11 @@ ; otherwise: not empty, delete "OPT" (goto-char begin-name) (delete-char (length "OPT")) + (progn + ;; fixup alignment. [alarson:19920309.2047CST] + (search-forward "=") + (delete-horizontal-space) + (indent-to-column bibtex-text-alignment)) (goto-char begin-field) ; and loop to go through next test )) (t @@ -1165,10 +1476,14 @@ (t (goto-char end-field)))))))) (goto-char start) - (skip-chars-forward "@a-zA-Z") - (bibtex-enclosing-reference) - (goto-char (match-end 0)) - (skip-chars-forward " \t\n"))) + (end-of-bibtex-entry) + ;; sct@dcs.edinburgh.ac.uk + (save-excursion + (previous-line 1) + (end-of-line) + (if (eq (preceding-char) ?,) + (backward-delete-char 1))) + (skip-whitespace-and-comments))) @@ -1176,7 +1491,7 @@ (defun bibtex-x-help (arg) "Mouse commands for BibTeX mode" - + (let ((selection (x-popup-menu arg @@ -1186,9 +1501,9 @@ (" Article in journal " . bibtex-Article) (" Book " . bibtex-Book) (" Booklet " . bibtex-Booklet) - (" Conference " . bibtex-InProceedings) + (" Conference " . bibtex-InProceedings) (" Master's Thesis " . bibtex-MastersThesis) - (" DEA Thesis " . bibtex-DEAthesis) +; (" DEA Thesis " . bibtex-DEAthesis) (" Phd. Thesis " . bibtex-PhdThesis) (" Technical Report " . bibtex-TechReport) (" technical Manual " . bibtex-Manual) @@ -1228,9 +1543,9 @@ ;; since we aren't interested. See etc/SUN-SUPPORT for the reasons why ;; we consider this nothing but a distraction from our work. -(defmacro eval-in-menu-window (&rest l) - "Evaluates its argument in the window in which the mouse button was pressed." - (list 'eval-in-window '*menu-window* l)) +;(defmacro eval-in-menu-window (&rest l) +; "Evaluates its argument in the window in which the mouse button was pressed." +; (list 'eval-in-window '*menu-window* l)) ;(defmenu bibtex-sun-entry-menu ; ("Article In Conf. Proc." eval-in-menu-window bibtex-InProceedings) @@ -1262,14 +1577,15 @@ ; ("describe BibTeX mode" eval-in-menu-window describe-mode) ; ("Main Emacs menu" . emacs-menu)) -(defun bibtex-sun-menu-eval (window x y) - "Pop-up menu of BibTeX commands." - (sun-menu-evaluate window (1+ x) (1- y) 'bibtex-sun-menu)) +;(defun bibtex-sun-menu-eval (window x y) +; "Pop-up menu of BibTeX commands." +; (sun-menu-evaluate window (1+ x) (1- y) 'bibtex-sun-menu)) +; +;(defun bibtex-sun-environment () +; "Set up sun menus for BibTeX mode. Call it as bibtex-mode-hook, or +;interactively" +; (interactive) +; (local-set-mouse '(text right) 'bibtex-sun-menu-eval)) +; -(defun bibtex-sun-environment () - "Set up sun menus for BibTeX mode. Call it as bibtex-mode-hook, or -interactively" - (interactive) - (local-set-mouse '(text right) 'bibtex-sun-menu-eval)) - -;;; bibtex-mode.el ends here +;;; bibtex.el ends here