emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* [PATCH] ob-lua: Support all types and multiple values in results
@ 2024-04-23 16:44 Rudolf Adamkovič
  2024-04-23 17:05 ` Rudolf Adamkovič
  2024-04-24 13:05 ` Ihor Radchenko
  0 siblings, 2 replies; 26+ messages in thread
From: Rudolf Adamkovič @ 2024-04-23 16:44 UTC (permalink / raw)
  To: emacs-orgmode; +Cc: Rudolf Adamkovič

* etc/ORG-NEWS
(New and changed options): Describe the new option
'org-babel-lua-multiple-values-separator'.
(New features): Describe the main change, as per the title of this
commit message.
* lisp/ob-lua.el
(org-babel-lua-multiple-values-separator): Enable the user to
customize the string that separates the individual values in
multi-valued returns.
(org-babel-lua-wrapper-method): Support all Lua types and multi-valued
returns.  Further, do not pretty-print tables with one or more
extraneous newline characters.
(org-babel-lua-pp-wrapper-method): Remove in favor of the new, more
general 'org-babel-lua-wrapper-method'.
(org-babel-lua-evaluate-external-process): Adapt for the new
'org-babel-lua-wrapper-method'.
* testing/lisp/test-ob-lua.el
(test-ob-lua/colnames-yes-header-argument-pp):
(test-ob-lua/colnames-nil-header-argument):
(test-ob-lua/colnames-no-header-argument): Stop expecting extraneous
newlines, now that the pretty printer does not output them.
(test-ob-lua/types): Test nil, boolean, number, string, and table
results.
(test-ob-lua/multiple-values): Test multi-valued results.
---
 etc/ORG-NEWS                | 17 +++++++++
 lisp/ob-lua.el              | 73 ++++++++++++++++++++++---------------
 testing/lisp/test-ob-lua.el | 48 ++++++++++++++++++++++--
 3 files changed, 105 insertions(+), 33 deletions(-)

diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index fc2ff9e00..696f46e53 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -637,6 +637,11 @@ link when storing any type of external link type in an Org file, not
 just =id:= links.
 
 ** New and changed options
+*** ~org-babel-lua-multiple-values-separator~
+
+The string that separates the values of multi-valued results returned
+from Lua code blocks.
+
 *** =.avif= images are now recognized in ~org-html-inline-image-rules~
 
 In =ox-html=, =.avif= image links are now inlined by default.
@@ -1012,6 +1017,18 @@ The option can be customized either by
 2. by setting the file local keyword =LATEX_FOOTNOTE_COMMAND=
 
 ** New features
+*** =ob-lua=: Support all types and multiple values in results
+
+Lua code blocks can now return values of any type and can also return
+multiple values.  Previously, values of certain types were incorrectly
+converted to the empty string =""=, which broke HTML export for inline
+code blocks, and multiple values were incorrectly concatenated, where
+~return 1, 2, 3~ was evaluated as =123=.
+
+Multiple values are comma-separated by default, so that they work well
+with inline code blocks.  To change the string used as the separator,
+customize ~org-babel-lua-multiple-values-separator~.
+
 *** ~org-paste-subtree~ now handles =C-u= and =C-u C-u= prefix arguments specially
 
 With =C-u= prefix argument, force inserting a sibling heading below.
diff --git a/lisp/ob-lua.el b/lisp/ob-lua.el
index b241fccdc..92a1b3344 100644
--- a/lisp/ob-lua.el
+++ b/lisp/ob-lua.el
@@ -81,6 +81,13 @@ This will typically be `lua-mode'."
   :package-version '(Org . "8.3")
   :type 'symbol)
 
+(defcustom org-babel-lua-multiple-values-separator ", "
+  "Separate multiple values with this string."
+  :group 'org-babel
+  :version "30.0"
+  :package-version '(Org . "9.7")
+  :type 'string)
+
 (defun org-babel-execute:lua (body params)
   "Execute Lua BODY according to PARAMS.
 This function is called by `org-babel-execute-src-block'."
@@ -251,41 +258,47 @@ function main()
 %s
 end
 
-fd=io.open(\"%s\", \"w\")
-fd:write( main() )
-fd:close()")
-(defvar org-babel-lua-pp-wrapper-method
-  "
--- table to string
-function t2s(t, indent)
+function dump(it, indent)
    if indent == nil then
-      indent = \"\"
+      indent = ''
    end
-   if type(t) == \"table\" then
-      ts = \"\"
-      for k,v in pairs(t) do
-         if type(v) == \"table\" then
-            ts = ts .. indent .. t2s(k,indent .. \"  \") .. \" = \\n\" ..
-               t2s(v, indent .. \"  \")
-         else
-            ts = ts .. indent .. t2s(k,indent .. \"  \") .. \" = \" ..
-               t2s(v, indent .. \"  \") .. \"\\n\"
+   if type(it) == 'table' and %s then
+      local count = 0
+      for _ in pairs(it) do
+         count = count + 1
+      end
+      local result = ''
+      if #indent ~= 0 then
+         result = result .. '\\n'
+      end
+      for key, value in pairs(it) do
+         result = result
+            .. indent
+            .. dump(key)
+            .. ' = '
+            .. dump(value, indent .. '  ')
+         count = count - 1
+         if count ~= 0 then
+            result = result .. '\\n'
          end
       end
-      return ts
+      return result
    else
-      return tostring(t)
+      return tostring(it)
    end
 end
 
-
-function main()
-%s
+function combine(...)
+  local result = {}
+  for index = 1, select('#', ...) do
+    result[index] = dump(select(index, ...))
+  end
+  return table.concat(result, '%s')
 end
 
-fd=io.open(\"%s\", \"w\")
-fd:write(t2s(main()))
-fd:close()")
+output = io.open('%s', 'w')
+output:write(combine(main()))
+output:close()")
 
 (defun org-babel-lua-evaluate
     (session body &optional result-type result-params preamble)
@@ -319,15 +332,17 @@ PREAMBLE string is appended to BODY."
 		      (concat
 		       preamble (and preamble "\n")
 		       (format
-			(if (member "pp" result-params)
-			    org-babel-lua-pp-wrapper-method
-			  org-babel-lua-wrapper-method)
+                        org-babel-lua-wrapper-method
 			(mapconcat
 			 (lambda (line) (format "\t%s" line))
 			 (split-string
 			  (org-remove-indentation
 			   (org-trim body))
-			  "[\r\n]") "\n")
+			  "[\r\n]")
+                         "\n")
+                        (if (member "pp" result-params)
+                            "true" "false")
+                        org-babel-lua-multiple-values-separator
 			(org-babel-process-file-name tmp-file 'noquote))))
 		     (org-babel-eval-read-file tmp-file))))))
     (org-babel-result-cond result-params
diff --git a/testing/lisp/test-ob-lua.el b/testing/lisp/test-ob-lua.el
index f30e65bb3..0a60c68ca 100644
--- a/testing/lisp/test-ob-lua.el
+++ b/testing/lisp/test-ob-lua.el
@@ -77,9 +77,9 @@ return x[1]
 
 
 (ert-deftest test-ob-lua/colnames-yes-header-argument-pp ()
-  "Test table passing with `colnames' header and pp option."
+  "Test table passing with `colnames' header and `pp' option."
   (should
-   (equal "a = 12\nb = 13\n"
+   (equal "a = 12\nb = 13"
 	  (org-test-with-temp-text
 	      "#+name: eg
 | col | val |
@@ -99,7 +99,7 @@ return x
 (ert-deftest test-ob-lua/colnames-nil-header-argument ()
   "Test table with `colnames' set to `nil'."
   (should
-   (equal "1 = a\n2 = b\n"
+   (equal "1 = a\n2 = b"
 	  (org-test-with-temp-text
 	      "#+name: eg
 | col |
@@ -119,7 +119,7 @@ return x
 (ert-deftest test-ob-lua/colnames-no-header-argument ()
   "Test table passing without `colnames'."
   (should
-   (equal "1 = col\n2 = a\n3 = b\n"
+   (equal "1 = col\n2 = a\n3 = b"
 	  (org-test-with-temp-text
 	      "#+name: eg
 | col |
@@ -136,6 +136,46 @@ return x
 	    (org-babel-next-src-block)
 	    (org-babel-execute-src-block)))))
 
+(ert-deftest test-ob-lua/types ()
+  "Test returning different types."
+  (should
+   (equal "nil"
+          (org-test-with-temp-text "src_lua{return nil}"
+            (org-babel-execute-src-block))))
+  (should
+   (equal "true"
+          (org-test-with-temp-text "src_lua{return true}"
+            (org-babel-execute-src-block))))
+  (should
+   (equal "false"
+          (org-test-with-temp-text "src_lua{return false}"
+            (org-babel-execute-src-block))))
+  (should
+   (equal 1
+          (org-test-with-temp-text "src_lua{return 1}"
+            (org-babel-execute-src-block))))
+  (should
+   (equal "hello world"
+          (org-test-with-temp-text "src_lua{return 'hello world'}"
+            (org-babel-execute-src-block))))
+  (should
+   (equal 0
+          (string-match "table: 0x[0-9A-F]+"
+                        (org-test-with-temp-text "src_lua{return {}}"
+                          (org-babel-execute-src-block))))))
+
+(ert-deftest test-ob-lua/multiple-values ()
+  "Test returning multiple values."
+  (should
+   (equal "1, 2, 3"
+          (org-test-with-temp-text "src_lua{return 1, 2, 3}"
+            (org-babel-execute-src-block))))
+  (should
+   (equal "1|2|3"
+          (let ((org-babel-lua-multiple-values-separator "|"))
+            (org-test-with-temp-text "src_lua{return 1, 2, 3}"
+              (org-babel-execute-src-block))))))
+
 (provide 'test-ob-lua)
 
 ;;; test-ob-lua.el ends here
-- 
2.44.0



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-04-23 16:44 [PATCH] ob-lua: Support all types and multiple values in results Rudolf Adamkovič
@ 2024-04-23 17:05 ` Rudolf Adamkovič
  2024-04-24 14:20   ` Ihor Radchenko
  2024-04-24 13:05 ` Ihor Radchenko
  1 sibling, 1 reply; 26+ messages in thread
From: Rudolf Adamkovič @ 2024-04-23 17:05 UTC (permalink / raw)
  To: emacs-orgmode

Rudolf Adamkovič <rudolf@adamkovic.org> writes:

> +Lua code blocks can now return values of any type and can also return
> +multiple values.  Previously, values of certain types were incorrectly
> +converted to the empty string =""=, which broke HTML export for inline
> +code blocks, and multiple values were incorrectly concatenated, where
> +~return 1, 2, 3~ was evaluated as =123=.

Also,

  #+BEGIN_SRC lua
  return {1, 2, 3}
  #+END_SRC

previously crashed, as did

  #+BEGIN_SRC lua
  function divide()
     error("oops")
     return divident / divisor
  end
  return pcall(oops)
  #+END_SRC

All that works now, with no more crashes.

P.S. #1

We still have an old bug where

  src_lua{return string.match("A {B} C", "%b{}")}

is misjudged to be a table:

  org-babel-insert-result: Inline error: list result cannot be used

P.S. #2

I did not update any session-related code.

Currently,

  #+BEGIN_SRC lua :session x
  print 1
  #+END_SRC

gives

  ... Sessions currently not supported, work in progress

This is also documented in the header

  ;; Requirements:
  ;; for session support, lua-mode is needed.
  ;; [...]
  ;; However, sessions are not yet working.

This half-finished session support should be removed, IMHO.

If someone needs it and are willing to finish it, they can still dig it
up it in the history.  That is what VC is for, after all.

As of now, all that session-related dead code only pollutes the file,
making it harder to change, as it drifts out of sync...

Rudy
-- 
"All you have to do is write one true sentence.  Write the truest
sentence that you know."  --- Ernest Miller Hemingway (1899-1961)

Rudolf Adamkovič <rudolf@adamkovic.org> [he/him]
Studenohorská 25, 84103 Bratislava, Slovakia, European Union


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-04-23 16:44 [PATCH] ob-lua: Support all types and multiple values in results Rudolf Adamkovič
  2024-04-23 17:05 ` Rudolf Adamkovič
@ 2024-04-24 13:05 ` Ihor Radchenko
  2024-04-24 15:01   ` Rudolf Adamkovič
  1 sibling, 1 reply; 26+ messages in thread
From: Ihor Radchenko @ 2024-04-24 13:05 UTC (permalink / raw)
  To: Rudolf Adamkovič; +Cc: emacs-orgmode

Rudolf Adamkovič <rudolf@adamkovic.org> writes:

> * etc/ORG-NEWS
> (New and changed options): Describe the new option
> 'org-babel-lua-multiple-values-separator'.
> (New features): Describe the main change, as per the title of this
> commit message.

Thanks!
Applied, onto main, after removing redundant :version keyword from
defcustom.
https://git.savannah.gnu.org/cgit/emacs/org-mode.git/commit/?id=252cc0be0

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-04-23 17:05 ` Rudolf Adamkovič
@ 2024-04-24 14:20   ` Ihor Radchenko
  0 siblings, 0 replies; 26+ messages in thread
From: Ihor Radchenko @ 2024-04-24 14:20 UTC (permalink / raw)
  To: Rudolf Adamkovič; +Cc: emacs-orgmode

Rudolf Adamkovič <rudolf@adamkovic.org> writes:

> P.S. #1
>
> We still have an old bug where
>
>   src_lua{return string.match("A {B} C", "%b{}")}
>
> is misjudged to be a table:
>
>   org-babel-insert-result: Inline error: list result cannot be used

May you create a test for this with expected failure?

> P.S. #2
>
> I did not update any session-related code.
>
> Currently,
>
>   #+BEGIN_SRC lua :session x
>   print 1
>   #+END_SRC
>
> gives
>
>   ... Sessions currently not supported, work in progress
>
> This is also documented in the header
>
>   ;; Requirements:
>   ;; for session support, lua-mode is needed.
>   ;; [...]
>   ;; However, sessions are not yet working.
>
> This half-finished session support should be removed, IMHO.

+1

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-04-24 13:05 ` Ihor Radchenko
@ 2024-04-24 15:01   ` Rudolf Adamkovič
  2024-04-26 13:40     ` Ihor Radchenko
  0 siblings, 1 reply; 26+ messages in thread
From: Rudolf Adamkovič @ 2024-04-24 15:01 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: emacs-orgmode

Ihor Radchenko <yantar92@posteo.net> writes:

> May you create a test for this with expected failure?

Sure!  Here is one:

  (should
   (equal "{B}"
          (org-test-with-temp-text
              "src_lua{return string.match('A {B} C', '%b{}')}"
            (org-babel-execute-src-block))))

The return value from 'string.match' is the substring "{B}", which Babel
misjudges to be a list and signals the error:

  (user-error "Inline error: list result cannot be used")

> Applied, onto main, after [...]

Thank you, Ihor!

Rudy
-- 
"I do not fear death.  I had been dead for billions and billions of
years before I was born, and had not suffered the slightest
inconvenience from it."  --- Mark Twain, paraphrased

Rudolf Adamkovič <rudolf@adamkovic.org> [he/him]
Studenohorská 25, 84103 Bratislava, Slovakia, European Union


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-04-24 15:01   ` Rudolf Adamkovič
@ 2024-04-26 13:40     ` Ihor Radchenko
  2024-04-27 10:57       ` Max Nikulin
  2024-04-27 16:33       ` Rudolf Adamkovič
  0 siblings, 2 replies; 26+ messages in thread
From: Ihor Radchenko @ 2024-04-26 13:40 UTC (permalink / raw)
  To: Rudolf Adamkovič; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 657 bytes --]

Rudolf Adamkovič <rudolf@adamkovic.org> writes:

> Ihor Radchenko <yantar92@posteo.net> writes:
>
>> May you create a test for this with expected failure?
>
> Sure!  Here is one:
>
>   (should
>    (equal "{B}"
>           (org-test-with-temp-text
>               "src_lua{return string.match('A {B} C', '%b{}')}"
>             (org-babel-execute-src-block))))
>
> The return value from 'string.match' is the substring "{B}", which Babel
> misjudges to be a list and signals the error:
>
>   (user-error "Inline error: list result cannot be used")

Maybe something like the attached.
(I am a casual lua user, so better double check)


[-- Attachment #2: 0001-ob-lua-Fix-edge-case-when-output-is-string.patch --]
[-- Type: text/x-patch, Size: 1840 bytes --]

From bfe0fa3d78cc13b84dec33c230755c9f4693a685 Mon Sep 17 00:00:00 2001
Message-ID: <bfe0fa3d78cc13b84dec33c230755c9f4693a685.1714138810.git.yantar92@posteo.net>
From: Ihor Radchenko <yantar92@posteo.net>
Date: Fri, 26 Apr 2024 16:39:07 +0300
Subject: [PATCH] ob-lua: Fix edge case when output is {string}
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* lisp/ob-lua.el (org-babel-lua-wrapper-method): Make sure that string
result is enclosed in "...", so that Org mode does not try to guess
the output type heuristically.
* testing/lisp/test-ob-lua.el (test-ob-lua/types): New test.

Co-authored-by: Rudolf Adamkovič <rudolf@adamkovic.org>
---
 lisp/ob-lua.el              | 2 ++
 testing/lisp/test-ob-lua.el | 6 ++++++
 2 files changed, 8 insertions(+)

diff --git a/lisp/ob-lua.el b/lisp/ob-lua.el
index 041abfabc..afe88065d 100644
--- a/lisp/ob-lua.el
+++ b/lisp/ob-lua.el
@@ -282,6 +282,8 @@ (defvar org-babel-lua-wrapper-method
          end
       end
       return result
+   elseif type(it) == 'string' then
+      return '\"' .. it .. '\"'
    else
       return tostring(it)
    end
diff --git a/testing/lisp/test-ob-lua.el b/testing/lisp/test-ob-lua.el
index 0a60c68ca..398ab761d 100644
--- a/testing/lisp/test-ob-lua.el
+++ b/testing/lisp/test-ob-lua.el
@@ -158,6 +158,12 @@ (ert-deftest test-ob-lua/types ()
    (equal "hello world"
           (org-test-with-temp-text "src_lua{return 'hello world'}"
             (org-babel-execute-src-block))))
+  ;; Edge case: string matching list syntax.
+  (should
+   (equal "{B}"
+	  (org-test-with-temp-text
+	      "src_lua{return string.match('A {B} C', '%b{}')}"
+	    (org-babel-execute-src-block))))
   (should
    (equal 0
           (string-match "table: 0x[0-9A-F]+"
-- 
2.44.0


[-- Attachment #3: Type: text/plain, Size: 224 bytes --]


-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-04-26 13:40     ` Ihor Radchenko
@ 2024-04-27 10:57       ` Max Nikulin
  2024-04-27 16:33       ` Rudolf Adamkovič
  1 sibling, 0 replies; 26+ messages in thread
From: Max Nikulin @ 2024-04-27 10:57 UTC (permalink / raw)
  To: emacs-orgmode

On 26/04/2024 20:40, Ihor Radchenko wrote:
> +++ b/lisp/ob-lua.el
> @@ -282,6 +282,8 @@ (defvar org-babel-lua-wrapper-method
>            end
>         end
>         return result
> +   elseif type(it) == 'string' then
> +      return '\"' .. it .. '\"'

If you are adding quotes around then quote characters in the value 
should be escaped.



^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-04-26 13:40     ` Ihor Radchenko
  2024-04-27 10:57       ` Max Nikulin
@ 2024-04-27 16:33       ` Rudolf Adamkovič
  2024-04-28 12:36         ` Ihor Radchenko
  1 sibling, 1 reply; 26+ messages in thread
From: Rudolf Adamkovič @ 2024-04-27 16:33 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: emacs-orgmode

Ihor Radchenko <yantar92@posteo.net> writes:

> Maybe something like the attached.

Nice:

  src_elisp{"foo"} {{{results(=foo=)}}}
  src_python{return "foo"} {{{results(=foo=)}}}
  src_lua{return "foo"} {{{results(=foo=)}}}

That said, I have just noticed:

  # expected: a, b, c
  src_lua{return "a", "b", "c"} {{{results(="a"  "b"  "c"=)}}}

  # expected: 1, 2
  src_lua{return 1, 2} {{{results(=1\, 2=)}}}

Oops!

We need *better tests*, otherwise all this is kind of useless.

I will hack on this some more...

Rudy
-- 
"Thinking is a momentary dismissal of irrelevancies."
--- Richard Buckminster Fuller, 1969

Rudolf Adamkovič <rudolf@adamkovic.org> [he/him]
Studenohorská 25, 84103 Bratislava, Slovakia, European Union


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-04-27 16:33       ` Rudolf Adamkovič
@ 2024-04-28 12:36         ` Ihor Radchenko
  2024-04-29 15:57           ` Rudolf Adamkovič
  0 siblings, 1 reply; 26+ messages in thread
From: Ihor Radchenko @ 2024-04-28 12:36 UTC (permalink / raw)
  To: Rudolf Adamkovič; +Cc: emacs-orgmode

Rudolf Adamkovič <rudolf@adamkovic.org> writes:

> ...
> We need *better tests*, otherwise all this is kind of useless.
>
> I will hack on this some more...

Will you be willing to provide some?

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-04-28 12:36         ` Ihor Radchenko
@ 2024-04-29 15:57           ` Rudolf Adamkovič
  2024-04-29 20:26             ` Rudolf Adamkovič
  0 siblings, 1 reply; 26+ messages in thread
From: Rudolf Adamkovič @ 2024-04-29 15:57 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: emacs-orgmode

Ihor Radchenko <yantar92@posteo.net> writes:

>> We need *better tests*, otherwise all this is kind of useless.
>>
>> I will hack on this some more...
>
> Will you be willing to provide some?

Definitely!  I am on it.

Rudy
-- 
"Genius is 1% inspiration and 99% perspiration."
--- Thomas Alva Edison, 1932

Rudolf Adamkovič <rudolf@adamkovic.org> [he/him]
Studenohorská 25, 84103 Bratislava, Slovakia, European Union


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-04-29 15:57           ` Rudolf Adamkovič
@ 2024-04-29 20:26             ` Rudolf Adamkovič
  2024-04-30 10:24               ` Ihor Radchenko
  2024-05-01 11:05               ` Max Nikulin
  0 siblings, 2 replies; 26+ messages in thread
From: Rudolf Adamkovič @ 2024-04-29 20:26 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 134 bytes --]

Rudolf Adamkovič <rudolf@adamkovic.org> writes:

> Definitely!  I am on it.

All right, how about the attached patch?

Rudy


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-ob-lua-Quote-list-like-strings-sort-tables-and-parse.patch --]
[-- Type: text/x-patch, Size: 14384 bytes --]

From 40270bc62f951cfd20916c17e2dfc52863d6b8e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rudolf=20Adamkovi=C4=8D?= <rudolf@adamkovic.org>
Date: Mon, 29 Apr 2024 21:42:04 +0200
Subject: [PATCH] ob-lua: Quote list-like strings, sort tables, and parse bare
 returns

* lisp/ob-lua.el (org-babel-lua-multiple-values-separator): Change the
default value from ", " to "|" to avoid '\\,' appearing in strings.
(org-babel-lua-wrapper-method): Improve 3 aspects: (1) Quote strings
with list-like content to prevent Org Babel from incorrectly guessing
their type, (2) sort pretty-printed non-sequential tables to make them
reproducible, and (3) handle implicit nils produced by 'return' used
with no arguments.
* testing/lisp/test-ob-lua.el (test-ob-lua/result/nil):
(test-ob-lua/result/nil/explicit):
(test-ob-lua/result/boolean):
(test-ob-lua/results/number/integer):
(test-ob-lua/results/number/integer/negative):
(test-ob-lua/results/number/integer/multiple):
(test-ob-lua/results/number/real):
(test-ob-lua/results/number/real/multiple):
(test-ob-lua/results/number/infinity):
(test-ob-lua/results/string/single-quotes):
(test-ob-lua/results/string/double-quotes):
(test-ob-lua/results/string/multiple):
(test-ob-lua/results/string/list-like):
(test-ob-lua/results/string/list-like/brackets):
(test-ob-lua/results/string/list-like/curlies):
(test-ob-lua/result/table):
(test-ob-lua/result/table/pretty-print):
(test-ob-lua/result/table/pretty-print/sorted):
(test-ob-lua/results/value-separator): New tests.
---
 lisp/ob-lua.el              |  41 ++++--
 testing/lisp/test-ob-lua.el | 264 ++++++++++++++++++++++++++++++++----
 2 files changed, 266 insertions(+), 39 deletions(-)

diff --git a/lisp/ob-lua.el b/lisp/ob-lua.el
index 041abfabc..5a0fdb18b 100644
--- a/lisp/ob-lua.el
+++ b/lisp/ob-lua.el
@@ -81,7 +81,7 @@ This will typically be `lua-mode'."
   :package-version '(Org . "8.3")
   :type 'symbol)
 
-(defcustom org-babel-lua-multiple-values-separator ", "
+(defcustom org-babel-lua-multiple-values-separator "|"
   "Separate multiple values with this string."
   :group 'org-babel
   :package-version '(Org . "9.7")
@@ -261,26 +261,33 @@ function dump(it, indent)
    if indent == nil then
       indent = ''
    end
+
    if type(it) == 'table' and %s then
-      local count = 0
-      for _ in pairs(it) do
-         count = count + 1
-      end
       local result = ''
+
       if #indent ~= 0 then
          result = result .. '\\n'
       end
-      for key, value in pairs(it) do
+
+      local keys = {}
+      for key in pairs(it) do
+        table.insert(keys, key)
+      end
+
+      table.sort(keys)
+
+      for index, key in pairs(keys) do
+         local value = it[key]
          result = result
             .. indent
             .. dump(key)
             .. ' = '
             .. dump(value, indent .. '  ')
-         count = count - 1
-         if count ~= 0 then
+         if index ~= #keys then
             result = result .. '\\n'
          end
       end
+
       return result
    else
       return tostring(it)
@@ -288,11 +295,27 @@ function dump(it, indent)
 end
 
 function combine(...)
+  local quotes = '\"'
   local result = {}
+
   for index = 1, select('#', ...) do
     result[index] = dump(select(index, ...))
   end
-  return table.concat(result, '%s')
+
+  if #result == 0 then
+    return dump(nil)
+  end
+
+  if #result == 1 then
+    local value = result[1]
+    if string.find(value, '[%%(%%[{]') == 1 then
+      return quotes .. value .. quotes
+    else
+      return value
+    end
+  end
+
+  return quotes .. table.concat(result, '%s') .. quotes
 end
 
 output = io.open('%s', 'w')
diff --git a/testing/lisp/test-ob-lua.el b/testing/lisp/test-ob-lua.el
index 0a60c68ca..775a5cf14 100644
--- a/testing/lisp/test-ob-lua.el
+++ b/testing/lisp/test-ob-lua.el
@@ -136,45 +136,249 @@ return x
 	    (org-babel-next-src-block)
 	    (org-babel-execute-src-block)))))
 
-(ert-deftest test-ob-lua/types ()
-  "Test returning different types."
+(ert-deftest test-ob-lua/result/nil ()
+  "Test returning nothing."
   (should
-   (equal "nil"
-          (org-test-with-temp-text "src_lua{return nil}"
-            (org-babel-execute-src-block))))
+   (equal
+    "src_lua{return} {{{results(=nil=)}}}"
+    (org-test-with-temp-text "src_lua{return}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/result/nil/explicit ()
+  "Test returning nothing explicitly."
+  (should
+   (equal
+    "src_lua{return nil} {{{results(=nil=)}}}"
+    (org-test-with-temp-text "src_lua{return nil}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/result/boolean ()
+  "Test returning the boolean values true and false."
+  (should
+   (equal
+    "src_lua{return true} {{{results(=true=)}}}"
+    (org-test-with-temp-text "src_lua{return true}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max)))))
   (should
-   (equal "true"
-          (org-test-with-temp-text "src_lua{return true}"
-            (org-babel-execute-src-block))))
+   (equal
+    "src_lua{return false} {{{results(=false=)}}}"
+    (org-test-with-temp-text "src_lua{return false}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/number/integer ()
+  "Test returning integers."
   (should
-   (equal "false"
-          (org-test-with-temp-text "src_lua{return false}"
-            (org-babel-execute-src-block))))
+   (equal
+    "src_lua{return 1} {{{results(=1=)}}}"
+    (org-test-with-temp-text "src_lua{return 1}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/number/integer/negative ()
+  "Test returning negative integers."
   (should
-   (equal 1
-          (org-test-with-temp-text "src_lua{return 1}"
-            (org-babel-execute-src-block))))
+   (equal
+    "src_lua{return -1} {{{results(=-1=)}}}"
+    (org-test-with-temp-text "src_lua{return -1}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/number/integer/multiple ()
+  "Test returning multiple integers at once."
   (should
-   (equal "hello world"
-          (org-test-with-temp-text "src_lua{return 'hello world'}"
-            (org-babel-execute-src-block))))
+   (equal
+    "src_lua{return 1, 2, 3} {{{results(=1|2|3=)}}}"
+    (org-test-with-temp-text "src_lua{return 1, 2, 3}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/number/real ()
+  "Test returning real numbers."
   (should
-   (equal 0
-          (string-match "table: 0x[0-9A-F]+"
-                        (org-test-with-temp-text "src_lua{return {}}"
-                          (org-babel-execute-src-block))))))
+   (equal
+    "src_lua{return 1.5} {{{results(=1.5=)}}}"
+    (org-test-with-temp-text "src_lua{return 1.5}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
 
-(ert-deftest test-ob-lua/multiple-values ()
-  "Test returning multiple values."
+(ert-deftest test-ob-lua/results/number/real/multiple ()
+  "Test returning multiple real numbers at once."
   (should
-   (equal "1, 2, 3"
-          (org-test-with-temp-text "src_lua{return 1, 2, 3}"
-            (org-babel-execute-src-block))))
+   (equal
+    "src_lua{return 1.5, 2.5, 3.5} {{{results(=1.5|2.5|3.5=)}}}"
+    (org-test-with-temp-text "src_lua{return 1.5, 2.5, 3.5}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/number/infinity ()
+  "Test returning the infinity."
+  (should
+   (equal
+    "src_lua{return 1 / 0} {{{results(=inf=)}}}"
+    (org-test-with-temp-text "src_lua{return 1 / 0}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/single-quotes ()
+  "Test returning strings in single quotes."
+  (should
+   (equal
+    "src_lua{return 'hello world'} {{{results(=hello world=)}}}"
+    (org-test-with-temp-text "src_lua{return 'hello world'}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/double-quotes ()
+  "Test returning strings in double quotes."
+  (should
+   (equal
+    "src_lua{return \"hello world\"} {{{results(=hello world=)}}}"
+    (org-test-with-temp-text "src_lua{return \"hello world\"}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/multiple ()
+  "Test returning multiple strings at once."
+  (should
+   (equal
+    "src_lua{return 'a', 'b'} {{{results(=a|b=)}}}"
+    (org-test-with-temp-text "src_lua{return 'a', 'b'}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/list-like ()
+  "Test returning strings that look like \"(...)\" lists."
+  (should
+   (equal
+    (concat "src_lua{return string.match('A (B) C', '%b()')}"
+            " {{{results(=(B)=)}}}")
+    (org-test-with-temp-text
+        "src_lua{return string.match('A (B) C', '%b()')}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/list-like/brackets ()
+  "Test returning strings that look like \"[...]\" lists."
+  (should
+   (equal
+    (concat "src_lua{return string.match('A [B] C', '%b[]')}"
+            " {{{results(=[B]=)}}}")
+    (org-test-with-temp-text
+        "src_lua{return string.match('A [B] C', '%b[]')}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/list-like/curlies ()
+  "Test returning strings that look like \"{...}\" lists."
+  (should
+   (equal
+    (concat "src_lua{return string.match('A {B} C', '%b{}')}"
+            " {{{results(={B}=)}}}")
+    (org-test-with-temp-text
+	"src_lua{return string.match('A {B} C', '%b{}')}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/result/table ()
+  "Test returning table references."
+  (should
+   (equal
+    0
+    (string-match
+     "src_lua{return {}} {{{results(=table: 0x[0-9A-F]+=)}}}"
+     (org-test-with-temp-text "src_lua{return {}}"
+       (org-babel-execute-src-block)
+       (buffer-substring-no-properties (point-min)
+                                       (point-max)))))))
+
+(ert-deftest test-ob-lua/result/table/pretty-print ()
+  "Test returning and pretty-printing sequential tables."
+  (should
+   (equal (string-join
+           '("#+BEGIN_SRC lua :results pp"
+             "return {10, {20, 30, {40, 50}, 60}, 70}"
+             "#+END_SRC"
+             ""
+             "#+RESULTS:"
+             ": 1 = 10"
+             ": 2 = "                   ; FIXME Trailing space.
+             ":   1 = 20"
+             ":   2 = 30"
+             ":   3 = "                 ; FIXME Trailing space.
+             ":     1 = 40"
+             ":     2 = 50"
+             ":   4 = 60"
+             ": 3 = 70"
+             "")
+           "\n")
+          (org-test-with-temp-text
+              (string-join
+               '("#+BEGIN_SRC lua :results pp"
+                 "return {10, {20, 30, {40, 50}, 60}, 70}<point>"
+                 "#+END_SRC")
+               "\n")
+	    (org-babel-execute-src-block)
+            (buffer-substring-no-properties (point-min)
+                                            (point-max))))))
+
+(ert-deftest test-ob-lua/result/table/pretty-print/sorted ()
+  "Test returning and pretty-printing non-sequential tables."
+  (should
+   (equal (string-join
+           '("#+BEGIN_SRC lua :results pp"
+             "return {b = 20, c = 30, a = 10}"
+             "#+END_SRC"
+             ""
+             "#+RESULTS:"
+             ;; NOTE The keys are sorted alphabetically.
+             ": a = 10"
+             ": b = 20"
+             ": c = 30"
+             "")
+           "\n")
+          (org-test-with-temp-text
+              (string-join
+               '("#+BEGIN_SRC lua :results pp"
+                 "return {b = 20, c = 30, a = 10}"
+                 "#+END_SRC")
+               "\n")
+	    (org-babel-execute-src-block)
+            (buffer-substring-no-properties (point-min)
+                                            (point-max))))))
+
+(ert-deftest test-ob-lua/results/value-separator ()
+  "Test customizing the separator of multiple values."
+  ;; TODO Once Org Babel supports returning lists from inline blocks,
+  ;; instead of trapping with the user error: "Inline error: list
+  ;; result cannot be used", use those for multiple values.
   (should
-   (equal "1|2|3"
-          (let ((org-babel-lua-multiple-values-separator "|"))
-            (org-test-with-temp-text "src_lua{return 1, 2, 3}"
-              (org-babel-execute-src-block))))))
+   (equal
+    "src_lua{return 1, 2, 3} {{{results(=1\t2\t3=)}}}"
+    (org-test-with-temp-text "src_lua{return 1, 2, 3}"
+      (let ((org-babel-lua-multiple-values-separator "\t"))
+        (org-babel-execute-src-block))
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
 
 (provide 'test-ob-lua)
 
-- 
2.39.3 (Apple Git-146)


[-- Attachment #3: Type: text/plain, Size: 277 bytes --]

-- 
"It is no paradox to say that in our most theoretical moods we may be
nearest to our most practical applications."
--- Alfred North Whitehead, 1861-1947

Rudolf Adamkovič <rudolf@adamkovic.org> [he/him]
Studenohorská 25, 84103 Bratislava, Slovakia, European Union

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-04-29 20:26             ` Rudolf Adamkovič
@ 2024-04-30 10:24               ` Ihor Radchenko
  2024-05-02 15:57                 ` Rudolf Adamkovič
  2024-05-02 15:58                 ` Rudolf Adamkovič
  2024-05-01 11:05               ` Max Nikulin
  1 sibling, 2 replies; 26+ messages in thread
From: Ihor Radchenko @ 2024-04-30 10:24 UTC (permalink / raw)
  To: Rudolf Adamkovič; +Cc: emacs-orgmode

Rudolf Adamkovič <rudolf@adamkovic.org> writes:

> Rudolf Adamkovič <rudolf@adamkovic.org> writes:
>
>> Definitely!  I am on it.

Thanks!

> All right, how about the attached patch?
> ...
> * lisp/ob-lua.el (org-babel-lua-multiple-values-separator): Change the
> default value from ", " to "|" to avoid '\\,' appearing in strings.

May you please elaborate why this breaking change is going to lead to
significant improvement? How is using "," worse than using "|"? Either
way, strings containing the separator will become problematic and need
to be escaped. Moreover, using "|" may lead to interpreting the output
as Org tables, which may be surprising to users.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-04-29 20:26             ` Rudolf Adamkovič
  2024-04-30 10:24               ` Ihor Radchenko
@ 2024-05-01 11:05               ` Max Nikulin
  2024-05-02 16:00                 ` Rudolf Adamkovič
  1 sibling, 1 reply; 26+ messages in thread
From: Max Nikulin @ 2024-05-01 11:05 UTC (permalink / raw)
  To: Rudolf Adamkovič; +Cc: emacs-orgmode

On 30/04/2024 03:26, Rudolf Adamkovič wrote:
> +    local value = result[1]
> +    if string.find(value, '[%%(%%[{]') == 1 then
> +      return quotes .. value .. quotes

Am I wrong that quotes in value may cause issues? I expect some way of 
escaping " characters.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-04-30 10:24               ` Ihor Radchenko
@ 2024-05-02 15:57                 ` Rudolf Adamkovič
  2024-05-02 15:58                 ` Rudolf Adamkovič
  1 sibling, 0 replies; 26+ messages in thread
From: Rudolf Adamkovič @ 2024-05-02 15:57 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: emacs-orgmode

Ihor Radchenko <yantar92@posteo.net> writes:

> May you please elaborate why this breaking change is going to lead to
> significant improvement? How is using "," worse than using "|"? Either
> way, strings containing the separator will become problematic and need
> to be escaped. Moreover, using "|" may lead to interpreting the output
> as Org tables, which may be surprising to users.

Thank you for the review!

The change of the separator was a lazy move on my part.  I appologize.
I changed the separator because I could not figure out how to make Org
behave sanely.  The problem is not specific to Lua:

  src_elisp{"3, 2, 1, and go!"} {{{results(=3\, 2\, 1\, and go!=)}}}

Why Org is escaping commas here?  In other words, should my tests expect
\-escapes in front of commas, or is that a bug?

I am attaching a V2 of the patch that:

- does not modify the separator anymore (resulting in 3 failing tests)
- adds one more test (which is just a sanity check, you can ignore it)
- fixes Lua code indentation (as indented by the Lua major mode)

Thank you for your guidance.

Rudy
-- 
"Be especially critical of any statement following the word
'obviously.'"
--- Anna Pell Wheeler, 1883-1966

Rudolf Adamkovič <rudolf@adamkovic.org> [he/him]
Studenohorská 25, 84103 Bratislava, Slovakia, European Union


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-04-30 10:24               ` Ihor Radchenko
  2024-05-02 15:57                 ` Rudolf Adamkovič
@ 2024-05-02 15:58                 ` Rudolf Adamkovič
  2024-05-02 16:02                   ` Rudolf Adamkovič
  1 sibling, 1 reply; 26+ messages in thread
From: Rudolf Adamkovič @ 2024-05-02 15:58 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: emacs-orgmode

Ihor Radchenko <yantar92@posteo.net> writes:

> May you please elaborate why this breaking change is going to lead to
> significant improvement? How is using "," worse than using "|"? Either
> way, strings containing the separator will become problematic and need
> to be escaped. Moreover, using "|" may lead to interpreting the output
> as Org tables, which may be surprising to users.

Thank you for the review!

The change of the separator was a lazy move on my part.  I appologize.
I changed the separator because I could not figure out how to make Org
behave sanely.  The problem is not specific to Lua:

  src_elisp{"3, 2, 1, and go!"} {{{results(=3\, 2\, 1\, and go!=)}}}

Why Org is escaping commas here?  In other words, should my tests expect
\-escapes in front of commas, or is that a bug?

I am attaching a V2 of the patch that:

- does not modify the separator anymore (resulting in 3 failing tests)
- adds one more test (which is just a sanity check, you can ignore it)
- fixes Lua code indentation (as indented by the Lua major mode)

Thank you for your guidance.

Rudy
-- 
"Be especially critical of any statement following the word
'obviously.'"
--- Anna Pell Wheeler, 1883-1966

Rudolf Adamkovič <rudolf@adamkovic.org> [he/him]
Studenohorská 25, 84103 Bratislava, Slovakia, European Union


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-05-01 11:05               ` Max Nikulin
@ 2024-05-02 16:00                 ` Rudolf Adamkovič
  2024-05-02 16:41                   ` Ihor Radchenko
  0 siblings, 1 reply; 26+ messages in thread
From: Rudolf Adamkovič @ 2024-05-02 16:00 UTC (permalink / raw)
  To: Max Nikulin; +Cc: emacs-orgmode

Max Nikulin <manikulin@gmail.com> writes:

> On 30/04/2024 03:26, Rudolf Adamkovič wrote:
>> +    local value = result[1]
>> +    if string.find(value, '[%%(%%[{]') == 1 then
>> +      return quotes .. value .. quotes
>
> Am I wrong that quotes in value may cause issues? I expect some way of
> escaping " characters.

What would the reproduction steps look like?

Rudy
-- 
"It is far better to have a question that can't be answered than an answer that
can't be questioned."
--- Carl Sagan

Rudolf Adamkovič <rudolf@adamkovic.org> [he/him]
Studenohorská 25, 84103 Bratislava, Slovakia, European Union


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-05-02 15:58                 ` Rudolf Adamkovič
@ 2024-05-02 16:02                   ` Rudolf Adamkovič
  0 siblings, 0 replies; 26+ messages in thread
From: Rudolf Adamkovič @ 2024-05-02 16:02 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 157 bytes --]

Rudolf Adamkovič <rudolf@adamkovic.org> writes:

> I am attaching a V2 of the patch that:

Oops, I forgot to attach the patch.  Here it is. :)

Rudy

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-ob-lua-Quote-list-like-strings-sort-tables-and-parse.patch --]
[-- Type: text/x-patch, Size: 14832 bytes --]

From b4d61bf511df74094fbcdf13c8c0c2b57b1e4a22 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rudolf=20Adamkovi=C4=8D?= <rudolf@adamkovic.org>
Date: Mon, 29 Apr 2024 21:42:04 +0200
Subject: [PATCH] ob-lua: Quote list-like strings, sort tables, and parse bare
 returns

* lisp/ob-lua.el (org-babel-lua-wrapper-method): 3 changes: (1) Quote
strings with list-like content to prevent Org Babel from incorrectly
guessing their type, (2) sort pretty-printed non-sequential tables to
make them reproducible, and (3) handle implicit nils produced by
'return' used with no arguments.
* testing/lisp/test-ob-lua.el (test-ob-lua/result/nil):
(test-ob-lua/result/nil/explicit):
(test-ob-lua/result/boolean):
(test-ob-lua/results/number/integer):
(test-ob-lua/results/number/integer/negative):
(test-ob-lua/results/number/integer/multiple):
(test-ob-lua/results/number/real):
(test-ob-lua/results/number/real/multiple):
(test-ob-lua/results/number/infinity):
(test-ob-lua/results/string/single-quotes):
(test-ob-lua/results/string/double-quotes):
(test-ob-lua/results/string/multiple):
(test-ob-lua/results/string/list-like):
(test-ob-lua/results/string/list-like/brackets):
(test-ob-lua/results/string/list-like/curlies):
(test-ob-lua/results/string/list-like/standard-output):
(test-ob-lua/result/table):
(test-ob-lua/result/table/pretty-print):
(test-ob-lua/result/table/pretty-print/sorted):
(test-ob-lua/results/value-separator): New tests.
---
 lisp/ob-lua.el              |  49 +++++--
 testing/lisp/test-ob-lua.el | 278 ++++++++++++++++++++++++++++++++----
 2 files changed, 284 insertions(+), 43 deletions(-)

diff --git a/lisp/ob-lua.el b/lisp/ob-lua.el
index 041abfabc..19950f2cb 100644
--- a/lisp/ob-lua.el
+++ b/lisp/ob-lua.el
@@ -254,33 +254,40 @@ then create.  Return the initialized session."
 (defvar org-babel-lua-wrapper-method
   "
 function main()
-%s
+   %s
 end
 
 function dump(it, indent)
    if indent == nil then
       indent = ''
    end
+
    if type(it) == 'table' and %s then
-      local count = 0
-      for _ in pairs(it) do
-         count = count + 1
-      end
       local result = ''
+
       if #indent ~= 0 then
          result = result .. '\\n'
       end
-      for key, value in pairs(it) do
+
+      local keys = {}
+      for key in pairs(it) do
+         table.insert(keys, key)
+      end
+
+      table.sort(keys)
+
+      for index, key in pairs(keys) do
+         local value = it[key]
          result = result
             .. indent
             .. dump(key)
             .. ' = '
             .. dump(value, indent .. '  ')
-         count = count - 1
-         if count ~= 0 then
+         if index ~= #keys then
             result = result .. '\\n'
          end
       end
+
       return result
    else
       return tostring(it)
@@ -288,11 +295,27 @@ function dump(it, indent)
 end
 
 function combine(...)
-  local result = {}
-  for index = 1, select('#', ...) do
-    result[index] = dump(select(index, ...))
-  end
-  return table.concat(result, '%s')
+   local quotes = '\"'
+   local result = {}
+
+   for index = 1, select('#', ...) do
+      result[index] = dump(select(index, ...))
+   end
+
+   if #result == 0 then
+      return dump(nil)
+   end
+
+   if #result == 1 then
+      local value = result[1]
+      if string.find(value, '[%%(%%[{]') == 1 then
+         return quotes .. value .. quotes
+      else
+         return value
+      end
+   end
+
+   return quotes .. table.concat(result, '%s') .. quotes
 end
 
 output = io.open('%s', 'w')
diff --git a/testing/lisp/test-ob-lua.el b/testing/lisp/test-ob-lua.el
index 0a60c68ca..a0a3b178c 100644
--- a/testing/lisp/test-ob-lua.el
+++ b/testing/lisp/test-ob-lua.el
@@ -136,45 +136,263 @@ return x
 	    (org-babel-next-src-block)
 	    (org-babel-execute-src-block)))))
 
-(ert-deftest test-ob-lua/types ()
-  "Test returning different types."
+(ert-deftest test-ob-lua/result/nil ()
+  "Test returning nothing."
   (should
-   (equal "nil"
-          (org-test-with-temp-text "src_lua{return nil}"
-            (org-babel-execute-src-block))))
+   (equal
+    "src_lua{return} {{{results(=nil=)}}}"
+    (org-test-with-temp-text "src_lua{return}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/result/nil/explicit ()
+  "Test returning nothing explicitly."
+  (should
+   (equal
+    "src_lua{return nil} {{{results(=nil=)}}}"
+    (org-test-with-temp-text "src_lua{return nil}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/result/boolean ()
+  "Test returning the boolean values true and false."
+  (should
+   (equal
+    "src_lua{return true} {{{results(=true=)}}}"
+    (org-test-with-temp-text "src_lua{return true}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max)))))
+  (should
+   (equal
+    "src_lua{return false} {{{results(=false=)}}}"
+    (org-test-with-temp-text "src_lua{return false}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/number/integer ()
+  "Test returning integers."
+  (should
+   (equal
+    "src_lua{return 1} {{{results(=1=)}}}"
+    (org-test-with-temp-text "src_lua{return 1}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/number/integer/negative ()
+  "Test returning negative integers."
   (should
-   (equal "true"
-          (org-test-with-temp-text "src_lua{return true}"
-            (org-babel-execute-src-block))))
+   (equal
+    "src_lua{return -1} {{{results(=-1=)}}}"
+    (org-test-with-temp-text "src_lua{return -1}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/number/integer/multiple ()
+  "Test returning multiple integers at once."
+  (should
+   (equal
+    "src_lua{return 1, 2, 3} {{{results(=1, 2, 3=)}}}"
+    (org-test-with-temp-text "src_lua{return 1, 2, 3}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/number/real ()
+  "Test returning real numbers."
+  (should
+   (equal
+    "src_lua{return 1.5} {{{results(=1.5=)}}}"
+    (org-test-with-temp-text "src_lua{return 1.5}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/number/real/multiple ()
+  "Test returning multiple real numbers at once."
   (should
-   (equal "false"
-          (org-test-with-temp-text "src_lua{return false}"
-            (org-babel-execute-src-block))))
+   (equal
+    "src_lua{return 1.5, 2.5, 3.5} {{{results(=1.5, 2.5, 3.5=)}}}"
+    (org-test-with-temp-text "src_lua{return 1.5, 2.5, 3.5}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/number/infinity ()
+  "Test returning the infinity."
   (should
-   (equal 1
-          (org-test-with-temp-text "src_lua{return 1}"
-            (org-babel-execute-src-block))))
+   (equal
+    "src_lua{return 1 / 0} {{{results(=inf=)}}}"
+    (org-test-with-temp-text "src_lua{return 1 / 0}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/single-quotes ()
+  "Test returning strings in single quotes."
   (should
-   (equal "hello world"
-          (org-test-with-temp-text "src_lua{return 'hello world'}"
-            (org-babel-execute-src-block))))
+   (equal
+    "src_lua{return 'hello world'} {{{results(=hello world=)}}}"
+    (org-test-with-temp-text "src_lua{return 'hello world'}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/double-quotes ()
+  "Test returning strings in double quotes."
   (should
-   (equal 0
-          (string-match "table: 0x[0-9A-F]+"
-                        (org-test-with-temp-text "src_lua{return {}}"
-                          (org-babel-execute-src-block))))))
+   (equal
+    "src_lua{return \"hello world\"} {{{results(=hello world=)}}}"
+    (org-test-with-temp-text "src_lua{return \"hello world\"}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
 
-(ert-deftest test-ob-lua/multiple-values ()
-  "Test returning multiple values."
+(ert-deftest test-ob-lua/results/string/multiple ()
+  "Test returning multiple strings at once."
   (should
-   (equal "1, 2, 3"
-          (org-test-with-temp-text "src_lua{return 1, 2, 3}"
-            (org-babel-execute-src-block))))
+   (equal
+    "src_lua{return 'a', 'b'} {{{results(=a, b=)}}}"
+    (org-test-with-temp-text "src_lua{return 'a', 'b'}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/list-like ()
+  "Test returning strings that look like \"(...)\" lists."
+  (should
+   (equal
+    (concat "src_lua{return string.match('A (B) C', '%b()')}"
+            " {{{results(=(B)=)}}}")
+    (org-test-with-temp-text
+        "src_lua{return string.match('A (B) C', '%b()')}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/list-like/brackets ()
+  "Test returning strings that look like \"[...]\" lists."
+  (should
+   (equal
+    (concat "src_lua{return string.match('A [B] C', '%b[]')}"
+            " {{{results(=[B]=)}}}")
+    (org-test-with-temp-text
+        "src_lua{return string.match('A [B] C', '%b[]')}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/list-like/curlies ()
+  "Test returning strings that look like \"{...}\" lists."
+  (should
+   (equal
+    (concat "src_lua{return string.match('A {B} C', '%b{}')}"
+            " {{{results(={B}=)}}}")
+    (org-test-with-temp-text
+	"src_lua{return string.match('A {B} C', '%b{}')}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/list-like/standard-output ()
+  "Test returning strings that look like lists to standard output."
+  (should
+   (equal
+    (concat "src_lua[:results output]"
+            "{print(string.match('A (B) C', '%b()'))}"
+            " {{{results(=(B)=)}}}")
+    (org-test-with-temp-text
+        (concat "src_lua[:results output]"
+                "{print(string.match('A (B) C', '%b()'))}")
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/result/table ()
+  "Test returning table references."
+  (should
+   (equal
+    0
+    (string-match
+     "src_lua{return {}} {{{results(=table: 0x[0-9A-F]+=)}}}"
+     (org-test-with-temp-text "src_lua{return {}}"
+       (org-babel-execute-src-block)
+       (buffer-substring-no-properties (point-min)
+                                       (point-max)))))))
+
+(ert-deftest test-ob-lua/result/table/pretty-print ()
+  "Test returning and pretty-printing sequential tables."
+  (should
+   (equal (string-join
+           '("#+BEGIN_SRC lua :results pp"
+             "return {10, {20, 30, {40, 50}, 60}, 70}"
+             "#+END_SRC"
+             ""
+             "#+RESULTS:"
+             ": 1 = 10"
+             ": 2 = "                   ; FIXME Trailing space.
+             ":   1 = 20"
+             ":   2 = 30"
+             ":   3 = "                 ; FIXME Trailing space.
+             ":     1 = 40"
+             ":     2 = 50"
+             ":   4 = 60"
+             ": 3 = 70"
+             "")
+           "\n")
+          (org-test-with-temp-text
+              (string-join
+               '("#+BEGIN_SRC lua :results pp"
+                 "return {10, {20, 30, {40, 50}, 60}, 70}<point>"
+                 "#+END_SRC")
+               "\n")
+	    (org-babel-execute-src-block)
+            (buffer-substring-no-properties (point-min)
+                                            (point-max))))))
+
+(ert-deftest test-ob-lua/result/table/pretty-print/sorted ()
+  "Test returning and pretty-printing non-sequential tables."
+  (should
+   (equal (string-join
+           '("#+BEGIN_SRC lua :results pp"
+             "return {b = 20, c = 30, a = 10}"
+             "#+END_SRC"
+             ""
+             "#+RESULTS:"
+             ;; NOTE The keys are sorted alphabetically.
+             ": a = 10"
+             ": b = 20"
+             ": c = 30"
+             "")
+           "\n")
+          (org-test-with-temp-text
+              (string-join
+               '("#+BEGIN_SRC lua :results pp"
+                 "return {b = 20, c = 30, a = 10}"
+                 "#+END_SRC")
+               "\n")
+	    (org-babel-execute-src-block)
+            (buffer-substring-no-properties (point-min)
+                                            (point-max))))))
+
+(ert-deftest test-ob-lua/results/value-separator ()
+  "Test customizing the separator of multiple values."
+  ;; TODO Once Org Babel supports returning lists from inline blocks,
+  ;; instead of trapping with the user error: "Inline error: list
+  ;; result cannot be used", use those for multiple values.
   (should
-   (equal "1|2|3"
-          (let ((org-babel-lua-multiple-values-separator "|"))
-            (org-test-with-temp-text "src_lua{return 1, 2, 3}"
-              (org-babel-execute-src-block))))))
+   (equal
+    "src_lua{return 1, 2, 3} {{{results(=1\t2\t3=)}}}"
+    (org-test-with-temp-text "src_lua{return 1, 2, 3}"
+      (let ((org-babel-lua-multiple-values-separator "\t"))
+        (org-babel-execute-src-block))
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
 
 (provide 'test-ob-lua)
 
-- 
2.39.3 (Apple Git-146)


[-- Attachment #3: Type: text/plain, Size: 259 bytes --]

-- 
“Those who cannot remember the past are condemned to repeat it.”
--- George Santayana, Life of Reason: Reason in Common Sense, 1905

Rudolf Adamkovič <rudolf@adamkovic.org> [he/him]
Studenohorská 25, 84103 Bratislava, Slovakia, European Union

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-05-02 16:00                 ` Rudolf Adamkovič
@ 2024-05-02 16:41                   ` Ihor Radchenko
  2024-06-09 20:54                     ` Rudolf Adamkovič
  0 siblings, 1 reply; 26+ messages in thread
From: Ihor Radchenko @ 2024-05-02 16:41 UTC (permalink / raw)
  To: Rudolf Adamkovič; +Cc: Max Nikulin, emacs-orgmode

Rudolf Adamkovič <rudolf@adamkovic.org> writes:

> Max Nikulin <manikulin@gmail.com> writes:
>
>> On 30/04/2024 03:26, Rudolf Adamkovič wrote:
>>> +    local value = result[1]
>>> +    if string.find(value, '[%%(%%[{]') == 1 then
>>> +      return quotes .. value .. quotes
>>
>> Am I wrong that quotes in value may cause issues? I expect some way of
>> escaping " characters.
>
> What would the reproduction steps look like?

I guess

#+begin_src lua
return '"hello " world"'
#+end_src

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-05-02 16:41                   ` Ihor Radchenko
@ 2024-06-09 20:54                     ` Rudolf Adamkovič
  2024-06-14 17:41                       ` Rudolf Adamkovič
  0 siblings, 1 reply; 26+ messages in thread
From: Rudolf Adamkovič @ 2024-06-09 20:54 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Max Nikulin, emacs-orgmode

Ihor Radchenko <yantar92@posteo.net> writes:

> I guess
>
> #+begin_src lua
> return '"hello " world"'
> #+end_src

Doh! :)

P.S. I will continue working on this patch soon.

Rudy
-- 
"Chop your own wood and it will warm you twice."
--- Henry Ford; Francis Kinloch, 1819; Henry David Thoreau, 1854

Rudolf Adamkovič <rudolf@adamkovic.org> [he/him]
http://adamkovic.org


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-06-09 20:54                     ` Rudolf Adamkovič
@ 2024-06-14 17:41                       ` Rudolf Adamkovič
  2024-06-14 17:48                         ` Rudolf Adamkovič
  0 siblings, 1 reply; 26+ messages in thread
From: Rudolf Adamkovič @ 2024-06-14 17:41 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Max Nikulin, emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 469 bytes --]

Rudolf Adamkovič <rudolf@adamkovic.org> writes:

> I will continue working on this patch soon.

All right, here I am, at last!

In the attached patchset, I address all the problems discussed in this
thread, plus some more I found:

1. Escape double quote characters in results [as discussed]
2. Sort tabular results [to fix flaky tests]
3. Remove half-baked session support [as discussed]
4. Improve documentation strings and commentary [bonus]

Rudy


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-ob-lua-Escape-double-quote-characters-in-results.patch --]
[-- Type: text/x-patch, Size: 1635 bytes --]

From 6dcca348337c05d33d62da6eeb1f4193b73f4d6e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rudolf=20Adamkovi=C4=8D?= <rudolf@adamkovic.org>
Date: Fri, 14 Jun 2024 16:55:24 +0200
Subject: [PATCH 1/4] ob-lua: Escape double quote characters in results

* lisp/ob-lua.el (org-babel-lua-wrapper-method): Escape all double
quote characters in Lua before giving them to Org Babel.
* testing/lisp/test-ob-lua.el (test-ob-lua/escaping-quotes): Test
automatic escaping of double quote characters.

Reported-by: Max Nikulin <manikulin@gmail.com>
Link: https://list.orgmode.org/216278dc-075c-47d1-94dc-f5bde8346b3c@gmail.com/
---
 lisp/ob-lua.el              | 2 +-
 testing/lisp/test-ob-lua.el | 6 ++++++
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/lisp/ob-lua.el b/lisp/ob-lua.el
index 041abfabc..0168bc070 100644
--- a/lisp/ob-lua.el
+++ b/lisp/ob-lua.el
@@ -283,7 +283,7 @@ function dump(it, indent)
       end
       return result
    else
-      return tostring(it)
+      return string.gsub(tostring(it), '\"', '\\\"')
    end
 end
 
diff --git a/testing/lisp/test-ob-lua.el b/testing/lisp/test-ob-lua.el
index 0a60c68ca..ff69f5411 100644
--- a/testing/lisp/test-ob-lua.el
+++ b/testing/lisp/test-ob-lua.el
@@ -176,6 +176,12 @@ return x
             (org-test-with-temp-text "src_lua{return 1, 2, 3}"
               (org-babel-execute-src-block))))))
 
+(ert-deftest test-ob-lua/escaping-quotes ()
+  (should
+   (equal "A \" B"
+          (org-test-with-temp-text "src_lua{return 'A \" B'}"
+            (org-babel-execute-src-block)))))
+
 (provide 'test-ob-lua)
 
 ;;; test-ob-lua.el ends here
-- 
2.39.3 (Apple Git-146)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-ob-lua-Sort-tabular-results.patch --]
[-- Type: text/x-patch, Size: 1252 bytes --]

From 3a2fc3f052ea2d36f51ae4fd9d0078fb8a08e522 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rudolf=20Adamkovi=C4=8D?= <rudolf@adamkovic.org>
Date: Fri, 14 Jun 2024 16:59:37 +0200
Subject: [PATCH 2/4] ob-lua: Sort tabular results

`test-ob-lua/colnames-yes-header-argument-pp' fails intermittently due
to tabular results being returned from Lua to Emacs Lisp in different
order than expected.  We fix the problem by sorting all tabular
results before returning them.

* lisp/ob-lua.el (org-babel-lua-wrapper-method): Sort all tabular
results, recursively, before returning them from Lua to Emacs Lisp.
---
 lisp/ob-lua.el | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/lisp/ob-lua.el b/lisp/ob-lua.el
index 0168bc070..5790073b6 100644
--- a/lisp/ob-lua.el
+++ b/lisp/ob-lua.el
@@ -270,7 +270,13 @@ function dump(it, indent)
       if #indent ~= 0 then
          result = result .. '\\n'
       end
-      for key, value in pairs(it) do
+      local keys = {}
+      for key in pairs(it) do
+        table.insert(keys, key)
+      end
+      table.sort(keys)
+      for _, key in ipairs(keys) do
+         local value = it[key]
          result = result
             .. indent
             .. dump(key)
-- 
2.39.3 (Apple Git-146)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0003-ob-lua-Remove-half-baked-session-support.patch --]
[-- Type: text/x-patch, Size: 12106 bytes --]

From da489d577fa714f6ce00fec5beb464f86823c4fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rudolf=20Adamkovi=C4=8D?= <rudolf@adamkovic.org>
Date: Fri, 14 Jun 2024 17:36:19 +0200
Subject: [PATCH 3/4] ob-lua: Remove half-baked session support

* lisp/ob-lua.el (org-babel-execute:lua):
(org-babel-prep-session:lua):
(org-babel-load-session:lua):
(org-babel-lua-session-buffer):
(org-babel-lua-with-earmuffs):
(org-babel-session-buffer:lua):
(org-babel-lua-without-earmuffs):
(lua-default-interpreter):
(lua-which-bufname):
(lua-shell-buffer-name):
(org-babel-lua-initiate-session-by-key):
(org-babel-lua-initiate-session):
(org-babel-lua-evaluate):
(org-babel-lua-evaluate-external-process):
(org-babel-lua-evaluate-session):
(org-babel-lua-read-string): Remove all unfinished Lua and Emacs Lisp
code related to sessions and emit a user error when a Lua session is
requested.
* testing/lisp/test-ob-lua.el (test-ob-lua/no-sessions): Test the user
error emitted when requesting a Lua session.

Link: https://list.orgmode.org/87y192etb4.fsf@localhost/
---
 lisp/ob-lua.el              | 205 +-----------------------------------
 testing/lisp/test-ob-lua.el |   9 ++
 2 files changed, 14 insertions(+), 200 deletions(-)

diff --git a/lisp/ob-lua.el b/lisp/ob-lua.el
index 5790073b6..f36c726df 100644
--- a/lisp/ob-lua.el
+++ b/lisp/ob-lua.el
@@ -25,15 +25,6 @@
 
 ;; Org-Babel support for evaluating lua source code.
 
-;; Requirements:
-;; for session support, lua-mode is needed.
-;; lua-mode is not part of GNU Emacs/orgmode, but can be obtained
-;; from marmalade or melpa.
-;; The source repository is here:
-;; https://github.com/immerrr/lua-mode
-
-;; However, sessions are not yet working.
-
 ;;; Code:
 
 (require 'org-macs)
@@ -90,11 +81,10 @@ This will typically be `lua-mode'."
 (defun org-babel-execute:lua (body params)
   "Execute Lua BODY according to PARAMS.
 This function is called by `org-babel-execute-src-block'."
-  (let* ((session (org-babel-lua-initiate-session
-		   (cdr (assq :session params))))
+  (let* ((session (cdr (assq :session params)))
          (result-params (cdr (assq :result-params params)))
          (result-type (cdr (assq :result-type params)))
-	 (return-val (when (and (eq result-type 'value) (not session))
+	 (return-val (when (eq result-type 'value)
 		       (cdr (assq :return params))))
 	 (preamble (cdr (assq :preamble params)))
          (full-body
@@ -102,7 +92,9 @@ This function is called by `org-babel-execute-src-block'."
 	   (concat body (if return-val (format "\nreturn %s" return-val) ""))
 	   params (org-babel-variable-assignments:lua params)))
          (result (org-babel-lua-evaluate
-		  session full-body result-type result-params preamble)))
+		  full-body result-type result-params preamble)))
+    (when (and session (not (equal session "none")))
+      (user-error "Sessions not supported for Lua"))
     (org-babel-reassemble-table
      result
      (org-babel-pick-name (cdr (assq :colname-names params))
@@ -110,28 +102,6 @@ This function is called by `org-babel-execute-src-block'."
      (org-babel-pick-name (cdr (assq :rowname-names params))
 			  (cdr (assq :rownames params))))))
 
-(defun org-babel-prep-session:lua (session params)
-  "Prepare SESSION according to the header arguments in PARAMS.
-VARS contains resolved variable references."
-  (let* ((session (org-babel-lua-initiate-session session))
-	 (var-lines
-	  (org-babel-variable-assignments:lua params)))
-    (org-babel-comint-in-buffer session
-      (mapc (lambda (var)
-              (end-of-line 1) (insert var) (comint-send-input)
-              (org-babel-comint-wait-for-output session))
-	    var-lines))
-    session))
-
-(defun org-babel-load-session:lua (session body params)
-  "Load BODY into SESSION."
-  (save-window-excursion
-    (let ((buffer (org-babel-prep-session:lua session params)))
-      (with-current-buffer buffer
-        (goto-char (process-mark (get-buffer-process (current-buffer))))
-        (insert (org-babel-chomp body)))
-      buffer)))
-
 ;; helper functions
 
 (defun org-babel-variable-assignments:lua (params)
@@ -178,76 +148,6 @@ Emacs-lisp table, otherwise return the results as a string."
 
 (defvar org-babel-lua-buffers '((:default . "*Lua*")))
 
-(defun org-babel-lua-session-buffer (session)
-  "Return the buffer associated with SESSION."
-  (cdr (assoc session org-babel-lua-buffers)))
-
-(defun org-babel-lua-with-earmuffs (session)
-  "Return buffer name for SESSION, as *SESSION*."
-  (let ((name (if (stringp session) session (format "%s" session))))
-    (if (and (string= "*" (substring name 0 1))
-	     (string= "*" (substring name (- (length name) 1))))
-	name
-      (format "*%s*" name))))
-
-(defun org-babel-session-buffer:lua (session &optional _)
-  "Return session buffer name for SESSION."
-  (or (org-babel-lua-session-buffer session)
-      (org-babel-lua-with-earmuffs session)))
-
-(defun org-babel-lua-without-earmuffs (session)
-"Remove stars around *SESSION*, leaving SESSION."
-  (let ((name (if (stringp session) session (format "%s" session))))
-    (if (and (string= "*" (substring name 0 1))
-	     (string= "*" (substring name (- (length name) 1))))
-	(substring name 1 (- (length name) 1))
-      name)))
-
-(defvar lua-default-interpreter)
-(defvar lua-which-bufname)
-(defvar lua-shell-buffer-name)
-(defun org-babel-lua-initiate-session-by-key (&optional session)
-  "Initiate a lua session.
-If there is not a current inferior-process-buffer in SESSION
-then create.  Return the initialized session."
-  ;; (require org-babel-lua-mode)
-  (save-window-excursion
-    (let* ((session (if session (intern session) :default))
-           (lua-buffer (org-babel-lua-session-buffer session))
-	   ;; (cmd (if (member system-type '(cygwin windows-nt ms-dos))
-	   ;; 	    (concat org-babel-lua-command " -i")
-	   ;; 	  org-babel-lua-command))
-	   )
-      (cond
-       ((and (eq 'lua-mode org-babel-lua-mode)
-             (fboundp 'lua-start-process)) ; lua-mode.el
-        ;; Make sure that lua-which-bufname is initialized, as otherwise
-        ;; it will be overwritten the first time a Lua buffer is
-        ;; created.
-        ;;(lua-toggle-shells lua-default-interpreter)
-        ;; `lua-shell' creates a buffer whose name is the value of
-        ;; `lua-which-bufname' with '*'s at the beginning and end
-        (let* ((bufname (if (and lua-buffer (buffer-live-p lua-buffer))
-                            (replace-regexp-in-string ;; zap surrounding *
-                             "^\\*\\([^*]+\\)\\*$" "\\1" (buffer-name lua-buffer))
-                          (concat "Lua-" (symbol-name session))))
-               (lua-which-bufname bufname))
-          (lua-start-process)
-          (setq lua-buffer (org-babel-lua-with-earmuffs bufname))))
-       (t
-	(error "No function available for running an inferior Lua")))
-      (setq org-babel-lua-buffers
-            (cons (cons session lua-buffer)
-                  (assq-delete-all session org-babel-lua-buffers)))
-      session)))
-
-(defun org-babel-lua-initiate-session (&optional session _params)
-  "Create a session named SESSION according to PARAMS."
-  (unless (string= session "none")
-    (error "Sessions currently not supported, work in progress")
-    (org-babel-lua-session-buffer
-     (org-babel-lua-initiate-session-by-key session))))
-
 (defvar org-babel-lua-eoe-indicator "--eoe"
   "A string to indicate that evaluation has completed.")
 
@@ -306,19 +206,6 @@ output:write(combine(main()))
 output:close()")
 
 (defun org-babel-lua-evaluate
-    (session body &optional result-type result-params preamble)
-  "Evaluate BODY in SESSION as Lua code.
-RESULT-TYPE and RESULT-PARAMS are passed to
-`org-babel-lua-evaluate-session' or
-`org-babel-lua-evaluate-external-process'.
-PREAMBLE is passed to `org-babel-lua-evaluate-external-process'."
-  (if session
-      (org-babel-lua-evaluate-session
-       session body result-type result-params)
-    (org-babel-lua-evaluate-external-process
-     body result-type result-params preamble)))
-
-(defun org-babel-lua-evaluate-external-process
     (body &optional result-type result-params preamble)
   "Evaluate BODY in external Lua process.
 If RESULT-TYPE equals `output' then return standard output as a
@@ -354,88 +241,6 @@ PREAMBLE string is appended to BODY."
       raw
       (org-babel-lua-table-or-string (org-trim raw)))))
 
-(defun org-babel-lua-evaluate-session
-    (session body &optional result-type result-params)
-  "Pass BODY to the Lua process in SESSION.
-If RESULT-TYPE equals `output' then return standard output as a
-string.  If RESULT-TYPE equals `value' then return the value of the
-last statement in BODY, as elisp."
-  (let* ((send-wait (lambda () (comint-send-input nil t) (sleep-for 0.005)))
-	 (dump-last-value
-	  (lambda
-	    (tmp-file pp)
-	    (mapc
-	     (lambda (statement) (insert statement) (funcall send-wait))
-	     (if pp
-		 (list
-		  "-- table to string
-function t2s(t, indent)
-   if indent == nil then
-      indent = \"\"
-   end
-   if type(t) == \"table\" then
-      ts = \"\"
-      for k,v in pairs(t) do
-         if type(v) == \"table\" then
-            ts = ts .. indent .. t2s(k,indent .. \"  \") .. \" = \\n\" ..
-               t2s(v, indent .. \"  \")
-         else
-            ts = ts .. indent .. t2s(k,indent .. \"  \") .. \" = \" ..
-               t2s(v, indent .. \"  \") .. \"\\n\"
-         end
-      end
-      return ts
-   else
-      return tostring(t)
-   end
-end
-"
-		  (concat "fd:write(_))
-fd:close()"
-			  (org-babel-process-file-name tmp-file 'noquote)))
-	       (list (format "fd=io.open(\"%s\", \"w\")
-fd:write( _ )
-fd:close()"
-			     (org-babel-process-file-name tmp-file
-                                                          'noquote)))))))
-	 (input-body (lambda (body)
-		       (mapc (lambda (line) (insert line) (funcall send-wait))
-			     (split-string body "[\r\n]"))
-		       (funcall send-wait)))
-         (results
-          (pcase result-type
-            (`output
-             (mapconcat
-              #'org-trim
-              (butlast
-               (org-babel-comint-with-output
-                   (session org-babel-lua-eoe-indicator t body)
-                 (funcall input-body body)
-                 (funcall send-wait) (funcall send-wait)
-                 (insert org-babel-lua-eoe-indicator)
-                 (funcall send-wait))
-               2) "\n"))
-            (`value
-             (let ((tmp-file (org-babel-temp-file "lua-")))
-               (org-babel-comint-with-output
-                   (session org-babel-lua-eoe-indicator nil body)
-                 (let ((comint-process-echoes nil))
-                   (funcall input-body body)
-                   (funcall dump-last-value tmp-file
-                            (member "pp" result-params))
-                   (funcall send-wait) (funcall send-wait)
-                   (insert org-babel-lua-eoe-indicator)
-                   (funcall send-wait)))
-               (org-babel-eval-read-file tmp-file))))))
-    (unless (string= (substring org-babel-lua-eoe-indicator 1 -1) results)
-      (org-babel-result-cond result-params
-	results
-        (org-babel-lua-table-or-string results)))))
-
-(defun org-babel-lua-read-string (string)
-  "Strip single quotes from around Lua STRING."
-  (org-unbracket-string "'" "'" string))
-
 (provide 'ob-lua)
 
 ;;; ob-lua.el ends here
diff --git a/testing/lisp/test-ob-lua.el b/testing/lisp/test-ob-lua.el
index ff69f5411..58a120e25 100644
--- a/testing/lisp/test-ob-lua.el
+++ b/testing/lisp/test-ob-lua.el
@@ -182,6 +182,15 @@ return x
           (org-test-with-temp-text "src_lua{return 'A \" B'}"
             (org-babel-execute-src-block)))))
 
+(ert-deftest test-ob-lua/no-sessions ()
+  (should
+   (equal
+    '(user-error "Sessions not supported for Lua")
+    (should-error
+     (org-test-with-temp-text "src_lua[:session 1]{}"
+       (org-babel-execute-src-block))
+     :type 'user-error))))
+
 (provide 'test-ob-lua)
 
 ;;; test-ob-lua.el ends here
-- 
2.39.3 (Apple Git-146)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0004-ob-lua-Improve-documentation-strings-and-commentary.patch --]
[-- Type: text/x-patch, Size: 3275 bytes --]

From 01ce86a80530eb70ea0213a9896e4dbb1aadca63 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rudolf=20Adamkovi=C4=8D?= <rudolf@adamkovic.org>
Date: Fri, 14 Jun 2024 17:47:17 +0200
Subject: [PATCH 4/4] ob-lua: Improve documentation strings and commentary

* lisp/ob-lua.el (org-babel-lua-mode):
(org-babel-lua-hline-to):
(org-babel-lua-None-to):
(org-babel-lua-var-to-lua):
(org-babel-lua-table-or-string):
(org-babel-lua-evaluate-external-process): Harmonize spelling,
capitalization, and quoting.
---
 lisp/ob-lua.el | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/lisp/ob-lua.el b/lisp/ob-lua.el
index f36c726df..826273e1f 100644
--- a/lisp/ob-lua.el
+++ b/lisp/ob-lua.el
@@ -23,7 +23,7 @@
 
 ;;; Commentary:
 
-;; Org-Babel support for evaluating lua source code.
+;; Org Babel support for evaluating Lua source code.
 
 ;;; Code:
 
@@ -51,7 +51,7 @@
   :type 'string)
 
 (defcustom org-babel-lua-mode 'lua-mode
-  "Preferred lua mode for use in running lua interactively.
+  "Preferred Lua mode for use in running Lua interactively.
 This will typically be `lua-mode'."
   :group 'org-babel
   :version "26.1"
@@ -59,14 +59,14 @@ This will typically be `lua-mode'."
   :type 'symbol)
 
 (defcustom org-babel-lua-hline-to "None"
-  "Replace hlines in incoming tables with this when translating to lua."
+  "Replace `hlines' in incoming tables with this when translating to Lua."
   :group 'org-babel
   :version "26.1"
   :package-version '(Org . "8.3")
   :type 'string)
 
 (defcustom org-babel-lua-None-to 'hline
-  "Replace `None' in lua tables with this before returning."
+  "Replace `None' in Lua tables with this before returning."
   :group 'org-babel
   :version "26.1"
   :package-version '(Org . "8.3")
@@ -115,8 +115,8 @@ The variable definitions are defining in PARAMS."
    (org-babel--get-vars params)))
 
 (defun org-babel-lua-var-to-lua (var)
-  "Convert an elisp value to a lua variable.
-Convert an elisp value, VAR, into a string of lua source code
+  "Convert an Emacs Lisp value to a Lua variable.
+Convert an Emacs Lisp value, VAR, into a string of Lua source code
 specifying a variable of the same value."
   (if (listp var)
       (if (and (= 1 (length var)) (not (listp (car var))))
@@ -136,9 +136,9 @@ specifying a variable of the same value."
        (if (stringp var) (substring-no-properties var) var)))))
 
 (defun org-babel-lua-table-or-string (results)
-  "Convert RESULTS into an appropriate elisp value.
+  "Convert RESULTS into an appropriate Emacs Lisp value.
 If the results look like a list or tuple, then convert them into an
-Emacs-lisp table, otherwise return the results as a string."
+Emacs Lisp table, otherwise return the results as a string."
   (let ((res (org-babel-script-escape results)))
     (if (listp res)
         (mapcar (lambda (el) (if (eq el 'None)
@@ -210,7 +210,7 @@ output:close()")
   "Evaluate BODY in external Lua process.
 If RESULT-TYPE equals `output' then return standard output as a
 string.  If RESULT-TYPE equals `value' then return the value of the
-last statement in BODY, as elisp.
+last statement in BODY, as Emacs Lisp.
 RESULT-PARAMS list all the :result header arg parameters.
 PREAMBLE string is appended to BODY."
   (let ((raw
-- 
2.39.3 (Apple Git-146)


[-- Attachment #6: Type: text/plain, Size: 311 bytes --]

-- 
"Programming reliably -- must be an activity of an undeniably
mathematical nature […] You see, mathematics is about thinking, and
doing mathematics is always trying to think as well as possible."
--- Edsger W. Dijkstra, 1981

Rudolf Adamkovič <rudolf@adamkovic.org> [he/him]
http://adamkovic.org

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-06-14 17:41                       ` Rudolf Adamkovič
@ 2024-06-14 17:48                         ` Rudolf Adamkovič
  2024-06-14 17:58                           ` Ihor Radchenko
  2024-06-14 21:20                           ` Rudolf Adamkovič
  0 siblings, 2 replies; 26+ messages in thread
From: Rudolf Adamkovič @ 2024-06-14 17:48 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Max Nikulin, emacs-orgmode

Rudolf Adamkovič <rudolf@adamkovic.org> writes:

> In the attached patchset, I address [...]

Oh, wait.  I forgot about the big patch I already sent to you.  Ha-ha!
Hold your horses, then; I will resolve all conflicts and send a patchset
that can be applied cleanly, end-to-end.

#StillCooking :)

Rudy
-- 
"It is far better to have a question that can't be answered than an answer that
can't be questioned."
--- Carl Sagan

Rudolf Adamkovič <rudolf@adamkovic.org> [he/him]
http://adamkovic.org


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-06-14 17:48                         ` Rudolf Adamkovič
@ 2024-06-14 17:58                           ` Ihor Radchenko
  2024-06-14 20:13                             ` Rudolf Adamkovič
  2024-06-14 21:20                           ` Rudolf Adamkovič
  1 sibling, 1 reply; 26+ messages in thread
From: Ihor Radchenko @ 2024-06-14 17:58 UTC (permalink / raw)
  To: Rudolf Adamkovič; +Cc: Max Nikulin, emacs-orgmode

Rudolf Adamkovič <rudolf@adamkovic.org> writes:

> Rudolf Adamkovič <rudolf@adamkovic.org> writes:
>
>> In the attached patchset, I address [...]
>
> Oh, wait.  I forgot about the big patch I already sent to you.  Ha-ha!
> Hold your horses, then; I will resolve all conflicts and send a patchset
> that can be applied cleanly, end-to-end.

Ok. So be it ...
git branch -d piem/ra/ob-lua-escape-double-quoteJun14

:)

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-06-14 17:58                           ` Ihor Radchenko
@ 2024-06-14 20:13                             ` Rudolf Adamkovič
  2024-06-14 20:18                               ` Ihor Radchenko
  0 siblings, 1 reply; 26+ messages in thread
From: Rudolf Adamkovič @ 2024-06-14 20:13 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Max Nikulin, emacs-orgmode

Ihor Radchenko <yantar92@posteo.net> writes:

> :)

Ihor, after banging my head against the desk for a while, I noticed that
the "separator problem" I am fighting is not Lua-specific:

src_elisp{"a, b"} {{{results(=a\, b=)}}}

Is the escaped comma in the 'results' a bug or a feature?

If it is a feature, let me know, and I will expect it in the tests.  If
not, then I will have to rewrite some of my tests using the verbose
'#+BEGIN_SRC' and '#+END_SRC' blocks instead of using 'src_lua'.

Rudy
-- 
"We shall not cease from exploration
 And the end of all our exploring
 Will be to arrive where we started
 And know the place for the first time"
--- T. S. Eliot, Little Gidding, Four Quarters, 1943

Rudolf Adamkovič <rudolf@adamkovic.org> [he/him]
http://adamkovic.org


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-06-14 20:13                             ` Rudolf Adamkovič
@ 2024-06-14 20:18                               ` Ihor Radchenko
  2024-06-14 20:37                                 ` Rudolf Adamkovič
  0 siblings, 1 reply; 26+ messages in thread
From: Ihor Radchenko @ 2024-06-14 20:18 UTC (permalink / raw)
  To: Rudolf Adamkovič; +Cc: Max Nikulin, emacs-orgmode

Rudolf Adamkovič <rudolf@adamkovic.org> writes:

> Ihor, after banging my head against the desk for a while, I noticed that
> the "separator problem" I am fighting is not Lua-specific:
>
> src_elisp{"a, b"} {{{results(=a\, b=)}}}
>
> Is the escaped comma in the 'results' a bug or a feature?

It is not a bug or feature. It is syntax of Org mode macros. Commas
separate macro arguments and must be escaped otherwise.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-06-14 20:18                               ` Ihor Radchenko
@ 2024-06-14 20:37                                 ` Rudolf Adamkovič
  0 siblings, 0 replies; 26+ messages in thread
From: Rudolf Adamkovič @ 2024-06-14 20:37 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Max Nikulin, emacs-orgmode

Ihor Radchenko <yantar92@posteo.net> writes:

> It is not a bug or feature. It is syntax of Org mode macros. Commas
> separate macro arguments and must be escaped otherwise.

It transcendents both bugs and features. :)

I will consider it a feature then (as per the traditional terminology,
where a "feature" means "works as specified"), and so I will expect the
commas in my tests.

Thank you, Ihor!

Rudy
-- 
"Music is the mathematics of the sense, mathematics is the music of the reason."
--- James Joseph Sylvester, 1814-1897

Rudolf Adamkovič <rudolf@adamkovic.org> [he/him]
http://adamkovic.org


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] ob-lua: Support all types and multiple values in results
  2024-06-14 17:48                         ` Rudolf Adamkovič
  2024-06-14 17:58                           ` Ihor Radchenko
@ 2024-06-14 21:20                           ` Rudolf Adamkovič
  1 sibling, 0 replies; 26+ messages in thread
From: Rudolf Adamkovič @ 2024-06-14 21:20 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Max Nikulin, emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 480 bytes --]

Rudolf Adamkovič <rudolf@adamkovic.org> writes:

> #StillCooking :)

All right, here we go!  5 patches, all based on top of the head
(73da6beb5) of `main' as of today (2024-06-14), in order:

0. [main, as of today]
1. ob-lua: Escape double quote characters in results
2. ob-lua: Sort tabular results
3. ob-lua: Remove half-baked session support
4. ob-lua: Improve documentation strings and commentary
5. ob-lua: Do not confuse list-like strings with lists

Rudy


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-ob-lua-Escape-double-quote-characters-in-results.patch --]
[-- Type: text/x-patch, Size: 1635 bytes --]

From 6dcca348337c05d33d62da6eeb1f4193b73f4d6e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rudolf=20Adamkovi=C4=8D?= <rudolf@adamkovic.org>
Date: Fri, 14 Jun 2024 16:55:24 +0200
Subject: [PATCH 1/5] ob-lua: Escape double quote characters in results

* lisp/ob-lua.el (org-babel-lua-wrapper-method): Escape all double
quote characters in Lua before giving them to Org Babel.
* testing/lisp/test-ob-lua.el (test-ob-lua/escaping-quotes): Test
automatic escaping of double quote characters.

Reported-by: Max Nikulin <manikulin@gmail.com>
Link: https://list.orgmode.org/216278dc-075c-47d1-94dc-f5bde8346b3c@gmail.com/
---
 lisp/ob-lua.el              | 2 +-
 testing/lisp/test-ob-lua.el | 6 ++++++
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/lisp/ob-lua.el b/lisp/ob-lua.el
index 041abfabc..0168bc070 100644
--- a/lisp/ob-lua.el
+++ b/lisp/ob-lua.el
@@ -283,7 +283,7 @@ function dump(it, indent)
       end
       return result
    else
-      return tostring(it)
+      return string.gsub(tostring(it), '\"', '\\\"')
    end
 end
 
diff --git a/testing/lisp/test-ob-lua.el b/testing/lisp/test-ob-lua.el
index 0a60c68ca..ff69f5411 100644
--- a/testing/lisp/test-ob-lua.el
+++ b/testing/lisp/test-ob-lua.el
@@ -176,6 +176,12 @@ return x
             (org-test-with-temp-text "src_lua{return 1, 2, 3}"
               (org-babel-execute-src-block))))))
 
+(ert-deftest test-ob-lua/escaping-quotes ()
+  (should
+   (equal "A \" B"
+          (org-test-with-temp-text "src_lua{return 'A \" B'}"
+            (org-babel-execute-src-block)))))
+
 (provide 'test-ob-lua)
 
 ;;; test-ob-lua.el ends here
-- 
2.39.3 (Apple Git-146)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-ob-lua-Sort-tabular-results.patch --]
[-- Type: text/x-patch, Size: 1251 bytes --]

From 93acae0704e873168f27d304901cde8fd9524dd3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rudolf=20Adamkovi=C4=8D?= <rudolf@adamkovic.org>
Date: Fri, 14 Jun 2024 16:59:37 +0200
Subject: [PATCH 2/5] ob-lua: Sort tabular results

`test-ob-lua/colnames-yes-header-argument-pp' fails intermittently due
to tabular results being returned from Lua to Emacs Lisp in different
order than expected.  We fix the problem by sorting all tabular
results before returning them.

* lisp/ob-lua.el (org-babel-lua-wrapper-method): Sort all tabular
results, recursively, before returning them from Lua to Emacs Lisp.
---
 lisp/ob-lua.el | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/lisp/ob-lua.el b/lisp/ob-lua.el
index 0168bc070..b2eb46c07 100644
--- a/lisp/ob-lua.el
+++ b/lisp/ob-lua.el
@@ -270,7 +270,13 @@ function dump(it, indent)
       if #indent ~= 0 then
          result = result .. '\\n'
       end
-      for key, value in pairs(it) do
+      local keys = {}
+      for key in pairs(it) do
+        table.insert(keys, key)
+      end
+      table.sort(keys)
+      for _, key in pairs(keys) do
+         local value = it[key]
          result = result
             .. indent
             .. dump(key)
-- 
2.39.3 (Apple Git-146)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0003-ob-lua-Remove-half-baked-session-support.patch --]
[-- Type: text/x-patch, Size: 12106 bytes --]

From d7034c49212af85c141391bf1dbb5e891aea30ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rudolf=20Adamkovi=C4=8D?= <rudolf@adamkovic.org>
Date: Fri, 14 Jun 2024 17:36:19 +0200
Subject: [PATCH 3/5] ob-lua: Remove half-baked session support

* lisp/ob-lua.el (org-babel-execute:lua):
(org-babel-prep-session:lua):
(org-babel-load-session:lua):
(org-babel-lua-session-buffer):
(org-babel-lua-with-earmuffs):
(org-babel-session-buffer:lua):
(org-babel-lua-without-earmuffs):
(lua-default-interpreter):
(lua-which-bufname):
(lua-shell-buffer-name):
(org-babel-lua-initiate-session-by-key):
(org-babel-lua-initiate-session):
(org-babel-lua-evaluate):
(org-babel-lua-evaluate-external-process):
(org-babel-lua-evaluate-session):
(org-babel-lua-read-string): Remove all unfinished Lua and Emacs Lisp
code related to sessions and emit a user error when a Lua session is
requested.
* testing/lisp/test-ob-lua.el (test-ob-lua/no-sessions): Test the user
error emitted when requesting a Lua session.

Link: https://list.orgmode.org/87y192etb4.fsf@localhost/
---
 lisp/ob-lua.el              | 205 +-----------------------------------
 testing/lisp/test-ob-lua.el |   9 ++
 2 files changed, 14 insertions(+), 200 deletions(-)

diff --git a/lisp/ob-lua.el b/lisp/ob-lua.el
index b2eb46c07..54405f898 100644
--- a/lisp/ob-lua.el
+++ b/lisp/ob-lua.el
@@ -25,15 +25,6 @@
 
 ;; Org-Babel support for evaluating lua source code.
 
-;; Requirements:
-;; for session support, lua-mode is needed.
-;; lua-mode is not part of GNU Emacs/orgmode, but can be obtained
-;; from marmalade or melpa.
-;; The source repository is here:
-;; https://github.com/immerrr/lua-mode
-
-;; However, sessions are not yet working.
-
 ;;; Code:
 
 (require 'org-macs)
@@ -90,11 +81,10 @@ This will typically be `lua-mode'."
 (defun org-babel-execute:lua (body params)
   "Execute Lua BODY according to PARAMS.
 This function is called by `org-babel-execute-src-block'."
-  (let* ((session (org-babel-lua-initiate-session
-		   (cdr (assq :session params))))
+  (let* ((session (cdr (assq :session params)))
          (result-params (cdr (assq :result-params params)))
          (result-type (cdr (assq :result-type params)))
-	 (return-val (when (and (eq result-type 'value) (not session))
+	 (return-val (when (eq result-type 'value)
 		       (cdr (assq :return params))))
 	 (preamble (cdr (assq :preamble params)))
          (full-body
@@ -102,7 +92,9 @@ This function is called by `org-babel-execute-src-block'."
 	   (concat body (if return-val (format "\nreturn %s" return-val) ""))
 	   params (org-babel-variable-assignments:lua params)))
          (result (org-babel-lua-evaluate
-		  session full-body result-type result-params preamble)))
+		  full-body result-type result-params preamble)))
+    (when (and session (not (equal session "none")))
+      (user-error "Sessions not supported for Lua"))
     (org-babel-reassemble-table
      result
      (org-babel-pick-name (cdr (assq :colname-names params))
@@ -110,28 +102,6 @@ This function is called by `org-babel-execute-src-block'."
      (org-babel-pick-name (cdr (assq :rowname-names params))
 			  (cdr (assq :rownames params))))))
 
-(defun org-babel-prep-session:lua (session params)
-  "Prepare SESSION according to the header arguments in PARAMS.
-VARS contains resolved variable references."
-  (let* ((session (org-babel-lua-initiate-session session))
-	 (var-lines
-	  (org-babel-variable-assignments:lua params)))
-    (org-babel-comint-in-buffer session
-      (mapc (lambda (var)
-              (end-of-line 1) (insert var) (comint-send-input)
-              (org-babel-comint-wait-for-output session))
-	    var-lines))
-    session))
-
-(defun org-babel-load-session:lua (session body params)
-  "Load BODY into SESSION."
-  (save-window-excursion
-    (let ((buffer (org-babel-prep-session:lua session params)))
-      (with-current-buffer buffer
-        (goto-char (process-mark (get-buffer-process (current-buffer))))
-        (insert (org-babel-chomp body)))
-      buffer)))
-
 ;; helper functions
 
 (defun org-babel-variable-assignments:lua (params)
@@ -178,76 +148,6 @@ Emacs-lisp table, otherwise return the results as a string."
 
 (defvar org-babel-lua-buffers '((:default . "*Lua*")))
 
-(defun org-babel-lua-session-buffer (session)
-  "Return the buffer associated with SESSION."
-  (cdr (assoc session org-babel-lua-buffers)))
-
-(defun org-babel-lua-with-earmuffs (session)
-  "Return buffer name for SESSION, as *SESSION*."
-  (let ((name (if (stringp session) session (format "%s" session))))
-    (if (and (string= "*" (substring name 0 1))
-	     (string= "*" (substring name (- (length name) 1))))
-	name
-      (format "*%s*" name))))
-
-(defun org-babel-session-buffer:lua (session &optional _)
-  "Return session buffer name for SESSION."
-  (or (org-babel-lua-session-buffer session)
-      (org-babel-lua-with-earmuffs session)))
-
-(defun org-babel-lua-without-earmuffs (session)
-"Remove stars around *SESSION*, leaving SESSION."
-  (let ((name (if (stringp session) session (format "%s" session))))
-    (if (and (string= "*" (substring name 0 1))
-	     (string= "*" (substring name (- (length name) 1))))
-	(substring name 1 (- (length name) 1))
-      name)))
-
-(defvar lua-default-interpreter)
-(defvar lua-which-bufname)
-(defvar lua-shell-buffer-name)
-(defun org-babel-lua-initiate-session-by-key (&optional session)
-  "Initiate a lua session.
-If there is not a current inferior-process-buffer in SESSION
-then create.  Return the initialized session."
-  ;; (require org-babel-lua-mode)
-  (save-window-excursion
-    (let* ((session (if session (intern session) :default))
-           (lua-buffer (org-babel-lua-session-buffer session))
-	   ;; (cmd (if (member system-type '(cygwin windows-nt ms-dos))
-	   ;; 	    (concat org-babel-lua-command " -i")
-	   ;; 	  org-babel-lua-command))
-	   )
-      (cond
-       ((and (eq 'lua-mode org-babel-lua-mode)
-             (fboundp 'lua-start-process)) ; lua-mode.el
-        ;; Make sure that lua-which-bufname is initialized, as otherwise
-        ;; it will be overwritten the first time a Lua buffer is
-        ;; created.
-        ;;(lua-toggle-shells lua-default-interpreter)
-        ;; `lua-shell' creates a buffer whose name is the value of
-        ;; `lua-which-bufname' with '*'s at the beginning and end
-        (let* ((bufname (if (and lua-buffer (buffer-live-p lua-buffer))
-                            (replace-regexp-in-string ;; zap surrounding *
-                             "^\\*\\([^*]+\\)\\*$" "\\1" (buffer-name lua-buffer))
-                          (concat "Lua-" (symbol-name session))))
-               (lua-which-bufname bufname))
-          (lua-start-process)
-          (setq lua-buffer (org-babel-lua-with-earmuffs bufname))))
-       (t
-	(error "No function available for running an inferior Lua")))
-      (setq org-babel-lua-buffers
-            (cons (cons session lua-buffer)
-                  (assq-delete-all session org-babel-lua-buffers)))
-      session)))
-
-(defun org-babel-lua-initiate-session (&optional session _params)
-  "Create a session named SESSION according to PARAMS."
-  (unless (string= session "none")
-    (error "Sessions currently not supported, work in progress")
-    (org-babel-lua-session-buffer
-     (org-babel-lua-initiate-session-by-key session))))
-
 (defvar org-babel-lua-eoe-indicator "--eoe"
   "A string to indicate that evaluation has completed.")
 
@@ -306,19 +206,6 @@ output:write(combine(main()))
 output:close()")
 
 (defun org-babel-lua-evaluate
-    (session body &optional result-type result-params preamble)
-  "Evaluate BODY in SESSION as Lua code.
-RESULT-TYPE and RESULT-PARAMS are passed to
-`org-babel-lua-evaluate-session' or
-`org-babel-lua-evaluate-external-process'.
-PREAMBLE is passed to `org-babel-lua-evaluate-external-process'."
-  (if session
-      (org-babel-lua-evaluate-session
-       session body result-type result-params)
-    (org-babel-lua-evaluate-external-process
-     body result-type result-params preamble)))
-
-(defun org-babel-lua-evaluate-external-process
     (body &optional result-type result-params preamble)
   "Evaluate BODY in external Lua process.
 If RESULT-TYPE equals `output' then return standard output as a
@@ -354,88 +241,6 @@ PREAMBLE string is appended to BODY."
       raw
       (org-babel-lua-table-or-string (org-trim raw)))))
 
-(defun org-babel-lua-evaluate-session
-    (session body &optional result-type result-params)
-  "Pass BODY to the Lua process in SESSION.
-If RESULT-TYPE equals `output' then return standard output as a
-string.  If RESULT-TYPE equals `value' then return the value of the
-last statement in BODY, as elisp."
-  (let* ((send-wait (lambda () (comint-send-input nil t) (sleep-for 0.005)))
-	 (dump-last-value
-	  (lambda
-	    (tmp-file pp)
-	    (mapc
-	     (lambda (statement) (insert statement) (funcall send-wait))
-	     (if pp
-		 (list
-		  "-- table to string
-function t2s(t, indent)
-   if indent == nil then
-      indent = \"\"
-   end
-   if type(t) == \"table\" then
-      ts = \"\"
-      for k,v in pairs(t) do
-         if type(v) == \"table\" then
-            ts = ts .. indent .. t2s(k,indent .. \"  \") .. \" = \\n\" ..
-               t2s(v, indent .. \"  \")
-         else
-            ts = ts .. indent .. t2s(k,indent .. \"  \") .. \" = \" ..
-               t2s(v, indent .. \"  \") .. \"\\n\"
-         end
-      end
-      return ts
-   else
-      return tostring(t)
-   end
-end
-"
-		  (concat "fd:write(_))
-fd:close()"
-			  (org-babel-process-file-name tmp-file 'noquote)))
-	       (list (format "fd=io.open(\"%s\", \"w\")
-fd:write( _ )
-fd:close()"
-			     (org-babel-process-file-name tmp-file
-                                                          'noquote)))))))
-	 (input-body (lambda (body)
-		       (mapc (lambda (line) (insert line) (funcall send-wait))
-			     (split-string body "[\r\n]"))
-		       (funcall send-wait)))
-         (results
-          (pcase result-type
-            (`output
-             (mapconcat
-              #'org-trim
-              (butlast
-               (org-babel-comint-with-output
-                   (session org-babel-lua-eoe-indicator t body)
-                 (funcall input-body body)
-                 (funcall send-wait) (funcall send-wait)
-                 (insert org-babel-lua-eoe-indicator)
-                 (funcall send-wait))
-               2) "\n"))
-            (`value
-             (let ((tmp-file (org-babel-temp-file "lua-")))
-               (org-babel-comint-with-output
-                   (session org-babel-lua-eoe-indicator nil body)
-                 (let ((comint-process-echoes nil))
-                   (funcall input-body body)
-                   (funcall dump-last-value tmp-file
-                            (member "pp" result-params))
-                   (funcall send-wait) (funcall send-wait)
-                   (insert org-babel-lua-eoe-indicator)
-                   (funcall send-wait)))
-               (org-babel-eval-read-file tmp-file))))))
-    (unless (string= (substring org-babel-lua-eoe-indicator 1 -1) results)
-      (org-babel-result-cond result-params
-	results
-        (org-babel-lua-table-or-string results)))))
-
-(defun org-babel-lua-read-string (string)
-  "Strip single quotes from around Lua STRING."
-  (org-unbracket-string "'" "'" string))
-
 (provide 'ob-lua)
 
 ;;; ob-lua.el ends here
diff --git a/testing/lisp/test-ob-lua.el b/testing/lisp/test-ob-lua.el
index ff69f5411..58a120e25 100644
--- a/testing/lisp/test-ob-lua.el
+++ b/testing/lisp/test-ob-lua.el
@@ -182,6 +182,15 @@ return x
           (org-test-with-temp-text "src_lua{return 'A \" B'}"
             (org-babel-execute-src-block)))))
 
+(ert-deftest test-ob-lua/no-sessions ()
+  (should
+   (equal
+    '(user-error "Sessions not supported for Lua")
+    (should-error
+     (org-test-with-temp-text "src_lua[:session 1]{}"
+       (org-babel-execute-src-block))
+     :type 'user-error))))
+
 (provide 'test-ob-lua)
 
 ;;; test-ob-lua.el ends here
-- 
2.39.3 (Apple Git-146)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0004-ob-lua-Improve-documentation-strings-and-commentary.patch --]
[-- Type: text/x-patch, Size: 3275 bytes --]

From 6749c0e4a1389ba4272efba02ee13fc850aa8f67 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rudolf=20Adamkovi=C4=8D?= <rudolf@adamkovic.org>
Date: Fri, 14 Jun 2024 17:47:17 +0200
Subject: [PATCH 4/5] ob-lua: Improve documentation strings and commentary

* lisp/ob-lua.el (org-babel-lua-mode):
(org-babel-lua-hline-to):
(org-babel-lua-None-to):
(org-babel-lua-var-to-lua):
(org-babel-lua-table-or-string):
(org-babel-lua-evaluate-external-process): Harmonize spelling,
capitalization, and quoting.
---
 lisp/ob-lua.el | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/lisp/ob-lua.el b/lisp/ob-lua.el
index 54405f898..10001626a 100644
--- a/lisp/ob-lua.el
+++ b/lisp/ob-lua.el
@@ -23,7 +23,7 @@
 
 ;;; Commentary:
 
-;; Org-Babel support for evaluating lua source code.
+;; Org Babel support for evaluating Lua source code.
 
 ;;; Code:
 
@@ -51,7 +51,7 @@
   :type 'string)
 
 (defcustom org-babel-lua-mode 'lua-mode
-  "Preferred lua mode for use in running lua interactively.
+  "Preferred Lua mode for use in running Lua interactively.
 This will typically be `lua-mode'."
   :group 'org-babel
   :version "26.1"
@@ -59,14 +59,14 @@ This will typically be `lua-mode'."
   :type 'symbol)
 
 (defcustom org-babel-lua-hline-to "None"
-  "Replace hlines in incoming tables with this when translating to lua."
+  "Replace `hlines' in incoming tables with this when translating to Lua."
   :group 'org-babel
   :version "26.1"
   :package-version '(Org . "8.3")
   :type 'string)
 
 (defcustom org-babel-lua-None-to 'hline
-  "Replace `None' in lua tables with this before returning."
+  "Replace `None' in Lua tables with this before returning."
   :group 'org-babel
   :version "26.1"
   :package-version '(Org . "8.3")
@@ -115,8 +115,8 @@ The variable definitions are defining in PARAMS."
    (org-babel--get-vars params)))
 
 (defun org-babel-lua-var-to-lua (var)
-  "Convert an elisp value to a lua variable.
-Convert an elisp value, VAR, into a string of lua source code
+  "Convert an Emacs Lisp value to a Lua variable.
+Convert an Emacs Lisp value, VAR, into a string of Lua source code
 specifying a variable of the same value."
   (if (listp var)
       (if (and (= 1 (length var)) (not (listp (car var))))
@@ -136,9 +136,9 @@ specifying a variable of the same value."
        (if (stringp var) (substring-no-properties var) var)))))
 
 (defun org-babel-lua-table-or-string (results)
-  "Convert RESULTS into an appropriate elisp value.
+  "Convert RESULTS into an appropriate Emacs Lisp value.
 If the results look like a list or tuple, then convert them into an
-Emacs-lisp table, otherwise return the results as a string."
+Emacs Lisp table, otherwise return the results as a string."
   (let ((res (org-babel-script-escape results)))
     (if (listp res)
         (mapcar (lambda (el) (if (eq el 'None)
@@ -210,7 +210,7 @@ output:close()")
   "Evaluate BODY in external Lua process.
 If RESULT-TYPE equals `output' then return standard output as a
 string.  If RESULT-TYPE equals `value' then return the value of the
-last statement in BODY, as elisp.
+last statement in BODY, as Emacs Lisp.
 RESULT-PARAMS list all the :result header arg parameters.
 PREAMBLE string is appended to BODY."
   (let ((raw
-- 
2.39.3 (Apple Git-146)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: 0005-ob-lua-Do-not-confuse-list-like-strings-with-lists.patch --]
[-- Type: text/x-patch, Size: 14747 bytes --]

From d9c61349d2cc6b07460fd9078c2ca29aef20b999 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rudolf=20Adamkovi=C4=8D?= <rudolf@adamkovic.org>
Date: Fri, 14 Jun 2024 22:43:15 +0200
Subject: [PATCH 5/5] ob-lua: Do not confuse list-like strings with lists

* lisp/ob-lua.el (org-babel-lua-wrapper-method): Prevent Org Babel
from confusing strings that look like lists with actual lists.
* testing/lisp/test-ob-lua.el (test-ob-lua/result/none):
(test-ob-lua/result/nil):
(test-ob-lua/result/nil/multiple):
(test-ob-lua/result/boolean):
(test-ob-lua/results/number/integer):
(test-ob-lua/results/number/integer/negative):
(test-ob-lua/results/number/integer/multiple):
(test-ob-lua/results/number/real):
(test-ob-lua/results/number/real/multiple):
(test-ob-lua/results/number/infinity):
(test-ob-lua/results/string/single-quotes):
(test-ob-lua/results/string/double-quotes):
(test-ob-lua/results/string/multiple):
(test-ob-lua/results/string/list-like):
(test-ob-lua/results/string/list-like/brackets):
(test-ob-lua/results/string/list-like/curlies):
(test-ob-lua/results/string/list-like/multiple):
(test-ob-lua/result/table):
(test-ob-lua/result/table/pretty-print):
(test-ob-lua/result/table/pretty-print/sorted):
(test-ob-lua/results/value-separator): Add new tests.
---
 lisp/ob-lua.el              |  28 +++-
 testing/lisp/test-ob-lua.el | 289 ++++++++++++++++++++++++++++++++----
 2 files changed, 279 insertions(+), 38 deletions(-)

diff --git a/lisp/ob-lua.el b/lisp/ob-lua.el
index 10001626a..f7950eadd 100644
--- a/lisp/ob-lua.el
+++ b/lisp/ob-lua.el
@@ -161,32 +161,33 @@ function dump(it, indent)
    if indent == nil then
       indent = ''
    end
+
    if type(it) == 'table' and %s then
-      local count = 0
-      for _ in pairs(it) do
-         count = count + 1
-      end
       local result = ''
+
       if #indent ~= 0 then
          result = result .. '\\n'
       end
+
       local keys = {}
       for key in pairs(it) do
         table.insert(keys, key)
       end
+
       table.sort(keys)
-      for _, key in pairs(keys) do
+
+      for index, key in pairs(keys) do
          local value = it[key]
          result = result
             .. indent
             .. dump(key)
             .. ' = '
             .. dump(value, indent .. '  ')
-         count = count - 1
-         if count ~= 0 then
+         if index ~= #keys then
             result = result .. '\\n'
          end
       end
+
       return result
    else
       return string.gsub(tostring(it), '\"', '\\\"')
@@ -195,10 +196,21 @@ end
 
 function combine(...)
   local result = {}
+
   for index = 1, select('#', ...) do
     result[index] = dump(select(index, ...))
   end
-  return table.concat(result, '%s')
+
+  if #result == 1 then
+    local value = result[1]
+    if string.find(value, '[%%(%%[{]') == 1 then
+      return '\"' .. value .. '\"'
+    else
+      return value
+    end
+  end
+
+  return '\"' .. table.concat(result, '%s') .. '\"'
 end
 
 output = io.open('%s', 'w')
diff --git a/testing/lisp/test-ob-lua.el b/testing/lisp/test-ob-lua.el
index 58a120e25..48648d1c7 100644
--- a/testing/lisp/test-ob-lua.el
+++ b/testing/lisp/test-ob-lua.el
@@ -136,45 +136,274 @@ return x
 	    (org-babel-next-src-block)
 	    (org-babel-execute-src-block)))))
 
-(ert-deftest test-ob-lua/types ()
-  "Test returning different types."
+(ert-deftest test-ob-lua/result/none ()
+  "Test returning nothing."
   (should
-   (equal "nil"
-          (org-test-with-temp-text "src_lua{return nil}"
-            (org-babel-execute-src-block))))
+   (equal
+    ;; FIXME Update `ob-core' to output e.g. "{{{results(n/a)}}}" or
+    ;; "{{{results(/no results/)}}}", for the empty verbatim breaks
+    ;; e.g. HTML export.
+    "src_lua{return} {{{results(==)}}}"
+    (org-test-with-temp-text "src_lua{return}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/result/nil ()
+  "Test returning nothing."
   (should
-   (equal "true"
-          (org-test-with-temp-text "src_lua{return true}"
-            (org-babel-execute-src-block))))
+   (equal
+    "src_lua{return nil} {{{results(=nil=)}}}"
+    (org-test-with-temp-text "src_lua{return nil}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/result/nil/multiple ()
+  "Test returning multiple nothings."
+  (should
+   (equal
+    "src_lua{return nil, nil} {{{results(=nil\\, nil=)}}}"
+    (org-test-with-temp-text "src_lua{return nil, nil}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/result/boolean ()
+  "Test returning the boolean values true and false."
   (should
-   (equal "false"
-          (org-test-with-temp-text "src_lua{return false}"
-            (org-babel-execute-src-block))))
+   (equal
+    "src_lua{return true} {{{results(=true=)}}}"
+    (org-test-with-temp-text "src_lua{return true}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max)))))
   (should
-   (equal 1
-          (org-test-with-temp-text "src_lua{return 1}"
-            (org-babel-execute-src-block))))
+   (equal
+    "src_lua{return false} {{{results(=false=)}}}"
+    (org-test-with-temp-text "src_lua{return false}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/number/integer ()
+  "Test returning integers."
   (should
-   (equal "hello world"
-          (org-test-with-temp-text "src_lua{return 'hello world'}"
-            (org-babel-execute-src-block))))
+   (equal
+    "src_lua{return 1} {{{results(=1=)}}}"
+    (org-test-with-temp-text "src_lua{return 1}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/number/integer/negative ()
+  "Test returning negative integers."
   (should
-   (equal 0
-          (string-match "table: 0x[0-9A-F]+"
-                        (org-test-with-temp-text "src_lua{return {}}"
-                          (org-babel-execute-src-block))))))
+   (equal
+    "src_lua{return -1} {{{results(=-1=)}}}"
+    (org-test-with-temp-text "src_lua{return -1}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
 
-(ert-deftest test-ob-lua/multiple-values ()
-  "Test returning multiple values."
+(ert-deftest test-ob-lua/results/number/integer/multiple ()
+  "Test returning multiple integers at once."
   (should
-   (equal "1, 2, 3"
-          (org-test-with-temp-text "src_lua{return 1, 2, 3}"
-            (org-babel-execute-src-block))))
+   (equal
+    "src_lua{return 1, 2, 3} {{{results(=1\\, 2\\, 3=)}}}"
+    (org-test-with-temp-text "src_lua{return 1, 2, 3}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/number/real ()
+  "Test returning real numbers."
+  (should
+   (equal
+    "src_lua{return 1.5} {{{results(=1.5=)}}}"
+    (org-test-with-temp-text "src_lua{return 1.5}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/number/real/multiple ()
+  "Test returning multiple real numbers at once."
+  (should
+   (equal
+    "src_lua{return 1.5, 2.5, 3.5} {{{results(=1.5\\, 2.5\\, 3.5=)}}}"
+    (org-test-with-temp-text "src_lua{return 1.5, 2.5, 3.5}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/number/infinity ()
+  "Test returning the infinity."
+  (should
+   (equal
+    "src_lua{return 1 / 0} {{{results(=inf=)}}}"
+    (org-test-with-temp-text "src_lua{return 1 / 0}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/single-quotes ()
+  "Test returning strings in single quotes."
+  (should
+   (equal
+    "src_lua{return 'hello world'} {{{results(=hello world=)}}}"
+    (org-test-with-temp-text "src_lua{return 'hello world'}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/double-quotes ()
+  "Test returning strings in double quotes."
   (should
-   (equal "1|2|3"
-          (let ((org-babel-lua-multiple-values-separator "|"))
-            (org-test-with-temp-text "src_lua{return 1, 2, 3}"
-              (org-babel-execute-src-block))))))
+   (equal
+    "src_lua{return \"hello world\"} {{{results(=hello world=)}}}"
+    (org-test-with-temp-text "src_lua{return \"hello world\"}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/multiple ()
+  "Test returning multiple strings at once."
+  (should
+   (equal
+    "src_lua{return 'a', 'b'} {{{results(=a\\, b=)}}}"
+    (org-test-with-temp-text "src_lua{return 'a', 'b'}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/list-like ()
+  "Test returning strings that look like \"(...)\" lists."
+  (should
+   (equal
+    (concat "src_lua{return string.match('A (B) C', '%b()')}"
+            " {{{results(=(B)=)}}}")
+    (org-test-with-temp-text
+        "src_lua{return string.match('A (B) C', '%b()')}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/list-like/brackets ()
+  "Test returning strings that look like \"[...]\" lists."
+  (should
+   (equal
+    (concat "src_lua{return string.match('A [B] C', '%b[]')}"
+            " {{{results(=[B]=)}}}")
+    (org-test-with-temp-text
+        "src_lua{return string.match('A [B] C', '%b[]')}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/list-like/curlies ()
+  "Test returning strings that look like \"{...}\" lists."
+  (should
+   (equal
+    (concat "src_lua{return string.match('A {B} C', '%b{}')}"
+            " {{{results(={B}=)}}}")
+    (org-test-with-temp-text
+	"src_lua{return string.match('A {B} C', '%b{}')}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/results/string/list-like/multiple ()
+  "Test returning multiple strings that look like \"(...)\" lists."
+  (should
+   (equal
+    (concat "src_lua{return '(A)', '(B)'}"
+            " {{{results(=(A)\\, (B)=)}}}")
+    (org-test-with-temp-text
+        "src_lua{return '(A)', '(B)'}"
+      (org-babel-execute-src-block)
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
+
+(ert-deftest test-ob-lua/result/table ()
+  "Test returning table references."
+  (should
+   (equal
+    0
+    (string-match
+     "src_lua{return {}} {{{results(=table: 0x[0-9A-F]+=)}}}"
+     (org-test-with-temp-text "src_lua{return {}}"
+       (org-babel-execute-src-block)
+       (buffer-substring-no-properties (point-min)
+                                       (point-max)))))))
+
+(ert-deftest test-ob-lua/result/table/pretty-print ()
+  "Test returning and pretty-printing sequential tables."
+  (should
+   (equal (string-join
+           '("#+BEGIN_SRC lua :results pp"
+             "return {10, {20, 30, {40, 50}, 60}, 70}"
+             "#+END_SRC"
+             ""
+             "#+RESULTS:"
+             ": 1 = 10"
+             ": 2 = "                   ; FIXME Trailing space.
+             ":   1 = 20"
+             ":   2 = 30"
+             ":   3 = "                 ; FIXME Trailing space.
+             ":     1 = 40"
+             ":     2 = 50"
+             ":   4 = 60"
+             ": 3 = 70"
+             "")
+           "\n")
+          (org-test-with-temp-text
+              (string-join
+               '("#+BEGIN_SRC lua :results pp"
+                 "return {10, {20, 30, {40, 50}, 60}, 70}<point>"
+                 "#+END_SRC")
+               "\n")
+	    (org-babel-execute-src-block)
+            (buffer-substring-no-properties (point-min)
+                                            (point-max))))))
+
+(ert-deftest test-ob-lua/result/table/pretty-print/sorted ()
+  "Test returning and pretty-printing non-sequential tables."
+  (should
+   (equal (string-join
+           '("#+BEGIN_SRC lua :results pp"
+             "return {b = 20, c = 30, a = 10}"
+             "#+END_SRC"
+             ""
+             "#+RESULTS:"
+             ;; NOTE The keys are sorted alphabetically.
+             ": a = 10"
+             ": b = 20"
+             ": c = 30"
+             "")
+           "\n")
+          (org-test-with-temp-text
+              (string-join
+               '("#+BEGIN_SRC lua :results pp"
+                 "return {b = 20, c = 30, a = 10}"
+                 "#+END_SRC")
+               "\n")
+	    (org-babel-execute-src-block)
+            (buffer-substring-no-properties (point-min)
+                                            (point-max))))))
+
+(ert-deftest test-ob-lua/results/value-separator ()
+  "Test customizing the separator of multiple values."
+  ;; TODO Once Org Babel supports returning lists from inline blocks,
+  ;; instead of trapping with the user error: "Inline error: list
+  ;; result cannot be used", use those for multiple values.
+  (should
+   (equal
+    "src_lua{return 1, 2, 3} {{{results(=1\t2\t3=)}}}"
+    (org-test-with-temp-text "src_lua{return 1, 2, 3}"
+      (let ((org-babel-lua-multiple-values-separator "\t"))
+        (org-babel-execute-src-block))
+      (buffer-substring-no-properties (point-min)
+                                      (point-max))))))
 
 (ert-deftest test-ob-lua/escaping-quotes ()
   (should
-- 
2.39.3 (Apple Git-146)


[-- Attachment #7: Type: text/plain, Size: 200 bytes --]

-- 
"I love deadlines.  I love the whooshing noise they make as they go by."
--- Douglas Adams, The Salmon of Doubt, 2002

Rudolf Adamkovič <rudolf@adamkovic.org> [he/him]
http://adamkovic.org

^ permalink raw reply related	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2024-06-14 21:22 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-23 16:44 [PATCH] ob-lua: Support all types and multiple values in results Rudolf Adamkovič
2024-04-23 17:05 ` Rudolf Adamkovič
2024-04-24 14:20   ` Ihor Radchenko
2024-04-24 13:05 ` Ihor Radchenko
2024-04-24 15:01   ` Rudolf Adamkovič
2024-04-26 13:40     ` Ihor Radchenko
2024-04-27 10:57       ` Max Nikulin
2024-04-27 16:33       ` Rudolf Adamkovič
2024-04-28 12:36         ` Ihor Radchenko
2024-04-29 15:57           ` Rudolf Adamkovič
2024-04-29 20:26             ` Rudolf Adamkovič
2024-04-30 10:24               ` Ihor Radchenko
2024-05-02 15:57                 ` Rudolf Adamkovič
2024-05-02 15:58                 ` Rudolf Adamkovič
2024-05-02 16:02                   ` Rudolf Adamkovič
2024-05-01 11:05               ` Max Nikulin
2024-05-02 16:00                 ` Rudolf Adamkovič
2024-05-02 16:41                   ` Ihor Radchenko
2024-06-09 20:54                     ` Rudolf Adamkovič
2024-06-14 17:41                       ` Rudolf Adamkovič
2024-06-14 17:48                         ` Rudolf Adamkovič
2024-06-14 17:58                           ` Ihor Radchenko
2024-06-14 20:13                             ` Rudolf Adamkovič
2024-06-14 20:18                               ` Ihor Radchenko
2024-06-14 20:37                                 ` Rudolf Adamkovič
2024-06-14 21:20                           ` Rudolf Adamkovič

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).