Skip to content

Commit

Permalink
REPL: improve prompt! async function handler (#54760)
Browse files Browse the repository at this point in the history
  • Loading branch information
IanButterworth authored Jun 11, 2024
1 parent d0f165f commit e7893a1
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 43 deletions.
71 changes: 38 additions & 33 deletions stdlib/REPL/src/LineEdit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ mutable struct MIState
key_repeats::Int
last_action::Symbol
current_action::Symbol
async_channel::Channel
async_channel::Channel{Function}
end

MIState(i, mod, c, a, m) = MIState(i, mod, c, a, m, String[], 0, Char[], 0, :none, :none, Channel())
MIState(i, mod, c, a, m) = MIState(i, mod, c, a, m, String[], 0, Char[], 0, :none, :none, Channel{Function}())

const BufferLike = Union{MIState,ModeState,IOBuffer}
const State = Union{MIState,ModeState}
Expand Down Expand Up @@ -2828,40 +2828,45 @@ function prompt!(term::TextTerminal, prompt::ModalInterface, s::MIState = init_s
try
activate(prompt, s, term, term)
old_state = mode(s)
l = Base.ReentrantLock()
t = @async while true
fcn = take!(s.async_channel)
status = @lock l fcn(s)
status (:ok, :ignore) || break
end
Base.errormonitor(t)
while true
kmap = keymap(s, prompt)
waitany((
@async(eof(term) || peek(term, Char)),
@async(wait(s.async_channel)),
), throw=true)
fcn = isempty(s.async_channel) ? match_input(kmap, s) : take!(s.async_channel)
kdata = keymap_data(s, prompt)
s.current_action = :unknown # if the to-be-run action doesn't update this field,
# :unknown will be recorded in the last_action field
local status
# errors in keymaps shouldn't cause the REPL to fail, so wrap in a
# try/catch block
try
status = fcn(s, kdata)
catch e
@error "Error in the keymap" exception=e,catch_backtrace()
# try to cleanup and get `s` back to its original state before returning
transition(s, :reset)
transition(s, old_state)
status = :done
end
status !== :ignore && (s.last_action = s.current_action)
if status === :abort
s.aborted = true
return buffer(s), false, false
elseif status === :done
return buffer(s), true, false
elseif status === :suspend
if Sys.isunix()
return buffer(s), true, true
fcn = match_input(kmap, s)
@lock l begin
kdata = keymap_data(s, prompt)
s.current_action = :unknown # if the to-be-run action doesn't update this field,
# :unknown will be recorded in the last_action field
local status
# errors in keymaps shouldn't cause the REPL to fail, so wrap in a
# try/catch block
try
status = fcn(s, kdata)
catch e
@error "Error in the keymap" exception=e,catch_backtrace()
# try to cleanup and get `s` back to its original state before returning
transition(s, :reset)
transition(s, old_state)
status = :done
end
status !== :ignore && (s.last_action = s.current_action)
if status === :abort
s.aborted = true
return buffer(s), false, false
elseif status === :done
return buffer(s), true, false
elseif status === :suspend
if Sys.isunix()
return buffer(s), true, true
end
else
@assert status (:ok, :ignore)
end
else
@assert status (:ok, :ignore)
end
end
finally
Expand Down
2 changes: 1 addition & 1 deletion stdlib/REPL/src/REPL.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1281,7 +1281,7 @@ function setup_interface(
REPLExt = load_pkg()
if REPLExt isa Module && isdefined(REPLExt, :PkgCompletionProvider)
put!(s.async_channel,
function (s::MIState, _)
function (s::MIState)
LineEdit.mode(s) === dummy_pkg_mode || return :ok
for mode in repl.interface.modes
if mode isa LineEdit.Prompt && mode.complete isa REPLExt.PkgCompletionProvider
Expand Down
12 changes: 3 additions & 9 deletions stdlib/REPL/src/precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -220,14 +220,8 @@ end
generate_precompile_statements()

precompile(Tuple{typeof(getproperty), REPL.REPLBackend, Symbol})

# Helps Pkg repl mode switch
precompile(Tuple{typeof(REPL.Terminals.clear_line), REPL.Terminals.TTYTerminal})
precompile(Tuple{typeof(Base.print), REPL.Terminals.TTYTerminal, Base.AnnotatedString{String}})
precompile(Tuple{typeof(Base.peek), Base.TTY, Type{Char}})
precompile(Tuple{typeof(Base.similar), Array{String, 1}})
precompile(Tuple{typeof(Base.Iterators.enumerate), Array{String, 1}})
precompile(Tuple{typeof(Base.setindex!), Array{String, 1}, String, Int64})
precompile(Tuple{typeof(Base.convert), Type{Base.Dict{String, Union{Array{String, 1}, String}}}, Base.Dict{String, Any}})
precompile(Tuple{typeof(Base.take!), Base.Channel{Function}})
precompile(Tuple{typeof(Base.put!), Base.Channel{Function}, Function})
precompile(Tuple{typeof(Core.kwcall), NamedTuple{names, T} where T<:Tuple where names, typeof(REPL.LineEdit.complete_line), REPL.LineEdit.EmptyCompletionProvider, Any})

end # Precompile

2 comments on commit e7893a1

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Executing the daily package evaluation, I will reply here when finished:

@nanosoldier runtests(isdaily = true)

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The package evaluation job you requested has completed - possible new issues were detected.
The full report is available.

Please sign in to comment.