Skip to content

Commit

Permalink
Add custom command to return LSP internal state
Browse files Browse the repository at this point in the history
  • Loading branch information
vinistock committed Feb 13, 2025
1 parent 5c2ce7e commit 2afdeb7
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 1 deletion.
3 changes: 2 additions & 1 deletion lib/ruby_lsp/base_server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ def start
# The following requests need to be executed in the main thread directly to avoid concurrency issues. Everything
# else is pushed into the incoming queue
case method
when "initialize", "initialized", "textDocument/didOpen", "textDocument/didClose", "textDocument/didChange"
when "initialize", "initialized", "textDocument/didOpen", "textDocument/didClose", "textDocument/didChange",
"rubyLsp/diagnoseState"
process_message(message)
when "shutdown"
@global_state.synchronize do
Expand Down
21 changes: 21 additions & 0 deletions lib/ruby_lsp/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ def process_message(message)
)
when "rubyLsp/composeBundle"
compose_bundle(message)
when "rubyLsp/diagnoseState"
diagnose_state(message)
when "$/cancelRequest"
@global_state.synchronize { @cancelled_requests << message[:params][:id] }
when nil
Expand Down Expand Up @@ -1368,5 +1370,24 @@ def compose_bundle(message)
end
end
end

# Returns internal state information for debugging purposes
sig { params(message: T::Hash[Symbol, T.untyped]).void }
def diagnose_state(message)
documents = {}
@store.each { |uri, document| documents[uri] = document.source }

send_message(
Result.new(
id: message[:id],
response: {
workerAlive: @worker.alive?,
backtrace: @worker.backtrace,
documents: documents,
incomingQueueSize: @incoming_queue.length,
},
),
)
end
end
end
25 changes: 25 additions & 0 deletions test/server_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1371,6 +1371,31 @@ class Foo
end
end

def test_diagnose_state
@server.process_message({
method: "textDocument/didOpen",
params: {
textDocument: {
uri: URI::Generic.from_path(path: "/foo.rb"),
text: "class Foo\nend",
version: 1,
languageId: "ruby",
},
},
})
@server.process_message({ id: 1, method: "rubyLsp/diagnoseState", params: {} })
result = find_message(RubyLsp::Result, id: 1)

assert(result.response[:workerAlive])
assert_equal({ "file:///foo.rb" => "class Foo\nend" }, result.response[:documents])

first, second = result.response[:backtrace]
assert_match(/<internal:thread_sync>.*Thread::Queue#pop/, first)
assert_match(/base_server\.rb.*RubyLsp::BaseServer#new_worker/, second)

assert_equal(0, result.response[:incomingQueueSize])
end

private

def with_uninstalled_rubocop(&block)
Expand Down

0 comments on commit 2afdeb7

Please sign in to comment.