Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
6 changes: 6 additions & 0 deletions src/JETLS.jl
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ end

include("utils.jl")
include("completions.jl")
include("signature-help.jl")

struct IncludeCallback <: Function
file_cache::Dict{URI,FileInfo}
Expand Down Expand Up @@ -186,6 +187,8 @@ function _handle_message(state::ServerState, msg)
return handle_CompletionRequest(state, msg)
elseif msg isa CompletionResolveRequest
return handle_CompletionResolveRequest(state, msg)
elseif msg isa SignatureHelpRequest
return handle_SignatureHelpRequest(state, msg)
elseif JETLS_DEV_MODE
@warn "Unhandled message" msg
end
Expand Down Expand Up @@ -245,6 +248,9 @@ function initialize_result()
triggerCharacters = ["@"],
completionItem = (;
labelDetailsSupport = true)),
signatureHelpProvider = SignatureHelpOptions(;
triggerCharacters = ["(", ",", ";"],
retriggerCharacters = ["."]),
),
serverInfo = (;
name = "JETLS",
Expand Down
1 change: 1 addition & 0 deletions src/LSP/LSP.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ include("lifecycle-messages/exit.jl")
include("document-synchronization.jl")
include("language-features/diagnostics.jl")
include("language-features/completions.jl")
include("language-features/signature-help.jl")
include("workspace-features/workspace-folders.jl")
include("workspace-features/files.jl")
include("capabilities.jl")
Expand Down
2 changes: 2 additions & 0 deletions src/LSP/capabilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

completionProvider::Union{CompletionOptions, Nothing} = nothing

signatureHelpProvider::Union{SignatureHelpOptions, Nothing} = nothing

"Workspace specific server capabilities"
workspace::Union{Nothing, @interface begin
"""
Expand Down
251 changes: 251 additions & 0 deletions src/LSP/language-features/signature-help.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
@interface SignatureHelpClientCapabilities begin
"""
Whether signature help supports dynamic registration.
"""
dynamicRegistration::Union{Nothing, Bool} = nothing

"""
The client supports the following `SignatureInformation`
specific properties.
"""
signatureInformation::Union{Nothing, @interface begin
"""
Client supports the follow content formats for the documentation
property. The order describes the preferred format of the client.
"""
documentationFormat::Union{Nothing, Vector{MarkupKind.Ty}} = nothing

"""
Client capabilities specific to parameter information.
"""
parameterInformation::Union{Nothing, @interface begin
"""
The client supports processing label offsets instead of a
simple label string.

# Tags
- since - 3.14.0
"""
labelOffsetSupport::Union{Nothing, Bool} = nothing
end} = nothing

"""
The client supports the `activeParameter` property on
`SignatureInformation` literal.

# Tags
- since - 3.16.0
"""
activeParameterSupport::Union{Nothing, Bool} = nothing
end} = nothing

"""
The client supports to send additional context information for a
`textDocument/signatureHelp` request. A client that opts into
contextSupport will also support the `retriggerCharacters` on
`SignatureHelpOptions`.

# Tags
- since - 3.15.0
"""
contextSupport::Union{Nothing, Bool} = nothing
end

@interface SignatureHelpOptions @extends WorkDoneProgressOptions begin
"""
The characters that trigger signature help
automatically.
"""
triggerCharacters::Union{Nothing, Vector{String}} = nothing

"""
List of characters that re-trigger signature help.

These trigger characters are only active when signature help is already
showing. All trigger characters are also counted as re-trigger
characters.

# Tags
- since - 3.15.0
"""
retriggerCharacters::Union{Nothing, Vector{String}} = nothing
end

@interface SignatureHelpRegistrationOptions @extends TextDocumentRegistrationOptions, SignatureHelpOptions begin
end

"""
How a signature help was triggered.

# Tags
- since - 3.15.0
"""
@namespace SignatureHelpTriggerKind::Int begin
"""
Signature help was invoked manually by the user or by a command.
"""
Invoked = 1
"""
Signature help was triggered by a trigger character.
"""
TriggerCharacter = 2
"""
Signature help was triggered by the cursor moving or by the document
content changing.
"""
ContentChange = 3
end

"""
Represents a parameter of a callable-signature. A parameter can
have a label and a doc-comment.
"""
@interface ParameterInformation begin

"""
The label of this parameter information.

Either a string or an inclusive start and exclusive end offsets within
its containing signature label. (see SignatureInformation.label). The
offsets are based on a UTF-16 string representation as `Position` and
`Range` does.

*Note*: a label of type string should be a substring of its containing
signature label. Its intended use case is to highlight the parameter
label part in the `SignatureInformation.label`.
"""
label::Union{String, Vector{UInt}} # vector should have length 2

"""
The human-readable doc-comment of this parameter. Will be shown
in the UI but can be omitted.
"""
documentation::Union{Nothing, String, MarkupContent} = nothing
end

"""
Represents the signature of something callable. A signature
can have a label, like a function-name, a doc-comment, and
a set of parameters.
"""
@interface SignatureInformation begin
"""
The label of this signature. Will be shown in
the UI.
"""
label::String

"""
The human-readable doc-comment of this signature. Will be shown
in the UI but can be omitted.
"""
documentation::Union{Nothing, String, MarkupContent} = nothing

"""
The parameters of this signature.
"""
parameters::Union{Nothing, Vector{ParameterInformation}} = nothing

"""
The index of the active parameter.

If provided, this is used in place of `SignatureHelp.activeParameter`.

# Tags
- since - 3.16.0
"""
activeParameter::Union{Nothing, UInt} = nothing
end

"""
Signature help represents the signature of something
callable. There can be multiple signature but only one
active and only one active parameter.
"""
@interface SignatureHelp begin
"""

Check warning on line 166 in src/LSP/language-features/signature-help.jl

View check run for this annotation

Codecov / codecov/patch

src/LSP/language-features/signature-help.jl#L166

Added line #L166 was not covered by tests
One or more signatures. If no signatures are available the signature help
request should return `null`.
"""
signatures::Vector{SignatureInformation}

"""
The active signature. If omitted or the value lies outside the
range of `signatures` the value defaults to zero or is ignore if
the `SignatureHelp` as no signatures.

Whenever possible implementors should make an active decision about
the active signature and shouldn't rely on a default value.

In future version of the protocol this property might become
mandatory to better express this.
"""
activeSignature::Union{Nothing, UInt} = nothing

"""
The active parameter of the active signature. If omitted or the value
lies outside the range of `signatures[activeSignature].parameters`
defaults to 0 if the active signature has parameters. If
the active signature has no parameters it is ignored.
In future version of the protocol this property might become
mandatory to better express the active parameter if the
active signature does have any.
"""
activeParameter::Union{Nothing, UInt} = nothing
end

"""
Additional information about the context in which a signature help request
was triggered.

# Tags
- since - 3.15.0
"""
@interface SignatureHelpContext begin
"""
Action that caused signature help to be triggered.
"""
triggerKind::SignatureHelpTriggerKind.Ty

"""
Character that caused signature help to be triggered.

This is undefined when triggerKind !==
SignatureHelpTriggerKind.TriggerCharacter
"""
triggerCharacter::Union{Nothing, String} = nothing

"""
`true` if signature help was already showing when it was triggered.

Retriggers occur when the signature help is already active and can be
caused by actions such as typing a trigger character, a cursor move, or
document content changes.
"""
isRetrigger::Bool

"""
The currently active `SignatureHelp`.

The `activeSignatureHelp` has its `SignatureHelp.activeSignature` field
updated based on the user navigating through available signatures.
"""
activeSignatureHelp::Union{Nothing, SignatureHelp} = nothing
end

@interface SignatureHelpParams @extends TextDocumentPositionParams, WorkDoneProgressParams begin
"""
The signature help context. This is only available if the client
specifies to send this using the client capability
`textDocument.signatureHelp.contextSupport === true`

# Tags
- since - 3.15.0
"""
context::Union{Nothing, SignatureHelpContext} = nothing
end

@interface SignatureHelpRequest @extends RequestMessage begin
method::String = "textDocument/signatureHelp"
params::SignatureHelpParams
end
74 changes: 0 additions & 74 deletions src/completions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,53 +32,6 @@ end
# local completions
# =================

"""
Like `Base.unique`, but over node ids, and with this comment promising that the
lowest-index copy of each node is kept.
"""
function deduplicate_syntaxlist(sl::JL.SyntaxList)
sl2 = JL.SyntaxList(sl.graph)
seen = Set{JL.NodeId}()
for st in sl
if !(st._id in seen)
push!(sl2, st._id)
push!(seen, st._id)
end
end
return sl2
end

"""
byte_ancestors(st::JL.SyntaxTree, rng::UnitRange{Int})
byte_ancestors(st::JL.SyntaxTree, byte::Int)

Get a list of `SyntaxTree`s containing certain bytes.
Output should be topologically sorted, children first.

If we know that parent ranges contain all child ranges, and that siblings don't
have overlapping ranges (this is not true after lowering, but appear to be true
after parsing), each tree in the result will be a child of the next.
"""
function byte_ancestors(st::JL.SyntaxTree, rng::UnitRange{Int})
sl = JL.SyntaxList(st._graph, [st._id])
stack = [st]
while !isempty(stack)
st = pop!(stack)
if JS.numchildren(st) === 0
continue
end
for ci in JS.children(st)
if rng ⊆ JS.byte_range(ci)
push!(sl, ci)
end
push!(stack, ci)
end
end
# delete later duplicates when sorted parent->child
return reverse!(deduplicate_syntaxlist(sl))
end
byte_ancestors(st::JL.SyntaxTree, byte::Int) = byte_ancestors(st, byte:byte)

"""
Find any largest lowerable tree containing the cursor and the cursor's position
within it. For local completions; something like least_unlowerable would be
Expand Down Expand Up @@ -301,33 +254,6 @@ end
# global completions
# ==================

function find_file_module!(state::ServerState, uri::URI, pos::Position)
mod = find_file_module(state, uri, pos)
state.completion_module[] = mod
return mod
end
function find_file_module(state::ServerState, uri::URI, pos::Position)
haskey(state.contexts, uri) || return Main
contexts = state.contexts[uri]
context = first(contexts)
for ctx in contexts
# prioritize `PackageSourceAnalysisEntry` if exists
if isa(context.entry, PackageSourceAnalysisEntry)
context = ctx
break
end
end
safi = successfully_analyzed_file_info(context, uri)
isnothing(safi) && return Main
curline = Int(pos.line) + 1
curmod = Main
for (range, mod) in safi.module_range_infos
curline in range || continue
curmod = mod
end
return curmod
end

function global_completions!(items::Dict{String, CompletionItem}, state::ServerState, uri::URI, params::CompletionParams)
pos = params.position
is_macro_invoke = let context = params.context
Expand Down
Loading
Loading