Skip to content

Commit

Permalink
Use _response as Listeners' internal interface
Browse files Browse the repository at this point in the history
This will allow `ExternalListener` to encapsulate response merging logic
under `response`, which means we can always call `response` on the listener
regardless of whether it's an extensible or not.
  • Loading branch information
st0012 committed Sep 5, 2023
1 parent e9fede7 commit 9a211db
Show file tree
Hide file tree
Showing 15 changed files with 57 additions and 52 deletions.
6 changes: 3 additions & 3 deletions SERVER_EXTENSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ module RubyLsp
ResponseType = type_member { { fixed: T.nilable(::RubyLsp::Interface::Hover) } }

sig { override.returns(ResponseType) }
attr_reader :response
attr_reader :_response

# Listeners are initialized with the EventEmitter. This object is used by the Ruby LSP to emit the events when it
# finds nodes during AST analysis. Listeners must register which nodes they want to handle with the emitter (see
Expand All @@ -145,7 +145,7 @@ module RubyLsp
def initialize(config, emitter, message_queue)
super

@response = T.let(nil, ResponseType)
@_response = T.let(nil, ResponseType)
@config = config

# Register that this listener will handle `on_const` events (i.e.: whenever a constant is found in the code)
Expand All @@ -159,7 +159,7 @@ module RubyLsp
# Certain helpers are made available to listeners to build LSP responses. The classes under `RubyLsp::Interface`
# are generally used to build responses and they match exactly what the specification requests.
contents = RubyLsp::Interface::MarkupContent.new(kind: "markdown", value: "Hello!")
@response = RubyLsp::Interface::Hover.new(range: range_from_syntax_tree_node(node), contents: contents)
@_response = RubyLsp::Interface::Hover.new(range: range_from_syntax_tree_node(node), contents: contents)
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions lib/ruby_lsp/executor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ def run(request)

# Store all responses retrieve in this round of visits in the cache and then return the response for the request
# we actually received
document.cache_set("textDocument/documentSymbol", document_symbol.merged_response)
document.cache_set("textDocument/documentSymbol", document_symbol.response)
document.cache_set("textDocument/documentLink", document_link.response)
document.cache_set("textDocument/codeLens", code_lens.merged_response)
document.cache_set("textDocument/codeLens", code_lens.response)
document.cache_set(
"textDocument/semanticTokens/full",
Requests::Support::SemanticTokenEncoder.new.encode(semantic_highlighting.response),
Expand Down Expand Up @@ -291,7 +291,7 @@ def hover(uri, position)
# Emit events for all listeners
emitter.emit_for_target(target)

hover.merged_response
hover.response
end

sig { params(uri: URI::Generic, content_changes: T::Array[Document::EditShape], version: Integer).returns(Object) }
Expand Down
11 changes: 8 additions & 3 deletions lib/ruby_lsp/listener.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@ def initialize(emitter, message_queue)
@message_queue = message_queue
end

sig { returns(ResponseType) }
def response
_response
end

# Override this method with an attr_reader that returns the response of your listener. The listener should
# accumulate results in a @response variable and then provide the reader so that it is accessible
sig { abstract.returns(ResponseType) }
def response; end
def _response; end
end

# ExtensibleListener is an abstract class to be used by requests that accept extensions.
Expand Down Expand Up @@ -55,9 +60,9 @@ def merge_external_listeners_responses!
end

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

sig do
Expand Down
14 changes: 7 additions & 7 deletions lib/ruby_lsp/requests/code_lens.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ class CodeLens < ExtensibleListener
SUPPORTED_TEST_LIBRARIES = T.let(["minitest", "test-unit"], T::Array[String])

sig { override.returns(ResponseType) }
attr_reader :response
attr_reader :_response

sig { params(uri: URI::Generic, emitter: EventEmitter, message_queue: Thread::Queue, test_library: String).void }
def initialize(uri, emitter, message_queue, test_library)
@uri = T.let(uri, URI::Generic)
@test_library = T.let(test_library, String)
@response = T.let([], ResponseType)
@_response = T.let([], ResponseType)
@path = T.let(uri.to_standardized_path, T.nilable(String))
# visibility_stack is a stack of [current_visibility, previous_visibility]
@visibility_stack = T.let([["public", "public"]], T::Array[T::Array[T.nilable(String)]])
Expand Down Expand Up @@ -153,7 +153,7 @@ def initialize_external_listener(extension)

sig { override.params(other: Listener[ResponseType]).returns(T.self_type) }
def merge_response!(other)
@response.concat(other.response)
@_response.concat(other.response)
self
end

Expand All @@ -176,23 +176,23 @@ def add_test_code_lens(node, name:, command:, kind:)
},
]

@response << create_code_lens(
@_response << create_code_lens(
node,
title: "Run",
command_name: "rubyLsp.runTest",
arguments: arguments,
data: { type: "test", kind: kind },
)

@response << create_code_lens(
@_response << create_code_lens(
node,
title: "Run In Terminal",
command_name: "rubyLsp.runTestInTerminal",
arguments: arguments,
data: { type: "test_in_terminal", kind: kind },
)

@response << create_code_lens(
@_response << create_code_lens(
node,
title: "Debug",
command_name: "rubyLsp.debugTest",
Expand Down Expand Up @@ -241,7 +241,7 @@ def generate_test_command(class_name:, method_name: nil)

sig { params(node: SyntaxTree::Command, remote: String).void }
def add_open_gem_remote_code_lens(node, remote)
@response << create_code_lens(
@_response << create_code_lens(
node,
title: "Open remote",
command_name: "rubyLsp.openLink",
Expand Down
10 changes: 5 additions & 5 deletions lib/ruby_lsp/requests/definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class Definition < Listener
ResponseType = type_member { { fixed: T.nilable(T.any(T::Array[Interface::Location], Interface::Location)) } }

sig { override.returns(ResponseType) }
attr_reader :response
attr_reader :_response

sig do
params(
Expand All @@ -41,7 +41,7 @@ def initialize(uri, nesting, index, emitter, message_queue)
@uri = uri
@nesting = nesting
@index = index
@response = T.let(nil, ResponseType)
@_response = T.let(nil, ResponseType)
emitter.register(self, :on_command, :on_const, :on_const_path_ref)
end

Expand Down Expand Up @@ -74,7 +74,7 @@ def on_command(node)
candidate = find_file_in_load_path(required_file)

if candidate
@response = Interface::Location.new(
@_response = Interface::Location.new(
uri: URI::Generic.from_path(path: candidate).to_s,
range: Interface::Range.new(
start: Interface::Position.new(line: 0, character: 0),
Expand All @@ -88,7 +88,7 @@ def on_command(node)
candidate = File.expand_path(File.join(current_folder, required_file))

if candidate
@response = Interface::Location.new(
@_response = Interface::Location.new(
uri: URI::Generic.from_path(path: candidate).to_s,
range: Interface::Range.new(
start: Interface::Position.new(line: 0, character: 0),
Expand All @@ -112,7 +112,7 @@ def find_in_index(value)
nil
end

@response = entries.filter_map do |entry|
@_response = entries.filter_map do |entry|
location = entry.location
# If the project has Sorbet, then we only want to handle go to definition for constants defined in gems, as an
# additional behavior on top of jumping to RBIs. Sorbet can already handle go to definition for all constants
Expand Down
6 changes: 3 additions & 3 deletions lib/ruby_lsp/requests/document_highlight.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class DocumentHighlight < Listener
ResponseType = type_member { { fixed: T::Array[Interface::DocumentHighlight] } }

sig { override.returns(ResponseType) }
attr_reader :response
attr_reader :_response

sig do
params(
Expand All @@ -41,7 +41,7 @@ class DocumentHighlight < Listener
def initialize(target, parent, emitter, message_queue)
super(emitter, message_queue)

@response = T.let([], T::Array[Interface::DocumentHighlight])
@_response = T.let([], T::Array[Interface::DocumentHighlight])

return unless target && parent

Expand Down Expand Up @@ -83,7 +83,7 @@ def on_node(node)
sig { params(match: Support::HighlightTarget::HighlightMatch).void }
def add_highlight(match)
range = range_from_syntax_tree_node(match.node)
@response << Interface::DocumentHighlight.new(range: range, kind: match.type)
@_response << Interface::DocumentHighlight.new(range: range, kind: match.type)
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions lib/ruby_lsp/requests/document_link.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def gem_paths
end

sig { override.returns(ResponseType) }
attr_reader :response
attr_reader :_response

sig { params(uri: URI::Generic, emitter: EventEmitter, message_queue: Thread::Queue).void }
def initialize(uri, emitter, message_queue)
Expand All @@ -84,7 +84,7 @@ def initialize(uri, emitter, message_queue)
path = uri.to_standardized_path
version_match = path ? /(?<=%40)[\d.]+(?=\.rbi$)/.match(path) : nil
@gem_version = T.let(version_match && version_match[0], T.nilable(String))
@response = T.let([], T::Array[Interface::DocumentLink])
@_response = T.let([], T::Array[Interface::DocumentLink])

emitter.register(self, :on_comment)
end
Expand All @@ -99,7 +99,7 @@ def on_comment(node)
file_path = self.class.gem_paths.dig(uri.gem_name, gem_version, CGI.unescape(uri.path))
return if file_path.nil?

@response << Interface::DocumentLink.new(
@_response << Interface::DocumentLink.new(
range: range_from_syntax_tree_node(node),
target: "file://#{file_path}##{uri.line_number}",
tooltip: "Jump to #{file_path}##{uri.line_number}",
Expand Down
6 changes: 3 additions & 3 deletions lib/ruby_lsp/requests/document_symbol.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ def initialize
end

sig { override.returns(T::Array[Interface::DocumentSymbol]) }
attr_reader :response
attr_reader :_response

sig { params(emitter: EventEmitter, message_queue: Thread::Queue).void }
def initialize(emitter, message_queue)
@root = T.let(SymbolHierarchyRoot.new, SymbolHierarchyRoot)
@response = T.let(@root.children, T::Array[Interface::DocumentSymbol])
@_response = T.let(@root.children, T::Array[Interface::DocumentSymbol])
@stack = T.let(
[@root],
T::Array[T.any(SymbolHierarchyRoot, Interface::DocumentSymbol)],
Expand Down Expand Up @@ -83,7 +83,7 @@ def initialize_external_listener(extension)
# Merges responses from other listeners
sig { override.params(other: Listener[ResponseType]).returns(T.self_type) }
def merge_response!(other)
@response.concat(other.response)
@_response.concat(other.response)
self
end

Expand Down
12 changes: 6 additions & 6 deletions lib/ruby_lsp/requests/hover.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class Hover < ExtensibleListener
)

sig { override.returns(ResponseType) }
attr_reader :response
attr_reader :_response

sig do
params(
Expand All @@ -43,7 +43,7 @@ class Hover < ExtensibleListener
def initialize(index, nesting, emitter, message_queue)
@nesting = nesting
@index = index
@response = T.let(nil, ResponseType)
@_response = T.let(nil, ResponseType)

super(emitter, message_queue)
emitter.register(self, :on_const_path_ref, :on_const)
Expand All @@ -60,10 +60,10 @@ def merge_response!(other)
other_response = other.response
return self unless other_response

if @response.nil?
@response = other.response
if @_response.nil?
@_response = other.response
else
@response.contents.value << "\n\n" << other_response.contents.value
@_response.contents.value << "\n\n" << other_response.contents.value
end

self
Expand Down Expand Up @@ -113,7 +113,7 @@ def generate_hover(name, node)
kind: "markdown",
value: "#{title}\n\n**Definitions**: #{definitions.join(" | ")}\n\n#{content}",
)
@response = Interface::Hover.new(range: range_from_syntax_tree_node(node), contents: contents)
@_response = Interface::Hover.new(range: range_from_syntax_tree_node(node), contents: contents)
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions lib/ruby_lsp/requests/inlay_hints.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ class InlayHints < Listener
RESCUE_STRING_LENGTH = T.let("rescue".length, Integer)

sig { override.returns(ResponseType) }
attr_reader :response
attr_reader :_response

sig { params(range: T::Range[Integer], emitter: EventEmitter, message_queue: Thread::Queue).void }
def initialize(range, emitter, message_queue)
super(emitter, message_queue)

@response = T.let([], ResponseType)
@_response = T.let([], ResponseType)
@range = range

emitter.register(self, :on_rescue)
Expand All @@ -47,7 +47,7 @@ def on_rescue(node)
loc = node.location
return unless visible?(node, @range)

@response << Interface::InlayHint.new(
@_response << Interface::InlayHint.new(
position: { line: loc.start_line - 1, character: loc.start_column + RESCUE_STRING_LENGTH },
label: "StandardError",
padding_left: true,
Expand Down
6 changes: 3 additions & 3 deletions lib/ruby_lsp/requests/path_completion.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ class PathCompletion < Listener
ResponseType = type_member { { fixed: T::Array[Interface::CompletionItem] } }

sig { override.returns(ResponseType) }
attr_reader :response
attr_reader :_response

sig { params(emitter: EventEmitter, message_queue: Thread::Queue).void }
def initialize(emitter, message_queue)
super
@response = T.let([], ResponseType)
@_response = T.let([], ResponseType)
@tree = T.let(Support::PrefixTree.new(collect_load_path_files), Support::PrefixTree)

emitter.register(self, :on_tstring_content)
Expand All @@ -34,7 +34,7 @@ def initialize(emitter, message_queue)
sig { params(node: SyntaxTree::TStringContent).void }
def on_tstring_content(node)
@tree.search(node.value).sort.each do |path|
@response << build_completion(path, node)
@_response << build_completion(path, node)
end
end

Expand Down
8 changes: 4 additions & 4 deletions lib/ruby_lsp/requests/semantic_highlighting.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def initialize(location:, length:, type:, modifier:)
end

sig { override.returns(ResponseType) }
attr_reader :response
attr_reader :_response

sig do
params(
Expand All @@ -117,7 +117,7 @@ def initialize(location:, length:, type:, modifier:)
def initialize(emitter, message_queue, range: nil)
super(emitter, message_queue)

@response = T.let([], ResponseType)
@_response = T.let([], ResponseType)
@range = range
@special_methods = T.let(nil, T.nilable(T::Array[String]))

Expand Down Expand Up @@ -174,7 +174,7 @@ def on_const(node)
# When finding a module or class definition, we will have already pushed a token related to this constant. We
# need to look at the previous two tokens and if they match this locatione exactly, avoid pushing another token
# on top of the previous one
return if @response.last(2).any? { |token| token.location == node.location }
return if @_response.last(2).any? { |token| token.location == node.location }

add_token(node.location, :namespace)
end
Expand Down Expand Up @@ -327,7 +327,7 @@ def on_module(node)
def add_token(location, type, modifiers = [])
length = location.end_char - location.start_char
modifiers_indices = modifiers.filter_map { |modifier| TOKEN_MODIFIERS[modifier] }
@response.push(
@_response.push(
SemanticToken.new(
location: location,
length: length,
Expand Down
Loading

0 comments on commit 9a211db

Please sign in to comment.