Skip to content

Commit 3c1f1eb

Browse files
committed
Merge branch 'master' into local-completions
2 parents 90bfee4 + 5575343 commit 3c1f1eb

File tree

4 files changed

+139
-40
lines changed

4 files changed

+139
-40
lines changed

src/LSP/basic-json-structures.jl

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -318,23 +318,6 @@ Structure to capture a description for an error code.
318318
href::URI
319319
end
320320

321-
"""
322-
Represents a reference to a command. Provides a title which will be used to
323-
represent a command in the UI. Commands are identified by a string
324-
identifier. The recommended way to handle commands is to implement their
325-
execution on the server side if the client and server provides the corresponding
326-
capabilities. Alternatively the tool extension code could handle the
327-
command. The protocol currently doesn’t specify a set of well-known commands.
328-
"""
329-
@interface Command begin
330-
"Title of the command, like `save`."
331-
title::String
332-
"The identifier of the actual command handler."
333-
command::String
334-
"Arguments that the command handler should be invoked with"
335-
arguments::Union{Vector{Any}, Nothing} = nothing
336-
end
337-
338321
"""
339322
Represents a diagnostic, such as a compiler error or warning.
340323
Diagnostic objects are only valid in the scope of a resource.
@@ -395,6 +378,71 @@ Diagnostic objects are only valid in the scope of a resource.
395378
data::Union{Any, Nothing} = nothing
396379
end
397380

381+
"""
382+
Describes the content type that a client supports in various
383+
result literals like `Hover`, `ParameterInfo` or `CompletionItem`.
384+
Please note that `MarkupKinds` must not start with a `\$`. This kinds
385+
are reserved for internal usage.
386+
"""
387+
@namespace MarkupKind::String begin
388+
"Plain text is supported as a content format"
389+
PlainText = "plaintext"
390+
"Markdown is supported as a content format"
391+
Markdown = "markdown"
392+
end
393+
394+
"""
395+
A `MarkupContent` literal represents a string value which content is
396+
interpreted base on its kind flag. Currently the protocol supports
397+
`plaintext` and `markdown` as markup kinds.
398+
399+
If the kind is `markdown` then the value can contain fenced code blocks like
400+
in GitHub issues.
401+
402+
Here is an example how such a string can be constructed using
403+
JavaScript / TypeScript:
404+
```typescript
405+
let markdown: MarkdownContent = {
406+
kind: MarkupKind.Markdown,
407+
value: [
408+
'# Header',
409+
'Some text',
410+
'```typescript',
411+
'someCode();',
412+
'```',
413+
].join('\n')
414+
};
415+
```
416+
417+
*Please Note* that clients might sanitize the return markdown. A client could
418+
decide to remove HTML from the markdown to avoid script execution.
419+
*/
420+
"""
421+
@interface MarkupContent begin
422+
"The type of the Markup"
423+
kind::MarkupKind.Ty
424+
425+
"The content itself"
426+
value::String
427+
end
428+
429+
"""
430+
Represents a reference to a command. Provides a title which will be used to
431+
represent a command in the UI. Commands are identified by a string
432+
identifier. The recommended way to handle commands is to implement their
433+
execution on the server side if the client and server provides the corresponding
434+
capabilities. Alternatively the tool extension code could handle the
435+
command. The protocol currently doesn’t specify a set of well-known commands.
436+
"""
437+
@interface Command begin
438+
"Title of the command, like `save`."
439+
title::String
440+
"The identifier of the actual command handler."
441+
command::String
442+
"Arguments that the command handler should be invoked with"
443+
arguments::Union{Vector{Any}, Nothing} = nothing
444+
end
445+
398446
# Work done progress
399447
# ==================
400448

src/LSP/language-features/completions.jl

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,7 @@ end
276276
detail::Union{String, Nothing} = nothing
277277

278278
"A human-readable string that represents a doc-comment."
279-
# documentation::Union{Union{MarkupContent, String}, Nothing} = nothing
280-
documentation::Union{String, Nothing} = nothing
279+
documentation::Union{MarkupContent, String, Nothing} = nothing
281280

282281
"""
283282
Indicates if this item is deprecated.
@@ -528,11 +527,11 @@ end
528527
"""
529528
commitCharactersSupport::Union{Nothing, Bool} = nothing
530529

531-
# """
532-
# Client supports the follow content formats for the documentation
533-
# property. The order describes the preferred format of the client.
534-
# """
535-
# documentationFormat::Union{Nothing, Vector{MarkupKind}} = nothing
530+
"""
531+
Client supports the follow content formats for the documentation
532+
property. The order describes the preferred format of the client.
533+
"""
534+
documentationFormat::Union{Nothing, Vector{MarkupKind.Ty}} = nothing
536535

537536
"""
538537
Client supports the deprecated property on a completion item.

src/completions.jl

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import JuliaLowering: SyntaxTree, JuliaLowering as JL
22
import JuliaSyntax: @K_str, @KSet_str, JuliaSyntax as JS
33

4-
# get_fileinfo(s::ServerState, t::TextDocumentPositionParams) = get_fileinfo(s, t.textDocument)
5-
get_fileinfo(s::ServerState, t::CompletionParams) = get_fileinfo(s, t.textDocument)
4+
# local completions
5+
# =================
66

77
"""
88
Like `Base.unique`, but over node ids, and with this comment promising that the
@@ -238,24 +238,78 @@ function test_handle_CompletionRequest(s::String, b::Int)
238238
map(o->to_completion(o[1], o[2], o[3]), out)
239239
end
240240

241+
function local_completions!(items::Vector{CompletionItem}, s::ServerState, uri::URI, pos::Position)
242+
fi = get_fileinfo(s, uri)
243+
fi === nothing && return items
244+
st0 = JuliaSyntax.build_tree(SyntaxTree, fi.parsed_stream)
245+
for o in cursor_bindings(st0, xy_to_offset(fi, pos))
246+
push!(items, to_completion(o[1], o[2]))
247+
end
248+
return items
249+
end
250+
251+
# global completions
252+
# ==================
253+
254+
function find_file_module(state::ServerState, uri::URI, pos::Position)
255+
haskey(state.contexts, uri) || return Main
256+
contexts = state.contexts[uri]
257+
context = first(contexts)
258+
for ctx in contexts
259+
# prioritize `PackageSourceAnalysisEntry` if exists
260+
if isa(context.entry, PackageSourceAnalysisEntry)
261+
context = ctx
262+
break
263+
end
264+
end
265+
haskey(context.analyzed_file_infos, uri) || return Main
266+
analyzed_file_info = context.analyzed_file_infos[uri]
267+
curline = Int(pos.line) + 1
268+
_, idx = findmin(analyzed_file_info.module_range_infos) do (range, mod)
269+
curline in range || return typemax(Int)
270+
return last(range) - first(range)
271+
end
272+
return last(analyzed_file_info.module_range_infos[idx])
273+
end
274+
275+
function global_completions!(items::Vector{CompletionItem}, state::ServerState, uri::URI, pos::Position)
276+
mod = find_file_module(state, uri, pos)
277+
for name in names(mod; all=true, imported=true, usings=true)
278+
s = String(name)
279+
startswith(s, "#") && continue
280+
push!(items, CompletionItem(
281+
; label = s,
282+
labelDetails = CompletionItemLabelDetails(
283+
; description = "global"),
284+
kind = CompletionItemKind.Variable,
285+
documentation = nothing))
286+
end
287+
return items
288+
end
289+
290+
291+
# request handler
292+
# ===============
241293

242294
function handle_CompletionRequest(s::ServerState, msg::CompletionRequest)
243-
fi = get_fileinfo(s, msg.params)
244-
b = xy_to_offset(fi, msg.params.position)
295+
uri = URI(msg.params.textDocument.uri)
245296

246-
st0 = JuliaSyntax.build_tree(SyntaxTree, fi.parsed_stream)
247-
out = map(o->to_completion(o[1], o[2]), cursor_bindings(st0, b))
297+
# show local completions first, and then global completions
298+
items = CompletionItem[]
299+
# local_completions!(items, s, uri, msg.params.position)
300+
# global_completions!(items, s, uri, msg.params.position)
248301

249302
return s.send(
250303
ResponseMessage(
251304
; id = msg.id,
252305
result =
253306
CompletionList(
254307
; isIncomplete = true,
255-
items = out,
256-
itemDefaults = (
257-
; data = (
258-
; position = msg.params.position,
259-
translated_pos = b,
260-
untranslated_pos = offset_to_xy(fi, b))))))
308+
items,
309+
# itemDefaults = (
310+
# ; data = (
311+
# ; position = msg.params.position,
312+
# translated_pos = b,
313+
# untranslated_pos = offset_to_xy(fi, b)))
314+
)))
261315
end

src/utils.jl

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,8 @@ end
4242
"""
4343
Fetch cached FileInfo given an LSclient-provided structure with a URI
4444
"""
45-
function get_fileinfo(s::ServerState, t::TextDocumentIdentifier)
46-
uri = URI(t.uri)
47-
return haskey(s.file_cache, uri) ? s.file_cache[uri] : nothing
48-
end
45+
get_fileinfo(s::ServerState, uri::URI) = haskey(s.file_cache, uri) ? s.file_cache[uri] : nothing
46+
get_fileinfo(s::ServerState, t::TextDocumentIdentifier) = get_fileinfo(s, URI(t.uri))
4947

5048
# JuliaLowering uses byte offsets; LSP uses lineno and UTF-* character offset.
5149
# These functions do the conversion.

0 commit comments

Comments
 (0)