org-roam / org-roam-bibtex

Org Roam integration with bibliography management software
GNU General Public License v3.0
568 stars 47 forks source link

`orb--pre-expand-template` to use `bibtex-completion-get-value` instead of `bibtex-completion-apa-get-value` #202

Closed sati-bodhi closed 3 years ago

sati-bodhi commented 3 years ago

Is your feature request related to a problem? Please describe.

"${author}" expands to include a trailing comma with bibtex-completion-apa-get-value, which is undesirable.

Resultant File-Header with "${author}" expansion:

:PROPERTIES:
:ID:       b894eb9b-182a-4082-8320-12379602d26c
:ROAM_REFS: cite:林素英_郭店服喪思想_2003
:END:
#+type: book
#+author: 林素英, 
#+title: 從郭店簡探究其倫常觀念:以服喪思想為討論基點

Describe the solution you'd like

Defining orb--pre-expand-template with bibtex-completion-get-value would solve the problem:

(defun orb--pre-expand-template (template entry)
  "Helper function for `orb--new-note'.
TEMPLATE is an element of `org-roam-capture-templates' and ENTRY
is a BibTeX entry as returned by `bibtex-completion-get-entry'."
  ;; Handle org-roam-capture part
  (letrec (;; Org-capture templates: handle different types of
           ;; org-capture-templates: string, file and function; this is
           ;; a stripped down version of `org-capture-get-template'
           (org-template
            (pcase (nth 3 template)       ; org-capture template is here
              (`nil 'nil)
              ((and (pred stringp) tmpl) tmpl)
              (`(file ,file)
               (let ((flnm (expand-file-name file org-directory)))
                 (if (file-exists-p flnm) (f-read-text flnm)
                   (format "Template file %S not found" file))))
              (`(function ,fun)
               (if (functionp fun) (funcall fun)
                 (format "Template function %S not found" fun)))
              (_ (user-error "ORB: Invalid capture template"))))
           ;;  org-roam capture properties are here
           (plst (cddddr template))
           ;; regexp for org-capture prompt wildcard
           (rx "\\(%\\^{[[:alnum:]-_]*}\\)")
           (file-keyword (when orb-process-file-keyword
                           (or (and (stringp orb-process-file-keyword)
                                    orb-process-file-keyword)
                               "file")))
           ;; inline function to handle :if-new list expansion
           (expand-roam-template
            (lambda (roam-template-list old new)
              (let (elements)
                (dolist (el roam-template-list)
                  (if (listp el)
                      (setq elements
                            (nreverse
                             (append elements
                                     (list (funcall expand-roam-template
                                                    el old new)))))
                    (push (s-replace old new el) elements)))
                (nreverse elements))))
           (lst nil))
    ;; First run:
    ;; 1) Make a list of (org-wildcard field-value match-position) for the
    ;; second run
    ;; 2) replace org-roam-capture wildcards
    (dolist (keyword orb-preformat-keywords)
      (let* (;; prompt wildcard keyword
             (keyword (cond
                       ;; for some backward compatibility with old
                       ;; `orb-preformat-keywords'
                       ((consp keyword) (car keyword))
                       ((stringp keyword) keyword)
                       (t (user-error "Error in `orb-preformat-keywords': \
Keyword \"%s\" has invalid type (string was expected)" keyword))))
             ;; bibtex field name
             (field-name (or (car (rassoc keyword orb-bibtex-field-aliases))
                             keyword))
             ;; get the bibtex field value
             (field-value
              ;; maybe process file keyword
              (or (if (and file-keyword (string= field-name file-keyword))
                      (prog1
                          (orb-process-file-field
                           (bibtex-completion-get-value "=key=" entry))
                        ;; we're done so don't even compare file-name with
                        ;; file-keyword in the successive cycles
                        (setq file-keyword nil))
                    ;; do the usual processing otherwise
                    ;; condition-case to temporary workaround an upstream bug
                    (condition-case nil
                        (bibtex-completion-get-value field-name entry)
                      (error "")))
                  ""))
             ;; org-capture prompt wildcard
             (org-wildcard (concat "%^{" (or keyword "citekey") "}"))
             ;; org-roam-capture prompt wildcard
             (roam-wildcard (concat "${" (or keyword "citekey") "}"))
             ;; org-roam-capture :if-new property
             (roam-template (plist-get plst :if-new))
             (i 1)                      ; match counter
             pos)
        ;; Search for org-wildcard, set flag m if found
        (when org-template
          (while (string-match rx org-template pos)
            (if (string= (match-string 1 org-template) org-wildcard)
                (progn
                  (setq pos (length org-template))
                  (cl-pushnew (list org-wildcard field-value i) lst ))
              (setq pos (match-end 1)
                    i (1+ i)))))
        ;; Replace placeholders in org-roam-capture-templates :if-new property
        (when roam-template
          (setcdr roam-template
                  (funcall expand-roam-template
                           (cdr roam-template) roam-wildcard field-value)))))
    ;; Second run: replace prompts and prompt matches in org-capture
    ;; template string
    (dolist (l lst)
      (when (and org-template (nth 1 l))
        (let ((pos (concat "%\\" (number-to-string (nth 2 l)))))
          ;; replace prompt match wildcards with prompt wildcards
          ;; replace prompt wildcards with BibTeX field value
          (setq org-template (s-replace pos (car l) org-template)
                org-template (s-replace (car l) (nth 1 l) org-template))))
      (setf (nth 3 template) org-template))
    template))

Describe alternatives you've considered

Allow for a custom bibtex-completion function so that bibtex-completion-get-value can be used in place of bibtex-completion-apa-get-value easily.

Presently, I have to redefine the entire orb--pre-expand-template in my Doom config.el, which is cumbersome.

Additional context Add any other context or screenshots about the feature request here.

(setq entry (bibtex-completion-get-entry "林素英_郭店服喪思想_2003"))

(s-format
    (concat "${author}" (annobib-cited-year-zh) "《${title}》。${location}:${publisher}。")
    'bibtex-completion-apa-get-value entry)

;; use bibtex-completion-get-value to see difference

Sample Bibtex:

@book{林素英_郭店服喪思想_2003,
  title = {從郭店簡探究其倫常觀念:以服喪思想為討論基點},
  shorttitle = {從郭店簡探究其倫常觀念},
  author = {{林素英}},
  date = {2003},
  edition = {初版},
  publisher = {{萬卷樓}},
  location = {{台北市}},
  isbn = {978-957-739-425-5},
  langid = {chi},
  keywords = {人道,喪禮,硏究與考訂,簡牘}
}
myshevchuk commented 3 years ago

Hi, the latest commit introduces a user option orb-bibtex-entry-get-value-function. The default value is still bibtex-completion-apa-get-value, but you can change it to bibtex-completion-get-value or your own custom function:

(setq orb-bibtex-entry-get-value-function #'bibtex-completion-get-value)

(setq orb-bibtex-entry-get-value-function #'my-custom-get-value)