SPQR
1
RT,因为citar默认文件匹配规则要么是直接写在bib文件里面,要么文件名需要是bib文件里面对应entry 的citekey,而denote的命名规则里面文件名不含cite key,而一般包含title信息,所以有了这个hack。
利用denote创建新笔记的部分可以参考denote-ciar
(require 'denote)
(setq citar-templates
'((main . "${author editor:30} ${date year issued:4} ${title:90}")
(suffix . " ${=key= id:15} ${=type=:12} ${volume keywords:*}")
(preview . "${author editor} (${year issued date}) ${title}, ${journal journaltitle publisher container-title collection-title}.\n")
(note . "Notes on ${author editor}, ${title}")))
(add-to-list 'citar-file-sources '(:items citar-denote--get-library-files :hasitems citar-denote--has-library-files))
(defun citar-denote--translate-citekey (citekey)
(denote-sluggify
(concat
(citar-get-value "title" citekey)
(when (member (citar-get-value "=type=" citekey) '("book" "mvbook"))
(format " volume %s" (citar-get-value "volume" citekey))))))
(defun citar-denote--has-library-files ()
(lambda (citekey)
(not (hash-table-empty-p (citar-denote--get-library-files (list citekey))))))
(defun citar-denote--get-library-files (&optional keys)
(citar--check-configuration 'citar-library-paths 'citar-library-file-extensions)
(citar-denote--directory-files
citar-library-paths keys citar-library-file-extensions))
(defun citar-denote--has-notes ()
(lambda (citekey)
(not (hash-table-empty-p (citar-denote--get-notes (list citekey))))))
(defun citar-denote--get-notes (&optional keys)
(citar--check-configuration 'citar-library-paths 'citar-library-file-extensions)
(citar-denote--directory-files
citar-notes-paths keys citar-file-note-extensions))
(defun citar-denote--directory-files (dirs &optional keys extensions)
(let ((files (make-hash-table :test 'equal)))
(prog1 files
(dolist (dir dirs)
(when (file-directory-p dir)
(dolist (key keys)
(let ((filenames (directory-files-recursively dir (citar-denote--translate-citekey key))))
(dolist (filename filenames)
(let ((filename (expand-file-name filename dir)))
(when (and (file-exists-p filename) (member (file-name-extension filename) extensions))
(push filename (gethash key files)))))))))
;; Reverse file lists because push adds elements to the front
(maphash (lambda (key filelist)
(puthash key (nreverse filelist) files))
files))))
2 个赞
SPQR
2
新版本,稍微提升了一些性能,逻辑和citar内置函数更类似了,并加入了一个简单的从citar创建denote笔记的例子。
(with-eval-after-load 'citar
(citar-embark-mode)
(require 'denote)
(setq citar-templates
'((main . "${author editor:30} ${date year issued:4} ${title:90}")
(suffix . " ${=key= id:15} ${=type=:12} ${volume keywords:*}")
(preview . "${author editor} (${year issued date}) ${title}, ${journal journaltitle publisher container-title collection-title}.\n")
(note . "Notes on ${author editor}, ${title}")))
(add-to-list 'citar-file-sources '(:items citar-denote--get-library-files :hasitems citar-denote--has-library-files))
(defun citar-denote--translate-citekey (citekey)
"Translate citekey into proper title."
(concat
(citar-get-value "title" citekey)
(when (and (citar-get-value "volume" citekey) (member (citar-get-value "=type=" citekey) '("book" "mvbook")))
(format " volume %s" (citar-get-value "volume" citekey)))))
(defun citar-denote--translate-title (title &optional type volume)
"Translate TITLE into denote style file name."
(denote-sluggify
(concat
title
(when (and volume (member type '("book" "mvbook")))
(format " volume %s" volume)))))
(defun citar-denote--has-library-files ()
"Return predicate testing whether cite key has library files."
(let ((files (citar-denote--get-library-files)))
(unless (hash-table-empty-p files)
(lambda (citekey)
(and (gethash citekey files) t)))))
(defun citar-denote--get-library-files (&optional keys)
(citar--check-configuration 'citar-library-paths 'citar-library-file-extensions)
(citar-denote--directory-files
citar-library-paths keys citar-library-file-extensions))
(defun citar-denote--has-notes ()
"Return predicate testing whether cite key has library files."
(let ((files (citar-denote--get-notes)))
(unless (hash-table-empty-p files)
(lambda (citekey)
(and (gethash citekey files) t)))))
(defun citar-denote--get-notes (&optional keys)
(citar--check-configuration 'citar-library-paths 'citar-library-file-extensions)
(citar-denote--directory-files
citar-notes-paths keys citar-file-note-extensions))
(defun citar-denote--directory-files (dirs &optional keys extensions)
"Check corresponding files in DIR by KEYS, filtered by EXTENSIONS."
(let ((files (make-hash-table :test 'equal))
(keys (if keys keys (hash-table-keys (citar-get-entries)))))
(prog1 files
(dolist (dir dirs)
(when (file-directory-p dir)
(dolist (key keys)
(let* ((entry (gethash key (citar-get-entries)))
(type (cdr (assoc "=type=" entry)))
(title (cdr (assoc "title" entry)))
(volume (cdr (assoc "volume" entry)))
(filenames (directory-files-recursively
dir
(citar-denote--translate-title title type volume))))
(dolist (filename filenames)
(when (and (file-exists-p filename) (member (file-name-extension filename) extensions))
(push filename (gethash key files))))))))
;; Reverse file lists because push adds elements to the front
(maphash (lambda (key filelist)
(puthash key (nreverse filelist) files))
files))))
(defun citar-denote--keywords-prompt ()
"Prompt for one or more keywords and include `denote-citar-keyword'."
(let ((choice (denote--keywords-crm (denote-keywords))))
(if denote-sort-keywords
(sort choice #'string-lessp)
choice)))
(defun citar-denote-file--create-note (key &optional entry)
"Create a bibliography note through Citar."
(let ((denote-file-type 'org)) ; make sure it is Org
(denote
(citar-denote--translate-citekey key)
(citar-denote--keywords-prompt))
;; The `denote-last-buffer' is the one we just created with `denote'.
(goto-char (point-max))))
(setq citar-notes-sources
`((citar-file .
,(list :name "Notes"
:category 'file
:items #'citar-denote--get-notes
:hasitems #'citar-denote--has-notes
:open #'find-file
:create #'citar-denote-file--create-note
:transform #'file-name-nondirectory)))))