diff --git a/stdlib/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index 4af7ea187d9e9..d3072978d2537 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -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} @@ -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 diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 34af995c9b162..aa1a51fc380aa 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -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 diff --git a/stdlib/REPL/src/precompile.jl b/stdlib/REPL/src/precompile.jl index 3154642b74307..7c45bc8a0be5b 100644 --- a/stdlib/REPL/src/precompile.jl +++ b/stdlib/REPL/src/precompile.jl @@ -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