For academic writing and note taking in Emacs Org mode, I have been relying on the org-ref package (which can be installed from Melpa) to insert bibliography citations, visit associated PDF files and take notes. The backend bibliography database is actually a BibTeX file, which is exported from my Zotero library with the help of the Better BibTex extension. org-ref also depends on the bibtex-completion package, which enables me to interact with the bibliography database efficiently.

The following variables need to be configured for org-ref.

;; The root folder, which is the reference for generating relative paths for
;; those linked PDF files.
(setq zotero-base-directory-for-linked-pdf "/home/jihuan/文档/Documents/academic/Papers/zotero/")
;; BibTeX file exported from Zotero.
(setq bibtex-completion-bibliography "/home/jihuan/文档/Documents/academic/Papers/zotero/zotero-library.bib")
;; Folder for storing PDF files, which I set it to the root folder of Zotero
;; library.
(setq bibtex-completion-library-path "/home/jihuan/文档/Documents/academic/Papers/zotero/")
;; Centralized note file.
(setq bibtex-completion-notes-path "/home/jihuan/文档/Documents/academic/Papers/zotero/notes.org")
;; The name of the BibTeX field in which the path to PDF files is stored or
;; ‘nil’ if no such field should be used.
(setq bibtex-completion-pdf-field "file")

;; Open pdf with system PDF viewer.
(setq bibtex-completion-pdf-open-function
      (lambda (fpath)
        (start-process "xdg-open" "*xdg-open*" "xdg-open" fpath)))

For citing a bibliography item from the database, call the command org-ref-insert-cite-link. If we click on the inserted link, an interactive buffer will be opened, from which we can choose to open the PDF file, BibTeX item or related notes.

img

Moreover, because some of my PDF files are associated with their bibliography items in the Zotero library as relative links (relative to a root path, which is stored in the variable zotero-base-library) instead of being imported as copies, the function bibtex-completion-find-pdf-in-field should be modified as below and evaluated after loading the bibtex-completion package. Otherwise, the path to any of these linked PDF files that is returned from the default version will be merely a single / character, which is invalid.

(eval-after-load "bibtex-completion"
  '(defun bibtex-completion-find-pdf-in-field (key-or-entry)
     "Return the path of the PDF specified in the field `bibtex-completion-pdf-field' if that file exists.
Returns nil if no file is specified, or if the specified file
does not exist, or if `bibtex-completion-pdf-field' is nil."
     (when bibtex-completion-pdf-field
       (let* ((entry (if (stringp key-or-entry)
                         (bibtex-completion-get-entry1 key-or-entry t)
                       key-or-entry))
              (value (bibtex-completion-get-value bibtex-completion-pdf-field entry)))
         (cond
          ((not value) nil)         ; Field not defined.
          ((f-file? value) (list value))   ; A bare full path was found.
          ((-any 'f-file? (--map (f-join it (f-filename value)) (-flatten bibtex-completion-library-path))) (-filter 'f-file? (--map (f-join it (f-filename value)) (-flatten bibtex-completion-library-path))))
          (t                               ; Zotero/Mendeley/JabRef/Calibre format:
           (let ((value (replace-regexp-in-string "\\([^\\]\\)[;,]" "\\1\^^" value)))
             (cl-loop  ; Looping over the files:
              for record in (s-split "\^^" value)
                                        ; Replace unescaped colons by field separator:
              for record = (replace-regexp-in-string "\\([^\\]\\|^\\):" "\\1\^_" record)
                                        ; Unescape stuff:
              for record = (replace-regexp-in-string "\\\\\\(.\\)" "\\1" record)
                                        ; Now we can safely split:
              for record = (s-split "\^_" record)
              for file-name = (nth 0 record)
              for path = (or (nth 1 record) "")
              for paths = (if (s-match "^[A-Z]:" path)
                              (list path)                 ; Absolute Windows path
                                        ; Something else:
                            (append
                             (list
                              path
                              file-name
                              ;; (f-join (f-root) path) ; Mendeley #105
                              ;; (f-join (f-root) path file-name) ; Mendeley #105
                              (if (string-match-p "^\\.\\./" file-name)
                                  ;; If the ~file-name~ starts with
                                  ;; "../", it is a relative hyperlink to
                                  ;; the attachment, which has been
                                  ;; created in Zotero. The base
                                  ;; directory to which this relative
                                  ;; hyperlink is with respect is stored
                                  ;; in the variable
                                  ;; ~zotero-base-directory-for-linked-pdf~.
				                  (expand-file-name file-name zotero-base-directory-for-linked-pdf)
                                (f-join bibtex-completion-library-path file-name)))
                             (--map (f-join it path)
                                    (-flatten bibtex-completion-library-path)) ; Jabref #100
                             (--map (f-join it path file-name)
                                    (-flatten bibtex-completion-library-path)))) ; Jabref #100
              for result = (-first (lambda (path)
                                     (if (and (not (s-blank-str? path))
                                              (f-exists? path))
                                         path nil)) paths)
              if result collect result))))))))

Meanwhile, the variable bibtex-completion-pdf-open-function should be set as below. By default, it will use xdg-open to open the PDF file associated with a bibliography item. However, this does not work on my side, so I use Okular instead.

;; Open pdf with Okular. xdg-open does not work here.
(setq bibtex-completion-pdf-open-function
  (lambda (fpath)
    (start-process "okular" "*okular*" "okular" fpath)))