class RubyLsp::Addon

@abstract
“‘
end
end
end
“My add-on name”
def name
end
# Perform any relevant initialization
def activate
class MyAddon < Addon
module MyGem
“`ruby
# Example
To register an add-on, inherit from this class and implement both `name` and `activate`

def activate(global_state, outgoing_queue)

Other tags:
    Abstract: -
def activate(global_state, outgoing_queue)
  raise AbstractMethodInvokedError
end

def add_error(error)

: (StandardError error) -> self
def add_error(error)
  @errors << error
  self
end

def create_code_lens_listener(response_builder, uri, dispatcher); end

: (ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens] response_builder, URI::Generic uri, Prism::Dispatcher dispatcher) -> void
@overridable
Creates a new CodeLens listener. This method is invoked on every CodeLens request
def create_code_lens_listener(response_builder, uri, dispatcher); end

def create_completion_listener(response_builder, node_context, dispatcher, uri); end

: (ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem] response_builder, NodeContext node_context, Prism::Dispatcher dispatcher, URI::Generic uri) -> void
@overridable
Creates a new Completion listener. This method is invoked on every Completion request
def create_completion_listener(response_builder, node_context, dispatcher, uri); end

def create_definition_listener(response_builder, uri, node_context, dispatcher); end

: (ResponseBuilders::CollectionResponseBuilder[(Interface::Location | Interface::LocationLink)] response_builder, URI::Generic uri, NodeContext node_context, Prism::Dispatcher dispatcher) -> void
@overridable
Creates a new Definition listener. This method is invoked on every Definition request
def create_definition_listener(response_builder, uri, node_context, dispatcher); end

def create_discover_tests_listener(response_builder, dispatcher, uri); end

: (ResponseBuilders::TestCollection response_builder, Prism::Dispatcher dispatcher, URI::Generic uri) -> void
@overridable
Creates a new Discover Tests listener. This method is invoked on every DiscoverTests request
def create_discover_tests_listener(response_builder, dispatcher, uri); end

def create_document_symbol_listener(response_builder, dispatcher); end

: (ResponseBuilders::DocumentSymbol response_builder, Prism::Dispatcher dispatcher) -> void
@overridable
Creates a new DocumentSymbol listener. This method is invoked on every DocumentSymbol request
def create_document_symbol_listener(response_builder, dispatcher); end

def create_hover_listener(response_builder, node_context, dispatcher); end

: (ResponseBuilders::Hover response_builder, NodeContext node_context, Prism::Dispatcher dispatcher) -> void
@overridable
Creates a new Hover listener. This method is invoked on every Hover request
def create_hover_listener(response_builder, node_context, dispatcher); end

def create_semantic_highlighting_listener(response_builder, dispatcher); end

: (ResponseBuilders::SemanticHighlighting response_builder, Prism::Dispatcher dispatcher) -> void
@overridable
def create_semantic_highlighting_listener(response_builder, dispatcher); end

def deactivate

Other tags:
    Abstract: -
def deactivate
  raise AbstractMethodInvokedError
end

def depend_on_ruby_lsp!(*version_constraints)

: (*String version_constraints) -> void
```
end
end
# ...
class MyAddon < RubyLsp::Addon
module MyGem

RubyLsp::Addon.depend_on_ruby_lsp!(">= 0.18.0")
```ruby

`addon.rb` file before defining any classes or requiring any files. For example:
gem that does not have a runtime dependency on the ruby-lsp gem. This method should be invoked at the top of the
Depend on a specific version of the Ruby LSP. This method should only be used if the add-on is distributed in a
def depend_on_ruby_lsp!(*version_constraints)
  version_object = Gem::Version.new(RubyLsp::VERSION)
  unless version_constraints.all? { |constraint| Gem::Requirement.new(constraint).satisfied_by?(version_object) }
    raise IncompatibleApiError,
      "Add-on is not compatible with this version of the Ruby LSP. Skipping its activation"
  end
end

def error?

: -> bool
def error?
  @errors.any?
end

def errors_details

: -> String
def errors_details
  @errors.map(&:full_message).join("\n\n")
end

def formatted_errors

: -> String
def formatted_errors
  <<~ERRORS
    #{name}:
      #{@errors.map(&:message).join("\n")}
  ERRORS
end

def get(addon_name, *version_constraints)

: (String addon_name, *String version_constraints) -> Addon
the responsibility of the add-ons using this API to handle these errors appropriately.
current version does not satisfy the given version constraint, then IncompatibleApiError will be raised. It is
Important: if the add-on is not found, AddonNotFoundError will be raised. If the add-on is found, but its

other add-ons, this is the way to get access to that API.
Get a reference to another add-on object by name and version. If an add-on exports an API that can be used by
def get(addon_name, *version_constraints)
  if version_constraints.empty?
    raise IncompatibleApiError, "Must specify version constraints when accessing other add-ons"
  end
  addon = addons.find { |addon| addon.name == addon_name }
  raise AddonNotFoundError, "Could not find add-on '#{addon_name}'" unless addon
  version_object = Gem::Version.new(addon.version)
  unless version_constraints.all? { |constraint| Gem::Requirement.new(constraint).satisfied_by?(version_object) }
    raise IncompatibleApiError,
      "Constraints #{version_constraints.inspect} is incompatible with #{addon_name} version #{addon.version}"
  end
  addon
end

def handle_window_show_message_response(title); end

: (String title) -> void
@overridable
https://microsoft.github.io/language-server-protocol/specification#window_showMessageRequest
the response
original request so that the response is delegated to the correct add-on and must override this method to handle
Handle a response from a window/showMessageRequest request. Add-ons must include the addon_name as part of the
def handle_window_show_message_response(title); end

def inherited(child_class)

: (singleton(Addon) child_class) -> void
Automatically track and instantiate add-on classes
def inherited(child_class)
  addon_classes << child_class
  super
end

def initialize

: -> void
def initialize
  @errors = [] #: Array[StandardError]
end

def load_addons(global_state, outgoing_queue, include_project_addons: true)

: (GlobalState global_state, Thread::Queue outgoing_queue, ?include_project_addons: bool) -> Array[StandardError]
Discovers and loads all add-ons. Returns a list of errors when trying to require add-ons
def load_addons(global_state, outgoing_queue, include_project_addons: true)
  # Require all add-ons entry points, which should be placed under
  # `some_gem/lib/ruby_lsp/your_gem_name/addon.rb` or in the workspace under
  # `your_project/ruby_lsp/project_name/addon.rb`
  addon_files = Gem.find_files("ruby_lsp/**/addon.rb")
  if include_project_addons
    project_addons = Dir.glob("#{global_state.workspace_path}/**/ruby_lsp/**/addon.rb")
    bundle_path = Bundler.bundle_path.to_s
    gems_dir = Bundler.bundle_path.join("gems")
    # Create an array of rejection glob patterns to ignore add-ons already discovered through Gem.find_files if
    # they are also copied inside the workspace for whatever reason. We received reports of projects having gems
    # installed in vendor/bundle despite BUNDLE_PATH pointing elsewhere. Without this mechanism, we will
    # double-require the same add-on, potentially for different versions of the same gem, which leads to incorrect
    # behavior
    reject_glob_patterns = addon_files.map do |path|
      relative_gem_path = Pathname.new(path).relative_path_from(gems_dir)
      first_part, *parts = relative_gem_path.to_s.split(File::SEPARATOR)
      first_part&.gsub!(/-([0-9.]+)$/, "*")
      "**/#{first_part}/#{parts.join("/")}"
    end
    project_addons.reject! do |path|
      path.start_with?(bundle_path) ||
        reject_glob_patterns.any? { |pattern| File.fnmatch?(pattern, path, File::Constants::FNM_PATHNAME) }
    end
    addon_files.concat(project_addons)
  end
  errors = addon_files.filter_map do |addon_path|
    # Avoid requiring this file twice. This may happen if you're working on the Ruby LSP itself and at the same
    # time have `ruby-lsp` installed as a vendored gem
    next if File.basename(File.dirname(addon_path)) == "ruby_lsp"
    require File.expand_path(addon_path)
    nil
  rescue => e
    e
  end
  # Instantiate all discovered add-on classes
  self.addons = addon_classes.map(&:new)
  self.file_watcher_addons = addons.select { |addon| addon.respond_to?(:workspace_did_change_watched_files) }
  # Activate each one of the discovered add-ons. If any problems occur in the add-ons, we don't want to
  # fail to boot the server
  addons.each do |addon|
    addon.activate(global_state, outgoing_queue)
  rescue => e
    addon.add_error(e)
  end
  errors
end

def name

Other tags:
    Abstract: -
def name
  raise AbstractMethodInvokedError
end

def resolve_test_commands(items)

: (Array[Hash[Symbol, untyped]]) -> Array[String]
@overridable
handling items related to the framework they add support for and have discovered themselves
Resolves the minimal set of commands required to execute the requested tests. Add-ons are responsible for only
def resolve_test_commands(items)
  []
end

def unload_addons

: -> void
Unloads all add-ons. Only intended to be invoked once when shutting down the Ruby LSP server
def unload_addons
  @addons.each(&:deactivate)
  @addons.clear
  @addon_classes.clear
  @file_watcher_addons.clear
end

def version

Other tags:
    Abstract: -
def version
  raise AbstractMethodInvokedError
end