Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,9 @@ Sorbet/StrictSigil:
- "**/*.rake"
- "test/**/*.rb"
- "lib/ruby_lsp/ruby_lsp_rails/server.rb" # we can't assume sorbet-runtime is available

Layout/LeadingCommentSpace:
AllowRBSInlineAnnotation: true

Layout/LineLength:
AllowedPatterns: ['\A\s*#:'] # for inline RBS signaturs
51 changes: 28 additions & 23 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,9 @@ GEM
irb (1.14.1)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
json (2.7.6)
language_server-protocol (3.17.0.3)
json (2.10.1)
language_server-protocol (3.17.0.4)
lint_roller (1.1.0)
logger (1.6.5)
loofah (2.23.1)
crass (~> 1.0.2)
Expand Down Expand Up @@ -142,7 +143,7 @@ GEM
nokogiri (1.18.1-x86_64-linux-musl)
racc (~> 1.4)
parallel (1.26.3)
parser (3.3.6.0)
parser (3.3.7.1)
ast (~> 2.4.1)
racc
prism (1.3.0)
Expand Down Expand Up @@ -196,20 +197,21 @@ GEM
logger
rdoc (6.7.0)
psych (>= 4.0.0)
regexp_parser (2.9.2)
regexp_parser (2.10.0)
reline (0.5.11)
io-console (~> 0.5)
rubocop (1.68.0)
rubocop (1.73.1)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.4, < 3.0)
rubocop-ast (>= 1.32.2, < 2.0)
regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.38.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.34.0)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.38.1)
parser (>= 3.3.1.0)
rubocop-minitest (0.36.0)
rubocop (>= 1.61, < 2.0)
Expand All @@ -218,7 +220,7 @@ GEM
rubocop (~> 1.0)
rubocop-shopify (2.15.1)
rubocop (~> 1.51)
rubocop-sorbet (0.8.7)
rubocop-sorbet (0.8.9)
rubocop (>= 1)
ruby-lsp (0.23.6)
language_server-protocol (~> 3.17.0)
Expand All @@ -228,18 +230,19 @@ GEM
ruby-progressbar (1.13.0)
ruby2_keywords (0.0.5)
securerandom (0.3.1)
sorbet (0.5.11761)
sorbet-static (= 0.5.11761)
sorbet-runtime (0.5.11761)
sorbet-static (0.5.11761-aarch64-linux)
sorbet-static (0.5.11761-universal-darwin)
sorbet-static (0.5.11761-x86_64-linux)
sorbet-static-and-runtime (0.5.11761)
sorbet (= 0.5.11761)
sorbet-runtime (= 0.5.11761)
spoom (1.5.1)
sorbet (0.5.11865)
sorbet-static (= 0.5.11865)
sorbet-runtime (0.5.11865)
sorbet-static (0.5.11865-aarch64-linux)
sorbet-static (0.5.11865-universal-darwin)
sorbet-static (0.5.11865-x86_64-linux)
sorbet-static-and-runtime (0.5.11865)
sorbet (= 0.5.11865)
sorbet-runtime (= 0.5.11865)
spoom (1.5.4)
erubi (>= 1.10.0)
prism (>= 0.28.0)
rbi (>= 0.2.3)
sorbet-static-and-runtime (>= 0.5.10187)
thor (>= 0.19.2)
sqlite3 (2.5.0-aarch64-linux-gnu)
Expand All @@ -264,9 +267,11 @@ GEM
timeout (0.4.2)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
tzinfo-data (1.2024.2)
tzinfo-data (1.2025.1)
tzinfo (>= 1.0.0)
unicode-display_width (2.6.0)
unicode-display_width (3.1.4)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
uri (1.0.1)
useragent (0.16.10)
websocket-driver (0.7.6)
Expand Down
85 changes: 31 additions & 54 deletions lib/ruby_lsp/ruby_lsp_rails/addon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Addon < ::RubyLsp::Addon

RUN_MIGRATIONS_TITLE = "Run Migrations"

sig { void }
#: -> void
def initialize
super

Expand Down Expand Up @@ -53,12 +53,13 @@ def initialize
end
end

sig { returns(RunnerClient) }
#: -> RunnerClient
def rails_runner_client
@addon_mutex.synchronize { @rails_runner_client }
end

sig { override.params(global_state: GlobalState, outgoing_queue: Thread::Queue).void }
# @override
#: (GlobalState global_state, Thread::Queue outgoing_queue) -> void
def activate(global_state, outgoing_queue)
@global_state = global_state
@outgoing_queue = outgoing_queue
Expand All @@ -73,82 +74,56 @@ def activate(global_state, outgoing_queue)
@client_mutex.unlock
end

sig { override.void }
# @override
#: -> void
def deactivate
@rails_runner_client.shutdown
end

sig { override.returns(String) }
# @override
#: -> String
def version
VERSION
end

# Creates a new CodeLens listener. This method is invoked on every CodeLens request
sig do
override.params(
response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens],
uri: URI::Generic,
dispatcher: Prism::Dispatcher,
).void
end
# @override
#: (ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens] response_builder, URI::Generic uri, Prism::Dispatcher dispatcher) -> void
def create_code_lens_listener(response_builder, uri, dispatcher)
return unless @global_state

CodeLens.new(@rails_runner_client, @global_state, response_builder, uri, dispatcher)
end

sig do
override.params(
response_builder: ResponseBuilders::Hover,
node_context: NodeContext,
dispatcher: Prism::Dispatcher,
).void
end
# @override
#: (ResponseBuilders::Hover response_builder, NodeContext node_context, Prism::Dispatcher dispatcher) -> void
def create_hover_listener(response_builder, node_context, dispatcher)
return unless @global_state

Hover.new(@rails_runner_client, response_builder, node_context, @global_state, dispatcher)
end

sig do
override.params(
response_builder: ResponseBuilders::DocumentSymbol,
dispatcher: Prism::Dispatcher,
).returns(Object)
end
# @override
#: (ResponseBuilders::DocumentSymbol response_builder, Prism::Dispatcher dispatcher) -> Object
def create_document_symbol_listener(response_builder, dispatcher)
DocumentSymbol.new(response_builder, dispatcher)
end

sig do
override.params(
response_builder: ResponseBuilders::CollectionResponseBuilder[T.any(
Interface::Location, Interface::LocationLink
)],
uri: URI::Generic,
node_context: NodeContext,
dispatcher: Prism::Dispatcher,
).void
end
# @override
#: (ResponseBuilders::CollectionResponseBuilder[(Interface::Location | Interface::LocationLink)] response_builder, URI::Generic uri, NodeContext node_context, Prism::Dispatcher dispatcher) -> void
def create_definition_listener(response_builder, uri, node_context, dispatcher)
return unless @global_state

Definition.new(@rails_runner_client, response_builder, node_context, @global_state.index, dispatcher)
end

sig do
override.params(
response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem],
node_context: NodeContext,
dispatcher: Prism::Dispatcher,
uri: URI::Generic,
).void
end
# @override
#: (ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem] response_builder, NodeContext node_context, Prism::Dispatcher dispatcher, URI::Generic uri) -> void
def create_completion_listener(response_builder, node_context, dispatcher, uri)
Completion.new(@rails_runner_client, response_builder, node_context, dispatcher, uri)
end

sig { params(changes: T::Array[{ uri: String, type: Integer }]).void }
#: (Array[{uri: String, type: Integer}] changes) -> void
def workspace_did_change_watched_files(changes)
if changes.any? { |c| c[:uri].end_with?("db/schema.rb") || c[:uri].end_with?("structure.sql") }
@rails_runner_client.trigger_reload
Expand All @@ -162,12 +137,14 @@ def workspace_did_change_watched_files(changes)
end
end

sig { override.returns(String) }
# @override
#: -> String
def name
"Ruby LSP Rails"
end

sig { override.params(title: String).void }
# @override
#: (String title) -> void
def handle_window_show_message_response(title)
if title == RUN_MIGRATIONS_TITLE

Expand All @@ -194,7 +171,7 @@ def handle_window_show_message_response(title)

private

sig { params(id: String, title: String, percentage: T.nilable(Integer), message: T.nilable(String)).void }
#: (String id, String title, ?percentage: Integer?, ?message: String?) -> void
def begin_progress(id, title, percentage: nil, message: nil)
return unless @global_state&.client_capabilities&.supports_progress && @outgoing_queue

Expand All @@ -212,21 +189,21 @@ def begin_progress(id, title, percentage: nil, message: nil)
)
end

sig { params(id: String, percentage: T.nilable(Integer), message: T.nilable(String)).void }
def report_progress(id, percentage: nil, message: nil)
#: (String id, ?percentage: Integer?, ?message: String?) -> void
def report_progress(id, percentage: nil, message: nil)
return unless @global_state&.client_capabilities&.supports_progress && @outgoing_queue

@outgoing_queue << Notification.progress_report(id, percentage: percentage, message: message)
end

sig { params(id: String).void }
#: (String id) -> void
def end_progress(id)
return unless @global_state&.client_capabilities&.supports_progress && @outgoing_queue

@outgoing_queue << Notification.progress_end(id)
end

sig { params(global_state: GlobalState, outgoing_queue: Thread::Queue).void }
#: (global_state: GlobalState, outgoing_queue: Thread::Queue) -> void
def register_additional_file_watchers(global_state:, outgoing_queue:)
return unless global_state.client_capabilities.supports_watching_files

Expand All @@ -247,23 +224,23 @@ def register_additional_file_watchers(global_state:, outgoing_queue:)
)
end

sig { returns(Interface::FileSystemWatcher) }
#: -> Interface::FileSystemWatcher
def structure_sql_file_watcher
Interface::FileSystemWatcher.new(
glob_pattern: "**/*structure.sql",
kind: Constant::WatchKind::CREATE | Constant::WatchKind::CHANGE | Constant::WatchKind::DELETE,
)
end

sig { returns(Interface::FileSystemWatcher) }
#: -> Interface::FileSystemWatcher
def fixture_file_watcher
Interface::FileSystemWatcher.new(
glob_pattern: "**/fixtures/**/*.{yml,yaml,yml.erb,yaml.erb}",
kind: Constant::WatchKind::CREATE | Constant::WatchKind::CHANGE | Constant::WatchKind::DELETE,
)
end

sig { void }
#: -> void
def offer_to_run_pending_migrations
return unless @outgoing_queue
return unless @global_state&.client_capabilities&.window_show_message_supports_extra_properties
Expand Down
Loading
Loading