From 4b99196425bd3477ba9504de64bdaf0c3ba4886a Mon Sep 17 00:00:00 2001 From: Sebastian Pfitzner Date: Sun, 7 Apr 2019 14:23:36 +0300 Subject: [PATCH] Improve REPL completions (#30569) * fix internal repl completion error * fix error with broadcast method completions * method completions for broadcasted functioncalls * better broadcast funcall completions (cherry picked from commit a0474d7cc2905da1f4e83998fcf5fa8a73834488) --- stdlib/REPL/src/REPLCompletions.jl | 31 +++++++++++++++++++++-------- stdlib/REPL/test/replcompletions.jl | 18 +++++++++++++++++ 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index d9a9136074d8d..571d50c2130fe 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -353,7 +353,7 @@ get_value(sym, fn) = (sym, true) function get_value_getfield(ex::Expr, fn) # Example :((top(getfield))(Base,:max)) val, found = get_value_getfield(ex.args[2],fn) #Look up Base in Main and returns the module - found || return (nothing, false) + (found && length(ex.args) >= 3) || return (nothing, false) return get_value_getfield(ex.args[3], val) #Look up max in Base and returns the function if found. end get_value_getfield(sym, fn) = get_value(sym, fn) @@ -407,7 +407,7 @@ function try_get_type(sym::Expr, fn::Module) elseif sym.head === :ref # some simple cases of `expand` return try_get_type(Expr(:call, GlobalRef(Base, :getindex), sym.args...), fn) - elseif sym.head === :. + elseif sym.head === :. && sym.args[2] isa QuoteNode # second check catches broadcasting return try_get_type(Expr(:call, GlobalRef(Core, :getfield), sym.args...), fn) end return (Any, false) @@ -432,10 +432,21 @@ function complete_methods(ex_org::Expr, context_module=Main)::Vector{Completion} args_ex = Any[] func, found = get_value(ex_org.args[1], context_module) !found && return Completion[] - for ex in ex_org.args[2:end] - val, found = get_type(ex, context_module) - push!(args_ex, val) + + funargs = ex_org.args[2:end] + # handle broadcasting, but only handle number of arguments instead of + # argument types + if ex_org.head === :. && ex_org.args[2] isa Expr + for _ in ex_org.args[2].args + push!(args_ex, Any) + end + else + for ex in funargs + val, found = get_type(ex, context_module) + push!(args_ex, val) + end end + out = Completion[] t_in = Tuple{Core.Typeof(func), args_ex...} # Input types na = length(args_ex)+1 @@ -610,12 +621,16 @@ function completions(string, pos, context_module=Main)::Completions # Make sure that only bslash_completions is working on strings inc_tag==:string && return String[], 0:-1, false - if inc_tag == :other && should_method_complete(partial) frange, method_name_end = find_start_brace(partial) ex = Meta.parse(partial[frange] * ")", raise=false, depwarn=false) - if isa(ex, Expr) && ex.head==:call - return complete_methods(ex, context_module), first(frange):method_name_end, false + + if isa(ex, Expr) + if ex.head==:call + return complete_methods(ex, context_module), first(frange):method_name_end, false + elseif ex.head==:. && ex.args[2] isa Expr && ex.args[2].head==:tuple + return complete_methods(ex, context_module), first(frange):(method_name_end - 1), false + end end elseif inc_tag == :comment return Completion[], 0:-1, false diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index 15bcc527c6953..eb19f8d60097b 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -960,6 +960,16 @@ let s = "type_test.xx.y" @test s[r] == "y" end +let s = ":(function foo(::Int) end).args[1].args[2]." + c, r = test_complete_context(s) + @test c == Any[] +end + +let s = "log(log.(x)," + c, r = test_complete_context(s) + @test !isempty(c) +end + let s = "Base.return_types(getin" c, r = test_complete_context(s) @test "getindex" in c @@ -981,6 +991,14 @@ let s = "test(1,1, " @test s[r] == "test" end +let s = "test.(1,1, " + c, r, res = test_complete_context(s) + @test !res + @test length(c) == 4 + @test r == 1:4 + @test s[r] == "test" +end + let s = "prevind(\"θ\",1," c, r, res = test_complete_context(s) @test c[1] == string(first(methods(prevind, Tuple{String, Int})))