@@ -269,7 +269,7 @@ function check_for_missing_packages_and_run_hooks(ast)
269269 mods = modules_to_be_loaded (ast)
270270 filter! (mod -> isnothing (Base. identify_package (String (mod))), mods) # keep missing modules
271271 if ! isempty (mods)
272- isempty (install_packages_hooks) && Base . require_stdlib (Base . PkgId (Base . UUID ( " 44cfe95a-1eb2-52ea-b672-e2afdf69b78f " ), " Pkg " ) )
272+ isempty (install_packages_hooks) && load_pkg ( )
273273 for f in install_packages_hooks
274274 Base. invokelatest (f, mods) && return
275275 end
@@ -575,6 +575,7 @@ mutable struct LineEditREPL <: AbstractREPL
575575 answer_color:: String
576576 shell_color:: String
577577 help_color:: String
578+ pkg_color:: String
578579 history_file:: Bool
579580 in_shell:: Bool
580581 in_help:: Bool
@@ -587,13 +588,13 @@ mutable struct LineEditREPL <: AbstractREPL
587588 interface:: ModalInterface
588589 backendref:: REPLBackendRef
589590 frontend_task:: Task
590- function LineEditREPL (t,hascolor,prompt_color,input_color,answer_color,shell_color,help_color,history_file,in_shell,in_help,envcolors)
591+ function LineEditREPL (t,hascolor,prompt_color,input_color,answer_color,shell_color,help_color,pkg_color, history_file,in_shell,in_help,envcolors)
591592 opts = Options ()
592593 opts. hascolor = hascolor
593594 if ! hascolor
594595 opts. beep_colors = [" " ]
595596 end
596- new (t,hascolor,prompt_color,input_color,answer_color,shell_color,help_color,history_file,in_shell,
597+ new (t,hascolor,prompt_color,input_color,answer_color,shell_color,help_color,pkg_color, history_file,in_shell,
597598 in_help,envcolors,false ,nothing , opts, nothing , Tuple{String,Int}[])
598599 end
599600end
@@ -610,6 +611,7 @@ LineEditREPL(t::TextTerminal, hascolor::Bool, envcolors::Bool=false) =
610611 hascolor ? Base. answer_color () : " " ,
611612 hascolor ? Base. text_colors[:red ] : " " ,
612613 hascolor ? Base. text_colors[:yellow ] : " " ,
614+ hascolor ? Base. text_colors[:blue ] : " " ,
613615 false , false , false , envcolors
614616 )
615617
@@ -1080,6 +1082,20 @@ setup_interface(
10801082 extra_repl_keymap:: Any = repl. options. extra_keymap
10811083) = setup_interface (repl, hascolor, extra_repl_keymap)
10821084
1085+ const Pkg_pkgid = Base. PkgId (Base. UUID (" 44cfe95a-1eb2-52ea-b672-e2afdf69b78f" ), " Pkg" )
1086+ const Pkg_REPLExt_pkgid = Base. PkgId (Base. UUID (" ceef7b17-42e7-5b1c-81d4-4cc4a2494ccf" ), " REPLExt" )
1087+
1088+ function load_pkg ()
1089+ @lock Base. require_lock begin
1090+ REPLExt = Base. require_stdlib (Pkg_pkgid, " REPLExt" )
1091+ # require_stdlib does not guarantee that the `__init__` of the package is done when loading is done async
1092+ # but we need to wait for the repl mode to be set up
1093+ lock = get (Base. package_locks, Pkg_REPLExt_pkgid. uuid, nothing )
1094+ lock != = nothing && wait (lock[2 ])
1095+ return REPLExt
1096+ end
1097+ end
1098+
10831099# This non keyword method can be precompiled which is important
10841100function setup_interface (
10851101 repl:: LineEditREPL ,
@@ -1155,14 +1171,43 @@ function setup_interface(
11551171 end ,
11561172 sticky = true )
11571173
1174+ # Set up dummy Pkg mode that will be replaced once Pkg is loaded
1175+ # use 6 dots to occupy the same space as the most likely "@v1.xx" env name
1176+ dummy_pkg_mode = Prompt (" (......) $PKG_PROMPT " ,
1177+ prompt_prefix = hascolor ? repl. pkg_color : " " ,
1178+ prompt_suffix = hascolor ?
1179+ (repl. envcolors ? Base. input_color : repl. input_color) : " " ,
1180+ repl = repl,
1181+ complete = LineEdit. EmptyCompletionProvider (),
1182+ on_done = respond (line-> nothing , repl, julia_prompt),
1183+ on_enter = function (s:: MIState )
1184+ # This is hit when the user tries to execute a command before the real Pkg mode has been
1185+ # switched to. Ok to do this even if Pkg is loading on the other task because of the loading lock.
1186+ REPLExt = load_pkg ()
1187+ if REPLExt isa Module && isdefined (REPLExt, :PkgCompletionProvider )
1188+ for mode in repl. interface. modes
1189+ if mode isa LineEdit. Prompt && mode. complete isa REPLExt. PkgCompletionProvider
1190+ # pkg mode
1191+ buf = copy (LineEdit. buffer (s))
1192+ transition (s, mode) do
1193+ LineEdit. state (s, mode). input_buffer = buf
1194+ end
1195+ end
1196+ end
1197+ end
1198+ return true
1199+ end ,
1200+ sticky = true )
1201+
11581202
11591203 # ################################ Stage II #############################
11601204
11611205 # Setup history
11621206 # We will have a unified history for all REPL modes
11631207 hp = REPLHistoryProvider (Dict {Symbol,Prompt} (:julia => julia_prompt,
11641208 :shell => shell_mode,
1165- :help => help_mode))
1209+ :help => help_mode,
1210+ :pkg => dummy_pkg_mode))
11661211 if repl. history_file
11671212 try
11681213 hist_path = find_hist_file ()
@@ -1185,6 +1230,7 @@ function setup_interface(
11851230 julia_prompt. hist = hp
11861231 shell_mode. hist = hp
11871232 help_mode. hist = hp
1233+ dummy_pkg_mode. hist = hp
11881234
11891235 julia_prompt. on_done = respond (x-> Base. parse_input_line (x,filename= repl_filename (repl,hp)), repl, julia_prompt)
11901236
@@ -1225,47 +1271,36 @@ function setup_interface(
12251271 end ,
12261272 ' ]' => function (s:: MIState ,o... )
12271273 if isempty (s) || position (LineEdit. buffer (s)) == 0
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
1274+ buf = copy (LineEdit. buffer (s))
1275+ transition (s, dummy_pkg_mode) do
1276+ LineEdit. state (s, dummy_pkg_mode). input_buffer = buf
1277+ end
1278+ # load Pkg on another thread if available so that typing in the dummy Pkg prompt
1279+ # isn't blocked, but instruct the main REPL task to do the transition via s.async_channel
12361280 t_replswitch = Threads. @spawn begin
1237- pkgid = Base. PkgId (Base. UUID (" 44cfe95a-1eb2-52ea-b672-e2afdf69b78f" ), " Pkg" )
1238- REPLExt = Base. require_stdlib (pkgid, " REPLExt" )
1281+ REPLExt = load_pkg ()
12391282 if REPLExt isa Module && isdefined (REPLExt, :PkgCompletionProvider )
1240- for mode in repl. interface. modes
1241- if mode isa LineEdit. Prompt && mode. complete isa REPLExt. PkgCompletionProvider
1242- pkg_mode = mode
1243- break
1283+ put! (s. async_channel,
1284+ function (s:: MIState , _)
1285+ LineEdit. mode (s) === dummy_pkg_mode || return :ok
1286+ for mode in repl. interface. modes
1287+ if mode isa LineEdit. Prompt && mode. complete isa REPLExt. PkgCompletionProvider
1288+ buf = copy (LineEdit. buffer (s))
1289+ transition (s, mode) do
1290+ LineEdit. state (s, mode). input_buffer = buf
1291+ end
1292+ if ! isempty (s) && @invokelatest (LineEdit. check_for_hint (s))
1293+ @invokelatest (LineEdit. refresh_line (s))
1294+ end
1295+ break
1296+ end
1297+ end
1298+ return :ok
12441299 end
1245- end
1246- 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
1300+ )
12581301 end
12591302 end
12601303 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))
1267- end
1268- end
12691304 else
12701305 edit_insert (s, ' ]' )
12711306 end
@@ -1448,9 +1483,9 @@ function setup_interface(
14481483 b = Dict{Any,Any}[skeymap, mk, prefix_keymap, LineEdit. history_keymap, LineEdit. default_keymap, LineEdit. escape_defaults]
14491484 prepend! (b, extra_repl_keymap)
14501485
1451- shell_mode. keymap_dict = help_mode. keymap_dict = LineEdit. keymap (b)
1486+ shell_mode. keymap_dict = help_mode. keymap_dict = dummy_pkg_mode . keymap_dict = LineEdit. keymap (b)
14521487
1453- allprompts = LineEdit. TextInterface[julia_prompt, shell_mode, help_mode, search_prompt, prefix_prompt]
1488+ allprompts = LineEdit. TextInterface[julia_prompt, shell_mode, help_mode, dummy_pkg_mode, search_prompt, prefix_prompt]
14541489 return ModalInterface (allprompts)
14551490end
14561491
0 commit comments