Skip to content

Commit

Permalink
Allow declaration of project addons
Browse files Browse the repository at this point in the history
  • Loading branch information
vinistock committed Sep 30, 2024
1 parent b4280d2 commit 8b3f382
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 5 deletions.
4 changes: 4 additions & 0 deletions jekyll/add-ons.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ The Ruby LSP discovers add-ons based on the existence of an `addon.rb` file plac
example, `my_gem/lib/ruby_lsp/my_gem/addon.rb`. This file must declare the add-on class, which can be used to perform any
necessary activation when the server starts.

{: .note }
Projects can also define their own private add-ons for functionality that only applies to a particular application. As
long as a file matching `ruby_lsp/**/addon.rb` exists inside of the workspace (not necessarily at the root), it will be
loaded by the Ruby LSP.

```ruby
# frozen_string_literal: true
Expand Down
2 changes: 2 additions & 0 deletions lib/ruby_indexer/lib/ruby_indexer/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ def initial_excluded_gems

excluded.uniq!
excluded.map(&:name)
rescue Bundler::GemfileNotFound
[]
end
end
end
7 changes: 7 additions & 0 deletions lib/ruby_lsp/addon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ def load_addons(global_state, outgoing_queue)
e
end

project_addons = Dir.glob(File.join(global_state.workspace_path, "**", "ruby_lsp/**/addon.rb"))
project_addons.each do |addon_path|
require File.expand_path(addon_path)
rescue => e
errors << e
end

# Instantiate all discovered addon classes
self.addons = addon_classes.map(&:new)
self.file_watcher_addons = addons.select { |addon| addon.respond_to?(:workspace_did_change_watched_files) }
Expand Down
18 changes: 15 additions & 3 deletions lib/ruby_lsp/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ module RubyLsp
module TestHelper
extend T::Sig

sig { void }
def before_setup
@mutex = T.let(Mutex.new, T.nilable(Mutex))
super
end

sig do
type_parameters(:T)
.params(
Expand Down Expand Up @@ -42,12 +48,18 @@ def with_server(source = nil, uri = Kernel.URI("file:///fake.rb"), stub_no_typec
RubyIndexer::IndexablePath.new(nil, T.must(uri.to_standardized_path)),
source,
)
server.load_addons if load_addons

if load_addons
T.must(@mutex).synchronize { server.load_addons }
end

block.call(server, uri)
ensure
if load_addons
RubyLsp::Addon.addons.each(&:deactivate)
RubyLsp::Addon.addons.clear
T.must(@mutex).synchronize do
RubyLsp::Addon.addons.each(&:deactivate)
RubyLsp::Addon.addons.clear
end
end
T.must(server).run_shutdown
end
Expand Down
35 changes: 35 additions & 0 deletions test/addon_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,5 +131,40 @@ def test_addons_receive_settings
ensure
T.must(outgoing_queue).close
end

def test_project_specific_addons
Dir.mktmpdir do |dir|
Dir.chdir(dir) do
addon_dir = File.join(dir, "lib", "ruby_lsp", "test_addon")
FileUtils.mkdir_p(addon_dir)
File.write(File.join(addon_dir, "addon.rb"), <<~RUBY)
class ProjectAddon < RubyLsp::Addon
attr_reader :hello
def activate(global_state, outgoing_queue)
@hello = true
end
def name
"Project Addon"
end
end
RUBY

queue = Thread::Queue.new
global_state = GlobalState.new
global_state.apply_options({
workspaceFolders: [{ uri: URI::Generic.from_path(path: dir).to_s }],
})
Addon.load_addons(global_state, queue)

addon = Addon.get("Project Addon")
assert_equal("Project Addon", addon.name)
assert_predicate(T.unsafe(addon), :hello)
ensure
T.must(queue).close
end
end
end
end
end
2 changes: 0 additions & 2 deletions test/requests/code_lens_expectations_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,6 @@ class Test < Minitest::Test; end
assert_match("Run In Terminal", response[1].command.title)
assert_match("Debug", response[2].command.title)
assert_match("Run Test", response[3].command.title)
ensure
RubyLsp::Addon.addon_classes.clear
end
end
end
Expand Down

0 comments on commit 8b3f382

Please sign in to comment.