From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp0 ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms11 with LMTPS id fcSlCU8oWV/5YgAA0tVLHw (envelope-from ) for ; Wed, 09 Sep 2020 19:09:03 +0000 Received: from aspmx1.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp0 with LMTPS id 2IAaBU8oWV+DXgAA1q6Kng (envelope-from ) for ; Wed, 09 Sep 2020 19:09:03 +0000 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 BF25F9401D0 for ; Wed, 9 Sep 2020 19:09:02 +0000 (UTC) Received: from localhost ([::1]:44964 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kG5Sn-0007Ru-Og for larch@yhetil.org; Wed, 09 Sep 2020 15:09:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:34554) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kG5QJ-0003i3-Ml for emacs-orgmode@gnu.org; Wed, 09 Sep 2020 15:06:27 -0400 Received: from mail-pg1-x52b.google.com ([2607:f8b0:4864:20::52b]:40508) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1kG5QG-0002OQ-6c; Wed, 09 Sep 2020 15:06:27 -0400 Received: by mail-pg1-x52b.google.com with SMTP id j34so2757034pgi.7; Wed, 09 Sep 2020 12:06:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:cc:subject:in-reply-to:references:date:message-id :mime-version; bh=fnszWnrX7ohrWiIk5LrhSgcs1LwdLdZ9jNSMeL0GvMU=; b=ScqtZT2XyB6FCLvk2XCCHB01c1UrodYqtJEbe496gc6IPFugAbCJL6sKC/7yP2mATA k/04uuRoabV1Jc7nOpy68MWb2wrnqNu19dt5C9Ru7YF4bCGmmi46QUvZMu2k2YGt/sf2 TnrZKozsYxtbtHpObR1CNEbH6LoUuQMkBk2UEsebylGr/YiVpdZRC3yl0A070P1A2v37 VwXnh/RBjBmp7MXu6eC6YXPoM864hXE7pb8F1TO+rEo3QoEWIT29kViOWUKLxNueYTlN Bh1QGj8BkKi/ennBFLMATwYxsOpXp7Q8YM2cLx/rqS5Qi5SSU7tTH0PFE5gA7SaPYzCJ bJ3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:cc:subject:in-reply-to:references :date:message-id:mime-version; bh=fnszWnrX7ohrWiIk5LrhSgcs1LwdLdZ9jNSMeL0GvMU=; b=gvZao0zNfxp9RJxtMjXd4CSaqvde9x8YOYkRxt0KWAXisFp83SFSVIDY9zMAn7qq30 0bxkiuluXkQPkgE5JXfBOOiidAnpqdtQj54rwelhMaKaLyjIp8/HCeGP/MbpmkZLjoJ1 htjvqGBOxuvNsaEDpIvCsWwz99YAyqsemzGZ4kZr34lOYBB79dfDogZXiw1eliAiWPQ/ FGyCqEDPFvJlUGJITicAxzfVubn0T57ue1GMy+ojPgFnGes+uDtXi/nJ98jfy/fi0O1B DQK17dN5aJsfG1uJaVLM1dZNPV5wQykueFzOA55Xdi1W5bwZMa602HfT6MTiWVBj3sn+ 44Ew== X-Gm-Message-State: AOAM531r+Ap81n4dVmwC4U2pWfwJUJIDIX09qFw5WRC3h0qhHMBPdvtT 0pGD7Ad0IjR0PIjcbm8addVQWW8WO1Z0Lw== X-Google-Smtp-Source: ABdhPJwda2kZXtpCd7ysW+HAwFOff/ad8Rf9bllTm1LdKXDhFubW60nRbjZ17eBz1ZTUrB53EguBWg== X-Received: by 2002:a63:5943:: with SMTP id j3mr48019pgm.392.1599678380713; Wed, 09 Sep 2020 12:06:20 -0700 (PDT) Received: from ryzen3950 (c-73-71-89-135.hsd1.ca.comcast.net. [73.71.89.135]) by smtp.gmail.com with ESMTPSA id w192sm3564950pfd.156.2020.09.09.12.06.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 09 Sep 2020 12:06:19 -0700 (PDT) From: Matt Huszagh To: Tom Gillespie , Bastien Subject: Re: babel default header args as functions In-Reply-To: References: <87ftflikkc.fsf@gmail.com> <871rjqprdu.fsf@gmail.com> <875z8wxis3.fsf@gmail.com> <87k0x8dy3s.fsf@gnu.org> Date: Wed, 09 Sep 2020 12:06:12 -0700 Message-ID: <87y2lizs63.fsf@gmail.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Received-SPF: pass client-ip=2607:f8b0:4864:20::52b; envelope-from=huszaghmatt@gmail.com; helo=mail-pg1-x52b.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. 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.23 Precedence: list List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: , "emacs-orgmode@gnu.org" Errors-To: emacs-orgmode-bounces+larch=yhetil.org@gnu.org Sender: "Emacs-orgmode" X-Scanner: scn0 Authentication-Results: aspmx1.migadu.com; dkim=fail (rsa verify failed) header.d=gmail.com header.s=20161025 header.b=ScqtZT2X; dmarc=fail reason="SPF not aligned (relaxed)" header.from=gmail.com (policy=none); spf=pass (aspmx1.migadu.com: domain of emacs-orgmode-bounces@gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=emacs-orgmode-bounces@gnu.org X-Spam-Score: 0.09 X-TUID: FXLEYTtTNAvY --=-=-= Content-Type: text/plain Tom Gillespie writes: > [...] I have a number of use > cases that I can imagine would benefit greatly from being able to > define a :header-args: :header (lambda () "yay!") property as a > closure (and actually I assumed that it would just work that way if I > tried to do it, clearly not though). I can't tell for sure if the > patch enables this behavior though or whether I would still get a > Wrong type argument error. This should work. Do you have reason for believing it might not? For example, set: (setq org-babel-default-header-args:bash `((:var . (lambda () "a='yay'")))) Then in file.org: #+begin_src bash :results output echo $a #+end_src Executing this will yield: #+RESULTS: : yay > [...] Looking > at the patch it seems that it preserves the behavior of performing the > evaluation of the closures at the source block, but I'm not 100% sure. I'm not sure I completely understand what you mean here. However, the closures are evaluated when point is at the source block, during the source block evaluation, not when the default headers are declared. This allows the closures to use context-dependent functionality (e.g. you can call `org-element-at-point' inside the closure and retrieve whatever information you want). Does this address your concern? Please clarify if I've missed your point. > If the default header closures are being evaluated before checking > whether they have been superseded by the headers on a block then that > is incorrect and they should not be evaluated until it is clear that > they are the value of the header for that block and have not been > superseded. I've fixed my patch (attached) so that now closures are only evaluated when they are used as part of the final set of headers. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-ob-core.el-Add-ability-to-use-closures-as-default-he.patch >From 4a461a90ec4f3c5f9634b687a6685ea3ba74f168 Mon Sep 17 00:00:00 2001 From: Matt Huszagh Date: Fri, 28 Aug 2020 11:05:59 -0700 Subject: [PATCH] ob-core.el: Add ability to use closures as default header arguments * lisp/ob-core.el (org-babel-default-header-args): Document ability to use closures. (org-babel-eval-headers): New function to generate header arguments, which adds the ability to evaluate closures during source block execution or export. (org-babel-merge-params): Only evaluate closures when we have our final list of headers. --- lisp/ob-core.el | 60 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/lisp/ob-core.el b/lisp/ob-core.el index 578622232..bef34d7c0 100644 --- a/lisp/ob-core.el +++ b/lisp/ob-core.el @@ -473,7 +473,35 @@ For the format of SAFE-LIST, see `org-babel-safe-header-args'." (defvar org-babel-default-header-args '((:session . "none") (:results . "replace") (:exports . "code") (:cache . "no") (:noweb . "no") (:hlines . "no") (:tangle . "no")) - "Default arguments to use when evaluating a source block.") + "Default arguments to use when evaluating a source block. + +This is a list in which each element is an alist. Each key +corresponds to a header argument, and each value to that header's +value. The value can either be a string or a closure that +evaluates to a string. The closure is evaluated when the source +block is being evaluated (e.g. during execution or export), with +point at the source block. It is not possible to use an +arbitrary function symbol (e.g. 'some-func), since org uses +lexical binding. To achieve the same functionality, call the +function within a closure (e.g. (lambda () (some-func))). + +To understand how closures can be used as default header +arguments, imagine you'd like to set the file name output of a +latex source block to a sha1 of its contents. We could achieve +this with: + +(defun org-src-sha () + (let ((elem (org-element-at-point))) + (concat (sha1 (org-element-property :value elem)) \".svg\"))) + +(setq org-babel-default-header-args:latex + `((:results . \"file link replace\") + (:file . (lambda () (org-src-sha))))) + +Because the closure is evaluated with point at the source block, +the call to `org-element-at-point' above will always retrieve +information about the current source block.") + (put 'org-babel-default-header-args 'safe-local-variable (org-babel-header-args-safe-fn org-babel-safe-header-args)) @@ -584,6 +612,19 @@ the outer-most code block.") (defvar *this*) +(defun org-babel-eval-headers (headers) + "Compute header list set with HEADERS. + +Evaluate all header arguments set to functions prior to returning +the list of header arguments." + (let ((lst nil)) + (dolist (elem headers) + (if (and (cdr elem) + (functionp (cdr elem))) + (push `(,(car elem) . ,(funcall (cdr elem))) lst) + (push elem lst))) + lst)) + (defun org-babel-get-src-block-info (&optional light datum) "Extract information from a source block or inline source block. @@ -2704,12 +2745,21 @@ parameters when merging lists." results-exclusive-groups results (split-string - (if (stringp value) value (eval value t)))))) + (if (stringp value) + value + (if (functionp value) + (funcall value) + (eval value t))))))) (`(:exports . ,value) (setq exports (funcall merge exports-exclusive-groups exports - (split-string (or value ""))))) + (split-string (or + (if value + (if (functionp value) + (funcall value) + value) + "")))))) ;; Regular keywords: any value overwrites the previous one. (_ (setq params (cons pair (assq-delete-all (car pair) params))))))) ;; Handle `:var' and clear out colnames and rownames for replaced @@ -2724,14 +2774,14 @@ parameters when merging lists." (cdr (assq param params)))) (setq params (cl-remove-if (lambda (pair) (and (equal (car pair) param) - (null (cdr pair)))) + (null (cdr pair)))) params))))) ;; Handle other special keywords, which accept multiple values. (setq params (nconc (list (cons :results (mapconcat #'identity results " ")) (cons :exports (mapconcat #'identity exports " "))) params)) ;; Return merged params. - params)) + (org-babel-eval-headers params))) (defun org-babel-noweb-p (params context) "Check if PARAMS require expansion in CONTEXT. -- 2.28.0 --=-=-=--