From 29eff32307494eabed5c0160ad1713d832e65f74 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Francesco=20Potort=C3=AC?= Date: Mon, 16 Nov 2020 22:36:05 +0100 Subject: [PATCH] Add new user option bibtex-unify-case-convert * lisp/textmodes/bibtex.el (bibtex-unify-case-convert): New variable (bug#44614). (bibtex-format-entry): Use it (bug#44614). --- etc/NEWS | 5 +++ lisp/textmodes/bibtex.el | 89 +++++++++++++++++++++++----------------- 2 files changed, 56 insertions(+), 38 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 90e4d292bac..79c937b9aea 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1307,6 +1307,11 @@ This new command (bound to 'C-c C-l') regenerates the current hunk. ** Miscellaneous +--- +*** New user option 'bibtex-unify-case-convert'. +This new option allows the user to customize how case is converted +when unifying entries. + +++ *** 'format-seconds' can now be used for sub-second times. The new optional "," parameter has been added, and diff --git a/lisp/textmodes/bibtex.el b/lisp/textmodes/bibtex.el index fcf63ed5ecf..b69d715faa7 100644 --- a/lisp/textmodes/bibtex.el +++ b/lisp/textmodes/bibtex.el @@ -88,6 +88,17 @@ If this is a function, call it to generate the initial field text." (const :tag "Default" t)) :risky t) +(defcustom bibtex-unify-case-convert 'identity + "*Function called when unifying case on entry and field names. +This variable is buffer-local." + :version "28.1" + :type '(choice (const :tag "Same case as in `bibtex-field-alist'" identity) + (const :tag "Downcase" downcase) + (const :tag "Capitalize" capitalize) + (const :tag "Upcase" upcase) + (function :tag "Conversion function"))) +(make-variable-buffer-local 'bibtex-unify-case-convert) + (defcustom bibtex-user-optional-fields '(("annote" "Personal annotation (ignored)")) "List of optional fields the user wants to have always present. @@ -122,7 +133,8 @@ last-comma Add or delete comma on end of last field in entry, according to value of `bibtex-comma-after-last-field'. delimiters Change delimiters according to variables `bibtex-field-delimiters' and `bibtex-entry-delimiters'. -unify-case Change case of entry types and field names. +unify-case Change case of entry and field names according to + `bibtex-unify-case-convert'. braces Enclose parts of field entries by braces according to `bibtex-field-braces-alist'. strings Replace parts of field entries by string constants @@ -2346,7 +2358,7 @@ Formats current entry according to variable `bibtex-entry-format'." ;; unify case of entry type (when (memq 'unify-case format) (delete-region beg-type end-type) - (insert (car entry-list))) + (insert (funcall bibtex-unify-case-convert (car entry-list)))) ;; update left entry delimiter (when (memq 'delimiters format) @@ -2549,47 +2561,48 @@ Formats current entry according to variable `bibtex-entry-format'." (error "Mandatory field `%s' is empty" field-name)) ;; unify case of field name - (if (memq 'unify-case format) - (let ((fname (car (assoc-string field-name - default-field-list t)))) - (if fname - (progn - (delete-region beg-name end-name) - (goto-char beg-name) - (insert fname)) - ;; there are no rules we could follow - (downcase-region beg-name end-name)))) + (when (memq 'unify-case format) + (let ((fname (car (assoc-string field-name + default-field-list t))) + (curname (buffer-substring beg-name end-name))) + (delete-region beg-name end-name) + (goto-char beg-name) + (insert (funcall bibtex-unify-case-convert + (or fname curname))))) ;; update point (goto-char end-field)))) ;; check whether all required fields are present - (if (memq 'required-fields format) - (let ((alt-expect (make-vector num-alt nil)) - (alt-found (make-vector num-alt 0))) - (dolist (fname req-field-list) - (cond ((setq idx (nth 3 fname)) - ;; t if field has alternative flag - (bibtex-vec-push alt-expect idx (car fname)) - (if (member-ignore-case (car fname) field-list) - (bibtex-vec-incr alt-found idx))) - ((not (member-ignore-case (car fname) field-list)) - ;; If we use the crossref field, a required field - ;; can have the OPT prefix. So if it was empty, - ;; we have deleted by now. Nonetheless we can - ;; move point on this empty field. - (setq error-field-name (car fname)) - (error "Mandatory field `%s' is missing" (car fname))))) - (dotimes (idx num-alt) - (cond ((= 0 (aref alt-found idx)) - (setq error-field-name (car (last (aref alt-fields idx)))) - (error "Alternative mandatory field `%s' is missing" - (aref alt-expect idx))) - ((< 1 (aref alt-found idx)) - (setq error-field-name (car (last (aref alt-fields idx)))) - (error "Alternative fields `%s' are defined %s times" - (aref alt-expect idx) - (length (aref alt-fields idx)))))))) + (when (memq 'required-fields format) + (let ((alt-expect (make-vector num-alt nil)) + (alt-found (make-vector num-alt 0))) + (dolist (fname req-field-list) + (cond ((setq idx (nth 3 fname)) + ;; t if field has alternative flag + (bibtex-vec-push alt-expect idx (car fname)) + (if (member-ignore-case (car fname) field-list) + (bibtex-vec-incr alt-found idx))) + ((not (member-ignore-case (car fname) field-list)) + ;; If we use the crossref field, a required field + ;; can have the OPT prefix. So if it was empty, + ;; we have deleted by now. Nonetheless we can + ;; move point on this empty field. + (setq error-field-name (car fname)) + (error "Mandatory field `%s' is missing" + (car fname))))) + (dotimes (idx num-alt) + (cond ((= 0 (aref alt-found idx)) + (setq error-field-name + (car (last (aref alt-fields idx)))) + (error "Alternative mandatory field `%s' is missing" + (aref alt-expect idx))) + ((< 1 (aref alt-found idx)) + (setq error-field-name + (car (last (aref alt-fields idx)))) + (error "Alternative fields `%s' are defined %s times" + (aref alt-expect idx) + (length (aref alt-fields idx)))))))) ;; update comma after last field (if (memq 'last-comma format) -- 2.39.5