From 5b919ce80a245ca325ff2d1bb909915dfbd96a7c Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Fri, 24 May 2024 18:08:27 -0400 Subject: [PATCH 1/7] switch to pkg mode prompt immediately --- stdlib/REPL/src/REPL.jl | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 2613c54d16427..cf92d74e0508c 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -1230,22 +1230,34 @@ function setup_interface( if isempty(s) || position(LineEdit.buffer(s)) == 0 global pkg_mode if pkg_mode === nothing - pkgid = Base.PkgId(Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg") - REPLExt = Base.require_stdlib(pkgid, "REPLExt") - pkg_mode = nothing - if REPLExt isa Module && isdefined(REPLExt, :PkgCompletionProvider) - for mode in repl.interface.modes - if mode isa LineEdit.Prompt && mode.complete isa REPLExt.PkgCompletionProvider - pkg_mode = mode - break + LineEdit.clear_line(LineEdit.terminal(s)) + # use 6 .'s here because its the same width as the most likely `@v1.xx` env name + print(LineEdit.terminal(s), styled"{blue,bold:({gray:......}) pkg> }") + # spawn Pkg load to avoid blocking typing during loading. Typing will block if only 1 thread + t_replswitch = Threads.@spawn begin + pkgid = Base.PkgId(Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg") + REPLExt = Base.require_stdlib(pkgid, "REPLExt") + if REPLExt isa Module && isdefined(REPLExt, :PkgCompletionProvider) + for mode in repl.interface.modes + if mode isa LineEdit.Prompt && mode.complete isa REPLExt.PkgCompletionProvider + pkg_mode = mode + break + end + end + end + if pkg_mode !== nothing + buf = copy(LineEdit.buffer(s)) + transition(s, pkg_mode) do + LineEdit.state(s, pkg_mode).input_buffer = buf end end end - end - if pkg_mode !== nothing - buf = copy(LineEdit.buffer(s)) - transition(s, pkg_mode) do - LineEdit.state(s, pkg_mode).input_buffer = buf + Base.errormonitor(t_replswitch) + # while loading just accept all keys, no keymap functionality + while !istaskdone(t_replswitch) + c = read(stdin, Char) + istaskdone(t_replswitch) && break + edit_insert(s, c) end return end From cf74683aacb9483f9d026b8392370025a327b50a Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Sat, 1 Jun 2024 12:44:07 +0200 Subject: [PATCH 2/7] revert pkg_mode caching & tidy Reverts "Pkg REPL: cache `pkg_mode` lookup (#54359)" as this function is replaced when Pkg loads by a simpler repl switch so no caching is needed --- stdlib/REPL/src/REPL.jl | 60 +++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index cf92d74e0508c..782644494aa2d 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -1080,9 +1080,6 @@ setup_interface( extra_repl_keymap::Any = repl.options.extra_keymap ) = setup_interface(repl, hascolor, extra_repl_keymap) -# we have to grab this after Pkg is loaded so cache it -pkg_mode::Union{Nothing,LineEdit.Prompt} = nothing - # This non keyword method can be precompiled which is important function setup_interface( repl::LineEditREPL, @@ -1228,41 +1225,40 @@ function setup_interface( end, ']' => function (s::MIState,o...) if isempty(s) || position(LineEdit.buffer(s)) == 0 - global pkg_mode - if pkg_mode === nothing - LineEdit.clear_line(LineEdit.terminal(s)) - # use 6 .'s here because its the same width as the most likely `@v1.xx` env name - print(LineEdit.terminal(s), styled"{blue,bold:({gray:......}) pkg> }") - # spawn Pkg load to avoid blocking typing during loading. Typing will block if only 1 thread - t_replswitch = Threads.@spawn begin - pkgid = Base.PkgId(Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg") - REPLExt = Base.require_stdlib(pkgid, "REPLExt") - if REPLExt isa Module && isdefined(REPLExt, :PkgCompletionProvider) - for mode in repl.interface.modes - if mode isa LineEdit.Prompt && mode.complete isa REPLExt.PkgCompletionProvider - pkg_mode = mode - break - end - end - end - if pkg_mode !== nothing - buf = copy(LineEdit.buffer(s)) - transition(s, pkg_mode) do - LineEdit.state(s, pkg_mode).input_buffer = buf + # print a dummy pkg prompt while Pkg loads + LineEdit.clear_line(LineEdit.terminal(s)) + # use 6 .'s here because its the same width as the most likely `@v1.xx` env name + print(LineEdit.terminal(s), styled"{blue,bold:({gray:......}) pkg> }") + pkg_mode = nothing + # spawn Pkg load to avoid blocking typing during loading. Typing will block if only 1 thread + t_replswitch = Threads.@spawn begin + pkgid = Base.PkgId(Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg") + REPLExt = Base.require_stdlib(pkgid, "REPLExt") + if REPLExt isa Module && isdefined(REPLExt, :PkgCompletionProvider) + for mode in repl.interface.modes + if mode isa LineEdit.Prompt && mode.complete isa REPLExt.PkgCompletionProvider + pkg_mode = mode + break end end end - Base.errormonitor(t_replswitch) - # while loading just accept all keys, no keymap functionality - while !istaskdone(t_replswitch) - c = read(stdin, Char) - istaskdone(t_replswitch) && break - edit_insert(s, c) + if pkg_mode !== nothing + buf = copy(LineEdit.buffer(s)) + transition(s, pkg_mode) do + LineEdit.state(s, pkg_mode).input_buffer = buf + end end - return end + Base.errormonitor(t_replswitch) + # while loading just accept all keys, no keymap functionality + while !istaskdone(t_replswitch) + c = read(stdin, Char) + istaskdone(t_replswitch) && break + edit_insert(s, c) + end + else + edit_insert(s, ']') end - edit_insert(s, ']') end, # Bracketed Paste Mode From fd23f58dace4aa4f8649817b23ca422ac6230c4e Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Sat, 1 Jun 2024 18:47:30 +0200 Subject: [PATCH 3/7] don't take from stdin if loading is finished --- stdlib/REPL/src/REPL.jl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 782644494aa2d..4ad2e8a1c2b39 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -1252,9 +1252,11 @@ function setup_interface( Base.errormonitor(t_replswitch) # while loading just accept all keys, no keymap functionality while !istaskdone(t_replswitch) - c = read(stdin, Char) - istaskdone(t_replswitch) && break - edit_insert(s, c) + # wait but only take if task is still running + peek(stdin, Char) + if !istaskdone(t_replswitch) + edit_insert(s, read(stdin, Char)) + end end else edit_insert(s, ']') From 7de3591791d1e43314eb320f49fa5bb938e464fb Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Sun, 2 Jun 2024 12:18:36 -0400 Subject: [PATCH 4/7] check for hint after repl switch --- stdlib/REPL/src/REPL.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 4ad2e8a1c2b39..137aabb1fe967 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -1247,6 +1247,7 @@ function setup_interface( transition(s, pkg_mode) do LineEdit.state(s, pkg_mode).input_buffer = buf end + @invokelatest(LineEdit.check_for_hint(s)) && @invokelatest(LineEdit.refresh_line(s)) end end Base.errormonitor(t_replswitch) From 38d57c887a6fc72c709eddbac0bb3ed245457d49 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Sun, 2 Jun 2024 12:52:40 -0400 Subject: [PATCH 5/7] reduce chance of race --- stdlib/REPL/src/REPL.jl | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 137aabb1fe967..b74ea22494ade 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -1230,6 +1230,8 @@ function setup_interface( # use 6 .'s here because its the same width as the most likely `@v1.xx` env name print(LineEdit.terminal(s), styled"{blue,bold:({gray:......}) pkg> }") pkg_mode = nothing + transition_finished = false + iolock = Base.ReentrantLock() # to avoid race between tasks reading stdin & input buffer # spawn Pkg load to avoid blocking typing during loading. Typing will block if only 1 thread t_replswitch = Threads.@spawn begin pkgid = Base.PkgId(Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg") @@ -1243,11 +1245,14 @@ function setup_interface( end end if pkg_mode !== nothing - buf = copy(LineEdit.buffer(s)) - transition(s, pkg_mode) do - LineEdit.state(s, pkg_mode).input_buffer = buf + @lock iolock begin + buf = copy(LineEdit.buffer(s)) + transition(s, pkg_mode) do + LineEdit.state(s, pkg_mode).input_buffer = buf + end + @invokelatest(LineEdit.check_for_hint(s)) && @invokelatest(LineEdit.refresh_line(s)) + transition_finished = true end - @invokelatest(LineEdit.check_for_hint(s)) && @invokelatest(LineEdit.refresh_line(s)) end end Base.errormonitor(t_replswitch) @@ -1255,8 +1260,8 @@ function setup_interface( while !istaskdone(t_replswitch) # wait but only take if task is still running peek(stdin, Char) - if !istaskdone(t_replswitch) - edit_insert(s, read(stdin, Char)) + @lock iolock begin + transition_finished || edit_insert(s, read(stdin, Char)) end end else From bde18bfef3ce80faa6d3c44bf7a7f12a7d7c3c90 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Mon, 3 Jun 2024 12:55:06 -0400 Subject: [PATCH 6/7] add some precompiles --- stdlib/REPL/src/precompile.jl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/stdlib/REPL/src/precompile.jl b/stdlib/REPL/src/precompile.jl index 7299742eaef1c..3154642b74307 100644 --- a/stdlib/REPL/src/precompile.jl +++ b/stdlib/REPL/src/precompile.jl @@ -220,4 +220,14 @@ 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}}) + end # Precompile From 757fb707c674905f8b2490bf5c4d488e4997be7c Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Mon, 3 Jun 2024 16:05:19 -0400 Subject: [PATCH 7/7] only check for hint if prompt is not empty --- stdlib/REPL/src/REPL.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index b74ea22494ade..a39b44d17f9a1 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -1250,7 +1250,9 @@ function setup_interface( transition(s, pkg_mode) do LineEdit.state(s, pkg_mode).input_buffer = buf end - @invokelatest(LineEdit.check_for_hint(s)) && @invokelatest(LineEdit.refresh_line(s)) + if !isempty(s) + @invokelatest(LineEdit.check_for_hint(s)) && @invokelatest(LineEdit.refresh_line(s)) + end transition_finished = true end end