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

Add option to complete functions with parentheses #1167

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions src/languageserverinstance.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ mutable struct LanguageServerInstance
lint_missingrefs::Symbol
lint_disableddirs::Vector{String}
completion_mode::Symbol
complete_func_parens::Bool
inlay_hints::Bool
inlay_hints_variable_types::Bool
inlay_hints_parameter_names::Symbol
Expand Down Expand Up @@ -87,6 +88,7 @@ mutable struct LanguageServerInstance
:all,
LINT_DIABLED_DIRS,
:qualify, # options: :import or :qualify, anything else turns this off
false,
true,
true,
:literals,
Expand Down
33 changes: 18 additions & 15 deletions src/requests/completions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ function latex_completions(partial::String, state::CompletionState)
for (k, v) in Iterators.flatten((REPL.REPLCompletions.latex_symbols, REPL.REPLCompletions.emoji_symbols))
if is_completion_match(string(k), partial)
# t1 = TextEdit(Range(state.doc, (state.offset - sizeof(partial)):state.offset), v)
add_completion_item(state, CompletionItem(k, CompletionItemKinds.Unit, missing, v, v, missing, missing, missing, missing, missing, missing, texteditfor(state, partial, v), missing, missing, missing, missing))
add_completion_item(state, CompletionItem(k, CompletionItemKinds.Unit, missing, v, v, missing, missing, missing, missing, missing, missing, texteditfor(state, partial, v, CompletionItemKinds.Unit), missing, missing, missing, missing))
end
end
end
Expand All @@ -119,7 +119,7 @@ function kw_completion(partial::String, state::CompletionState)
for (kw, comp) in snippet_completions
if startswith(kw, partial)
kind = occursin("\$0", comp) ? CompletionItemKinds.Snippet : CompletionItemKinds.Keyword
add_completion_item(state, CompletionItem(kw, kind, missing, missing, kw, missing, missing, missing, missing, missing, InsertTextFormats.Snippet, texteditfor(state, partial, comp), missing, missing, missing, missing))
add_completion_item(state, CompletionItem(kw, kind, missing, missing, kw, missing, missing, missing, missing, missing, InsertTextFormats.Snippet, texteditfor(state, partial, comp, kind), missing, missing, missing, missing))
end
end
end
Expand Down Expand Up @@ -161,8 +161,11 @@ const snippet_completions = Dict{String,String}(
)


function texteditfor(state::CompletionState, partial, n)
TextEdit(Range(Position(state.range.start.line, max(state.range.start.character - length(partial), 0)), state.range.stop), n)
function texteditfor(state::CompletionState, partial, newtext, kind)
if state.server.complete_func_parens && (kind == CompletionItemKinds.Method || kind == CompletionItemKinds.Function)
newtext = newtext * "()"
end
TextEdit(Range(Position(state.range.start.line, max(state.range.start.character - length(partial), 0)), state.range.stop), newtext)
end

function string_macro_altname(s)
Expand Down Expand Up @@ -196,11 +199,11 @@ function collect_completions(m::SymbolServer.ModuleStore, spartial, state::Compl
end
if StaticLint.isexportedby(canonical_name, m) || inclexported
foreach(possible_names) do n
add_completion_item(state, CompletionItem(n, _completion_kind(v), get_typed_definition(v), MarkupContent(sanitize_docstring(v.doc)), texteditfor(state, spartial, n)))
add_completion_item(state, CompletionItem(n, _completion_kind(v), get_typed_definition(v), MarkupContent(sanitize_docstring(v.doc)), texteditfor(state, spartial, n, _completion_kind(v))))
end
elseif dotcomps
foreach(possible_names) do n
push!(state.completions, CompletionItem(n, _completion_kind(v), get_typed_definition(v), MarkupContent(sanitize_docstring(v.doc)), texteditfor(state, spartial, string(m.name, ".", n))))
push!(state.completions, CompletionItem(n, _completion_kind(v), get_typed_definition(v), MarkupContent(sanitize_docstring(v.doc)), texteditfor(state, spartial, string(m.name, ".", n), _completion_kind(v))))
end
elseif length(spartial) > 3 && !variable_already_imported(m, canonical_name, state)
if state.server.completion_mode === :import
Expand All @@ -209,14 +212,14 @@ function collect_completions(m::SymbolServer.ModuleStore, spartial, state::Compl
foreach(possible_names) do n
ci = CompletionItem(n, _completion_kind(v), missing, "This is an unexported symbol and will be explicitly imported.",
MarkupContent(sanitize_docstring(v.doc)), missing, missing, missing, missing, missing, InsertTextFormats.PlainText,
texteditfor(state, spartial, n), textedit_to_insert_using_stmt(m, canonical_name, state), missing, missing, "import")
texteditfor(state, spartial, n, _completion_kind(v)), textedit_to_insert_using_stmt(m, canonical_name, state), missing, missing, "import")
add_completion_item(state, ci)
end
elseif state.server.completion_mode === :qualify
foreach(possible_names) do n
add_completion_item(state, CompletionItem(string(m.name, ".", n), _completion_kind(v), missing,
missing, MarkupContent(sanitize_docstring(v.doc)), missing,
missing, string(n), missing, missing, InsertTextFormats.PlainText, texteditfor(state, spartial, string(m.name, ".", n)),
missing, string(n), missing, missing, InsertTextFormats.PlainText, texteditfor(state, spartial, string(m.name, ".", n), _completion_kind(v)),
missing, missing, missing, missing))
end
end
Expand Down Expand Up @@ -272,7 +275,7 @@ function collect_completions(x::StaticLint.Scope, spartial, state::CompletionSta
sanitize_docstring(documentation)
end
foreach(possible_names) do nn
add_completion_item(state, CompletionItem(nn, _completion_kind(n[2]), get_typed_definition(n[2]), MarkupContent(documentation), texteditfor(state, spartial, nn)))
add_completion_item(state, CompletionItem(nn, _completion_kind(n[2]), get_typed_definition(n[2]), MarkupContent(documentation), texteditfor(state, spartial, nn, _completion_kind(n[2]))))
end
end
end
Expand Down Expand Up @@ -301,14 +304,14 @@ function _get_dot_completion(px::EXPR, spartial, state::CompletionState)
for a in refof(px).type.fieldnames
a = String(a)
if is_completion_match(a, spartial)
add_completion_item(state, CompletionItem(a, CompletionItemKinds.Method, get_typed_definition(a), MarkupContent(a), texteditfor(state, spartial, a)))
add_completion_item(state, CompletionItem(a, CompletionItemKinds.Method, get_typed_definition(a), MarkupContent(a), texteditfor(state, spartial, a, CompletionItemKinds.Method)))
end
end
elseif refof(px).type isa StaticLint.Binding && refof(px).type.val isa SymbolServer.DataTypeStore
for a in refof(px).type.val.fieldnames
a = String(a)
if is_completion_match(a, spartial)
add_completion_item(state, CompletionItem(a, CompletionItemKinds.Method, get_typed_definition(a), MarkupContent(a), texteditfor(state, spartial, a)))
add_completion_item(state, CompletionItem(a, CompletionItemKinds.Method, get_typed_definition(a), MarkupContent(a), texteditfor(state, spartial, a, CompletionItemKinds.Method)))
end
end
elseif refof(px).type isa StaticLint.Binding && refof(px).type.val isa EXPR && CSTParser.defines_struct(refof(px).type.val) && scopeof(refof(px).type.val) isa StaticLint.Scope
Expand Down Expand Up @@ -453,7 +456,7 @@ function import_completions(ppt, pt, t, is_at_end, x, state::CompletionState)
for (n, m) in refof(import_root).vals
n = String(n)
if is_completion_match(n, t.val) && !startswith(n, "#")
add_completion_item(state, CompletionItem(n, _completion_kind(m), get_typed_definition(m), MarkupContent(m isa SymbolServer.SymStore ? sanitize_docstring(m.doc) : n), texteditfor(state, t.val, n)))
add_completion_item(state, CompletionItem(n, _completion_kind(m), get_typed_definition(m), MarkupContent(m isa SymbolServer.SymStore ? sanitize_docstring(m.doc) : n), texteditfor(state, t.val, n, _completion_kind(m))))
end
end
else
Expand All @@ -476,7 +479,7 @@ function import_completions(ppt, pt, t, is_at_end, x, state::CompletionState)
for (n, m) in rootmod.vals
n = String(n)
if is_completion_match(n, t.val) && !startswith(n, "#")
add_completion_item(state, CompletionItem(n, _completion_kind(m), get_typed_definition(m), MarkupContent(m isa SymbolServer.SymStore ? sanitize_docstring(m.doc) : n), texteditfor(state, t.val, n)))
add_completion_item(state, CompletionItem(n, _completion_kind(m), get_typed_definition(m), MarkupContent(m isa SymbolServer.SymStore ? sanitize_docstring(m.doc) : n), texteditfor(state, t.val, n, _completion_kind(m))))
end
end
end
Expand All @@ -485,14 +488,14 @@ function import_completions(ppt, pt, t, is_at_end, x, state::CompletionState)
for (n, m) in refof(import_root).vals
n = String(n)
if is_completion_match(n, t.val) && !startswith(n, "#")
add_completion_item(state, CompletionItem(n, _completion_kind(m), get_typed_definition(m), MarkupContent(m isa SymbolServer.SymStore ? sanitize_docstring(m.doc) : n), texteditfor(state, t.val, n)))
add_completion_item(state, CompletionItem(n, _completion_kind(m), get_typed_definition(m), MarkupContent(m isa SymbolServer.SymStore ? sanitize_docstring(m.doc) : n), texteditfor(state, t.val, n, _completion_kind(m))))
end
end
else
for (n, m) in StaticLint.getsymbols(getenv(state))
n = String(n)
if is_completion_match(n, t.val)
add_completion_item(state, CompletionItem(n, CompletionItemKinds.Module, get_typed_definition(m), MarkupContent(m isa SymbolServer.SymStore ? m.doc : n), texteditfor(state, t.val, n)))
add_completion_item(state, CompletionItem(n, CompletionItemKinds.Module, get_typed_definition(m), MarkupContent(m isa SymbolServer.SymStore ? m.doc : n), texteditfor(state, t.val, n, CompletionItemKinds.Module,)))
end
end
end
Expand Down
11 changes: 7 additions & 4 deletions src/requests/workspace.jl
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ function request_julia_config(server::LanguageServerInstance, conn)
ConfigurationItem(missing, "julia.lint.missingrefs"),
ConfigurationItem(missing, "julia.lint.disabledDirs"),
ConfigurationItem(missing, "julia.completionmode"),
ConfigurationItem(missing, "julia.completeFunctionParens")
ConfigurationItem(missing, "julia.inlayHints.static.enabled"),
ConfigurationItem(missing, "julia.inlayHints.static.variableTypes.enabled"),
ConfigurationItem(missing, "julia.inlayHints.static.parameterNames.enabled"),
Expand All @@ -119,10 +120,11 @@ function request_julia_config(server::LanguageServerInstance, conn)
new_lint_missingrefs = Symbol(something(response[12], :all))
new_lint_disableddirs = something(response[13], LINT_DIABLED_DIRS)
new_completion_mode = Symbol(something(response[14], :import))
inlayHints = something(response[15], true)
inlayHintsVariableTypes = something(response[16], true)
inlayHintsParameterNames = Symbol(something(response[17], :literals))

new_complete_func_parens = something(response[15], false)
inlayHints = something(response[16], true)
inlayHintsVariableTypes = something(response[17], true)
inlayHintsParameterNames = Symbol(something(response[18], :literals))

rerun_lint = begin
any(getproperty(server.lint_options, opt) != getproperty(new_SL_opts, opt) for opt in fieldnames(StaticLint.LintOptions)) ||
server.runlinter != new_runlinter ||
Expand All @@ -135,6 +137,7 @@ function request_julia_config(server::LanguageServerInstance, conn)
server.lint_missingrefs = new_lint_missingrefs
server.lint_disableddirs = new_lint_disableddirs
server.completion_mode = new_completion_mode
server.complete_func_parens = new_complete_func_parens
server.inlay_hints = inlayHints
server.inlay_hints_variable_types = inlayHintsVariableTypes
server.inlay_hints_parameter_names = inlayHintsParameterNames
Expand Down
16 changes: 16 additions & 0 deletions test/requests/test_completions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,19 @@ end
@test any(i -> i.label == "yyy" && occursin("yyy::Bar", i.detail), items1)
@test any(i -> i.label == "xxx" && occursin("xxx::Bar = f.yyy", i.detail), items2)
end

@testitem "complete function parens" begin
include("../test_shared_server.jl")

server.complete_func_parens = true
settestdoc("""
foo_func() = 1
foo_var = 2
fo
""")
items = completion_test(2, 2).items
@test any(i -> i.label == "foo_func" && i.textEdit.newText == "foo_func()", items)
@test any(i -> i.label == "foo_var" && i.textEdit.newText == "foo_var", items)
@test any(i -> i.label == "foldl" && i.textEdit.newText == "foldl()", items)
server.complete_func_parens = false
end
Loading