Skip to content

Commit 13635e1

Browse files
Switch to Pkg mode prompt immediately and load Pkg in the background (#54594)
Because Pkg is now a pkgimage it can load slowly on slower machines, which is a bit frustrating in the first repl switch. This makes the repl immediately switch to a dummy prompt that looks like Pkg mode to allow the user to keep typing while Pkg loads. During which the keymap is disabled. It works best if julia has >1 thread, otherwise typing stalls during Pkg load. If Pkg takes longer to load than the user to type the command and press return, then the UX isn't great as it won't do anything. https://github.com/JuliaLang/julia/assets/1694067/1bf17323-441a-4db2-8a3b-4d571eac622f
1 parent 4e211eb commit 13635e1

File tree

2 files changed

+40
-12
lines changed

2 files changed

+40
-12
lines changed

stdlib/REPL/src/REPL.jl

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,9 +1080,6 @@ setup_interface(
10801080
extra_repl_keymap::Any = repl.options.extra_keymap
10811081
) = setup_interface(repl, hascolor, extra_repl_keymap)
10821082

1083-
# we have to grab this after Pkg is loaded so cache it
1084-
pkg_mode::Union{Nothing,LineEdit.Prompt} = nothing
1085-
10861083
# This non keyword method can be precompiled which is important
10871084
function setup_interface(
10881085
repl::LineEditREPL,
@@ -1228,11 +1225,17 @@ function setup_interface(
12281225
end,
12291226
']' => function (s::MIState,o...)
12301227
if isempty(s) || position(LineEdit.buffer(s)) == 0
1231-
global pkg_mode
1232-
if pkg_mode === nothing
1228+
# print a dummy pkg prompt while Pkg loads
1229+
LineEdit.clear_line(LineEdit.terminal(s))
1230+
# use 6 .'s here because its the same width as the most likely `@v1.xx` env name
1231+
print(LineEdit.terminal(s), styled"{blue,bold:({gray:......}) pkg> }")
1232+
pkg_mode = nothing
1233+
transition_finished = false
1234+
iolock = Base.ReentrantLock() # to avoid race between tasks reading stdin & input buffer
1235+
# spawn Pkg load to avoid blocking typing during loading. Typing will block if only 1 thread
1236+
t_replswitch = Threads.@spawn begin
12331237
pkgid = Base.PkgId(Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg")
12341238
REPLExt = Base.require_stdlib(pkgid, "REPLExt")
1235-
pkg_mode = nothing
12361239
if REPLExt isa Module && isdefined(REPLExt, :PkgCompletionProvider)
12371240
for mode in repl.interface.modes
12381241
if mode isa LineEdit.Prompt && mode.complete isa REPLExt.PkgCompletionProvider
@@ -1241,16 +1244,31 @@ function setup_interface(
12411244
end
12421245
end
12431246
end
1247+
if pkg_mode !== nothing
1248+
@lock iolock begin
1249+
buf = copy(LineEdit.buffer(s))
1250+
transition(s, pkg_mode) do
1251+
LineEdit.state(s, pkg_mode).input_buffer = buf
1252+
end
1253+
if !isempty(s)
1254+
@invokelatest(LineEdit.check_for_hint(s)) && @invokelatest(LineEdit.refresh_line(s))
1255+
end
1256+
transition_finished = true
1257+
end
1258+
end
12441259
end
1245-
if pkg_mode !== nothing
1246-
buf = copy(LineEdit.buffer(s))
1247-
transition(s, pkg_mode) do
1248-
LineEdit.state(s, pkg_mode).input_buffer = buf
1260+
Base.errormonitor(t_replswitch)
1261+
# while loading just accept all keys, no keymap functionality
1262+
while !istaskdone(t_replswitch)
1263+
# wait but only take if task is still running
1264+
peek(stdin, Char)
1265+
@lock iolock begin
1266+
transition_finished || edit_insert(s, read(stdin, Char))
12491267
end
1250-
return
12511268
end
1269+
else
1270+
edit_insert(s, ']')
12521271
end
1253-
edit_insert(s, ']')
12541272
end,
12551273

12561274
# Bracketed Paste Mode

stdlib/REPL/src/precompile.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,4 +220,14 @@ end
220220
generate_precompile_statements()
221221

222222
precompile(Tuple{typeof(getproperty), REPL.REPLBackend, Symbol})
223+
224+
# Helps Pkg repl mode switch
225+
precompile(Tuple{typeof(REPL.Terminals.clear_line), REPL.Terminals.TTYTerminal})
226+
precompile(Tuple{typeof(Base.print), REPL.Terminals.TTYTerminal, Base.AnnotatedString{String}})
227+
precompile(Tuple{typeof(Base.peek), Base.TTY, Type{Char}})
228+
precompile(Tuple{typeof(Base.similar), Array{String, 1}})
229+
precompile(Tuple{typeof(Base.Iterators.enumerate), Array{String, 1}})
230+
precompile(Tuple{typeof(Base.setindex!), Array{String, 1}, String, Int64})
231+
precompile(Tuple{typeof(Base.convert), Type{Base.Dict{String, Union{Array{String, 1}, String}}}, Base.Dict{String, Any}})
232+
223233
end # Precompile

0 commit comments

Comments
 (0)