Skip to content

Commit 5d516cf

Browse files
committed
Merge branch 'master' into sp/document-highlight
2 parents d9c6239 + 8f77b37 commit 5d516cf

16 files changed

+153
-67
lines changed

.github/workflows/jlpkgbutler-ci-master-workflow.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
runs-on: ${{ matrix.os }}
1111
strategy:
1212
matrix:
13-
julia-version: ['1.0', '1.1', '1.2', '1.3', '1.4', '1.5']
13+
julia-version: ['1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6']
1414
julia-arch: [x64, x86]
1515
os: [ubuntu-latest, windows-latest, macOS-latest]
1616
exclude:

.github/workflows/jlpkgbutler-ci-pr-workflow.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ${{ matrix.os }}
1010
strategy:
1111
matrix:
12-
julia-version: ['1.0', '1.1', '1.2', '1.3', '1.4', '1.5']
12+
julia-version: ['1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6']
1313
julia-arch: [x64, x86]
1414
os: [ubuntu-latest, windows-latest, macOS-latest]
1515
exclude:

.github/workflows/jlpkgbutler-codeformat-pr-workflow.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
- uses: actions/checkout@v2
1313
- uses: julia-actions/julia-codeformat@releases/v1
1414
- name: Create Pull Request
15-
uses: peter-evans/create-pull-request@v2
15+
uses: peter-evans/create-pull-request@v3
1616
with:
1717
token: ${{ secrets.GITHUB_TOKEN }}
1818
commit-message: Format files using DocumentFormat

src/document.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ function obscure_text(s)
155155
end
156156
i += di
157157
end
158-
s1 = String(take!(io))
158+
String(take!(io))
159159
end
160160

161161
"""
@@ -229,7 +229,7 @@ byte offset.
229229
function get_position_at(doc::Document, offset::Integer)
230230
offset > sizeof(get_text(doc)) && throw(LSPositionToOffsetException("offset[$offset] > sizeof(content)[$(sizeof(get_text(doc)))]")) # OK, offset comes from EXPR spans
231231
line_offsets = get_line_offsets(doc)
232-
line, ind = get_line_of(line_offsets, offset)
232+
line, _ = get_line_of(line_offsets, offset)
233233
io = IOBuffer(get_text(doc))
234234
seek(io, line_offsets[line])
235235
character = 0

src/languageserverinstance.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ function create_symserver_progress_ui(server)
142142
if server.clientcapability_window_workdoneprogress
143143
token = string(uuid4())
144144
server.current_symserver_progress_token = token
145-
response = JSONRPC.send(server.jr_endpoint, window_workDoneProgress_create_request_type, WorkDoneProgressCreateParams(token))
145+
JSONRPC.send(server.jr_endpoint, window_workDoneProgress_create_request_type, WorkDoneProgressCreateParams(token))
146146

147147
JSONRPC.send(
148148
server.jr_endpoint,
@@ -293,6 +293,7 @@ function Base.run(server::LanguageServerInstance)
293293
end
294294

295295
msg_dispatcher = JSONRPC.MsgDispatcher()
296+
296297
msg_dispatcher[textDocument_codeAction_request_type] = request_wrapper(textDocument_codeAction_request, server)
297298
msg_dispatcher[workspace_executeCommand_request_type] = request_wrapper(workspace_executeCommand_request, server)
298299
msg_dispatcher[textDocument_completion_request_type] = request_wrapper(textDocument_completion_request, server)
@@ -327,6 +328,7 @@ function Base.run(server::LanguageServerInstance)
327328
msg_dispatcher[workspace_symbol_request_type] = request_wrapper(workspace_symbol_request, server)
328329
msg_dispatcher[julia_refreshLanguageServer_notification_type] = request_wrapper(julia_refreshLanguageServer_notification, server)
329330
msg_dispatcher[julia_getDocFromWord_request_type] = request_wrapper(julia_getDocFromWord_request, server)
331+
msg_dispatcher[textDocument_selectionRange_request_type] = request_wrapper(textDocument_selectionRange_request, server)
330332

331333
while true
332334
message = take!(server.combined_msg_queue)

src/protocol/messagedefs.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const textDocument_didSave_notification_type = JSONRPC.NotificationType("textDoc
1515
const textDocument_willSave_notification_type = JSONRPC.NotificationType("textDocument/willSave", WillSaveTextDocumentParams)
1616
const textDocument_willSaveWaitUntil_request_type = JSONRPC.RequestType("textDocument/willSaveWaitUntil", WillSaveTextDocumentParams, Vector{TextEdit})
1717
const textDocument_publishDiagnostics_notification_type = JSONRPC.NotificationType("textDocument/publishDiagnostics", PublishDiagnosticsParams)
18+
const textDocument_selectionRange_request_type = JSONRPC.RequestType("textDocument/selectionRange", SelectionRangeParams, Vector{SelectionRange})
1819

1920
const workspace_executeCommand_request_type = JSONRPC.RequestType("workspace/executeCommand", ExecuteCommandParams, Nothing)
2021
const workspace_symbol_request_type = JSONRPC.RequestType("workspace/symbol", WorkspaceSymbolParams, Vector{SymbolInformation})

src/requests/actions.jl

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ function reexport_package(x::EXPR, server, conn)
160160
return
161161
end
162162
using_stmt = parentof(x)
163-
file, offset = get_file_loc(x)
163+
file, _ = get_file_loc(x)
164164
insertpos = get_next_line_offset(using_stmt)
165165
insertpos == -1 && return
166166

@@ -196,7 +196,7 @@ function reexport_module(x::EXPR, server, conn)
196196
exported_names = find_exported_names(mod_expr)
197197

198198
isempty(exported_names) && return
199-
file, offset = get_file_loc(x)
199+
file, _ = get_file_loc(x)
200200
insertpos = get_next_line_offset(using_stmt)
201201
insertpos == -1 && return
202202
names = filter!(s -> !isempty(s), collect(CSTParser.str_value.(exported_names)))
@@ -210,8 +210,6 @@ end
210210
function wrap_block(x, server, type, conn) end
211211
function wrap_block(x::EXPR, server, type, conn)
212212
file, offset = get_file_loc(x) # rese
213-
l0, _ = get_position_at(file, offset)
214-
l1, _ = get_position_at(file, offset + x.span)
215213
if type == :if
216214
tde = TextDocumentEdit(VersionedTextDocumentIdentifier(file._uri, file._version), TextEdit[
217215
TextEdit(Range(file, offset .+ (0:0)), "if CONDITION\n"),
@@ -228,7 +226,7 @@ function is_fixable_missing_ref(x::EXPR, cac::CodeActionContext)
228226
xname = StaticLint.valofid(x)
229227
tls = StaticLint.retrieve_toplevel_scope(x)
230228
if tls isa StaticLint.Scope && tls.modules !== nothing
231-
for (n, m) in tls.modules
229+
for m in values(tls.modules)
232230
if (m isa SymbolServer.ModuleStore && haskey(m, Symbol(xname))) || (m isa StaticLint.Scope && StaticLint.scopehasbinding(m, xname))
233231
return true
234232
end
@@ -241,7 +239,6 @@ end
241239
function applymissingreffix(x, server, conn)
242240
xname = StaticLint.valofid(x)
243241
file, offset = get_file_loc(x)
244-
l, c = get_position_at(file, offset)
245242
tls = StaticLint.retrieve_toplevel_scope(x)
246243
if tls.modules !== nothing
247244
for (n, m) in tls.modules

src/requests/completions.jl

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,22 @@
33
# - fuzzy completions
44
# - (maybe) export latex completions into a separate package
55

6+
using REPL
7+
8+
"""
9+
is_completion_match(s::AbstractString, prefix::AbstractString, cutoff=3)
10+
11+
Returns true if `s` starts with `prefix` or has a sufficiently high fuzzy score.
12+
"""
13+
function is_completion_match(s::AbstractString, prefix::AbstractString, cutoff=3)
14+
starter = if all(islowercase, prefix)
15+
startswith(lowercase(s), prefix)
16+
else
17+
startswith(s, prefix)
18+
end
19+
starter || REPL.fuzzyscore(prefix, s) >= cutoff
20+
end
21+
622
function textDocument_completion_request(params::CompletionParams, server::LanguageServerInstance, conn)
723
CIs = CompletionItem[]
824
doc = getdocument(server, URI2(params.textDocument.uri))
@@ -61,14 +77,14 @@ function textDocument_completion_request(params::CompletionParams, server::Langu
6177
end
6278

6379
function get_partial_completion(doc, offset)
64-
ppt, pt, t = toks = get_toks(doc, offset)
80+
ppt, pt, t = get_toks(doc, offset)
6581
is_at_end = offset == t.endbyte + 1
6682
return ppt, pt, t, is_at_end
6783
end
6884

6985
function latex_completions(doc, offset, partial, CIs)
7086
for (k, v) in REPL.REPLCompletions.latex_symbols
71-
if startswith(string(k), partial)
87+
if is_completion_match(string(k), partial)
7288
t1 = TextEdit(Range(doc, (offset - sizeof(partial)):offset), v)
7389
push!(CIs, CompletionItem(k, 11, missing, v, v, missing, missing, missing, missing, missing, missing, t1, missing, missing, missing, missing))
7490
end
@@ -77,10 +93,10 @@ end
7793

7894
function kw_completion(doc, spartial, CIs, offset)
7995
length(spartial) == 0 && return
80-
fc = first(spartial)
8196
for (kw, comp) in snippet_completions
8297
if startswith(kw, spartial)
83-
push!(CIs, CompletionItem(kw, 14, missing, missing, kw, missing, missing, missing, missing, missing, InsertTextFormats.Snippet, TextEdit(Range(doc, offset:offset), comp[length(spartial) + 1:end]), missing, missing, missing, missing))
98+
t1 = TextEdit(Range(doc, (offset - sizeof(spartial)):offset), comp)
99+
push!(CIs, CompletionItem(kw, 14, missing, missing, kw, missing, missing, missing, missing, missing, InsertTextFormats.Snippet, t1, missing, missing, missing, missing))
84100
end
85101
end
86102
end
@@ -123,13 +139,14 @@ function collect_completions(m::SymbolServer.ModuleStore, spartial, rng, CIs, se
123139
for val in m.vals
124140
n, v = String(val[1]), val[2]
125141
(startswith(n, ".") || startswith(n, "#")) && continue
126-
!startswith(n, spartial) && continue
142+
!is_completion_match(n, spartial) && continue
127143
if v isa SymbolServer.VarRef
128144
v = SymbolServer._lookup(v, getsymbolserver(server), true)
129145
v === nothing && return
130146
end
131147
if StaticLint.isexportedby(n, m) || inclexported
132-
push!(CIs, CompletionItem(n, _completion_kind(v, server), MarkupContent(sanitize_docstring(v.doc)), TextEdit(rng, n[nextind(n, sizeof(spartial)):end])))
148+
rng1 = Range(Position(rng.start.line, rng.start.character - sizeof(spartial)), rng.stop)
149+
push!(CIs, CompletionItem(n, _completion_kind(v, server), MarkupContent(sanitize_docstring(v.doc)), TextEdit(rng1, n)))
133150
elseif dotcomps
134151
rng1 = Range(Position(rng.start.line, rng.start.character - sizeof(spartial)), rng.stop)
135152
push!(CIs, CompletionItem(n, _completion_kind(v, server), MarkupContent(sanitize_docstring(v.doc)), TextEdit(rng1, string(m.name, ".", n))))
@@ -156,13 +173,14 @@ end
156173
function collect_completions(x::StaticLint.Scope, spartial, rng, CIs, server, inclexported=false, dotcomps=false)
157174
if x.names !== nothing
158175
for n in x.names
159-
if startswith(n[1], spartial)
176+
if is_completion_match(n[1], spartial)
160177
documentation = ""
161178
if n[2] isa StaticLint.Binding
162179
documentation = get_hover(n[2], documentation, server)
163180
sanitize_docstring(documentation)
164181
end
165-
push!(CIs, CompletionItem(n[1], _completion_kind(n[2], server), MarkupContent(documentation), TextEdit(rng, n[1][nextind(n[1], sizeof(spartial)):end])))
182+
rng1 = Range(Position(rng.start.line, rng.start.character - sizeof(spartial)), rng.stop)
183+
push!(CIs, CompletionItem(n[1], _completion_kind(n[2], server), MarkupContent(documentation), TextEdit(rng1, n[1])))
166184
end
167185
end
168186
end
@@ -189,15 +207,17 @@ function _get_dot_completion(px::EXPR, spartial, rng, CIs, server)
189207
elseif refof(px).type isa SymbolServer.DataTypeStore
190208
for a in refof(px).type.fieldnames
191209
a = String(a)
192-
if startswith(a, spartial)
193-
push!(CIs, CompletionItem(a, 2, MarkupContent(a), TextEdit(rng, a[nextind(a, sizeof(spartial)):end])))
210+
if is_completion_match(a, spartial)
211+
rng1 = Range(Position(rng.start.line, rng.start.character - sizeof(spartial)), rng.stop)
212+
push!(CIs, CompletionItem(a, 2, MarkupContent(a), TextEdit(rng1, a)))
194213
end
195214
end
196215
elseif refof(px).type isa StaticLint.Binding && refof(px).type.val isa SymbolServer.DataTypeStore
197216
for a in refof(px).type.val.fieldnames
198217
a = String(a)
199-
if startswith(a, spartial)
200-
push!(CIs, CompletionItem(a, 2, MarkupContent(a), TextEdit(rng, a[nextind(a, sizeof(spartial)):end])))
218+
if is_completion_match(a, spartial)
219+
rng1 = Range(Position(rng.start.line, rng.start.character - sizeof(spartial)), rng.stop)
220+
push!(CIs, CompletionItem(a, 2, MarkupContent(a), TextEdit(rng1, a)))
201221
end
202222
end
203223
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
@@ -247,7 +267,7 @@ end
247267
function string_completion(doc, offset, rng, t, CIs)
248268
path_completion(doc, offset, rng, t, CIs)
249269
# Need to adjust things for quotation marks
250-
if t.kind in (CSTParser.Tokenize.Tokens.STRING,CSTParser.Tokenize.Tokens.CMD)
270+
if t.kind in (CSTParser.Tokenize.Tokens.STRING, CSTParser.Tokenize.Tokens.CMD)
251271
t.startbyte < offset <= t.endbyte || return
252272
relative_offset = offset - t.startbyte - 1
253273
content = t.val[2:prevind(t.val, lastindex(t.val))]
@@ -310,7 +330,8 @@ function path_completion(doc, offset, rng, t, CIs)
310330
if isdir(joinpath(dir, f))
311331
f = string(f, "/")
312332
end
313-
push!(CIs, CompletionItem(f, 17, f, TextEdit(rng, f[nextind(f, lastindex(partial)):end])))
333+
rng1 = Range(doc, offset - sizeof(partial):offset)
334+
push!(CIs, CompletionItem(f, 17, f, TextEdit(rng1, f)))
314335
catch err
315336
isa(err, Base.IOError) || isa(err, Base.SystemError) || rethrow()
316337
end
@@ -326,17 +347,18 @@ is_in_import_statement(x::EXPR) = is_in_fexpr(x, x -> headof(x) in (:using, :imp
326347

327348
function import_completions(doc, offset, rng, ppt, pt, t, is_at_end, x, CIs, server)
328349
import_statement = StaticLint.get_parent_fexpr(x, x -> headof(x) === :using || headof(x) === :import)
329-
350+
330351
import_root = get_import_root(import_statement)
331-
352+
332353
if (t.kind == CSTParser.Tokens.WHITESPACE && pt.kind (CSTParser.Tokens.USING, CSTParser.Tokens.IMPORT, CSTParser.Tokens.IMPORTALL, CSTParser.Tokens.COMMA, CSTParser.Tokens.COLON)) ||
333354
(t.kind in (CSTParser.Tokens.COMMA, CSTParser.Tokens.COLON))
334355
# no partial, no dot
335356
if import_root !== nothing && refof(import_root) isa SymbolServer.ModuleStore
336357
for (n, m) in refof(import_root).vals
337358
n = String(n)
338-
if startswith(n, t.val) && !startswith(n, "#")
339-
push!(CIs, CompletionItem(n, _completion_kind(m, server), MarkupContent(m isa SymbolServer.SymStore ? sanitize_docstring(m.doc) : n), TextEdit(rng, n[length(t.val) + 1:end])))
359+
if is_completion_match(n, t.val) && !startswith(n, "#")
360+
rng1 = Range(doc, offset - sizeof(t.val):offset)
361+
push!(CIs, CompletionItem(n, _completion_kind(m, server), MarkupContent(m isa SymbolServer.SymStore ? sanitize_docstring(m.doc) : n), TextEdit(rng1, n)))
340362
end
341363
end
342364
else
@@ -358,24 +380,27 @@ function import_completions(doc, offset, rng, ppt, pt, t, is_at_end, x, CIs, ser
358380
rootmod = StaticLint.getsymbolserver(server)[Symbol(ppt.val)]
359381
for (n, m) in rootmod.vals
360382
n = String(n)
361-
if startswith(n, t.val) && !startswith(n, "#")
362-
push!(CIs, CompletionItem(n, _completion_kind(m, server), MarkupContent(m isa SymbolServer.SymStore ? sanitize_docstring(m.doc) : n), TextEdit(rng, n[length(t.val) + 1:end])))
383+
if is_completion_match(n, t.val) && !startswith(n, "#")
384+
rng1 = Range(doc, offset - sizeof(t.val):offset)
385+
push!(CIs, CompletionItem(n, _completion_kind(m, server), MarkupContent(m isa SymbolServer.SymStore ? sanitize_docstring(m.doc) : n), TextEdit(rng1, n)))
363386
end
364387
end
365388
end
366389
else
367390
if import_root !== nothing && refof(import_root) isa SymbolServer.ModuleStore
368391
for (n, m) in refof(import_root).vals
369392
n = String(n)
370-
if startswith(n, t.val) && !startswith(n, "#")
371-
push!(CIs, CompletionItem(n, _completion_kind(m, server), MarkupContent(m isa SymbolServer.SymStore ? sanitize_docstring(m.doc) : n), TextEdit(rng, n[length(t.val) + 1:end])))
393+
if is_completion_match(n, t.val) && !startswith(n, "#")
394+
rng1 = Range(doc, offset - sizeof(t.val):offset)
395+
push!(CIs, CompletionItem(n, _completion_kind(m, server), MarkupContent(m isa SymbolServer.SymStore ? sanitize_docstring(m.doc) : n), TextEdit(rng1, n)))
372396
end
373397
end
374398
else
375399
for (n, m) in StaticLint.getsymbolserver(server)
376400
n = String(n)
377-
if startswith(n, t.val)
378-
push!(CIs, CompletionItem(n, 9, MarkupContent(m isa SymbolServer.SymStore ? m.doc : n), TextEdit(rng, n[nextind(n, sizeof(t.val)):end])))
401+
if is_completion_match(n, t.val)
402+
rng1 = Range(doc, offset - sizeof(t.val):offset)
403+
push!(CIs, CompletionItem(n, 9, MarkupContent(m isa SymbolServer.SymStore ? m.doc : n), TextEdit(rng1, n)))
379404
end
380405
end
381406
end

src/requests/features.jl

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,6 @@ function get_name_of_binding(name::EXPR)
186186
end
187187

188188
function textDocument_documentSymbol_request(params::DocumentSymbolParams, server::LanguageServerInstance, conn)
189-
syms = SymbolInformation[]
190189
uri = params.textDocument.uri
191190
doc = getdocument(server, URI2(uri))
192191

@@ -285,8 +284,20 @@ function julia_getModuleAt_request(params::VersionedTextDocumentPositionParams,
285284
doc = getdocument(server, uri)
286285
if doc._version == params.version
287286
offset = get_offset2(doc, params.position.line, params.position.character, true)
288-
x = get_expr_or_parent(getcst(doc), offset, 1)
287+
x, p = get_expr_or_parent(getcst(doc), offset, 1)
289288
if x isa EXPR
289+
if x.head === :MODULE || x.head === :IDENTIFIER || x.head === :END
290+
if x.parent !== nothing && x.parent.head === :module
291+
x = x.parent
292+
if CSTParser.defines_module(x)
293+
x = x.parent
294+
end
295+
end
296+
end
297+
if CSTParser.defines_module(x) && p <= offset <= p + x[1].fullspan + x[2].fullspan
298+
x = x.parent
299+
end
300+
290301
scope = StaticLint.retrieve_scope(x)
291302
if scope !== nothing
292303
return get_module_of(scope)
@@ -350,3 +361,21 @@ function julia_getDocFromWord_request(params::NamedTuple{(:word,),Tuple{String}}
350361
return join(isempty(exact_matches) ? approx_matches[1:min(end, 10)] : exact_matches, "\n---\n")
351362
end
352363
end
364+
365+
function textDocument_selectionRange_request(params::SelectionRangeParams, server::LanguageServerInstance, conn)
366+
doc = getdocument(server, URI2(params.textDocument.uri))
367+
map(params.positions) do position
368+
offset = get_offset(doc, position)
369+
x = get_expr1(getcst(doc), offset)
370+
get_selection_range_of_expr(x)
371+
end
372+
end
373+
374+
# Just returns a selection for each parent EXPR, should be more selective
375+
get_selection_range_of_expr(x) = missing
376+
function get_selection_range_of_expr(x::EXPR)
377+
doc, offset = get_file_loc(x)
378+
l1, c1 = get_position_at(doc, offset)
379+
l2, c2 = get_position_at(doc, offset + x.span)
380+
SelectionRange(Range(l1, c1, l2, c2), get_selection_range_of_expr(x.parent))
381+
end

0 commit comments

Comments
 (0)