emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* ob-lua
@ 2016-08-20  5:18 Thibault Marin
  2016-08-20 16:02 ` ob-lua Nicolas Goaziou
  0 siblings, 1 reply; 12+ messages in thread
From: Thibault Marin @ 2016-08-20  5:18 UTC (permalink / raw)
  To: emacs-orgmode@gnu.org


Hi list,

I was looking for lua support in source blocks and I came across this
discussion:
https://lists.gnu.org/archive/html/emacs-orgmode/2014-05/msg01149.html.  It
seems that this was never merged, but I am not sure why.

Trying to use the ob-lua.el file linked, it appears to be working for my task (I
just need to be able to pass variables to a lua block).  I only had to make a
small change to the file to get it to work, as `org-babel-get-header' is no
longer available:

132c132
<    (mapcar #'cdr (org-babel-get-header params :var))))
---
>    (remove nil (mapcar (lambda (x) (when (eq (car x) :var) (cdr x))) params))))

There may be a better way to do it, but it seems to work.

So my question is: could this be considered for a merge?  The code does
not seem to support sessions, I am not sure if that should be a blocker.

Thanks,
thibault

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

* Re: ob-lua
  2016-08-20  5:18 ob-lua Thibault Marin
@ 2016-08-20 16:02 ` Nicolas Goaziou
  2016-08-21  4:47   ` ob-lua Thibault Marin
  0 siblings, 1 reply; 12+ messages in thread
From: Nicolas Goaziou @ 2016-08-20 16:02 UTC (permalink / raw)
  To: Thibault Marin; +Cc: emacs-orgmode@gnu.org

Hello,

Thibault Marin <thibault.marin@gmx.com> writes:

> I was looking for lua support in source blocks and I came across this
> discussion:
> https://lists.gnu.org/archive/html/emacs-orgmode/2014-05/msg01149.html.  It
> seems that this was never merged, but I am not sure why.

It looks like Bastien was waiting for a following patch, which never
happened.

> Trying to use the ob-lua.el file linked, it appears to be working for my task (I
> just need to be able to pass variables to a lua block).  I only had to make a
> small change to the file to get it to work, as `org-babel-get-header' is no
> longer available:
>
> 132c132
> <    (mapcar #'cdr (org-babel-get-header params :var))))
> ---
>>    (remove nil (mapcar (lambda (x) (when (eq (car x) :var) (cdr x))) params))))
>
> There may be a better way to do it, but it seems to work.

In this case, `org-babel-get-header' should be replaced with
`org-babel--get-vars', per ORG-NEWS.

> So my question is: could this be considered for a merge?  The code does
> not seem to support sessions, I am not sure if that should be
> a blocker.

It isn't a blocker, indeed. Could you send an updated patch? A set of
tests would be nice, too.

Thank you.


Regards,

-- 
Nicolas Goaziou

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

* Re: ob-lua
  2016-08-20 16:02 ` ob-lua Nicolas Goaziou
@ 2016-08-21  4:47   ` Thibault Marin
  2016-08-21  9:30     ` ob-lua Nicolas Goaziou
  0 siblings, 1 reply; 12+ messages in thread
From: Thibault Marin @ 2016-08-21  4:47 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode@gnu.org

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


>> There may be a better way to do it, but it seems to work.
>
> In this case, `org-babel-get-header' should be replaced with
> `org-babel--get-vars', per ORG-NEWS.

Thanks, it is much better.

>> So my question is: could this be considered for a merge?  The code does
>> not seem to support sessions, I am not sure if that should be
>> a blocker.
>
> It isn't a blocker, indeed. Could you send an updated patch? A set of
> tests would be nice, too.

I have updated the patch to use `org-babel--get-vars' as suggested.  I
also have replaced `org-babel-trim' by `org-trim' (as advised in
ORG-NEWS) and replaced the `case' statement by a `pcase' (I used
ob-python.el for reference).  Please let me know if these changes are
acceptable and if other changes are required.

About the test, I am attaching my first attempt at this, please let me
know if you have some advice on how to improve it or if you had
something else in mind.  This is the first time I use ert or org-test,
but these seem to pass and test the basic features.

By the way, when trying to run the tests from emacs, I had an error
message when doing a (require 'org-test): "let: Required feature `ert-x'
was not provided".  Am I doing something wrong?  I worked around it by
(1) installing the `ertx' package and (2) replacing (require 'ert-x) by
(require 'ertx) in org-test.el (that's probably the wrong thing to do,
but it allowed me to run my tests).

Thanks for your help.

thibault


[-- Attachment #2: test-ob-lua.el --]
[-- Type: application/emacs-lisp, Size: 3042 bytes --]

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: ob-lua.el.patch --]
[-- Type: text/x-diff, Size: 2185 bytes --]

132c132
<    (mapcar #'cdr (org-babel-get-header params :var))))
---
>    (org-babel--get-vars params)))
292,312c292,312
<          (case result-type
<            (output (org-babel-eval org-babel-lua-command
<                                    (concat (if preamble (concat preamble "\n"))
<                                            body)))
<            (value (let ((tmp-file (org-babel-temp-file "lua-")))
<                     (org-babel-eval
<                      org-babel-lua-command
<                      (concat
<                       (if preamble (concat preamble "\n") "")
<                       (format
<                        (if (member "pp" result-params)
<                            org-babel-lua-pp-wrapper-method
<                          org-babel-lua-wrapper-method)
<                        (mapconcat
<                         (lambda (line) (format "\t%s" line))
<                         (split-string
<                          (org-remove-indentation
<                           (org-babel-trim body))
<                          "[\r\n]") "\n")
<                        (org-babel-process-file-name tmp-file 'noquote))))
<                     (org-babel-eval-read-file tmp-file))))))
---
>          (pcase result-type
>            (`output (org-babel-eval org-babel-lua-command
> 				    (concat (if preamble (concat preamble "\n"))
> 					    body)))
>            (`value (let ((tmp-file (org-babel-temp-file "lua-")))
> 		     (org-babel-eval
> 		      org-babel-lua-command
> 		      (concat
> 		       (if preamble (concat preamble "\n") "")
> 		       (format
> 			(if (member "pp" result-params)
> 			    org-babel-lua-pp-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")
> 			(org-babel-process-file-name tmp-file 'noquote))))
> 		     (org-babel-eval-read-file tmp-file))))))
315c315
<       (org-babel-lua-table-or-string (org-babel-trim raw)))))
---
>       (org-babel-lua-table-or-string (org-trim raw)))))
369c369
<               #'org-babel-trim
---
>               #'org-trim

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

* Re: ob-lua
  2016-08-21  4:47   ` ob-lua Thibault Marin
@ 2016-08-21  9:30     ` Nicolas Goaziou
  2016-08-22  2:38       ` ob-lua Thibault Marin
  0 siblings, 1 reply; 12+ messages in thread
From: Nicolas Goaziou @ 2016-08-21  9:30 UTC (permalink / raw)
  To: Thibault Marin; +Cc: emacs-orgmode@gnu.org

Hello,

Thibault Marin <thibault.marin@gmx.com> writes:

> I have updated the patch to use `org-babel--get-vars' as suggested.  I
> also have replaced `org-babel-trim' by `org-trim' (as advised in
> ORG-NEWS) and replaced the `case' statement by a `pcase' (I used
> ob-python.el for reference).  Please let me know if these changes are
n> acceptable and if other changes are required.

The changes look fine. Could you send them using git format-patch, with
a proper commit message? See
<http://orgmode.org/worg/org-contribute.html#patches> for details.

> About the test, I am attaching my first attempt at this, please let me
> know if you have some advice on how to improve it or if you had
> something else in mind.  This is the first time I use ert or org-test,
> but these seem to pass and test the basic features.

Nice. Thank you. I only have a small suggestion about test structure.
See above.

> By the way, when trying to run the tests from emacs, I had an error
> message when doing a (require 'org-test): "let: Required feature `ert-x'
> was not provided".  Am I doing something wrong?  I worked around it by
> (1) installing the `ertx' package and (2) replacing (require 'ert-x) by
> (require 'ertx) in org-test.el (that's probably the wrong thing to do,
> but it allowed me to run my tests).

I usually only call "make test" from Org root directory.

> ;;; test-ob-lua.el --- tests for ob-lua.el
>
> ;; Copyright (c) 2011-2014 Eric Schulte
> ;; Authors: Eric Schulte

The information above is wrong.

> ;; This file is not part of GNU Emacs.
>
> ;; This program is free software; you can redistribute it and/or modify
> ;; it under the terms of the GNU General Public License as published by
> ;; the Free Software Foundation, either version 3 of the License, or
> ;; (at your option) any later version.
>
> ;; This program is distributed in the hope that it will be useful,
> ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
> ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> ;; GNU General Public License for more details.
>
> ;; You should have received a copy of the GNU General Public License
> ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
>
> ;;; Code:
> (unless (featurep 'ob-lua)
>   (signal 'missing-test-dependency "Support for Lua code blocks"))
>
>
> (ert-deftest test-ob-lua/simple-value ()
>   (org-test-with-temp-text "#+name: eg
> | a   | 1 |
> | b   | 2 |
>
> #+header: :results value
> #+header: :var x = eg
> #+begin_src lua
> return x['b']
> #+end_src"
>     (org-babel-next-src-block)
>     (should (equal 2 (org-babel-execute-src-block)))))

You could explain in the docstring, or in a comment, what you are
testing.

Also, I suggest to move `should' and the test on the outside of the
sexp, like this

  (ert-deftest test-ob-lua/simple-value ()
    "Test ..."
    (should
     (= 2
        (org-test-with-temp-text "#+name: eg
  | a   | 1 |
  | b   | 2 |

  #+header: :results value
  #+header: :var x = eg
  #+begin_src lua
  return x['b']
  #+end_src"
          (org-babel-next-src-block)
          (org-babel-execute-src-block)))))

This way, you can simply inspect the return value of your test by
calling `eval-last-sexp' after the parenthesis closing
(org-test-with-temp-text ...). It makes debugging easier, IMO.


Regards,

-- 
Nicolas Goaziou

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

* Re: ob-lua
  2016-08-21  9:30     ` ob-lua Nicolas Goaziou
@ 2016-08-22  2:38       ` Thibault Marin
  2016-08-22  9:28         ` ob-lua Nicolas Goaziou
  0 siblings, 1 reply; 12+ messages in thread
From: Thibault Marin @ 2016-08-22  2:38 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: Dieter Schoen, emacs-orgmode@gnu.org

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: 0001-ob-lua.el-Add-lua-support-to-org-babel.patch --]
[-- Type: text/x-diff, Size: 19158 bytes --]

From bd6e5cf8e11fc87b0e4219b7378d43ddf69de7f1 Mon Sep 17 00:00:00 2001
From: thibault <thibault.marin@gmx.com>
Date: Sun, 21 Aug 2016 20:43:37 -0500
Subject: [PATCH] ob-lua.el: Add lua support to org-babel

* contrib/lisp/ob-lua.el: Resurrect ob-lua.el from
https://lists.gnu.org/archive/html/emacs-orgmode/2014-05/msg01149.html,
replace deprecated functions `org-babel-get-header' and
`org-babel-trim' by `org-babel--get-vars' and `org-trim'
respectively.  Sessions are not supported.

* testing/test-ob-lua.el: Testing for ob-lua.el.  Test table
variable passing and results with `value' and `output' options.
---
 contrib/lisp/ob-lua.el      | 405 ++++++++++++++++++++++++++++++++++++++++++++
 testing/lisp/test-ob-lua.el | 141 +++++++++++++++
 2 files changed, 546 insertions(+)
 create mode 100644 contrib/lisp/ob-lua.el
 create mode 100644 testing/lisp/test-ob-lua.el

diff --git a/contrib/lisp/ob-lua.el b/contrib/lisp/ob-lua.el
new file mode 100644
index 0000000..a81ec66
--- /dev/null
+++ b/contrib/lisp/ob-lua.el
@@ -0,0 +1,405 @@
+;;; ob-lua.el --- org-babel functions for lua evaluation
+
+;; Copyright (C) 2009-2014 Free Software Foundation, Inc.
+
+;; Authors: Dieter Schoen
+;;	 Eric Schulte, Dan Davison
+;; Keywords: literate programming, reproducible research
+;; Homepage: http://orgmode.org
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;; 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 respository is here:
+;; https://github.com/immerrr/lua-mode
+
+;; However, sessions are not yet working.
+
+;; Org-Babel support for evaluating lua source code.
+
+;;; Code:
+(require 'ob)
+(eval-when-compile (require 'cl))
+
+(declare-function org-remove-indentation "org" )
+(declare-function lua-shell "ext:lua-mode" (&optional argprompt))
+(declare-function lua-toggle-shells "ext:lua-mode" (arg))
+(declare-function run-lua "ext:lua" (cmd &optional dedicated show))
+
+(defvar org-babel-tangle-lang-exts)
+(add-to-list 'org-babel-tangle-lang-exts '("lua" . "lua"))
+
+(defvar org-babel-default-header-args:lua '())
+
+(defcustom org-babel-lua-command "lua"
+  "Name of the command for executing Lua code."
+  :version "24.5"
+  :package-version '(Org . "8.3")
+  :group 'org-babel
+  :type 'string)
+
+(defcustom org-babel-lua-mode 'lua-mode
+  "Preferred lua mode for use in running lua interactively.
+This will typically be 'lua-mode."
+  :group 'org-babel
+  :version "24.5"
+  :package-version '(Org . "8.3")
+  :type 'symbol)
+
+(defcustom org-babel-lua-hline-to "None"
+  "Replace hlines in incoming tables with this when translating to lua."
+  :group 'org-babel
+  :version "24.5"
+  :package-version '(Org . "8.3")
+  :type 'string)
+
+(defcustom org-babel-lua-None-to 'hline
+  "Replace 'None' in lua tables with this before returning."
+  :group 'org-babel
+  :version "24.5"
+  :package-version '(Org . "8.3")
+  :type 'symbol)
+
+(defun org-babel-execute:lua (body params)
+  "Execute a block of Lua code with Babel.
+This function is called by `org-babel-execute-src-block'."
+  (let* ((session (org-babel-lua-initiate-session
+		   (cdr (assoc :session params))))
+         (result-params (cdr (assoc :result-params params)))
+         (result-type (cdr (assoc :result-type params)))
+	 (return-val (when (and (eq result-type 'value) (not session))
+		       (cdr (assoc :return params))))
+	 (preamble (cdr (assoc :preamble params)))
+         (full-body
+	  (org-babel-expand-body:generic
+	   (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)))
+    (org-babel-reassemble-table
+     result
+     (org-babel-pick-name (cdr (assoc :colname-names params))
+			  (cdr (assoc :colnames params)))
+     (org-babel-pick-name (cdr (assoc :rowname-names params))
+			  (cdr (assoc :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)
+  "Return a list of Lua statements assigning the block's variables."
+  (mapcar
+   (lambda (pair)
+     (format "%s=%s"
+	     (car pair)
+	     (org-babel-lua-var-to-lua (cdr pair))))
+   (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
+specifying a variable of the same value."
+  (if (listp var)
+      (if (and (= 1 (length var)) (not (listp (car var))))
+          (org-babel-lua-var-to-lua (car var))
+        (if (and
+             (= 2 (length var))
+             (not (listp (car var))))
+            (concat
+             (substring-no-properties (car var))
+             "="
+             (org-babel-lua-var-to-lua (cdr var)))
+          (concat "{" (mapconcat #'org-babel-lua-var-to-lua var ", ") "}")))
+    (if (equal var 'hline)
+        org-babel-lua-hline-to
+      (format
+       (if (and (stringp var) (string-match "[\n\r]" var)) "\"\"%S\"\"" "%S")
+       (if (stringp var) (substring-no-properties var) var)))))
+
+(defun org-babel-lua-table-or-string (results)
+  "Convert RESULTS into an appropriate elisp 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."
+  (let ((res (org-babel-script-escape results)))
+    (if (listp res)
+        (mapcar (lambda (el) (if (equal el 'None)
+                            org-babel-lua-None-to el))
+                res)
+      res)))
+
+(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)
+  (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-lua-without-earmuffs (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-process-buffer
+                                 (buffer-live-p lua-process-buffer))
+                            (replace-regexp-in-string ;; zap surrounding *
+                             "^\\*\\([^*]+\\)\\*$" "\\1" (buffer-name lua-process-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-process-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.")
+
+(defvar org-babel-lua-wrapper-method
+  "
+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)
+   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
+
+
+function main()
+%s
+end
+
+fd=io.open(\"%s\", \"w\")
+fd:write(t2s(main()))
+fd:close()")
+
+(defun org-babel-lua-evaluate
+  (session body &optional result-type result-params preamble)
+  "Evaluate BODY as Lua code."
+  (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
+string.  If RESULT-TYPE equals 'value then return the value of the
+last statement in BODY, as elisp."
+  (let ((raw
+         (pcase result-type
+           (`output (org-babel-eval org-babel-lua-command
+				    (concat (if preamble (concat preamble "\n"))
+					    body)))
+           (`value (let ((tmp-file (org-babel-temp-file "lua-")))
+		     (org-babel-eval
+		      org-babel-lua-command
+		      (concat
+		       (if preamble (concat preamble "\n") "")
+		       (format
+			(if (member "pp" result-params)
+			    org-babel-lua-pp-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")
+			(org-babel-process-file-name tmp-file 'noquote))))
+		     (org-babel-eval-read-file tmp-file))))))
+    (org-babel-result-cond result-params
+      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 5)))
+	 (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
+"
+		  (format "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
+          (case 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 's from around Lua string."
+  (if (string-match "^'\\([^\000]+\\)'$" string)
+      (match-string 1 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
new file mode 100644
index 0000000..d0c1302
--- /dev/null
+++ b/testing/lisp/test-ob-lua.el
@@ -0,0 +1,141 @@
+;;; test-ob-lua.el --- tests for ob-lua.el
+
+;; Copyright (c) 2016 Thibault Marin
+;; Authors: Thibault Marin
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+(unless (featurep 'ob-lua)
+  (signal 'missing-test-dependency "Support for Lua code blocks"))
+
+(ert-deftest test-ob-lua/simple-value ()
+  "Test associative array return by value."
+  (should
+   (= 2
+      (org-test-with-temp-text
+	  "#+name: eg
+| a   | 1 |
+| b   | 2 |
+
+#+header: :results value
+#+header: :var x = eg
+#+begin_src lua
+return x['b']
+#+end_src"
+        (org-babel-next-src-block)
+        (org-babel-execute-src-block)))))
+
+(ert-deftest test-ob-lua/simple-output ()
+  "Test text output from table."
+  (should
+   (equal "result: c\n"
+	  (org-test-with-temp-text
+	      "#+name: eg
+| a | b | c | d |
+
+#+header: :results output
+#+header: :var x = eg
+#+begin_src lua
+print('result: ' .. x[1][3])
+#+end_src"
+	    (org-babel-next-src-block)
+	    (org-babel-execute-src-block)))))
+
+
+(ert-deftest test-ob-lua/colnames-yes-header-argument ()
+  "Test table passing with `colnames' header."
+  (should
+   (equal "a"
+	  (org-test-with-temp-text
+	      "#+name: eg
+| col |
+|-----|
+| a   |
+| b   |
+
+#+header: :colnames yes
+#+header: :var x = eg
+#+begin_src lua
+return x[1]
+#+end_src"
+	    (org-babel-next-src-block)
+	    (org-babel-execute-src-block)))))
+
+
+(ert-deftest test-ob-lua/colnames-yes-header-argument-pp ()
+  "Test table passing with `colnames' header and pp option."
+  (should
+   (equal "a = 12\nb = 13\n"
+	  (org-test-with-temp-text
+	      "#+name: eg
+| col | val |
+|-----+-----|
+| a   |  12 |
+| b   |  13 |
+
+#+header: :results value pp
+#+header: :colnames yes
+#+header: :var x = eg
+#+begin_src lua
+return x
+#+end_src"
+	    (org-babel-next-src-block)
+	    (org-babel-execute-src-block)))))
+
+(ert-deftest test-ob-lua/colnames-nil-header-argument ()
+  "Test table with `colnames' set to `nil'."
+  (should
+   (equal "1 = a\n2 = b\n"
+	  (org-test-with-temp-text
+	      "#+name: eg
+| col |
+|-----|
+| a   |
+| b   |
+
+#+header: :colnames nil
+#+header: :var x = eg
+#+header: :results value pp
+#+begin_src lua
+return x
+#+end_src"
+	    (org-babel-next-src-block)
+	    (org-babel-execute-src-block)))))
+
+(ert-deftest test-ob-lua/colnames-no-header-argument ()
+  "Test table passing without `colnames'."
+  (should
+   (equal "1 = col\n2 = a\n3 = b\n"
+	  (org-test-with-temp-text
+	      "#+name: eg
+| col |
+|-----|
+| a   |
+| b   |
+
+#+header: :colnames no
+#+header: :var x = eg
+#+header: :results value pp
+#+begin_src lua
+return x
+#+end_src"
+	    (org-babel-next-src-block)
+	    (org-babel-execute-src-block)))))
+
+(provide 'test-ob-lua)
+
+;;; test-ob-lua.el ends here
-- 
2.8.1


[-- Attachment #2: Type: text/plain, Size: 1425 bytes --]


> The changes look fine. Could you send them using git format-patch, with
> a proper commit message? See
> <http://orgmode.org/worg/org-contribute.html#patches> for details.

The attached patch (using git format-patch) is adding test-ob-lua.el and
ob-lua.el.  My contribution to ob-lua.el is only a tiny patch on top of
Dieter's ob-lua.el but it appears as a new file in the patch, since
ob-lua.el is not currently in the repository.

>> By the way, when trying to run the tests from emacs, I had an error
>> message when doing a (require 'org-test): "let: Required feature `ert-x'
>> was not provided".  Am I doing something wrong?  I worked around it by
>> (1) installing the `ertx' package and (2) replacing (require 'ert-x) by
>> (require 'ertx) in org-test.el (that's probably the wrong thing to do,
>> but it allowed me to run my tests).
>
> I usually only call "make test" from Org root directory.

I am still a bit confused about this (make test complains about a
missing dependency for ob-lua, maybe because it is in contrib/lisp?),
but I can run the test using the command line emacs --batch command
described in testing/README, and it does not require any change to
org-test.el, so I'll run tests this way from now on.

> Also, I suggest to move `should' and the test on the outside of the
> sexp, like this

Done, thanks.

Please let me know if some other changes are needed.  Thanks for the
guidance.

thibault

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

* Re: ob-lua
  2016-08-22  2:38       ` ob-lua Thibault Marin
@ 2016-08-22  9:28         ` Nicolas Goaziou
  2016-08-22 12:56           ` ob-lua Thibault Marin
  0 siblings, 1 reply; 12+ messages in thread
From: Nicolas Goaziou @ 2016-08-22  9:28 UTC (permalink / raw)
  To: Thibault Marin; +Cc: Dieter Schoen, emacs-orgmode@gnu.org

Hello,

Thibault Marin <thibault.marin@gmx.com> writes:

> The attached patch (using git format-patch) is adding test-ob-lua.el and
> ob-lua.el.  My contribution to ob-lua.el is only a tiny patch on top of
> Dieter's ob-lua.el but it appears as a new file in the patch, since
> ob-lua.el is not currently in the repository.

That is not a problem. We can make this appear as two patches.

> I am still a bit confused about this (make test complains about a
> missing dependency for ob-lua, maybe because it is in contrib/lisp?),
> but I can run the test using the command line emacs --batch command
> described in testing/README, and it does not require any change to
> org-test.el, so I'll run tests this way from now on.

The point is to add it to core Org, not to contrib/, isn't it?

> Please let me know if some other changes are needed.  Thanks for the
> guidance.

It looks good. Thank you.

I noticed stardiviner (Cc'ed) also provides "ob-lua" on MELPA, although
Dieter's predates it.

Stardiviner, what is the status of your library wrt to the one provided
in this thread ? Is the latter a superset of yours, or are there some
features that could be merged/improved with your code?


Regards,

-- 
Nicolas Goaziou

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

* Re: ob-lua
  2016-08-22  9:28         ` ob-lua Nicolas Goaziou
@ 2016-08-22 12:56           ` Thibault Marin
  2016-08-24  2:39             ` ob-lua Thibault Marin
  0 siblings, 1 reply; 12+ messages in thread
From: Thibault Marin @ 2016-08-22 12:56 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: Dieter Schoen, emacs-orgmode@gnu.org

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


>> The attached patch (using git format-patch) is adding test-ob-lua.el and
>> ob-lua.el.  My contribution to ob-lua.el is only a tiny patch on top of
>> Dieter's ob-lua.el but it appears as a new file in the patch, since
>> ob-lua.el is not currently in the repository.
>
> That is not a problem. We can make this appear as two patches.
OK, should I send two patches then?

>
>> I am still a bit confused about this (make test complains about a
>> missing dependency for ob-lua, maybe because it is in contrib/lisp?),
>> but I can run the test using the command line emacs --batch command
>> described in testing/README, and it does not require any change to
>> org-test.el, so I'll run tests this way from now on.
>
> The point is to add it to core Org, not to contrib/, isn't it?
I wasn't sure, attached is a new patch with ob-lua in lisp/.

Thanks,
thibault


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-ob-lua.el-Add-lua-support-to-org-babel.patch --]
[-- Type: text/x-diff, Size: 19118 bytes --]

From 61dd519d763db6714be6b66ca4fdd7ddab126317 Mon Sep 17 00:00:00 2001
From: thibault <thibault.marin@gmx.com>
Date: Mon, 22 Aug 2016 07:48:06 -0500
Subject: [PATCH] ob-lua.el: Add lua support to org-babel

* lisp/ob-lua.el: Resurrect ob-lua.el from
https://lists.gnu.org/archive/html/emacs-orgmode/2014-05/msg01149.html,
replace deprecated functions `org-babel-get-header' and
`org-babel-trim' by `org-babel--get-vars' and `org-trim'
respectively.  Sessions are not supported.

* testing/test-ob-lua.el: Testing for ob-lua.el.  Test table
variable passing and results with `value' and `output' options.
---
 lisp/ob-lua.el              | 405 ++++++++++++++++++++++++++++++++++++++++++++
 testing/lisp/test-ob-lua.el | 141 +++++++++++++++
 2 files changed, 546 insertions(+)
 create mode 100644 lisp/ob-lua.el
 create mode 100644 testing/lisp/test-ob-lua.el

diff --git a/lisp/ob-lua.el b/lisp/ob-lua.el
new file mode 100644
index 0000000..a81ec66
--- /dev/null
+++ b/lisp/ob-lua.el
@@ -0,0 +1,405 @@
+;;; ob-lua.el --- org-babel functions for lua evaluation
+
+;; Copyright (C) 2009-2014 Free Software Foundation, Inc.
+
+;; Authors: Dieter Schoen
+;;	 Eric Schulte, Dan Davison
+;; Keywords: literate programming, reproducible research
+;; Homepage: http://orgmode.org
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;; 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 respository is here:
+;; https://github.com/immerrr/lua-mode
+
+;; However, sessions are not yet working.
+
+;; Org-Babel support for evaluating lua source code.
+
+;;; Code:
+(require 'ob)
+(eval-when-compile (require 'cl))
+
+(declare-function org-remove-indentation "org" )
+(declare-function lua-shell "ext:lua-mode" (&optional argprompt))
+(declare-function lua-toggle-shells "ext:lua-mode" (arg))
+(declare-function run-lua "ext:lua" (cmd &optional dedicated show))
+
+(defvar org-babel-tangle-lang-exts)
+(add-to-list 'org-babel-tangle-lang-exts '("lua" . "lua"))
+
+(defvar org-babel-default-header-args:lua '())
+
+(defcustom org-babel-lua-command "lua"
+  "Name of the command for executing Lua code."
+  :version "24.5"
+  :package-version '(Org . "8.3")
+  :group 'org-babel
+  :type 'string)
+
+(defcustom org-babel-lua-mode 'lua-mode
+  "Preferred lua mode for use in running lua interactively.
+This will typically be 'lua-mode."
+  :group 'org-babel
+  :version "24.5"
+  :package-version '(Org . "8.3")
+  :type 'symbol)
+
+(defcustom org-babel-lua-hline-to "None"
+  "Replace hlines in incoming tables with this when translating to lua."
+  :group 'org-babel
+  :version "24.5"
+  :package-version '(Org . "8.3")
+  :type 'string)
+
+(defcustom org-babel-lua-None-to 'hline
+  "Replace 'None' in lua tables with this before returning."
+  :group 'org-babel
+  :version "24.5"
+  :package-version '(Org . "8.3")
+  :type 'symbol)
+
+(defun org-babel-execute:lua (body params)
+  "Execute a block of Lua code with Babel.
+This function is called by `org-babel-execute-src-block'."
+  (let* ((session (org-babel-lua-initiate-session
+		   (cdr (assoc :session params))))
+         (result-params (cdr (assoc :result-params params)))
+         (result-type (cdr (assoc :result-type params)))
+	 (return-val (when (and (eq result-type 'value) (not session))
+		       (cdr (assoc :return params))))
+	 (preamble (cdr (assoc :preamble params)))
+         (full-body
+	  (org-babel-expand-body:generic
+	   (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)))
+    (org-babel-reassemble-table
+     result
+     (org-babel-pick-name (cdr (assoc :colname-names params))
+			  (cdr (assoc :colnames params)))
+     (org-babel-pick-name (cdr (assoc :rowname-names params))
+			  (cdr (assoc :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)
+  "Return a list of Lua statements assigning the block's variables."
+  (mapcar
+   (lambda (pair)
+     (format "%s=%s"
+	     (car pair)
+	     (org-babel-lua-var-to-lua (cdr pair))))
+   (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
+specifying a variable of the same value."
+  (if (listp var)
+      (if (and (= 1 (length var)) (not (listp (car var))))
+          (org-babel-lua-var-to-lua (car var))
+        (if (and
+             (= 2 (length var))
+             (not (listp (car var))))
+            (concat
+             (substring-no-properties (car var))
+             "="
+             (org-babel-lua-var-to-lua (cdr var)))
+          (concat "{" (mapconcat #'org-babel-lua-var-to-lua var ", ") "}")))
+    (if (equal var 'hline)
+        org-babel-lua-hline-to
+      (format
+       (if (and (stringp var) (string-match "[\n\r]" var)) "\"\"%S\"\"" "%S")
+       (if (stringp var) (substring-no-properties var) var)))))
+
+(defun org-babel-lua-table-or-string (results)
+  "Convert RESULTS into an appropriate elisp 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."
+  (let ((res (org-babel-script-escape results)))
+    (if (listp res)
+        (mapcar (lambda (el) (if (equal el 'None)
+                            org-babel-lua-None-to el))
+                res)
+      res)))
+
+(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)
+  (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-lua-without-earmuffs (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-process-buffer
+                                 (buffer-live-p lua-process-buffer))
+                            (replace-regexp-in-string ;; zap surrounding *
+                             "^\\*\\([^*]+\\)\\*$" "\\1" (buffer-name lua-process-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-process-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.")
+
+(defvar org-babel-lua-wrapper-method
+  "
+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)
+   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
+
+
+function main()
+%s
+end
+
+fd=io.open(\"%s\", \"w\")
+fd:write(t2s(main()))
+fd:close()")
+
+(defun org-babel-lua-evaluate
+  (session body &optional result-type result-params preamble)
+  "Evaluate BODY as Lua code."
+  (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
+string.  If RESULT-TYPE equals 'value then return the value of the
+last statement in BODY, as elisp."
+  (let ((raw
+         (pcase result-type
+           (`output (org-babel-eval org-babel-lua-command
+				    (concat (if preamble (concat preamble "\n"))
+					    body)))
+           (`value (let ((tmp-file (org-babel-temp-file "lua-")))
+		     (org-babel-eval
+		      org-babel-lua-command
+		      (concat
+		       (if preamble (concat preamble "\n") "")
+		       (format
+			(if (member "pp" result-params)
+			    org-babel-lua-pp-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")
+			(org-babel-process-file-name tmp-file 'noquote))))
+		     (org-babel-eval-read-file tmp-file))))))
+    (org-babel-result-cond result-params
+      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 5)))
+	 (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
+"
+		  (format "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
+          (case 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 's from around Lua string."
+  (if (string-match "^'\\([^\000]+\\)'$" string)
+      (match-string 1 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
new file mode 100644
index 0000000..d0c1302
--- /dev/null
+++ b/testing/lisp/test-ob-lua.el
@@ -0,0 +1,141 @@
+;;; test-ob-lua.el --- tests for ob-lua.el
+
+;; Copyright (c) 2016 Thibault Marin
+;; Authors: Thibault Marin
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+(unless (featurep 'ob-lua)
+  (signal 'missing-test-dependency "Support for Lua code blocks"))
+
+(ert-deftest test-ob-lua/simple-value ()
+  "Test associative array return by value."
+  (should
+   (= 2
+      (org-test-with-temp-text
+	  "#+name: eg
+| a   | 1 |
+| b   | 2 |
+
+#+header: :results value
+#+header: :var x = eg
+#+begin_src lua
+return x['b']
+#+end_src"
+        (org-babel-next-src-block)
+        (org-babel-execute-src-block)))))
+
+(ert-deftest test-ob-lua/simple-output ()
+  "Test text output from table."
+  (should
+   (equal "result: c\n"
+	  (org-test-with-temp-text
+	      "#+name: eg
+| a | b | c | d |
+
+#+header: :results output
+#+header: :var x = eg
+#+begin_src lua
+print('result: ' .. x[1][3])
+#+end_src"
+	    (org-babel-next-src-block)
+	    (org-babel-execute-src-block)))))
+
+
+(ert-deftest test-ob-lua/colnames-yes-header-argument ()
+  "Test table passing with `colnames' header."
+  (should
+   (equal "a"
+	  (org-test-with-temp-text
+	      "#+name: eg
+| col |
+|-----|
+| a   |
+| b   |
+
+#+header: :colnames yes
+#+header: :var x = eg
+#+begin_src lua
+return x[1]
+#+end_src"
+	    (org-babel-next-src-block)
+	    (org-babel-execute-src-block)))))
+
+
+(ert-deftest test-ob-lua/colnames-yes-header-argument-pp ()
+  "Test table passing with `colnames' header and pp option."
+  (should
+   (equal "a = 12\nb = 13\n"
+	  (org-test-with-temp-text
+	      "#+name: eg
+| col | val |
+|-----+-----|
+| a   |  12 |
+| b   |  13 |
+
+#+header: :results value pp
+#+header: :colnames yes
+#+header: :var x = eg
+#+begin_src lua
+return x
+#+end_src"
+	    (org-babel-next-src-block)
+	    (org-babel-execute-src-block)))))
+
+(ert-deftest test-ob-lua/colnames-nil-header-argument ()
+  "Test table with `colnames' set to `nil'."
+  (should
+   (equal "1 = a\n2 = b\n"
+	  (org-test-with-temp-text
+	      "#+name: eg
+| col |
+|-----|
+| a   |
+| b   |
+
+#+header: :colnames nil
+#+header: :var x = eg
+#+header: :results value pp
+#+begin_src lua
+return x
+#+end_src"
+	    (org-babel-next-src-block)
+	    (org-babel-execute-src-block)))))
+
+(ert-deftest test-ob-lua/colnames-no-header-argument ()
+  "Test table passing without `colnames'."
+  (should
+   (equal "1 = col\n2 = a\n3 = b\n"
+	  (org-test-with-temp-text
+	      "#+name: eg
+| col |
+|-----|
+| a   |
+| b   |
+
+#+header: :colnames no
+#+header: :var x = eg
+#+header: :results value pp
+#+begin_src lua
+return x
+#+end_src"
+	    (org-babel-next-src-block)
+	    (org-babel-execute-src-block)))))
+
+(provide 'test-ob-lua)
+
+;;; test-ob-lua.el ends here
-- 
2.8.1


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

* Re: ob-lua
  2016-08-22 12:56           ` ob-lua Thibault Marin
@ 2016-08-24  2:39             ` Thibault Marin
  2016-08-29  7:10               ` ob-lua Nicolas Goaziou
  0 siblings, 1 reply; 12+ messages in thread
From: Thibault Marin @ 2016-08-24  2:39 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: Dieter Schoen, emacs-orgmode@gnu.org

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


Hi,

Thibault Marin writes:

>>> The attached patch (using git format-patch) is adding test-ob-lua.el and
>>> ob-lua.el.  My contribution to ob-lua.el is only a tiny patch on top of
>>> Dieter's ob-lua.el but it appears as a new file in the patch, since
>>> ob-lua.el is not currently in the repository.
>>
>> That is not a problem. We can make this appear as two patches.
> OK, should I send two patches then?
>
>>
>>> I am still a bit confused about this (make test complains about a
>>> missing dependency for ob-lua, maybe because it is in contrib/lisp?),
>>> but I can run the test using the command line emacs --batch command
>>> described in testing/README, and it does not require any change to
>>> org-test.el, so I'll run tests this way from now on.
>>
>> The point is to add it to core Org, not to contrib/, isn't it?
> I wasn't sure, attached is a new patch with ob-lua in lisp/.
>
> Thanks,
> thibault

I am attaching an updated patch adding the Lua language to the CSS in
`org-html-style-default'.

If you would like me to make two separate patches, one with the original
ob-lua.el from Dieter Schoen and one with my changes and additions
(test-ob-lua.el and ox-html.el), please let me know.

Thanks,
thibault


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-ob-lua.el-Add-lua-support-to-org-babel.patch --]
[-- Type: text/x-diff, Size: 19739 bytes --]

From e79446cda1a8fbf025145f00c0f2c7ba1caaa374 Mon Sep 17 00:00:00 2001
From: thibault <thibault.marin@gmx.com>
Date: Mon, 22 Aug 2016 10:32:55 -0500
Subject: [PATCH] ob-lua.el: Add lua support to org-babel

* lisp/ob-lua.el: Resurrect ob-lua.el from
https://lists.gnu.org/archive/html/emacs-orgmode/2014-05/msg01149.html,
replace deprecated functions `org-babel-get-header' and
`org-babel-trim' by `org-babel--get-vars' and `org-trim'
respectively.  Sessions are not supported.

* testing/test-ob-lua.el: Testing for ob-lua.el.  Test table
variable passing and results with `value' and `output' options.

* lisp/ox-html.el (org-html-style-default): Add pre.src-lua to css.
---
 lisp/ob-lua.el              | 405 ++++++++++++++++++++++++++++++++++++++++++++
 lisp/ox-html.el             |   1 +
 testing/lisp/test-ob-lua.el | 141 +++++++++++++++
 3 files changed, 547 insertions(+)
 create mode 100644 lisp/ob-lua.el
 create mode 100644 testing/lisp/test-ob-lua.el

diff --git a/lisp/ob-lua.el b/lisp/ob-lua.el
new file mode 100644
index 0000000..a81ec66
--- /dev/null
+++ b/lisp/ob-lua.el
@@ -0,0 +1,405 @@
+;;; ob-lua.el --- org-babel functions for lua evaluation
+
+;; Copyright (C) 2009-2014 Free Software Foundation, Inc.
+
+;; Authors: Dieter Schoen
+;;	 Eric Schulte, Dan Davison
+;; Keywords: literate programming, reproducible research
+;; Homepage: http://orgmode.org
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;; 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 respository is here:
+;; https://github.com/immerrr/lua-mode
+
+;; However, sessions are not yet working.
+
+;; Org-Babel support for evaluating lua source code.
+
+;;; Code:
+(require 'ob)
+(eval-when-compile (require 'cl))
+
+(declare-function org-remove-indentation "org" )
+(declare-function lua-shell "ext:lua-mode" (&optional argprompt))
+(declare-function lua-toggle-shells "ext:lua-mode" (arg))
+(declare-function run-lua "ext:lua" (cmd &optional dedicated show))
+
+(defvar org-babel-tangle-lang-exts)
+(add-to-list 'org-babel-tangle-lang-exts '("lua" . "lua"))
+
+(defvar org-babel-default-header-args:lua '())
+
+(defcustom org-babel-lua-command "lua"
+  "Name of the command for executing Lua code."
+  :version "24.5"
+  :package-version '(Org . "8.3")
+  :group 'org-babel
+  :type 'string)
+
+(defcustom org-babel-lua-mode 'lua-mode
+  "Preferred lua mode for use in running lua interactively.
+This will typically be 'lua-mode."
+  :group 'org-babel
+  :version "24.5"
+  :package-version '(Org . "8.3")
+  :type 'symbol)
+
+(defcustom org-babel-lua-hline-to "None"
+  "Replace hlines in incoming tables with this when translating to lua."
+  :group 'org-babel
+  :version "24.5"
+  :package-version '(Org . "8.3")
+  :type 'string)
+
+(defcustom org-babel-lua-None-to 'hline
+  "Replace 'None' in lua tables with this before returning."
+  :group 'org-babel
+  :version "24.5"
+  :package-version '(Org . "8.3")
+  :type 'symbol)
+
+(defun org-babel-execute:lua (body params)
+  "Execute a block of Lua code with Babel.
+This function is called by `org-babel-execute-src-block'."
+  (let* ((session (org-babel-lua-initiate-session
+		   (cdr (assoc :session params))))
+         (result-params (cdr (assoc :result-params params)))
+         (result-type (cdr (assoc :result-type params)))
+	 (return-val (when (and (eq result-type 'value) (not session))
+		       (cdr (assoc :return params))))
+	 (preamble (cdr (assoc :preamble params)))
+         (full-body
+	  (org-babel-expand-body:generic
+	   (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)))
+    (org-babel-reassemble-table
+     result
+     (org-babel-pick-name (cdr (assoc :colname-names params))
+			  (cdr (assoc :colnames params)))
+     (org-babel-pick-name (cdr (assoc :rowname-names params))
+			  (cdr (assoc :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)
+  "Return a list of Lua statements assigning the block's variables."
+  (mapcar
+   (lambda (pair)
+     (format "%s=%s"
+	     (car pair)
+	     (org-babel-lua-var-to-lua (cdr pair))))
+   (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
+specifying a variable of the same value."
+  (if (listp var)
+      (if (and (= 1 (length var)) (not (listp (car var))))
+          (org-babel-lua-var-to-lua (car var))
+        (if (and
+             (= 2 (length var))
+             (not (listp (car var))))
+            (concat
+             (substring-no-properties (car var))
+             "="
+             (org-babel-lua-var-to-lua (cdr var)))
+          (concat "{" (mapconcat #'org-babel-lua-var-to-lua var ", ") "}")))
+    (if (equal var 'hline)
+        org-babel-lua-hline-to
+      (format
+       (if (and (stringp var) (string-match "[\n\r]" var)) "\"\"%S\"\"" "%S")
+       (if (stringp var) (substring-no-properties var) var)))))
+
+(defun org-babel-lua-table-or-string (results)
+  "Convert RESULTS into an appropriate elisp 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."
+  (let ((res (org-babel-script-escape results)))
+    (if (listp res)
+        (mapcar (lambda (el) (if (equal el 'None)
+                            org-babel-lua-None-to el))
+                res)
+      res)))
+
+(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)
+  (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-lua-without-earmuffs (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-process-buffer
+                                 (buffer-live-p lua-process-buffer))
+                            (replace-regexp-in-string ;; zap surrounding *
+                             "^\\*\\([^*]+\\)\\*$" "\\1" (buffer-name lua-process-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-process-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.")
+
+(defvar org-babel-lua-wrapper-method
+  "
+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)
+   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
+
+
+function main()
+%s
+end
+
+fd=io.open(\"%s\", \"w\")
+fd:write(t2s(main()))
+fd:close()")
+
+(defun org-babel-lua-evaluate
+  (session body &optional result-type result-params preamble)
+  "Evaluate BODY as Lua code."
+  (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
+string.  If RESULT-TYPE equals 'value then return the value of the
+last statement in BODY, as elisp."
+  (let ((raw
+         (pcase result-type
+           (`output (org-babel-eval org-babel-lua-command
+				    (concat (if preamble (concat preamble "\n"))
+					    body)))
+           (`value (let ((tmp-file (org-babel-temp-file "lua-")))
+		     (org-babel-eval
+		      org-babel-lua-command
+		      (concat
+		       (if preamble (concat preamble "\n") "")
+		       (format
+			(if (member "pp" result-params)
+			    org-babel-lua-pp-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")
+			(org-babel-process-file-name tmp-file 'noquote))))
+		     (org-babel-eval-read-file tmp-file))))))
+    (org-babel-result-cond result-params
+      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 5)))
+	 (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
+"
+		  (format "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
+          (case 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 's from around Lua string."
+  (if (string-match "^'\\([^\000]+\\)'$" string)
+      (match-string 1 string)
+    string))
+
+(provide 'ob-lua)
+
+
+
+;;; ob-lua.el ends here
diff --git a/lisp/ox-html.el b/lisp/ox-html.el
index 5f02f25..adc68b2 100644
--- a/lisp/ox-html.el
+++ b/lisp/ox-html.el
@@ -339,6 +339,7 @@ for the JavaScript code in this tag.
   pre.src-ledger:before { content: 'Ledger'; }
   pre.src-lisp:before { content: 'Lisp'; }
   pre.src-lilypond:before { content: 'Lilypond'; }
+  pre.src-lua:before { content: 'Lua'; }
   pre.src-matlab:before { content: 'MATLAB'; }
   pre.src-mscgen:before { content: 'Mscgen'; }
   pre.src-ocaml:before { content: 'Objective Caml'; }
diff --git a/testing/lisp/test-ob-lua.el b/testing/lisp/test-ob-lua.el
new file mode 100644
index 0000000..d0c1302
--- /dev/null
+++ b/testing/lisp/test-ob-lua.el
@@ -0,0 +1,141 @@
+;;; test-ob-lua.el --- tests for ob-lua.el
+
+;; Copyright (c) 2016 Thibault Marin
+;; Authors: Thibault Marin
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+(unless (featurep 'ob-lua)
+  (signal 'missing-test-dependency "Support for Lua code blocks"))
+
+(ert-deftest test-ob-lua/simple-value ()
+  "Test associative array return by value."
+  (should
+   (= 2
+      (org-test-with-temp-text
+	  "#+name: eg
+| a   | 1 |
+| b   | 2 |
+
+#+header: :results value
+#+header: :var x = eg
+#+begin_src lua
+return x['b']
+#+end_src"
+        (org-babel-next-src-block)
+        (org-babel-execute-src-block)))))
+
+(ert-deftest test-ob-lua/simple-output ()
+  "Test text output from table."
+  (should
+   (equal "result: c\n"
+	  (org-test-with-temp-text
+	      "#+name: eg
+| a | b | c | d |
+
+#+header: :results output
+#+header: :var x = eg
+#+begin_src lua
+print('result: ' .. x[1][3])
+#+end_src"
+	    (org-babel-next-src-block)
+	    (org-babel-execute-src-block)))))
+
+
+(ert-deftest test-ob-lua/colnames-yes-header-argument ()
+  "Test table passing with `colnames' header."
+  (should
+   (equal "a"
+	  (org-test-with-temp-text
+	      "#+name: eg
+| col |
+|-----|
+| a   |
+| b   |
+
+#+header: :colnames yes
+#+header: :var x = eg
+#+begin_src lua
+return x[1]
+#+end_src"
+	    (org-babel-next-src-block)
+	    (org-babel-execute-src-block)))))
+
+
+(ert-deftest test-ob-lua/colnames-yes-header-argument-pp ()
+  "Test table passing with `colnames' header and pp option."
+  (should
+   (equal "a = 12\nb = 13\n"
+	  (org-test-with-temp-text
+	      "#+name: eg
+| col | val |
+|-----+-----|
+| a   |  12 |
+| b   |  13 |
+
+#+header: :results value pp
+#+header: :colnames yes
+#+header: :var x = eg
+#+begin_src lua
+return x
+#+end_src"
+	    (org-babel-next-src-block)
+	    (org-babel-execute-src-block)))))
+
+(ert-deftest test-ob-lua/colnames-nil-header-argument ()
+  "Test table with `colnames' set to `nil'."
+  (should
+   (equal "1 = a\n2 = b\n"
+	  (org-test-with-temp-text
+	      "#+name: eg
+| col |
+|-----|
+| a   |
+| b   |
+
+#+header: :colnames nil
+#+header: :var x = eg
+#+header: :results value pp
+#+begin_src lua
+return x
+#+end_src"
+	    (org-babel-next-src-block)
+	    (org-babel-execute-src-block)))))
+
+(ert-deftest test-ob-lua/colnames-no-header-argument ()
+  "Test table passing without `colnames'."
+  (should
+   (equal "1 = col\n2 = a\n3 = b\n"
+	  (org-test-with-temp-text
+	      "#+name: eg
+| col |
+|-----|
+| a   |
+| b   |
+
+#+header: :colnames no
+#+header: :var x = eg
+#+header: :results value pp
+#+begin_src lua
+return x
+#+end_src"
+	    (org-babel-next-src-block)
+	    (org-babel-execute-src-block)))))
+
+(provide 'test-ob-lua)
+
+;;; test-ob-lua.el ends here
-- 
2.8.1


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

* Re: ob-lua
  2016-08-24  2:39             ` ob-lua Thibault Marin
@ 2016-08-29  7:10               ` Nicolas Goaziou
  2016-08-31  3:36                 ` ob-lua Thibault Marin
  0 siblings, 1 reply; 12+ messages in thread
From: Nicolas Goaziou @ 2016-08-29  7:10 UTC (permalink / raw)
  To: Thibault Marin; +Cc: emacs-orgmode@gnu.org

Hello,

Thibault Marin <thibault.marin@gmx.com> writes:

> I am attaching an updated patch adding the Lua language to the CSS in
> `org-html-style-default'.

Patches applied. Thank you.

Would you consider signing FSF papers if not already done?


Regards,

-- 
Nicolas Goaziou

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

* Re: ob-lua
  2016-08-29  7:10               ` ob-lua Nicolas Goaziou
@ 2016-08-31  3:36                 ` Thibault Marin
  2016-09-01 16:40                   ` ob-lua Nicolas Goaziou
  0 siblings, 1 reply; 12+ messages in thread
From: Thibault Marin @ 2016-08-31  3:36 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode@gnu.org


Thanks,

I have just submitted the FSF papers.

Best,
thibault

Nicolas Goaziou writes:

> Hello,
>
> Thibault Marin <thibault.marin@gmx.com> writes:
>
>> I am attaching an updated patch adding the Lua language to the CSS in
>> `org-html-style-default'.
>
> Patches applied. Thank you.
>
> Would you consider signing FSF papers if not already done?
>
>
> Regards,

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

* Re: ob-lua
  2016-08-31  3:36                 ` ob-lua Thibault Marin
@ 2016-09-01 16:40                   ` Nicolas Goaziou
  2016-09-08  4:37                     ` ob-lua Thibault Marin
  0 siblings, 1 reply; 12+ messages in thread
From: Nicolas Goaziou @ 2016-09-01 16:40 UTC (permalink / raw)
  To: Thibault Marin; +Cc: emacs-orgmode@gnu.org

Hello,

Thibault Marin <thibault.marin@gmx.com> writes:

> I have just submitted the FSF papers.

Great! Please let me know when the whole process is done.

Thank you.

-- 
Nicolas Goaziou

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

* Re: ob-lua
  2016-09-01 16:40                   ` ob-lua Nicolas Goaziou
@ 2016-09-08  4:37                     ` Thibault Marin
  0 siblings, 0 replies; 12+ messages in thread
From: Thibault Marin @ 2016-09-08  4:37 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode@gnu.org


Hi,

I have received the FSF papers.

Thanks
thibault

Nicolas Goaziou writes:

> Hello,
>
> Thibault Marin <thibault.marin@gmx.com> writes:
>
>> I have just submitted the FSF papers.
>
> Great! Please let me know when the whole process is done.
>
> Thank you.

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

end of thread, other threads:[~2016-09-08  4:38 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-20  5:18 ob-lua Thibault Marin
2016-08-20 16:02 ` ob-lua Nicolas Goaziou
2016-08-21  4:47   ` ob-lua Thibault Marin
2016-08-21  9:30     ` ob-lua Nicolas Goaziou
2016-08-22  2:38       ` ob-lua Thibault Marin
2016-08-22  9:28         ` ob-lua Nicolas Goaziou
2016-08-22 12:56           ` ob-lua Thibault Marin
2016-08-24  2:39             ` ob-lua Thibault Marin
2016-08-29  7:10               ` ob-lua Nicolas Goaziou
2016-08-31  3:36                 ` ob-lua Thibault Marin
2016-09-01 16:40                   ` ob-lua Nicolas Goaziou
2016-09-08  4:37                     ` ob-lua Thibault Marin

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).