Ihor Radchenko <[email protected]> writes:
> See my comments below.
Thanks for taking the time to look at this!
>> +*** Menu for choosing how to follow citations
>> +If invoked with a prefix of C-- C-u, following citations with
>> +the org-cite-basic citation backend will no present a transient menu,
>> +offering choices for how to follow citations.
>
> I imagine C-- C-u more as a toggle - if `org-cite-basic-follow-ask' is
> t, it disables the menu; enables otherwise.
That is more useful, thanks!
>
>> +(defcustom org-cite-basic-follow-ask nil
>> + "Should `org-cite-basic' ask how to follow citations?
>> +
>> +When this option is nil, `org-cite-basic-follow' opens the bibliography
>> entry.
>> +Otherwise, `org-cite-basic-follow' will display a transient menu prompting
>> the
>> +user for an action. The contents of this menu can be customized in
>> +`org-cite-basic-follow-actions'."
>
> Note: our convention is to use double space between sentences.
> There are also typos, but that's a minor thing I can fix myself before
> merging.
Ah, bummer. I have fixed (at least some) of those typos.
>> +(defcustom org-cite-basic-follow-actions
>> + '[["Open"
>> + ("b" "bibliography entry" (org-cite-basic-goto !citation !prefix))]]
>> + "Actions in the `org-cite-basic-follow' transient menu.
>> +
>> +This option uses the same syntax as `transient-define-prefix', see Info node
>> +`(transient)Binding Suffix and Infix Commands'. In addition, it is possible
>> +to specify a function call for the COMMAND part, where !citation,
>> +!prefix, and !citation-key can be used to access those values.
>> +
>> +If COMMAND is a lambda form, it can access the citation and prefix like
>> this:
>> +
>> + (lambda (citation prefix)
>> + (interactive (transient-scope))
>> + ...)"
>
> Could we make !prefix, and !citation work in lambdas? We should be able
> to.
Sure! It took me some trial and error to get the list splicing right but
now it works in lambdas to. I added another helper to do let binding.
>> +(transient-define-prefix org-cite-basic-follow (citation &optional prefix)
>> + "Follow citation.
>> +
>> +This transient is invoked through `org-open-at-point'.
>> +When `org-open-at-point' is invoked
>
> It should not matter for this command where it is called from.
> You can simply drop references to `org-open-at-point'
>
> We can even make the prefix work as a standalone command. Simply using
> interactive spec.
>
> (interactive
> (list (let ((obj (org-element-context)))
> (pcase (org-element-type obj)
> ((or citation citation-reference) obj)
> (_ (user-error "No citation at point"))))))
I was not able to get this to work.
>> ... with a negative prefix, +or `org-cite-basic-follow-ask' is
>> non-nil, it will present +a transient menu prompting the user for an
>> action. Otherwise, +it will open the bibliography entry for the
>> citation at point.
>
>> +Suffixes can not be added to this transient menu using the ordinary
>> +`transient-append-suffix' or `transient-insert-suffix', instead, the
>> +contents of the menu are defined in the variable
>> +`org-cite-basic-follow-actions'."
>
> Suffixes can be added. Try
>
> (transient-append-suffix 'org-cite-basic-follow nil
> '[["Other" ("t" "test" (lambda () (interactive) (message "Hello!")))]])
Ah, I didn't know you could nil the position.
>> +(defun org-cite-basic-follow--parse-suffix-specification (specification)
>> + (pcase specification
>
> Please, add the docstring.
>
Ok.
>> + ((and val `(,key ,desc (,fn . ,fn-args) . ,other))
>> + (if (eq fn 'lambda) val
>> + `(,key ,desc
>> + (lambda ()
>> + (interactive)
>> + (let ((!citation (car (transient-scope)))
>> + (!prefix (cadr (transient-scope)))
>> + (!citation-key
>> + (org-element-property :key (car (transient-scope)))))
>
> `org-open-at-point' may be called with point at citation rather than
> citation reference. Citation object does not have :key property.
>
> I think that we should drop !citation-key spec and instead specify that
> the command may be called with citation or citation-reference object in
> !citation.
`org-cite-basic-goto' handles this by prompting the user for a key, if
it is called with a citation object. I adopted this approach. (I find the
!citation-key useful for a lot of things I like to do to citations, and
would like to keep it.)
>> +(defun org-cite-basic-follow--setup (_)
>> + (transient-parse-suffixes
>
> Docstring here as well.
Ok.
Version 2 of the patch is attached.
Cheers,
Tor-björn
>From e91fff9f6c03e2c766dee410f46382398f883997 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tor-bj=C3=B6rn=20Claesson?= <[email protected]>
Date: Tue, 12 Nov 2024 11:09:16 +0200
Subject: [PATCH] lisp/oc-basic.el: Transient menu for following citations
* lisp/oc-basic.el (require 'transient): Pull in transient.
(org-cite-basic-follow-ask): New customization option. should
`org-cite-basic-follow' prompt the user for an action?
(org-cite-basic-follow-actions): New customization option, that
specifies the contents of the transient menu.
(org-cite-basic-follow): New function. Displays a menu asking how to
follow a citation if `org-cite-basic-follow-ask' is
non-nil. Otherwise, it retains the default behaviour of opening the
bibliography entry. This can be inversed with a negative prefix argument.
(org-cite-basic-follow--parse-suffix-specification,
org-cite-basic-follow--wrap-function, and
org-cite-basic-follow--setup): Helper functions for
`org-cite-basic-follow'.
(org-cite-register-processor 'basic): Update the basic citation
processor to follow citations using `org-cite-basic-follow'.
* etc/ORG_NEWS (Menu for choosing how to follow citations): Describe
the new feature
(New option ~org-cite-basic-follow-ask~): Describe this new
customization option.
(New option ~org-cite-basic-follow-actions~): Describe this new
customization option, which specifies the layout of the
`org-cite-basic-follow' transient menu.
This change was co-authored with much support from Ihor Radchenko and
Jonas Bernoulli, thanks!
---
etc/ORG-NEWS | 22 +++++++++++
lisp/oc-basic.el | 95 +++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 116 insertions(+), 1 deletion(-)
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index de4f11b25..b859b0ada 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -114,6 +114,15 @@ The keybindings in the repeat-maps can be changed by customizing
See the new [[info:org#Repeating commands]["Repeating commands"]] section in Org mode manual.
+*** Menu for choosing how to follow citations
+
+Following citations with the org-cite-basic citation backend can now present a
+transient menu. To show this menu, set ~org-cite-basic-follow-ask~ to non-nil.
+This behaviour can be reversed with a negativ prefix.
+
+The contents of this menu can be customized in
+~org-cite-basic-follow-actions~.
+
** New and changed options
# Chanes deadling with changing default values of customizations,
@@ -158,6 +167,19 @@ English. The default value is ~t~ as the CSL standard assumes that
English titles are specified in sentence-case but the bibtex
bibliography format requires them to be written in title-case.
+*** New option ~org-cite-basic-follow-ask~
+
+When this option is non-nil, following a citation with the basic citation
+backend will present a transient menu with choices for how to follow the
+citation.
+If nil, following a citation will open its bibliography entry.
+
+This behaviour can be reversed with a negative prefix argument.
+
+*** New option ~org-cite-basic-follow-actions~
+
+This option specifies the options presented by ~org-cite-basic-follow~.
+
** New functions and changes in function arguments
# This also includes changes in function behavior from Elisp perspective.
diff --git a/lisp/oc-basic.el b/lisp/oc-basic.el
index e207a1997..c3fc3f34d 100644
--- a/lisp/oc-basic.el
+++ b/lisp/oc-basic.el
@@ -74,6 +74,7 @@
(require 'map)
(require 'oc)
(require 'seq)
+(require 'transient)
(declare-function org-open-at-point "org" (&optional arg))
(declare-function org-open-file "org" (path &optional in-emacs line search))
@@ -140,6 +141,30 @@
:type 'face
:safe #'facep)
+(defcustom org-cite-basic-follow-ask nil
+ "Should `org-cite-basic' ask how to follow citations?
+
+When this option is nil, `org-cite-basic-follow' opens the bibliography entry.
+Otherwise, `org-cite-basic-follow' will display a transient menu prompting the
+user for an action. The contents of this menu can be customized in
+`org-cite-basic-follow-actions'."
+ :group 'org-cite
+ :package-version '(Org . "9.8")
+ :type 'boolean)
+
+(defcustom org-cite-basic-follow-actions
+ '[["Open"
+ ("b" "bibliography entry" (org-cite-basic-goto !citation !prefix))]]
+ "Actions in the `org-cite-basic-follow' transient menu.
+
+This option uses the same syntax as `transient-define-prefix', see Info node
+`(transient)Binding Suffix and Infix Commands'. In addition, it is possible
+to specify a function call for the COMMAND part, where !citation,
+!prefix, and !citation-key can be used to access those values."
+ :group 'org-cite
+ :package-version '(Org . "9.8")
+ :type 'sexp)
+
;;; Internal variables
(defvar org-cite-basic--bibliography-cache nil
@@ -832,6 +857,74 @@ present in the citation."
(bibtex-set-dialect)
(bibtex-search-entry key)))))
+(transient-define-prefix org-cite-basic-follow (citation &optional prefix)
+ "Follow citation.
+
+If `org-cite-basic-follow-ask' is non-nil, this transient will present
+a menu prompting the user for an action.
+Otherwise, it will open the bibliography entry for the citation at point.
+This behaviour is inverted when the transient is called with a negative prefix
+argument.
+
+The contents of the menu are defined in the variable
+`org-cite-basic-follow-actions'."
+ [:class transient-columns
+ :setup-children org-cite-basic-follow--setup
+ :pad-keys t]
+ (interactive)
+ (if (xor org-cite-basic-follow-ask
+ (equal prefix '(-4)))
+ (transient-setup 'org-cite-basic-follow nil nil
+ :scope (list citation prefix))
+ (org-cite-basic-goto citation prefix)))
+
+(defun org-cite-basic-follow--wrap-function (fn-args &optional fn)
+ "Provide !citation, !prefix, and !citation-key symbols."
+ (append
+ `(let ((!citation (car (transient-scope)))
+ (!prefix (cadr (transient-scope)))
+ (!citation-key
+ (if (org-element-type-p (car (transient-scope)) 'citation-reference)
+ (org-element-property :key (car (transient-scope)))
+ (pcase (org-cite-get-references (car (transient-scope)) t)
+ (`(,key) key)
+ (keys
+ (or (completing-read "Select citation key: " keys nil t)
+ (user-error "Aborted"))))))))
+ (if fn
+ `((,fn ,@fn-args))
+ fn-args)))
+
+(defun org-cite-basic-follow--parse-suffix-specification (specification)
+ "Handle special syntax for `org-cite-basic-follow-actions'."
+ (pcase specification
+ (`(,key ,desc (lambda ,args . ,fn-args) . ,other)
+ `(,key ,desc
+ (lambda ,args
+ ,(unless (and (listp (car fn-args))
+ (equal (caar fn-args)
+ 'interactive))
+ '(interactive))
+ ,(org-cite-basic-follow--wrap-function fn-args))
+ ,@other))
+ (`(,key ,desc (,fn . ,fn-args) . ,other)
+ `(,key ,desc
+ (lambda ()
+ (interactive)
+ ,(org-cite-basic-follow--wrap-function fn-args fn))
+ ,@other))
+ (other other)))
+
+(defun org-cite-basic-follow--setup (_)
+ "Update `org-cite-basic-follow' when `org-cite-basic-follow-actions' changes."
+ (transient-parse-suffixes
+ 'org-cite-basic-follow
+ (cl-map 'vector
+ (lambda (group)
+ (cl-map 'vector #'org-cite-basic-follow--parse-suffix-specification
+ group))
+ org-cite-basic-follow-actions)))
+
;;; "Insert" capability
(defun org-cite-basic--complete-style (_)
@@ -920,7 +1013,7 @@ Raise an error when no bibliography is set in the buffer."
:activate #'org-cite-basic-activate
:export-citation #'org-cite-basic-export-citation
:export-bibliography #'org-cite-basic-export-bibliography
- :follow #'org-cite-basic-goto
+ :follow #'org-cite-basic-follow
:insert (org-cite-make-insert-processor #'org-cite-basic--complete-key
#'org-cite-basic--complete-style)
:cite-styles
--
2.46.0