Skip to content

Commit

Permalink
Decouple Listener from Request
Browse files Browse the repository at this point in the history
  • Loading branch information
st0012 committed Jan 10, 2024
1 parent 2b1caa5 commit 885c4ed
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 53 deletions.
2 changes: 1 addition & 1 deletion lib/ruby_lsp/check_docs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def run_task
# documented
features = ObjectSpace.each_object(Class).select do |k|
klass = T.unsafe(k)
klass < Requests::Request && klass != Listener && klass != ExtensibleListener
klass < Requests::Request
end

missing_docs = T.let(Hash.new { |h, k| h[k] = [] }, T::Hash[String, T::Array[String]])
Expand Down
54 changes: 2 additions & 52 deletions lib/ruby_lsp/listener.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
module RubyLsp
# Listener is an abstract class to be used by requests for listening to events emitted when visiting an AST using the
# Prism::Dispatcher.
class Listener < Requests::Request
class Listener
extend T::Sig
extend T::Helpers
extend T::Generic
Expand All @@ -20,7 +20,7 @@ def initialize(dispatcher)
@dispatcher = dispatcher
end

sig { override.returns(ResponseType) }
sig { returns(ResponseType) }
def response
_response
end
Expand All @@ -30,54 +30,4 @@ def response
sig { abstract.returns(ResponseType) }
def _response; end
end

# ExtensibleListener is an abstract class to be used by requests that accept addons.
class ExtensibleListener < Listener
extend T::Sig
extend T::Generic

ResponseType = type_member

abstract!

# When inheriting from ExtensibleListener, the `super` of constructor must be called **after** the subclass's own
# ivars have been initialized. This is because the constructor of ExtensibleListener calls
# `initialize_external_listener` which may depend on the subclass's ivars.
sig { params(dispatcher: Prism::Dispatcher).void }
def initialize(dispatcher)
super
@response_merged = T.let(false, T::Boolean)
@external_listeners = T.let(
Addon.addons.filter_map do |ext|
initialize_external_listener(ext)
end,
T::Array[RubyLsp::Listener[ResponseType]],
)
end

# Merge responses from all external listeners into the base listener's response. We do this to return a single
# response to the editor including the results of all addons
sig { void }
def merge_external_listeners_responses!
@external_listeners.each { |l| merge_response!(l) }
end

sig { override.returns(ResponseType) }
def response
merge_external_listeners_responses! unless @response_merged
super
end

sig do
abstract.params(addon: RubyLsp::Addon).returns(T.nilable(RubyLsp::Listener[ResponseType]))
end
def initialize_external_listener(addon); end

# Does nothing by default. Requests that accept addons should override this method to define how to merge responses
# coming from external listeners
sig { abstract.params(other: Listener[T.untyped]).returns(T.self_type) }
def merge_response!(other)
end
end
private_constant(:ExtensibleListener)
end

0 comments on commit 885c4ed

Please sign in to comment.