Skip to content

Commit

Permalink
Add support for Embark multi-actions
Browse files Browse the repository at this point in the history
* Introduces the following naming convention for function arguments:
 - KEYS-ENTRIES is a list whose elements are either KEY or (KEY . ENTRY) pairs.
 - KEY-ENTRY-ALIST is a list whose elements are (KEY . ENTRY) pairs
 - KEYS is a list whose elements are keys.

* The existing function `citar--extract-keys` will transform KEYS-ENTRIES into
KEYS.

* The new function `citar--ensure-entries` will transform KEYS or KEYS-ENTRIES
into a KEY-ENTRY-ALIST.

Almost all the user-facing Citar commands (and the non-interactive function
`citar-run-default-action` take KEYS-ENTRIES arguments and have been added to
`embark-multitarget-actions`. These arguments are transformed into
`KEY-ENTRY-ALIST` in the few places that need them.

Closes emacs-citar#486.
  • Loading branch information
roshanshariff committed Dec 14, 2021
1 parent 51b30f2 commit 43f6e04
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 46 deletions.
4 changes: 2 additions & 2 deletions citar-citeproc.el
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,13 @@ With prefix-argument, select CSL style."
(let* ((style (if (string-match-p "/" citar-citeproc-csl-style)
citar-citeproc-csl-style
(concat citar-citeproc-csl-styles-dir "/" citar-citeproc-csl-style)))
(itemids (mapcar (lambda (x) (car x)) keys-entries))
(keys (citar--extract-keys keys-entries))
(proc (citeproc-create style
(citeproc-hash-itemgetter-from-any citar-bibliography)
(citeproc-locale-getter-from-dir citar-citeproc-csl-locales-dir)
"en-US"))
(references (car (progn
(citeproc-add-uncited itemids proc)
(citeproc-add-uncited keys proc)
(citeproc-render-bib proc 'plain)
))))
references))
Expand Down
8 changes: 4 additions & 4 deletions citar-file.el
Original file line number Diff line number Diff line change
Expand Up @@ -244,10 +244,10 @@ See `citar-file--files-for-multiple-entries` for details on DIRS,
EXTENSIONS, and how files are found."
(citar-file--files-for-multiple-entries (list (cons key entry)) dirs extensions))

(defun citar-file--files-for-multiple-entries (keys-entries dirs extensions)
(defun citar-file--files-for-multiple-entries (key-entry-alist dirs extensions)
"Find files related to bibliography items in KEYS-ENTRIES.
KEYS-ENTRIES is a list of (KEY . ENTRY) pairs. Return a list of
KEYS-ENTRY-ALIST is a list of (KEY . ENTRY) pairs. Return a list of
files found in two ways:
- By scanning directories in DIRS for files starting with keys in
Expand All @@ -260,7 +260,7 @@ files found in two ways:
entries in KEYS-ENTRIES. DIRS is used to resolve relative
paths and non-existent files are ignored; see
`citar-file--parse-file-field`."
(let* ((keys (seq-map #'car keys-entries))
(let* ((keys (seq-map #'car key-entry-alist))
(files (citar-file--directory-files dirs keys extensions
citar-file-additional-files-separator)))
(delete-dups
Expand All @@ -271,7 +271,7 @@ files found in two ways:
(seq-filter
#'file-exists-p
(citar-file--parse-file-field (cdr key-entry) citar-file-variable dirs))))
keys-entries))))
key-entry-alist))))

;;;; Opening and creating files functions

Expand Down
107 changes: 67 additions & 40 deletions citar.el
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@ manager like Zotero or JabRef."
:type 'hook)

(defcustom citar-default-action #'citar-open
"The default action for the `citar-at-point' command."
"The default action for the `citar-at-point' command.
Should be a function that takes one argument, a list with each
entry being either a citation KEY or a (KEY . ENTRY) pair."
:group 'citar
:type 'function)

Expand Down Expand Up @@ -706,7 +708,31 @@ If FORCE-REBUILD-CACHE is t, force reload the cache."

(defun citar--extract-keys (keys-entries)
"Extract list of keys from KEYS-ENTRIES alist."
(seq-map #'car keys-entries))
(seq-map (lambda (key-entry)
(if (consp key-entry) (car key-entry) key-entry))
keys-entries))

(defun citar--ensure-entries (keys-entries)
"Return copy of KEYS-ENTRIES with every element a (KEY . ENTRY) pair.
Each element of KEYS-ENTRIES should be either a KEY or a (KEY
. ENTRY) pair. If it is the former, look up the corresponding
ENTRY and transform the element to a (KEY . ENTRY) pair."
(let ((candidates 'uninitialized))
;; Get candidates only if some key has a missing entry, to avoid nasty
;; recursion issues like https://github.com/bdarcus/citar/issues/286. Also
;; avoids lots of memory allocation in the common case when all entries are
;; present.
(seq-map
(lambda (key-entry)
(if (consp key-entry)
key-entry
(when (eq candidates 'uninitialized)
(setq candidates (citar--get-candidates)))
(cons key-entry
(cddr (seq-find (lambda (cand-key-entry)
(string= key-entry (cadr cand-key-entry)))
candidates)))))
keys-entries)))

;;;###autoload
(defun citar-insert-preset ()
Expand Down Expand Up @@ -802,8 +828,15 @@ into the corresponding reference key. Return
;;;###autoload
(with-eval-after-load 'embark
(add-to-list 'embark-target-finders 'citar-citation-finder)
(add-to-list 'embark-target-finders 'citar-key-finder))

(add-to-list 'embark-target-finders 'citar-key-finder)
(when (boundp 'embark-multitarget-actions)
(dolist (command (list #'citar-open #'citar-open-notes
#'citar-open-entry #'citar-open-link
#'citar-open-library-files #'citar-attach-library-files
#'citar-insert-bibtex #'citar-insert-citation
#'citar-insert-reference #'citar-copy-reference
#'citar-insert-keys #'citar-run-default-action))
(add-to-list 'embark-multitarget-actions command))))

(with-eval-after-load 'embark
(set-keymap-parent citar-map embark-general-map)
Expand All @@ -822,17 +855,18 @@ into the corresponding reference key. Return
(when (and citar-library-paths
(stringp citar-library-paths))
(message "Make sure 'citar-library-paths' is a list of paths"))
(let* ((files
(citar-file--files-for-multiple-entries
keys-entries
(append citar-library-paths citar-notes-paths)
;; find files with any extension:
nil))
(let* ((key-entry-alist (citar--ensure-entries keys-entries))
(files
(citar-file--files-for-multiple-entries
key-entry-alist
(append citar-library-paths citar-notes-paths)
;; find files with any extension:
nil))
(links
(seq-map
(lambda (key-entry)
(citar-get-link (cdr key-entry)))
keys-entries))
key-entry-alist))
(resource-candidates (delete-dups (append files (remq nil links))))
(resources
(when resource-candidates
Expand All @@ -851,7 +885,7 @@ into the corresponding reference key. Return
('attach 'mml-attach-file)))
(files
(citar-file--files-for-multiple-entries
keys-entries
(citar--ensure-entries keys-entries)
citar-library-paths
citar-file-extensions)))
(if (and citar-file-open-prompt
Expand Down Expand Up @@ -889,7 +923,7 @@ With prefix, rebuild the cache before offering candidates."
(equal citar-format-note-function
'citar-org-format-note-default))
(error "You must set 'citar-notes-paths' to open notes with default notes function"))
(dolist (key-entry keys-entries)
(dolist (key-entry (citar--ensure-entries keys-entries))
(funcall citar-open-note-function (car key-entry) (cdr key-entry))))

(defun citar--open-note (key entry)
Expand All @@ -902,13 +936,13 @@ With prefix, rebuild the cache before offering candidates."
(funcall citar-format-note-function key entry file)))

;;;###autoload
(defun citar-open-entry (key-entry)
"Open bibliographic entry associated with the KEY-ENTRY.
(defun citar-open-entry (keys-entries)
"Open bibliographic entry associated with the first of KEYS-ENTRIES.
With prefix, rebuild the cache before offering candidates."
(interactive (list (citar-select-refs
:rebuild-cache current-prefix-arg)))
(let ((key (citar--extract-keys key-entry)))
(citar--open-entry (car key))))
(when-let ((key (car (citar--extract-keys keys-entries))))
(citar--open-entry key)))

(defun citar--open-entry (key)
"Open bibliographic entry asociated with the KEY."
Expand All @@ -922,9 +956,8 @@ With prefix, rebuild the cache before offering candidates."
With prefix, rebuild the cache before offering candidates."
(interactive (list (citar-select-refs
:rebuild-cache current-prefix-arg)))
(let ((keys (citar--extract-keys keys-entries)))
(dolist (key keys)
(citar--insert-bibtex key))))
(dolist (key (citar--extract-keys keys-entries))
(citar--insert-bibtex key)))

(defun citar--insert-bibtex (key)
"Insert the bibtex entry for KEY at point."
Expand Down Expand Up @@ -965,7 +998,7 @@ With prefix, rebuild the cache before offering candidates."
;; (browse-url-default-browser "https://google.com")
(interactive (list (citar-select-refs
:rebuild-cache current-prefix-arg)))
(dolist (key-entry keys-entries)
(dolist (key-entry (citar--ensure-entries keys-entries))
(let ((link (citar-get-link (cdr key-entry))))
(if link
(browse-url-default-browser link)
Expand Down Expand Up @@ -1001,25 +1034,27 @@ citation styles. See specific functions for more detail."
(defun citar-insert-reference (keys-entries)
"Insert formatted reference(s) associated with the KEYS-ENTRIES."
(interactive (list (citar-select-refs)))
(insert (funcall citar-format-reference-function keys-entries)))
(let ((key-entry-alist (citar--ensure-entries keys-entries)))
(insert (funcall citar-format-reference-function key-entry-alist))))

;;;###autoload
(defun citar-copy-reference (keys-entries)
"Copy formatted reference(s) associated with the KEYS-ENTRIES."
(interactive (list (citar-select-refs)))
(let ((references (funcall citar-format-reference-function keys-entries)))
(let* ((key-entry-alist (citar--ensure-entries keys-entries))
(references (funcall citar-format-reference-function key-entry-alist)))
(if (not (equal "" references))
(progn
(kill-new references)
(message (format "Copied:\n%s" references)))
(message "Key not found."))))

(defun citar-format-reference (keys-entries)
"Return formatted reference(s) associated with the KEYS-ENTRIES."
(defun citar-format-reference (key-entry-alist)
"Return formatted reference(s) for the elements of KEY-ENTRY-ALIST."
(let* ((template (citar-get-template 'preview))
(references
(with-temp-buffer
(dolist (key-entry keys-entries)
(dolist (key-entry key-entry-alist)
(when template
(insert (citar--format-entry-no-widths (cdr key-entry) template))))
(buffer-string))))
Expand Down Expand Up @@ -1055,26 +1090,18 @@ With prefix, rebuild the cache before offering candidates."
(make-obsolete 'citar-add-pdf-attachment 'citar-attach-library-files "0.9")

;;;###autoload
(defun citar-run-default-action (keys)
"Run the default action `citar-default-action' on KEYS."
(let* ((keys-parsed
(if (stringp keys)
(split-string keys " & ")
(split-string (cdr keys) " & ")))
(keys-entries
(seq-map
(lambda (key)
(cons key (citar--get-entry key))) keys-parsed)))
(funcall citar-default-action keys-entries)))
(defun citar-run-default-action (keys-entries)
"Run the default action `citar-default-action' on KEYS-ENTRIES."
(funcall citar-default-action keys-entries))

;;;###autoload
(defun citar-dwim ()
"Run the default action on citation keys found at point."
(interactive)
(if-let ((keys (or (car (citar--major-mode-function 'citation-at-point #'ignore))
(list (car (citar--major-mode-function 'key-at-point #'ignore))))))
;; FIX how?
(citar-run-default-action (citar--stringify-keys keys))))
(car (citar--major-mode-function 'key-at-point #'ignore)))))
(citar-run-default-action (if (listp keys) keys (list keys)))
(user-error "No citation keys found")))

(provide 'citar)
;;; citar.el ends here

0 comments on commit 43f6e04

Please sign in to comment.