@@ -269,7 +269,7 @@ function check_for_missing_packages_and_run_hooks(ast)
269
269
mods = modules_to_be_loaded (ast)
270
270
filter! (mod -> isnothing (Base. identify_package (String (mod))), mods) # keep missing modules
271
271
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 ( )
273
273
for f in install_packages_hooks
274
274
Base. invokelatest (f, mods) && return
275
275
end
@@ -575,6 +575,7 @@ mutable struct LineEditREPL <: AbstractREPL
575
575
answer_color:: String
576
576
shell_color:: String
577
577
help_color:: String
578
+ pkg_color:: String
578
579
history_file:: Bool
579
580
in_shell:: Bool
580
581
in_help:: Bool
@@ -587,13 +588,13 @@ mutable struct LineEditREPL <: AbstractREPL
587
588
interface:: ModalInterface
588
589
backendref:: REPLBackendRef
589
590
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)
591
592
opts = Options ()
592
593
opts. hascolor = hascolor
593
594
if ! hascolor
594
595
opts. beep_colors = [" " ]
595
596
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,
597
598
in_help,envcolors,false ,nothing , opts, nothing , Tuple{String,Int}[])
598
599
end
599
600
end
@@ -610,6 +611,7 @@ LineEditREPL(t::TextTerminal, hascolor::Bool, envcolors::Bool=false) =
610
611
hascolor ? Base. answer_color () : " " ,
611
612
hascolor ? Base. text_colors[:red ] : " " ,
612
613
hascolor ? Base. text_colors[:yellow ] : " " ,
614
+ hascolor ? Base. text_colors[:blue ] : " " ,
613
615
false , false , false , envcolors
614
616
)
615
617
@@ -1080,6 +1082,20 @@ setup_interface(
1080
1082
extra_repl_keymap:: Any = repl. options. extra_keymap
1081
1083
) = setup_interface (repl, hascolor, extra_repl_keymap)
1082
1084
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
+
1083
1099
# This non keyword method can be precompiled which is important
1084
1100
function setup_interface (
1085
1101
repl:: LineEditREPL ,
@@ -1155,14 +1171,43 @@ function setup_interface(
1155
1171
end ,
1156
1172
sticky = true )
1157
1173
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
+
1158
1202
1159
1203
# ################################ Stage II #############################
1160
1204
1161
1205
# Setup history
1162
1206
# We will have a unified history for all REPL modes
1163
1207
hp = REPLHistoryProvider (Dict {Symbol,Prompt} (:julia => julia_prompt,
1164
1208
:shell => shell_mode,
1165
- :help => help_mode))
1209
+ :help => help_mode,
1210
+ :pkg => dummy_pkg_mode))
1166
1211
if repl. history_file
1167
1212
try
1168
1213
hist_path = find_hist_file ()
@@ -1185,6 +1230,7 @@ function setup_interface(
1185
1230
julia_prompt. hist = hp
1186
1231
shell_mode. hist = hp
1187
1232
help_mode. hist = hp
1233
+ dummy_pkg_mode. hist = hp
1188
1234
1189
1235
julia_prompt. on_done = respond (x-> Base. parse_input_line (x,filename= repl_filename (repl,hp)), repl, julia_prompt)
1190
1236
@@ -1225,47 +1271,36 @@ function setup_interface(
1225
1271
end ,
1226
1272
' ]' => function (s:: MIState ,o... )
1227
1273
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
1236
1280
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 ()
1239
1282
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
1244
1299
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
+ )
1258
1301
end
1259
1302
end
1260
1303
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
1269
1304
else
1270
1305
edit_insert (s, ' ]' )
1271
1306
end
@@ -1448,9 +1483,9 @@ function setup_interface(
1448
1483
b = Dict{Any,Any}[skeymap, mk, prefix_keymap, LineEdit. history_keymap, LineEdit. default_keymap, LineEdit. escape_defaults]
1449
1484
prepend! (b, extra_repl_keymap)
1450
1485
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)
1452
1487
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]
1454
1489
return ModalInterface (allprompts)
1455
1490
end
1456
1491
0 commit comments