diff --git a/README.org b/README.org index c66765dc..e560c006 100644 --- a/README.org +++ b/README.org @@ -122,8 +122,10 @@ Such adapters can provide the following capabilities, which one can configure wi 1. ~insert-keys~: to insert citation keys (this may go away though) 2. ~insert-citation~: to insert citations -3. ~local-bib-files~: to find bibliographic files associated with a buffer -4. ~keys-at-point~: returns a list of citekeys at point +3. ~insert-edit~: to insert citations or edit at point +4. ~local-bib-files~: to find bibliographic files associated with a buffer +5. ~key-at-point~: returns the citation key at point +6. ~citation-at-point~: returns the list of keys in the citation at point Citar currently includes the following such adapters: diff --git a/citar-latex.el b/citar-latex.el index f25b47e7..c8a4bff0 100644 --- a/citar-latex.el +++ b/citar-latex.el @@ -34,7 +34,7 @@ (defvar citar-major-mode-functions) (defcustom citar-latex-cite-commands - '((("cite" "Cite" "citet" "Citet" "parencite" + '((("cite" "Cite" "citet" "Citet" "citep" "Citep" "parencite" "Parencite" "footcite" "footcitetext" "textcite" "Textcite" "smartcite" "Smartcite" "cite*" "parencite*" "autocite" "Autocite" "autocite*" "Autocite*" "citeauthor" "Citeauthor" @@ -65,17 +65,63 @@ the point." (ignore-errors (reftex-get-bibfile-list))) ;;;###autoload -(defun citar-latex-keys-at-point () - "Return a list of keys at point in a latex buffer." - (unless (fboundp 'TeX-current-macro) - (error "Please install AUCTeX")) - (when (citar-latex-is-a-cite-command (TeX-current-macro)) - (split-string (thing-at-point 'list t) "," t "[{} ]+"))) +(defun citar-latex-key-at-point () + "Return citation key at point with its bounds. + +The return value is (KEY . BOUNDS), where KEY is the citation key +at point and BOUNDS is a pair of buffer positions. + +Return nil if there is no key at point." + (save-excursion + (when-let* ((bounds (citar-latex--macro-bounds)) + (keych "^,{}") + (beg (progn (skip-chars-backward keych (car bounds)) (point))) + (end (progn (skip-chars-forward keych (cdr bounds)) (point))) + (pre (buffer-substring-no-properties (car bounds) beg)) + (post (buffer-substring-no-properties end (cdr bounds)))) + (and (string-match-p "{\\([^{}]*,\\)?\\'" pre) ; preceded by { ... , + (string-match-p "\\`\\(,[^{}]*\\)?}" post) ; followed by , ... } + (goto-char beg) + (looking-at (concat "[[:space:]]*\\([" keych "]+?\\)[[:space:]]*[,}]")) + (cons (match-string-no-properties 1) + (cons (match-beginning 1) (match-end 1))))))) ;;;###autoload -(defun citar-latex-insert-keys (keys) - "Insert comma sperated KEYS in a latex buffer." - (insert (string-join keys ", "))) +(defun citar-latex-citation-at-point () + "Find citation macro at point and extract keys. + +Find brace-delimited strings inside the bounds of the macro, +splits them at comma characters, and trims whitespace. + +Return (KEYS . BOUNDS), where KEYS is a list of the found +citation keys and BOUNDS is a pair of buffer positions indicating +the start and end of the citation macro." + (save-excursion + (when-let ((bounds (citar-latex--macro-bounds))) + (let ((keylists nil)) + (goto-char (car bounds)) + (while (re-search-forward "{\\([^{}]*\\)}" (cdr bounds) 'noerror) + (push (split-string (match-string-no-properties 1) "," t "[[:space:]]*") + keylists)) + (cons (apply #'append (nreverse keylists)) + bounds))))) + +(defun citar-latex--macro-bounds () + "Return the bounds of the citation macro at point. + +Return a pair of buffer positions indicating the beginning and +end of the enclosing citation macro, or nil if point is not +inside a citation macro." + (unless (fboundp 'TeX-find-macro-boundaries) + (error "Please install AUCTeX")) + (save-excursion + (when-let* ((bounds (TeX-find-macro-boundaries)) + (macro (progn (goto-char (car bounds)) + (looking-at (concat (regexp-quote TeX-esc) + "\\([@A-Za-z]+\\)")) + (match-string-no-properties 1)))) + (when (citar-latex-is-a-cite-command macro) + bounds)))) (defvar citar-latex-cite-command-history nil "Variable for history of cite commands.") @@ -109,13 +155,20 @@ inserted." (TeX-parse-macro macro (when citar-latex-prompt-for-extra-arguments (cdr (citar-latex-is-a-cite-command macro)))))) - (citar-latex-insert-keys keys) + (citar--insert-keys-comma-separated keys) (skip-chars-forward "^}") (forward-char 1))) +;;;###autoload +(defun citar-latex-insert-edit (&optional arg) + "Prompt for keys and call `citar-latex-insert-citation. +With ARG non-nil, rebuild the cache before offering candidates." + (citar-latex-insert-citation + (citar--extract-keys (citar-select-refs :rebuild-cache arg)))) + (defun citar-latex-is-a-cite-command (command) "Return element of `citar-latex-cite-commands` containing COMMAND." (seq-find (lambda (x) (member command (car x))) - citar-latex-cite-commands)) + citar-latex-cite-commands)) (provide 'citar-latex) ;;; citar-latex.el ends here diff --git a/citar-markdown.el b/citar-markdown.el index 4cff194b..c61cacdb 100644 --- a/citar-markdown.el +++ b/citar-markdown.el @@ -28,6 +28,7 @@ ;;; Code: (require 'citar) +(require 'thingatpt) (defvar citar-major-mode-functions) @@ -39,37 +40,89 @@ ;;;###autoload (defun citar-markdown-insert-keys (keys) - "Insert comma sperated KEYS in a markdown buffer." + "Insert semicolon-separated and @-prefixed KEYS in a markdown buffer." (insert (mapconcat (lambda (k) (concat "@" k)) keys "; "))) ;;;###autoload (defun citar-markdown-insert-citation (keys) - "Insert a pandoc-style citation consisting of KEYS." - (let* ((prenote (if citar-markdown-prompt-for-extra-arguments - (read-from-minibuffer "Prenote: "))) - (postnote (if citar-markdown-prompt-for-extra-arguments - (read-from-minibuffer "Postnote: "))) - (prenote (if (string= "" prenote) "" (concat prenote " "))) - (postnote (if (string= "" postnote) "" (concat ", " postnote)))) - (insert (format "[%s%s%s]" - prenote - (mapconcat (lambda (k) (concat "@" k)) keys "; ") - postnote)))) - -(defconst citar-markdown-regex-citation-key - "\\(-?@\\([[:alnum:]_][[:alnum:]_:.#$%&+?<>~/-]*\\)\\)" - ;; borrowed from pandoc-mode + "Insert a pandoc-style citation consisting of KEYS. + +If the point is inside a citation, add new keys after the current +key. + +If point is immediately after the opening \[, add new keys +to the beginning of the citation." + (let* ((citation (citar-markdown-citation-at-point)) + (keys (if citation (seq-difference keys (car citation)) keys)) + (keyconcat (mapconcat (lambda (k) (concat "@" k)) keys "; "))) + (when keys + (if (or (not citation) + (= (point) (cadr citation)) + (= (point) (cddr citation))) + (let* ((prenote (when citar-markdown-prompt-for-extra-arguments + (read-from-minibuffer "Prenote: "))) + (postnote (when citar-markdown-prompt-for-extra-arguments + (read-from-minibuffer "Postnote: "))) + (prenote (if (string= "" prenote) "" (concat prenote " "))) + (postnote (if (string= "" postnote) "" (concat ", " postnote)))) + (insert (format "[%s%s%s]" prenote keyconcat postnote))) + (if (= (point) (1+ (cadr citation))) + (save-excursion (insert keyconcat "; ")) + (skip-chars-forward "^;]" (cddr citation)) + (insert "; " keyconcat)))))) + +;;;###autoload +(defun citar-markdown-insert-edit (&optional arg) + "Prompt for keys and call `citar-markdown-insert-citation. +With ARG non-nil, rebuild the cache before offering candidates." + (citar-markdown-insert-citation + (citar--extract-keys (citar-select-refs :rebuild-cache arg)))) + +(defconst citar-markdown-citation-key-regexp + (concat "-?@" ; @ preceded by optional - + "\\(?:" + "{\\(?1:.*?\\)}" ; brace-delimited key + "\\|" + "\\(?1:[[:alnum:]_][[:alnum:]]*\\(?:[:.#$%&+?<>~/-][[:alnum:]]+\\)*\\)" + "\\)") "Regular expression for a citation key.") ;;;###autoload (defun citar-markdown-key-at-point () - "Return a citation key at point for pandoc markdown citations." + "Return citation key at point (with its bounds) for pandoc markdown citations. +Returns (KEY . BOUNDS), where KEY is the citation key at point +and BOUNDS is a pair of buffer positions. Citation keys are +found using `citar-markdown-citation-key-regexp`. Returns nil if +there is no key at point." (interactive) - (when (thing-at-point-looking-at citar-markdown-regex-citation-key) - (let ((stab (copy-syntax-table))) - (with-syntax-table stab - (modify-syntax-entry ?@ "_") - (cadr (split-string (thing-at-point 'symbol) "[]@;]")))))) + (when (thing-at-point-looking-at citar-markdown-citation-key-regexp) + (cons (match-string-no-properties 1) + (cons (match-beginning 0) (match-end 0))))) + +;;;###autoload +(defun citar-markdown-citation-at-point () + "Return keys of citation at point. +Find balanced expressions starting and ending with square +brackets and containing at least one citation key (matching +`citar-markdown-citation-key-regexp`). Return (KEYS . BOUNDS), +where KEYS is a list of the found citation keys and BOUNDS is a +pair of buffer positions indicating the start and end of the +citation." + (save-excursion + (cond + ((eq ?\[ (char-after)) (forward-char)) + ((eq ?\] (char-before)) (backward-char))) + (seq-some ; for each opening paren + (lambda (startpos) ; return keys in balanced [ ] expr + (when-let ((endpos (and (eq ?\[ (char-after startpos)) + (scan-lists startpos 1 0)))) + (let (keys) + (goto-char startpos) + (while (re-search-forward citar-markdown-citation-key-regexp endpos t) + (push (match-string-no-properties 1) keys)) + (when keys + (cons (nreverse keys) (cons startpos endpos)))))) + (reverse (nth 9 (syntax-ppss)))))) (provide 'citar-markdown) ;;; citar-markdown.el ends here diff --git a/citar-org.el b/citar-org.el index fb4ad55a..a605ded2 100644 --- a/citar-org.el +++ b/citar-org.el @@ -44,6 +44,7 @@ (declare-function org-element-type "org") (declare-function org-cite-make-insert-processor "oc") (declare-function org-cite-get-references "oc") +(declare-function embark-act "ext:embark") (defvar embark-target-finders) (defvar embark-keymap-alist) (defvar embark-pre-action-hooks) @@ -84,31 +85,9 @@ Each function takes one argument, a citation." ;;; Keymaps -(defvar citar-org-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "o") (cons "open source (file or link)" #'citar-open)) - (define-key map (kbd "e") (cons "open bibtex entry" #'citar-open-entry)) - (define-key map (kbd "f") (cons "open source file" #'citar-open-library-files)) - (define-key map (kbd "l") (cons "open source link" #'citar-open-link)) - (define-key map (kbd "n") (cons "open notes" #'citar-open-notes)) - (define-key map (kbd "r") (cons "refresh" #'citar-refresh)) - map) - "Keymap for org-cite Embark minibuffer functionality.") - -(defvar citar-org-buffer-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "o") (cons "open source (file or link)" #'citar-open)) - (define-key map (kbd "e") (cons "open bibtex entry" #'citar-open-entry)) - (define-key map (kbd "f") (cons "open source file" #'citar-open-library-files)) - (define-key map (kbd "l") (cons "open source link" #'citar-open-link)) - (define-key map (kbd "n") (cons "open notes" #'citar-open-notes)) - (define-key map (kbd "r") (cons "refresh" #'citar-refresh)) - map) - "Keymap for org-cite Embark at-point functionality.") - (defvar citar-org-citation-map (let ((map (make-sparse-keymap))) - (define-key map (kbd "") (cons "default action" #'citar-dwim)) + (define-key map (kbd "") (cons "default action" #'org-open-at-point)) (with-eval-after-load 'embark (define-key map (kbd "") (cons "embark act" #'embark-act))) (define-key map (kbd "C-d") (cons "delete citation" #'citar-org-delete-citation)) @@ -170,13 +149,41 @@ With PROC list, limit to specific processor(s)." ;; NOTE I may move some or all of these to a separate project ;;;###autoload -(defun citar-org-insert (&optional multiple) +(defun citar-org-select-key (&optional multiple) "Return a list of keys when MULTIPLE, or else a key string." - (let ((references (citar--extract-keys - (citar-select-refs)))) - (if multiple - references - (car references)))) + (if multiple + (citar--extract-keys (citar-select-refs)) + (car (citar-select-ref)))) + +;;;###autoload +(defun citar-org-insert-citation (keys &optional style) + "Insert KEYS in org-cite format, with STYLE." + (let ((context (org-element-context))) + (if-let ((citation (citar-org--citation-at-point context))) + (when-let ((keys (seq-difference keys (org-cite-get-references citation t))) + (keystring (mapconcat (lambda (key) (concat "@" key)) keys "; ")) + (begin (org-element-property :contents-begin citation))) + (if (<= (point) begin) + (org-with-point-at begin + (insert keystring ";")) + (let ((refatpt (citar-org--reference-at-point))) + (org-with-point-at (or (and refatpt (org-element-property :end refatpt)) + (org-element-property :contents-end citation)) + (if (char-equal ?\; (char-before)) + (insert-before-markers keystring ";") + (insert-before-markers ";" keystring)))))) + (if (org-cite--allowed-p context) + (insert + (format "[cite%s:%s]" (or style "") + (mapconcat (lambda (key) (concat "@" key)) keys "; "))) + (user-error "Cannot insert a citation here"))))) + +;;;###autoload +(defun citar-org-insert-edit (&optional arg) + "Run `org-cite-insert` with citar insert processor. +ARG is used as the prefix argument." + (let ((org-cite-insert-processor 'citar)) + (org-cite-insert arg))) ;;;###autoload (defun citar-org-follow (_datum _arg) @@ -231,9 +238,10 @@ strings by style." (propertize formatted-preview 'face 'citar-org-style-preview))) ;;;###autoload -(defun citar-org-local-bibs () +(defun citar-org-local-bib-files (&rest _args) "Return local bib file paths for org buffer." - (org-cite-list-bibliography-files)) + (seq-difference (org-cite-list-bibliography-files) + org-cite-global-bibliography)) ;;; Org note function @@ -270,29 +278,39 @@ strings by style." ;;; Embark target finder -(defun citar-org-citation-finder () - "Return org-cite citation keys at point as a list for `embark'." - (when-let ((keys (citar-org-keys-at-point))) - (cons 'oc-citation (citar--stringify-keys keys)))) - ;;;###autoload -(defun citar-org-keys-at-point () +(defun citar-org-key-at-point () "Return key at point for org-cite citation-reference." - (when-let (((eq major-mode 'org-mode)) - (elt (org-element-context))) - (pcase (org-element-type elt) - ('citation-reference - (org-element-property :key elt)) - ('citation - (org-cite-get-references elt t))))) - -(defun citar-org--insert-keys (keys) - "Insert KEYS in org-cite format." - (string-join (seq-map (lambda (key) (concat "@" key)) keys) ":")) + (when-let ((reference (citar-org--reference-at-point))) + (cons (org-element-property :key reference) + (cons (org-element-property :begin reference) + (org-element-property :end reference))))) +;;;###autoload +(defun citar-org-citation-at-point () + "Return org-cite citation keys at point as a list for `embark'." + (when-let ((citation (citar-org--citation-at-point))) + (cons (org-cite-get-references citation t) + (org-cite-boundaries citation)))) ;;; Functions for editing/modifying citations +(defun citar-org--reference-at-point (&optional context) + "Return citation-reference org-element at point, if any." + (when-let ((context (or context (org-element-context)))) + (when (eq 'citation-reference (org-element-type context)) + context))) + +(defun citar-org--citation-at-point (&optional context) + "Return citation element containing point, if any." + (let ((element (or context (org-element-context)))) + (while (and element (not (eq 'citation (org-element-type element)))) + (setq element (org-element-property :parent element))) + (when-let ((bounds (and element (org-cite-boundaries element)))) + (when (and (>= (point) (car bounds)) + (<= (point) (cdr bounds))) + element)))) + ;; most of this section is adapted from org-ref-cite (defun citar-org-activate-keymap (citation) @@ -383,16 +401,6 @@ strings by style." `(citation-reference (:key ,key :prefix ,pre :suffix ,post)))))) -;; Embark configuration for org-cite - -(with-eval-after-load 'embark -; (set-keymap-parent citar-org-map embark-general-map) -; (set-keymap-parent citar-org-buffer-map embark-general-map) - (add-to-list 'embark-target-finders 'citar-org-citation-finder) - (add-to-list 'embark-keymap-alist '(bib-reference . citar-org-map)) - (add-to-list 'embark-keymap-alist '(oc-citation . citar-org-buffer-map)) - (add-to-list 'embark-pre-action-hooks '(org-cite-insert embark--ignore-target))) - ;; Load this last. ;;;###autoload @@ -406,7 +414,7 @@ Argument CITATION is an org-element holding the references." (with-eval-after-load 'oc (org-cite-register-processor 'citar :insert (org-cite-make-insert-processor - #'citar-org-insert + #'citar-org-select-key #'citar-org-select-style) :follow #'citar-org-follow :activate #'citar-org-activate)) diff --git a/citar.el b/citar.el index 35556cd5..388c9e3f 100644 --- a/citar.el +++ b/citar.el @@ -53,6 +53,7 @@ (defvar embark-keymap-alist) (defvar embark-target-finders) +(defvar embark-pre-action-hooks) (defvar embark-general-map) (defvar embark-meta-map) (defvar citar-org-open-note-function) @@ -189,18 +190,26 @@ If you use 'org-roam' and 'org-roam-bibtex', you can use (defcustom citar-major-mode-functions '(((org-mode) . - ((local-bib-files . citar-org-local-bibs) - (keys-at-point . citar-org-keys-at-point))) + ((local-bib-files . citar-org-local-bib-files) + (insert-citation . citar-org-insert-citation) + (insert-edit . citar-org-insert-edit) + (key-at-point . citar-org-key-at-point) + (citation-at-point . citar-org-citation-at-point))) ((latex-mode) . ((local-bib-files . citar-latex-local-bib-files) - (insert-keys . citar-latex-insert-keys) (insert-citation . citar-latex-insert-citation) - (keys-at-point . citar-latex-keys-at-point))) + (insert-edit . citar-latex-insert-edit) + (key-at-point . citar-latex-key-at-point) + (citation-at-point . citar-latex-citation-at-point))) ((markdown-mode) . ((insert-keys . citar-markdown-insert-keys) - (keys-at-point . citar-markdown-key-at-point) - (insert-citation . citar-markdown-insert-citation)))) - "The variable determining the major mode specifc functionality. + (insert-citation . citar-markdown-insert-citation) + (insert-edit . citar-markdown-insert-edit) + (key-at-point . citar-markdown-key-at-point) + (citation-at-point . citar-markdown-citation-at-point))) + (t . + ((insert-keys . citar--insert-keys-comma-separated)))) + "The variable determining the major mode specific functionality. It is alist with keys being a list of major modes. @@ -215,10 +224,23 @@ insert-keys: the corresponding function should insert the list of keys given to as the argument at point in the buffer. insert-citation: the corresponding function should insert a -complete citation from a list of keys at point. - -keys-at-point: the corresponding function should return the list of keys at -point." +complete citation from a list of keys at point. If the point is +in a citation, new keys should be added to the citation. + +insert-edit: the corresponding function should accept an optional +prefix argument and interactively edit the citation or key at +point. + +key-at-point: the corresponding function should return the +citation key at point or nil if there is none. The return value +should be (KEY . BOUNDS), where KEY is a string and BOUNDS is a +pair of buffer positions indicating the start and end of the key. + +citation-at-point: the corresponding function should return the +keys of the citation at point, or nil if there is none. The +return value should be (KEYS . BOUNDS), where KEYS is a list of +strings and BOUNDS is pair of buffer positions indicating the +start and end of the citation." :group 'citar :type 'alist) @@ -236,10 +258,10 @@ point." (defvar citar-map (let ((map (make-sparse-keymap))) - (define-key map (kbd "b") (cons "insert bibtex" #'citar-insert-bibtex)) (define-key map (kbd "c") (cons "insert citation" #'citar-insert-citation)) - (define-key map (kbd "k") (cons "insert key" #'citar-insert-keys)) + (define-key map (kbd "k") (cons "insert keys" #'citar-insert-keys)) (define-key map (kbd "fr") (cons "insert formatted reference" #'citar-insert-reference)) + (define-key map (kbd "b") (cons "insert bibtex" #'citar-insert-bibtex)) (define-key map (kbd "o") (cons "open source document" #'citar-open)) (define-key map (kbd "e") (cons "open bibtex entry" #'citar-open-entry)) (define-key map (kbd "l") (cons "open source URL or DOI" #'citar-open-link)) @@ -252,8 +274,10 @@ point." map) "Keymap for Embark minibuffer actions.") -(defvar citar-buffer-map +(defvar citar-citation-map (let ((map (make-sparse-keymap))) + (define-key map (kbd "i") (cons "insert or edit" #'citar-insert-edit)) + (define-key map (kbd "c") (cons "insert citation" #'citar-insert-citation)) (define-key map (kbd "o") (cons "open source document" #'citar-open)) (define-key map (kbd "e") (cons "open bibtex entry" #'citar-open-entry)) (define-key map (kbd "l") (cons "open source URL or DOI" #'citar-open-link)) @@ -290,7 +314,7 @@ offering the selection candidates." (if (eq action 'metadata) `(metadata (affixation-function . ,#'citar--affixation) - (category . bib-reference)) + (category . citar-reference)) (complete-with-action action candidates string predicate))) nil nil nil 'citar-history citar-presets nil))) @@ -322,7 +346,7 @@ offering the selection candidates." (if (eq action 'metadata) `(metadata (affixation-function . ,#'citar--affixation) - (category . bib-reference)) + (category . citar-reference)) (complete-with-action action candidates string predicate))) nil nil nil 'citar-history citar-presets nil))) @@ -355,18 +379,22 @@ offering the selection candidates." ((string= extension (or "org" "md")) "Notes") (t "Library Files"))))) +(defun citar--get-major-mode-function (key &optional default) + "Return KEY from 'major-mode-functions'." + (alist-get + key + (cdr (seq-find + (lambda (modefns) + (let ((modes (car modefns))) + (or (eq t modes) + (apply #'derived-mode-p (if (listp modes) modes (list modes)))))) + citar-major-mode-functions)) + default)) + (defun citar--major-mode-function (key default &rest args) "Function for the major mode corresponding to KEY applied to ARGS. If no function is found, the DEFAULT function is called." - (apply - (alist-get - key - (cdr - (seq-find - (lambda (x) (or (eq x t) (apply #'derived-mode-p (car x)))) - citar-major-mode-functions)) - default) - args)) + (apply (citar--get-major-mode-function key default) args)) (defun citar--local-files-to-cache () "The local bibliographic files not included in the global bibliography." @@ -673,11 +701,18 @@ FORMAT-STRING." ;;; At-point functions for Embark ;;;###autoload -(defun citar-keys-at-point () - "Return the keys of the entry at point." - (when-let (keys (and (not (minibufferp)) - (citar--major-mode-function 'keys-at-point #'ignore))) - (cons 'citation-key (citar--stringify-keys keys)))) +(defun citar-key-finder () + "Return the citation key at point." + (when-let (key (and (not (minibufferp)) + (citar--major-mode-function 'key-at-point #'ignore))) + (cons 'citar-key key))) + +;;;###autoload +(defun citar-citation-finder () + "Return the keys of the citation at point." + (when-let (citation (and (not (minibufferp)) + (citar--major-mode-function 'citation-at-point #'ignore))) + `(citar-citation ,(citar--stringify-keys (car citation)) . ,(cdr citation)))) (defun citar--stringify-keys (keys) "Return a list of KEYS as a crm-string for `embark'." @@ -685,13 +720,15 @@ FORMAT-STRING." ;;;###autoload (with-eval-after-load 'embark - (add-to-list 'embark-target-finders 'citar-keys-at-point)) + (add-to-list 'embark-target-finders 'citar-citation-finder) + (add-to-list 'embark-target-finders 'citar-key-finder)) + (with-eval-after-load 'embark - (set-keymap-parent citar-map embark-general-map) - (set-keymap-parent citar-buffer-map embark-general-map) - (add-to-list 'embark-keymap-alist '(bib-reference . citar-map)) - (add-to-list 'embark-keymap-alist '(citation-key . citar-buffer-map))) + (add-to-list 'embark-keymap-alist '(citar-reference . citar-map)) + (add-to-list 'embark-keymap-alist '(citar-key . citar-citation-map)) + (add-to-list 'embark-keymap-alist '(citar-citation . citar-citation-map)) + (add-to-list 'embark-pre-action-hooks '(citar-insert-edit embark--ignore-target))) ;;; Commands @@ -830,13 +867,21 @@ 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))) - ;; TODO (citar--major-mode-function 'insert-citation (lambda (&rest _) (message "Citation insertion is not supported for %s" major-mode)) (citar--extract-keys keys-entries))) +(defun citar-insert-edit (&optional arg) + "Edit the citation at point." + (interactive "P") + (citar--major-mode-function + 'insert-edit + (lambda (&rest _) + (message "Citation editing is not supported for %s" major-mode)) + arg)) + ;;;###autoload (defun citar-insert-reference (keys-entries) "Insert formatted reference(s) associated with the KEYS-ENTRIES. @@ -860,10 +905,13 @@ With prefix, rebuild the cache before offering candidates." :rebuild-cache current-prefix-arg))) (citar--major-mode-function 'insert-keys - (lambda (&rest _) - (message "Key insertion is not supported for %s" major-mode)) + #'citar--insert-keys-comma-separated (citar--extract-keys keys-entries))) +(defun citar--insert-keys-comma-separated (keys) + "Insert comma separated KEYS." + (insert (string-join keys ", "))) + ;;;###autoload (defun citar-add-pdf-to-library (keys-entries) "Add PDF associated with the KEYS-ENTRIES to library. @@ -909,9 +957,10 @@ With prefix, rebuild the cache before offering candidates." (defun citar-dwim () "Run the default action on citation keys found at point." (interactive) - (if-let ((keys (cdr (citar-keys-at-point)))) + (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 keys))) + (citar-run-default-action (citar--stringify-keys keys)))) (provide 'citar) ;;; citar.el ends here