Add :let keyword, more supported packages
parent
e86200172c
commit
e789251ce9
97
init.jl
97
init.jl
|
@ -1,4 +1,4 @@
|
|||
const supported_packages = [:DataFrames, :NamedArrays, :Plots]
|
||||
const supported_packages = [:DataFrames, :NamedArrays, :Plots, :HypothesisTests, :CSVFiles]
|
||||
|
||||
# Generic fallback
|
||||
orgshow(io::IO, Any, i; kwargs...) = show(io, i)
|
||||
|
@ -27,8 +27,17 @@ function orgshow(io::IO, ::MIME"text/csv", i::Array{T,2}; kwargs...) where T <:
|
|||
orgshow(io, MIME("text/org"), i; kwargs...)
|
||||
end
|
||||
|
||||
function orgstring(e::Tuple{Exception,Any})
|
||||
string("ERROR,", e[1], "\n",
|
||||
"Stacktrace:\n",
|
||||
join(e[2], '\n'))
|
||||
end
|
||||
|
||||
# The comma is needed to allow export as table
|
||||
orgshow(io::IO, ::MIME"text/org", e::Exception; kwargs...) = print(io, "ERROR,", e)
|
||||
function orgshow(io::IO, ::MIME"text/org", e::Tuple{Exception,Any};
|
||||
kwargs...)
|
||||
print(io, orgstring(e))
|
||||
end
|
||||
|
||||
function orgshow(io::IO, ::MIME"text/org", t::NamedTuple)
|
||||
print(io, join(string.(keys(t)), ','))
|
||||
|
@ -48,6 +57,26 @@ function orgshow(io::IO, ::MIME"text/org",
|
|||
end
|
||||
end
|
||||
|
||||
OrgAPApvalue(p) = p < 0.001 ? "< .001" : string("= ", round(p, sigdigits = 2))
|
||||
|
||||
function define_HypothesisTests()
|
||||
Main.@eval function orgshow(io::IO,
|
||||
m::MIME"text/org",
|
||||
test::PowerDivergenceTest; kwargs...)
|
||||
println(io, join(["test", "df", "N", "stat", "p-value"], ','))
|
||||
print(io, join(["X^2", test.df, test.n, test.stat, pvalue(test)], ','))
|
||||
end
|
||||
Main.@eval function orgshow(io::IO,
|
||||
m::MIME"text/html",
|
||||
test::PowerDivergenceTest; kwargs...)
|
||||
print(io, string("X^2",
|
||||
" (", test.df, ", N = ", test.n,
|
||||
") = ",
|
||||
round(test.stat; digits = 2),
|
||||
", p ", OrgAPApvalue(pvalue(test))))
|
||||
end
|
||||
end
|
||||
|
||||
function define_Plots()
|
||||
# Fallback: we will try to plot any image/png or image/svg
|
||||
Main.@eval function orgshow(io::IO,
|
||||
|
@ -65,9 +94,10 @@ function define_Plots()
|
|||
p::Plots.Plot; kwargs...)
|
||||
show(io, MIME("image/png"), plot(p; kwargs...))
|
||||
end
|
||||
Main.@eval function orgshow(io::IO, ::MIME"image/png", e::Exception; kwargs...)
|
||||
Main.@eval function orgshow(io::IO, ::MIME"image/png", e::Tuple{Exception,Any};
|
||||
kwargs...)
|
||||
let p = plot(showaxis = false, grid = false, bg = :yellow)
|
||||
annotate!([0.5], [0.5], (string("ERROR: ", e), :red))
|
||||
annotate!([0.5], [0.5], (orgstring(e), :red))
|
||||
orgshow(io, MIME("image/png"), p; kwargs...)
|
||||
end
|
||||
end
|
||||
|
@ -78,7 +108,10 @@ function define_Plots()
|
|||
end
|
||||
end
|
||||
Main.@eval function orgshow(io::IO, ::MIME"text/html", p::Plots.Plot; kwargs...)
|
||||
Plots._show(io, MIME("text/html"), plot(p; kwargs...))
|
||||
p = plot(p; kwargs...)
|
||||
p.attr[:html_output_format] = "png"
|
||||
# Plots._show(io::IO, MIME("text/html"), p::Plots.Plot; kwargs...)
|
||||
Plots._show(io, MIME("text/html"), p)
|
||||
end
|
||||
Main.@eval function orgshow(io::IO, ::MIME"image/svg+xml", p::Plots.Plot; kwargs...)
|
||||
show(io, MIME("image/svg+xml"), plot(p; kwargs...))
|
||||
|
@ -116,13 +149,30 @@ function define_DataFrames()
|
|||
end
|
||||
end
|
||||
|
||||
function define_CSVFiles()
|
||||
Main.@eval function orgshow(io::IO, ::MIME"text/csv", d::CSVFiles.CSVFile)
|
||||
orgshow(io, MIME("text/org"), d)
|
||||
end
|
||||
Main.@eval function orgshow(io::IO, ::MIME"text/html", d::CSVFiles.CSVFile)
|
||||
show(io, MIME("text/html"), RES)
|
||||
end
|
||||
Main.@eval function orgshow(io::IO, ::MIME"application/json", d::CSVFiles.CSVFile)
|
||||
show(io, MIME("application/vnd.dataresource+json"), RES)
|
||||
end
|
||||
Main.@eval function orgshow(io::IO, ::MIME"text/org", d::CSVFiles.CSVFile)
|
||||
orgshow(io, MIME("text/org"), collect(d))
|
||||
end
|
||||
end
|
||||
|
||||
function define_NamedArrays()
|
||||
Main.@eval function orgshow(io::IO, ::MIME"text/org",
|
||||
na::NamedArrays.NamedArray{T,2} where T <: Any)
|
||||
na::NamedArray{T,2} where T <: Any)
|
||||
n = names(na)
|
||||
a = collect(na)
|
||||
print(io, join(string.(na.dimnames), "/") * ',')
|
||||
print(io, join(n[2], ','') * '\n')
|
||||
# The char used by NamedArrays is '╲' but by default it's not
|
||||
# shown in pdf export
|
||||
print(io, join(string.(na.dimnames), " \\ ") * ',')
|
||||
print(io, join(n[2], ',') * '\n')
|
||||
print(io, join([join([string(n[1][i], ','),
|
||||
join([a[i,j]
|
||||
for j in 1:size(na,2)
|
||||
|
@ -130,7 +180,7 @@ function define_NamedArrays()
|
|||
for i in 1:size(na,1)
|
||||
], '\n'))
|
||||
end
|
||||
Main.@eval function orgshow(io::IO, ::MIME"text/org", na::NamedArrays.NamedArray{T,1} where T <: Any)
|
||||
Main.@eval function orgshow(io::IO, ::MIME"text/org", na::NamedArray{T,1} where T <: Any)
|
||||
n = names(na)
|
||||
a = collect(na)
|
||||
print(io, string(na.dimnames[1], ',', '\n'))
|
||||
|
@ -141,15 +191,16 @@ end
|
|||
|
||||
define_package_functions(pkg::Symbol) = (@eval $pkg)()
|
||||
|
||||
function OrgBabelImport(_imports; forced = false)
|
||||
function OrgBabelImport(imports; forced = false)
|
||||
"Load dependencies. Do this before calling OrgBabelReload()"
|
||||
# Reload this module, so that if new packages have been imported,
|
||||
# we can use them to save the output
|
||||
!forced && isempty(_imports) && return
|
||||
!forced && isempty(imports) && return
|
||||
println("$imports")
|
||||
try
|
||||
Main.eval(Meta.parse(
|
||||
"""begin
|
||||
$_imports
|
||||
$imports
|
||||
end"""))
|
||||
true
|
||||
catch e
|
||||
|
@ -183,29 +234,30 @@ function OrgBabelFormat(output_type::Symbol,
|
|||
dir, vars,
|
||||
src_file,
|
||||
silently::Bool,
|
||||
pure::Bool,
|
||||
kwargs)
|
||||
content = read(src_file, String)
|
||||
# Fake a prompt with the current input
|
||||
try
|
||||
println(string("\njulia> ", content))
|
||||
printstyled(IOContext(stdout, :color => true),
|
||||
"\njulia> ", color = :blue)
|
||||
println(content)
|
||||
catch
|
||||
end
|
||||
# Dispatch on output type
|
||||
code = pure ? "let $vars; $content; end" : "begin $vars; $content end"
|
||||
if output_type == :value
|
||||
# Run the code
|
||||
result = cd(dir) do
|
||||
try
|
||||
# Variable assignment
|
||||
Main.eval(Meta.parse(vars))
|
||||
# src block evaluation
|
||||
Main.eval(Meta.parse("begin $content end"))
|
||||
Main.eval(Meta.parse(code))
|
||||
catch e
|
||||
e
|
||||
(e, stacktrace())
|
||||
end
|
||||
end
|
||||
if !silently
|
||||
try
|
||||
print(result)
|
||||
display(MIME("text/plain"), result)
|
||||
catch e
|
||||
println("Error $e while showing results")
|
||||
end
|
||||
|
@ -236,12 +288,10 @@ function OrgBabelFormat(output_type::Symbol,
|
|||
redirect_stderr(f) do
|
||||
cd(dir) do
|
||||
try
|
||||
# Variable assignment
|
||||
Main.eval(Meta.parse(vars))
|
||||
# src block evaluation
|
||||
Main.eval(Meta.parse("begin $content end"))
|
||||
Main.eval(Meta.parse(code))
|
||||
catch e
|
||||
println(e)
|
||||
println(join(stacktrace(), '\n'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -260,3 +310,4 @@ function OrgBabelFormat(output_type::Symbol,
|
|||
end
|
||||
|
||||
OrgBabelReload()
|
||||
|
||||
|
|
80
ob-julia.el
80
ob-julia.el
|
@ -12,7 +12,7 @@
|
|||
:version "24.1"
|
||||
:type 'string)
|
||||
|
||||
(defcustom org-babel-julia-startup-script
|
||||
(defcustom ob-julia-startup-script
|
||||
(concat (file-name-directory (or load-file-name (buffer-file-name)))
|
||||
"init.jl")
|
||||
"Julia file path to run at startup. Must be absolute."
|
||||
|
@ -52,6 +52,7 @@ There's no effect in non-session evaluations"
|
|||
(height . :any)
|
||||
(size . :any)
|
||||
(inline . :any)
|
||||
(let . :any)
|
||||
(import . :any)
|
||||
(using . :any)
|
||||
(async . :any)
|
||||
|
@ -81,7 +82,14 @@ There's no effect in non-session evaluations"
|
|||
(set (make-local-variable 'org-babel-julia-session-directory) dir)
|
||||
(save-window-excursion
|
||||
(require 'ess)
|
||||
(julia)
|
||||
;; load the julia startup script (defined in ob-julia-startup-script)
|
||||
;; pass it along with other arguments defined in inferior-julia-args
|
||||
(let* ((start-script-arg
|
||||
(concat (format "--load=%s" ob-julia-startup-script)))
|
||||
(inferior-julia-args (if inferior-julia-args
|
||||
(concat inferior-julia-args start-script-arg)
|
||||
start-script-arg)))
|
||||
(julia))
|
||||
(rename-buffer
|
||||
(if (bufferp session)
|
||||
(buffer-name session)
|
||||
|
@ -92,14 +100,7 @@ There's no effect in non-session evaluations"
|
|||
;; running the command
|
||||
(set-process-filter (get-buffer-process
|
||||
(org-babel-comint-buffer-livep session))
|
||||
'org-julia-async-process-filter)
|
||||
;; Initialization
|
||||
(let ((julia-init
|
||||
(with-temp-buffer
|
||||
(insert-file-contents org-babel-julia-startup-script)
|
||||
(buffer-string))))
|
||||
(ess-send-string (ess-get-process) julia-init nil))
|
||||
(current-buffer))))
|
||||
'org-julia-async-process-filter))))
|
||||
|
||||
(defun org-babel-julia-get-session-name (params)
|
||||
"Extract the session name from the PARAMS.
|
||||
|
@ -153,8 +154,7 @@ This function is used for all async processing with and without session."
|
|||
;; This will evaluate the code again
|
||||
;; (cl-callf org-babel-process-params (nth 2 info))
|
||||
(setq params (nth 2 info))
|
||||
(setq cache (let ((c (cdr (assq :cache params))))
|
||||
(and c (string= "yes" c))))
|
||||
(setq cache (ob-julia-check-trueness params :cache))
|
||||
;; pass info to have a different hash
|
||||
(setq new-hash (if cache (org-babel-sha1-hash) nil))
|
||||
(org-babel-remove-result)
|
||||
|
@ -181,14 +181,14 @@ Does not rely on an ESS session."
|
|||
(make-process :name "*julia-async-process*"
|
||||
:filter #'org-julia-async-process-filter
|
||||
:command `(,org-babel-julia-command
|
||||
"--load" ,org-babel-julia-startup-script
|
||||
"--load" ,ob-julia-startup-script
|
||||
"--eval"
|
||||
,(format "include(%S);%s" tmpfile command)))
|
||||
(concat "julia-async:" uuid ":" outfile))
|
||||
(progn
|
||||
(shell-command
|
||||
(format "%s --load %s %s" org-babel-julia-command
|
||||
org-babel-julia-startup-script tmpfile))
|
||||
ob-julia-startup-script tmpfile))
|
||||
outfile))))
|
||||
|
||||
(defun org-babel-julia-assign-to-var-or-array (var)
|
||||
|
@ -201,7 +201,7 @@ Does not rely on an ESS session."
|
|||
"Create a Matrix (Vector{Any,2} from `MATRIX' and assign it to `NAME'"
|
||||
(format "%s = [%s]" name
|
||||
(mapconcat (lambda (line) (mapconcat (lambda (e)
|
||||
(format "%s" e))
|
||||
(format "%S" e))
|
||||
line " ")) matrix ";")))
|
||||
|
||||
(defun org-babel-julia-assign-to-var (name value)
|
||||
|
@ -290,19 +290,22 @@ else OUTFILE is used, and data is _write()_ to it."
|
|||
(format "OrgBabelImport(%S);OrgBabelReload();"
|
||||
(concat (if using (mapconcat (lambda (x) (concat "using " x))
|
||||
using "\n") "")
|
||||
"\n"
|
||||
(if import (mapconcat (lambda (x) (concat "import " x))
|
||||
import "\n") "")))
|
||||
"")
|
||||
(format
|
||||
"OrgBabelFormat(%s,%S,%S,%S,%S,%s,%S);"
|
||||
output-type outfile
|
||||
dir
|
||||
(mapconcat 'concat vars ";") srcfile
|
||||
(if org-babel-julia-silent-repl
|
||||
"true" "false")
|
||||
(org-babel-julia-make-kwargs `((width . ,width)
|
||||
(height . ,height)
|
||||
(size . ,size)))))))
|
||||
"OrgBabelFormat(%s,%S,%S,%S,%S,%s,%s,%S);"
|
||||
output-type outfile
|
||||
dir
|
||||
(mapconcat 'concat vars ";") srcfile
|
||||
(if org-babel-julia-silent-repl
|
||||
"true" "false")
|
||||
(if (ob-julia-check-trueness params :let)
|
||||
"true" "false")
|
||||
(org-babel-julia-make-kwargs `((width . ,width)
|
||||
(height . ,height)
|
||||
(size . ,size)))))))
|
||||
|
||||
(defun org-babel-execute:julia-async (buffer session body block output params)
|
||||
(let* ((uuid (org-id-uuid))
|
||||
|
@ -361,14 +364,14 @@ If PARAMS is :async, insert a link, unless CALLBACK is true."
|
|||
(if inlined
|
||||
(with-temp-buffer
|
||||
(when (bound-and-true-p org-export-current-backend)
|
||||
(insert (format "@@%s:"
|
||||
(insert (format "#+begin_export %s\n"
|
||||
(if org-export-current-backend
|
||||
org-export-current-backend
|
||||
inlined))))
|
||||
(insert-file-contents results)
|
||||
(when (bound-and-true-p org-export-current-backend)
|
||||
(goto-char (point-max))
|
||||
(insert "@@"))
|
||||
(insert "\n#+end_export"))
|
||||
(buffer-string))
|
||||
(org-babel-result-cond (if res (split-string res) nil)
|
||||
(with-temp-buffer
|
||||
|
@ -391,27 +394,25 @@ table. To force a matrix, use matrix"
|
|||
((member "raw" results) 'raw)
|
||||
(t 'auto))))
|
||||
|
||||
(defun ob-julia-check-trueness (params param)
|
||||
""
|
||||
(and (assoc param params)
|
||||
(let ((val (cdr (assoc param params))))
|
||||
(or
|
||||
(not val)
|
||||
(string= "t" val)
|
||||
(string= "yes" val)))))
|
||||
|
||||
(defun org-babel-julia-async-p (params)
|
||||
"Check whether the session should be async or not."
|
||||
(let* ((res (cdr (assoc :results params)))
|
||||
(async (assoc :async params)))
|
||||
(and async
|
||||
(or
|
||||
(not (cdr async))
|
||||
(string= "t" (cdr async))
|
||||
(string= "yes" (cdr async)))
|
||||
(ob-julia-check-trueness params :async)
|
||||
(and (eq org-babel-current-src-block-location (org-babel-where-is-src-block-head)))
|
||||
(not (and res (stringp res) (member "silent" (split-string res)))))))
|
||||
|
||||
(defun org-babel-julia-really-async-p ()
|
||||
;; (let*
|
||||
;; ((head (org-babel-where-is-src-block-head))
|
||||
;; (async (and (not (bound-and-true-p org-export-current-backend))
|
||||
;; head
|
||||
;; org-babel-current-src-block-location
|
||||
;; (equal org-babel-current-src-block-location
|
||||
;; head))))
|
||||
;; async)
|
||||
;; Disable async on export
|
||||
(not (bound-and-true-p org-export-current-backend)))
|
||||
|
||||
;; Copied from ob-python
|
||||
|
@ -442,7 +443,6 @@ This function is called by `org-babel-execute-src-block'.
|
|||
BODY is the content of the src block
|
||||
PARAMS are the parameter passed to the block"
|
||||
;; org-babel-current-src-block-location ; this variable does not work >.<
|
||||
(message (format "body: %s, params: %s" body params))
|
||||
(save-excursion
|
||||
(let* ((buffer (buffer-name))
|
||||
(session (org-babel-julia-get-session-name params))
|
||||
|
|
18
readme.org
18
readme.org
|
@ -19,7 +19,10 @@ See [[Implemented features]] for more details.
|
|||
(customized by =org-babel-julia-default-session=)
|
||||
3. If session has a values, use it's name
|
||||
3. Check if we want to use a session or not. Check if the session
|
||||
exists. Start the session accordingly.
|
||||
exists. Start the session accordingly. During startup, the file
|
||||
defined in =ob-julia-startup-script= is loaded. This file must define
|
||||
functions like OrgBabelFormat, to let emacs send code to
|
||||
execute. See =init.jl= for details.
|
||||
4. Is the evaluation async?
|
||||
1. YES:
|
||||
1. Register a filter function
|
||||
|
@ -100,7 +103,18 @@ sleep(1)
|
|||
Asynchronous evaluation is automatically disabled on export, or when a
|
||||
code block depends on one (=:var=)
|
||||
|
||||
** Variables input (=:var=), Standard output
|
||||
** Variables input (=:var =:let=), Standard output
|
||||
|
||||
As usual, you can set variables with the =:var= header. To make ob-julia
|
||||
behave like the julia REPL, variables are set in the global scope. If
|
||||
you want a block to be isolated, you can use the extra =:let= header
|
||||
argument: with this, the src block is inside a let block:
|
||||
|
||||
#+begin_src julia :exports code :eval never
|
||||
let vars
|
||||
src_block
|
||||
end
|
||||
#+end_src
|
||||
|
||||
*** Inputs
|
||||
|
||||
|
|
Loading…
Reference in New Issue