Skip to content

Commit bbb2720

Browse files
IanButterworthKristofferC
authored andcommitted
REPL: call display on the backend (#57773)
(cherry picked from commit c75cf3f)
1 parent 9b474fa commit bbb2720

File tree

2 files changed

+59
-27
lines changed

2 files changed

+59
-27
lines changed

stdlib/REPL/src/REPL.jl

Lines changed: 58 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,22 @@ mutable struct REPLBackend
193193
end
194194
REPLBackend() = REPLBackend(Channel(1), Channel(1), false)
195195

196+
# A reference to a backend that is not mutable
197+
struct REPLBackendRef
198+
repl_channel::Channel{Any}
199+
response_channel::Channel{Any}
200+
end
201+
REPLBackendRef(backend::REPLBackend) = REPLBackendRef(backend.repl_channel, backend.response_channel)
202+
203+
function destroy(ref::REPLBackendRef, state::Task)
204+
if istaskfailed(state)
205+
close(ref.repl_channel, TaskFailedException(state))
206+
close(ref.response_channel, TaskFailedException(state))
207+
end
208+
close(ref.repl_channel)
209+
close(ref.response_channel)
210+
end
211+
196212
"""
197213
softscope(ex)
198214
@@ -334,12 +350,23 @@ function repl_backend_loop(backend::REPLBackend, get_module::Function)
334350
while true
335351
tls = task_local_storage()
336352
tls[:SOURCE_PATH] = nothing
337-
ast, show_value = take!(backend.repl_channel)
353+
ast_or_func, show_value = take!(backend.repl_channel)
338354
if show_value == -1
339355
# exit flag
340356
break
341357
end
342-
eval_user_input(ast, backend, get_module())
358+
if show_value == 2 # 2 indicates a function to be called
359+
f = ast_or_func
360+
try
361+
ret = f()
362+
put!(backend.response_channel, Pair{Any, Bool}(ret, false))
363+
catch err
364+
put!(backend.response_channel, Pair{Any, Bool}(err, true))
365+
end
366+
else
367+
ast = ast_or_func
368+
eval_user_input(ast, backend, get_module())
369+
end
343370
end
344371
return nothing
345372
end
@@ -375,7 +402,7 @@ function print_response(repl::AbstractREPL, response, show_value::Bool, have_col
375402
repl.waserror = response[2]
376403
with_repl_linfo(repl) do io
377404
io = IOContext(io, :module => Base.active_module(repl)::Module)
378-
print_response(io, response, show_value, have_color, specialdisplay(repl))
405+
print_response(io, response, backend(repl), show_value, have_color, specialdisplay(repl))
379406
end
380407
return nothing
381408
end
@@ -392,7 +419,7 @@ function repl_display_error(errio::IO, @nospecialize errval)
392419
return nothing
393420
end
394421

395-
function print_response(errio::IO, response, show_value::Bool, have_color::Bool, specialdisplay::Union{AbstractDisplay,Nothing}=nothing)
422+
function print_response(errio::IO, response, backend::Union{REPLBackendRef,Nothing}, show_value::Bool, have_color::Bool, specialdisplay::Union{AbstractDisplay,Nothing}=nothing)
396423
Base.sigatomic_begin()
397424
val, iserr = response
398425
while true
@@ -404,15 +431,19 @@ function print_response(errio::IO, response, show_value::Bool, have_color::Bool,
404431
repl_display_error(errio, val)
405432
else
406433
if val !== nothing && show_value
407-
try
408-
if specialdisplay === nothing
434+
val2, iserr = if specialdisplay === nothing
435+
# display calls may require being run on the main thread
436+
eval_with_backend(backend) do
409437
Base.invokelatest(display, val)
410-
else
438+
end
439+
else
440+
eval_with_backend(backend) do
411441
Base.invokelatest(display, specialdisplay, val)
412442
end
413-
catch
443+
end
444+
if iserr
414445
println(errio, "Error showing value of type ", typeof(val), ":")
415-
rethrow()
446+
throw(val2)
416447
end
417448
end
418449
end
@@ -442,21 +473,7 @@ function print_response(errio::IO, response, show_value::Bool, have_color::Bool,
442473
nothing
443474
end
444475

445-
# A reference to a backend that is not mutable
446-
struct REPLBackendRef
447-
repl_channel::Channel{Any}
448-
response_channel::Channel{Any}
449-
end
450-
REPLBackendRef(backend::REPLBackend) = REPLBackendRef(backend.repl_channel, backend.response_channel)
451476

452-
function destroy(ref::REPLBackendRef, state::Task)
453-
if istaskfailed(state)
454-
close(ref.repl_channel, TaskFailedException(state))
455-
close(ref.response_channel, TaskFailedException(state))
456-
end
457-
close(ref.repl_channel)
458-
close(ref.response_channel)
459-
end
460477

461478
"""
462479
run_repl(repl::AbstractREPL)
@@ -977,12 +994,27 @@ find_hist_file() = get(ENV, "JULIA_HISTORY",
977994
!isempty(DEPOT_PATH) ? joinpath(DEPOT_PATH[1], "logs", "repl_history.jl") :
978995
error("DEPOT_PATH is empty and and ENV[\"JULIA_HISTORY\"] not set."))
979996

980-
backend(r::AbstractREPL) = r.backendref
997+
backend(r::AbstractREPL) = hasproperty(r, :backendref) ? r.backendref : nothing
981998

982-
function eval_with_backend(ast, backend::REPLBackendRef)
983-
put!(backend.repl_channel, (ast, 1))
999+
1000+
function eval_with_backend(ast::Expr, backend::REPLBackendRef)
1001+
put!(backend.repl_channel, (ast, 1)) # (f, show_value)
1002+
return take!(backend.response_channel) # (val, iserr)
1003+
end
1004+
function eval_with_backend(f, backend::REPLBackendRef)
1005+
put!(backend.repl_channel, (f, 2)) # (f, show_value) 2 indicates function (rather than ast)
9841006
return take!(backend.response_channel) # (val, iserr)
9851007
end
1008+
# if no backend just eval (used by tests)
1009+
function eval_with_backend(f, backend::Nothing)
1010+
try
1011+
ret = f()
1012+
return (ret, false) # (val, iserr)
1013+
catch err
1014+
return (err, true)
1015+
end
1016+
end
1017+
9861018

9871019
function respond(f, repl, main; pass_empty::Bool = false, suppress_on_semicolon::Bool = true)
9881020
return function do_respond(s::MIState, buf, ok::Bool)

stdlib/REPL/test/repl.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,7 @@ function test19864()
924924
@eval Base.showerror(io::IO, e::Error19864) = print(io, "correct19864")
925925
buf = IOBuffer()
926926
fake_response = (Base.ExceptionStack([(exception=Error19864(),backtrace=Ptr{Cvoid}[])]),true)
927-
REPL.print_response(buf, fake_response, false, false, nothing)
927+
REPL.print_response(buf, fake_response, nothing, false, false, nothing)
928928
return String(take!(buf))
929929
end
930930
@test occursin("correct19864", test19864())

0 commit comments

Comments
 (0)