From ba8e1662428b80cd0ef7d09e897dcd127dea85a1 Mon Sep 17 00:00:00 2001 From: Ian Date: Tue, 29 Dec 2020 03:53:30 -0500 Subject: [PATCH] REPL: offer to try to install package if not found --- stdlib/REPL/src/REPL.jl | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index d17482ec453cb..35cf6fc3c7968 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -776,9 +776,44 @@ find_hist_file() = get(ENV, "JULIA_HISTORY", backend(r::AbstractREPL) = r.backendref +# Allows an external package to add hooks into the code loading +# return true if all packages could be installed, false if not +# to e.g. install packages on demand +const install_packages_hooks = Any[] + function eval_with_backend(ast, backend::REPLBackendRef) + mods_to_be_loaded = modules_to_be_loaded(ast) + mods_not_found = list_unfindable_modules(mods_to_be_loaded) + !isempty(mods_not_found) && pass_to_install_package_hooks(mods_not_found) put!(backend.repl_channel, (ast, 1)) - return take!(backend.response_channel) # (val, iserr) + resp = take!(backend.response_channel) # (val, iserr) + return resp +end + +function modules_to_be_loaded(ast, mods = Symbol[]) + if ast.head in [:using, :import] + for arg in ast.args + if first(arg.args) isa Symbol # i.e. `Foo` + push!(mods, first(arg.args)) + else # i.e. `Foo: Bar` + push!(mods, first(first(arg.args).args)) + end + end + end + for arg in ast.args + arg isa Expr && modules_to_be_loaded(arg, mods) + end + return mods +end + +function list_unfindable_modules(mods) + filter(mod -> isnothing(Base.identify_package(String(mod))), mods) +end + +function pass_to_install_package_hooks(mods) + for f in install_packages_hooks + f(mods) && return + end end function respond(f, repl, main; pass_empty::Bool = false, suppress_on_semicolon::Bool = true)