Skip to content

Commit 15147da

Browse files
IanButterworthKristofferC
authored andcommitted
REPL: call display on the backend (#57773)
(cherry picked from commit c75cf3f)
1 parent 78f810b commit 15147da

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
@@ -120,6 +120,22 @@ mutable struct REPLBackend
120120
end
121121
REPLBackend() = REPLBackend(Channel(1), Channel(1), false)
122122

123+
# A reference to a backend that is not mutable
124+
struct REPLBackendRef
125+
repl_channel::Channel{Any}
126+
response_channel::Channel{Any}
127+
end
128+
REPLBackendRef(backend::REPLBackend) = REPLBackendRef(backend.repl_channel, backend.response_channel)
129+
130+
function destroy(ref::REPLBackendRef, state::Task)
131+
if istaskfailed(state)
132+
close(ref.repl_channel, TaskFailedException(state))
133+
close(ref.response_channel, TaskFailedException(state))
134+
end
135+
close(ref.repl_channel)
136+
close(ref.response_channel)
137+
end
138+
123139
"""
124140
softscope(ex)
125141
@@ -418,12 +434,23 @@ function repl_backend_loop(backend::REPLBackend, get_module::Function)
418434
while true
419435
tls = task_local_storage()
420436
tls[:SOURCE_PATH] = nothing
421-
ast, show_value = take!(backend.repl_channel)
437+
ast_or_func, show_value = take!(backend.repl_channel)
422438
if show_value == -1
423439
# exit flag
424440
break
425441
end
426-
eval_user_input(ast, backend, get_module())
442+
if show_value == 2 # 2 indicates a function to be called
443+
f = ast_or_func
444+
try
445+
ret = f()
446+
put!(backend.response_channel, Pair{Any, Bool}(ret, false))
447+
catch err
448+
put!(backend.response_channel, Pair{Any, Bool}(err, true))
449+
end
450+
else
451+
ast = ast_or_func
452+
eval_user_input(ast, backend, get_module())
453+
end
427454
end
428455
return nothing
429456
end
@@ -526,7 +553,7 @@ function print_response(repl::AbstractREPL, response, show_value::Bool, have_col
526553
repl.waserror = response[2]
527554
with_repl_linfo(repl) do io
528555
io = IOContext(io, :module => Base.active_module(repl)::Module)
529-
print_response(io, response, show_value, have_color, specialdisplay(repl))
556+
print_response(io, response, backend(repl), show_value, have_color, specialdisplay(repl))
530557
end
531558
return nothing
532559
end
@@ -543,7 +570,7 @@ function repl_display_error(errio::IO, @nospecialize errval)
543570
return nothing
544571
end
545572

546-
function print_response(errio::IO, response, show_value::Bool, have_color::Bool, specialdisplay::Union{AbstractDisplay,Nothing}=nothing)
573+
function print_response(errio::IO, response, backend::Union{REPLBackendRef,Nothing}, show_value::Bool, have_color::Bool, specialdisplay::Union{AbstractDisplay,Nothing}=nothing)
547574
Base.sigatomic_begin()
548575
val, iserr = response
549576
while true
@@ -555,15 +582,19 @@ function print_response(errio::IO, response, show_value::Bool, have_color::Bool,
555582
repl_display_error(errio, val)
556583
else
557584
if val !== nothing && show_value
558-
try
559-
if specialdisplay === nothing
585+
val2, iserr = if specialdisplay === nothing
586+
# display calls may require being run on the main thread
587+
eval_with_backend(backend) do
560588
Base.invokelatest(display, val)
561-
else
589+
end
590+
else
591+
eval_with_backend(backend) do
562592
Base.invokelatest(display, specialdisplay, val)
563593
end
564-
catch
594+
end
595+
if iserr
565596
println(errio, "Error showing value of type ", typeof(val), ":")
566-
rethrow()
597+
throw(val2)
567598
end
568599
end
569600
end
@@ -593,21 +624,7 @@ function print_response(errio::IO, response, show_value::Bool, have_color::Bool,
593624
nothing
594625
end
595626

596-
# A reference to a backend that is not mutable
597-
struct REPLBackendRef
598-
repl_channel::Channel{Any}
599-
response_channel::Channel{Any}
600-
end
601-
REPLBackendRef(backend::REPLBackend) = REPLBackendRef(backend.repl_channel, backend.response_channel)
602627

603-
function destroy(ref::REPLBackendRef, state::Task)
604-
if istaskfailed(state)
605-
close(ref.repl_channel, TaskFailedException(state))
606-
close(ref.response_channel, TaskFailedException(state))
607-
end
608-
close(ref.repl_channel)
609-
close(ref.response_channel)
610-
end
611628

612629
"""
613630
run_repl(repl::AbstractREPL)
@@ -1128,12 +1145,27 @@ find_hist_file() = get(ENV, "JULIA_HISTORY",
11281145
!isempty(DEPOT_PATH) ? joinpath(DEPOT_PATH[1], "logs", "repl_history.jl") :
11291146
error("DEPOT_PATH is empty and ENV[\"JULIA_HISTORY\"] not set."))
11301147

1131-
backend(r::AbstractREPL) = r.backendref
1148+
backend(r::AbstractREPL) = hasproperty(r, :backendref) ? r.backendref : nothing
11321149

1133-
function eval_with_backend(ast, backend::REPLBackendRef)
1134-
put!(backend.repl_channel, (ast, 1))
1150+
1151+
function eval_with_backend(ast::Expr, backend::REPLBackendRef)
1152+
put!(backend.repl_channel, (ast, 1)) # (f, show_value)
1153+
return take!(backend.response_channel) # (val, iserr)
1154+
end
1155+
function eval_with_backend(f, backend::REPLBackendRef)
1156+
put!(backend.repl_channel, (f, 2)) # (f, show_value) 2 indicates function (rather than ast)
11351157
return take!(backend.response_channel) # (val, iserr)
11361158
end
1159+
# if no backend just eval (used by tests)
1160+
function eval_with_backend(f, backend::Nothing)
1161+
try
1162+
ret = f()
1163+
return (ret, false) # (val, iserr)
1164+
catch err
1165+
return (err, true)
1166+
end
1167+
end
1168+
11371169

11381170
function respond(f, repl, main; pass_empty::Bool = false, suppress_on_semicolon::Bool = true)
11391171
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
@@ -925,7 +925,7 @@ function test19864()
925925
@eval Base.showerror(io::IO, e::Error19864) = print(io, "correct19864")
926926
buf = IOBuffer()
927927
fake_response = (Base.ExceptionStack([(exception=Error19864(),backtrace=Ptr{Cvoid}[])]),true)
928-
REPL.print_response(buf, fake_response, false, false, nothing)
928+
REPL.print_response(buf, fake_response, nothing, false, false, nothing)
929929
return String(take!(buf))
930930
end
931931
@test occursin("correct19864", test19864())

0 commit comments

Comments
 (0)