From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp12.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms9.migadu.com with LMTPS id +JXvLBX/CWT+KAEASxT56A (envelope-from ) for ; Thu, 09 Mar 2023 16:45:25 +0100 Received: from aspmx1.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp12.migadu.com with LMTPS id SK7NLBX/CWQVNAAAauVa8A (envelope-from ) for ; Thu, 09 Mar 2023 16:45:25 +0100 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 24F5529A7D for ; Thu, 9 Mar 2023 16:45:25 +0100 (CET) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1paIRh-0005qO-9M; Thu, 09 Mar 2023 10:44:45 -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 1paIRe-0005oJ-DW for emacs-orgmode@gnu.org; Thu, 09 Mar 2023 10:44:42 -0500 Received: from mout-p-101.mailbox.org ([2001:67c:2050:0:465::101]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_CHACHA20_POLY1305:256) (Exim 4.90_1) (envelope-from ) id 1paIRa-0002LX-VO for emacs-orgmode@gnu.org; Thu, 09 Mar 2023 10:44:41 -0500 Received: from smtp1.mailbox.org (smtp1.mailbox.org [10.196.197.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-101.mailbox.org (Postfix) with ESMTPS id 4PXYQS2fCBz9smN for ; Thu, 9 Mar 2023 16:44:32 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kraus.my; s=MBO0001; t=1678376672; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type; bh=DxzHacK9i7aOdL5xXDkP2VFovsDRK9nnRGb6NNKCcv8=; b=DuLsn2M+pTtvPVCV3A/F7kixx5+wXFTd1KQrV/3JKNlJDcNLxiE6MGF+JJ5drDSaqS1gHn z8C+1MzBzs8dpbuiSxDVbCUAgWvRZGWhIT8jNaeMeHUP7G7NcXuYcJj1pnrmCXvXZ6F2sK LXZnXmm28XACqUp9scXU5dYT3L6Kf2T7rg8tES6HXcAChadH/EswqjpLgartgc6cx0xWus 6XJUWxpg95Bcvi52Ihu6t8DzWCjgumd/2cFTjVJDh6KF7jzjbw6kinKX0LGpTJXdpLk9fU 9T+X9KlJFN67l32iysfu21Weoq5eedmqZjD02Gx7Ey3wOKK7ng6ut9tnMWWjlQ== From: Daniel Kraus To: emacs-orgmode@gnu.org Subject: [patch] ob-clojure: Fix results output Date: Thu, 09 Mar 2023 16:40:04 +0100 Message-ID: <87mt4m53qj.fsf@kraus.my> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Received-SPF: none client-ip=2001:67c:2050:0:465::101; envelope-from=daniel@kraus.my; helo=mout-p-101.mailbox.org X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 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, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_NONE=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 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1678376725; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=DxzHacK9i7aOdL5xXDkP2VFovsDRK9nnRGb6NNKCcv8=; b=OoYcfDMT3sdX8e6+8j01FQjquRwg/+meDGIHFRju8EfKMxEzqVmjGeoLOM+fglVdDY16xo FU1ETxUcEvjWdpZIFpsOmiXK7JOX0klzbWiyVUzJaQJrxOdAJGdHSmWQkkCSeRm0AKwiai 3efD/BeS2Xgei2mKA3sAWQMJL0/cfJAv+zegRbNZj/RanLqRkCyH+xnK2jK8WVSJHR/bS0 PNN3pmu6k0Ix2TPZSSwxor+DTSVlb6CeBq4WKWSxIR6HjfCRc7XASNMtH+AV6qT9MZQ+WA 1t9nGFUJfk/h/Qr/CcgBFLCdNcl23EbpcZANoCdGbooe4dDgiE9YbQdojX8RmA== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=pass header.d=kraus.my header.s=MBO0001 header.b=DuLsn2M+; 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=none ARC-Seal: i=1; s=key1; d=yhetil.org; t=1678376725; a=rsa-sha256; cv=none; b=WcwJ419H4oHYj7Z1lB3DUi6TjbCCyEO8Q2wRptw+vep5ByU6zFVeiN98eLmjK3D1yZRlUh E0t8xxfhBr3JgJ9SxirdhU0WNt5OzffwkBfpLhVGDi808P38pDOaeUC5BQTR3WG81rFrNw jfLklMZWBfMq18TE7+/u08dxzdNmFzOHI7BSBtdwfSFB8WDeC5Fampj7rGNz5jR59LNYkX LLC43jEOCpffFTwCJFbFLBNXfK6AAMBfRFgp2W25VjUlGDCAuG/mvoIejlxL6X7FFvrvhS hJoRD411ghta5mEEjTPcfl96CqFy+hSZGQuy9b2pj8pKDpKtWaPqKesfWIuekg== Authentication-Results: aspmx1.migadu.com; dkim=pass header.d=kraus.my header.s=MBO0001 header.b=DuLsn2M+; 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=none X-Migadu-Spam-Score: -2.30 X-Spam-Score: -2.30 X-Migadu-Queue-Id: 24F5529A7D X-Migadu-Scanner: scn1.migadu.com X-TUID: JAOhsaCyErmB --=-=-= Content-Type: text/plain Hi, attached is a bigger patch that fixes the result output of ob-clojure. The commit message contains examples what's currently wrong and what's fixed. This is a breaking change though. So if someone before relied on the fact that, e.g. cider, returns the result of every expression in every line instead of only the last one, they get a different result now. Is it ok to install? Other feedback? Cheers, Daniel --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-ob-clojure.el-Fix-results-output-support-clojure-cli.patch >From 77783d864d81ef1d962c302523d7c588f248c088 Mon Sep 17 00:00:00 2001 From: Daniel Kraus Date: Thu, 9 Mar 2023 16:11:27 +0100 Subject: [PATCH] ob-clojure.el: Fix results output, support clojure-cli * lisp/ob-clojure.el (org-babel-clojure-backend): Add support for clojure-cli. * lisp/ob-clojure.el (org-babel-clojurescript-backend): Move nbb to clojurescript. * lisp/ob-clojure.el (org-babel-expand-body:clojure) * lisp/ob-clojure.el (ob-clojure-eval-with-cider): Return only the last expression when :results is not set or value, and return only stdout when :results is set to output. * lisp/ob-clojure.el (ob-clojure-eval-with-cmd): Rename function as it is not only for babashka. * lisp/ob-clojure.el (org-babel-execute:clojure): Differentiate between Clojure and ClojureScript source blocks. The problem was that the ob-clojure results where not correctly taking the results parameter into account. E.g. with the cider backend, you would get all printed or returned values for each line in your block: (def small-map {:a 2 :b 4 :c 8}) {:some :map} (prn :xx) (:b small-map) | #'user/small-map | | {:some :map} | | 4 | or for babashka you would only get the printed values but not the last return value: (def small-map {:a 2 :b 4 :c 8}) {:some :map} (prn :xx) (:b small-map) : :xx Now when you specify :results value, the result is only the last returned value, and with :results output you get all values printed to stdout. So the examples above would all result in the same: (def small-map {:a 2 :b 4 :c 8}) {:some :map} (prn :xx) (:b small-map) : 4 --- lisp/ob-clojure.el | 120 +++++++++++++++++++++++++++++---------------- 1 file changed, 77 insertions(+), 43 deletions(-) diff --git a/lisp/ob-clojure.el b/lisp/ob-clojure.el index 5f589db00..6345927d6 100644 --- a/lisp/ob-clojure.el +++ b/lisp/ob-clojure.el @@ -25,20 +25,21 @@ ;;; Commentary: -;; Support for evaluating Clojure code +;; Support for evaluating Clojure / ClojureScript code. ;; Requirements: ;; - Clojure (at least 1.2.0) ;; - clojure-mode -;; - inf-clojure, Cider, SLIME, babashka or nbb +;; - babashka, nbb, Clojure CLI tools, Cider, inf-clojure or SLIME ;; For clojure-mode, see https://github.com/clojure-emacs/clojure-mode -;; For inf-clojure, see https://github.com/clojure-emacs/inf-clojure -;; For Cider, see https://github.com/clojure-emacs/cider -;; For SLIME, see https://slime.common-lisp.dev ;; For babashka, see https://github.com/babashka/babashka ;; For nbb, see https://github.com/babashka/nbb +;; For Clojure CLI tools, see https://clojure.org/guides/deps_and_cli +;; For Cider, see https://github.com/clojure-emacs/cider +;; For inf-clojure, see https://github.com/clojure-emacs/inf-clojure +;; For SLIME, see https://slime.common-lisp.dev ;; For SLIME, the best way to install its components is by following ;; the directions as set out by Phil Hagelberg (Technomancy) on the @@ -78,7 +79,7 @@ defvar org-babel-header-args:clojurescript (defcustom org-babel-clojure-backend (cond ((executable-find "bb") 'babashka) - ((executable-find "nbb") 'nbb) + ((executable-find "clojure") 'clojure-cli) ((featurep 'cider) 'cider) ((featurep 'inf-clojure) 'inf-clojure) ((featurep 'slime) 'slime) @@ -87,11 +88,24 @@ defcustom org-babel-clojure-backend :group 'org-babel :package-version '(Org . "9.6") :type '(choice - (const :tag "inf-clojure" inf-clojure) + (const :tag "babashka" babashka) + (const :tag "clojure-cli" clojure-cli) (const :tag "cider" cider) + (const :tag "inf-clojure" inf-clojure) (const :tag "slime" slime) - (const :tag "babashka" babashka) + (const :tag "Not configured yet" nil))) + +(defcustom org-babel-clojurescript-backend + (cond + ((or (executable-find "nbb") (executable-find "npx")) 'nbb) + ((featurep 'cider) 'cider) + (t nil)) + "Backend used to evaluate Clojure code blocks." + :group 'org-babel + :package-version '(Org . "9.6") + :type '(choice (const :tag "nbb" nbb) + (const :tag "cider" cider) (const :tag "Not configured yet" nil))) (defcustom org-babel-clojure-default-ns "user" @@ -105,15 +119,24 @@ defcustom ob-clojure-babashka-command :group 'org-babel :package-version '(Org . "9.6")) -(defcustom ob-clojure-nbb-command (executable-find "nbb") +(defcustom ob-clojure-nbb-command (or (executable-find "nbb") + (when-let (npx (executable-find "npx")) + (concat npx " nbb"))) "Path to the nbb executable." :type '(choice file (const nil)) + :group 'org-babel) + +(defcustom ob-clojure-cli-command (when-let (cmd (executable-find "clojure")) + (concat cmd " -M")) + "Clojure CLI command used to execute source blocks." + :type 'file :group 'org-babel :package-version '(Org . "9.6")) (defun org-babel-expand-body:clojure (body params) "Expand BODY according to PARAMS, return the expanded body." (let* ((vars (org-babel--get-vars params)) + (cljs-p (string= (cdr (assq :target params)) "cljs")) (backend-override (cdr (assq :backend params))) (org-babel-clojure-backend (cond @@ -146,10 +169,26 @@ defun org-babel-expand-body:clojure vars "\n ") body)))))) - (if (or (member "code" result-params) - (member "pp" result-params)) - (format "(clojure.pprint/pprint (do %s))" body) - body))) + ;; If the result param is set to "output" we don't have to do + ;; anything special and just let the backend handle everything + (if (member "output" result-params) + body + + ;; If the result is not "output" (i.e. it's "value"), disable + ;; stdout output and print the last returned value. Use pprint + ;; instead of prn when results param is "pp" or "code". + (concat + (if (or (member "code" result-params) + (member "pp" result-params)) + (concat (if cljs-p + "(require '[cljs.pprint :refer [pprint]])" + "(require '[clojure.pprint :refer [pprint]])") + " (pprint ") + "(prn ") + (if cljs-p + "(binding [cljs.core/*print-fn* (constantly nil)]" + "(binding [*out* (java.io.StringWriter.)]") + body "))")))) (defvar ob-clojure-inf-clojure-filter-out) (defvar ob-clojure-inf-clojure-tmp-output) @@ -228,29 +267,15 @@ defun ob-clojure-eval-with-inf-clojure (defun ob-clojure-eval-with-cider (expanded params) "Evaluate EXPANDED code block with PARAMS using cider." (org-require-package 'cider "Cider") - (let ((connection (cider-current-connection (cdr (assq :target params)))) - (result-params (cdr (assq :result-params params))) - result0) + (let ((connection (cider-current-connection (cdr (assq :target params))))) (unless connection (sesman-start-session 'CIDER)) (if (not connection) ;; Display in the result instead of using `user-error' - (setq result0 "Please reevaluate when nREPL is connected") - (ob-clojure-with-temp-expanded expanded params - (let ((response (nrepl-sync-request:eval exp connection))) - (push (or (nrepl-dict-get response "root-ex") - (nrepl-dict-get response "ex") - (nrepl-dict-get - response (if (or (member "output" result-params) - (member "pp" result-params)) - "out" - "value"))) - result0))) - (ob-clojure-string-or-list - ;; Filter out s-expressions that return nil (string "nil" - ;; from nrepl eval) or comment forms (actual nil from nrepl) - (reverse (delete "" (mapcar (lambda (r) - (replace-regexp-in-string "nil" "" (or r ""))) - result0))))))) + "Please reevaluate when nREPL is connected" + (let ((response (nrepl-sync-request:eval expanded connection))) + (or (nrepl-dict-get response "root-ex") + (nrepl-dict-get response "ex") + (nrepl-dict-get response "out")))))) (defun ob-clojure-eval-with-slime (expanded params) "Evaluate EXPANDED code block with PARAMS using slime." @@ -262,24 +287,30 @@ defun ob-clojure-eval-with-slime ,(buffer-substring-no-properties (point-min) (point-max))) (cdr (assq :package params))))) -(defun ob-clojure-eval-with-babashka (bb expanded) - "Evaluate EXPANDED code block using BB (babashka or nbb)." - (let ((script-file (org-babel-temp-file "clojure-bb-script-" ".clj"))) +(defun ob-clojure-eval-with-cmd (cmd expanded) + "Evaluate EXPANDED code block using CMD (babashka, clojure or nbb)." + (let ((script-file (org-babel-temp-file "clojure-cmd-script-" ".clj"))) (with-temp-file script-file (insert expanded)) (org-babel-eval - (format "%s %s" bb (org-babel-process-file-name script-file)) + (format "%s %s" cmd (org-babel-process-file-name script-file)) ""))) (defun org-babel-execute:clojure (body params) "Execute the BODY block of Clojure code with PARAMS using Babel." (let* ((backend-override (cdr (assq :backend params))) + (cljs-p (string= (cdr (assq :target params)) "cljs")) (org-babel-clojure-backend (cond (backend-override (intern backend-override)) - (org-babel-clojure-backend org-babel-clojure-backend) - (t (user-error "You need to customize `org-babel-clojure-backend' -or set the `:backend' header argument"))))) + (org-babel-clojure-backend (if cljs-p + org-babel-clojurescript-backend + org-babel-clojure-backend)) + (t (user-error "You need to customize `%S' +or set the `:backend' header argument" + (if cljs-p + org-babel-clojurescript-backend + org-babel-clojure-backend)))))) (let* ((expanded (org-babel-expand-body:clojure body params)) (result-params (cdr (assq :result-params params))) result) @@ -287,14 +318,17 @@ defun org-babel-execute:clojure (cond ((eq org-babel-clojure-backend 'inf-clojure) (ob-clojure-eval-with-inf-clojure expanded params)) + ((eq org-babel-clojure-backend 'clojure-cli) + (ob-clojure-eval-with-cmd ob-clojure-cli-command expanded)) ((eq org-babel-clojure-backend 'babashka) - (ob-clojure-eval-with-babashka ob-clojure-babashka-command expanded)) + (ob-clojure-eval-with-cmd ob-clojure-babashka-command expanded)) ((eq org-babel-clojure-backend 'nbb) - (ob-clojure-eval-with-babashka ob-clojure-nbb-command expanded)) + (ob-clojure-eval-with-cmd ob-clojure-nbb-command expanded)) ((eq org-babel-clojure-backend 'cider) (ob-clojure-eval-with-cider expanded params)) ((eq org-babel-clojure-backend 'slime) - (ob-clojure-eval-with-slime expanded params)))) + (ob-clojure-eval-with-slime expanded params)) + (t (user-error "Invalid backend")))) (org-babel-result-cond result-params result (condition-case nil (org-babel-script-escape result) -- 2.39.2 --=-=-=--