Support for evaluating Janet code in org mode. See the Working with source code section in the org manual.
ob-janet.el is based on ob-racket.
- Install Org mode
- Install Janet
- Download ob-janet.el and place it in your
load-path - When using use-package add the following to your
init.elfile:(use-package ob-janet :after org :pin manual :config (append '((janet . t)) org-babel-load-languages))
- Optionally install janet-mode to edit Janet code.
ob-janet has some
specific ones to control how code is evaluated.
:cmdset tojanetby default.Determines which Janet executable and any switches that will be used when evaluating the code.
:eval-fileNot set by default.When requiring modules that are relative to the code block the evaluation needs to happen in a specific path instead of
org-babel-temporary-directory.:eval-file FILENAMECan be used to specify where the code block is written and evaluated.If
:eval-file “”is used, the name is taken from#+NAMEandjanetis used as the extension.:output-dircan be used to specify the directory.
#+begin_src janet (def str-1 "hello") (def str-2 "world") (def all (string/join [str-1 str-2] ", ")) (string/ascii-upper all) #+end_src
Outputs:
HELLO, WORLD
#+begin_src janet :results output
(map pp
[nil true false
# Symbols
'symbol
'kebab-case-symbol
'snake_case_symbol
'my-module/my-fuction
'*****
'!%$^*__--__._+++===~-crazy-symbol
'*global-var*
'你好
# Keywords
:keyword :range :0x0x0x0 :a-keyword :: :
# Numbers
0 +0.0 -10_000 16r1234abcd 0x23.23 1e10 1.6e-4
7r343_111_266.6&+10 # a base 7 number in scientific notation. evaluates to 1.72625e+13 in base 10
# Strings
"This is a string."
"This\nis\na\nstring."
"This
is
a
string."
``
This
is
a
string
``
# Buffers
@"" @"Buffer." @``Another buffer``
# Tuples
(do 1 2 3) ['do 1 2 3]
# Arrays
@(:one :two :three) @[:one :two :three]
# Structs
{}
{:key1 "value1" :key2 :value2 :key3 3}
{[1 2 3] [4 5 6]}
{@[] @[]}
{1 2 3 4 5 6}
# Tables
@{}
@{:key1 "value1" :key2 :value2 :key3 3}
@{[1 2 3] [4 5 6]}
@{@[] @[]}
@{1 2 3 4 5 6}
# Splice
;["one" 2 ['III]]
])
#+end_src
Outputs:
nil
true
false
symbol
kebab-case-symbol
snake_case_symbol
my-module/my-fuction
*****
!%$^*__--__._+++===
-crazy-symbol
*global-var*
你好
:keyword
:range
:0x0x0x0
:a-keyword
::
:
0
0
-10000
305441741
35.1367
1e+10
0.00016
1.72625e+13
"This is a string."
"This\nis\na\nstring."
"This is a string."
" This\n is\n a\n string\n "
@""
@"Buffer."
@"Another buffer"
3
(do 1 2 3)
@[:one :two :three]
@[:one :two :three]
{}
{:key2 :value2 :key3 3 :key1 "value1"}
{(1 2 3) (4 5 6)}
{@[] @[]}
{5 6 3 4 1 2}
@{}
@{:key2 :value2 :key3 3 :key1 "value1"}
@{(1 2 3) (4 5 6)}
@{@[] @[]}
@{5 6 3 4 1 2}
"one"
2
(III)
#+NAME: a-list #+begin_src janet :results list '(Hello Wonderful World) #+end_src
Outputs:
- Hello
- Wonderful
- World
#+begin_src janet :results table :var input=a-list [input nil input] #+end_src
Outputs:
| Hello | Wonderful | World |
|---|---|---|
| Hello | Wonderful | World |
#+begin_src janet :var x=a-list :debug t (print x) (print "Hello World") #+end_src
Outputs:
(pp (do (def x '(Hello Wonderful World)) (print x) (print "Hello World")))
:results output is implicitly set.
#+NAME: code
#+begin_src janet :file-ext janet
(defn a-func []
(print "Hello World"))
#+end_src
Creates the file code.janet in the current directory with this content:
(defn a-func []
(print "Hello World"))The content of the file is not evaluated.
:results output is implicitly set to get the result of the evaluation.
#+NAME: eval-file #+begin_src janet :eval-file "" (import ./code) # Created in the `File` sample (code/a-func) #+end_src
Creates the file eval-file.janet in the current directory with this content:
(import ./code) # Created in the `File` sample
(code/a-func)And outputs:
Hello World
The contents of ob-janet.el are extracted from this file. To re-generate the
code, open this file in an Emacs buffer and M-x org-babel-tangle. The
complete source will be in exported to ob-janet.el.
(defun org-babel-execute:janet (body params)
"Evaluate a `janet' code block. BODY and PARAMS.
Some custom header arguments are supported to control the
evaluation. These are:
- :cmd which allows to set the Janet executable and the switches
on each code block.
- :debug which outputs the body before passing it to the
interpreter.
- :eval-file FILENAME which writes the body to FILENAME and then
evaluates the result. When FILENAME is equal to \"\" it is
derived from the code-block name."
(let ((vars (org-babel--get-vars params))
(prologue (alist-get :prologue params))
(epilogue (alist-get :epilogue params))
(cmd (alist-get :cmd params "janet"))
(result-type (alist-get :result-type params))
(ext (alist-get :file-ext params "janet"))
(file (alist-get :file params))
(eval-file (alist-get :eval-file params))
x-body)
(when (eq "" eval-file)
(setq eval-file (alist-get :file
(org-babel-generate-file-param
(nth 4 (org-babel-get-src-block-info))
(cons (cons :file-ext ext) params)))))
(setq x-body (if (or vars prologue epilogue)
(ob-janet--wrap-body body vars prologue epilogue)
body))
(when (and (not file)
(not eval-file)
(string= result-type "value"))
(setq x-body (format org-babel-function-wrapper:janet x-body)))
(if (assq :debug params)
x-body
(if file
(with-temp-file file (insert x-body))
(let* ((temp (or eval-file
(org-babel-temp-file "ob-" (concat "." ext))))
(result (progn (with-temp-file temp (insert x-body))
(org-babel-eval (concat cmd " " temp) ""))))
(org-babel-reassemble-table
(org-babel-result-cond (alist-get :result-params params)
result
(ob-janet--table-or-string result))
(org-babel-pick-name (alist-get :colname-names params)
(alist-get :colnames params))
(org-babel-pick-name (alist-get :rowname-names params)
(alist-get :rownames params))))))))(defun org-babel-prep-session:janet (session params)
"Not implemented. SESSION and PARAMS are discarded."
(error "`janet` presently does not support sessions"))(defvar org-babel-function-wrapper:janet
"(pp (do %s))"
"Janet code to print value of body.")(defun ob-janet--table-or-string (results)
"Convert RESULTS into an appropriate elisp value.
If RESULTS look like a table, then convert them into an Emacs-lisp table,
otherwise return the results as a string."
(let ((res (org-babel-script-escape (string-trim results))))
(if (listp res)
(mapcar
(lambda (el)
(if (equal el 'nil)
org-babel-janet-nil-to el))
res)
res)))(defun ob-janet--wrap-body (body vars prologue epilogue)
"Wraps BODY VARS, PROLOGUE and EPILOGUE if present.
Returns the wrapped body as a string."
(let ((var-defs nil))
(when (> (length vars) 0)
(setq var-defs (ob-janet--vars-to-values vars)))
(mapconcat #'identity
(append
(when prologue (list (ob-janet--expand-fmt pro)))
var-defs
(list body)
(when epilogue (list (ob-janet--expand-fmt epi))))
"\n")))(defun ob-janet--vars-to-values (vars)
"Convers VARS to a string of janet code.
VARS are wrapped with def."
(mapcar (lambda (var)
(concat
"(def"
(format " %s " (car var))
(format (if (listp (cdr var)) "'%S" "%S") (cdr var))
")"))
vars))(defun ob-janet--expand-fmt (fmt &optional params)
"Expands a format list `FMT', and return a string.
PARAMS
Substitutes symbols according to the `params` alist.
The `fmt` argument may also be a string, in which
case it is returned as is."
(if (stringp fmt)
fmt
(mapconcat
(lambda (x)
(cond
((stringp x) x)
((eq x 'ln) "\n")
((eq x 'quot) "\"")
((eq x 'apos) "\'")
((symbolp x)
(let ((p (cdr (assq x params))))
(unless p
(error "Key %s not in %S" x params))
(format "%s" p)))
(t (error "Expected string or symbol: %S" fmt))))
fmt "")))(defcustom org-babel-janet-hline-to "nil"
"Replace hlines in incoming tables with this when translating to janet."
:group 'org-babel
:version "27.0.50"
:package-version '(Org . "9.3.4")
:type 'string)
(defcustom org-babel-janet-nil-to 'hline
"Replace 'nil' in janet tables with this before returning."
:group 'org-babel
:version "27.0.50"
:package-version '(Org . "9.3.4")
:type 'symbol)Default header arguments.
(defvar org-babel-default-header-args:janet
'((:cmd . "janet"))
"Default arguments when evaluating a Janet source block.
Defaulting `:cmd' to `janet'.");;; ob-janet.el --- Janet language support in Emacs Org-mode -*- lexical-binding: t; -*-
;; Copyright (C) 2020 DEADB17
;; Author: DEADB17
;; Version: 1.0.0
;; Created: 2020-02-09
;; Keywords: literate programming, janet
;; Homepage: https://github.com/DEADB17/ob-janet
;; This file is not part of GNU Emacs
;;; License:
;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; Support for evaluating janet code in org-mode
;; See https://orgmode.org/manual/Working-with-source-code.html
;; Requirements:
;; - Janet, see http://janet-lang.org/
;; - janet-mode https://github.com/ALSchwalm/janet-mode
;;; Code:
(require 'ob)
;; add janet to languages supported by org
(defvar org-babel-tangle-lang-exts)
(add-to-list 'org-babel-tangle-lang-exts '("janet" . "janet"))
<<custom-options>>
<<defaults>>
<<auxiliary>>
<<main>>
(provide 'ob-janet)
;;; ob-janet.el ends here