263 lines
9.9 KiB
Julia
263 lines
9.9 KiB
Julia
|
const supported_packages = [:DataFrames, :NamedArrays, :Plots]
|
||
|
|
||
|
# Generic fallback
|
||
|
orgshow(io::IO, Any, i; kwargs...) = show(io, i)
|
||
|
orgshow(io::IO, ::MIME"text/org", i; kwargs...) = show(io, i)
|
||
|
# Overload types
|
||
|
orgshow(io::IO, ::MIME"text/org", t::Tuple; kwargs...) = print(io, join(t, ','))
|
||
|
orgshow(io::IO, ::MIME"text/org", ::Nothing; kwargs...) = print(io, "")
|
||
|
orgshow(io::IO, ::MIME"text/org", a::Array{T,1}; kwargs...) where T <: Any = print(io, join(a, '\n'))
|
||
|
|
||
|
# You can override this with a better one that uses some available module
|
||
|
function orgshow(io::IO, ::MIME"text/html", i::Array{T,2}; kwargs...) where T <: Any
|
||
|
width = get(Dict(kwargs), :width, "100")
|
||
|
print(io, """<table style="width:$width%">""")
|
||
|
content = eachrow(i) |> x -> string("<tr>",
|
||
|
join([string("<th>", join(l, "</th><th>"))
|
||
|
for l in x], "</tr><tr>"))
|
||
|
print(io, content, "</table>")
|
||
|
end
|
||
|
|
||
|
function orgshow(io::IO, ::MIME"text/org", i::Array{T,2}; kwargs...) where T <: Any
|
||
|
out = eachrow(i) |> x -> join([join(l, ',') for l in x], '\n')
|
||
|
print(io, out)
|
||
|
end
|
||
|
|
||
|
function orgshow(io::IO, ::MIME"text/csv", i::Array{T,2}; kwargs...) where T <: Any
|
||
|
orgshow(io, MIME("text/org"), i; kwargs...)
|
||
|
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", t::NamedTuple)
|
||
|
print(io, join(string.(keys(t)), ','))
|
||
|
println(io)
|
||
|
print(io, join(t, ','))
|
||
|
end
|
||
|
|
||
|
function orgshow(io::IO, ::MIME"text/org",
|
||
|
ta::Vector{<:NamedTuple})
|
||
|
"This assume keys are the same. A better NamedTuple export is provided by
|
||
|
the DataFrames (DataFrame(ta))"
|
||
|
length(ta) <= 0 && return ""
|
||
|
println(io, join(keys(first(ta)), ','))
|
||
|
for t in ta
|
||
|
print(io, join(string.(values(t)), ','))
|
||
|
println(io)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function define_Plots()
|
||
|
# Fallback: we will try to plot any image/png or image/svg
|
||
|
Main.@eval function orgshow(io::IO,
|
||
|
m::MIME"image/png",
|
||
|
any; kwargs...)
|
||
|
show(io, MIME("image/png"), plot(any; kwargs...))
|
||
|
end
|
||
|
Main.@eval function orgshow(io::IO,
|
||
|
m::MIME"image/svg+xml",
|
||
|
any; kwargs...)
|
||
|
show(io, MIME("image/svg+xml"), plot(any; kwargs...))
|
||
|
end
|
||
|
Main.@eval function orgshow(io::IO,
|
||
|
m::MIME"image/png",
|
||
|
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...)
|
||
|
let p = plot(showaxis = false, grid = false, bg = :yellow)
|
||
|
annotate!([0.5], [0.5], (string("ERROR: ", e), :red))
|
||
|
orgshow(io, MIME("image/png"), p; kwargs...)
|
||
|
end
|
||
|
end
|
||
|
Main.@eval function orgshow(io::IO, ::MIME"image/svg+xml", e::Exception; kwargs...)
|
||
|
let p = plot(showaxis = false, grid = false, bg = :yellow)
|
||
|
annotate!([0.5], [0.5], (string("ERROR: ", e), :red))
|
||
|
orgshow(io, MIME("image/svg+xml"), p; kwargs...)
|
||
|
end
|
||
|
end
|
||
|
Main.@eval function orgshow(io::IO, ::MIME"text/html", p::Plots.Plot; kwargs...)
|
||
|
Plots._show(io, MIME("text/html"), plot(p; kwargs...))
|
||
|
end
|
||
|
Main.@eval function orgshow(io::IO, ::MIME"image/svg+xml", p::Plots.Plot; kwargs...)
|
||
|
show(io, MIME("image/svg+xml"), plot(p; kwargs...))
|
||
|
end
|
||
|
Main.@eval function orgshow(io::IO, ::MIME"application/pdf", p::Plots.Plot; kwargs...)
|
||
|
# ps, eps, tex or pdf. I think extra packages are required for all but pdf
|
||
|
show(io, MIME("application/pdf"), plot(p; kwargs...))
|
||
|
end
|
||
|
Main.@eval function orgshow(io::IO, ::MIME"application/postscript", p::Plots.Plot; kwargs...)
|
||
|
show(io, MIME("application/postscript"), plot(p; kwargs...))
|
||
|
end
|
||
|
Main.@eval function orgshow(io::IO, ::MIME"image/eps", p::Plots.Plot;
|
||
|
kwargs...)
|
||
|
show(io, MIME("image/eps"), plot(p; kwargs...))
|
||
|
end
|
||
|
Main.@eval function orgshow(io::IO, ::MIME"application/x-tex", p::Plots.Plot;
|
||
|
kwargs...)
|
||
|
show(io, MIME("application/x-tex"), plot(p; kwargs...))
|
||
|
end
|
||
|
Main.@eval function orgshow(io::IO, ::MIME"text/org", p::Plots.Plot; kwargs...)
|
||
|
# png or svg
|
||
|
p.attr[:html_output_format] = "png"
|
||
|
orgshow(io::IO, MIME("text/html"), p::Plots.Plot; kwargs...)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function define_DataFrames()
|
||
|
Main.@eval function orgshow(io::IO, ::MIME"text/csv", d::DataFrames.DataFrame)
|
||
|
orgshow(io, MIME("text/org"), d)
|
||
|
end
|
||
|
Main.@eval function orgshow(io::IO, ::MIME"text/org", d::DataFrames.DataFrame)
|
||
|
out = join(string.(names(d)), ',') * '\n'
|
||
|
out *= join([join(x, ',') for x in eachrow(d) .|> collect],'\n')
|
||
|
print(io, out)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function define_NamedArrays()
|
||
|
Main.@eval function orgshow(io::IO, ::MIME"text/org",
|
||
|
na::NamedArrays.NamedArray{T,2} where T <: Any)
|
||
|
n = names(na)
|
||
|
a = collect(na)
|
||
|
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)
|
||
|
], ',')])
|
||
|
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)
|
||
|
n = names(na)
|
||
|
a = collect(na)
|
||
|
print(io, string(na.dimnames[1], ',', '\n'))
|
||
|
print(io, join([join([n[1][i], a[i]], ',')
|
||
|
for i in 1:length(n[1])], '\n'))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
define_package_functions(pkg::Symbol) = (@eval $pkg)()
|
||
|
|
||
|
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
|
||
|
try
|
||
|
Main.eval(Meta.parse(
|
||
|
"""begin
|
||
|
$_imports
|
||
|
end"""))
|
||
|
true
|
||
|
catch e
|
||
|
@show e
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function OrgBabelReload()
|
||
|
"Defines show method based on loaded packages"
|
||
|
for pkg in supported_packages
|
||
|
if isdefined(Main, pkg) && (isa(getfield(Main, pkg), Module) ||
|
||
|
isa(getfield(Main, pkg), UnionAll))
|
||
|
define_package_functions(Symbol("define_", pkg))
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
const Mimes = Dict(:org => "text/org",
|
||
|
:csv => "text/csv",
|
||
|
:png => "image/png",
|
||
|
:svg => "image/svg+xml",
|
||
|
:pdf => "application/pdf",
|
||
|
:html => "text/html",
|
||
|
:auto => "text/org",
|
||
|
:ps => "application/postscript",
|
||
|
:eps => "image/eps",
|
||
|
:tex => "application/x-tex")
|
||
|
|
||
|
function OrgBabelFormat(output_type::Symbol,
|
||
|
output_file,
|
||
|
dir, vars,
|
||
|
src_file,
|
||
|
silently::Bool,
|
||
|
kwargs)
|
||
|
content = read(src_file, String)
|
||
|
# Fake a prompt with the current input
|
||
|
try
|
||
|
println(string("\njulia> ", content))
|
||
|
catch
|
||
|
end
|
||
|
# Dispatch on output type
|
||
|
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"))
|
||
|
catch e
|
||
|
e
|
||
|
end
|
||
|
end
|
||
|
if !silently
|
||
|
try
|
||
|
print(result)
|
||
|
catch e
|
||
|
println("Error $e while showing results")
|
||
|
end
|
||
|
end
|
||
|
# Decide output type.
|
||
|
# If the output has an extension, use it.
|
||
|
# else, use the exporter format. Fallback to text/org
|
||
|
output_ext = replace(splitext(output_file)[2], "." => "")
|
||
|
required_format = isempty(output_ext) ? :auto : Symbol(output_ext)
|
||
|
mime = get(Mimes, required_format, "text/org")
|
||
|
temporary_output = IOBuffer()
|
||
|
# Output directly to org (no :file, -> save to output_file)
|
||
|
try
|
||
|
orgshow(temporary_output,
|
||
|
MIME(mime), result; Base.eval(Meta.parse(kwargs))...)
|
||
|
catch e
|
||
|
@error "Probable ob-julia error! Please report to the author!"
|
||
|
@error "Error: $e"
|
||
|
print(temporary_output,
|
||
|
"Probable ob-julia error! Please report to the author!",
|
||
|
"Error: $e")
|
||
|
end
|
||
|
write(output_file, take!(temporary_output))
|
||
|
elseif output_type == :output
|
||
|
temporary_output_file = tempname()
|
||
|
open(temporary_output_file, create = true, write = true) do f
|
||
|
redirect_stdout(f) do
|
||
|
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"))
|
||
|
catch e
|
||
|
println(e)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
if !silently
|
||
|
# It's stupid to write and read it but I don't know how to
|
||
|
# save redirect_stdout to IOBuffer or similar
|
||
|
print(read(temporary_output_file, String))
|
||
|
end
|
||
|
mv(temporary_output_file, output_file, force = true)
|
||
|
else
|
||
|
"ERROR: invalid ouput type"
|
||
|
end
|
||
|
return nothing
|
||
|
end
|
||
|
|
||
|
OrgBabelReload()
|