From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp1.migadu.com ([2001:41d0:403:4876::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms13.migadu.com with LMTPS id UMd7HA+5RGe2KgEA62LTzQ:P1 (envelope-from ) for ; Mon, 25 Nov 2024 17:51:11 +0000 Received: from aspmx1.migadu.com ([2001:41d0:403:4876::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp1.migadu.com with LMTPS id UMd7HA+5RGe2KgEA62LTzQ (envelope-from ) for ; Mon, 25 Nov 2024 18:51:11 +0100 X-Envelope-To: larch@yhetil.org Authentication-Results: aspmx1.migadu.com; dkim=fail ("body hash did not verify") header.d=gmail.com header.s=20230601 header.b=GIFPmqQn; dmarc=fail reason="SPF not aligned (relaxed)" header.from=gmail.com (policy=none); spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org" ARC-Seal: i=1; s=key1; d=yhetil.org; t=1732557071; a=rsa-sha256; cv=none; b=SWDzWmoYpT4O4XX9jrS/ka+NcnZzmmaIrdRvfjuNOQEJab6iB58z6ZXjxtZhEjFl3VUB99 ifbz2EAkWWAJ1gVvBnlnFmjbjuOfT8c3ufFzbL9xXYSLkG1WOESJzbyVr9LP/eulCRug9C PwHLeJ9slx5mcjBWX+wAsnx3dPUbHRGYE+NNsLWw7nR++mhOTsEWNau9UvKWkCDtrDGFpk +TI4qtKkqMn4ZLWZ5McpK4zHBqDLO009WV/UzvrSKM3VBpqUAAsVXjEhaOtxAeWELjLkou +gWZcp5DWOJo+eBFdxu3fvhtu/NT3gwbzOT1/z9m2GAmqhdYnCtXqpRgEqO/Eg== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("body hash did not verify") header.d=gmail.com header.s=20230601 header.b=GIFPmqQn; dmarc=fail reason="SPF not aligned (relaxed)" header.from=gmail.com (policy=none); spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org" ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1732557071; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=lb2mXMCQ0AZFoIrQ5J3wqBdH1PTtqzaKMOsAAN1bUkY=; b=NJG+1p5gESORlXpeR7UIOmOPFj0nC99a8y+UuWF2GPQpOEYNq/hHgvv2pwfeEhMJxm7SMj xoavdt0resjfjaSZ6ZWB7oqa6jGJMjvivBc98oN40geWfaEK6H5kqRZub1vUC/eFCWjRPn Bu2ZDb/YdeFF0G2cyp24DlGuglanvFEqkW5r0ksgP+1cS3HfLwvdZ43cvH+wuEDXrvEofr YQxEHKTPdPcXyNKiUR/oY+jn0E8ys3iG/gWypMWKhuUwS95gJQ8YZo5m3nKQUPMlIr6d2s cv94aBIekRnR8bUSB4kcQUvg2JDe66bxoQCU+C5l2WhcBJJdk48vbebx4VP58g== Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id EBA8678014 for ; Mon, 25 Nov 2024 18:51:10 +0100 (CET) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tFdDX-0008K6-BJ; Mon, 25 Nov 2024 12:49:48 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tFdDT-0008DW-K8 for emacs-orgmode@gnu.org; Mon, 25 Nov 2024 12:49:44 -0500 Received: from mail-lf1-x12e.google.com ([2a00:1450:4864:20::12e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1tFdDQ-0001NA-EP for emacs-orgmode@gnu.org; Mon, 25 Nov 2024 12:49:42 -0500 Received: by mail-lf1-x12e.google.com with SMTP id 2adb3069b0e04-53dde9acbb1so2060703e87.2 for ; Mon, 25 Nov 2024 09:49:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1732556977; x=1733161777; darn=gnu.org; h=mime-version:user-agent:message-id:date:references:in-reply-to :subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=WEFRsyrc+xJ3+zki9JCuUuA0lxEF9hcT0eY2j5DN/IA=; b=GIFPmqQnxkx+75kQan+l7PhKAsJLhBuy9uuy3Gzh5c58WRIVxkpH6D9S2SXnvApV4V SlPEM39icswVBxJFYIEztD0UQJ6OMXIlHsPGFI6QnJ5uE6hKlB1IJIUIViYwmT4/MAAl Y2cAzp+n1xTN7ftpCmGcbH+z+qP+2HuTsiEDaG0Mag5AWfWE/afMScTPXz+ZgJM7Fq2j C1xjWlwanjgAr8gMJx9fxID65jEY6RgzVggcg9OX+FMdJr+B26RX9LHA2cnsuemOq15B UqCBhhRFL0rb8arnPuAWy+udybXhBsgeM7OnBryM4HQX9BRjWnb0ERFvRmXcuxUD+edy rOkw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1732556977; x=1733161777; h=mime-version:user-agent:message-id:date:references:in-reply-to :subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=WEFRsyrc+xJ3+zki9JCuUuA0lxEF9hcT0eY2j5DN/IA=; b=TtHzm5W8O7jgsOwzC4zkbbn2IR++fnYoJIAU0grqWkfst0psDNHoznJDSFDJ/qMNlY dfqI4rpJdeHS/FtVNymP4snXP8E7xZ+CHQXd3/xxcpjDlgUT/rDScyL3Zp/7Be3P5h1z 2GAnd9TkALJ1hRuJpHg5fDX8fpHlDi5l+D3qz3iHSrGuu2Lca1ics+qPYFRZyHZIdLCj Vdf/ffQUI6RWK98mxbzl2YC1PydveU21JuEXJITiy4uOEpvdPggD+uoe+Ih7Pwtw+W3F eyCpjU1lqtTVswYCf4s5H5GP22CbGzu2CsOKD3fscYrBYIdEXtPLB0YoprwdO6GvqKVV vXXA== X-Gm-Message-State: AOJu0Yw9le6H0nAQP0c/xxGaRj1ThlGRbeNUMOIOTHWVjy3SW4kLtbG0 9fLUJ2epvKz0Shr1/Z1G4+Gz3PExoBsmLw/vuxyemdlvjIECBO7GEr8RsfUh X-Gm-Gg: ASbGncvLflaiIZY0zxnUAPhVR8SLgr5mc2Rwg4GSuKfu3BRwPLpEHOdhigR5KjnC0cb a7y8d6MnVHqvAUSUX0M/2lsDnCfS91Se1CuJkeGReqsPWhxZApvxJKnc3L9Otpcdw2bOd7sl0cP FwP3PHabYyS65Db6nr4hM4vKM82UabXst2qCSiTaq3s2QCR4XOdPFjon5Vy/YSzWzi72F+qk9Wt wl2KRjpWmdCwHJBMIVWbIex8kf1DBlBGN85hzb+pQ== X-Google-Smtp-Source: AGHT+IGF6t3A8LMSkpqP4oTT6n7dXufngGDjtlCxTr5w9pns9sSCd7ywVkEo2Ja2h8QcXLbzt4QsFQ== X-Received: by 2002:a19:2d44:0:b0:53d:d405:14a5 with SMTP id 2adb3069b0e04-53dd40514b7mr4578012e87.11.1732556976565; Mon, 25 Nov 2024 09:49:36 -0800 (PST) Received: from barbar ([193.64.204.56]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-53dd892b30fsm1494495e87.177.2024.11.25.09.49.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 25 Nov 2024 09:49:35 -0800 (PST) From: =?utf-8?Q?Tor-bj=C3=B6rn_Claesson?= To: Ihor Radchenko Cc: emacs-orgmode@gnu.org Subject: Re: Fwd: Org-cite: Replace basic follow-processor with transient menu? In-Reply-To: <87v7wd9a2h.fsf@localhost> (Ihor Radchenko's message of "Sat, 23 Nov 2024 16:41:42 +0000") References: <8734m28l9a.fsf@gmail.com> <87jzdo2e4m.fsf@gmail.com> <87a5eievav.fsf@localhost> <87wmhlmp83.fsf@gmail.com> <871pzte929.fsf@localhost> <87v7x548ri.fsf@gmail.com> <87y120daue.fsf@localhost> <874j4m9ep6.fsf@gmail.com> <87h68gfqj1.fsf@localhost> <87pln3f3cc.fsf@localhost> <87jzd9ojj0.fsf@localhost> <87cyj0ajm9.fsf@gmail.com> <87zfm4s50x.fsf@localhost> <87wmh8s358.fsf@localhost> <87y11nwp9z.fsf@gmail.com> <87v7wd9a2h.fsf@localhost> Date: Mon, 25 Nov 2024 19:49:33 +0200 Message-ID: <878qt7fbki.fsf@gmail.com> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Received-SPF: pass client-ip=2a00:1450:4864:20::12e; envelope-from=tclaesson@gmail.com; helo=mail-lf1-x12e.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-orgmode@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+larch=yhetil.org@gnu.org Sender: emacs-orgmode-bounces+larch=yhetil.org@gnu.org X-Migadu-Country: US X-Migadu-Flow: FLOW_IN X-Migadu-Spam-Score: 3.91 X-Spam-Score: 3.91 X-Migadu-Queue-Id: EBA8678014 X-Migadu-Scanner: mx10.migadu.com X-TUID: SIsKNTyryAxp --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Thank you for taking the time to look at this! Ihor Radchenko writes: >> +(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 pos= sible=20 >> +to specify a function call for the COMMAND part, where !citation and=20 >> +!prefix can be used to access those values." >> + :group 'org-cite >> + :package-version '(Org . "9.8") >> + :type 'sexp) > > 1. Ideally, we want at least one more menu entry here. Otherwise, the > menu is not very useful. > 2. It would be nice to provide some examples on using !citation and > !prefix in the docstring. Also, lambdas. > 3. We need to explain what !citation and !prefix refer to. 1. The infrastructure is very useful in itself, but I have added an option to add the DOI to the kill ring, it seems innocent enough. I had first thought that I would like to, as a next step, add a helper function to try really hard to get a citation key from a citation, but lets go with this. 2 and 3. I tried to describe this in the new version of the patch. >> +(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)) >> + (let ((!citation (car (transient-scope))) >> + (!prefix (cadr (transient-scope)))) > > This can be improved a bit. > Rather than storing transient scope as (list citation prefix), we can > use plist: (list :citation citation :prefix prefix). Then, we can do > (let ((!citation (plist-get (transient-scope) :citation)) > (!prefix (plist-get (transient-scope) :prefix))) ...) > > It will be more readable. Neat! Thanks! Please find attached version 4 of the patch. Cheers, Tor-bj=C3=B6rn --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-lisp-oc-basic.el-Transient-menu-for-following-citati-ver4.patch Content-Description: oc-basic transient follower version 4 >From c66af1e878f90e7b2cd89a613fc72da177cc6529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor-bj=C3=B6rn=20Claesson?= 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. (require 'org-element): Pull in org-element. (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 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 | 100 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index de4f11b25..bacc38be2 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. +*** New transient menu when following 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 -4 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 -4 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..c42f95489 100644 --- a/lisp/oc-basic.el +++ b/lisp/oc-basic.el @@ -74,6 +74,8 @@ (require 'map) (require 'oc) (require 'seq) +(require 'transient) +(require 'org-element) (declare-function org-open-at-point "org" (&optional arg)) (declare-function org-open-file "org" (path &optional in-emacs line search)) @@ -140,6 +142,43 @@ :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))] + ["Copy" + ("d" "DOI" + (kill-new + (save-excursion + (with-temp-buffer + (mapc #'insert-file-contents org-cite-global-bibliography) + (bibtex-set-dialect (parsebib-find-bibtex-dialect) t) + (bibtex-search-entry (org-element-property :key !citation)) + (setq doi (bibtex-autokey-get-field "doi")) + (replace-regexp-in-string "^http://dx.doi.org/" "" doi)))))]] + "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 (the citation +object to be followed) and !prefix (any prefix argument to the follower) can be +used to access those values. For example: +(org-cite-basic-goto !citation !prefix) or +(lambda () (message (org-element-property :key !citation)))" + :group 'org-cite + :package-version '(Org . "9.8") + :type 'sexp) + ;;; Internal variables (defvar org-cite-basic--bibliography-cache nil @@ -832,6 +871,65 @@ present in the citation." (bibtex-set-dialect) (bibtex-search-entry key))))) +(transient-define-prefix org-cite-basic-follow (citation-object &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 -4 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 + (list (let ((obj (org-element-context))) + (pcase (org-element-type obj) + ((or 'citation 'citation-reference) obj) + (_ (user-error "No citation at point")))))) + (if (xor org-cite-basic-follow-ask + (equal prefix '(-4))) + (transient-setup 'org-cite-basic-follow nil nil + :scope (list :citation citation-object :prefix prefix)) + (org-cite-basic-goto citation-object prefix))) + +(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)) + (let ((!citation (plist-get (transient-scope) :citation)) + (!prefix (plist-get (transient-scope) :prefix))) + ,@fn-args)) + ,@other)) + (`(,key ,desc (,fn . ,fn-args) . ,other) + `(,key ,desc + (lambda () + (interactive) + (let ((!citation (plist-get (transient-scope) :citation)) + (!prefix (plist-get (transient-scope) :prefix))) + (,fn ,@fn-args))) + ,@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 +1018,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 --=-=-=--