|
|
@@ -4,6 +4,7 @@ using Electron |
|
|
|
using Mustache |
|
|
|
using JLD2 |
|
|
|
using Printf |
|
|
|
using Scratch |
|
|
|
|
|
|
|
export jld2_view |
|
|
|
|
|
|
@@ -46,9 +47,12 @@ mutable struct Viewer |
|
|
|
path |
|
|
|
keys |
|
|
|
|
|
|
|
task |
|
|
|
|
|
|
|
function Viewer(path) |
|
|
|
viewer = new() |
|
|
|
viewer.fname = last(splitpath(path)) |
|
|
|
viewer.task = @async true |
|
|
|
|
|
|
|
create_win!(viewer) |
|
|
|
|
|
|
@@ -59,6 +63,8 @@ mutable struct Viewer |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
Base.show(io::IO, viewer::Viewer) = print(io, """Viewer("$(viewer.fname)")""") |
|
|
|
|
|
|
|
function get_data(viewer, path=viewer.path) |
|
|
|
f(dict, ::Tuple{}) = dict |
|
|
|
f(dict, path) = f(dict[first(path)], Base.tail(path)) |
|
|
@@ -97,15 +103,17 @@ function update!(viewer, path) |
|
|
|
FNAME = viewer.fname, |
|
|
|
PATH = [(idx=i, name=x) for (i,x) in enumerate(path)], |
|
|
|
WARNING = warning) |
|
|
|
open("index.html", "w") do f |
|
|
|
write(f, html) |
|
|
|
end |
|
|
|
Electron.load(viewer.win, html) |
|
|
|
end |
|
|
|
return viewer |
|
|
|
end |
|
|
|
|
|
|
|
function run!(viewer) |
|
|
|
function (viewer::Viewer)(; sync=true) |
|
|
|
if !istaskdone(viewer.task) |
|
|
|
@error "Viewer is already running." |
|
|
|
return viewer |
|
|
|
end |
|
|
|
|
|
|
|
if !viewer.app.exists |
|
|
|
@warn "Window does not exist any more. Creating a new one." |
|
|
|
create_win!(viewer) |
|
|
@@ -114,7 +122,7 @@ function run!(viewer) |
|
|
|
|
|
|
|
ch = msgchannel(viewer.win) |
|
|
|
|
|
|
|
try |
|
|
|
viewer.task = @async try |
|
|
|
while true |
|
|
|
msg = try |
|
|
|
take!(ch) |
|
|
@@ -139,10 +147,15 @@ function run!(viewer) |
|
|
|
update!(viewer, path) |
|
|
|
end |
|
|
|
end |
|
|
|
catch e |
|
|
|
e == :stop || rethrow() |
|
|
|
finally |
|
|
|
close(viewer.app) |
|
|
|
sleep(0.1) |
|
|
|
end |
|
|
|
|
|
|
|
sync && wait(viewer.task) |
|
|
|
return viewer |
|
|
|
end |
|
|
|
|
|
|
|
send_signal(viewer, action::Symbol, args...) = send_signal(viewer, Val(action), args...) |
|
|
@@ -156,28 +169,116 @@ function send_signal(viewer, ::Val{:select}, idx::Integer) |
|
|
|
end |
|
|
|
|
|
|
|
function send_signal(viewer, ::Val{:select_key}, key) |
|
|
|
idx = findfirst(==(key), viewer.keys) |
|
|
|
@assert !isnothing(idx) |
|
|
|
idx = nothing |
|
|
|
for i in 1:5 |
|
|
|
idx = findfirst(==(key), viewer.keys) |
|
|
|
isnothing(idx) || break |
|
|
|
|
|
|
|
@warn "Could not find key to select. Retrying in 1s." key "try"=i |
|
|
|
sleep(1) |
|
|
|
end |
|
|
|
send_signal(viewer, :select, idx) |
|
|
|
end |
|
|
|
|
|
|
|
function stop(viewer::Viewer) |
|
|
|
schedule(viewer.task, :stop, error=true) |
|
|
|
wait(viewer.task) |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
|
jld2_view(path; sync=true) -> viewer |
|
|
|
|
|
|
|
Open a window showing the contents of the JLD2 data file located at the given path. |
|
|
|
|
|
|
|
The returned `viewer` object can be re-used to re-display the contents of the same file: |
|
|
|
|
|
|
|
viewer(; sync=true) |
|
|
|
|
|
|
|
|
|
|
|
If `sync` is `true` (the default), wait for the window to be closed before |
|
|
|
returning. |
|
|
|
|
|
|
|
Setting `sync` to `false` will however return immediately. In that case, the |
|
|
|
application window can be stopped using: |
|
|
|
|
|
|
|
JLD2View.stop(viewer) |
|
|
|
|
|
|
|
""" |
|
|
|
function jld2_view(fname; sync=true) |
|
|
|
viewer = Viewer(fname) |
|
|
|
viewer(; sync) |
|
|
|
end |
|
|
|
|
|
|
|
task = @async try |
|
|
|
run!(viewer) |
|
|
|
catch e |
|
|
|
e == :stop || rethrow() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const JULIA_FLAGS_DEFAULT = ["--startup-file=no", "--quiet"] |
|
|
|
|
|
|
|
""" |
|
|
|
JLD2View.install(; kwargs...) |
|
|
|
|
|
|
|
Install the command-line interface. |
|
|
|
|
|
|
|
*Keyword arguments:* |
|
|
|
- `command`: name of the executable command, defaults to `jld2view`. |
|
|
|
- `destdir`: writable directory (available in PATH) for the executable, defaults to `~/.julia/bin`. |
|
|
|
- `julia`: path to the julia executable, defaults to the path of the currently running julia. |
|
|
|
- `julia_flags`: vector of command-line flags for the julia executable, defaults to `$JULIA_FLAGS_DEFAULT`. |
|
|
|
- `force`: boolean used to allow overwriting existing commands, defaults to `false`. |
|
|
|
- `compile`: boolean to enable the compilation of a custom system image, defaults to `true`. |
|
|
|
""" |
|
|
|
function install(; |
|
|
|
command = "jld2view", |
|
|
|
destdir = joinpath(first(DEPOT_PATH), "bin"), |
|
|
|
julia = first(Base.julia_cmd()), |
|
|
|
julia_flags = JULIA_FLAGS_DEFAULT, |
|
|
|
force = false, |
|
|
|
compile = true) |
|
|
|
flags = copy(julia_flags) |
|
|
|
projectdir = abspath(joinpath(@__DIR__, "..")) |
|
|
|
|
|
|
|
destdir = abspath(expanduser(destdir)) |
|
|
|
launcher = joinpath(destdir, command) |
|
|
|
if ispath(launcher) && !force |
|
|
|
error("File `launcher` already exists; please set `force=true` if you really want to overwrite it.") |
|
|
|
end |
|
|
|
|
|
|
|
sync && wait(task) |
|
|
|
return (viewer, task) |
|
|
|
end |
|
|
|
if compile |
|
|
|
make = joinpath(projectdir, "build", "make.jl") |
|
|
|
scratchdir = get_scratch!(@__MODULE__, "sysimages") |
|
|
|
|
|
|
|
# Sysimage base name |
|
|
|
sysimage_name = "sysimage" |
|
|
|
|
|
|
|
# Sysimage extension |
|
|
|
sysimage_ext = if Sys.iswindows() |
|
|
|
".dll" |
|
|
|
elseif Sys.isapple() |
|
|
|
".dylib" |
|
|
|
else |
|
|
|
".so" |
|
|
|
end |
|
|
|
|
|
|
|
sysimage = joinpath(scratchdir, sysimage_name*sysimage_ext) |
|
|
|
run(`$julia $make $sysimage`) |
|
|
|
|
|
|
|
function install() |
|
|
|
julia = first(Base.julia_cmd()) |
|
|
|
make = joinpath(@__DIR__, "..", "build", "make.jl") |
|
|
|
run(`$julia $make`) |
|
|
|
push!(flags, "--sysimage=$sysimage") |
|
|
|
end |
|
|
|
|
|
|
|
flags = join(flags, " ") |
|
|
|
@info "Installing the JLD2View command-line interface" launcher julia flags projectdir |
|
|
|
|
|
|
|
tmpl = Mustache.load(joinpath(projectdir, "resources", "run.sh")) # TODO: provide a run.bat template as well? |
|
|
|
mkpath(destdir) |
|
|
|
open(launcher, "w") do f |
|
|
|
write(f, render(tmpl, |
|
|
|
JULIA = julia, |
|
|
|
FLAGS = flags, |
|
|
|
PROJECT = projectdir, |
|
|
|
SCRIPT = joinpath(projectdir, "main.jl"))) |
|
|
|
end |
|
|
|
chmod(launcher, 0o0100775) |
|
|
|
end |
|
|
|
|
|
|
|
end # module |