Skip to content

Commit 295bc98

Browse files
authored
Merge branch 'master' into disable-comp
2 parents ea5092e + 5337be4 commit 295bc98

File tree

6 files changed

+121
-60
lines changed

6 files changed

+121
-60
lines changed

src/document.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ mutable struct Document
1313
root::Document
1414
function Document(uri::AbstractString, text::AbstractString, workspace_file::Bool, server=nothing)
1515
path = something(uri2filepath(uri), "")
16+
path == "" || isabspath(path) || throw(LSRelativePath("Relative path `$path` is not valid."))
1617
cst = CSTParser.parse(text, true)
1718
doc = new(uri, path, text, nothing, nothing, false, workspace_file, cst, [], 0, server)
1819
get_line_offsets(doc)
@@ -97,12 +98,13 @@ end
9798
get_offset(doc, p::Position) = get_offset(doc, p.line, p.character)
9899
get_offset(doc, r::Range) = get_offset(doc, r.start):get_offset(doc, r.stop)
99100

100-
function get_offset2(doc::Document, line::Integer, character::Integer)
101+
# 1-based. Basically the index at which (line, character) can be found in the document.
102+
function get_offset2(doc::Document, line::Integer, character::Integer, forgiving_mode=false)
101103
line_offsets = get_line_offsets2!(doc)
102104
text = get_text(doc)
103105

104106
if line >= length(line_offsets)
105-
throw(LSOffsetError("get_offset2 crashed. More diagnostics:\nline=$line\nline_offsets='$line_offsets'"))
107+
forgiving_mode || throw(LSOffsetError("get_offset2 crashed. More diagnostics:\nline=$line\nline_offsets='$line_offsets'"))
106108
return nextind(text, lastindex(text))
107109
elseif line < 0
108110
throw(LSOffsetError("get_offset2 crashed. More diagnostics:\nline=$line\nline_offsets='$line_offsets'"))

src/languageserverinstance.jl

Lines changed: 68 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ mutable struct LanguageServerInstance
6262
clientCapabilities::Union{ClientCapabilities,Missing}
6363
clientInfo::Union{InfoParams,Missing}
6464

65+
shutdown_requested::Bool
66+
6567
function LanguageServerInstance(pipe_in, pipe_out, env_path="", depot_path="", err_handler=nothing, symserver_store_path=nothing)
6668
new(
6769
JSONRPC.JSONRPCEndpoint(pipe_in, pipe_out, err_handler),
@@ -87,7 +89,8 @@ mutable struct LanguageServerInstance
8789
false,
8890
false,
8991
missing,
90-
missing
92+
missing,
93+
false
9194
)
9295
end
9396
end
@@ -174,16 +177,16 @@ function trigger_symbolstore_reload(server::LanguageServerInstance)
174177
server.symbol_server,
175178
server.env_path,
176179
function (i)
177-
if server.clientcapability_window_workdoneprogress && server.current_symserver_progress_token !== nothing
178-
JSONRPC.send(
180+
if server.clientcapability_window_workdoneprogress && server.current_symserver_progress_token !== nothing
181+
JSONRPC.send(
179182
server.jr_endpoint,
180183
progress_notification_type,
181184
ProgressParams(server.current_symserver_progress_token, WorkDoneProgressReport(missing, "Indexing $i...", missing))
182185
)
183-
else
184-
@info "Indexing $i..."
185-
end
186-
end,
186+
else
187+
@info "Indexing $i..."
188+
end
189+
end,
187190
server.err_handler
188191
)
189192

@@ -228,6 +231,21 @@ function trigger_symbolstore_reload(server::LanguageServerInstance)
228231
end
229232
end
230233

234+
function request_wrapper(func, server::LanguageServerInstance)
235+
return function (conn, params)
236+
if server.shutdown_requested
237+
# it's fine to always return a value here, even for notifications, because
238+
# JSONRPC discards it anyways in that case
239+
return JSONRPC.JSONRPCError(
240+
-32600,
241+
"LS shutdown was requested.",
242+
nothing
243+
)
244+
end
245+
func(params, server, conn)
246+
end
247+
end
248+
231249
"""
232250
run(server::LanguageServerInstance)
233251
@@ -252,6 +270,9 @@ function Base.run(server::LanguageServerInstance)
252270
else
253271
Base.display_error(stderr, err, bt)
254272
end
273+
finally
274+
put!(server.combined_msg_queue, (type = :close,))
275+
close(server.combined_msg_queue)
255276
end
256277

257278
@async try
@@ -266,47 +287,53 @@ function Base.run(server::LanguageServerInstance)
266287
else
267288
Base.display_error(stderr, err, bt)
268289
end
290+
finally
291+
put!(server.combined_msg_queue, (type = :close,))
292+
close(server.combined_msg_queue)
269293
end
270294

271295
msg_dispatcher = JSONRPC.MsgDispatcher()
272-
msg_dispatcher[textDocument_codeAction_request_type] = (conn, params) -> textDocument_codeAction_request(params, server, conn)
273-
msg_dispatcher[workspace_executeCommand_request_type] = (conn, params) -> workspace_executeCommand_request(params, server, conn)
274-
msg_dispatcher[textDocument_completion_request_type] = (conn, params) -> textDocument_completion_request(params, server, conn)
275-
msg_dispatcher[textDocument_signatureHelp_request_type] = (conn, params) -> textDocument_signatureHelp_request(params, server, conn)
276-
msg_dispatcher[textDocument_definition_request_type] = (conn, params) -> textDocument_definition_request(params, server, conn)
277-
msg_dispatcher[textDocument_formatting_request_type] = (conn, params) -> textDocument_formatting_request(params, server, conn)
278-
msg_dispatcher[textDocument_references_request_type] = (conn, params) -> textDocument_references_request(params, server, conn)
279-
msg_dispatcher[textDocument_rename_request_type] = (conn, params) -> textDocument_rename_request(params, server, conn)
280-
msg_dispatcher[textDocument_documentSymbol_request_type] = (conn, params) -> textDocument_documentSymbol_request(params, server, conn)
281-
msg_dispatcher[julia_getModuleAt_request_type] = (conn, params) -> julia_getModuleAt_request(params, server, conn)
282-
msg_dispatcher[julia_getDocAt_request_type] = (conn, params) -> julia_getDocAt_request(params, server, conn)
283-
msg_dispatcher[textDocument_hover_request_type] = (conn, params) -> textDocument_hover_request(params, server, conn)
284-
msg_dispatcher[initialize_request_type] = (conn, params) -> initialize_request(params, server, conn)
285-
msg_dispatcher[initialized_notification_type] = (conn, params) -> initialized_notification(params, server, conn)
286-
msg_dispatcher[shutdown_request_type] = (conn, params) -> shutdown_request(params, server, conn)
287-
msg_dispatcher[exit_notification_type] = (conn, params) -> exit_notification(params, server, conn)
288-
msg_dispatcher[cancel_notification_type] = (conn, params) -> cancel_notification(params, server, conn)
289-
msg_dispatcher[setTrace_notification_type] = (conn, params) -> setTrace_notification(params, server, conn)
290-
msg_dispatcher[setTraceNotification_notification_type] = (conn, params) -> setTraceNotification_notification(params, server, conn) # Can we drop this?
291-
msg_dispatcher[julia_getCurrentBlockRange_request_type] = (conn, params) -> julia_getCurrentBlockRange_request(params, server, conn)
292-
msg_dispatcher[julia_activateenvironment_notification_type] = (conn, params) -> julia_activateenvironment_notification(params, server, conn)
293-
msg_dispatcher[textDocument_didOpen_notification_type] = (conn, params) -> textDocument_didOpen_notification(params, server, conn)
294-
msg_dispatcher[textDocument_didClose_notification_type] = (conn, params) -> textDocument_didClose_notification(params, server, conn)
295-
msg_dispatcher[textDocument_didSave_notification_type] = (conn, params) -> textDocument_didSave_notification(params, server, conn)
296-
msg_dispatcher[textDocument_willSave_notification_type] = (conn, params) -> textDocument_willSave_notification(params, server, conn)
297-
msg_dispatcher[textDocument_willSaveWaitUntil_request_type] = (conn, params) -> textDocument_willSaveWaitUntil_request(params, server, conn)
298-
msg_dispatcher[textDocument_didChange_notification_type] = (conn, params) -> textDocument_didChange_notification(params, server, conn)
299-
msg_dispatcher[workspace_didChangeWatchedFiles_notification_type] = (conn, params) -> workspace_didChangeWatchedFiles_notification(params, server, conn)
300-
msg_dispatcher[workspace_didChangeConfiguration_notification_type] = (conn, params) -> workspace_didChangeConfiguration_notification(params, server, conn)
301-
msg_dispatcher[workspace_didChangeWorkspaceFolders_notification_type] = (conn, params) -> workspace_didChangeWorkspaceFolders_notification(params, server, conn)
302-
msg_dispatcher[workspace_symbol_request_type] = (conn, params) -> workspace_symbol_request(params, server, conn)
303-
msg_dispatcher[julia_refreshLanguageServer_notification_type] = (conn, params) -> julia_refreshLanguageServer_notification(params, server, conn)
304-
msg_dispatcher[julia_getDocFromWord_request_type] = (conn, params) -> julia_getDocFromWord_request(params, server, conn)
296+
msg_dispatcher[textDocument_codeAction_request_type] = request_wrapper(textDocument_codeAction_request, server)
297+
msg_dispatcher[workspace_executeCommand_request_type] = request_wrapper(workspace_executeCommand_request, server)
298+
msg_dispatcher[textDocument_completion_request_type] = request_wrapper(textDocument_completion_request, server)
299+
msg_dispatcher[textDocument_signatureHelp_request_type] = request_wrapper(textDocument_signatureHelp_request, server)
300+
msg_dispatcher[textDocument_definition_request_type] = request_wrapper(textDocument_definition_request, server)
301+
msg_dispatcher[textDocument_formatting_request_type] = request_wrapper(textDocument_formatting_request, server)
302+
msg_dispatcher[textDocument_references_request_type] = request_wrapper(textDocument_references_request, server)
303+
msg_dispatcher[textDocument_rename_request_type] = request_wrapper(textDocument_rename_request, server)
304+
msg_dispatcher[textDocument_documentSymbol_request_type] = request_wrapper(textDocument_documentSymbol_request, server)
305+
msg_dispatcher[julia_getModuleAt_request_type] = request_wrapper(julia_getModuleAt_request, server)
306+
msg_dispatcher[julia_getDocAt_request_type] = request_wrapper(julia_getDocAt_request, server)
307+
msg_dispatcher[textDocument_hover_request_type] = request_wrapper(textDocument_hover_request, server)
308+
msg_dispatcher[initialize_request_type] = request_wrapper(initialize_request, server)
309+
msg_dispatcher[initialized_notification_type] = request_wrapper(initialized_notification, server)
310+
msg_dispatcher[shutdown_request_type] = request_wrapper(shutdown_request, server)
311+
msg_dispatcher[exit_notification_type] = request_wrapper(exit_notification, server)
312+
msg_dispatcher[cancel_notification_type] = request_wrapper(cancel_notification, server)
313+
msg_dispatcher[setTrace_notification_type] = request_wrapper(setTrace_notification, server)
314+
msg_dispatcher[setTraceNotification_notification_type] = request_wrapper(setTraceNotification_notification, server)
315+
msg_dispatcher[julia_getCurrentBlockRange_request_type] = request_wrapper(julia_getCurrentBlockRange_request, server)
316+
msg_dispatcher[julia_activateenvironment_notification_type] = request_wrapper(julia_activateenvironment_notification, server)
317+
msg_dispatcher[textDocument_didOpen_notification_type] = request_wrapper(textDocument_didOpen_notification, server)
318+
msg_dispatcher[textDocument_didClose_notification_type] = request_wrapper(textDocument_didClose_notification, server)
319+
msg_dispatcher[textDocument_didSave_notification_type] = request_wrapper(textDocument_didSave_notification, server)
320+
msg_dispatcher[textDocument_willSave_notification_type] = request_wrapper(textDocument_willSave_notification, server)
321+
msg_dispatcher[textDocument_willSaveWaitUntil_request_type] = request_wrapper(textDocument_willSaveWaitUntil_request, server)
322+
msg_dispatcher[textDocument_didChange_notification_type] = request_wrapper(textDocument_didChange_notification, server)
323+
msg_dispatcher[workspace_didChangeWatchedFiles_notification_type] = request_wrapper(workspace_didChangeWatchedFiles_notification, server)
324+
msg_dispatcher[workspace_didChangeConfiguration_notification_type] = request_wrapper(workspace_didChangeConfiguration_notification, server)
325+
msg_dispatcher[workspace_didChangeWorkspaceFolders_notification_type] = request_wrapper(workspace_didChangeWorkspaceFolders_notification, server)
326+
msg_dispatcher[workspace_symbol_request_type] = request_wrapper(workspace_symbol_request, server)
327+
msg_dispatcher[julia_refreshLanguageServer_notification_type] = request_wrapper(julia_refreshLanguageServer_notification, server)
328+
msg_dispatcher[julia_getDocFromWord_request_type] = request_wrapper(julia_getDocFromWord_request, server)
305329

306330
while true
307331
message = take!(server.combined_msg_queue)
308332

309-
if message.type == :clientmsg
333+
if message.type == :close
334+
@info "Shutting down server instance."
335+
return
336+
elseif message.type == :clientmsg
310337
msg = message.msg
311338

312339
JSONRPC.dispatch_msg(server.jr_endpoint, msg_dispatcher, msg)

src/requests/features.jl

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,8 @@ end
2525

2626
function get_definitions(x::Union{SymbolServer.FunctionStore,SymbolServer.DataTypeStore}, tls, server, locations)
2727
StaticLint.iterate_over_ss_methods(x, tls, server, function (m)
28-
try
29-
if isfile(m.file)
30-
push!(locations, Location(filepath2uri(m.file), Range(m.line - 1, 0, m.line - 1, 0)))
31-
end
32-
catch err
33-
isa(err, Base.IOError) || isa(err, Base.SystemError) || rethrow()
28+
if safe_isfile(m.file)
29+
push!(locations, Location(filepath2uri(m.file), Range(m.line - 1, 0, m.line - 1, 0)))
3430
end
3531
return false
3632
end)
@@ -59,6 +55,16 @@ function get_definitions(x::EXPR, tls::StaticLint.Scope, server, locations)
5955
end
6056
end
6157

58+
safe_isfile(s::Symbol) = safe_isfile(string(s))
59+
function safe_isfile(s::AbstractString)
60+
try
61+
!occursin("\0", s) && isfile(s)
62+
catch err
63+
isa(err, Base.IOError) || isa(err, Base.SystemError) || rethrow()
64+
false
65+
end
66+
end
67+
6268
function textDocument_definition_request(params::TextDocumentPositionParams, server::LanguageServerInstance, conn)
6369
locations = Location[]
6470
doc = getdocument(server, URI2(params.textDocument.uri))
@@ -74,9 +80,9 @@ function textDocument_definition_request(params::TextDocumentPositionParams, ser
7480
# TODO: move to its own function
7581
if valof(x) isa String && sizeof(valof(x)) < 256 # AUDIT: OK
7682
try
77-
if isabspath(valof(x)) && isfile(valof(x))
83+
if isabspath(valof(x)) && safe_isfile(valof(x))
7884
push!(locations, Location(filepath2uri(valof(x)), Range(0, 0, 0, 0)))
79-
elseif !isempty(getpath(doc)) && isfile(joinpath(_dirname(getpath(doc)), valof(x)))
85+
elseif !isempty(getpath(doc)) && safe_isfile(joinpath(_dirname(getpath(doc)), valof(x)))
8086
push!(locations, Location(filepath2uri(joinpath(_dirname(getpath(doc)), valof(x))), Range(0, 0, 0, 0)))
8187
end
8288
catch err
@@ -120,7 +126,8 @@ function find_references(textDocument::TextDocumentIdentifier, position::Positio
120126
locations = Location[]
121127
doc = getdocument(server, URI2(textDocument.uri))
122128
offset = get_offset(doc, position)
123-
x = get_expr1(getcst(doc), offset)
129+
x = get_identifier(getcst(doc), offset)
130+
124131
if x isa EXPR && StaticLint.hasref(x) && refof(x) isa StaticLint.Binding
125132
for r in refof(x).refs
126133
if r isa EXPR
@@ -272,8 +279,8 @@ function julia_getModuleAt_request(params::VersionedTextDocumentPositionParams,
272279
if hasdocument(server, uri)
273280
doc = getdocument(server, uri)
274281
if doc._version == params.version
275-
offset = get_offset2(doc, params.position.line, params.position.character)
276-
x = get_expr(getcst(doc), offset)
282+
offset = get_offset2(doc, params.position.line, params.position.character, true)
283+
x = get_expr_or_parent(getcst(doc), offset, 1)
277284
if x isa EXPR
278285
scope = StaticLint.retrieve_scope(x)
279286
if scope !== nothing

src/requests/init.jl

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,13 +188,12 @@ function initialized_notification(params::InitializedParams, server::LanguageSer
188188
end
189189
end
190190

191-
# TODO provide type for params
192-
function shutdown_request(params, server::LanguageServerInstance, conn)
191+
function shutdown_request(params::Nothing, server::LanguageServerInstance, conn)
192+
server.shutdown_requested = true
193193
return nothing
194194
end
195195

196-
# TODO provide type for params
197-
function exit_notification(params, server::LanguageServerInstance, conn)
196+
function exit_notification(params::Nothing, server::LanguageServerInstance, conn)
198197
server.symbol_server.process isa Base.Process && kill(server.symbol_server.process)
199-
exit()
198+
exit(server.shutdown_requested ? 0 : 1)
200199
end

src/staticlint.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import StaticLint: getpath, getroot, setroot, getcst, setcst, semantic_pass, get
33
hasfile(server::LanguageServerInstance, path::String) = !isempty(path) && hasdocument(server, URI2(filepath2uri(path)))
44
function canloadfile(server::LanguageServerInstance, path::String)
55
try
6-
return !isempty(path) && isfile(path)
6+
return !isempty(path) && !safe_isfile(path)
77
catch err
88
isa(err, Base.IOError) || isa(err, Base.SystemError) || rethrow()
99
return false

src/utilities.jl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,32 @@ function get_expr(x, offset, pos=0, ignorewhitespace=false)
207207
end
208208
end
209209

210+
# like get_expr, but only returns a expr if offset is not on the edge of it's span
211+
function get_expr_or_parent(x, offset, pos=0)
212+
if pos > offset
213+
return nothing
214+
end
215+
if length(x) > 0 && headof(x) !== :NONSTDIDENTIFIER
216+
for a in x
217+
if pos < offset <= (pos + a.fullspan)
218+
if pos < offset < (pos + a.span)
219+
return get_expr_or_parent(a, offset, pos)
220+
else
221+
return x
222+
end
223+
end
224+
pos += a.fullspan
225+
end
226+
elseif pos == 0
227+
return x
228+
elseif (pos < offset <= (pos + x.fullspan))
229+
if pos + x.span < offset
230+
return x.parent
231+
end
232+
return x
233+
end
234+
end
235+
210236
function get_expr(x, offset::UnitRange{Int}, pos=0, ignorewhitespace=false)
211237
if all(pos .> offset)
212238
return nothing

0 commit comments

Comments
 (0)