Skip to content

Commit

Permalink
Improve REPL completions (#30569)
Browse files Browse the repository at this point in the history
* fix internal repl completion error

* fix error with broadcast method completions

* method completions for broadcasted functioncalls

* better broadcast funcall completions

(cherry picked from commit a0474d7)
  • Loading branch information
pfitzseb authored and KristofferC committed Apr 17, 2019
1 parent 5c8cd40 commit ad1a926
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 8 deletions.
31 changes: 23 additions & 8 deletions stdlib/REPL/src/REPLCompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
18 changes: 18 additions & 0 deletions stdlib/REPL/test/replcompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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})))
Expand Down

0 comments on commit ad1a926

Please sign in to comment.