Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autocomplete of methods for given variables #980

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions src/requests/completions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,14 @@ function textDocument_completion_request(params::CompletionParams, server::Langu
collect_completions(state.x, "in", state, false)
elseif t isa CSTParser.Tokens.Token && t.kind == CSTParser.Tokens.ISA && is_at_end && state.x !== nothing
collect_completions(state.x, "isa", state, false)
elseif t isa CSTParser.Tokens.Token && t.kind == CSTParser.Tokens.COMMA &&
pt isa CSTParser.Tokens.Token && pt.kind == CSTParser.Tokens.IDENTIFIER &&
ppt isa CSTParser.Tokens.Token && ppt.kind == CSTParser.Tokens.LPAREN &&
!(parentof(state.x) isa EXPR && CSTParser.iscall(parentof(state.x)))
# method completion for given argument
ptlen = (1 + pt.endbyte - pt.startbyte)
px = get_expr(getcst(state.doc), state.offset - ptlen)
method_completion(px, state, ptlen)
end

return CompletionList(true, unique(values(state.completions)))
Expand Down Expand Up @@ -542,3 +550,62 @@ function get_tls_arglist(tls::StaticLint.Scope)
error()
end
end

function method_completion(x, state, xlen)
scope = scopeof(parentof(parentof(state.x)))

x_type = refof(x).type.name

if x_type isa EXPR
typename = x_type.val
elseif x_type isa SymbolServer.FakeTypeName
typename = x_type.name.name
else
return
end

for m in scope.modules
for val in m[2].vals
n, v = String(val[1]), val[2]
(startswith(n, ".") || startswith(n, "#") || startswith(n, "_")) && continue
!(typeof(v) == SymbolServer.FunctionStore) && continue
siglen_max = 0 # maximum signature length
for m in v.methods
isempty(m.sig) && continue
!(typeof(m.sig[1][2]) == SymbolServer.FakeTypeName) && continue
!(m.sig[1][2].name.name == typename) && continue
siglen_max = max(siglen_max, length(m.sig))
end
(siglen_max == 0) && continue

prefix_edit = TextEdit(Range(
Position(state.range.start.line,
state.range.start.character - xlen - 2),
Position(state.range.stop.line,
state.range.stop.character - xlen - 2)), n)

if siglen_max == 1 # need to close bracket right away
additional_edits = [TextEdit(Range(
Position(state.range.start.line,
state.range.start.character - 1),
Position(state.range.stop.line,
state.range.stop.character)), ""), prefix_edit]
inplace_text = ""
else
inplace_text = " "
additional_edits = [prefix_edit]
end

inplace_edit = TextEdit(Range(
Position(state.range.start.line, state.range.start.character),
Position(state.range.stop.line, state.range.stop.character)),
inplace_text)

item = CompletionItem(n, 2, missing, missing, n,
missing, missing, missing, missing, missing,
InsertTextFormats.PlainText, inplace_edit, additional_edits,
missing, missing, missing)
add_completion_item(state, item)
end
end
end
26 changes: 16 additions & 10 deletions test/requests/completions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ completion_test(line, char) = LanguageServer.textDocument_completion_request(Lan
""")
@test completion_test(0, 9).items[1].textEdit.newText == "∴"
@test completion_test(0, 9).items[1].textEdit.range == LanguageServer.Range(0, 0, 0, 9)

@test completion_test(1, 10).items[1].textEdit.newText == "∴"
@test completion_test(1, 10).items[1].textEdit.range == LanguageServer.Range(1, 1, 1, 10)

@test completion_test(2, 10).items[1].textEdit.newText == "∴"
@test completion_test(2, 10).items[1].textEdit.range == LanguageServer.Range(2, 1, 2, 10)

@test completion_test(3, 10).items[1].textEdit.newText == "∴"
@test completion_test(3, 10).items[1].textEdit.range == LanguageServer.Range(3, 1, 3, 10)

@test completion_test(4, 12).items[1].textEdit.newText == "∴"
@test completion_test(4, 12).items[1].textEdit.range == LanguageServer.Range(4, 3, 4, 12)

Expand All @@ -41,7 +41,7 @@ end

settestdoc("import ")
@test all(item.label in ("Main", "Base", "Core") for item in completion_test(0, 7).items)

settestdoc("""module M end
import .""")
@test_broken completion_test(1, 8).items[1].label == "M"
Expand Down Expand Up @@ -70,7 +70,7 @@ end
@test any(item.label == "quot" for item in completion_test(1, 10).items)

settestdoc("""
module M
module M
inner = 1
end
M.
Expand Down Expand Up @@ -105,19 +105,19 @@ end

settestdoc("@t")
@test any(item.label == "@time" for item in completion_test(0, 2).items)

settestdoc("i")
@test any(item.label == "if" for item in completion_test(0, 1).items)

settestdoc("i")
@test any(item.label == "in" for item in completion_test(0, 1).items)

settestdoc("for")
@test any(item.label == "for" for item in completion_test(0, 3).items)

settestdoc("in")
@test any(item.label == "in" for item in completion_test(0, 2).items)

settestdoc("isa")
@test any(item.label == "isa" for item in completion_test(0, 3).items)
end
Expand All @@ -127,3 +127,9 @@ end
myv""")
@test any(item.label == "myvar" for item in completion_test(1, 3).items)
end

@testset "method completions" begin
settestdoc("""phi = 1
(phi,""")
@test any(item.label == "Float64" for item in completion_test(0, 13).items)
end