branch: main
commit 0c6f3b4801af9a9a1131a5618c119c226bd4d225
Author: Paul Nelson <[email protected]>
Commit: Arash Esbati <[email protected]>
Improved folding for citations
* NEWS.org (Added): Announce the addition.
* tex-fold.el (TeX-fold-macro-spec-list): Change default "cite"
display specification.
(bibtex):
(reftex): New require statements.
(TeX-fold--last-name):
(TeX-fold--bib-abbrev-entry-at-point):
(TeX-fold--bib-entry):
(TeX-fold--bib-abbrev): New helper functions.
(TeX-fold-bib-files): New user option.
(TeX-fold-cite-display): New function, using the above.
* doc/auctex.texi (Folding): Document the new user option.
(bug#73840)
---
NEWS.org | 6 ++++
doc/auctex.texi | 11 +++++++
tex-fold.el | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 116 insertions(+), 1 deletion(-)
diff --git a/NEWS.org b/NEWS.org
index 6960e062..b5a4bb91 100644
--- a/NEWS.org
+++ b/NEWS.org
@@ -11,6 +11,12 @@
** Added
+- Improve support for folding of citations macros. The current folding
+ =[c]= is changed to a more descriptive version, using author names and
+ publication years, like =[Ne21]= or =[ABC99]=. These are extracted
+ from any bib files referenced in the document or specified by the user
+ option ~TeX-fold-bib-file~.
+
- Add support for folding of =\begin{env}= and =\end{env}= macros. The
replacement specifiers are controlled by the custom option
~TeX-fold-begin-end-spec-list~.
diff --git a/doc/auctex.texi b/doc/auctex.texi
index 0356b96d..e7f6cc5e 100644
--- a/doc/auctex.texi
+++ b/doc/auctex.texi
@@ -2955,6 +2955,17 @@ specifications for @samp{begin} and @samp{end} from
@code{TeX-fold-macro-spec-list}.
@end defopt
+@defopt TeX-fold-bib-file
+The default folding behavior for @samp{\cite@{...@}} macros that point to
+a BibTeX entry is to replace them with a string of the form [XYZ99],
+formed using the authors' last names and the publication year. If
+@AUCTeX{} cannot find the required BibTeX entries in any bib files
+included in the current document, then, as a backup, it searches the files
+specified in @code{TeX-fold-bib-file}. This may be useful when using
+@samp{\thebibliography@{...@}} rather than BibTeX, or when working in
+non-file buffers.
+@end defopt
+
@node Outline
@section Outlining the Document
@cindex Outlining
diff --git a/tex-fold.el b/tex-fold.el
index dc7ac340..328dc4b1 100644
--- a/tex-fold.el
+++ b/tex-fold.el
@@ -72,7 +72,7 @@ macros, `math' for math macros and `comment' for comments."
(defcustom TeX-fold-macro-spec-list
'(("[f]" ("footnote" "marginpar"))
- ("[c]" ("cite"))
+ (TeX-fold-cite-display ("cite"))
("[l]" ("label"))
("[r]" ("ref" "pageref" "eqref" "footref"))
("[i]" ("index" "glossary"))
@@ -618,6 +618,8 @@ Return non-nil if a comment was found and folded, nil
otherwise."
;;; Display functions
+;; This section provides functions for use in `TeX-fold-macro-spec-list'.
+
;;;; textcolor
(defun TeX-fold-textcolor-display (color text &rest _args)
@@ -799,6 +801,102 @@ environment name, ARGS are ignored. Returns a string of
the form
(when description
(format "(%s) " description)))))
+;;;; citations
+
+(defun TeX-fold--last-name (name)
+ "Return string consisting of last name of NAME.
+NAME should be of the form \"Last, First\" or \"First Last\", possibly
+with some additional non-alphabetical characters such as braces."
+ (if-let ((comma (string-match "," name)))
+ (setq name (substring name 0 comma))
+ (when-let ((space (string-match " " name)))
+ (setq name (substring name space))))
+ (when-let ((index (string-match "[[:alpha:]]" name)))
+ (setq name (substring name index)))
+ (when-let ((index (string-match "[^[:alpha:]]" name)))
+ (setq name (substring name 0 index)))
+ name)
+
+(defun TeX-fold--bib-abbrev-entry-at-point ()
+ "Abbreviate the BibTeX entry at point.
+Return string of the form \"XYZ99\", formed using authors' last names and
+publication year, or nil if author/year not found."
+ (require 'bibtex)
+ (declare-function bibtex-parse-entry "bibtex")
+ (declare-function bibtex-text-in-field "bibtex")
+ (when-let* ((case-fold-search t)
+ (entry (bibtex-parse-entry))
+ (author (bibtex-text-in-field "author" entry))
+ (year (bibtex-text-in-field "year" entry))
+ (last-names
+ (mapcar #'TeX-fold--last-name (string-split author " and ")))
+ (last-names (seq-filter (lambda (name) (> (length name) 0))
+ last-names))
+ (initials
+ (if (and (eq (length last-names) 1)
+ (> (length (car last-names)) 1))
+ (substring (car last-names) 0 2)
+ (mapconcat (lambda (name)
+ (substring name 0 1))
+ last-names)))
+ (year-XX (when year (substring year -2))))
+ (concat initials year-XX)))
+
+(defun TeX-fold--bib-entry (key files)
+ "Retrieve BibTeX entry for KEY from FILES.
+Return first BibTeX entry found as a string, or nil if none found."
+ (when (fboundp 'reftex-pop-to-bibtex-entry)
+ (condition-case nil
+ (reftex-pop-to-bibtex-entry key files nil nil nil t)
+ (error nil))))
+
+(defcustom TeX-fold-bib-files nil
+ "List of BibTeX files from which to extract citation keys.
+This is used as a fallback option for citation folding when RefTeX can't
+find the citation keys in the provided bib files, and may be useful when
+using \\thebibliography or when working in non-file buffers."
+ :type '(repeat file)
+ :package-version '(auctex . "14.0.8"))
+
+(defun TeX-fold--bib-abbrev (key)
+ "Get abbreviation for BibTeX entry associated with KEY.
+Search using RefTeX (if available) and `TeX-fold-bib-file'. Return
+string of the form \"XYZ99\" or nil if the key is not found or does not
+contain the required information."
+ (when-let* ((entry (or (and (bound-and-true-p reftex-mode)
+ (fboundp 'reftex-get-bibfile-list)
+ (when-let (files
+ (condition-case nil
+ (reftex-get-bibfile-list)
+ (error nil)))
+ (TeX-fold--bib-entry key files)))
+ (TeX-fold--bib-entry
+ key TeX-fold-bib-files))))
+ (with-temp-buffer
+ (insert entry)
+ (goto-char (point-min))
+ (TeX-fold--bib-abbrev-entry-at-point))))
+
+(defun TeX-fold-cite-display (keys &rest _args)
+ "Fold display for a \\cite{KEYS} macro.
+KEYS are the citation key(s), as a comma-delimited list. Return string
+of the form \"[XYZ99]\" or \"[XYZ99, Optional Citation Text]\", formed
+using authors' last names and the the publication year."
+ (let* ((citation (car (TeX-fold-macro-nth-arg
+ 1 (point)
+ (TeX-fold-item-end (point) 'macro)
+ '(?\[ . ?\]))))
+ (key-list (split-string keys "[ \f\t\n\r\v,]+"))
+ (references
+ (mapcar #'TeX-fold--bib-abbrev key-list))
+ (joined-references (string-join references ", ")))
+ (concat "["
+ (if (string-empty-p joined-references)
+ "c" joined-references)
+ (when citation
+ (format ", %s" citation))
+ "]")))
+
;;; Utilities
(defun TeX-fold-make-overlay (ov-start ov-end type display-string-spec)