branch: main
commit 0c6f3b4801af9a9a1131a5618c119c226bd4d225
Author: Paul Nelson <ultr...@gmail.com>
Commit: Arash Esbati <ar...@gnu.org>

    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)

Reply via email to