From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp2.migadu.com ([2001:41d0:403:58f0::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms13.migadu.com with LMTPS id OFc8B+hpWWdWVQAAe85BDQ:P1 (envelope-from ) for ; Wed, 11 Dec 2024 10:31:04 +0000 Received: from aspmx1.migadu.com ([2001:41d0:403:58f0::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp2.migadu.com with LMTPS id OFc8B+hpWWdWVQAAe85BDQ (envelope-from ) for ; Wed, 11 Dec 2024 11:31:04 +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=ctqk9E64; 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"; dmarc=fail reason="SPF not aligned (relaxed)" header.from=gmail.com (policy=none) ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1733913062; 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=DbnOHQ0yrVcrG2Qxvahtgh0xBa/GIKii57H1GrScBGQ=; b=ChLLN/uGwWa/8Ovoey52imUFIhLt9wgGpGh+JzARTMZ4m+Y/P435IMFpVzPelqi7w0TQul uzIebu/lz1egcHG1tv5EHFI19obOK/thjng6XYIdZTHP5grDjCjGFwzNOgYPgUed8iU98z k+/Ddct0tiU1b2c74Gl5YWb7RWzgG9jkOsCZoTLkg0oWYYaN5Obnb3V9aSAKAprm7XYRYH udrLSR5wlqeuzGBmlWF9Q3FlygpAsjLMnjyGM/NadgCFcsKEEwekLHRCocFvK6g5u2qAck OVjaOjmY9MQDwOrWqaM6OtqowMRjNeNtaqna0aIpE0l3dO62QJhty+EPMddjxA== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("body hash did not verify") header.d=gmail.com header.s=20230601 header.b=ctqk9E64; 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"; dmarc=fail reason="SPF not aligned (relaxed)" header.from=gmail.com (policy=none) ARC-Seal: i=1; s=key1; d=yhetil.org; t=1733913062; a=rsa-sha256; cv=none; b=jR7OGLFnBOtNRe0NUdv6MS7DpUtfjygu71drwAhcYJbmo+1JJwenawSn+8DCpFOiWPKpvv yCHECquxesQ1oJp+EB6K6qoHjJVwutZzTPz4c7brLpiI617HsaVVIjy8VhahZHL0UI6dZR vG8hUdZ6q0rJuxDCJngy77aKWp6llgE0k7npxmIZgPNtNI9swPvRbfUNCsu7gBZveSH+Og 0VSkAwrlcQM2dLC/w9CngvvX0/3+x6KOutlSkdV0PnMj+hfsjDs0GEfzwSRBnVDDA0NZEn O70attPNM+hsL24DCSJMRAjBYo8/gg1X/NDZ93DoFiipIWXc5TRm8FV+PcsMQA== 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 A440047262 for ; Wed, 11 Dec 2024 11:31:02 +0100 (CET) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tLJbB-0003Kr-M5; Wed, 11 Dec 2024 05:05:41 -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 1tLJb4-0003KG-RA for emacs-orgmode@gnu.org; Wed, 11 Dec 2024 05:05:37 -0500 Received: from mail-lj1-x22b.google.com ([2a00:1450:4864:20::22b]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1tLJb2-0006wG-Lv for emacs-orgmode@gnu.org; Wed, 11 Dec 2024 05:05:34 -0500 Received: by mail-lj1-x22b.google.com with SMTP id 38308e7fff4ca-30225b2586cso5050521fa.0 for ; Wed, 11 Dec 2024 02:05:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1733911530; x=1734516330; 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=j6VKJpMRC4woKZ1HsMV/axlcqWwWKU5Q1PtVoMuqYJo=; b=ctqk9E64LnqvVSe/z9/no1cxB11VJA23MlGnkiNpy8Y+AeuahJzzJq8LePklTopUfq eGaQKrl3kFXgEKUUIPLtKQlUGIMbAZqN0M5mKw+Z6B0dV1YJFDp+a5okj8JdaMKcchmB rTO+ff5e9ffeUXyADGJykONksVgpnSbwlCJ37t7ULu1LvxrAgWymF1N9AbWEVNcN54TX 5svbV3aGnOFst1sLwd0lXHv2b4FtcrTT+QeFYNRevD0Ps8Yxf4yirx+HGeAJcxBIw6om 7UBS1YK67soh1tt9Mjy75hhket8R62Iq03fLP9ipkd6/Yy00yDY3xKt1QobaF1kHA9ee d6qA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733911530; x=1734516330; 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=j6VKJpMRC4woKZ1HsMV/axlcqWwWKU5Q1PtVoMuqYJo=; b=w7KS94MA6Ot0LUS8QYwGEmbbA9Qrocjq34Vo+x54Re9hA4PtmDhvXy8Kt/UJ7qrRxZ g2WMnj3uL/wtjxL8ffhGVZ6vub/H1AanCFy2AZgiQEMk+FGv7RfKKU/OAnLCeEcW/tZH xMt3yK80AQA962YDAGXSl8HdaQiZA+Sv+QNg0vneUZfIsoMDukrjUcjnZc+im/QEeRXk lBWKbCLAtn3Mz09D7/i1AIiBuKtIo/g2vSuAiI1rPpx1mIIzDwH15/AxdtdaOlqmKW5x B0fdqXdhRLLYKqg+KMl/pGSsLaQpqrQ5iUdh7w5iWTidXPsbhSipa8LVNcSAghcAaf8i Ibbg== X-Gm-Message-State: AOJu0YwqaZ5LZMCWarkDG36TJCrOZ9utz0N/FDOpqJk0Rok7lkbIC1z8 TQHhnKsEnMg+zAW5tzuoBD97RUc6DR9ydYPgNWlm3sMp8n4Bwr1yQ9IzgQ== X-Gm-Gg: ASbGncuu8UwdcqmwdPy+i5ES+q0yGMCV0/dTsgv/apYY6xT3jrqjbis70J6judXd/3c dde0GHXdSL3La3Uu8hdkpv5WyhR7cAowo7lIbH9tZcYEClEFsJMOLYzzeQKlIg1CoBa1L8SUYXe Fxgm1F3tRe9NM8dWixlKAIKz8rRdbIdjivQ6fJS6HsacMU4q/uKpX6jphD2c0cuCQz3+tAdAI3M 0/t6x2ly6tKtSAWYpanQBQ/StT7Oa5Fmkq+vWtkh4RRGw== X-Google-Smtp-Source: AGHT+IG2/LolMHUufHCl2EUOyrPf+4W2wanPdQtb1C0Fvv371ksnL8Qzhtd0elry5Tk5eEuw+j9dNA== X-Received: by 2002:a05:651c:543:b0:2ff:df01:2b4c with SMTP id 38308e7fff4ca-30241c9fbf2mr5832481fa.4.1733911529245; Wed, 11 Dec 2024 02:05:29 -0800 (PST) Received: from barbar ([193.64.204.56]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-30222c45d84sm8547611fa.111.2024.12.11.02.05.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Dec 2024 02:05:28 -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: <87o71jwdxz.fsf@localhost> (Ihor Radchenko's message of "Tue, 10 Dec 2024 19:11:36 +0000") References: <8734m28l9a.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> <878qt7fbki.fsf@gmail.com> <87o71jwdxz.fsf@localhost> Date: Wed, 11 Dec 2024 12:05:23 +0200 Message-ID: <87wmg6edr0.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::22b; envelope-from=tclaesson@gmail.com; helo=mail-lj1-x22b.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-Spam: Yes X-Migadu-Spam: Yes X-Migadu-Spam-Score: 8.04 X-Spam-Score: 8.04 X-Migadu-Queue-Id: A440047262 X-Migadu-Scanner: mx11.migadu.com X-TUID: ps43XgOjS9WG --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable > Two comments here: > 1. It should not be a lambda. Better have a function or even command > 2. The logic is not right. You should better follow > `org-cite-basic--key-completion-table': > `org-cite-basic--parse-bibliography', `org-cite-basic--get-entry', > and `org-cite-basic--get-field'. And this time with a patch, apologies. /Tor-bj=C3=B6rn --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-lisp-oc-basic.el-Transient-menu-for-following-citati-ver5.patch Content-Description: Patch version 5 >From 7e9e0c64fbda2dcb67d8c8421d1c9923ca93e8b4 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--get-key): New function. Get citation key from citation or citation reference. (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 | 115 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 128 insertions(+), 9 deletions(-) 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..fc55d3a32 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,39 @@ :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 + (org-cite-basic--get-field + 'doi + (org-cite-basic--get-key !citation))))]] + "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 @@ -326,6 +361,16 @@ INFO is the export state, as a property list." (map-keys entries)) (org-cite-basic--parse-bibliography))) +(defun org-cite-basic--get-key (citation-or-citation-reference) + "Return citation key for CITATION." + (if (org-element-type-p citation-or-citation-reference 'citation-reference) + (org-element-property :key citation-or-citation-reference) + (pcase (org-cite-get-references citation-or-citation-reference t) + (`(,key) key) + (keys + (or (completing-read "Select citation key: " keys nil t) + (user-error "Aborted")))))) + (defun org-cite-basic--get-entry (key &optional info) "Return BibTeX entry for KEY, as an association list. When non-nil, INFO is the export state, as a property list." @@ -805,14 +850,7 @@ export state, as a property list." When DATUM is a citation reference, open bibliography entry referencing the citation key. Otherwise, select which key to follow among all keys present in the citation." - (let* ((key - (if (org-element-type-p datum 'citation-reference) - (org-element-property :key datum) - (pcase (org-cite-get-references datum t) - (`(,key) key) - (keys - (or (completing-read "Select citation key: " keys nil t) - (user-error "Aborted")))))) + (let* ((key (org-cite-basic--get-key datum)) (file (pcase (seq-find (pcase-lambda (`(,_ . ,entries)) (gethash key entries)) @@ -832,6 +870,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 +1017,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 --=-=-=--