From 1746290506d1422057117535b9c69123cb351abe Mon Sep 17 00:00:00 2001 From: Rahguzar Date: Mon, 2 Mar 2026 18:30:06 +0500 Subject: [PATCH 1/6] fix: Try to keep user style for braces when exporting bibtex --- citar.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/citar.el b/citar.el index 8e5ed9cd..a0fcc6f1 100644 --- a/citar.el +++ b/citar.el @@ -1686,7 +1686,7 @@ including the citekeys, is maintained in Zotero with Better BibTeX." field t))) (when position (delete-region (caar position) - (car (last position)))))) + (nth 2 position))))) (let ((beg (bibtex-beginning-of-entry)) (end (bibtex-end-of-entry))) (buffer-substring-no-properties beg end))))) From 7a70eff27728e98bfcc5680168c495803099fc4f Mon Sep 17 00:00:00 2001 From: Rahguzar Date: Mon, 2 Mar 2026 18:42:35 +0500 Subject: [PATCH 2/6] perf: Insert bibliographies only once when exporting bibtex Currently they are inserted once for each citekey. This also removes the private function citar--insert-bibtex --- citar.el | 47 +++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/citar.el b/citar.el index a0fcc6f1..99895a2e 100644 --- a/citar.el +++ b/citar.el @@ -1668,30 +1668,26 @@ including the citekeys, is maintained in Zotero with Better BibTeX." (defun citar-insert-bibtex (citekeys) "Insert bibliographic entry associated with the CITEKEYS." (interactive (list (citar-select-refs))) - (dolist (citekey citekeys) - (citar--insert-bibtex citekey))) - -(defun citar--insert-bibtex (citekey) - "Insert the bibtex entry for CITEKEY at point." - (let* ((bibtex-files - (citar--bibliography-files)) - (entry - (with-temp-buffer - (bibtex-set-dialect) - (dolist (bib-file bibtex-files) - (insert-file-contents bib-file)) - (bibtex-search-entry citekey) - (dolist (field citar-bibtex-no-export-fields) - (let ((position (bibtex-search-forward-field - field t))) - (when position - (delete-region (caar position) - (nth 2 position))))) - (let ((beg (bibtex-beginning-of-entry)) - (end (bibtex-end-of-entry))) - (buffer-substring-no-properties beg end))))) - (unless (equal entry "") - (insert entry "\n\n")))) + (let ((bibtex-files + (citar--bibliography-files)) + (buffer (current-buffer))) + (with-temp-buffer + (bibtex-set-dialect) + (dolist (bib-file bibtex-files) + (insert-file-contents bib-file)) + (dolist (citekey citekeys) + (bibtex-search-entry citekey) + (dolist (field citar-bibtex-no-export-fields) + (let ((position (bibtex-search-forward-field + field t))) + (when position + (delete-region (caar position) (nth 2 position))))) + (let ((beg (bibtex-beginning-of-entry)) + (end (bibtex-end-of-entry))) + (unless (eq beg end) + (goto-char end) + (insert "\n\n") + (insert-into-buffer buffer beg (point)))))))) ;;;###autoload (defun citar-export-local-bib-file () @@ -1705,8 +1701,7 @@ directory as current buffer." (ext (file-name-extension (car citar-bibliography))) (file (format "%slocal-bib.%s" (file-name-directory buffer-file-name) ext))) (with-temp-file file - (dolist (citekey citekeys) - (citar--insert-bibtex citekey))))) + (citar-insert-bibtex citekeys)))) ;;;###autoload (defun citar-insert-citation (citekeys &optional arg) From bfecaff5067ff1230dbc8ffdef7c72aea9c2f71f Mon Sep 17 00:00:00 2001 From: Rahguzar Date: Mon, 2 Mar 2026 18:56:00 +0500 Subject: [PATCH 3/6] fix: tests failing due to long documentation line Also remove compat and require cl-lib. This gets rid of message that cl-set-difference might be undefined. --- citar.el | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/citar.el b/citar.el index 99895a2e..7ed22ffb 100644 --- a/citar.el +++ b/citar.el @@ -8,7 +8,7 @@ ;; SPDX-License-Identifier: GPL-3.0-or-later ;; Version: 1.4.0 ;; Homepage: https://github.com/emacs-citar/citar -;; Package-Requires: ((emacs "27.1") (parsebib "4.2") (org "9.5") (citeproc "0.9") (compat "30")) +;; Package-Requires: ((emacs "27.1") (parsebib "4.2") (org "9.5") (citeproc "0.9")) ;; This file is not part of GNU Emacs. ;; @@ -20,9 +20,8 @@ ;; ;;; Code: -(require 'compat) +(require 'cl-lib) (eval-when-compile - (require 'cl-lib) (require 'subr-x)) (require 'seq) (require 'map) @@ -154,7 +153,7 @@ for the title field for new notes." (defcustom citar-ellipsis nil "Ellipsis string to mark ending of truncated display fields. -If t, use the value of `truncate-string-ellipsis'. If nil, no +If t, use the value of variable `truncate-string-ellipsis'. If nil, no ellipsis will be used. Otherwise, this should be a non-empty string specifying the ellipsis." :group 'citar @@ -1572,7 +1571,7 @@ specifying TYPE." ;;;###autoload (defun citar-attach-files (citekey-or-citekeys) - "Attach library file associated with CITEKEY-OR-CITEKEYS to outgoing MIME message." + "Attach library file containing CITEKEY-OR-CITEKEYS to outgoing MIME message." (interactive (list (citar-select-ref))) (citar--library-file-action citekey-or-citekeys #'mml-attach-file)) From a6e591f3a991661ce4ffd5aaf7cb809afab8f339 Mon Sep 17 00:00:00 2001 From: Rahguzar Date: Mon, 2 Mar 2026 20:42:10 +0500 Subject: [PATCH 4/6] fix: Tweaks to bibtex-export Close #834 --- citar.el | 48 ++++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/citar.el b/citar.el index 7ed22ffb..3d20bddb 100644 --- a/citar.el +++ b/citar.el @@ -1664,43 +1664,47 @@ including the citekeys, is maintained in Zotero with Better BibTeX." (concat "zotero://select/items/@" citekey))) ;;;###autoload -(defun citar-insert-bibtex (citekeys) - "Insert bibliographic entry associated with the CITEKEYS." +(defun citar-insert-bibtex (citekeys &optional bib-files) + "Insert bibliographic entries associated with the CITEKEYS in current buffer. +Entries are searched among BIB-FILES. By default BIBFILES includes global +bib files as well as bib files local to the current document." (interactive (list (citar-select-refs))) - (let ((bibtex-files - (citar--bibliography-files)) + (let ((bib-files + (or bib-files (citar--bibliography-files))) (buffer (current-buffer))) (with-temp-buffer (bibtex-set-dialect) - (dolist (bib-file bibtex-files) + (dolist (bib-file bib-files) (insert-file-contents bib-file)) (dolist (citekey citekeys) - (bibtex-search-entry citekey) - (dolist (field citar-bibtex-no-export-fields) - (let ((position (bibtex-search-forward-field - field t))) - (when position - (delete-region (caar position) (nth 2 position))))) - (let ((beg (bibtex-beginning-of-entry)) - (end (bibtex-end-of-entry))) - (unless (eq beg end) - (goto-char end) - (insert "\n\n") - (insert-into-buffer buffer beg (point)))))))) + (when (bibtex-search-entry citekey) + (dolist (field citar-bibtex-no-export-fields) + (let ((position (bibtex-search-forward-field + field t))) + (when position + (delete-region (caar position) (nth 2 position))))) + (let ((beg (bibtex-beginning-of-entry)) + (end (bibtex-end-of-entry))) + (unless (eq beg end) + (goto-char end) + (insert "\n\n") + (insert-into-buffer buffer beg (point))))))))) ;;;###autoload (defun citar-export-local-bib-file () "Create a new bibliography file from citations in current buffer. The file is titled \"local-bib\", given the same extension as -the first entry in `citar-bibliography', and created in the same -directory as current buffer." +the first entry in `citar-bibliography', and created in the +`default-directory'." (interactive) (let* ((citekeys (citar--major-mode-function 'list-keys #'ignore)) - (ext (file-name-extension (car citar-bibliography))) - (file (format "%slocal-bib.%s" (file-name-directory buffer-file-name) ext))) + (bib-files (citar--bibliography-files)) + (ext (file-name-extension (or (car-safe citar-bibliography) + citar-bibliography))) + (file (expand-file-name (format "local-bib.%s" ext)))) (with-temp-file file - (citar-insert-bibtex citekeys)))) + (citar-insert-bibtex citekeys bib-files)))) ;;;###autoload (defun citar-insert-citation (citekeys &optional arg) From 99be3d406b6bfd111c10ee816dbca4a51f6ff104 Mon Sep 17 00:00:00 2001 From: Rahguzar Date: Tue, 3 Mar 2026 12:41:18 +0500 Subject: [PATCH 5/6] refactor: Bibtex Export --- citar.el | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/citar.el b/citar.el index 3d20bddb..a72f6662 100644 --- a/citar.el +++ b/citar.el @@ -1664,31 +1664,29 @@ including the citekeys, is maintained in Zotero with Better BibTeX." (concat "zotero://select/items/@" citekey))) ;;;###autoload -(defun citar-insert-bibtex (citekeys &optional bib-files) +(defun citar-insert-bibtex (citekeys &optional bibfiles) "Insert bibliographic entries associated with the CITEKEYS in current buffer. -Entries are searched among BIB-FILES. By default BIBFILES includes global +Entries are searched among BIBFILES. By default BIBFILES includes global bib files as well as bib files local to the current document." (interactive (list (citar-select-refs))) - (let ((bib-files - (or bib-files (citar--bibliography-files))) - (buffer (current-buffer))) + (let ((bibfiles (or bibfiles (citar--bibliography-files))) + (target (current-buffer))) (with-temp-buffer - (bibtex-set-dialect) - (dolist (bib-file bib-files) - (insert-file-contents bib-file)) + (bibtex-set-dialect nil t) + (dolist (bibfile bibfiles) + (insert-file-contents bibfile)) (dolist (citekey citekeys) - (when (bibtex-search-entry citekey) + (when-let* ((beg (bibtex-search-entry citekey))) (dolist (field citar-bibtex-no-export-fields) - (let ((position (bibtex-search-forward-field - field t))) - (when position - (delete-region (caar position) (nth 2 position))))) - (let ((beg (bibtex-beginning-of-entry)) - (end (bibtex-end-of-entry))) - (unless (eq beg end) - (goto-char end) - (insert "\n\n") - (insert-into-buffer buffer beg (point))))))))) + (when-let* ((position (bibtex-search-forward-field + field t))) + (delete-region (caar position) (nth 2 position)))) + (when-let* ((end (bibtex-end-of-entry)) + ((not (eq beg end))) + (source (current-buffer))) + (with-current-buffer target + (insert-buffer-substring-no-properties source beg end) + (insert "\n\n")))))))) ;;;###autoload (defun citar-export-local-bib-file () From 25c49bd8d445715265dac4ab2fabea399e5d379e Mon Sep 17 00:00:00 2001 From: Rahguzar Date: Sun, 26 Apr 2026 14:02:36 +0500 Subject: [PATCH 6/6] feat: customizable file name for export Also sort the entries --- citar.el | 62 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/citar.el b/citar.el index a72f6662..819fff75 100644 --- a/citar.el +++ b/citar.el @@ -87,6 +87,13 @@ buffer.") :group 'citar :type '(repeat file)) +(defcustom citar-exported-bib-file-name "local-bib" + "The file name (without extension) used by `citar-export-local-bib-file'. +If it is not an absolute file name it is expanded relative to the +`default-directory' of the buffer from which entries are being exported." + :group 'citar + :type 'file) + (defcustom citar-library-paths nil "A list of files paths for related PDFs, etc." :group 'citar @@ -1671,38 +1678,49 @@ bib files as well as bib files local to the current document." (interactive (list (citar-select-refs))) (let ((bibfiles (or bibfiles (citar--bibliography-files))) (target (current-buffer))) + (unless bibfiles + (user-error "There are no bibliographic files to export from")) (with-temp-buffer (bibtex-set-dialect nil t) (dolist (bibfile bibfiles) (insert-file-contents bibfile)) (dolist (citekey citekeys) - (when-let* ((beg (bibtex-search-entry citekey))) - (dolist (field citar-bibtex-no-export-fields) - (when-let* ((position (bibtex-search-forward-field - field t))) - (delete-region (caar position) (nth 2 position)))) - (when-let* ((end (bibtex-end-of-entry)) - ((not (eq beg end))) - (source (current-buffer))) - (with-current-buffer target - (insert-buffer-substring-no-properties source beg end) - (insert "\n\n")))))))) + (goto-char (point-min)) + (if-let* ((beg (bibtex-search-entry citekey))) + (progn + (dolist (field citar-bibtex-no-export-fields) + (when-let* ((position (bibtex-search-forward-field + field t))) + (delete-region (caar position) (nth 2 position)))) + (when-let* ((end (bibtex-end-of-entry)) + ((not (eq beg end))) + (source (current-buffer))) + (with-current-buffer target + (insert-buffer-substring-no-properties source beg end) + (insert "\n\n")))) + (message "Citkey %s not found among %S" citekey bibfiles)))))) ;;;###autoload -(defun citar-export-local-bib-file () - "Create a new bibliography file from citations in current buffer. +(defun citar-export-local-bib-file (&optional file) + "Create a new bibliography FILE file from citations in current buffer. -The file is titled \"local-bib\", given the same extension as -the first entry in `citar-bibliography', and created in the -`default-directory'." +By default, FILE is created in `default-directory' based on the value of +`citar-exported-bib-file-name' with extension determined by the bibliographies +of current buffer. If `citar-exported-bib-file-name' is nil or extension can't +be determined, user is prompted for a filename." (interactive) - (let* ((citekeys (citar--major-mode-function 'list-keys #'ignore)) - (bib-files (citar--bibliography-files)) - (ext (file-name-extension (or (car-safe citar-bibliography) - citar-bibliography))) - (file (expand-file-name (format "local-bib.%s" ext)))) + (let* ((citekeys (sort (citar--major-mode-function 'list-keys #'ignore) + :in-place t)) + (bibfiles (citar--bibliography-files)) + (file (expand-file-name + (or file + (if-let* ((citar-exported-bib-file-name) + (bib (car bibfiles)) + (ext (file-name-extension bib))) + (format "%s.%s" citar-exported-bib-file-name ext) + (read-file-name "Export to file: ")))))) (with-temp-file file - (citar-insert-bibtex citekeys bib-files)))) + (citar-insert-bibtex citekeys bibfiles)))) ;;;###autoload (defun citar-insert-citation (citekeys &optional arg)