diff --git a/Gemfile.lock b/Gemfile.lock
index 43184392c..91d32942a 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,11 +1,11 @@
PATH
remote: .
specs:
- ruby-lsp (0.10.1)
+ ruby-lsp (0.11.0)
language_server-protocol (~> 3.17.0)
sorbet-runtime
syntax_tree (>= 6.1.1, < 7)
- yarp (>= 0.11, < 0.12)
+ yarp (>= 0.12, < 0.13)
GEM
remote: https://rubygems.org/
@@ -17,7 +17,6 @@ GEM
debug (1.8.0)
irb (>= 1.5.0)
reline (>= 0.3.1)
- diff-lcs (1.5.0)
erubi (1.12.0)
io-console (0.6.0)
irb (1.8.0)
@@ -44,11 +43,9 @@ GEM
racc (1.7.1)
rainbow (3.1.1)
rake (13.0.6)
- rbi (0.0.17)
- ast
- parser (>= 3.0.0)
+ rbi (0.1.1)
sorbet-runtime (>= 0.5.9204)
- unparser (>= 0.5.6)
+ yarp (>= 0.11.0)
rdoc (6.5.0)
psych (>= 4.0.0)
regexp_parser (2.8.1)
@@ -79,42 +76,38 @@ GEM
rubocop (>= 0.90.0)
ruby-progressbar (1.13.0)
ruby2_keywords (0.0.5)
- sorbet (0.5.11013)
- sorbet-static (= 0.5.11013)
- sorbet-runtime (0.5.11013)
- sorbet-static (0.5.11013-universal-darwin)
- sorbet-static (0.5.11013-x86_64-linux)
- sorbet-static-and-runtime (0.5.11013)
- sorbet (= 0.5.11013)
- sorbet-runtime (= 0.5.11013)
- spoom (1.2.2)
+ sorbet (0.5.11026)
+ sorbet-static (= 0.5.11026)
+ sorbet-runtime (0.5.11026)
+ sorbet-static (0.5.11026-universal-darwin)
+ sorbet-static (0.5.11026-x86_64-linux)
+ sorbet-static-and-runtime (0.5.11026)
+ sorbet (= 0.5.11026)
+ sorbet-runtime (= 0.5.11026)
+ spoom (1.2.4)
erubi (>= 1.10.0)
- sorbet (>= 0.5.10187)
- sorbet-runtime (>= 0.5.9204)
+ sorbet-static-and-runtime (>= 0.5.10187)
syntax_tree (>= 6.1.1)
thor (>= 0.19.2)
stringio (3.0.7)
syntax_tree (6.1.1)
prettier_print (>= 1.2.0)
- tapioca (0.11.8)
+ tapioca (0.11.9)
bundler (>= 2.2.25)
netrc (>= 0.11.0)
parallel (>= 1.21.0)
- rbi (~> 0.0.0, >= 0.0.16)
+ rbi (~> 0.1.0, >= 0.1.0)
sorbet-static-and-runtime (>= 0.5.10187)
spoom (~> 1.2.0, >= 1.2.0)
thor (>= 1.2.0)
yard-sorbet
thor (1.2.2)
unicode-display_width (2.4.2)
- unparser (0.6.8)
- diff-lcs (~> 1.3)
- parser (>= 3.2.0)
yard (0.9.34)
yard-sorbet (0.8.1)
sorbet-runtime (>= 0.5)
yard (>= 0.9)
- yarp (0.11.0)
+ yarp (0.12.0)
PLATFORMS
arm64-darwin
diff --git a/Rakefile b/Rakefile
index 21cceda54..238bfa279 100644
--- a/Rakefile
+++ b/Rakefile
@@ -13,6 +13,7 @@ end
RDoc::Task.new do |rdoc|
rdoc.main = "README.md"
+ rdoc.title = "Ruby LSP documentation"
rdoc.rdoc_files.include("*.md", "lib/**/*.rb")
rdoc.rdoc_dir = "docs"
rdoc.markup = "markdown"
diff --git a/SERVER_EXTENSIONS.md b/SERVER_EXTENSIONS.md
index a99c1f2d5..8f3ff181c 100644
--- a/SERVER_EXTENSIONS.md
+++ b/SERVER_EXTENSIONS.md
@@ -115,11 +115,13 @@ module RubyLsp
sig do
override.params(
+ nesting: T::Array[String],
+ index: RubyIndexer::Index,
emitter: EventEmitter,
message_queue: Thread::Queue,
).returns(T.nilable(Listener[T.nilable(Interface::Hover)]))
end
- def create_hover_listener(emitter, message_queue)
+ def create_hover_listener(nesting, index emitter, message_queue)
# Use the listener factory methods to instantiate listeners with parameters sent by the LSP combined with any
# pre-computed information in the extension. These factory methods are invoked on every request
Hover.new(@config, emitter, message_queue)
@@ -148,18 +150,18 @@ module RubyLsp
@_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)
- emitter.register(self, :on_const)
+ # Register that this listener will handle `on_constant_read` events (i.e.: whenever a constant read is found in the code)
+ emitter.register(self, :on_constant_read)
end
# Listeners must define methods for each event they registered with the emitter. In this case, we have to define
# `on_const` to specify what this listener should do every time we find a constant
- sig { params(node: SyntaxTree::Const).void }
- def on_const(node)
+ sig { params(node: YARP::ConstantReadNode).void }
+ def on_constant_read(node)
# 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_node(node), contents: contents)
end
end
end
diff --git a/VERSION b/VERSION
index 571215736..d9df1bbc0 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.10.1
+0.11.0
diff --git a/lib/ruby_indexer/lib/ruby_indexer/configuration.rb b/lib/ruby_indexer/lib/ruby_indexer/configuration.rb
index 90ebb5fa0..28a085314 100644
--- a/lib/ruby_indexer/lib/ruby_indexer/configuration.rb
+++ b/lib/ruby_indexer/lib/ruby_indexer/configuration.rb
@@ -18,11 +18,7 @@ class Configuration
sig { void }
def initialize
- excluded_gem_names = Bundler.definition.dependencies.filter_map do |dependency|
- dependency.name if dependency.groups == [:development]
- end
-
- @excluded_gems = T.let(excluded_gem_names, T::Array[String])
+ @excluded_gems = T.let(initial_excluded_gems, T::Array[String])
@included_gems = T.let([], T::Array[String])
@excluded_patterns = T.let([File.join("**", "*_test.rb")], T::Array[String])
path = Bundler.settings["path"]
@@ -174,5 +170,39 @@ def apply_config(config)
@included_patterns.concat(config["included_patterns"]) if config["included_patterns"]
@excluded_magic_comments.concat(config["excluded_magic_comments"]) if config["excluded_magic_comments"]
end
+
+ sig { returns(T::Array[String]) }
+ def initial_excluded_gems
+ excluded, others = Bundler.definition.dependencies.partition do |dependency|
+ dependency.groups == [:development]
+ end
+
+ # When working on a gem, we need to make sure that its gemspec dependencies can't be excluded. This is necessary
+ # because Bundler doesn't assign groups to gemspec dependencies
+ this_gem = Bundler.definition.dependencies.find { |d| d.to_spec.full_gem_path == Dir.pwd }
+ others.concat(this_gem.to_spec.dependencies) if this_gem
+
+ excluded.each do |dependency|
+ next unless dependency.runtime?
+
+ dependency.to_spec.dependencies.each do |transitive_dependency|
+ # If the transitive dependency is included in other groups, skip it
+ next if others.any? { |d| d.name == transitive_dependency.name }
+
+ # If the transitive dependency is included as a transitive dependency of a gem outside of the development
+ # group, skip it
+ next if others.any? { |d| d.to_spec.dependencies.include?(transitive_dependency) }
+
+ excluded << transitive_dependency
+ end
+ rescue Gem::MissingSpecError
+ # If a gem is scoped only to some specific platform, then its dependencies may not be installed either, but they
+ # are still listed in dependencies. We can't index them because they are not installed for the platform, so we
+ # just ignore if they're missing
+ end
+
+ excluded.uniq!
+ excluded.map(&:name)
+ end
end
end
diff --git a/lib/ruby_indexer/lib/ruby_indexer/index.rb b/lib/ruby_indexer/lib/ruby_indexer/index.rb
index f467b197f..cf26b89a4 100644
--- a/lib/ruby_indexer/lib/ruby_indexer/index.rb
+++ b/lib/ruby_indexer/lib/ruby_indexer/index.rb
@@ -167,12 +167,16 @@ class Entry
sig { returns(T::Array[String]) }
attr_reader :comments
+ sig { returns(Symbol) }
+ attr_accessor :visibility
+
sig { params(name: String, file_path: String, location: YARP::Location, comments: T::Array[String]).void }
def initialize(name, file_path, location, comments)
@name = name
@file_path = file_path
@location = location
@comments = comments
+ @visibility = T.let(:public, Symbol)
end
sig { returns(String) }
diff --git a/lib/ruby_indexer/lib/ruby_indexer/visitor.rb b/lib/ruby_indexer/lib/ruby_indexer/visitor.rb
index 586e99ede..f3e709505 100644
--- a/lib/ruby_indexer/lib/ruby_indexer/visitor.rb
+++ b/lib/ruby_indexer/lib/ruby_indexer/visitor.rb
@@ -39,6 +39,9 @@ def visit(node)
add_constant(node)
when YARP::ConstantPathWriteNode, YARP::ConstantPathOrWriteNode
add_constant_with_path(node)
+ when YARP::CallNode
+ message = node.message
+ handle_private_constant(node) if message == "private_constant"
end
end
@@ -50,6 +53,31 @@ def visit_all(nodes)
private
+ sig { params(node: YARP::CallNode).void }
+ def handle_private_constant(node)
+ arguments = node.arguments&.arguments
+ return unless arguments
+
+ first_argument = arguments.first
+
+ name = case first_argument
+ when YARP::StringNode
+ first_argument.content
+ when YARP::SymbolNode
+ first_argument.value
+ end
+
+ return unless name
+
+ receiver = node.receiver
+ name = "#{receiver.slice}::#{name}" if receiver
+
+ # The private_constant method does not resolve the constant name. It always points to a constant that needs to
+ # exist in the current namespace
+ entries = @index[fully_qualify_name(name)]
+ entries&.each { |entry| entry.visibility = :private }
+ end
+
sig do
params(
node: T.any(YARP::ConstantWriteNode, YARP::ConstantOrWriteNode),
diff --git a/lib/ruby_indexer/test/classes_and_modules_test.rb b/lib/ruby_indexer/test/classes_and_modules_test.rb
index e3e3458ba..6079ebb42 100644
--- a/lib/ruby_indexer/test/classes_and_modules_test.rb
+++ b/lib/ruby_indexer/test/classes_and_modules_test.rb
@@ -216,5 +216,28 @@ class Bar; end
second_foo_entry = @index["Bar"][0]
assert_equal("This is a Bar comment", second_foo_entry.comments.join("\n"))
end
+
+ def test_private_class_and_module_indexing
+ index(<<~RUBY)
+ class A
+ class B; end
+ private_constant(:B)
+
+ module C; end
+ private_constant("C")
+
+ class D; end
+ end
+ RUBY
+
+ b_const = @index["A::B"].first
+ assert_equal(:private, b_const.visibility)
+
+ c_const = @index["A::C"].first
+ assert_equal(:private, c_const.visibility)
+
+ d_const = @index["A::D"].first
+ assert_equal(:public, d_const.visibility)
+ end
end
end
diff --git a/lib/ruby_indexer/test/configuration_test.rb b/lib/ruby_indexer/test/configuration_test.rb
index f0005f9d6..bcdc36289 100644
--- a/lib/ruby_indexer/test/configuration_test.rb
+++ b/lib/ruby_indexer/test/configuration_test.rb
@@ -15,6 +15,8 @@ def test_load_configuration_executes_configure_block
assert(indexables.none? { |indexable| indexable.full_path.include?("test/fixtures") })
assert(indexables.none? { |indexable| indexable.full_path.include?("minitest-reporters") })
+ assert(indexables.none? { |indexable| indexable.full_path.include?("ansi") })
+ assert(indexables.any? { |indexable| indexable.full_path.include?("sorbet-runtime") })
assert(indexables.none? { |indexable| indexable.full_path == __FILE__ })
end
diff --git a/lib/ruby_indexer/test/constant_test.rb b/lib/ruby_indexer/test/constant_test.rb
index 4f40658e9..796a9ca91 100644
--- a/lib/ruby_indexer/test/constant_test.rb
+++ b/lib/ruby_indexer/test/constant_test.rb
@@ -104,5 +104,82 @@ def test_variable_path_constants_are_ignored
assert_no_entry
end
+
+ def test_private_constant_indexing
+ index(<<~RUBY)
+ class A
+ B = 1
+ private_constant(:B)
+
+ C = 2
+ private_constant("C")
+
+ D = 1
+ end
+ RUBY
+
+ b_const = @index["A::B"].first
+ assert_equal(:private, b_const.visibility)
+
+ c_const = @index["A::C"].first
+ assert_equal(:private, c_const.visibility)
+
+ d_const = @index["A::D"].first
+ assert_equal(:public, d_const.visibility)
+ end
+
+ def test_marking_constants_as_private_reopening_namespaces
+ index(<<~RUBY)
+ module A
+ module B
+ CONST_A = 1
+ private_constant(:CONST_A)
+
+ CONST_B = 2
+ CONST_C = 3
+ end
+
+ module B
+ private_constant(:CONST_B)
+ end
+ end
+
+ module A
+ module B
+ private_constant(:CONST_C)
+ end
+ end
+ RUBY
+
+ a_const = @index["A::B::CONST_A"].first
+ assert_equal(:private, a_const.visibility)
+
+ b_const = @index["A::B::CONST_B"].first
+ assert_equal(:private, b_const.visibility)
+
+ c_const = @index["A::B::CONST_C"].first
+ assert_equal(:private, c_const.visibility)
+ end
+
+ def test_marking_constants_as_private_with_receiver
+ index(<<~RUBY)
+ module A
+ module B
+ CONST_A = 1
+ CONST_B = 2
+ end
+
+ B.private_constant(:CONST_A)
+ end
+
+ A::B.private_constant(:CONST_B)
+ RUBY
+
+ a_const = @index["A::B::CONST_A"].first
+ assert_equal(:private, a_const.visibility)
+
+ b_const = @index["A::B::CONST_B"].first
+ assert_equal(:private, b_const.visibility)
+ end
end
end
diff --git a/lib/ruby_lsp/document.rb b/lib/ruby_lsp/document.rb
index 064f0b331..4bd9e9120 100644
--- a/lib/ruby_lsp/document.rb
+++ b/lib/ruby_lsp/document.rb
@@ -9,8 +9,8 @@ class Document
RangeShape = T.type_alias { { start: PositionShape, end: PositionShape } }
EditShape = T.type_alias { { range: RangeShape, text: String } }
- sig { returns(T.nilable(SyntaxTree::Node)) }
- attr_reader :tree
+ sig { returns(YARP::ParseResult) }
+ attr_reader :parse_result
sig { returns(String) }
attr_reader :source
@@ -29,10 +29,17 @@ def initialize(source:, version:, uri:, encoding: Constant::PositionEncodingKind
@version = T.let(version, Integer)
@uri = T.let(uri, URI::Generic)
@unparsed_edits = T.let([], T::Array[EditShape])
- @syntax_error = T.let(false, T::Boolean)
- @tree = T.let(SyntaxTree.parse(@source), T.nilable(SyntaxTree::Node))
- rescue SyntaxTree::Parser::ParseError
- @syntax_error = true
+ @parse_result = T.let(YARP.parse(@source), YARP::ParseResult)
+ end
+
+ sig { returns(YARP::ProgramNode) }
+ def tree
+ @parse_result.value
+ end
+
+ sig { returns(T::Array[YARP::Comment]) }
+ def comments
+ @parse_result.comments
end
sig { params(other: Document).returns(T::Boolean) }
@@ -89,20 +96,12 @@ def parse
return if @unparsed_edits.empty?
@unparsed_edits.clear
- @tree = SyntaxTree.parse(@source)
- @syntax_error = false
- rescue SyntaxTree::Parser::ParseError
- @syntax_error = true
+ @parse_result = YARP.parse(@source)
end
sig { returns(T::Boolean) }
def syntax_error?
- @syntax_error
- end
-
- sig { returns(T::Boolean) }
- def parsed?
- !@tree.nil?
+ @parse_result.failure?
end
sig { returns(Scanner) }
@@ -113,27 +112,25 @@ def create_scanner
sig do
params(
position: PositionShape,
- node_types: T::Array[T.class_of(SyntaxTree::Node)],
- ).returns([T.nilable(SyntaxTree::Node), T.nilable(SyntaxTree::Node), T::Array[String]])
+ node_types: T::Array[T.class_of(YARP::Node)],
+ ).returns([T.nilable(YARP::Node), T.nilable(YARP::Node), T::Array[String]])
end
def locate_node(position, node_types: [])
- return [nil, nil, []] unless parsed?
-
- locate(T.must(@tree), create_scanner.find_char_position(position), node_types: node_types)
+ locate(@parse_result.value, create_scanner.find_char_position(position), node_types: node_types)
end
sig do
params(
- node: SyntaxTree::Node,
+ node: YARP::Node,
char_position: Integer,
- node_types: T::Array[T.class_of(SyntaxTree::Node)],
- ).returns([T.nilable(SyntaxTree::Node), T.nilable(SyntaxTree::Node), T::Array[String]])
+ node_types: T::Array[T.class_of(YARP::Node)],
+ ).returns([T.nilable(YARP::Node), T.nilable(YARP::Node), T::Array[String]])
end
def locate(node, char_position, node_types: [])
- queue = T.let(node.child_nodes.compact, T::Array[T.nilable(SyntaxTree::Node)])
+ queue = T.let(node.child_nodes.compact, T::Array[T.nilable(YARP::Node)])
closest = node
- parent = T.let(nil, T.nilable(SyntaxTree::Node))
- nesting = T.let([], T::Array[T.any(SyntaxTree::ClassDeclaration, SyntaxTree::ModuleDeclaration)])
+ parent = T.let(nil, T.nilable(YARP::Node))
+ nesting = T.let([], T::Array[T.any(YARP::ClassNode, YARP::ModuleNode)])
until queue.empty?
candidate = queue.shift
@@ -144,24 +141,24 @@ def locate(node, char_position, node_types: [])
# Add the next child_nodes to the queue to be processed. The order here is important! We want to move in the
# same order as the visiting mechanism, which means searching the child nodes before moving on to the next
# sibling
- queue.unshift(*candidate.child_nodes)
+ T.unsafe(queue).unshift(*candidate.child_nodes)
# Skip if the current node doesn't cover the desired position
loc = candidate.location
- next unless (loc.start_char...loc.end_char).cover?(char_position)
+ next unless (loc.start_offset...loc.end_offset).cover?(char_position)
# If the node's start character is already past the position, then we should've found the closest node
# already
- break if char_position < loc.start_char
+ break if char_position < loc.start_offset
# If the candidate starts after the end of the previous nesting level, then we've exited that nesting level and
# need to pop the stack
previous_level = nesting.last
- nesting.pop if previous_level && candidate.start_char > previous_level.end_char
+ nesting.pop if previous_level && loc.start_offset > previous_level.location.end_offset
# Keep track of the nesting where we found the target. This is used to determine the fully qualified name of the
# target when it is a constant
- if candidate.is_a?(SyntaxTree::ClassDeclaration) || candidate.is_a?(SyntaxTree::ModuleDeclaration)
+ if candidate.is_a?(YARP::ClassNode) || candidate.is_a?(YARP::ModuleNode)
nesting << candidate
end
@@ -170,13 +167,13 @@ def locate(node, char_position, node_types: [])
# If the current node is narrower than or equal to the previous closest node, then it is more precise
closest_loc = closest.location
- if loc.end_char - loc.start_char <= closest_loc.end_char - closest_loc.start_char
+ if loc.end_offset - loc.start_offset <= closest_loc.end_offset - closest_loc.start_offset
parent = closest
closest = candidate
end
end
- [closest, parent, nesting.map { |n| n.constant.constant.value }]
+ [closest, parent, nesting.map { |n| n.constant_path.location.slice }]
end
class Scanner
diff --git a/lib/ruby_lsp/event_emitter.rb b/lib/ruby_lsp/event_emitter.rb
index 6c2d49b90..cc4fdb6c2 100644
--- a/lib/ruby_lsp/event_emitter.rb
+++ b/lib/ruby_lsp/event_emitter.rb
@@ -2,7 +2,7 @@
# frozen_string_literal: true
module RubyLsp
- # EventEmitter is an intermediary between our requests and Syntax Tree visitors. It's used to visit the document's AST
+ # EventEmitter is an intermediary between our requests and YARP visitors. It's used to visit the document's AST
# and emit events that the requests can listen to for providing functionality. Usages:
#
# - For positional requests, locate the target node and use `emit_for_target` to fire events for each listener
@@ -18,9 +18,8 @@ module RubyLsp
# emitter.emit_for_target(target_node)
# listener.response
# ```
- class EventEmitter < SyntaxTree::Visitor
+ class EventEmitter < YARP::Visitor
extend T::Sig
- include SyntaxTree::WithScope
sig { void }
def initialize
@@ -35,154 +34,317 @@ def register(listener, *events)
# Emit events for a specific node. This is similar to the regular `visit` method, but avoids going deeper into the
# tree for performance
- sig { params(node: T.nilable(SyntaxTree::Node)).void }
+ sig { params(node: T.nilable(YARP::Node)).void }
def emit_for_target(node)
case node
- when SyntaxTree::Command
- @listeners[:on_command]&.each { |l| T.unsafe(l).on_command(node) }
- when SyntaxTree::CallNode
+ when YARP::CallNode
@listeners[:on_call]&.each { |l| T.unsafe(l).on_call(node) }
- when SyntaxTree::TStringContent
- @listeners[:on_tstring_content]&.each { |l| T.unsafe(l).on_tstring_content(node) }
- when SyntaxTree::ConstPathRef
- @listeners[:on_const_path_ref]&.each { |l| T.unsafe(l).on_const_path_ref(node) }
- when SyntaxTree::Const
- @listeners[:on_const]&.each { |l| T.unsafe(l).on_const(node) }
- when SyntaxTree::TopConstRef
- @listeners[:on_top_const_ref]&.each { |l| T.unsafe(l).on_top_const_ref(node) }
+ when YARP::ConstantPathNode
+ @listeners[:on_constant_path]&.each { |l| T.unsafe(l).on_constant_path(node) }
+ when YARP::StringNode
+ @listeners[:on_string]&.each { |l| T.unsafe(l).on_string(node) }
+ when YARP::ClassNode
+ @listeners[:on_class]&.each { |l| T.unsafe(l).on_class(node) }
+ when YARP::ModuleNode
+ @listeners[:on_module]&.each { |l| T.unsafe(l).on_module(node) }
+ when YARP::ConstantWriteNode
+ @listeners[:on_constant_write]&.each { |l| T.unsafe(l).on_constant_write(node) }
+ when YARP::ConstantReadNode
+ @listeners[:on_constant_read]&.each { |l| T.unsafe(l).on_constant_read(node) }
end
end
# Visit dispatchers are below. Notice that for nodes that create a new scope (e.g.: classes, modules, method defs)
# we need both an `on_*` and `after_*` event. This is because some requests must know when we exit the scope
- sig { override.params(node: T.nilable(SyntaxTree::Node)).void }
+ sig { override.params(node: T.nilable(YARP::Node)).void }
def visit(node)
@listeners[:on_node]&.each { |l| T.unsafe(l).on_node(node) }
super
end
- sig { override.params(node: SyntaxTree::ClassDeclaration).void }
- def visit_class(node)
+ sig { params(nodes: T::Array[T.nilable(YARP::Node)]).void }
+ def visit_all(nodes)
+ nodes.each { |node| visit(node) }
+ end
+
+ sig { override.params(node: YARP::ClassNode).void }
+ def visit_class_node(node)
@listeners[:on_class]&.each { |l| T.unsafe(l).on_class(node) }
super
@listeners[:after_class]&.each { |l| T.unsafe(l).after_class(node) }
end
- sig { override.params(node: SyntaxTree::ModuleDeclaration).void }
- def visit_module(node)
+ sig { override.params(node: YARP::ModuleNode).void }
+ def visit_module_node(node)
@listeners[:on_module]&.each { |l| T.unsafe(l).on_module(node) }
super
@listeners[:after_module]&.each { |l| T.unsafe(l).after_module(node) }
end
- sig { override.params(node: SyntaxTree::Command).void }
- def visit_command(node)
- @listeners[:on_command]&.each { |l| T.unsafe(l).on_command(node) }
+ sig { override.params(node: YARP::CallNode).void }
+ def visit_call_node(node)
+ @listeners[:on_call]&.each { |l| T.unsafe(l).on_call(node) }
super
- @listeners[:after_command]&.each { |l| T.unsafe(l).after_command(node) }
+ @listeners[:after_call]&.each { |l| T.unsafe(l).after_call(node) }
end
- sig { override.params(node: SyntaxTree::CommandCall).void }
- def visit_command_call(node)
- @listeners[:on_command_call]&.each { |l| T.unsafe(l).on_command_call(node) }
+ sig { override.params(node: YARP::InstanceVariableWriteNode).void }
+ def visit_instance_variable_write_node(node)
+ @listeners[:on_instance_variable_write]&.each { |l| T.unsafe(l).on_instance_variable_write(node) }
super
end
- sig { override.params(node: SyntaxTree::CallNode).void }
- def visit_call(node)
- @listeners[:on_call]&.each { |l| T.unsafe(l).on_call(node) }
+ sig { override.params(node: YARP::ClassVariableWriteNode).void }
+ def visit_class_variable_write_node(node)
+ @listeners[:on_class_variable_write]&.each { |l| T.unsafe(l).on_class_variable_write(node) }
super
- @listeners[:after_call]&.each { |l| T.unsafe(l).after_call(node) }
end
- sig { override.params(node: SyntaxTree::VCall).void }
- def visit_vcall(node)
- @listeners[:on_vcall]&.each { |l| T.unsafe(l).on_vcall(node) }
+ sig { override.params(node: YARP::DefNode).void }
+ def visit_def_node(node)
+ @listeners[:on_def]&.each { |l| T.unsafe(l).on_def(node) }
super
+ @listeners[:after_def]&.each { |l| T.unsafe(l).after_def(node) }
end
- sig { override.params(node: SyntaxTree::ConstPathField).void }
- def visit_const_path_field(node)
- @listeners[:on_const_path_field]&.each { |l| T.unsafe(l).on_const_path_field(node) }
+ sig { override.params(node: YARP::BlockNode).void }
+ def visit_block_node(node)
+ @listeners[:on_block]&.each { |l| T.unsafe(l).on_block(node) }
super
+ @listeners[:after_block]&.each { |l| T.unsafe(l).after_block(node) }
end
- sig { override.params(node: SyntaxTree::TopConstField).void }
- def visit_top_const_field(node)
- @listeners[:on_top_const_field]&.each { |l| T.unsafe(l).on_top_const_field(node) }
+ sig { override.params(node: YARP::SelfNode).void }
+ def visit_self_node(node)
+ @listeners[:on_self]&.each { |l| T.unsafe(l).on_self(node) }
super
end
- sig { override.params(node: SyntaxTree::DefNode).void }
- def visit_def(node)
- @listeners[:on_def]&.each { |l| T.unsafe(l).on_def(node) }
+ sig { override.params(node: YARP::RescueNode).void }
+ def visit_rescue_node(node)
+ @listeners[:on_rescue]&.each { |l| T.unsafe(l).on_rescue(node) }
super
- @listeners[:after_def]&.each { |l| T.unsafe(l).after_def(node) }
end
- sig { override.params(node: SyntaxTree::VarField).void }
- def visit_var_field(node)
- @listeners[:on_var_field]&.each { |l| T.unsafe(l).on_var_field(node) }
+ sig { override.params(node: YARP::BlockParameterNode).void }
+ def visit_block_parameter_node(node)
+ @listeners[:on_block_parameter]&.each { |l| T.unsafe(l).on_block_parameter(node) }
super
end
- sig { override.params(node: SyntaxTree::Comment).void }
- def visit_comment(node)
- @listeners[:on_comment]&.each { |l| T.unsafe(l).on_comment(node) }
+ sig { override.params(node: YARP::KeywordParameterNode).void }
+ def visit_keyword_parameter_node(node)
+ @listeners[:on_keyword_parameter]&.each { |l| T.unsafe(l).on_keyword_parameter(node) }
super
end
- sig { override.params(node: SyntaxTree::Rescue).void }
- def visit_rescue(node)
- @listeners[:on_rescue]&.each { |l| T.unsafe(l).on_rescue(node) }
+ sig { override.params(node: YARP::KeywordRestParameterNode).void }
+ def visit_keyword_rest_parameter_node(node)
+ @listeners[:on_keyword_rest_parameter]&.each { |l| T.unsafe(l).on_keyword_rest_parameter(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::OptionalParameterNode).void }
+ def visit_optional_parameter_node(node)
+ @listeners[:on_optional_parameter]&.each { |l| T.unsafe(l).on_optional_parameter(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::RequiredParameterNode).void }
+ def visit_required_parameter_node(node)
+ @listeners[:on_required_parameter]&.each { |l| T.unsafe(l).on_required_parameter(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::RestParameterNode).void }
+ def visit_rest_parameter_node(node)
+ @listeners[:on_rest_parameter]&.each { |l| T.unsafe(l).on_rest_parameter(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::ConstantReadNode).void }
+ def visit_constant_read_node(node)
+ @listeners[:on_constant_read]&.each { |l| T.unsafe(l).on_constant_read(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::ConstantPathNode).void }
+ def visit_constant_path_node(node)
+ @listeners[:on_constant_path]&.each { |l| T.unsafe(l).on_constant_path(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::ConstantPathWriteNode).void }
+ def visit_constant_path_write_node(node)
+ @listeners[:on_constant_path_write]&.each { |l| T.unsafe(l).on_constant_path_write(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::ConstantWriteNode).void }
+ def visit_constant_write_node(node)
+ @listeners[:on_constant_write]&.each { |l| T.unsafe(l).on_constant_write(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::ConstantAndWriteNode).void }
+ def visit_constant_and_write_node(node)
+ @listeners[:on_constant_and_write]&.each { |l| T.unsafe(l).on_constant_and_write(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::ConstantOperatorWriteNode).void }
+ def visit_constant_operator_write_node(node)
+ @listeners[:on_constant_operator_write]&.each { |l| T.unsafe(l).on_constant_operator_write(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::ConstantOrWriteNode).void }
+ def visit_constant_or_write_node(node)
+ @listeners[:on_constant_or_write]&.each { |l| T.unsafe(l).on_constant_or_write(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::ConstantTargetNode).void }
+ def visit_constant_target_node(node)
+ @listeners[:on_constant_target]&.each { |l| T.unsafe(l).on_constant_target(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::LocalVariableWriteNode).void }
+ def visit_local_variable_write_node(node)
+ @listeners[:on_local_variable_write]&.each { |l| T.unsafe(l).on_local_variable_write(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::LocalVariableReadNode).void }
+ def visit_local_variable_read_node(node)
+ @listeners[:on_local_variable_read]&.each { |l| T.unsafe(l).on_local_variable_read(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::LocalVariableAndWriteNode).void }
+ def visit_local_variable_and_write_node(node)
+ @listeners[:on_local_variable_and_write]&.each { |l| T.unsafe(l).on_local_variable_and_write(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::LocalVariableOperatorWriteNode).void }
+ def visit_local_variable_operator_write_node(node)
+ @listeners[:on_local_variable_operator_write]&.each { |l| T.unsafe(l).on_local_variable_operator_write(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::LocalVariableOrWriteNode).void }
+ def visit_local_variable_or_write_node(node)
+ @listeners[:on_local_variable_or_write]&.each { |l| T.unsafe(l).on_local_variable_or_write(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::LocalVariableTargetNode).void }
+ def visit_local_variable_target_node(node)
+ @listeners[:on_local_variable_target]&.each { |l| T.unsafe(l).on_local_variable_target(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::BlockLocalVariableNode).void }
+ def visit_block_local_variable_node(node)
+ @listeners[:on_block_local_variable]&.each { |l| T.unsafe(l).on_block_local_variable(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::IfNode).void }
+ def visit_if_node(node)
+ @listeners[:on_if]&.each { |l| T.unsafe(l).on_if(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::InNode).void }
+ def visit_in_node(node)
+ @listeners[:on_in]&.each { |l| T.unsafe(l).on_in(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::WhenNode).void }
+ def visit_when_node(node)
+ @listeners[:on_when]&.each { |l| T.unsafe(l).on_when(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::InterpolatedStringNode).void }
+ def visit_interpolated_string_node(node)
+ @listeners[:on_interpolated_string]&.each { |l| T.unsafe(l).on_interpolated_string(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::ArrayNode).void }
+ def visit_array_node(node)
+ @listeners[:on_array]&.each { |l| T.unsafe(l).on_array(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::CaseNode).void }
+ def visit_case_node(node)
+ @listeners[:on_case]&.each { |l| T.unsafe(l).on_case(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::ForNode).void }
+ def visit_for_node(node)
+ @listeners[:on_for]&.each { |l| T.unsafe(l).on_for(node) }
+ super
+ end
+
+ sig { override.params(node: YARP::HashNode).void }
+ def visit_hash_node(node)
+ @listeners[:on_hash]&.each { |l| T.unsafe(l).on_hash(node) }
super
end
- sig { override.params(node: SyntaxTree::Kw).void }
- def visit_kw(node)
- @listeners[:on_kw]&.each { |l| T.unsafe(l).on_kw(node) }
+ sig { override.params(node: YARP::SingletonClassNode).void }
+ def visit_singleton_class_node(node)
+ @listeners[:on_singleton_class]&.each { |l| T.unsafe(l).on_singleton_class(node) }
super
end
- sig { override.params(node: SyntaxTree::Params).void }
- def visit_params(node)
- @listeners[:on_params]&.each { |l| T.unsafe(l).on_params(node) }
+ sig { override.params(node: YARP::UnlessNode).void }
+ def visit_unless_node(node)
+ @listeners[:on_unless]&.each { |l| T.unsafe(l).on_unless(node) }
super
end
- sig { override.params(node: SyntaxTree::Field).void }
- def visit_field(node)
- @listeners[:on_field]&.each { |l| T.unsafe(l).on_field(node) }
+ sig { override.params(node: YARP::UntilNode).void }
+ def visit_until_node(node)
+ @listeners[:on_until]&.each { |l| T.unsafe(l).on_until(node) }
super
end
- sig { override.params(node: SyntaxTree::VarRef).void }
- def visit_var_ref(node)
- @listeners[:on_var_ref]&.each { |l| T.unsafe(l).on_var_ref(node) }
+ sig { override.params(node: YARP::WhileNode).void }
+ def visit_while_node(node)
+ @listeners[:on_while]&.each { |l| T.unsafe(l).on_while(node) }
super
end
- sig { override.params(node: SyntaxTree::BlockVar).void }
- def visit_block_var(node)
- @listeners[:on_block_var]&.each { |l| T.unsafe(l).on_block_var(node) }
+ sig { override.params(node: YARP::ElseNode).void }
+ def visit_else_node(node)
+ @listeners[:on_else]&.each { |l| T.unsafe(l).on_else(node) }
super
end
- sig { override.params(node: SyntaxTree::LambdaVar).void }
- def visit_lambda_var(node)
- @listeners[:on_lambda_var]&.each { |l| T.unsafe(l).on_lambda_var(node) }
+ sig { override.params(node: YARP::EnsureNode).void }
+ def visit_ensure_node(node)
+ @listeners[:on_ensure]&.each { |l| T.unsafe(l).on_ensure(node) }
super
end
- sig { override.params(node: SyntaxTree::Binary).void }
- def visit_binary(node)
+ sig { override.params(node: YARP::BeginNode).void }
+ def visit_begin_node(node)
+ @listeners[:on_begin]&.each { |l| T.unsafe(l).on_begin(node) }
super
- @listeners[:after_binary]&.each { |l| T.unsafe(l).after_binary(node) }
end
- sig { override.params(node: SyntaxTree::Const).void }
- def visit_const(node)
- @listeners[:on_const]&.each { |l| T.unsafe(l).on_const(node) }
+ sig { override.params(node: YARP::StringConcatNode).void }
+ def visit_string_concat_node(node)
+ @listeners[:on_string_concat]&.each { |l| T.unsafe(l).on_string_concat(node) }
super
end
end
diff --git a/lib/ruby_lsp/executor.rb b/lib/ruby_lsp/executor.rb
index fc11036c1..69961094e 100644
--- a/lib/ruby_lsp/executor.rb
+++ b/lib/ruby_lsp/executor.rb
@@ -82,12 +82,10 @@ def run(request)
request.dig(:params, :contentChanges),
request.dig(:params, :textDocument, :version),
)
- when "textDocument/foldingRange"
- folding_range(uri)
when "textDocument/selectionRange"
selection_range(uri, request.dig(:params, :positions))
when "textDocument/documentSymbol", "textDocument/documentLink", "textDocument/codeLens",
- "textDocument/semanticTokens/full"
+ "textDocument/semanticTokens/full", "textDocument/foldingRange"
document = @store.get(uri)
# If the response has already been cached by another request, return it
@@ -96,15 +94,17 @@ def run(request)
# Run listeners for the document
emitter = EventEmitter.new
+ folding_range = Requests::FoldingRanges.new(document.parse_result.comments, emitter, @message_queue)
document_symbol = Requests::DocumentSymbol.new(emitter, @message_queue)
- document_link = Requests::DocumentLink.new(uri, emitter, @message_queue)
- code_lens = Requests::CodeLens.new(uri, emitter, @message_queue, @test_library)
+ document_link = Requests::DocumentLink.new(uri, document.comments, emitter, @message_queue)
+ code_lens = Requests::CodeLens.new(uri, @test_library, emitter, @message_queue)
semantic_highlighting = Requests::SemanticHighlighting.new(emitter, @message_queue)
- emitter.visit(document.tree) if document.parsed?
+ emitter.visit(document.tree)
# 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/foldingRange", folding_range.response)
document.cache_set("textDocument/documentSymbol", document_symbol.response)
document.cache_set("textDocument/documentLink", document_link.response)
document.cache_set("textDocument/codeLens", code_lens.response)
@@ -246,14 +246,12 @@ def show_syntax_tree(uri, range)
end
def definition(uri, position)
document = @store.get(uri)
- return if document.syntax_error?
-
target, parent, nesting = document.locate_node(
position,
- node_types: [SyntaxTree::Command, SyntaxTree::Const, SyntaxTree::ConstPathRef],
+ node_types: [YARP::CallNode, YARP::ConstantReadNode, YARP::ConstantPathNode],
)
- target = parent if target.is_a?(SyntaxTree::Const) && parent.is_a?(SyntaxTree::ConstPathRef)
+ target = parent if target.is_a?(YARP::ConstantReadNode) && parent.is_a?(YARP::ConstantPathNode)
emitter = EventEmitter.new
base_listener = Requests::Definition.new(uri, nesting, @index, emitter, @message_queue)
@@ -261,13 +259,6 @@ def definition(uri, position)
base_listener.response
end
- sig { params(uri: URI::Generic).returns(T::Array[Interface::FoldingRange]) }
- def folding_range(uri)
- @store.cache_fetch(uri, "textDocument/foldingRange") do |document|
- Requests::FoldingRanges.new(document).run
- end
- end
-
sig do
params(
uri: URI::Generic,
@@ -276,8 +267,6 @@ def folding_range(uri)
end
def hover(uri, position)
document = @store.get(uri)
- return if document.syntax_error?
-
target, parent, nesting = document.locate_node(
position,
node_types: Requests::Hover::ALLOWED_TARGETS,
@@ -285,7 +274,7 @@ def hover(uri, position)
if (Requests::Hover::ALLOWED_TARGETS.include?(parent.class) &&
!Requests::Hover::ALLOWED_TARGETS.include?(target.class)) ||
- (parent.is_a?(SyntaxTree::ConstPathRef) && target.is_a?(SyntaxTree::Const))
+ (parent.is_a?(YARP::ConstantPathNode) && target.is_a?(YARP::ConstantReadNode))
target = parent
end
@@ -371,7 +360,6 @@ def on_type_formatting(uri, position, character)
end
def document_highlight(uri, position)
document = @store.get(uri)
- return if document.syntax_error?
target, parent = document.locate_node(position)
emitter = EventEmitter.new
@@ -383,7 +371,6 @@ def document_highlight(uri, position)
sig { params(uri: URI::Generic, range: Document::RangeShape).returns(T.nilable(T::Array[Interface::InlayHint])) }
def inlay_hint(uri, range)
document = @store.get(uri)
- return if document.syntax_error?
start_line = range.dig(:start, :line)
end_line = range.dig(:end, :line)
@@ -443,7 +430,7 @@ def diagnostic(uri)
Requests::Diagnostics.new(document).run
end
- Interface::FullDocumentDiagnosticReport.new(kind: "full", items: response.map(&:to_lsp_diagnostic)) if response
+ Interface::FullDocumentDiagnosticReport.new(kind: "full", items: response) if response
end
sig { params(uri: URI::Generic, range: Document::RangeShape).returns(Interface::SemanticTokens) }
@@ -458,7 +445,7 @@ def semantic_tokens_range(uri, range)
@message_queue,
range: start_line..end_line,
)
- emitter.visit(document.tree) if document.parsed?
+ emitter.visit(document.tree)
Requests::Support::SemanticTokenEncoder.new.encode(listener.response)
end
@@ -471,7 +458,6 @@ def semantic_tokens_range(uri, range)
end
def completion(uri, position)
document = @store.get(uri)
- return unless document.parsed?
char_position = document.create_scanner.find_char_position(position)
@@ -480,35 +466,29 @@ def completion(uri, position)
# the node, as it could not be a constant
target_node_types = if ("A".."Z").cover?(document.source[char_position - 1])
char_position -= 1
- [SyntaxTree::Const, SyntaxTree::ConstPathRef, SyntaxTree::TopConstRef]
+ [YARP::ConstantReadNode, YARP::ConstantPathNode]
else
- [SyntaxTree::Command, SyntaxTree::CommandCall, SyntaxTree::CallNode]
+ [YARP::CallNode]
end
- matched, parent, nesting = document.locate(T.must(document.tree), char_position, node_types: target_node_types)
+ matched, parent, nesting = document.locate(document.tree, char_position, node_types: target_node_types)
return unless matched && parent
target = case matched
- when SyntaxTree::Command, SyntaxTree::CallNode, SyntaxTree::CommandCall
+ when YARP::CallNode
message = matched.message
- return if message.is_a?(Symbol)
- return unless message.value == "require"
-
- args = matched.arguments
- args = args.arguments if args.is_a?(SyntaxTree::ArgParen)
- return if args.nil? || args.is_a?(SyntaxTree::ArgsForward)
+ return unless message == "require"
- argument = args.parts.first
- return unless argument.is_a?(SyntaxTree::StringLiteral)
+ args = matched.arguments&.arguments
+ return if args.nil? || args.is_a?(YARP::ForwardingArgumentsNode)
- path_node = argument.parts.first
- return unless path_node.is_a?(SyntaxTree::TStringContent)
- return unless (path_node.location.start_char..path_node.location.end_char).cover?(char_position)
+ argument = args.first
+ return unless argument.is_a?(YARP::StringNode)
+ return unless (argument.location.start_offset..argument.location.end_offset).cover?(char_position)
- path_node
- when SyntaxTree::Const, SyntaxTree::ConstPathRef
- if (parent.is_a?(SyntaxTree::ConstPathRef) || parent.is_a?(SyntaxTree::TopConstRef)) &&
- matched.is_a?(SyntaxTree::Const)
+ argument
+ when YARP::ConstantReadNode, YARP::ConstantPathNode
+ if parent.is_a?(YARP::ConstantPathNode) && matched.is_a?(YARP::ConstantReadNode)
parent
else
matched
diff --git a/lib/ruby_lsp/extension.rb b/lib/ruby_lsp/extension.rb
index ac539efae..4d82ecb78 100644
--- a/lib/ruby_lsp/extension.rb
+++ b/lib/ruby_lsp/extension.rb
@@ -119,11 +119,13 @@ def create_code_lens_listener(uri, emitter, message_queue); end
# Creates a new Hover listener. This method is invoked on every Hover request
sig do
overridable.params(
+ nesting: T::Array[String],
+ index: RubyIndexer::Index,
emitter: EventEmitter,
message_queue: Thread::Queue,
).returns(T.nilable(Listener[T.nilable(Interface::Hover)]))
end
- def create_hover_listener(emitter, message_queue); end
+ def create_hover_listener(nesting, index, emitter, message_queue); end
# Creates a new DocumentSymbol listener. This method is invoked on every DocumentSymbol request
sig do
diff --git a/lib/ruby_lsp/internal.rb b/lib/ruby_lsp/internal.rb
index d79e6866d..b54b96f8d 100644
--- a/lib/ruby_lsp/internal.rb
+++ b/lib/ruby_lsp/internal.rb
@@ -14,6 +14,7 @@
require "ruby_indexer/ruby_indexer"
require "core_ext/uri"
require "ruby_lsp/utils"
+require "ruby_lsp/parameter_scope"
require "ruby_lsp/server"
require "ruby_lsp/executor"
require "ruby_lsp/event_emitter"
diff --git a/lib/ruby_lsp/parameter_scope.rb b/lib/ruby_lsp/parameter_scope.rb
new file mode 100644
index 000000000..45d928734
--- /dev/null
+++ b/lib/ruby_lsp/parameter_scope.rb
@@ -0,0 +1,33 @@
+# typed: strict
+# frozen_string_literal: true
+
+module RubyLsp
+ class ParameterScope
+ extend T::Sig
+
+ sig { returns(T.nilable(ParameterScope)) }
+ attr_reader :parent
+
+ sig { params(parent: T.nilable(ParameterScope)).void }
+ def initialize(parent = nil)
+ @parent = parent
+ @parameters = T.let(Set.new, T::Set[Symbol])
+ end
+
+ sig { params(name: T.any(String, Symbol)).void }
+ def <<(name)
+ @parameters << name.to_sym
+ end
+
+ sig { params(name: T.any(Symbol, String)).returns(Symbol) }
+ def type_for(name)
+ parameter?(name) ? :parameter : :variable
+ end
+
+ sig { params(name: T.any(Symbol, String)).returns(T::Boolean) }
+ def parameter?(name)
+ sym = name.to_sym
+ @parameters.include?(sym) || (!@parent.nil? && @parent.parameter?(sym))
+ end
+ end
+end
diff --git a/lib/ruby_lsp/requests/base_request.rb b/lib/ruby_lsp/requests/base_request.rb
index 6fffe211d..745e3427b 100644
--- a/lib/ruby_lsp/requests/base_request.rb
+++ b/lib/ruby_lsp/requests/base_request.rb
@@ -4,7 +4,7 @@
module RubyLsp
module Requests
# :nodoc:
- class BaseRequest < SyntaxTree::Visitor
+ class BaseRequest < YARP::Visitor
extend T::Sig
extend T::Helpers
include Support::Common
@@ -20,10 +20,10 @@ def initialize(document)
sig { abstract.returns(Object) }
def run; end
- # Syntax Tree implements `visit_all` using `map` instead of `each` for users who want to use the pattern
+ # YARP implements `visit_all` using `map` instead of `each` for users who want to use the pattern
# `result = visitor.visit(tree)`. However, we don't use that pattern and should avoid producing a new array for
# every single node visited
- sig { params(nodes: T::Array[T.nilable(SyntaxTree::Node)]).void }
+ sig { params(nodes: T::Array[T.nilable(YARP::Node)]).void }
def visit_all(nodes)
nodes.each { |node| visit(node) }
end
diff --git a/lib/ruby_lsp/requests/code_action_resolve.rb b/lib/ruby_lsp/requests/code_action_resolve.rb
index 58a3299ac..757e04f89 100644
--- a/lib/ruby_lsp/requests/code_action_resolve.rb
+++ b/lib/ruby_lsp/requests/code_action_resolve.rb
@@ -46,8 +46,6 @@ def run
source_range = @code_action.dig(:data, :range)
return Error::EmptySelection if source_range[:start] == source_range[:end]
- return Error::InvalidTargetRange if @document.syntax_error?
-
scanner = @document.create_scanner
start_index = scanner.find_char_position(source_range[:start])
end_index = scanner.find_char_position(source_range[:end])
@@ -55,26 +53,23 @@ def run
# Find the closest statements node, so that we place the refactor in a valid position
closest_statements, parent_statements = @document
- .locate(T.must(@document.tree), start_index, node_types: [SyntaxTree::Statements])
+ .locate(@document.tree, start_index, node_types: [YARP::StatementsNode, YARP::BlockNode])
+
return Error::InvalidTargetRange if closest_statements.nil?
# Find the node with the end line closest to the requested position, so that we can place the refactor
# immediately after that closest node
- closest_node = closest_statements.child_nodes.compact.min_by do |node|
+ closest_node = T.must(closest_statements.child_nodes.compact.min_by do |node|
distance = source_range.dig(:start, :line) - (node.location.end_line - 1)
distance <= 0 ? Float::INFINITY : distance
- end
+ end)
- # Find the parent expression of the closest node
- parent_expression = parent_statements.child_nodes.compact.find do |node|
- loc = node.location
- loc.start_line - 1 <= source_range.dig(:start, :line) && loc.end_line - 1 >= source_range.dig(:end, :line)
- end if parent_statements
+ return Error::InvalidTargetRange if closest_node.is_a?(YARP::MissingNode)
closest_node_loc = closest_node.location
# If the parent expression is a single line block, then we have to extract it inside of the oneline block
- if parent_expression.is_a?(SyntaxTree::MethodAddBlock) &&
- parent_expression.location.start_line == parent_expression.location.end_line
+ if parent_statements.is_a?(YARP::BlockNode) &&
+ parent_statements.location.start_line == parent_statements.location.end_line
variable_source = " #{NEW_VARIABLE_NAME} = #{extracted_source};"
character = source_range.dig(:start, :character) - 1
@@ -105,7 +100,10 @@ def run
end: { line: target_line, character: indentation },
}
- variable_source = if T.must(lines[target_line]).strip.empty?
+ line = lines[target_line]
+ return Error::InvalidTargetRange unless line
+
+ variable_source = if line.strip.empty?
"\n#{" " * indentation}#{NEW_VARIABLE_NAME} = #{extracted_source}"
else
"#{NEW_VARIABLE_NAME} = #{extracted_source}\n#{" " * indentation}"
diff --git a/lib/ruby_lsp/requests/code_lens.rb b/lib/ruby_lsp/requests/code_lens.rb
index c8ec78f2f..b60c7b2db 100644
--- a/lib/ruby_lsp/requests/code_lens.rb
+++ b/lib/ruby_lsp/requests/code_lens.rb
@@ -31,8 +31,8 @@ class CodeLens < ExtensibleListener
sig { override.returns(ResponseType) }
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)
+ sig { params(uri: URI::Generic, test_library: String, emitter: EventEmitter, message_queue: Thread::Queue).void }
+ def initialize(uri, test_library, emitter, message_queue)
@uri = T.let(uri, URI::Generic)
@test_library = T.let(test_library, String)
@_response = T.let([], ResponseType)
@@ -48,18 +48,15 @@ def initialize(uri, emitter, message_queue, test_library)
:on_class,
:after_class,
:on_def,
- :on_command,
- :after_command,
:on_call,
:after_call,
- :on_vcall,
)
end
- sig { params(node: SyntaxTree::ClassDeclaration).void }
+ sig { params(node: YARP::ClassNode).void }
def on_class(node)
@visibility_stack.push(["public", "public"])
- class_name = node.constant.constant.value
+ class_name = node.constant_path.slice
@class_stack.push(class_name)
if @path && class_name.end_with?("Test")
@@ -72,20 +69,20 @@ def on_class(node)
end
end
- sig { params(node: SyntaxTree::ClassDeclaration).void }
+ sig { params(node: YARP::ClassNode).void }
def after_class(node)
@visibility_stack.pop
@class_stack.pop
end
- sig { params(node: SyntaxTree::DefNode).void }
+ sig { params(node: YARP::DefNode).void }
def on_def(node)
class_name = @class_stack.last
return unless class_name&.end_with?("Test")
visibility, _ = @visibility_stack.last
if visibility == "public"
- method_name = node.name.value
+ method_name = node.name.to_s
if @path && method_name.start_with?("test_")
add_test_code_lens(
node,
@@ -97,55 +94,41 @@ def on_def(node)
end
end
- sig { params(node: SyntaxTree::Command).void }
- def on_command(node)
- node_message = node.message.value
- if ACCESS_MODIFIERS.include?(node_message) && node.arguments.parts.any?
- visibility, _ = @visibility_stack.pop
- @visibility_stack.push([node_message, visibility])
- elsif @path&.include?("Gemfile") && node_message.include?("gem") && node.arguments.parts.any?
- remote = resolve_gem_remote(node)
- return unless remote
+ sig { params(node: YARP::CallNode).void }
+ def on_call(node)
+ name = node.name
+ arguments = node.arguments
+
+ # If we found `private` by itself or `private def foo`
+ if ACCESS_MODIFIERS.include?(name)
+ if arguments.nil?
+ @visibility_stack.pop
+ @visibility_stack.push([name, name])
+ elsif arguments.arguments.first.is_a?(YARP::DefNode)
+ visibility, _ = @visibility_stack.pop
+ @visibility_stack.push([name, visibility])
+ end
- add_open_gem_remote_code_lens(node, remote)
+ return
end
- end
- sig { params(node: SyntaxTree::Command).void }
- def after_command(node)
- _, prev_visibility = @visibility_stack.pop
- @visibility_stack.push([prev_visibility, prev_visibility])
- end
+ if @path&.include?("Gemfile") && name == "gem" && arguments
+ first_argument = arguments.arguments.first
+ return unless first_argument.is_a?(YARP::StringNode)
- sig { params(node: SyntaxTree::CallNode).void }
- def on_call(node)
- ident = node.message if node.message.is_a?(SyntaxTree::Ident)
+ remote = resolve_gem_remote(first_argument)
+ return unless remote
- if ident
- ident_value = T.cast(ident, SyntaxTree::Ident).value
- if ACCESS_MODIFIERS.include?(ident_value)
- visibility, _ = @visibility_stack.pop
- @visibility_stack.push([ident_value, visibility])
- end
+ add_open_gem_remote_code_lens(node, remote)
end
end
- sig { params(node: SyntaxTree::CallNode).void }
+ sig { params(node: YARP::CallNode).void }
def after_call(node)
_, prev_visibility = @visibility_stack.pop
@visibility_stack.push([prev_visibility, prev_visibility])
end
- sig { params(node: SyntaxTree::VCall).void }
- def on_vcall(node)
- vcall_value = node.value.value
-
- if ACCESS_MODIFIERS.include?(vcall_value)
- @visibility_stack.pop
- @visibility_stack.push([vcall_value, vcall_value])
- end
- end
-
sig { override.params(extension: RubyLsp::Extension).returns(T.nilable(Listener[ResponseType])) }
def initialize_external_listener(extension)
extension.create_code_lens_listener(@uri, @emitter, @message_queue)
@@ -159,7 +142,7 @@ def merge_response!(other)
private
- sig { params(node: SyntaxTree::Node, name: String, command: String, kind: Symbol).void }
+ sig { params(node: YARP::Node, name: String, command: String, kind: Symbol).void }
def add_test_code_lens(node, name:, command:, kind:)
# don't add code lenses if the test library is not supported or unknown
return unless SUPPORTED_TEST_LIBRARIES.include?(@test_library) && @path
@@ -201,15 +184,9 @@ def add_test_code_lens(node, name:, command:, kind:)
)
end
- sig { params(node: SyntaxTree::Command).returns(T.nilable(String)) }
- def resolve_gem_remote(node)
- gem_statement = node.arguments.parts.first
- return unless gem_statement.is_a?(SyntaxTree::StringLiteral)
-
- gem_name = gem_statement.parts.first
- return unless gem_name.is_a?(SyntaxTree::TStringContent)
-
- spec = Gem::Specification.stubs.find { |gem| gem.name == gem_name.value }&.to_spec
+ sig { params(gem_name: YARP::StringNode).returns(T.nilable(String)) }
+ def resolve_gem_remote(gem_name)
+ spec = Gem::Specification.stubs.find { |gem| gem.name == gem_name.content }&.to_spec
return if spec.nil?
[spec.homepage, spec.metadata["source_code_uri"]].compact.find do |page|
@@ -239,7 +216,7 @@ def generate_test_command(class_name:, method_name: nil)
command
end
- sig { params(node: SyntaxTree::Command, remote: String).void }
+ sig { params(node: YARP::CallNode, remote: String).void }
def add_open_gem_remote_code_lens(node, remote)
@_response << create_code_lens(
node,
diff --git a/lib/ruby_lsp/requests/completion.rb b/lib/ruby_lsp/requests/completion.rb
index be9291d39..e8525d546 100644
--- a/lib/ruby_lsp/requests/completion.rb
+++ b/lib/ruby_lsp/requests/completion.rb
@@ -40,22 +40,22 @@ def initialize(index, nesting, emitter, message_queue)
@index = index
@nesting = nesting
- emitter.register(self, :on_tstring_content, :on_const_path_ref, :on_const, :on_top_const_ref)
+ emitter.register(self, :on_string, :on_constant_path, :on_constant_read)
end
- sig { params(node: SyntaxTree::TStringContent).void }
- def on_tstring_content(node)
- @index.search_require_paths(node.value).map!(&:require_path).sort!.each do |path|
+ sig { params(node: YARP::StringNode).void }
+ def on_string(node)
+ @index.search_require_paths(node.content).map!(&:require_path).sort!.each do |path|
@_response << build_completion(T.must(path), node)
end
end
# Handle completion on regular constant references (e.g. `Bar`)
- sig { params(node: SyntaxTree::Const).void }
- def on_const(node)
+ sig { params(node: YARP::ConstantReadNode).void }
+ def on_constant_read(node)
return if DependencyDetector::HAS_TYPECHECKER
- name = node.value
+ name = node.slice
candidates = @index.prefix_search(name, @nesting)
candidates.each do |entries|
@_response << build_entry_completion(name, node, entries, top_level?(T.must(entries.first).name, candidates))
@@ -63,35 +63,38 @@ def on_const(node)
end
# Handle completion on namespaced constant references (e.g. `Foo::Bar`)
- sig { params(node: SyntaxTree::ConstPathRef).void }
- def on_const_path_ref(node)
+ sig { params(node: YARP::ConstantPathNode).void }
+ def on_constant_path(node)
return if DependencyDetector::HAS_TYPECHECKER
- name = full_constant_name(node)
- candidates = @index.prefix_search(name, @nesting)
- candidates.each do |entries|
- @_response << build_entry_completion(name, node, entries, top_level?(T.must(entries.first).name, candidates))
- end
- end
+ name = node.slice
- # Handle completion on top level constant references (e.g. `::Bar`)
- sig { params(node: SyntaxTree::TopConstRef).void }
- def on_top_const_ref(node)
- return if DependencyDetector::HAS_TYPECHECKER
+ top_level_reference = if name.start_with?("::")
+ name = name.delete_prefix("::")
+ true
+ else
+ false
+ end
- name = full_constant_name(node)
- candidates = @index.prefix_search(name, [])
- candidates.each { |entries| @_response << build_entry_completion(name, node, entries, true) }
+ candidates = @index.prefix_search(name, top_level_reference ? [] : @nesting)
+ candidates.each do |entries|
+ @_response << build_entry_completion(
+ name,
+ node,
+ entries,
+ top_level_reference || top_level?(T.must(entries.first).name, candidates),
+ )
+ end
end
private
- sig { params(label: String, node: SyntaxTree::TStringContent).returns(Interface::CompletionItem) }
+ sig { params(label: String, node: YARP::StringNode).returns(Interface::CompletionItem) }
def build_completion(label, node)
Interface::CompletionItem.new(
label: label,
text_edit: Interface::TextEdit.new(
- range: range_from_syntax_tree_node(node),
+ range: range_from_node(node),
new_text: label,
),
kind: Constant::CompletionItemKind::REFERENCE,
@@ -101,7 +104,7 @@ def build_completion(label, node)
sig do
params(
name: String,
- node: SyntaxTree::Node,
+ node: YARP::Node,
entries: T::Array[RubyIndexer::Index::Entry],
top_level: T::Boolean,
).returns(Interface::CompletionItem)
@@ -146,7 +149,7 @@ def build_entry_completion(name, node, entries, top_level)
label: first_entry.name,
filter_text: top_level ? "::#{first_entry.name}" : first_entry.name,
text_edit: Interface::TextEdit.new(
- range: range_from_syntax_tree_node(node),
+ range: range_from_node(node),
new_text: insertion_text,
),
kind: kind,
diff --git a/lib/ruby_lsp/requests/definition.rb b/lib/ruby_lsp/requests/definition.rb
index 33928bd9b..dad604ff6 100644
--- a/lib/ruby_lsp/requests/definition.rb
+++ b/lib/ruby_lsp/requests/definition.rb
@@ -43,7 +43,7 @@ def initialize(uri, nesting, index, emitter, message_queue)
super(emitter, message_queue)
- emitter.register(self, :on_command, :on_const, :on_const_path_ref)
+ emitter.register(self, :on_call, :on_constant_read, :on_constant_path)
end
sig { override.params(ext: Extension).returns(T.nilable(RubyLsp::Listener[ResponseType])) }
@@ -67,32 +67,21 @@ def merge_response!(other)
self
end
- sig { params(node: SyntaxTree::ConstPathRef).void }
- def on_const_path_ref(node)
- name = full_constant_name(node)
- find_in_index(name)
- end
-
- sig { params(node: SyntaxTree::Const).void }
- def on_const(node)
- find_in_index(node.value)
- end
-
- sig { params(node: SyntaxTree::Command).void }
- def on_command(node)
- message = node.message.value
+ sig { params(node: YARP::CallNode).void }
+ def on_call(node)
+ message = node.name
return unless message == "require" || message == "require_relative"
- argument = node.arguments.parts.first
- return unless argument.is_a?(SyntaxTree::StringLiteral)
+ arguments = node.arguments
+ return unless arguments
- string = argument.parts.first
- return unless string.is_a?(SyntaxTree::TStringContent)
+ argument = arguments.arguments.first
+ return unless argument.is_a?(YARP::StringNode)
case message
when "require"
- entry = @index.search_require_paths(string.value).find do |indexable_path|
- indexable_path.require_path == string.value
+ entry = @index.search_require_paths(argument.content).find do |indexable_path|
+ indexable_path.require_path == argument.content
end
if entry
@@ -107,7 +96,7 @@ def on_command(node)
)
end
when "require_relative"
- required_file = "#{string.value}.rb"
+ required_file = "#{argument.content}.rb"
path = @uri.to_standardized_path
current_folder = path ? Pathname.new(CGI.unescape(path)).dirname : Dir.pwd
candidate = File.expand_path(File.join(current_folder, required_file))
@@ -122,6 +111,16 @@ def on_command(node)
end
end
+ sig { params(node: YARP::ConstantPathNode).void }
+ def on_constant_path(node)
+ find_in_index(node.slice)
+ end
+
+ sig { params(node: YARP::ConstantReadNode).void }
+ def on_constant_read(node)
+ find_in_index(node.slice)
+ end
+
private
sig { params(value: String).void }
diff --git a/lib/ruby_lsp/requests/diagnostics.rb b/lib/ruby_lsp/requests/diagnostics.rb
index bde2298c6..dc523f430 100644
--- a/lib/ruby_lsp/requests/diagnostics.rb
+++ b/lib/ruby_lsp/requests/diagnostics.rb
@@ -28,10 +28,10 @@ def initialize(document)
@uri = T.let(document.uri, URI::Generic)
end
- sig { override.returns(T.nilable(T.all(T::Array[Support::RuboCopDiagnostic], Object))) }
+ sig { override.returns(T.nilable(T.all(T::Array[Interface::Diagnostic], Object))) }
def run
# Running RuboCop is slow, so to avoid excessive runs we only do so if the file is syntactically valid
- return if @document.syntax_error?
+ return syntax_error_diagnostics if @document.syntax_error?
return unless defined?(Support::RuboCopDiagnosticsRunner)
@@ -39,7 +39,30 @@ def run
path = @uri.to_standardized_path
return unless path.nil? || path.start_with?(T.must(WORKSPACE_URI.to_standardized_path))
- Support::RuboCopDiagnosticsRunner.instance.run(@uri, @document)
+ Support::RuboCopDiagnosticsRunner.instance.run(@uri, @document).map!(&:to_lsp_diagnostic)
+ end
+
+ private
+
+ sig { returns(T.nilable(T::Array[Interface::Diagnostic])) }
+ def syntax_error_diagnostics
+ @document.parse_result.errors.map do |error|
+ Interface::Diagnostic.new(
+ range: Interface::Range.new(
+ start: Interface::Position.new(
+ line: error.location.start_line - 1,
+ character: error.location.start_column,
+ ),
+ end: Interface::Position.new(
+ line: error.location.end_line - 1,
+ character: error.location.end_column,
+ ),
+ ),
+ message: error.message,
+ severity: Constant::DiagnosticSeverity::ERROR,
+ source: "YARP",
+ )
+ end
end
end
end
diff --git a/lib/ruby_lsp/requests/document_highlight.rb b/lib/ruby_lsp/requests/document_highlight.rb
index da25948f2..791ab5a09 100644
--- a/lib/ruby_lsp/requests/document_highlight.rb
+++ b/lib/ruby_lsp/requests/document_highlight.rb
@@ -32,8 +32,8 @@ class DocumentHighlight < Listener
sig do
params(
- target: T.nilable(SyntaxTree::Node),
- parent: T.nilable(SyntaxTree::Node),
+ target: T.nilable(YARP::Node),
+ parent: T.nilable(YARP::Node),
emitter: EventEmitter,
message_queue: Thread::Queue,
).void
@@ -47,11 +47,21 @@ def initialize(target, parent, emitter, message_queue)
highlight_target =
case target
- when *DIRECT_HIGHLIGHTS
+ when YARP::GlobalVariableReadNode, YARP::GlobalVariableAndWriteNode, YARP::GlobalVariableOperatorWriteNode,
+ YARP::GlobalVariableOrWriteNode, YARP::GlobalVariableTargetNode, YARP::GlobalVariableWriteNode,
+ YARP::InstanceVariableAndWriteNode, YARP::InstanceVariableOperatorWriteNode,
+ YARP::InstanceVariableOrWriteNode, YARP::InstanceVariableReadNode, YARP::InstanceVariableTargetNode,
+ YARP::InstanceVariableWriteNode, YARP::ConstantAndWriteNode, YARP::ConstantOperatorWriteNode,
+ YARP::ConstantOrWriteNode, YARP::ConstantPathAndWriteNode, YARP::ConstantPathNode,
+ YARP::ConstantPathOperatorWriteNode, YARP::ConstantPathOrWriteNode, YARP::ConstantPathTargetNode,
+ YARP::ConstantPathWriteNode, YARP::ConstantReadNode, YARP::ConstantTargetNode, YARP::ConstantWriteNode,
+ YARP::ClassVariableAndWriteNode, YARP::ClassVariableOperatorWriteNode, YARP::ClassVariableOrWriteNode,
+ YARP::ClassVariableReadNode, YARP::ClassVariableTargetNode, YARP::ClassVariableWriteNode,
+ YARP::LocalVariableAndWriteNode, YARP::LocalVariableOperatorWriteNode, YARP::LocalVariableOrWriteNode,
+ YARP::LocalVariableReadNode, YARP::LocalVariableTargetNode, YARP::LocalVariableWriteNode, YARP::CallNode,
+ YARP::BlockParameterNode, YARP::KeywordParameterNode, YARP::KeywordRestParameterNode,
+ YARP::OptionalParameterNode, YARP::RequiredParameterNode, YARP::RestParameterNode
Support::HighlightTarget.new(target)
- when SyntaxTree::Ident
- relevant_node = parent.is_a?(SyntaxTree::Params) ? target : parent
- Support::HighlightTarget.new(relevant_node)
end
@target = T.let(highlight_target, T.nilable(Support::HighlightTarget))
@@ -59,7 +69,7 @@ def initialize(target, parent, emitter, message_queue)
emitter.register(self, :on_node) if @target
end
- sig { params(node: T.nilable(SyntaxTree::Node)).void }
+ sig { params(node: T.nilable(YARP::Node)).void }
def on_node(node)
return if node.nil?
@@ -69,20 +79,9 @@ def on_node(node)
private
- DIRECT_HIGHLIGHTS = T.let(
- [
- SyntaxTree::GVar,
- SyntaxTree::IVar,
- SyntaxTree::Const,
- SyntaxTree::CVar,
- SyntaxTree::VarField,
- ],
- T::Array[T.class_of(SyntaxTree::Node)],
- )
-
sig { params(match: Support::HighlightTarget::HighlightMatch).void }
def add_highlight(match)
- range = range_from_syntax_tree_node(match.node)
+ range = range_from_location(match.location)
@_response << Interface::DocumentHighlight.new(range: range, kind: match.type)
end
end
diff --git a/lib/ruby_lsp/requests/document_link.rb b/lib/ruby_lsp/requests/document_link.rb
index 321747cee..c75b16ae6 100644
--- a/lib/ruby_lsp/requests/document_link.rb
+++ b/lib/ruby_lsp/requests/document_link.rb
@@ -75,8 +75,15 @@ def gem_paths
sig { override.returns(ResponseType) }
attr_reader :_response
- sig { params(uri: URI::Generic, emitter: EventEmitter, message_queue: Thread::Queue).void }
- def initialize(uri, emitter, message_queue)
+ sig do
+ params(
+ uri: URI::Generic,
+ comments: T::Array[YARP::Comment],
+ emitter: EventEmitter,
+ message_queue: Thread::Queue,
+ ).void
+ end
+ def initialize(uri, comments, emitter, message_queue)
super(emitter, message_queue)
# Match the version based on the version in the RBI file name. Notice that the `@` symbol is sanitized to `%40`
@@ -85,13 +92,49 @@ def initialize(uri, emitter, message_queue)
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])
+ @lines_to_comments = T.let(
+ comments.to_h do |comment|
+ [comment.location.end_line, comment]
+ end,
+ T::Hash[Integer, YARP::Comment],
+ )
- emitter.register(self, :on_comment)
+ emitter.register(self, :on_def, :on_class, :on_module, :on_constant_write, :on_constant_path_write)
end
- sig { params(node: SyntaxTree::Comment).void }
- def on_comment(node)
- match = node.value.match(%r{source://.*#\d+$})
+ sig { params(node: YARP::DefNode).void }
+ def on_def(node)
+ extract_document_link(node)
+ end
+
+ sig { params(node: YARP::ClassNode).void }
+ def on_class(node)
+ extract_document_link(node)
+ end
+
+ sig { params(node: YARP::ModuleNode).void }
+ def on_module(node)
+ extract_document_link(node)
+ end
+
+ sig { params(node: YARP::ConstantWriteNode).void }
+ def on_constant_write(node)
+ extract_document_link(node)
+ end
+
+ sig { params(node: YARP::ConstantPathWriteNode).void }
+ def on_constant_path_write(node)
+ extract_document_link(node)
+ end
+
+ private
+
+ sig { params(node: YARP::Node).void }
+ def extract_document_link(node)
+ comment = @lines_to_comments[node.location.start_line - 1]
+ return unless comment
+
+ match = comment.location.slice.match(%r{source://.*#\d+$})
return unless match
uri = T.cast(URI(T.must(match[0])), URI::Source)
@@ -102,14 +145,12 @@ def on_comment(node)
return if file_path.nil?
@_response << Interface::DocumentLink.new(
- range: range_from_syntax_tree_node(node),
+ range: range_from_location(comment.location),
target: "file://#{file_path}##{uri.line_number}",
tooltip: "Jump to #{file_path}##{uri.line_number}",
)
end
- private
-
# Try to figure out the gem version for a source:// link. The order of precedence is:
# 1. The version in the URI
# 2. The version in the RBI file name
diff --git a/lib/ruby_lsp/requests/document_symbol.rb b/lib/ruby_lsp/requests/document_symbol.rb
index e0cf36e3f..ec3f74253 100644
--- a/lib/ruby_lsp/requests/document_symbol.rb
+++ b/lib/ruby_lsp/requests/document_symbol.rb
@@ -64,14 +64,15 @@ def initialize(emitter, message_queue)
self,
:on_class,
:after_class,
- :on_command,
- :on_const_path_field,
+ :on_call,
+ :on_constant_path_write,
+ :on_constant_write,
:on_def,
:after_def,
:on_module,
:after_module,
- :on_top_const_field,
- :on_var_field,
+ :on_instance_variable_write,
+ :on_class_variable_write,
)
end
@@ -87,116 +88,122 @@ def merge_response!(other)
self
end
- sig { params(node: SyntaxTree::ClassDeclaration).void }
+ sig { params(node: YARP::ClassNode).void }
def on_class(node)
@stack << create_document_symbol(
- name: full_constant_name(node.constant),
+ name: node.constant_path.location.slice,
kind: Constant::SymbolKind::CLASS,
- range_node: node,
- selection_range_node: node.constant,
+ range_location: node.location,
+ selection_range_location: node.constant_path.location,
)
end
- sig { params(node: SyntaxTree::ClassDeclaration).void }
+ sig { params(node: YARP::ClassNode).void }
def after_class(node)
@stack.pop
end
- sig { params(node: SyntaxTree::Command).void }
- def on_command(node)
- return unless ATTR_ACCESSORS.include?(node.message.value)
+ sig { params(node: YARP::CallNode).void }
+ def on_call(node)
+ return unless ATTR_ACCESSORS.include?(node.name) && node.receiver.nil?
- node.arguments.parts.each do |argument|
- next unless argument.is_a?(SyntaxTree::SymbolLiteral)
+ arguments = node.arguments
+ return unless arguments
+
+ arguments.arguments.each do |argument|
+ next unless argument.is_a?(YARP::SymbolNode)
+
+ name = argument.value
+ next unless name
create_document_symbol(
- name: argument.value.value,
+ name: name,
kind: Constant::SymbolKind::FIELD,
- range_node: argument,
- selection_range_node: argument.value,
+ range_location: argument.location,
+ selection_range_location: T.must(argument.value_loc),
)
end
end
- sig { params(node: SyntaxTree::ConstPathField).void }
- def on_const_path_field(node)
+ sig { params(node: YARP::ConstantPathWriteNode).void }
+ def on_constant_path_write(node)
+ create_document_symbol(
+ name: node.target.location.slice,
+ kind: Constant::SymbolKind::CONSTANT,
+ range_location: node.location,
+ selection_range_location: node.target.location,
+ )
+ end
+
+ sig { params(node: YARP::ConstantWriteNode).void }
+ def on_constant_write(node)
create_document_symbol(
- name: node.constant.value,
+ name: node.name.to_s,
kind: Constant::SymbolKind::CONSTANT,
- range_node: node,
- selection_range_node: node.constant,
+ range_location: node.location,
+ selection_range_location: node.name_loc,
+ )
+ end
+
+ sig { params(node: YARP::DefNode).void }
+ def after_def(node)
+ @stack.pop
+ end
+
+ sig { params(node: YARP::ModuleNode).void }
+ def on_module(node)
+ @stack << create_document_symbol(
+ name: node.constant_path.location.slice,
+ kind: Constant::SymbolKind::MODULE,
+ range_location: node.location,
+ selection_range_location: node.constant_path.location,
)
end
- sig { params(node: SyntaxTree::DefNode).void }
+ sig { params(node: YARP::DefNode).void }
def on_def(node)
- target = node.target
+ receiver = node.receiver
- if target.is_a?(SyntaxTree::VarRef) && target.value.is_a?(SyntaxTree::Kw) && target.value.value == "self"
- name = "self.#{node.name.value}"
+ if receiver.is_a?(YARP::SelfNode)
+ name = "self.#{node.name}"
kind = Constant::SymbolKind::METHOD
else
- name = node.name.value
+ name = node.name.to_s
kind = name == "initialize" ? Constant::SymbolKind::CONSTRUCTOR : Constant::SymbolKind::METHOD
end
symbol = create_document_symbol(
name: name,
kind: kind,
- range_node: node,
- selection_range_node: node.name,
+ range_location: node.location,
+ selection_range_location: node.name_loc,
)
@stack << symbol
end
- sig { params(node: SyntaxTree::DefNode).void }
- def after_def(node)
- @stack.pop
- end
-
- sig { params(node: SyntaxTree::ModuleDeclaration).void }
- def on_module(node)
- @stack << create_document_symbol(
- name: full_constant_name(node.constant),
- kind: Constant::SymbolKind::MODULE,
- range_node: node,
- selection_range_node: node.constant,
- )
- end
-
- sig { params(node: SyntaxTree::ModuleDeclaration).void }
+ sig { params(node: YARP::ModuleNode).void }
def after_module(node)
@stack.pop
end
- sig { params(node: SyntaxTree::TopConstField).void }
- def on_top_const_field(node)
+ sig { params(node: YARP::InstanceVariableWriteNode).void }
+ def on_instance_variable_write(node)
create_document_symbol(
- name: node.constant.value,
- kind: Constant::SymbolKind::CONSTANT,
- range_node: node,
- selection_range_node: node.constant,
+ name: node.name.to_s,
+ kind: Constant::SymbolKind::VARIABLE,
+ range_location: node.name_loc,
+ selection_range_location: node.name_loc,
)
end
- sig { params(node: SyntaxTree::VarField).void }
- def on_var_field(node)
- value = node.value
- kind = case value
- when SyntaxTree::Const
- Constant::SymbolKind::CONSTANT
- when SyntaxTree::CVar, SyntaxTree::IVar
- Constant::SymbolKind::VARIABLE
- else
- return
- end
-
+ sig { params(node: YARP::ClassVariableWriteNode).void }
+ def on_class_variable_write(node)
create_document_symbol(
- name: value.value,
- kind: kind,
- range_node: node,
- selection_range_node: value,
+ name: node.name.to_s,
+ kind: Constant::SymbolKind::VARIABLE,
+ range_location: node.name_loc,
+ selection_range_location: node.name_loc,
)
end
@@ -206,16 +213,16 @@ def on_var_field(node)
params(
name: String,
kind: Integer,
- range_node: SyntaxTree::Node,
- selection_range_node: SyntaxTree::Node,
+ range_location: YARP::Location,
+ selection_range_location: YARP::Location,
).returns(Interface::DocumentSymbol)
end
- def create_document_symbol(name:, kind:, range_node:, selection_range_node:)
+ def create_document_symbol(name:, kind:, range_location:, selection_range_location:)
symbol = Interface::DocumentSymbol.new(
name: name,
kind: kind,
- range: range_from_syntax_tree_node(range_node),
- selection_range: range_from_syntax_tree_node(selection_range_node),
+ range: range_from_location(range_location),
+ selection_range: range_from_location(selection_range_location),
children: [],
)
diff --git a/lib/ruby_lsp/requests/folding_ranges.rb b/lib/ruby_lsp/requests/folding_ranges.rb
index fd75278f8..979d33bcc 100644
--- a/lib/ruby_lsp/requests/folding_ranges.rb
+++ b/lib/ruby_lsp/requests/folding_ranges.rb
@@ -15,288 +15,265 @@ module Requests
# puts "Hello"
# end # <-- folding range end
# ```
- class FoldingRanges < BaseRequest
+ class FoldingRanges < Listener
extend T::Sig
-
- SIMPLE_FOLDABLES = T.let(
- [
- SyntaxTree::ArrayLiteral,
- SyntaxTree::BlockNode,
- SyntaxTree::Case,
- SyntaxTree::ClassDeclaration,
- SyntaxTree::For,
- SyntaxTree::HashLiteral,
- SyntaxTree::Heredoc,
- SyntaxTree::ModuleDeclaration,
- SyntaxTree::SClass,
- SyntaxTree::UnlessNode,
- SyntaxTree::UntilNode,
- SyntaxTree::WhileNode,
- SyntaxTree::Else,
- SyntaxTree::Ensure,
- SyntaxTree::Begin,
- ].freeze,
- T::Array[T.class_of(SyntaxTree::Node)],
- )
-
- NODES_WITH_STATEMENTS = T.let(
- [
- SyntaxTree::IfNode,
- SyntaxTree::Elsif,
- SyntaxTree::In,
- SyntaxTree::Rescue,
- SyntaxTree::When,
- ].freeze,
- T::Array[T.class_of(SyntaxTree::Node)],
- )
-
- StatementNode = T.type_alias do
- T.any(
- SyntaxTree::IfNode,
- SyntaxTree::Elsif,
- SyntaxTree::In,
- SyntaxTree::Rescue,
- SyntaxTree::When,
+ extend T::Generic
+
+ ResponseType = type_member { { fixed: T::Array[Interface::FoldingRange] } }
+
+ sig { params(comments: T::Array[YARP::Comment], emitter: EventEmitter, queue: Thread::Queue).void }
+ def initialize(comments, emitter, queue)
+ super(emitter, queue)
+
+ @_response = T.let([], ResponseType)
+ @requires = T.let([], T::Array[YARP::CallNode])
+ @finalized_response = T.let(false, T::Boolean)
+ @comments = comments
+
+ emitter.register(
+ self,
+ :on_if,
+ :on_in,
+ :on_rescue,
+ :on_when,
+ :on_interpolated_string,
+ :on_array,
+ :on_block,
+ :on_case,
+ :on_class,
+ :on_module,
+ :on_for,
+ :on_hash,
+ :on_singleton_class,
+ :on_unless,
+ :on_until,
+ :on_while,
+ :on_else,
+ :on_ensure,
+ :on_begin,
+ :on_string_concat,
+ :on_def,
+ :on_call,
)
end
- sig { params(document: Document).void }
- def initialize(document)
- super
+ sig { override.returns(ResponseType) }
+ def _response
+ unless @finalized_response
+ push_comment_ranges
+ emit_requires_range
+ @finalized_response = true
+ end
- @ranges = T.let([], T::Array[Interface::FoldingRange])
- @partial_range = T.let(nil, T.nilable(PartialRange))
+ @_response
end
- sig { override.returns(T.all(T::Array[Interface::FoldingRange], Object)) }
- def run
- if @document.parsed?
- visit(@document.tree)
- emit_partial_range
- end
+ sig { params(node: YARP::IfNode).void }
+ def on_if(node)
+ add_statements_range(node)
+ end
- @ranges
+ sig { params(node: YARP::InNode).void }
+ def on_in(node)
+ add_statements_range(node)
end
- private
+ sig { params(node: YARP::RescueNode).void }
+ def on_rescue(node)
+ add_statements_range(node)
+ end
- sig { override.params(node: T.nilable(SyntaxTree::Node)).void }
- def visit(node)
- return unless handle_partial_range(node)
+ sig { params(node: YARP::WhenNode).void }
+ def on_when(node)
+ add_statements_range(node)
+ end
- case node
- when *SIMPLE_FOLDABLES
- location = T.must(node).location
- add_lines_range(location.start_line, location.end_line - 1)
- when *NODES_WITH_STATEMENTS
- add_statements_range(T.must(node), T.cast(node, StatementNode).statements)
- when SyntaxTree::CallNode, SyntaxTree::CommandCall
- # If there is a receiver, it may be a chained invocation,
- # so we need to process it in special way.
- if node.receiver.nil?
- location = node.location
- add_lines_range(location.start_line, location.end_line - 1)
- else
- add_call_range(node)
- return
- end
- when SyntaxTree::Command
- unless same_lines_for_command_and_block?(node)
- location = node.location
- add_lines_range(location.start_line, location.end_line - 1)
- end
- when SyntaxTree::DefNode
- add_def_range(node)
- when SyntaxTree::StringConcat
- add_string_concat(node)
- return
- end
+ sig { params(node: YARP::InterpolatedStringNode).void }
+ def on_interpolated_string(node)
+ opening_loc = node.opening_loc
+ closing_loc = node.closing_loc
- super
+ add_lines_range(opening_loc.start_line, closing_loc.end_line - 1) if opening_loc && closing_loc
end
- # This is to prevent duplicate ranges
- sig { params(node: T.any(SyntaxTree::Command, SyntaxTree::CommandCall)).returns(T::Boolean) }
- def same_lines_for_command_and_block?(node)
- node_block = node.block
- return false unless node_block
+ sig { params(node: YARP::ArrayNode).void }
+ def on_array(node)
+ add_simple_range(node)
+ end
- location = node.location
- block_location = node_block.location
- block_location.start_line == location.start_line && block_location.end_line == location.end_line
+ sig { params(node: YARP::BlockNode).void }
+ def on_block(node)
+ add_simple_range(node)
end
- class PartialRange
- extend T::Sig
+ sig { params(node: YARP::CaseNode).void }
+ def on_case(node)
+ add_simple_range(node)
+ end
- sig { returns(String) }
- attr_reader :kind
+ sig { params(node: YARP::ClassNode).void }
+ def on_class(node)
+ add_simple_range(node)
+ end
- sig { returns(Integer) }
- attr_reader :end_line
+ sig { params(node: YARP::ModuleNode).void }
+ def on_module(node)
+ add_simple_range(node)
+ end
- class << self
- extend T::Sig
+ sig { params(node: YARP::ForNode).void }
+ def on_for(node)
+ add_simple_range(node)
+ end
- sig { params(node: SyntaxTree::Node, kind: String).returns(PartialRange) }
- def from(node, kind)
- new(node.location.start_line - 1, node.location.end_line - 1, kind)
- end
- end
+ sig { params(node: YARP::HashNode).void }
+ def on_hash(node)
+ add_simple_range(node)
+ end
- sig { params(start_line: Integer, end_line: Integer, kind: String).void }
- def initialize(start_line, end_line, kind)
- @start_line = start_line
- @end_line = end_line
- @kind = kind
- end
+ sig { params(node: YARP::SingletonClassNode).void }
+ def on_singleton_class(node)
+ add_simple_range(node)
+ end
- sig { params(node: SyntaxTree::Node).returns(PartialRange) }
- def extend_to(node)
- @end_line = node.location.end_line - 1
- self
- end
+ sig { params(node: YARP::UnlessNode).void }
+ def on_unless(node)
+ add_simple_range(node)
+ end
- sig { params(node: SyntaxTree::Node).returns(T::Boolean) }
- def new_section?(node)
- node.is_a?(SyntaxTree::Comment) && @end_line + 1 != node.location.start_line - 1
- end
+ sig { params(node: YARP::UntilNode).void }
+ def on_until(node)
+ add_simple_range(node)
+ end
- sig { returns(Interface::FoldingRange) }
- def to_range
- Interface::FoldingRange.new(
- start_line: @start_line,
- end_line: @end_line,
- kind: @kind,
- )
- end
+ sig { params(node: YARP::WhileNode).void }
+ def on_while(node)
+ add_simple_range(node)
+ end
- sig { returns(T::Boolean) }
- def multiline?
- @end_line > @start_line
- end
+ sig { params(node: YARP::ElseNode).void }
+ def on_else(node)
+ add_simple_range(node)
end
- sig { params(node: T.nilable(SyntaxTree::Node)).returns(T::Boolean) }
- def handle_partial_range(node)
- kind = partial_range_kind(node)
+ sig { params(node: YARP::EnsureNode).void }
+ def on_ensure(node)
+ add_simple_range(node)
+ end
- if kind.nil?
- emit_partial_range
- return true
- end
+ sig { params(node: YARP::BeginNode).void }
+ def on_begin(node)
+ add_simple_range(node)
+ end
- target_node = T.must(node)
- @partial_range = if @partial_range.nil?
- PartialRange.from(target_node, kind)
- elsif @partial_range.kind != kind || @partial_range.new_section?(target_node)
- emit_partial_range
- PartialRange.from(target_node, kind)
- else
- @partial_range.extend_to(target_node)
- end
+ sig { params(node: YARP::Node).void }
+ def on_node(node)
+ emit_requires_range unless node.is_a?(YARP::CallNode)
+ end
- false
+ sig { params(node: YARP::StringConcatNode).void }
+ def on_string_concat(node)
+ left = T.let(node.left, YARP::Node)
+ left = left.left while left.is_a?(YARP::StringConcatNode)
+
+ add_lines_range(left.location.start_line, node.right.location.end_line - 1)
end
- sig { params(node: T.nilable(SyntaxTree::Node)).returns(T.nilable(String)) }
- def partial_range_kind(node)
- case node
- when SyntaxTree::Comment
- "comment"
- when SyntaxTree::Command
- if node.message.value == "require" || node.message.value == "require_relative"
- "imports"
- end
+ sig { params(node: YARP::DefNode).void }
+ def on_def(node)
+ params = node.parameters
+ parameter_loc = params&.location
+ location = node.location
+
+ if params && parameter_loc.end_line > location.start_line
+ # Multiline parameters
+ add_lines_range(location.start_line, parameter_loc.end_line)
+ add_lines_range(parameter_loc.end_line + 1, location.end_line - 1)
+ else
+ add_lines_range(location.start_line, location.end_line - 1)
end
end
- sig { void }
- def emit_partial_range
- return if @partial_range.nil?
+ sig { params(node: YARP::CallNode).void }
+ def on_call(node)
+ # If we find a require, don't visit the child nodes (prevent `super`), so that we can keep accumulating into
+ # the `@requires` array and then push the range whenever we find a node that isn't a CallNode
+ if require?(node)
+ @requires << node
+ return
+ end
- @ranges << @partial_range.to_range if @partial_range.multiline?
- @partial_range = nil
+ location = node.location
+ add_lines_range(location.start_line, location.end_line - 1)
end
- sig { params(node: T.any(SyntaxTree::CallNode, SyntaxTree::CommandCall)).void }
- def add_call_range(node)
- receiver = T.let(node.receiver, T.nilable(SyntaxTree::Node))
-
- loop do
- case receiver
- when SyntaxTree::CallNode
- visit(receiver.arguments)
- receiver = receiver.receiver
- when SyntaxTree::MethodAddBlock
- visit(receiver.block)
- receiver = receiver.call
-
- if receiver.is_a?(SyntaxTree::CallNode) || receiver.is_a?(SyntaxTree::CommandCall)
- receiver = receiver.receiver
- end
- else
- break
- end
+ private
+
+ sig { void }
+ def push_comment_ranges
+ # Group comments that are on consecutive lines and then push ranges for each group that has at least 2 comments
+ @comments.chunk_while do |this, other|
+ this.location.end_line + 1 == other.location.start_line
+ end.each do |chunk|
+ next if chunk.length == 1
+
+ @_response << Interface::FoldingRange.new(
+ start_line: T.must(chunk.first).location.start_line - 1,
+ end_line: T.must(chunk.last).location.end_line - 1,
+ kind: "comment",
+ )
end
+ end
- if receiver
- unless node.is_a?(SyntaxTree::CommandCall) && same_lines_for_command_and_block?(node)
- add_lines_range(
- receiver.location.start_line,
- node.location.end_line - 1,
- )
- end
+ sig { void }
+ def emit_requires_range
+ if @requires.length > 1
+ @_response << Interface::FoldingRange.new(
+ start_line: T.must(@requires.first).location.start_line - 1,
+ end_line: T.must(@requires.last).location.end_line - 1,
+ kind: "imports",
+ )
end
- visit(node.arguments)
- visit(node.block) if node.is_a?(SyntaxTree::CommandCall)
+ @requires.clear
end
- sig { params(node: SyntaxTree::DefNode).void }
- def add_def_range(node)
- # For an endless method with no arguments, `node.params` returns `nil` for Ruby 3.0, but a `Syntax::Params`
- # for Ruby 3.1
- params = node.params
- return unless params
+ sig { params(node: YARP::CallNode).returns(T::Boolean) }
+ def require?(node)
+ message = node.message
+ return false unless message == "require" || message == "require_relative"
- params_location = params.location
+ receiver = node.receiver
+ return false unless receiver.nil? || receiver.slice == "Kernel"
- if params_location.start_line < params_location.end_line
- add_lines_range(params_location.end_line, node.location.end_line - 1)
- else
- location = node.location
- add_lines_range(location.start_line, location.end_line - 1)
- end
+ arguments = node.arguments&.arguments
+ return false unless arguments
- bodystmt = node.bodystmt
- if bodystmt.is_a?(SyntaxTree::BodyStmt)
- visit(bodystmt.statements)
- else
- visit(bodystmt)
- end
+ arguments.length == 1 && arguments.first.is_a?(YARP::StringNode)
end
- sig { params(node: SyntaxTree::Node, statements: SyntaxTree::Statements).void }
- def add_statements_range(node, statements)
- return if statements.empty?
+ sig { params(node: T.any(YARP::IfNode, YARP::InNode, YARP::RescueNode, YARP::WhenNode)).void }
+ def add_statements_range(node)
+ statements = node.statements
+ return unless statements
- add_lines_range(node.location.start_line, T.must(statements.body.last).location.end_line)
- end
+ body = statements.body
+ return if body.empty?
- sig { params(node: SyntaxTree::StringConcat).void }
- def add_string_concat(node)
- left = T.let(node.left, SyntaxTree::Node)
- left = left.left while left.is_a?(SyntaxTree::StringConcat)
+ add_lines_range(node.location.start_line, T.must(body.last).location.end_line)
+ end
- add_lines_range(left.location.start_line, node.right.location.end_line - 1)
+ sig { params(node: YARP::Node).void }
+ def add_simple_range(node)
+ location = node.location
+ add_lines_range(location.start_line, location.end_line - 1)
end
sig { params(start_line: Integer, end_line: Integer).void }
def add_lines_range(start_line, end_line)
return if start_line >= end_line
- @ranges << Interface::FoldingRange.new(
+ @_response << Interface::FoldingRange.new(
start_line: start_line - 1,
end_line: end_line - 1,
kind: "region",
diff --git a/lib/ruby_lsp/requests/hover.rb b/lib/ruby_lsp/requests/hover.rb
index 5cf9ff1b8..23eba552c 100644
--- a/lib/ruby_lsp/requests/hover.rb
+++ b/lib/ruby_lsp/requests/hover.rb
@@ -21,12 +21,12 @@ class Hover < ExtensibleListener
ALLOWED_TARGETS = T.let(
[
- SyntaxTree::Const,
- SyntaxTree::Command,
- SyntaxTree::CallNode,
- SyntaxTree::ConstPathRef,
+ YARP::CallNode,
+ YARP::ConstantReadNode,
+ YARP::ConstantWriteNode,
+ YARP::ConstantPathNode,
],
- T::Array[T.class_of(SyntaxTree::Node)],
+ T::Array[T.class_of(YARP::Node)],
)
sig { override.returns(ResponseType) }
@@ -46,12 +46,12 @@ def initialize(index, nesting, emitter, message_queue)
@_response = T.let(nil, ResponseType)
super(emitter, message_queue)
- emitter.register(self, :on_const_path_ref, :on_const)
+ emitter.register(self, :on_constant_read, :on_constant_write, :on_constant_path)
end
sig { override.params(extension: RubyLsp::Extension).returns(T.nilable(Listener[ResponseType])) }
def initialize_external_listener(extension)
- extension.create_hover_listener(@emitter, @message_queue)
+ extension.create_hover_listener(@nesting, @index, @emitter, @message_queue)
end
# Merges responses from other hover listeners
@@ -69,30 +69,36 @@ def merge_response!(other)
self
end
- sig { params(node: SyntaxTree::ConstPathRef).void }
- def on_const_path_ref(node)
+ sig { params(node: YARP::ConstantReadNode).void }
+ def on_constant_read(node)
return if DependencyDetector::HAS_TYPECHECKER
- name = full_constant_name(node)
- generate_hover(name, node)
+ generate_hover(node.slice, node.location)
end
- sig { params(node: SyntaxTree::Const).void }
- def on_const(node)
+ sig { params(node: YARP::ConstantWriteNode).void }
+ def on_constant_write(node)
return if DependencyDetector::HAS_TYPECHECKER
- generate_hover(node.value, node)
+ generate_hover(node.name.to_s, node.name_loc)
+ end
+
+ sig { params(node: YARP::ConstantPathNode).void }
+ def on_constant_path(node)
+ return if DependencyDetector::HAS_TYPECHECKER
+
+ generate_hover(node.slice, node.location)
end
private
- sig { params(name: String, node: SyntaxTree::Node).void }
- def generate_hover(name, node)
+ sig { params(name: String, location: YARP::Location).void }
+ def generate_hover(name, location)
entries = @index.resolve(name, @nesting)
return unless entries
@_response = Interface::Hover.new(
- range: range_from_syntax_tree_node(node),
+ range: range_from_location(location),
contents: markdown_from_index_entries(name, entries),
)
end
diff --git a/lib/ruby_lsp/requests/inlay_hints.rb b/lib/ruby_lsp/requests/inlay_hints.rb
index cbe654983..0a8d2a34d 100644
--- a/lib/ruby_lsp/requests/inlay_hints.rb
+++ b/lib/ruby_lsp/requests/inlay_hints.rb
@@ -39,10 +39,9 @@ def initialize(range, emitter, message_queue)
emitter.register(self, :on_rescue)
end
- sig { params(node: SyntaxTree::Rescue).void }
+ sig { params(node: YARP::RescueNode).void }
def on_rescue(node)
- exception = node.exception
- return unless exception.nil? || exception.exceptions.nil?
+ return unless node.exceptions.empty?
loc = node.location
return unless visible?(node, @range)
diff --git a/lib/ruby_lsp/requests/selection_ranges.rb b/lib/ruby_lsp/requests/selection_ranges.rb
index dea4765f3..c435850eb 100644
--- a/lib/ruby_lsp/requests/selection_ranges.rb
+++ b/lib/ruby_lsp/requests/selection_ranges.rb
@@ -25,41 +25,37 @@ class SelectionRanges < BaseRequest
NODES_THAT_CAN_BE_PARENTS = T.let(
[
- SyntaxTree::Assign,
- SyntaxTree::ArrayLiteral,
- SyntaxTree::Begin,
- SyntaxTree::BlockNode,
- SyntaxTree::CallNode,
- SyntaxTree::Case,
- SyntaxTree::ClassDeclaration,
- SyntaxTree::Command,
- SyntaxTree::DefNode,
- SyntaxTree::Elsif,
- SyntaxTree::Else,
- SyntaxTree::EmbDoc,
- SyntaxTree::Ensure,
- SyntaxTree::For,
- SyntaxTree::HashLiteral,
- SyntaxTree::Heredoc,
- SyntaxTree::HeredocBeg,
- SyntaxTree::HshPtn,
- SyntaxTree::IfNode,
- SyntaxTree::In,
- SyntaxTree::Lambda,
- SyntaxTree::MethodAddBlock,
- SyntaxTree::ModuleDeclaration,
- SyntaxTree::Params,
- SyntaxTree::Rescue,
- SyntaxTree::RescueEx,
- SyntaxTree::StringConcat,
- SyntaxTree::StringLiteral,
- SyntaxTree::UnlessNode,
- SyntaxTree::UntilNode,
- SyntaxTree::VCall,
- SyntaxTree::When,
- SyntaxTree::WhileNode,
+ YARP::ArgumentsNode,
+ YARP::ArrayNode,
+ YARP::AssocNode,
+ YARP::BeginNode,
+ YARP::BlockNode,
+ YARP::CallNode,
+ YARP::CaseNode,
+ YARP::ClassNode,
+ YARP::DefNode,
+ YARP::ElseNode,
+ YARP::EnsureNode,
+ YARP::ForNode,
+ YARP::HashNode,
+ YARP::HashPatternNode,
+ YARP::IfNode,
+ YARP::InNode,
+ YARP::InterpolatedStringNode,
+ YARP::KeywordHashNode,
+ YARP::LambdaNode,
+ YARP::LocalVariableWriteNode,
+ YARP::ModuleNode,
+ YARP::ParametersNode,
+ YARP::RescueNode,
+ YARP::StringConcatNode,
+ YARP::StringNode,
+ YARP::UnlessNode,
+ YARP::UntilNode,
+ YARP::WhenNode,
+ YARP::WhileNode,
].freeze,
- T::Array[T.class_of(SyntaxTree::Node)],
+ T::Array[T.class_of(YARP::Node)],
)
sig { params(document: Document).void }
@@ -72,19 +68,23 @@ def initialize(document)
sig { override.returns(T.all(T::Array[Support::SelectionRange], Object)) }
def run
- visit(@document.tree) if @document.parsed?
+ visit(@document.tree)
@ranges.reverse!
end
private
- sig { override.params(node: T.nilable(SyntaxTree::Node)).void }
+ sig { override.params(node: T.nilable(YARP::Node)).void }
def visit(node)
return if node.nil?
- range = create_selection_range(node.location, @stack.last)
-
+ range = if node.is_a?(YARP::InterpolatedStringNode)
+ create_heredoc_selection_range(node, @stack.last)
+ else
+ create_selection_range(node.location, @stack.last)
+ end
@ranges << range
+
return if node.child_nodes.empty?
@stack << range if NODES_THAT_CAN_BE_PARENTS.include?(node.class)
@@ -94,11 +94,36 @@ def visit(node)
sig do
params(
- location: SyntaxTree::Location,
+ node: YARP::InterpolatedStringNode,
+ parent: T.nilable(Support::SelectionRange),
+ ).returns(Support::SelectionRange)
+ end
+ def create_heredoc_selection_range(node, parent)
+ opening_loc = node.opening_loc || node.location
+ closing_loc = node.closing_loc || node.location
+
+ RubyLsp::Requests::Support::SelectionRange.new(
+ range: Interface::Range.new(
+ start: Interface::Position.new(
+ line: opening_loc.start_line - 1,
+ character: opening_loc.start_column,
+ ),
+ end: Interface::Position.new(
+ line: closing_loc.end_line - 1,
+ character: closing_loc.end_column,
+ ),
+ ),
+ parent: parent,
+ )
+ end
+
+ sig do
+ params(
+ location: YARP::Location,
parent: T.nilable(Support::SelectionRange),
).returns(Support::SelectionRange)
end
- def create_selection_range(location, parent = nil)
+ def create_selection_range(location, parent)
RubyLsp::Requests::Support::SelectionRange.new(
range: Interface::Range.new(
start: Interface::Position.new(
diff --git a/lib/ruby_lsp/requests/semantic_highlighting.rb b/lib/ruby_lsp/requests/semantic_highlighting.rb
index d7f840e92..b1ff709e5 100644
--- a/lib/ruby_lsp/requests/semantic_highlighting.rb
+++ b/lib/ruby_lsp/requests/semantic_highlighting.rb
@@ -83,7 +83,7 @@ class SemanticHighlighting < Listener
class SemanticToken
extend T::Sig
- sig { returns(SyntaxTree::Location) }
+ sig { returns(YARP::Location) }
attr_reader :location
sig { returns(Integer) }
@@ -95,7 +95,7 @@ class SemanticToken
sig { returns(T::Array[Integer]) }
attr_reader :modifier
- sig { params(location: SyntaxTree::Location, length: Integer, type: Integer, modifier: T::Array[Integer]).void }
+ sig { params(location: YARP::Location, length: Integer, type: Integer, modifier: T::Array[Integer]).void }
def initialize(location:, length:, type:, modifier:)
@location = location
@length = length
@@ -120,56 +120,60 @@ def initialize(emitter, message_queue, range: nil)
@_response = T.let([], ResponseType)
@range = range
@special_methods = T.let(nil, T.nilable(T::Array[String]))
+ @current_scope = T.let(ParameterScope.new, ParameterScope)
emitter.register(
self,
- :after_binary,
- :on_block_var,
:on_call,
:on_class,
- :on_command,
- :on_command_call,
- :on_const,
:on_def,
- :on_field,
- :on_kw,
- :on_lambda_var,
+ :after_def,
+ :on_block,
+ :after_block,
+ :on_self,
:on_module,
- :on_params,
- :on_var_field,
- :on_var_ref,
- :on_vcall,
+ :on_local_variable_write,
+ :on_local_variable_read,
+ :on_block_parameter,
+ :on_keyword_parameter,
+ :on_keyword_rest_parameter,
+ :on_optional_parameter,
+ :on_required_parameter,
+ :on_rest_parameter,
+ :on_constant_read,
+ :on_constant_write,
+ :on_constant_and_write,
+ :on_constant_operator_write,
+ :on_constant_or_write,
+ :on_constant_target,
+ :on_local_variable_and_write,
+ :on_local_variable_operator_write,
+ :on_local_variable_or_write,
+ :on_local_variable_target,
+ :on_block_local_variable,
)
end
- sig { params(node: SyntaxTree::CallNode).void }
+ sig { params(node: YARP::CallNode).void }
def on_call(node)
return unless visible?(node, @range)
message = node.message
- if !message.is_a?(Symbol) && !special_method?(message.value)
- type = Support::Sorbet.annotation?(node) ? :type : :method
- add_token(message.location, type)
- end
- end
-
- sig { params(node: SyntaxTree::Command).void }
- def on_command(node)
- return unless visible?(node, @range)
+ return unless message
- add_token(node.message.location, :method) unless special_method?(node.message.value)
- end
+ # We can't push a semantic token for [] and []= because the argument inside the brackets is a part of
+ # the message_loc
+ return if message.start_with?("[") && (message.end_with?("]") || message.end_with?("]="))
- sig { params(node: SyntaxTree::CommandCall).void }
- def on_command_call(node)
- return unless visible?(node, @range)
+ return process_regexp_locals(node) if message == "=~"
+ return if special_method?(message)
- message = node.message
- add_token(message.location, :method) unless message.is_a?(Symbol)
+ type = Support::Sorbet.annotation?(node) ? :type : :method
+ add_token(T.must(node.message_loc), type)
end
- sig { params(node: SyntaxTree::Const).void }
- def on_const(node)
+ sig { params(node: YARP::ConstantReadNode).void }
+ def on_constant_read(node)
return unless visible?(node, @range)
# 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
@@ -179,153 +183,199 @@ def on_const(node)
add_token(node.location, :namespace)
end
- sig { params(node: SyntaxTree::DefNode).void }
- def on_def(node)
+ sig { params(node: YARP::ConstantWriteNode).void }
+ def on_constant_write(node)
return unless visible?(node, @range)
- add_token(node.name.location, :method, [:declaration])
+ add_token(node.name_loc, :namespace)
end
- sig { params(node: SyntaxTree::Kw).void }
- def on_kw(node)
+ sig { params(node: YARP::ConstantAndWriteNode).void }
+ def on_constant_and_write(node)
return unless visible?(node, @range)
- case node.value
- when "self"
- add_token(node.location, :variable, [:default_library])
- end
+ add_token(node.name_loc, :namespace)
end
- sig { params(node: SyntaxTree::Params).void }
- def on_params(node)
+ sig { params(node: YARP::ConstantOperatorWriteNode).void }
+ def on_constant_operator_write(node)
return unless visible?(node, @range)
- node.keywords.each do |keyword, *|
- location = keyword.location
- add_token(location_without_colon(location), :parameter)
- end
+ add_token(node.name_loc, :namespace)
+ end
- node.requireds.each do |required|
- add_token(required.location, :parameter)
- end
+ sig { params(node: YARP::ConstantOrWriteNode).void }
+ def on_constant_or_write(node)
+ return unless visible?(node, @range)
- rest = node.keyword_rest
- if rest && !rest.is_a?(SyntaxTree::ArgsForward) && !rest.is_a?(Symbol)
- name = rest.name
- add_token(name.location, :parameter) if name
- end
+ add_token(node.name_loc, :namespace)
+ end
+
+ sig { params(node: YARP::ConstantTargetNode).void }
+ def on_constant_target(node)
+ return unless visible?(node, @range)
+
+ add_token(node.location, :namespace)
end
- sig { params(node: SyntaxTree::Field).void }
- def on_field(node)
+ sig { params(node: YARP::DefNode).void }
+ def on_def(node)
+ @current_scope = ParameterScope.new(@current_scope)
return unless visible?(node, @range)
- add_token(node.name.location, :method)
+ add_token(node.name_loc, :method, [:declaration])
+ end
+
+ sig { params(node: YARP::DefNode).void }
+ def after_def(node)
+ @current_scope = T.must(@current_scope.parent)
+ end
+
+ sig { params(node: YARP::BlockNode).void }
+ def on_block(node)
+ @current_scope = ParameterScope.new(@current_scope)
end
- sig { params(node: SyntaxTree::VarField).void }
- def on_var_field(node)
+ sig { params(node: YARP::BlockNode).void }
+ def after_block(node)
+ @current_scope = T.must(@current_scope.parent)
+ end
+
+ sig { params(node: YARP::BlockLocalVariableNode).void }
+ def on_block_local_variable(node)
+ add_token(node.location, :variable)
+ end
+
+ sig { params(node: YARP::BlockParameterNode).void }
+ def on_block_parameter(node)
+ name = node.name
+ @current_scope << name.to_sym if name
+ end
+
+ sig { params(node: YARP::KeywordParameterNode).void }
+ def on_keyword_parameter(node)
+ name = node.name
+ @current_scope << name.to_s.delete_suffix(":").to_sym if name
+
return unless visible?(node, @range)
- value = node.value
+ location = node.name_loc
+ add_token(location.copy(length: location.length - 1), :parameter)
+ end
- case value
- when SyntaxTree::Ident
- type = type_for_local(value)
- add_token(value.location, type)
+ sig { params(node: YARP::KeywordRestParameterNode).void }
+ def on_keyword_rest_parameter(node)
+ name = node.name
+
+ if name
+ @current_scope << name.to_sym
+
+ add_token(T.must(node.name_loc), :parameter) if visible?(node, @range)
end
end
- sig { params(node: SyntaxTree::VarRef).void }
- def on_var_ref(node)
+ sig { params(node: YARP::OptionalParameterNode).void }
+ def on_optional_parameter(node)
+ @current_scope << node.name
+ return unless visible?(node, @range)
+
+ add_token(node.name_loc, :parameter)
+ end
+
+ sig { params(node: YARP::RequiredParameterNode).void }
+ def on_required_parameter(node)
+ @current_scope << node.name
return unless visible?(node, @range)
- value = node.value
+ add_token(node.location, :parameter)
+ end
+
+ sig { params(node: YARP::RestParameterNode).void }
+ def on_rest_parameter(node)
+ name = node.name
- case value
- when SyntaxTree::Ident
- type = type_for_local(value)
- add_token(value.location, type)
+ if name
+ @current_scope << name.to_sym
+
+ add_token(T.must(node.name_loc), :parameter) if visible?(node, @range)
end
end
- # All block locals are variables. E.g.: [].each do |x; block_local|
- sig { params(node: SyntaxTree::BlockVar).void }
- def on_block_var(node)
- node.locals.each { |local| add_token(local.location, :variable) }
+ sig { params(node: YARP::SelfNode).void }
+ def on_self(node)
+ return unless visible?(node, @range)
+
+ add_token(node.location, :variable, [:default_library])
end
- # All lambda locals are variables. E.g.: ->(x; lambda_local) {}
- sig { params(node: SyntaxTree::LambdaVar).void }
- def on_lambda_var(node)
- node.locals.each { |local| add_token(local.location, :variable) }
+ sig { params(node: YARP::LocalVariableWriteNode).void }
+ def on_local_variable_write(node)
+ return unless visible?(node, @range)
+
+ add_token(node.name_loc, @current_scope.type_for(node.name))
end
- sig { params(node: SyntaxTree::VCall).void }
- def on_vcall(node)
+ sig { params(node: YARP::LocalVariableReadNode).void }
+ def on_local_variable_read(node)
return unless visible?(node, @range)
- # A VCall may exist as a local in the current_scope. This happens when used named capture groups in a regexp
- ident = node.value
- value = ident.value
- local = @emitter.current_scope.find_local(value)
- return if local.nil? && special_method?(value)
-
- type = if local
- :variable
- elsif Support::Sorbet.annotation?(node)
- :type
- else
- :method
+ # Numbered parameters
+ if /_\d+/.match?(node.name)
+ add_token(node.location, :parameter)
+ return
end
- add_token(node.value.location, type)
+ add_token(node.location, @current_scope.type_for(node.name))
end
- sig { params(node: SyntaxTree::Binary).void }
- def after_binary(node)
- # You can only capture local variables with regexp by using the =~ operator
- return unless node.operator == :=~
+ sig { params(node: YARP::LocalVariableAndWriteNode).void }
+ def on_local_variable_and_write(node)
+ return unless visible?(node, @range)
- left = node.left
- # The regexp needs to be on the left hand side of the =~ for local variable capture
- return unless left.is_a?(SyntaxTree::RegexpLiteral)
+ add_token(node.name_loc, @current_scope.type_for(node.name))
+ end
- parts = left.parts
- return unless parts.one?
+ sig { params(node: YARP::LocalVariableOperatorWriteNode).void }
+ def on_local_variable_operator_write(node)
+ return unless visible?(node, @range)
- content = parts.first
- return unless content.is_a?(SyntaxTree::TStringContent)
+ add_token(node.name_loc, @current_scope.type_for(node.name))
+ end
- # For each capture name we find in the regexp, look for a local in the current_scope
- Regexp.new(content.value, Regexp::FIXEDENCODING).names.each do |name|
- local = @emitter.current_scope.find_local(name)
- next unless local
+ sig { params(node: YARP::LocalVariableOrWriteNode).void }
+ def on_local_variable_or_write(node)
+ return unless visible?(node, @range)
- local.definitions.each { |definition| add_token(definition, :variable) }
- end
+ add_token(node.name_loc, @current_scope.type_for(node.name))
+ end
+
+ sig { params(node: YARP::LocalVariableTargetNode).void }
+ def on_local_variable_target(node)
+ return unless visible?(node, @range)
+
+ add_token(node.location, @current_scope.type_for(node.name))
end
- sig { params(node: SyntaxTree::ClassDeclaration).void }
+ sig { params(node: YARP::ClassNode).void }
def on_class(node)
return unless visible?(node, @range)
- add_token(node.constant.location, :class, [:declaration])
+ add_token(node.constant_path.location, :class, [:declaration])
superclass = node.superclass
add_token(superclass.location, :class) if superclass
end
- sig { params(node: SyntaxTree::ModuleDeclaration).void }
+ sig { params(node: YARP::ModuleNode).void }
def on_module(node)
return unless visible?(node, @range)
- add_token(node.constant.location, :namespace, [:declaration])
+ add_token(node.constant_path.location, :namespace, [:declaration])
end
- sig { params(location: SyntaxTree::Location, type: Symbol, modifiers: T::Array[Symbol]).void }
+ sig { params(location: YARP::Location, type: Symbol, modifiers: T::Array[Symbol]).void }
def add_token(location, type, modifiers = [])
- length = location.end_char - location.start_char
+ length = location.end_offset - location.start_offset
modifiers_indices = modifiers.filter_map { |modifier| TOKEN_MODIFIERS[modifier] }
@_response.push(
SemanticToken.new(
@@ -339,38 +389,30 @@ def add_token(location, type, modifiers = [])
private
- # Exclude the ":" symbol at the end of a location
- # We use it on keyword parameters to be consistent
- # with the rest of the parameters
- sig { params(location: T.untyped).returns(SyntaxTree::Location) }
- def location_without_colon(location)
- SyntaxTree::Location.new(
- start_line: location.start_line,
- start_column: location.start_column,
- start_char: location.start_char,
- end_char: location.end_char - 1,
- end_column: location.end_column - 1,
- end_line: location.end_line,
- )
- end
-
- # Textmate provides highlighting for a subset
- # of these special Ruby-specific methods.
- # We want to utilize that highlighting, so we
- # avoid making a semantic token for it.
+ # Textmate provides highlighting for a subset of these special Ruby-specific methods. We want to utilize that
+ # highlighting, so we avoid making a semantic token for it.
sig { params(method_name: String).returns(T::Boolean) }
def special_method?(method_name)
SPECIAL_RUBY_METHODS.include?(method_name)
end
- sig { params(value: SyntaxTree::Ident).returns(Symbol) }
- def type_for_local(value)
- local = @emitter.current_scope.find_local(value.value)
+ sig { params(node: YARP::CallNode).void }
+ def process_regexp_locals(node)
+ receiver = node.receiver
+
+ # The regexp needs to be the receiver of =~ for local variable capture
+ return unless receiver.is_a?(YARP::RegularExpressionNode)
+
+ content = receiver.content
+ loc = receiver.content_loc
+
+ # For each capture name we find in the regexp, look for a local in the current_scope
+ Regexp.new(content, Regexp::FIXEDENCODING).names.each do |name|
+ # The +3 is to compensate for the "(?<" part of the capture name
+ capture_name_offset = T.must(content.index("(?<#{name}>")) + 3
+ local_var_loc = loc.copy(start_offset: loc.start_offset + capture_name_offset, length: name.length)
- if local.nil? || local.type == :variable
- :variable
- else
- :parameter
+ add_token(local_var_loc, @current_scope.type_for(name))
end
end
end
diff --git a/lib/ruby_lsp/requests/show_syntax_tree.rb b/lib/ruby_lsp/requests/show_syntax_tree.rb
index 8763ceb79..cfd80cb5d 100644
--- a/lib/ruby_lsp/requests/show_syntax_tree.rb
+++ b/lib/ruby_lsp/requests/show_syntax_tree.rb
@@ -29,7 +29,6 @@ def initialize(document, range)
sig { override.returns(String) }
def run
- return "Document contains syntax error" if @document.syntax_error?
return ast_for_range if @range
output_string = +""
@@ -47,7 +46,7 @@ def ast_for_range
start_char = scanner.find_char_position(range[:start])
end_char = scanner.find_char_position(range[:end])
- queue = T.cast(@document.tree, SyntaxTree::Program).statements.body.dup
+ queue = @document.tree.statements.body.dup
found_nodes = []
until queue.empty?
@@ -58,10 +57,10 @@ def ast_for_range
# If the node is fully covered by the selection, then we found one of the nodes to be displayed and don't want
# to continue descending into its children
- if (start_char..end_char).cover?(loc.start_char..loc.end_char)
+ if (start_char..end_char).cover?(loc.start_offset..loc.end_offset)
found_nodes << node
else
- queue.unshift(*node.child_nodes)
+ T.unsafe(queue).unshift(*node.child_nodes)
end
end
diff --git a/lib/ruby_lsp/requests/support/annotation.rb b/lib/ruby_lsp/requests/support/annotation.rb
index 1a9e19f42..3f659ba0e 100644
--- a/lib/ruby_lsp/requests/support/annotation.rb
+++ b/lib/ruby_lsp/requests/support/annotation.rb
@@ -17,28 +17,29 @@ def initialize(arity:, receiver: false)
@receiver = receiver
end
- sig { returns(T.any(Integer, T::Range[Integer])) }
- attr_reader :arity
+ sig { params(node: YARP::CallNode).returns(T::Boolean) }
+ def match?(node)
+ receiver_matches?(node) && arity_matches?(node)
+ end
- sig { returns(T::Boolean) }
- attr_reader :receiver
+ private
- sig { params(arity: T.any(T::Range[Integer], Integer)).returns(T::Boolean) }
- def supports_arity?(arity)
- if @arity.is_a?(Integer)
- @arity == arity
- elsif @arity.is_a?(Range)
- @arity.cover?(arity)
- else
- T.absurd(@arity)
- end
+ sig { params(node: YARP::CallNode).returns(T::Boolean) }
+ def receiver_matches?(node)
+ node_receiver = node.receiver
+ (node_receiver && @receiver && node_receiver.location.slice == "T") || (!node_receiver && !@receiver)
end
- sig { params(receiver: T.nilable(String)).returns(T::Boolean) }
- def supports_receiver?(receiver)
- return receiver.nil? || receiver.empty? if @receiver == false
+ sig { params(node: YARP::CallNode).returns(T::Boolean) }
+ def arity_matches?(node)
+ node_arity = node.arguments&.arguments&.size || 0
- receiver == "T"
+ case @arity
+ when Integer
+ node_arity == @arity
+ when Range
+ @arity.cover?(node_arity)
+ end
end
end
end
diff --git a/lib/ruby_lsp/requests/support/common.rb b/lib/ruby_lsp/requests/support/common.rb
index 10269fab9..5d98bcf2b 100644
--- a/lib/ruby_lsp/requests/support/common.rb
+++ b/lib/ruby_lsp/requests/support/common.rb
@@ -9,8 +9,8 @@ module Common
# or extensions by created by developers outside of Shopify, so be cautious of changing anything.
extend T::Sig
- sig { params(node: SyntaxTree::Node).returns(Interface::Range) }
- def range_from_syntax_tree_node(node)
+ sig { params(node: YARP::Node).returns(Interface::Range) }
+ def range_from_node(node)
loc = node.location
Interface::Range.new(
@@ -22,28 +22,18 @@ def range_from_syntax_tree_node(node)
)
end
- sig do
- params(node: T.any(SyntaxTree::ConstPathRef, SyntaxTree::ConstRef, SyntaxTree::TopConstRef)).returns(String)
- end
- def full_constant_name(node)
- name = node.constant.value.dup
- constant = T.let(node, SyntaxTree::Node)
-
- while constant.is_a?(SyntaxTree::ConstPathRef)
- constant = constant.parent
-
- case constant
- when SyntaxTree::ConstPathRef
- name.prepend("#{constant.constant.value}::")
- when SyntaxTree::VarRef
- name.prepend("#{constant.value.value}::")
- end
- end
-
- name
+ sig { params(location: YARP::Location).returns(Interface::Range) }
+ def range_from_location(location)
+ Interface::Range.new(
+ start: Interface::Position.new(
+ line: location.start_line - 1,
+ character: location.start_column,
+ ),
+ end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
+ )
end
- sig { params(node: T.nilable(SyntaxTree::Node), range: T.nilable(T::Range[Integer])).returns(T::Boolean) }
+ sig { params(node: T.nilable(YARP::Node), range: T.nilable(T::Range[Integer])).returns(T::Boolean) }
def visible?(node, range)
return true if range.nil?
return false if node.nil?
@@ -54,7 +44,7 @@ def visible?(node, range)
sig do
params(
- node: SyntaxTree::Node,
+ node: YARP::Node,
title: String,
command_name: String,
arguments: T.nilable(T::Array[T.untyped]),
@@ -62,7 +52,7 @@ def visible?(node, range)
).returns(Interface::CodeLens)
end
def create_code_lens(node, title:, command_name:, arguments:, data:)
- range = range_from_syntax_tree_node(node)
+ range = range_from_node(node)
Interface::CodeLens.new(
range: range,
diff --git a/lib/ruby_lsp/requests/support/highlight_target.rb b/lib/ruby_lsp/requests/support/highlight_target.rb
index 47895307e..8eadcf36d 100644
--- a/lib/ruby_lsp/requests/support/highlight_target.rb
+++ b/lib/ruby_lsp/requests/support/highlight_target.rb
@@ -16,81 +16,100 @@ class HighlightMatch
sig { returns(Integer) }
attr_reader :type
- sig { returns(SyntaxTree::Node) }
- attr_reader :node
+ sig { returns(YARP::Location) }
+ attr_reader :location
- sig { params(type: Integer, node: SyntaxTree::Node).void }
- def initialize(type:, node:)
+ sig { params(type: Integer, location: YARP::Location).void }
+ def initialize(type:, location:)
@type = type
- @node = node
+ @location = location
end
end
- sig { params(node: SyntaxTree::Node).void }
+ sig { params(node: YARP::Node).void }
def initialize(node)
@node = node
@value = T.let(value(node), T.nilable(String))
end
- sig { params(other: SyntaxTree::Node).returns(T.nilable(HighlightMatch)) }
+ sig { params(other: YARP::Node).returns(T.nilable(HighlightMatch)) }
def highlight_type(other)
- matched_highlight(other) if other.is_a?(SyntaxTree::Params) || (@value && @value == value(other))
+ matched_highlight(other) if @value && @value == value(other)
end
private
# Match the target type (where the cursor is positioned) with the `other` type (the node we're currently
# visiting)
- sig { params(other: SyntaxTree::Node).returns(T.nilable(HighlightMatch)) }
+ sig { params(other: YARP::Node).returns(T.nilable(HighlightMatch)) }
def matched_highlight(other)
case @node
# Method definitions and invocations
- when SyntaxTree::VCall, SyntaxTree::CallNode, SyntaxTree::Command,
- SyntaxTree::CommandCall, SyntaxTree::DefNode
+ when YARP::CallNode, YARP::DefNode
case other
- when SyntaxTree::VCall, SyntaxTree::CallNode, SyntaxTree::Command, SyntaxTree::CommandCall
- HighlightMatch.new(type: READ, node: other)
- when SyntaxTree::DefNode
- HighlightMatch.new(type: WRITE, node: other.name)
+ when YARP::CallNode
+ HighlightMatch.new(type: READ, location: other.location)
+ when YARP::DefNode
+ HighlightMatch.new(type: WRITE, location: other.name_loc)
end
# Variables, parameters and constants
- when SyntaxTree::GVar, SyntaxTree::IVar, SyntaxTree::Const, SyntaxTree::CVar, SyntaxTree::VarField,
- SyntaxTree::VarRef, SyntaxTree::Ident
+ else
case other
- when SyntaxTree::VarField
- HighlightMatch.new(type: WRITE, node: other)
- when SyntaxTree::VarRef
- HighlightMatch.new(type: READ, node: other)
- when SyntaxTree::ClassDeclaration, SyntaxTree::ModuleDeclaration
- HighlightMatch.new(type: WRITE, node: other.constant)
- when SyntaxTree::ConstPathRef
- HighlightMatch.new(type: READ, node: other.constant)
- when SyntaxTree::Params
- params = other.child_nodes.compact
- match = params.find { |param| value(param) == @value }
- HighlightMatch.new(type: WRITE, node: match) if match
+ when YARP::GlobalVariableTargetNode, YARP::InstanceVariableTargetNode, YARP::ConstantPathTargetNode,
+ YARP::ConstantTargetNode, YARP::ClassVariableTargetNode, YARP::LocalVariableTargetNode,
+ YARP::BlockParameterNode, YARP::RequiredParameterNode
+
+ HighlightMatch.new(type: WRITE, location: other.location)
+ when YARP::LocalVariableWriteNode, YARP::KeywordParameterNode, YARP::RestParameterNode,
+ YARP::OptionalParameterNode, YARP::KeywordRestParameterNode, YARP::LocalVariableAndWriteNode,
+ YARP::LocalVariableOperatorWriteNode, YARP::LocalVariableOrWriteNode, YARP::ClassVariableWriteNode,
+ YARP::ClassVariableOrWriteNode, YARP::ClassVariableOperatorWriteNode, YARP::ClassVariableAndWriteNode,
+ YARP::ConstantWriteNode, YARP::ConstantOrWriteNode, YARP::ConstantOperatorWriteNode,
+ YARP::InstanceVariableWriteNode, YARP::ConstantAndWriteNode, YARP::InstanceVariableOrWriteNode,
+ YARP::InstanceVariableAndWriteNode, YARP::InstanceVariableOperatorWriteNode,
+ YARP::GlobalVariableWriteNode, YARP::GlobalVariableOrWriteNode, YARP::GlobalVariableAndWriteNode,
+ YARP::GlobalVariableOperatorWriteNode
+
+ HighlightMatch.new(type: WRITE, location: T.must(other.name_loc)) if other.name
+ when YARP::ConstantPathWriteNode, YARP::ConstantPathOrWriteNode, YARP::ConstantPathAndWriteNode,
+ YARP::ConstantPathOperatorWriteNode
+
+ HighlightMatch.new(type: WRITE, location: other.target.location)
+ when YARP::LocalVariableReadNode, YARP::ConstantPathNode, YARP::ConstantReadNode,
+ YARP::InstanceVariableReadNode, YARP::ClassVariableReadNode, YARP::GlobalVariableReadNode
+
+ HighlightMatch.new(type: READ, location: other.location)
+ when YARP::ClassNode, YARP::ModuleNode
+ HighlightMatch.new(type: WRITE, location: other.constant_path.location)
end
end
end
- sig { params(node: SyntaxTree::Node).returns(T.nilable(String)) }
+ sig { params(node: YARP::Node).returns(T.nilable(String)) }
def value(node)
case node
- when SyntaxTree::ConstPathRef, SyntaxTree::ConstPathField, SyntaxTree::TopConstField
- node.constant.value
- when SyntaxTree::GVar, SyntaxTree::IVar, SyntaxTree::Const, SyntaxTree::CVar, SyntaxTree::Ident
- node.value
- when SyntaxTree::Field, SyntaxTree::DefNode, SyntaxTree::RestParam,
- SyntaxTree::KwRestParam, SyntaxTree::BlockArg
- node.name&.value
- when SyntaxTree::VarField, SyntaxTree::VarRef, SyntaxTree::VCall
- value = node.value
- value.value unless value.nil? || value.is_a?(Symbol)
- when SyntaxTree::CallNode, SyntaxTree::Command, SyntaxTree::CommandCall
- message = node.message
- message.value unless message.is_a?(Symbol)
- when SyntaxTree::ClassDeclaration, SyntaxTree::ModuleDeclaration
- node.constant.constant.value
+ when YARP::ConstantReadNode, YARP::ConstantPathNode, YARP::BlockArgumentNode, YARP::ConstantTargetNode,
+ YARP::ConstantPathWriteNode, YARP::ConstantPathTargetNode, YARP::ConstantPathOrWriteNode,
+ YARP::ConstantPathOperatorWriteNode, YARP::ConstantPathAndWriteNode
+ node.slice
+ when YARP::GlobalVariableReadNode, YARP::GlobalVariableAndWriteNode, YARP::GlobalVariableOperatorWriteNode,
+ YARP::GlobalVariableOrWriteNode, YARP::GlobalVariableTargetNode, YARP::GlobalVariableWriteNode,
+ YARP::InstanceVariableAndWriteNode, YARP::InstanceVariableOperatorWriteNode,
+ YARP::InstanceVariableOrWriteNode, YARP::InstanceVariableReadNode, YARP::InstanceVariableTargetNode,
+ YARP::InstanceVariableWriteNode, YARP::ConstantAndWriteNode, YARP::ConstantOperatorWriteNode,
+ YARP::ConstantOrWriteNode, YARP::ConstantWriteNode, YARP::ClassVariableAndWriteNode,
+ YARP::ClassVariableOperatorWriteNode, YARP::ClassVariableOrWriteNode, YARP::ClassVariableReadNode,
+ YARP::ClassVariableTargetNode, YARP::ClassVariableWriteNode, YARP::LocalVariableAndWriteNode,
+ YARP::LocalVariableOperatorWriteNode, YARP::LocalVariableOrWriteNode, YARP::LocalVariableReadNode,
+ YARP::LocalVariableTargetNode, YARP::LocalVariableWriteNode, YARP::DefNode, YARP::BlockParameterNode,
+ YARP::KeywordParameterNode, YARP::KeywordRestParameterNode, YARP::OptionalParameterNode,
+ YARP::RequiredParameterNode, YARP::RestParameterNode
+
+ node.name.to_s
+ when YARP::CallNode
+ node.message
+ when YARP::ClassNode, YARP::ModuleNode
+ node.constant_path.slice
end
end
end
diff --git a/lib/ruby_lsp/requests/support/selection_range.rb b/lib/ruby_lsp/requests/support/selection_range.rb
index 4474c9421..8e0b59cac 100644
--- a/lib/ruby_lsp/requests/support/selection_range.rb
+++ b/lib/ruby_lsp/requests/support/selection_range.rb
@@ -9,10 +9,11 @@ class SelectionRange < Interface::SelectionRange
sig { params(position: Document::PositionShape).returns(T::Boolean) }
def cover?(position)
- line_range = (range.start.line..range.end.line)
- character_range = (range.start.character..range.end.character)
-
- line_range.cover?(position[:line]) && character_range.cover?(position[:character])
+ start_covered = range.start.line < position[:line] ||
+ (range.start.line == position[:line] && range.start.character <= position[:character])
+ end_covered = range.end.line > position[:line] ||
+ (range.end.line == position[:line] && range.end.character >= position[:character])
+ start_covered && end_covered
end
end
end
diff --git a/lib/ruby_lsp/requests/support/sorbet.rb b/lib/ruby_lsp/requests/support/sorbet.rb
index 9ff9871a7..1dcd96e5c 100644
--- a/lib/ruby_lsp/requests/support/sorbet.rb
+++ b/lib/ruby_lsp/requests/support/sorbet.rb
@@ -42,66 +42,11 @@ class << self
sig do
params(
- node: T.any(SyntaxTree::CallNode, SyntaxTree::VCall),
+ node: YARP::CallNode,
).returns(T::Boolean)
end
def annotation?(node)
- annotation = annotation(node)
-
- return false if annotation.nil?
-
- return false unless annotation.supports_receiver?(receiver_name(node))
-
- annotation.supports_arity?(node.arity)
- end
-
- private
-
- sig { params(node: T.any(SyntaxTree::CallNode, SyntaxTree::VCall)).returns(T.nilable(Annotation)) }
- def annotation(node)
- case node
- when SyntaxTree::VCall
- ANNOTATIONS[node.value.value]
- when SyntaxTree::CallNode
- message = node.message
- ANNOTATIONS[message.value] unless message.is_a?(Symbol)
- else
- T.absurd(node)
- end
- end
-
- sig do
- params(receiver: T.any(SyntaxTree::CallNode, SyntaxTree::VCall)).returns(T.nilable(String))
- end
- def receiver_name(receiver)
- case receiver
- when SyntaxTree::CallNode
- node_name(receiver.receiver)
- when SyntaxTree::VCall
- nil
- else
- T.absurd(receiver)
- end
- end
-
- sig do
- params(node: T.nilable(SyntaxTree::Node)).returns(T.nilable(String))
- end
- def node_name(node)
- case node
- when SyntaxTree::VarRef
- node.value.value
- when SyntaxTree::CallNode
- node_name(node.receiver)
- when SyntaxTree::VCall
- node_name(node.value)
- when SyntaxTree::Ident, SyntaxTree::Backtick, SyntaxTree::Const, SyntaxTree::Op
- node.value
- when NilClass, SyntaxTree::Node
- nil
- else
- T.absurd(node)
- end
+ !!ANNOTATIONS[node.name]&.match?(node)
end
end
end
diff --git a/ruby-lsp.gemspec b/ruby-lsp.gemspec
index 391dccf23..35eb8065b 100644
--- a/ruby-lsp.gemspec
+++ b/ruby-lsp.gemspec
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
s.add_dependency("language_server-protocol", "~> 3.17.0")
s.add_dependency("sorbet-runtime")
s.add_dependency("syntax_tree", ">= 6.1.1", "< 7")
- s.add_dependency("yarp", ">= 0.11", "< 0.12")
+ s.add_dependency("yarp", ">= 0.12", "< 0.13")
s.required_ruby_version = ">= 3.0"
end
diff --git a/sorbet/rbi/gems/diff-lcs@1.5.0.rbi b/sorbet/rbi/gems/diff-lcs@1.5.0.rbi
deleted file mode 100644
index 4e1f79154..000000000
--- a/sorbet/rbi/gems/diff-lcs@1.5.0.rbi
+++ /dev/null
@@ -1,1083 +0,0 @@
-# typed: true
-
-# DO NOT EDIT MANUALLY
-# This is an autogenerated file for types exported from the `diff-lcs` gem.
-# Please instead update this file by running `bin/tapioca gem diff-lcs`.
-
-# source://diff-lcs//lib/diff/lcs.rb#3
-module Diff; end
-
-# source://diff-lcs//lib/diff/lcs.rb#51
-module Diff::LCS
- # Returns the difference set between +self+ and +other+. See Diff::LCS#diff.
- #
- # source://diff-lcs//lib/diff/lcs.rb#75
- def diff(other, callbacks = T.unsafe(nil), &block); end
-
- # Returns an Array containing the longest common subsequence(s) between
- # +self+ and +other+. See Diff::LCS#lcs.
- #
- # lcs = seq1.lcs(seq2)
- #
- # A note when using objects: Diff::LCS only works properly when each object
- # can be used as a key in a Hash, which typically means that the objects must
- # implement Object#eql? in a way that two identical values compare
- # identically for key purposes. That is:
- #
- # O.new('a').eql?(O.new('a')) == true
- #
- # source://diff-lcs//lib/diff/lcs.rb#70
- def lcs(other, &block); end
-
- # Attempts to patch +self+ with the provided +patchset+. A new sequence based
- # on +self+ and the +patchset+ will be created. See Diff::LCS#patch. Attempts
- # to autodiscover the direction of the patch.
- #
- # source://diff-lcs//lib/diff/lcs.rb#101
- def patch(patchset); end
-
- # Attempts to patch +self+ with the provided +patchset+. A new sequence based
- # on +self+ and the +patchset+ will be created. See Diff::LCS#patch. Does no
- # patch direction autodiscovery.
- #
- # source://diff-lcs//lib/diff/lcs.rb#109
- def patch!(patchset); end
-
- # Attempts to patch +self+ with the provided +patchset+, using #patch!. If
- # the sequence this is used on supports #replace, the value of +self+ will be
- # replaced. See Diff::LCS#patch. Does no patch direction autodiscovery.
- #
- # source://diff-lcs//lib/diff/lcs.rb#123
- def patch_me(patchset); end
-
- # Returns the balanced ("side-by-side") difference set between +self+ and
- # +other+. See Diff::LCS#sdiff.
- #
- # source://diff-lcs//lib/diff/lcs.rb#81
- def sdiff(other, callbacks = T.unsafe(nil), &block); end
-
- # Traverses the discovered longest common subsequences between +self+ and
- # +other+ using the alternate, balanced algorithm. See
- # Diff::LCS#traverse_balanced.
- #
- # source://diff-lcs//lib/diff/lcs.rb#94
- def traverse_balanced(other, callbacks = T.unsafe(nil), &block); end
-
- # Traverses the discovered longest common subsequences between +self+ and
- # +other+. See Diff::LCS#traverse_sequences.
- #
- # source://diff-lcs//lib/diff/lcs.rb#87
- def traverse_sequences(other, callbacks = T.unsafe(nil), &block); end
-
- # Attempts to patch +self+ with the provided +patchset+. A new sequence based
- # on +self+ and the +patchset+ will be created. See Diff::LCS#patch. Attempts
- # to autodiscover the direction of the patch.
- #
- # source://diff-lcs//lib/diff/lcs.rb#101
- def unpatch(patchset); end
-
- # Attempts to unpatch +self+ with the provided +patchset+. A new sequence
- # based on +self+ and the +patchset+ will be created. See Diff::LCS#unpatch.
- # Does no patch direction autodiscovery.
- #
- # source://diff-lcs//lib/diff/lcs.rb#116
- def unpatch!(patchset); end
-
- # Attempts to unpatch +self+ with the provided +patchset+, using #unpatch!.
- # If the sequence this is used on supports #replace, the value of +self+ will
- # be replaced. See Diff::LCS#unpatch. Does no patch direction autodiscovery.
- #
- # source://diff-lcs//lib/diff/lcs.rb#134
- def unpatch_me(patchset); end
-
- class << self
- # :yields seq1[i] for each matched:
- #
- # source://diff-lcs//lib/diff/lcs.rb#144
- def LCS(seq1, seq2, &block); end
-
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#52
- def callbacks_for(callbacks); end
-
- # #diff computes the smallest set of additions and deletions necessary to
- # turn the first sequence into the second, and returns a description of these
- # changes.
- #
- # See Diff::LCS::DiffCallbacks for the default behaviour. An alternate
- # behaviour may be implemented with Diff::LCS::ContextDiffCallbacks. If a
- # Class argument is provided for +callbacks+, #diff will attempt to
- # initialise it. If the +callbacks+ object (possibly initialised) responds to
- # #finish, it will be called.
- #
- # source://diff-lcs//lib/diff/lcs.rb#168
- def diff(seq1, seq2, callbacks = T.unsafe(nil), &block); end
-
- # :yields seq1[i] for each matched:
- #
- # source://diff-lcs//lib/diff/lcs.rb#144
- def lcs(seq1, seq2, &block); end
-
- # Applies a +patchset+ to the sequence +src+ according to the +direction+
- # (:patch or :unpatch), producing a new sequence.
- #
- # If the +direction+ is not specified, Diff::LCS::patch will attempt to
- # discover the direction of the +patchset+.
- #
- # A +patchset+ can be considered to apply forward (:patch) if the
- # following expression is true:
- #
- # patch(s1, diff(s1, s2)) -> s2
- #
- # A +patchset+ can be considered to apply backward (:unpatch) if the
- # following expression is true:
- #
- # patch(s2, diff(s1, s2)) -> s1
- #
- # If the +patchset+ contains no changes, the +src+ value will be returned as
- # either src.dup or +src+. A +patchset+ can be deemed as having no
- # changes if the following predicate returns true:
- #
- # patchset.empty? or
- # patchset.flatten(1).all? { |change| change.unchanged? }
- #
- # === Patchsets
- #
- # A +patchset+ is always an enumerable sequence of changes, hunks of changes,
- # or a mix of the two. A hunk of changes is an enumerable sequence of
- # changes:
- #
- # [ # patchset
- # # change
- # [ # hunk
- # # change
- # ]
- # ]
- #
- # The +patch+ method accepts patchsets that are enumerable sequences
- # containing either Diff::LCS::Change objects (or a subclass) or the array
- # representations of those objects. Prior to application, array
- # representations of Diff::LCS::Change objects will be reified.
- #
- # source://diff-lcs//lib/diff/lcs.rb#624
- def patch(src, patchset, direction = T.unsafe(nil)); end
-
- # Given a set of patchset, convert the current version to the next version.
- # Does no auto-discovery.
- #
- # source://diff-lcs//lib/diff/lcs.rb#734
- def patch!(src, patchset); end
-
- # #sdiff computes all necessary components to show two sequences and their
- # minimized differences side by side, just like the Unix utility
- # sdiff does:
- #
- # old < -
- # same same
- # before | after
- # - > new
- #
- # See Diff::LCS::SDiffCallbacks for the default behaviour. An alternate
- # behaviour may be implemented with Diff::LCS::ContextDiffCallbacks. If a
- # Class argument is provided for +callbacks+, #diff will attempt to
- # initialise it. If the +callbacks+ object (possibly initialised) responds to
- # #finish, it will be called.
- #
- # Each element of a returned array is a Diff::LCS::ContextChange object,
- # which can be implicitly converted to an array.
- #
- # Diff::LCS.sdiff(a, b).each do |action, (old_pos, old_element), (new_pos, new_element)|
- # case action
- # when '!'
- # # replace
- # when '-'
- # # delete
- # when '+'
- # # insert
- # end
- # end
- #
- # source://diff-lcs//lib/diff/lcs.rb#200
- def sdiff(seq1, seq2, callbacks = T.unsafe(nil), &block); end
-
- # #traverse_balanced is an alternative to #traverse_sequences. It uses a
- # different algorithm to iterate through the entries in the computed longest
- # common subsequence. Instead of viewing the changes as insertions or
- # deletions from one of the sequences, #traverse_balanced will report
- # changes between the sequences.
- #
- # The arguments to #traverse_balanced are the two sequences to traverse and a
- # callback object, like this:
- #
- # traverse_balanced(seq1, seq2, Diff::LCS::ContextDiffCallbacks.new)
- #
- # #sdiff is implemented with #traverse_balanced.
- #
- # == Callback Methods
- #
- # Optional callback methods are emphasized.
- #
- # callbacks#match:: Called when +a+ and +b+ are pointing to
- # common elements in +A+ and +B+.
- # callbacks#discard_a:: Called when +a+ is pointing to an
- # element not in +B+.
- # callbacks#discard_b:: Called when +b+ is pointing to an
- # element not in +A+.
- # callbacks#change:: Called when +a+ and +b+ are pointing to
- # the same relative position, but
- # A[a] and B[b] are not
- # the same; a change has
- # occurred.
- #
- # #traverse_balanced might be a bit slower than #traverse_sequences,
- # noticable only while processing huge amounts of data.
- #
- # == Algorithm
- #
- # a---+
- # v
- # A = a b c e h j l m n p
- # B = b c d e f j k l m r s t
- # ^
- # b---+
- #
- # === Matches
- #
- # If there are two arrows (+a+ and +b+) pointing to elements of sequences +A+
- # and +B+, the arrows will initially point to the first elements of their
- # respective sequences. #traverse_sequences will advance the arrows through
- # the sequences one element at a time, calling a method on the user-specified
- # callback object before each advance. It will advance the arrows in such a
- # way that if there are elements A[i] and B[j] which are
- # both equal and part of the longest common subsequence, there will be some
- # moment during the execution of #traverse_sequences when arrow +a+ is
- # pointing to A[i] and arrow +b+ is pointing to B[j]. When
- # this happens, #traverse_sequences will call callbacks#match and
- # then it will advance both arrows.
- #
- # === Discards
- #
- # Otherwise, one of the arrows is pointing to an element of its sequence that
- # is not part of the longest common subsequence. #traverse_sequences will
- # advance that arrow and will call callbacks#discard_a or
- # callbacks#discard_b, depending on which arrow it advanced.
- #
- # === Changes
- #
- # If both +a+ and +b+ point to elements that are not part of the longest
- # common subsequence, then #traverse_sequences will try to call
- # callbacks#change and advance both arrows. If
- # callbacks#change is not implemented, then
- # callbacks#discard_a and callbacks#discard_b will be
- # called in turn.
- #
- # The methods for callbacks#match, callbacks#discard_a,
- # callbacks#discard_b, and callbacks#change are invoked
- # with an event comprising the action ("=", "+", "-", or "!", respectively),
- # the indicies +i+ and +j+, and the elements A[i] and B[j].
- # Return values are discarded by #traverse_balanced.
- #
- # === Context
- #
- # Note that +i+ and +j+ may not be the same index position, even if +a+ and
- # +b+ are considered to be pointing to matching or changed elements.
- #
- # source://diff-lcs//lib/diff/lcs.rb#475
- def traverse_balanced(seq1, seq2, callbacks = T.unsafe(nil)); end
-
- # #traverse_sequences is the most general facility provided by this module;
- # #diff and #lcs are implemented as calls to it.
- #
- # The arguments to #traverse_sequences are the two sequences to traverse, and
- # a callback object, like this:
- #
- # traverse_sequences(seq1, seq2, Diff::LCS::ContextDiffCallbacks.new)
- #
- # == Callback Methods
- #
- # Optional callback methods are emphasized.
- #
- # callbacks#match:: Called when +a+ and +b+ are pointing to
- # common elements in +A+ and +B+.
- # callbacks#discard_a:: Called when +a+ is pointing to an
- # element not in +B+.
- # callbacks#discard_b:: Called when +b+ is pointing to an
- # element not in +A+.
- # callbacks#finished_a:: Called when +a+ has reached the end of
- # sequence +A+.
- # callbacks#finished_b:: Called when +b+ has reached the end of
- # sequence +B+.
- #
- # == Algorithm
- #
- # a---+
- # v
- # A = a b c e h j l m n p
- # B = b c d e f j k l m r s t
- # ^
- # b---+
- #
- # If there are two arrows (+a+ and +b+) pointing to elements of sequences +A+
- # and +B+, the arrows will initially point to the first elements of their
- # respective sequences. #traverse_sequences will advance the arrows through
- # the sequences one element at a time, calling a method on the user-specified
- # callback object before each advance. It will advance the arrows in such a
- # way that if there are elements A[i] and B[j] which are
- # both equal and part of the longest common subsequence, there will be some
- # moment during the execution of #traverse_sequences when arrow +a+ is
- # pointing to A[i] and arrow +b+ is pointing to B[j]. When
- # this happens, #traverse_sequences will call callbacks#match and
- # then it will advance both arrows.
- #
- # Otherwise, one of the arrows is pointing to an element of its sequence that
- # is not part of the longest common subsequence. #traverse_sequences will
- # advance that arrow and will call callbacks#discard_a or
- # callbacks#discard_b, depending on which arrow it advanced. If both
- # arrows point to elements that are not part of the longest common
- # subsequence, then #traverse_sequences will advance arrow +a+ and call the
- # appropriate callback, then it will advance arrow +b+ and call the appropriate
- # callback.
- #
- # The methods for callbacks#match, callbacks#discard_a, and
- # callbacks#discard_b are invoked with an event comprising the
- # action ("=", "+", or "-", respectively), the indicies +i+ and +j+, and the
- # elements A[i] and B[j]. Return values are discarded by
- # #traverse_sequences.
- #
- # === End of Sequences
- #
- # If arrow +a+ reaches the end of its sequence before arrow +b+ does,
- # #traverse_sequence will try to call callbacks#finished_a with the
- # last index and element of +A+ (A[-1]) and the current index and
- # element of +B+ (B[j]). If callbacks#finished_a does not
- # exist, then callbacks#discard_b will be called on each element of
- # +B+ until the end of the sequence is reached (the call will be done with
- # A[-1] and B[j] for each element).
- #
- # If +b+ reaches the end of +B+ before +a+ reaches the end of +A+,
- # callbacks#finished_b will be called with the current index and
- # element of +A+ (A[i]) and the last index and element of +B+
- # (A[-1]). Again, if callbacks#finished_b does not exist on
- # the callback object, then callbacks#discard_a will be called on
- # each element of +A+ until the end of the sequence is reached (A[i]
- # and B[-1]).
- #
- # There is a chance that one additional callbacks#discard_a or
- # callbacks#discard_b will be called after the end of the sequence
- # is reached, if +a+ has not yet reached the end of +A+ or +b+ has not yet
- # reached the end of +B+.
- #
- # source://diff-lcs//lib/diff/lcs.rb#285
- def traverse_sequences(seq1, seq2, callbacks = T.unsafe(nil)); end
-
- # Given a set of patchset, convert the current version to the prior version.
- # Does no auto-discovery.
- #
- # source://diff-lcs//lib/diff/lcs.rb#728
- def unpatch!(src, patchset); end
-
- private
-
- # source://diff-lcs//lib/diff/lcs/internals.rb#4
- def diff_traversal(method, seq1, seq2, callbacks, &block); end
- end
-end
-
-# An alias for DefaultCallbacks that is used in
-# Diff::LCS#traverse_balanced.
-#
-# Diff::LCS.LCS(seq1, seq2, Diff::LCS::BalancedCallbacks)
-#
-# source://diff-lcs//lib/diff/lcs/callbacks.rb#50
-Diff::LCS::BalancedCallbacks = Diff::LCS::DefaultCallbacks
-
-# A block is an operation removing, adding, or changing a group of items.
-# Basically, this is just a list of changes, where each change adds or
-# deletes a single item. Used by bin/ldiff.
-#
-# source://diff-lcs//lib/diff/lcs/block.rb#6
-class Diff::LCS::Block
- # @return [Block] a new instance of Block
- #
- # source://diff-lcs//lib/diff/lcs/block.rb#9
- def initialize(chunk); end
-
- # Returns the value of attribute changes.
- #
- # source://diff-lcs//lib/diff/lcs/block.rb#7
- def changes; end
-
- # source://diff-lcs//lib/diff/lcs/block.rb#21
- def diff_size; end
-
- # Returns the value of attribute insert.
- #
- # source://diff-lcs//lib/diff/lcs/block.rb#7
- def insert; end
-
- # source://diff-lcs//lib/diff/lcs/block.rb#25
- def op; end
-
- # Returns the value of attribute remove.
- #
- # source://diff-lcs//lib/diff/lcs/block.rb#7
- def remove; end
-end
-
-# Represents a simplistic (non-contextual) change. Represents the removal or
-# addition of an element from either the old or the new sequenced
-# enumerable.
-#
-# source://diff-lcs//lib/diff/lcs/change.rb#6
-class Diff::LCS::Change
- include ::Comparable
-
- # @return [Change] a new instance of Change
- #
- # source://diff-lcs//lib/diff/lcs/change.rb#27
- def initialize(*args); end
-
- # source://diff-lcs//lib/diff/lcs/change.rb#65
- def <=>(other); end
-
- # source://diff-lcs//lib/diff/lcs/change.rb#58
- def ==(other); end
-
- # Returns the action this Change represents.
- #
- # source://diff-lcs//lib/diff/lcs/change.rb#20
- def action; end
-
- # @return [Boolean]
- #
- # source://diff-lcs//lib/diff/lcs/change.rb#72
- def adding?; end
-
- # @return [Boolean]
- #
- # source://diff-lcs//lib/diff/lcs/change.rb#84
- def changed?; end
-
- # @return [Boolean]
- #
- # source://diff-lcs//lib/diff/lcs/change.rb#76
- def deleting?; end
-
- # Returns the sequence element of the Change.
- #
- # source://diff-lcs//lib/diff/lcs/change.rb#25
- def element; end
-
- # @return [Boolean]
- #
- # source://diff-lcs//lib/diff/lcs/change.rb#88
- def finished_a?; end
-
- # @return [Boolean]
- #
- # source://diff-lcs//lib/diff/lcs/change.rb#92
- def finished_b?; end
-
- # source://diff-lcs//lib/diff/lcs/change.rb#34
- def inspect(*_args); end
-
- # Returns the position of the Change.
- #
- # source://diff-lcs//lib/diff/lcs/change.rb#23
- def position; end
-
- # source://diff-lcs//lib/diff/lcs/change.rb#38
- def to_a; end
-
- # source://diff-lcs//lib/diff/lcs/change.rb#38
- def to_ary; end
-
- # @return [Boolean]
- #
- # source://diff-lcs//lib/diff/lcs/change.rb#80
- def unchanged?; end
-
- class << self
- # source://diff-lcs//lib/diff/lcs/change.rb#44
- def from_a(arr); end
-
- # @return [Boolean]
- #
- # source://diff-lcs//lib/diff/lcs/change.rb#15
- def valid_action?(action); end
- end
-end
-
-# source://diff-lcs//lib/diff/lcs/change.rb#7
-Diff::LCS::Change::IntClass = Integer
-
-# The only actions valid for changes are '+' (add), '-' (delete), '='
-# (no change), '!' (changed), '<' (tail changes from first sequence), or
-# '>' (tail changes from second sequence). The last two ('<>') are only
-# found with Diff::LCS::diff and Diff::LCS::sdiff.
-#
-# source://diff-lcs//lib/diff/lcs/change.rb#13
-Diff::LCS::Change::VALID_ACTIONS = T.let(T.unsafe(nil), Array)
-
-# Represents a contextual change. Contains the position and values of the
-# elements in the old and the new sequenced enumerables as well as the action
-# taken.
-#
-# source://diff-lcs//lib/diff/lcs/change.rb#100
-class Diff::LCS::ContextChange < ::Diff::LCS::Change
- # @return [ContextChange] a new instance of ContextChange
- #
- # source://diff-lcs//lib/diff/lcs/change.rb#114
- def initialize(*args); end
-
- # source://diff-lcs//lib/diff/lcs/change.rb#166
- def <=>(other); end
-
- # source://diff-lcs//lib/diff/lcs/change.rb#157
- def ==(other); end
-
- # Returns the new element being changed.
- #
- # source://diff-lcs//lib/diff/lcs/change.rb#112
- def new_element; end
-
- # Returns the new position being changed.
- #
- # source://diff-lcs//lib/diff/lcs/change.rb#108
- def new_position; end
-
- # Returns the old element being changed.
- #
- # source://diff-lcs//lib/diff/lcs/change.rb#110
- def old_element; end
-
- # Returns the old position being changed.
- #
- # source://diff-lcs//lib/diff/lcs/change.rb#106
- def old_position; end
-
- # source://diff-lcs//lib/diff/lcs/change.rb#122
- def to_a; end
-
- # source://diff-lcs//lib/diff/lcs/change.rb#122
- def to_ary; end
-
- class << self
- # source://diff-lcs//lib/diff/lcs/change.rb#132
- def from_a(arr); end
-
- # Simplifies a context change for use in some diff callbacks. '<' actions
- # are converted to '-' and '>' actions are converted to '+'.
- #
- # source://diff-lcs//lib/diff/lcs/change.rb#138
- def simplify(event); end
- end
-end
-
-# This will produce a compound array of contextual diff change objects. Each
-# element in the #diffs array is a "hunk" array, where each element in each
-# "hunk" array is a single change. Each change is a Diff::LCS::ContextChange
-# that contains both the old index and new index values for the change. The
-# "hunk" provides the full context for the changes. Both old and new objects
-# will be presented for changed objects. +nil+ will be substituted for a
-# discarded object.
-#
-# seq1 = %w(a b c e h j l m n p)
-# seq2 = %w(b c d e f j k l m r s t)
-#
-# diffs = Diff::LCS.diff(seq1, seq2, Diff::LCS::ContextDiffCallbacks)
-# # This example shows a simplified array format.
-# # [ [ [ '-', [ 0, 'a' ], [ 0, nil ] ] ], # 1
-# # [ [ '+', [ 3, nil ], [ 2, 'd' ] ] ], # 2
-# # [ [ '-', [ 4, 'h' ], [ 4, nil ] ], # 3
-# # [ '+', [ 5, nil ], [ 4, 'f' ] ] ],
-# # [ [ '+', [ 6, nil ], [ 6, 'k' ] ] ], # 4
-# # [ [ '-', [ 8, 'n' ], [ 9, nil ] ], # 5
-# # [ '+', [ 9, nil ], [ 9, 'r' ] ],
-# # [ '-', [ 9, 'p' ], [ 10, nil ] ],
-# # [ '+', [ 10, nil ], [ 10, 's' ] ],
-# # [ '+', [ 10, nil ], [ 11, 't' ] ] ] ]
-#
-# The five hunks shown are comprised of individual changes; if there is a
-# related set of changes, they are still shown individually.
-#
-# This callback can also be used with Diff::LCS#sdiff, which will produce
-# results like:
-#
-# diffs = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextCallbacks)
-# # This example shows a simplified array format.
-# # [ [ [ "-", [ 0, "a" ], [ 0, nil ] ] ], # 1
-# # [ [ "+", [ 3, nil ], [ 2, "d" ] ] ], # 2
-# # [ [ "!", [ 4, "h" ], [ 4, "f" ] ] ], # 3
-# # [ [ "+", [ 6, nil ], [ 6, "k" ] ] ], # 4
-# # [ [ "!", [ 8, "n" ], [ 9, "r" ] ], # 5
-# # [ "!", [ 9, "p" ], [ 10, "s" ] ],
-# # [ "+", [ 10, nil ], [ 11, "t" ] ] ] ]
-#
-# The five hunks are still present, but are significantly shorter in total
-# presentation, because changed items are shown as changes ("!") instead of
-# potentially "mismatched" pairs of additions and deletions.
-#
-# The result of this operation is similar to that of
-# Diff::LCS::SDiffCallbacks. They may be compared as:
-#
-# s = Diff::LCS.sdiff(seq1, seq2).reject { |e| e.action == "=" }
-# c = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextDiffCallbacks).flatten(1)
-#
-# s == c # -> true
-#
-# === Use
-#
-# This callback object must be initialised and can be used by the
-# Diff::LCS#diff or Diff::LCS#sdiff methods.
-#
-# cbo = Diff::LCS::ContextDiffCallbacks.new
-# Diff::LCS.LCS(seq1, seq2, cbo)
-# cbo.finish
-#
-# Note that the call to #finish is absolutely necessary, or the last set of
-# changes will not be visible. Alternatively, can be used as:
-#
-# cbo = Diff::LCS::ContextDiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) }
-#
-# The necessary #finish call will be made.
-#
-# === Simplified Array Format
-#
-# The simplified array format used in the example above can be obtained
-# with:
-#
-# require 'pp'
-# pp diffs.map { |e| e.map { |f| f.to_a } }
-#
-# source://diff-lcs//lib/diff/lcs/callbacks.rb#223
-class Diff::LCS::ContextDiffCallbacks < ::Diff::LCS::DiffCallbacks
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#232
- def change(event); end
-
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#224
- def discard_a(event); end
-
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#228
- def discard_b(event); end
-end
-
-# This callback object implements the default set of callback events,
-# which only returns the event itself. Note that #finished_a and
-# #finished_b are not implemented -- I haven't yet figured out where they
-# would be useful.
-#
-# Note that this is intended to be called as is, e.g.,
-#
-# Diff::LCS.LCS(seq1, seq2, Diff::LCS::DefaultCallbacks)
-#
-# source://diff-lcs//lib/diff/lcs/callbacks.rb#14
-class Diff::LCS::DefaultCallbacks
- class << self
- # Called when both the old and new values have changed.
- #
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#32
- def change(event); end
-
- # Called when the old value is discarded in favour of the new value.
- #
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#22
- def discard_a(event); end
-
- # Called when the new value is discarded in favour of the old value.
- #
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#27
- def discard_b(event); end
-
- # Called when two items match.
- #
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#17
- def match(event); end
-
- private
-
- def new(*_arg0); end
- end
-end
-
-# This will produce a compound array of simple diff change objects. Each
-# element in the #diffs array is a +hunk+ or +hunk+ array, where each
-# element in each +hunk+ array is a single Change object representing the
-# addition or removal of a single element from one of the two tested
-# sequences. The +hunk+ provides the full context for the changes.
-#
-# diffs = Diff::LCS.diff(seq1, seq2)
-# # This example shows a simplified array format.
-# # [ [ [ '-', 0, 'a' ] ], # 1
-# # [ [ '+', 2, 'd' ] ], # 2
-# # [ [ '-', 4, 'h' ], # 3
-# # [ '+', 4, 'f' ] ],
-# # [ [ '+', 6, 'k' ] ], # 4
-# # [ [ '-', 8, 'n' ], # 5
-# # [ '-', 9, 'p' ],
-# # [ '+', 9, 'r' ],
-# # [ '+', 10, 's' ],
-# # [ '+', 11, 't' ] ] ]
-#
-# There are five hunks here. The first hunk says that the +a+ at position 0
-# of the first sequence should be deleted ('-'). The second hunk
-# says that the +d+ at position 2 of the second sequence should be inserted
-# ('+'). The third hunk says that the +h+ at position 4 of the
-# first sequence should be removed and replaced with the +f+ from position 4
-# of the second sequence. The other two hunks are described similarly.
-#
-# === Use
-#
-# This callback object must be initialised and is used by the Diff::LCS#diff
-# method.
-#
-# cbo = Diff::LCS::DiffCallbacks.new
-# Diff::LCS.LCS(seq1, seq2, cbo)
-# cbo.finish
-#
-# Note that the call to #finish is absolutely necessary, or the last set of
-# changes will not be visible. Alternatively, can be used as:
-#
-# cbo = Diff::LCS::DiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) }
-#
-# The necessary #finish call will be made.
-#
-# === Simplified Array Format
-#
-# The simplified array format used in the example above can be obtained
-# with:
-#
-# require 'pp'
-# pp diffs.map { |e| e.map { |f| f.to_a } }
-#
-# source://diff-lcs//lib/diff/lcs/callbacks.rb#106
-class Diff::LCS::DiffCallbacks
- # :yields self:
- #
- # @return [DiffCallbacks] a new instance of DiffCallbacks
- #
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#110
- def initialize; end
-
- # Returns the difference set collected during the diff process.
- #
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#108
- def diffs; end
-
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#133
- def discard_a(event); end
-
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#137
- def discard_b(event); end
-
- # Finalizes the diff process. If an unprocessed hunk still exists, then it
- # is appended to the diff list.
- #
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#125
- def finish; end
-
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#129
- def match(_event); end
-
- private
-
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#141
- def finish_hunk; end
-end
-
-# A Hunk is a group of Blocks which overlap because of the context surrounding
-# each block. (So if we're not using context, every hunk will contain one
-# block.) Used in the diff program (bin/ldiff).
-#
-# source://diff-lcs//lib/diff/lcs/hunk.rb#8
-class Diff::LCS::Hunk
- # Create a hunk using references to both the old and new data, as well as the
- # piece of data.
- #
- # @return [Hunk] a new instance of Hunk
- #
- # source://diff-lcs//lib/diff/lcs/hunk.rb#16
- def initialize(data_old, data_new, piece, flag_context, file_length_difference); end
-
- # Returns the value of attribute blocks.
- #
- # source://diff-lcs//lib/diff/lcs/hunk.rb#63
- def blocks; end
-
- # Returns a diff string based on a format.
- #
- # source://diff-lcs//lib/diff/lcs/hunk.rb#116
- def diff(format, last = T.unsafe(nil)); end
-
- # Returns the value of attribute end_new.
- #
- # source://diff-lcs//lib/diff/lcs/hunk.rb#65
- def end_new; end
-
- # Returns the value of attribute end_old.
- #
- # source://diff-lcs//lib/diff/lcs/hunk.rb#65
- def end_old; end
-
- # Returns the value of attribute file_length_difference.
- #
- # source://diff-lcs//lib/diff/lcs/hunk.rb#66
- def file_length_difference; end
-
- # Change the "start" and "end" fields to note that context should be added
- # to this hunk.
- #
- # source://diff-lcs//lib/diff/lcs/hunk.rb#70
- def flag_context; end
-
- # source://diff-lcs//lib/diff/lcs/hunk.rb#72
- def flag_context=(context); end
-
- # Merges this hunk and the provided hunk together if they overlap. Returns
- # a truthy value so that if there is no overlap, you can know the merge
- # was skipped.
- #
- # source://diff-lcs//lib/diff/lcs/hunk.rb#98
- def merge(hunk); end
-
- # @return [Boolean]
- #
- # source://diff-lcs//lib/diff/lcs/hunk.rb#326
- def missing_last_newline?(data); end
-
- # Determines whether there is an overlap between this hunk and the
- # provided hunk. This will be true if the difference between the two hunks
- # start or end positions is within one position of each other.
- #
- # @return [Boolean]
- #
- # source://diff-lcs//lib/diff/lcs/hunk.rb#110
- def overlaps?(hunk); end
-
- # Returns the value of attribute start_new.
- #
- # source://diff-lcs//lib/diff/lcs/hunk.rb#64
- def start_new; end
-
- # Returns the value of attribute start_old.
- #
- # source://diff-lcs//lib/diff/lcs/hunk.rb#64
- def start_old; end
-
- # Merges this hunk and the provided hunk together if they overlap. Returns
- # a truthy value so that if there is no overlap, you can know the merge
- # was skipped.
- #
- # source://diff-lcs//lib/diff/lcs/hunk.rb#98
- def unshift(hunk); end
-
- private
-
- # source://diff-lcs//lib/diff/lcs/hunk.rb#213
- def context_diff(last = T.unsafe(nil)); end
-
- # Generate a range of item numbers to print. Only print 1 number if the
- # range has only one item in it. Otherwise, it's 'start,end'
- #
- # source://diff-lcs//lib/diff/lcs/hunk.rb#293
- def context_range(mode, op, last = T.unsafe(nil)); end
-
- # source://diff-lcs//lib/diff/lcs/hunk.rb#271
- def ed_diff(format, _last = T.unsafe(nil)); end
-
- # source://diff-lcs//lib/diff/lcs/hunk.rb#339
- def encode(literal, target_encoding = T.unsafe(nil)); end
-
- # source://diff-lcs//lib/diff/lcs/hunk.rb#343
- def encode_as(string, *args); end
-
- # Note that an old diff can't have any context. Therefore, we know that
- # there's only one block in the hunk.
- #
- # source://diff-lcs//lib/diff/lcs/hunk.rb#135
- def old_diff(_last = T.unsafe(nil)); end
-
- # source://diff-lcs//lib/diff/lcs/hunk.rb#160
- def unified_diff(last = T.unsafe(nil)); end
-
- # Generate a range of item numbers to print for unified diff. Print number
- # where block starts, followed by number of lines in the block
- # (don't print number of lines if it's 1)
- #
- # source://diff-lcs//lib/diff/lcs/hunk.rb#311
- def unified_range(mode, last); end
-end
-
-# source://diff-lcs//lib/diff/lcs/hunk.rb#10
-Diff::LCS::Hunk::ED_DIFF_OP_ACTION = T.let(T.unsafe(nil), Hash)
-
-# source://diff-lcs//lib/diff/lcs/hunk.rb#9
-Diff::LCS::Hunk::OLD_DIFF_OP_ACTION = T.let(T.unsafe(nil), Hash)
-
-# source://diff-lcs//lib/diff/lcs/internals.rb#29
-module Diff::LCS::Internals
- class << self
- # This method will analyze the provided patchset to provide a single-pass
- # normalization (conversion of the array form of Diff::LCS::Change objects to
- # the object form of same) and detection of whether the patchset represents
- # changes to be made.
- #
- # source://diff-lcs//lib/diff/lcs/internals.rb#102
- def analyze_patchset(patchset, depth = T.unsafe(nil)); end
-
- # Examine the patchset and the source to see in which direction the
- # patch should be applied.
- #
- # WARNING: By default, this examines the whole patch, so this could take
- # some time. This also works better with Diff::LCS::ContextChange or
- # Diff::LCS::Change as its source, as an array will cause the creation
- # of one of the above.
- #
- # source://diff-lcs//lib/diff/lcs/internals.rb#147
- def intuit_diff_direction(src, patchset, limit = T.unsafe(nil)); end
-
- # Compute the longest common subsequence between the sequenced
- # Enumerables +a+ and +b+. The result is an array whose contents is such
- # that
- #
- # result = Diff::LCS::Internals.lcs(a, b)
- # result.each_with_index do |e, i|
- # assert_equal(a[i], b[e]) unless e.nil?
- # end
- #
- # source://diff-lcs//lib/diff/lcs/internals.rb#41
- def lcs(a, b); end
-
- private
-
- # If +vector+ maps the matching elements of another collection onto this
- # Enumerable, compute the inverse of +vector+ that maps this Enumerable
- # onto the collection. (Currently unused.)
- #
- # source://diff-lcs//lib/diff/lcs/internals.rb#286
- def inverse_vector(a, vector); end
-
- # Returns a hash mapping each element of an Enumerable to the set of
- # positions it occupies in the Enumerable, optionally restricted to the
- # elements specified in the range of indexes specified by +interval+.
- #
- # source://diff-lcs//lib/diff/lcs/internals.rb#298
- def position_hash(enum, interval); end
-
- # Find the place at which +value+ would normally be inserted into the
- # Enumerable. If that place is already occupied by +value+, do nothing
- # and return +nil+. If the place does not exist (i.e., it is off the end
- # of the Enumerable), add it to the end. Otherwise, replace the element
- # at that point with +value+. It is assumed that the Enumerable's values
- # are numeric.
- #
- # This operation preserves the sort order.
- #
- # source://diff-lcs//lib/diff/lcs/internals.rb#252
- def replace_next_larger(enum, value, last_index = T.unsafe(nil)); end
- end
-end
-
-# This will produce a simple array of diff change objects. Each element in
-# the #diffs array is a single ContextChange. In the set of #diffs provided
-# by SDiffCallbacks, both old and new objects will be presented for both
-# changed and unchanged objects. +nil+ will be substituted
-# for a discarded object.
-#
-# The diffset produced by this callback, when provided to Diff::LCS#sdiff,
-# will compute and display the necessary components to show two sequences
-# and their minimized differences side by side, just like the Unix utility
-# +sdiff+.
-#
-# same same
-# before | after
-# old < -
-# - > new
-#
-# seq1 = %w(a b c e h j l m n p)
-# seq2 = %w(b c d e f j k l m r s t)
-#
-# diffs = Diff::LCS.sdiff(seq1, seq2)
-# # This example shows a simplified array format.
-# # [ [ "-", [ 0, "a"], [ 0, nil ] ],
-# # [ "=", [ 1, "b"], [ 0, "b" ] ],
-# # [ "=", [ 2, "c"], [ 1, "c" ] ],
-# # [ "+", [ 3, nil], [ 2, "d" ] ],
-# # [ "=", [ 3, "e"], [ 3, "e" ] ],
-# # [ "!", [ 4, "h"], [ 4, "f" ] ],
-# # [ "=", [ 5, "j"], [ 5, "j" ] ],
-# # [ "+", [ 6, nil], [ 6, "k" ] ],
-# # [ "=", [ 6, "l"], [ 7, "l" ] ],
-# # [ "=", [ 7, "m"], [ 8, "m" ] ],
-# # [ "!", [ 8, "n"], [ 9, "r" ] ],
-# # [ "!", [ 9, "p"], [ 10, "s" ] ],
-# # [ "+", [ 10, nil], [ 11, "t" ] ] ]
-#
-# The result of this operation is similar to that of
-# Diff::LCS::ContextDiffCallbacks. They may be compared as:
-#
-# s = Diff::LCS.sdiff(seq1, seq2).reject { |e| e.action == "=" }
-# c = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextDiffCallbacks).flatten(1)
-#
-# s == c # -> true
-#
-# === Use
-#
-# This callback object must be initialised and is used by the Diff::LCS#sdiff
-# method.
-#
-# cbo = Diff::LCS::SDiffCallbacks.new
-# Diff::LCS.LCS(seq1, seq2, cbo)
-#
-# As with the other initialisable callback objects,
-# Diff::LCS::SDiffCallbacks can be initialised with a block. As there is no
-# "fininishing" to be done, this has no effect on the state of the object.
-#
-# cbo = Diff::LCS::SDiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) }
-#
-# === Simplified Array Format
-#
-# The simplified array format used in the example above can be obtained
-# with:
-#
-# require 'pp'
-# pp diffs.map { |e| e.to_a }
-#
-# source://diff-lcs//lib/diff/lcs/callbacks.rb#301
-class Diff::LCS::SDiffCallbacks
- # :yields self:
- #
- # @return [SDiffCallbacks] a new instance of SDiffCallbacks
- # @yield [_self]
- # @yieldparam _self [Diff::LCS::SDiffCallbacks] the object that the method was called on
- #
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#305
- def initialize; end
-
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#322
- def change(event); end
-
- # Returns the difference set collected during the diff process.
- #
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#303
- def diffs; end
-
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#314
- def discard_a(event); end
-
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#318
- def discard_b(event); end
-
- # source://diff-lcs//lib/diff/lcs/callbacks.rb#310
- def match(event); end
-end
-
-# An alias for DefaultCallbacks that is used in
-# Diff::LCS#traverse_sequences.
-#
-# Diff::LCS.LCS(seq1, seq2, Diff::LCS::SequenceCallbacks)
-#
-# source://diff-lcs//lib/diff/lcs/callbacks.rb#44
-Diff::LCS::SequenceCallbacks = Diff::LCS::DefaultCallbacks
-
-# source://diff-lcs//lib/diff/lcs.rb#52
-Diff::LCS::VERSION = T.let(T.unsafe(nil), String)
diff --git a/sorbet/rbi/gems/unparser@0.6.8.rbi b/sorbet/rbi/gems/unparser@0.6.8.rbi
deleted file mode 100644
index 937e27312..000000000
--- a/sorbet/rbi/gems/unparser@0.6.8.rbi
+++ /dev/null
@@ -1,4525 +0,0 @@
-# typed: true
-
-# DO NOT EDIT MANUALLY
-# This is an autogenerated file for types exported from the `unparser` gem.
-# Please instead update this file by running `bin/tapioca gem unparser`.
-
-# Library namespace
-#
-# source://unparser//lib/unparser/equalizer.rb#3
-module Unparser
- class << self
- # Construct a parser buffer from string
- #
- # @param source [String]
- # @return [Parser::Source::Buffer]
- #
- # source://unparser//lib/unparser.rb#147
- def buffer(source, identification = T.unsafe(nil)); end
-
- # Parse string into AST
- #
- # @param source [String]
- # @return [Parser::AST::Node, nil]
- #
- # source://unparser//lib/unparser.rb#105
- def parse(source); end
-
- # Parse string into either syntax error or AST
- #
- # @param source [String]
- # @return [Either]
- #
- # source://unparser//lib/unparser.rb#114
- def parse_either(source); end
-
- # Parse string into AST, with comments
- #
- # @param source [String]
- # @return [Parser::AST::Node]
- #
- # source://unparser//lib/unparser.rb#125
- def parse_with_comments(source); end
-
- # Parser instance that produces AST unparser understands
- #
- # @api private
- # @return [Parser::Base]
- #
- # source://unparser//lib/unparser.rb#134
- def parser; end
-
- # Unparse an AST (and, optionally, comments) into a string
- #
- # @api public
- # @param node [Parser::AST::Node, nil]
- # @param comment_array [Array]
- # @raise InvalidNodeError
- # if the node passed is invalid
- # @return [String]
- #
- # source://unparser//lib/unparser.rb#60
- def unparse(node, comment_array = T.unsafe(nil)); end
-
- # Unparse capturing errors
- #
- # This is mostly useful for writing testing tools against unparser.
- #
- # @param node [Parser::AST::Node, nil]
- # @return [Either]
- #
- # source://unparser//lib/unparser.rb#96
- def unparse_either(node); end
-
- # Unparse with validation
- #
- # @param node [Parser::AST::Node, nil]
- # @param comment_array [Array]
- # @return [Either]
- #
- # source://unparser//lib/unparser.rb#78
- def unparse_validate(node, comment_array = T.unsafe(nil)); end
- end
-end
-
-# Namespace for AST processing tools
-#
-# source://unparser//lib/unparser/ast.rb#5
-module Unparser::AST
- class << self
- # Return local variables that get assigned in scope
- #
- # @api private
- # @param node [Parser::AST::Node]
- # @return [Set]
- #
- # source://unparser//lib/unparser/ast.rb#57
- def local_variable_assignments(node); end
-
- # Return local variables read
- #
- # @api private
- # @param node [Parser::AST::Node]
- # @return [Set]
- #
- # source://unparser//lib/unparser/ast.rb#72
- def local_variable_reads(node); end
-
- # Test for local variable inherited scope reset
- #
- # @api private
- # @param node [Parser::AST::Node]
- # @return [Boolean]
- #
- # source://unparser//lib/unparser/ast.rb#33
- def not_close_scope?(node); end
-
- # Test for local variable scope reset
- #
- # @api private
- # @param node [Parser::AST::Node]
- # @return [Boolean]
- #
- # source://unparser//lib/unparser/ast.rb#45
- def not_reset_scope?(node); end
- end
-end
-
-# Nodes that assign a local variable
-#
-# source://unparser//lib/unparser/ast.rb#14
-Unparser::AST::ASSIGN_NODES = T.let(T.unsafe(nil), Set)
-
-# source://unparser//lib/unparser/ast.rb#11
-Unparser::AST::CLOSE_NODES = T.let(T.unsafe(nil), Array)
-
-# AST enumerator
-#
-# source://unparser//lib/unparser/ast.rb#80
-class Unparser::AST::Enumerator
- include ::Enumerable
- include ::Unparser::Equalizer::Methods
- include ::Unparser::Adamantium
- include ::Unparser::Adamantium::InstanceMethods
- extend ::Unparser::Adamantium::ModuleMethods
- extend ::Unparser::Adamantium::ClassMethods
-
- # Return each node
- #
- # @api private
- # @return [Enumerator] if no block given
- # @return [self] otherwise
- #
- # source://unparser//lib/unparser/ast.rb#106
- def each(&block); end
-
- # Return nodes selected by type
- #
- # @api private
- # @param type [Symbol]
- # @return [Enumerable]
- #
- # source://unparser//lib/unparser/ast.rb#130
- def type(type); end
-
- # Return nodes selected by types
- #
- # @api private
- # @param types [Enumerable]
- # @return [Enumerable]
- #
- # source://unparser//lib/unparser/ast.rb#118
- def types(types); end
-
- class << self
- # Return new instance
- #
- # @api private
- # @param node [Parser::AST::Node]
- # @param controller [#call(node)]
- # @return [Enumerator]
- #
- # source://unparser//lib/unparser/ast.rb#92
- def new(node, controller = T.unsafe(nil)); end
-
- private
-
- # Return frozne set of objects
- #
- # @api private
- # @param enumerable [Enumerable]
- # @return [Set]
- #
- # source://unparser//lib/unparser/ast.rb#142
- def set(enumerable); end
-
- # Return nodes of type
- #
- # @api private
- # @param node [Parser::AST::Node]
- # @param type [Symbol]
- # @return [Enumerable>] ]
- # otherwise
- #
- # source://unparser//lib/unparser/ast/local_variable_scope.rb#121
- def each(node, &block); end
-
- private
-
- # source://unparser//lib/unparser/ast/local_variable_scope.rb#127
- def current; end
-
- # source://unparser//lib/unparser/ast/local_variable_scope.rb#156
- def define(name); end
-
- # source://unparser//lib/unparser/ast/local_variable_scope.rb#141
- def enter(node); end
-
- # source://unparser//lib/unparser/ast/local_variable_scope.rb#152
- def leave(node); end
-
- # source://unparser//lib/unparser/ast/local_variable_scope.rb#168
- def pop; end
-
- # source://unparser//lib/unparser/ast/local_variable_scope.rb#164
- def push_inherit; end
-
- # source://unparser//lib/unparser/ast/local_variable_scope.rb#160
- def push_reset; end
-
- # @yield [node, current.dup, before]
- #
- # source://unparser//lib/unparser/ast/local_variable_scope.rb#131
- def visit(node, &block); end
-
- class << self
- # Enumerate each node with its local variable scope
- #
- # @api private
- # @param node [Parser::AST::Node]
- # @return [self]
- #
- # source://unparser//lib/unparser/ast/local_variable_scope.rb#106
- def each(node, &block); end
- end
-end
-
-# source://unparser//lib/unparser/ast.rb#9
-Unparser::AST::RESET_NODES = T.let(T.unsafe(nil), Array)
-
-# source://unparser//lib/unparser/ast.rb#7
-Unparser::AST::TAUTOLOGY = T.let(T.unsafe(nil), Proc)
-
-# Controlled AST walker walking the AST in deeth first search with pre order
-#
-# source://unparser//lib/unparser/ast.rb#164
-class Unparser::AST::Walker
- include ::Unparser::Equalizer::Methods
-
- # Call walker with node
- #
- # @api private
- # @param node [Parser::AST::Node]
- # @return [undefined]
- #
- # source://unparser//lib/unparser/ast.rb#188
- def call(node); end
-
- class << self
- # Call ast walker
- #
- # @api private
- # @param node [Parser::AST::Node]
- # @return [self]
- #
- # source://unparser//lib/unparser/ast.rb#175
- def call(node, controller = T.unsafe(nil), &block); end
- end
-end
-
-# Module to allow class and methods to be abstract
-#
-# Original code before vendoring and reduction from: https://github.com/dkubb/abstract_type.
-#
-# source://unparser//lib/unparser/abstract_type.rb#7
-module Unparser::AbstractType
- mixes_in_class_methods ::Unparser::AbstractType::AbstractMethodDeclarations
-
- class << self
- private
-
- # Define the new method on the abstract type
- #
- # Ensures that the instance cannot be of the abstract type
- # and must be a descendant.
- #
- # @api private
- # @param abstract_class [Class]
- # @return [undefined]
- #
- # source://unparser//lib/unparser/abstract_type.rb#35
- def create_new_method(abstract_class); end
-
- # Hook called when module is included
- #
- # @api private
- # @param descendant [Module] the module or class including AbstractType
- # @return [undefined]
- #
- # source://unparser//lib/unparser/abstract_type.rb#17
- def included(descendant); end
- end
-end
-
-# source://unparser//lib/unparser/abstract_type.rb#47
-module Unparser::AbstractType::AbstractMethodDeclarations
- # Create abstract instance methods
- #
- # @api public
- # @example
- # class Foo
- # include AbstractType
- #
- # # Create an abstract instance method
- # abstract_method :some_method
- # end
- # @param names [Array<#to_s>]
- # @return [self]
- #
- # source://unparser//lib/unparser/abstract_type.rb#64
- def abstract_method(*names); end
-
- # Create abstract singleton methods
- #
- # @api private
- # @example
- # class Foo
- # include AbstractType
- #
- # # Create an abstract instance method
- # abstract_singleton_method :some_method
- # end
- # @param names [Array<#to_s>]
- # @return [self]
- #
- # source://unparser//lib/unparser/abstract_type.rb#84
- def abstract_singleton_method(*names); end
-
- private
-
- # Create abstract instance method
- #
- # @api private
- # @param name [#to_s] the name of the method to create
- # @return [undefined]
- #
- # source://unparser//lib/unparser/abstract_type.rb#113
- def create_abstract_instance_method(name); end
-
- # Create abstract singleton method
- #
- # @api private
- # @param name [#to_s] the name of the method to create
- # @return [undefined]
- #
- # source://unparser//lib/unparser/abstract_type.rb#99
- def create_abstract_singleton_method(name); end
-end
-
-# Allows objects to be made immutable
-#
-# Original code before vendoring and reduction from: https://github.com/dkubb/adamantium.
-#
-# source://unparser//lib/unparser/adamantium.rb#7
-module Unparser::Adamantium
- include ::Unparser::Adamantium::InstanceMethods
-
- mixes_in_class_methods ::Unparser::Adamantium::ModuleMethods
- mixes_in_class_methods ::Unparser::Adamantium::ClassMethods
-
- class << self
- private
-
- # ModuleMethods
- #
- # source://unparser//lib/unparser/adamantium.rb#141
- def included(descendant); end
- end
-end
-
-# Methods mixed in to adamantium classes
-#
-# source://unparser//lib/unparser/adamantium.rb#70
-module Unparser::Adamantium::ClassMethods
- # Instantiate a new frozen object
- #
- # @api public
- # @return [Object]
- #
- # source://unparser//lib/unparser/adamantium.rb#77
- def new(*_arg0); end
-end
-
-# source://unparser//lib/unparser/adamantium.rb#8
-module Unparser::Adamantium::InstanceMethods
- # A noop #dup for immutable objects
- #
- # @api public
- # @return [self]
- #
- # source://unparser//lib/unparser/adamantium.rb#14
- def dup; end
-
- # Freeze the object
- #
- # @api public
- # @return [Object]
- #
- # source://unparser//lib/unparser/adamantium.rb#23
- def freeze; end
-
- private
-
- # source://unparser//lib/unparser/adamantium.rb#30
- def memoized_method_cache; end
-end
-
-# Storage for memoized methods
-#
-# source://unparser//lib/unparser/adamantium.rb#37
-class Unparser::Adamantium::Memory
- # Initialize the memory storage for memoized methods
- #
- # @api private
- # @return [undefined]
- #
- # source://unparser//lib/unparser/adamantium.rb#44
- def initialize(values); end
-
- # Fetch the value from memory, or evaluate if it does not exist
- #
- # @api public
- # @param name [Symbol]
- # @yieldreturn [Object] the value to memoize
- #
- # source://unparser//lib/unparser/adamantium.rb#58
- def fetch(name); end
-end
-
-# Build the memoized method
-#
-# source://unparser//lib/unparser/adamantium/method_builder.rb#6
-class Unparser::Adamantium::MethodBuilder
- # Initialize an object to build a memoized method
- #
- # @api private
- # @param descendant [Module]
- # @param method_name [Symbol]
- # @return [undefined]
- #
- # source://unparser//lib/unparser/adamantium/method_builder.rb#47
- def initialize(descendant, method_name); end
-
- # Build a new memoized method
- #
- # @api public
- # @example
- # method_builder.call # => creates new method
- # @return [UnboundMethod]
- #
- # source://unparser//lib/unparser/adamantium/method_builder.rb#63
- def call; end
-
- private
-
- # source://unparser//lib/unparser/adamantium/method_builder.rb#72
- def assert_arity(arity); end
-
- # source://unparser//lib/unparser/adamantium/method_builder.rb#83
- def create_memoized_method; end
-
- # source://unparser//lib/unparser/adamantium/method_builder.rb#78
- def remove_original_method; end
-
- # source://unparser//lib/unparser/adamantium/method_builder.rb#97
- def set_method_visibility; end
-
- # source://unparser//lib/unparser/adamantium/method_builder.rb#101
- def visibility; end
-end
-
-# Raised when a block is passed to a memoized method
-#
-# source://unparser//lib/unparser/adamantium/method_builder.rb#25
-class Unparser::Adamantium::MethodBuilder::BlockNotAllowedError < ::ArgumentError
- # Initialize a block not allowed exception
- #
- # @api private
- # @param descendant [Module]
- # @param method [Symbol]
- # @return [BlockNotAllowedError] a new instance of BlockNotAllowedError
- #
- # source://unparser//lib/unparser/adamantium/method_builder.rb#33
- def initialize(descendant, method); end
-end
-
-# Raised when the method arity is invalid
-#
-# source://unparser//lib/unparser/adamantium/method_builder.rb#9
-class Unparser::Adamantium::MethodBuilder::InvalidArityError < ::ArgumentError
- # Initialize an invalid arity exception
- #
- # @api private
- # @param descendant [Module]
- # @param method [Symbol]
- # @param arity [Integer]
- # @return [InvalidArityError] a new instance of InvalidArityError
- #
- # source://unparser//lib/unparser/adamantium/method_builder.rb#18
- def initialize(descendant, method, arity); end
-end
-
-# Methods mixed in to adamantium modules
-#
-# source://unparser//lib/unparser/adamantium.rb#84
-module Unparser::Adamantium::ModuleMethods
- # Memoize a list of methods
- #
- # @api public
- # @param methods [Array<#to_s>] a list of methods to memoize
- # @return [self]
- #
- # source://unparser//lib/unparser/adamantium.rb#94
- def memoize(*methods); end
-
- # Test if method is memoized
- #
- # @param name [Symbol]
- # @return [Bool]
- #
- # source://unparser//lib/unparser/adamantium.rb#104
- def memoized?(method_name); end
-
- # Return unmemoized instance method
- #
- # @api public
- # @param name [Symbol]
- # @raise [NameError] raised if the method is unknown
- # @return [UnboundMethod] the memoized method
- #
- # source://unparser//lib/unparser/adamantium.rb#119
- def unmemoized_instance_method(method_name); end
-
- private
-
- # source://unparser//lib/unparser/adamantium.rb#127
- def memoize_method(method_name); end
-
- # source://unparser//lib/unparser/adamantium.rb#135
- def memoized_methods; end
-end
-
-# Original code before vendoring and reduction from: https://github.com/mbj/anima.
-#
-# source://unparser//lib/unparser/anima.rb#5
-class Unparser::Anima < ::Module
- include ::Unparser::Equalizer::Methods
- include ::Unparser::Adamantium
- include ::Unparser::Adamantium::InstanceMethods
- extend ::Unparser::Adamantium::ModuleMethods
- extend ::Unparser::Adamantium::ClassMethods
-
- # Initialize object
- #
- #
- # @return [undefined]
- #
- # source://unparser//lib/unparser/anima.rb#18
- def initialize(*names); end
-
- # Return new anima with attributes added
- #
- # @example
- # anima = Anima.new(:foo)
- # anima.add(:bar) # equals Anima.new(:foo, :bar)
- # @return [Anima]
- #
- # source://unparser//lib/unparser/anima.rb#31
- def add(*names); end
-
- # Return attribute names
- #
- # @return [Enumerable]
- #
- # source://unparser//lib/unparser/adamantium/method_builder.rb#87
- def attribute_names(&block); end
-
- # Return names
- #
- # @return [AttributeSet]
- #
- # source://unparser//lib/unparser/anima.rb#11
- def attributes; end
-
- # Return attributes hash for instance
- #
- # @param object [Object]
- # @return [Hash]
- #
- # source://unparser//lib/unparser/anima.rb#52
- def attributes_hash(object); end
-
- # Initialize instance
- #
- # @param object [Object]
- # @param attribute_hash [Hash]
- # @return [self]
- #
- # source://unparser//lib/unparser/anima.rb#73
- def initialize_instance(object, attribute_hash); end
-
- # Return new anima with attributes removed
- #
- # @example
- # anima = Anima.new(:foo, :bar)
- # anima.remove(:bar) # equals Anima.new(:foo)
- # @return [Anima]
- #
- # source://unparser//lib/unparser/anima.rb#43
- def remove(*names); end
-
- private
-
- # Fail unless keys in +attribute_hash+ matches #attribute_names
- #
- # @param klass [Class] the class being initialized
- # @param attribute_hash [Hash] the attributes to initialize +object+ with
- # @raise [Error]
- # @return [undefined]
- #
- # source://unparser//lib/unparser/anima.rb#164
- def assert_known_attributes(klass, attribute_hash); end
-
- # Infect the instance with anima
- #
- # @param scope [Class, Module]
- # @return [undefined]
- #
- # source://unparser//lib/unparser/anima.rb#137
- def included(descendant); end
-
- # Return new instance
- #
- # @param attributes [Enumerable]
- # @return [Anima]
- #
- # source://unparser//lib/unparser/anima.rb#180
- def new(attributes); end
-end
-
-# An attribute
-#
-# source://unparser//lib/unparser/anima/attribute.rb#6
-class Unparser::Anima::Attribute
- include ::Unparser::Equalizer::Methods
- include ::Unparser::Adamantium
- include ::Unparser::Adamantium::InstanceMethods
- extend ::Unparser::Adamantium::ModuleMethods
- extend ::Unparser::Adamantium::ClassMethods
-
- # Initialize attribute
- #
- # @param name [Symbol]
- # @return [Attribute] a new instance of Attribute
- #
- # source://unparser//lib/unparser/anima/attribute.rb#12
- def initialize(name); end
-
- # Get attribute value from object
- #
- # @param object [Object]
- # @return [Object]
- #
- # source://unparser//lib/unparser/anima/attribute.rb#42
- def get(object); end
-
- # Return instance variable name
- #
- # @return [Symbol]
- #
- # source://unparser//lib/unparser/anima/attribute.rb#25
- def instance_variable_name; end
-
- # Load attribute
- #
- # @param object [Object]
- # @param attributes [Hash]
- # @return [self]
- #
- # source://unparser//lib/unparser/anima/attribute.rb#33
- def load(object, attributes); end
-
- # Return attribute name
- #
- # @return [Symbol]
- #
- # source://unparser//lib/unparser/anima/attribute.rb#20
- def name; end
-
- # Set attribute value in object
- #
- # @param object [Object]
- # @param value [Object]
- # @return [self]
- #
- # source://unparser//lib/unparser/anima/attribute.rb#52
- def set(object, value); end
-end
-
-# Abstract base class for anima errors
-#
-# source://unparser//lib/unparser/anima/error.rb#6
-class Unparser::Anima::Error < ::RuntimeError
- # Initialize object
- #
- # @param klass [Class] the class being initialized
- # @param missing [Enumerable]
- # @param unknown [Enumerable]
- # @return [undefined]
- #
- # source://unparser//lib/unparser/anima/error.rb#18
- def initialize(klass, missing, unknown); end
-end
-
-# source://unparser//lib/unparser/anima/error.rb#7
-Unparser::Anima::Error::FORMAT = T.let(T.unsafe(nil), String)
-
-# Static instance methods for anima infected classes
-#
-# source://unparser//lib/unparser/anima.rb#82
-module Unparser::Anima::InstanceMethods
- # Initialize an anima infected object
- #
- #
- # @param attributes [#to_h] a hash that matches anima defined attributes
- # @return [undefined]
- #
- # source://unparser//lib/unparser/anima.rb#91
- def initialize(attributes); end
-
- # Return a hash representation of an anima infected object
- #
- # @api public
- # @example
- # anima.to_h # => { :foo => : bar }
- # @return [Hash]
- #
- # source://unparser//lib/unparser/anima.rb#104
- def to_h; end
-
- # Return updated instance
- #
- # @api public
- # @example
- # klass = Class.new do
- # include Anima.new(:foo, :bar)
- # end
- #
- # foo = klass.new(:foo => 1, :bar => 2)
- # updated = foo.with(:foo => 3)
- # updated.foo # => 3
- # updated.bar # => 2
- # @param attributes [Hash]
- # @return [Anima]
- #
- # source://unparser//lib/unparser/anima.rb#125
- def with(attributes); end
-end
-
-# Buffer used to emit into
-#
-# source://unparser//lib/unparser/buffer.rb#6
-class Unparser::Buffer
- # Initialize object
- #
- # @api private
- # @return [undefined]
- #
- # source://unparser//lib/unparser/buffer.rb#16
- def initialize; end
-
- # Append string
- #
- # @api private
- # @param string [String]
- # @return [self]
- #
- # source://unparser//lib/unparser/buffer.rb#29
- def append(string); end
-
- # Append a string without an indentation prefix
- #
- # @api private
- # @param string [String]
- # @return [self]
- #
- # source://unparser//lib/unparser/buffer.rb#45
- def append_without_prefix(string); end
-
- # Return content of buffer
- #
- # @api private
- # @return [String]
- #
- # source://unparser//lib/unparser/buffer.rb#104
- def content; end
-
- # Test for a fresh line
- #
- # @api private
- # @return [Boolean]
- #
- # source://unparser//lib/unparser/buffer.rb#94
- def fresh_line?; end
-
- # Increase indent
- #
- # @api private
- # @return [self]
- #
- # source://unparser//lib/unparser/buffer.rb#55
- def indent; end
-
- # Write newline
- #
- # @api private
- # @return [self]
- #
- # source://unparser//lib/unparser/buffer.rb#77
- def nl; end
-
- # source://unparser//lib/unparser/buffer.rb#81
- def root_indent; end
-
- # Decrease indent
- #
- # @api private
- # @return [self]
- #
- # source://unparser//lib/unparser/buffer.rb#66
- def unindent; end
-
- # Write raw fragment to buffer
- #
- # Does not do indentation logic.
- #
- # @param fragment [String]
- # @return [self]
- #
- # source://unparser//lib/unparser/buffer.rb#115
- def write(fragment); end
-
- private
-
- # source://unparser//lib/unparser/buffer.rb#124
- def prefix; end
-end
-
-# source://unparser//lib/unparser/buffer.rb#122
-Unparser::Buffer::INDENT_SPACE = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/buffer.rb#8
-Unparser::Buffer::NL = T.let(T.unsafe(nil), String)
-
-# Unparser specific AST builder defaulting to modern AST format
-#
-# source://unparser//lib/unparser.rb#23
-class Unparser::Builder < ::Parser::Builders::Default
- # @return [Builder] a new instance of Builder
- #
- # source://unparser//lib/unparser.rb#26
- def initialize; end
-end
-
-# Unparser CLI implementation
-#
-# source://unparser//lib/unparser/cli.rb#5
-class Unparser::CLI
- # Initialize object
- #
- # @api private
- # @param arguments [Array]
- # @return [undefined]
- #
- # source://unparser//lib/unparser/cli.rb#74
- def initialize(arguments); end
-
- # Add options
- #
- #
- # @api private
- # @param builder [OptionParser]
- # @return [undefined]
- #
- # source://unparser//lib/unparser/cli.rb#102
- def add_options(builder); end
-
- # Return exit status
- #
- # @api private
- # @return [Integer]
- #
- # source://unparser//lib/unparser/cli.rb#132
- def exit_status; end
-
- private
-
- # source://unparser//lib/unparser/cli.rb#155
- def effective_targets; end
-
- # source://unparser//lib/unparser/cli.rb#143
- def process_target(target); end
-
- # source://unparser//lib/unparser/cli.rb#170
- def targets(file_name); end
-
- class << self
- # Run CLI
- #
- # @api private
- # @param arguments [Array]
- # @return [Integer] the exit status
- #
- # source://unparser//lib/unparser/cli.rb#63
- def run(*arguments); end
- end
-end
-
-# source://unparser//lib/unparser/cli.rb#8
-Unparser::CLI::EXIT_FAILURE = T.let(T.unsafe(nil), Integer)
-
-# source://unparser//lib/unparser/cli.rb#7
-Unparser::CLI::EXIT_SUCCESS = T.let(T.unsafe(nil), Integer)
-
-# source://unparser//lib/unparser/cli.rb#10
-class Unparser::CLI::Target
- include ::Unparser::AbstractType
- extend ::Unparser::AbstractType::AbstractMethodDeclarations
-
- class << self
- # source://unparser//lib/unparser/abstract_type.rb#36
- def new(*args, &block); end
- end
-end
-
-# Path target
-#
-# source://unparser//lib/unparser/cli.rb#14
-class Unparser::CLI::Target::Path < ::Unparser::CLI::Target
- include ::Unparser::Equalizer::Methods
-
- # Literal for this target
- #
- # @return [Validation]
- #
- # source://unparser//lib/unparser/cli.rb#27
- def literal_validation; end
-
- # Validation for this target
- #
- # @return [Validation]
- #
- # source://unparser//lib/unparser/cli.rb#20
- def validation; end
-end
-
-# String target
-#
-# source://unparser//lib/unparser/cli.rb#33
-class Unparser::CLI::Target::String
- include ::Unparser::Equalizer::Methods
-
- # Literal for this target
- #
- # @return [Validation]
- #
- # source://unparser//lib/unparser/cli.rb#46
- def literal_validation; end
-
- # Validation for this target
- #
- # @return [Validation]
- #
- # source://unparser//lib/unparser/cli.rb#39
- def validation; end
-end
-
-# Class to colorize strings
-#
-# source://unparser//lib/unparser/color.rb#5
-class Unparser::Color
- include ::Unparser::Equalizer::Methods
- include ::Unparser::Adamantium
- include ::Unparser::Adamantium::InstanceMethods
- extend ::Unparser::Adamantium::ModuleMethods
- extend ::Unparser::Adamantium::ClassMethods
-
- # Format text with color
- #
- # @param text [String]
- # @return [String]
- #
- # source://unparser//lib/unparser/color.rb#13
- def format(text); end
-end
-
-# source://unparser//lib/unparser/color.rb#41
-Unparser::Color::GREEN = T.let(T.unsafe(nil), Unparser::Color)
-
-# source://unparser//lib/unparser/color.rb#17
-Unparser::Color::NONE = T.let(T.unsafe(nil), T.untyped)
-
-# source://unparser//lib/unparser/color.rb#40
-Unparser::Color::RED = T.let(T.unsafe(nil), Unparser::Color)
-
-# Holds the comments that remain to be emitted
-#
-# source://unparser//lib/unparser/comments.rb#6
-class Unparser::Comments
- # Initialize object
- #
- # @api private
- # @param comments [Array]
- # @return [undefined]
- #
- # source://unparser//lib/unparser/comments.rb#30
- def initialize(comments); end
-
- # Consume part or all of the node
- #
- # @api private
- # @param node [Parser::AST::Node]
- # @param source_part [Symbol]
- # @return [undefined]
- #
- # source://unparser//lib/unparser/comments.rb#44
- def consume(node, source_part = T.unsafe(nil)); end
-
- # Proxy to singleton
- #
- # NOTICE:
- # Delegating to stateless helpers is a pattern I saw many times in our code.
- # Maybe we should make another helper module? include SingletonDelegator.new(:source_range) ?
- #
- # @api private
- # @return [undefined]
- #
- # source://unparser//lib/unparser/comments.rb#18
- def source_range(*arguments); end
-
- # Take all remaining comments
- #
- # @api private
- # @return [Array]
- #
- # source://unparser//lib/unparser/comments.rb#68
- def take_all; end
-
- # Take comments appear in the source before the specified part of the node
- #
- # @api private
- # @param node [Parser::AST::Node]
- # @param source_part [Symbol]
- # @return [Array]
- #
- # source://unparser//lib/unparser/comments.rb#81
- def take_before(node, source_part); end
-
- # Take end-of-line comments
- #
- # @api private
- # @return [Array]
- #
- # source://unparser//lib/unparser/comments.rb#55
- def take_eol_comments; end
-
- private
-
- # source://unparser//lib/unparser/comments.rb#119
- def take_up_to_line(line); end
-
- # source://unparser//lib/unparser/comments.rb#114
- def take_while; end
-
- # source://unparser//lib/unparser/comments.rb#123
- def unshift_documents(comments); end
-
- class << self
- # Return source location part
- #
- # FIXME: This method should not be needed. It does to much inline signalling.
- #
- # :reek:ManualDispatch
- #
- # @api private
- # @param node [Parser::AST::Node]
- # @param part [Symbol]
- # @return [Parser::Source::Range] if present
- # @return [nil] otherwise
- #
- # source://unparser//lib/unparser/comments.rb#107
- def source_range(node, part); end
- end
-end
-
-# A mixin to define a composition
-#
-# Original code before vendoring and reduction from: https://github.com/mbj/concord.
-#
-# source://unparser//lib/unparser/concord.rb#7
-class Unparser::Concord < ::Module
- include ::Unparser::Equalizer::Methods
- include ::Unparser::Adamantium
- include ::Unparser::Adamantium::InstanceMethods
- extend ::Unparser::Adamantium::ModuleMethods
- extend ::Unparser::Adamantium::ClassMethods
-
- # Initialize object
- #
- #
- # @api private
- # @return [undefined]
- #
- # source://unparser//lib/unparser/concord.rb#30
- def initialize(*names); end
-
- # Return names
- #
- # @api private
- # @return [Enumerable]
- #
- # source://unparser//lib/unparser/concord.rb#19
- def names; end
-
- private
-
- # Define equalizer
- #
- # @api private
- # @return [undefined]
- #
- # source://unparser//lib/unparser/concord.rb#48
- def define_equalizer; end
-
- # Define initialize method
- #
- # @api private
- # @return [undefined]
- #
- # source://unparser//lib/unparser/concord.rb#72
- def define_initialize; end
-
- # Define readers
- #
- # @api private
- # @return [undefined]
- #
- # source://unparser//lib/unparser/concord.rb#58
- def define_readers; end
-
- # Return instance variable names
- #
- # @api private
- # @return [String]
- #
- # source://unparser//lib/unparser/concord.rb#92
- def instance_variable_names; end
-end
-
-# The maximum number of objects the hosting class is composed of
-#
-# source://unparser//lib/unparser/concord.rb#11
-Unparser::Concord::MAX_NR_OF_OBJECTS = T.let(T.unsafe(nil), Integer)
-
-# Mixin for public attribute readers
-#
-# source://unparser//lib/unparser/concord.rb#97
-class Unparser::Concord::Public < ::Unparser::Concord
- # Hook called when module is included
- #
- # @api private
- # @param descendant [Class, Module]
- # @return [undefined]
- #
- # source://unparser//lib/unparser/concord.rb#107
- def included(descendant); end
-end
-
-# All unparser constants maybe included in other libraries.
-#
-# source://unparser//lib/unparser/constants.rb#5
-module Unparser::Constants; end
-
-# All binary operators of the ruby language
-#
-# source://unparser//lib/unparser/constants.rb#13
-Unparser::Constants::BINARY_OPERATORS = T.let(T.unsafe(nil), Set)
-
-# source://unparser//lib/unparser/constants.rb#63
-Unparser::Constants::KEYWORDS = T.let(T.unsafe(nil), Set)
-
-# source://unparser//lib/unparser/constants.rb#45
-Unparser::Constants::K_ALIAS = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#44
-Unparser::Constants::K_AND = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#23
-Unparser::Constants::K_BEGIN = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#37
-Unparser::Constants::K_BREAK = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#24
-Unparser::Constants::K_CASE = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#25
-Unparser::Constants::K_CLASS = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#21
-Unparser::Constants::K_DEF = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#28
-Unparser::Constants::K_DEFINE = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#33
-Unparser::Constants::K_DEFINED = T.let(T.unsafe(nil), String)
-
-# Keywords
-#
-# source://unparser//lib/unparser/constants.rb#20
-Unparser::Constants::K_DO = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#59
-Unparser::Constants::K_EEND = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#46
-Unparser::Constants::K_ELSE = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#47
-Unparser::Constants::K_ELSIF = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#58
-Unparser::Constants::K_ENCODING = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#22
-Unparser::Constants::K_END = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#27
-Unparser::Constants::K_ENSURE = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#41
-Unparser::Constants::K_FALSE = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#60
-Unparser::Constants::K_FILE = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#48
-Unparser::Constants::K_FOR = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#43
-Unparser::Constants::K_IF = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#51
-Unparser::Constants::K_IN = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#29
-Unparser::Constants::K_MODULE = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#40
-Unparser::Constants::K_NEXT = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#49
-Unparser::Constants::K_NIL = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#50
-Unparser::Constants::K_NOT = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#52
-Unparser::Constants::K_OR = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#35
-Unparser::Constants::K_POSTEXE = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#34
-Unparser::Constants::K_PREEXE = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#39
-Unparser::Constants::K_REDO = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#30
-Unparser::Constants::K_RESCUE = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#38
-Unparser::Constants::K_RETRY = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#31
-Unparser::Constants::K_RETURN = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#26
-Unparser::Constants::K_SELF = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#36
-Unparser::Constants::K_SUPER = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#61
-Unparser::Constants::K_THEN = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#42
-Unparser::Constants::K_TRUE = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#32
-Unparser::Constants::K_UNDEF = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#53
-Unparser::Constants::K_UNLESS = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#56
-Unparser::Constants::K_UNTIL = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#54
-Unparser::Constants::K_WHEN = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#55
-Unparser::Constants::K_WHILE = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/constants.rb#57
-Unparser::Constants::K_YIELD = T.let(T.unsafe(nil), String)
-
-# All unary operators of the ruby language
-#
-# source://unparser//lib/unparser/constants.rb#8
-Unparser::Constants::UNARY_OPERATORS = T.let(T.unsafe(nil), Set)
-
-# DSL to help defining emitters
-#
-# source://unparser//lib/unparser/dsl.rb#5
-module Unparser::DSL
- private
-
- # source://unparser//lib/unparser/dsl.rb#32
- def children(*names); end
-
- # source://unparser//lib/unparser/dsl.rb#17
- def define_child(name, index); end
-
- # source://unparser//lib/unparser/dsl.rb#24
- def define_group(name, range); end
-
- # source://unparser//lib/unparser/dsl.rb#9
- def define_remaining_children(names); end
-end
-
-# Class to create diffs from source code
-#
-# source://unparser//lib/unparser/diff.rb#5
-class Unparser::Diff
- include ::Unparser::Equalizer::Methods
- include ::Unparser::Adamantium
- include ::Unparser::Adamantium::InstanceMethods
- extend ::Unparser::Adamantium::ModuleMethods
- extend ::Unparser::Adamantium::ClassMethods
-
- # Colorized unified source diff between old and new
- #
- # @return [String] if there is a diff
- # @return [nil] otherwise
- #
- # source://unparser//lib/unparser/adamantium/method_builder.rb#87
- def colorized_diff(&block); end
-
- # Unified source diff between old and new
- #
- # @return [String] if there is exactly one diff
- # @return [nil] otherwise
- #
- # source://unparser//lib/unparser/adamantium/method_builder.rb#87
- def diff(&block); end
-
- private
-
- # source://unparser//lib/unparser/diff.rb#62
- def diffs; end
-
- # source://unparser//lib/unparser/diff.rb#66
- def hunks; end
-
- # source://unparser//lib/unparser/diff.rb#81
- def max_length; end
-
- # source://unparser//lib/unparser/diff.rb#72
- def minimized_hunk; end
-
- class << self
- # Build new object from source strings
- #
- # @param old [String]
- # @param new [String]
- # @return [Diff]
- #
- # source://unparser//lib/unparser/diff.rb#46
- def build(old, new); end
-
- private
-
- # source://unparser//lib/unparser/diff.rb#85
- def colorize_line(line); end
-
- # Break up source into lines
- #
- # @param source [String]
- # @return [Array]
- #
- # source://unparser//lib/unparser/diff.rb#55
- def lines(source); end
- end
-end
-
-# source://unparser//lib/unparser/diff.rb#8
-Unparser::Diff::ADDITION = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/diff.rb#9
-Unparser::Diff::DELETION = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser/diff.rb#10
-Unparser::Diff::NEWLINE = T.let(T.unsafe(nil), String)
-
-# source://unparser//lib/unparser.rb#34
-Unparser::EMPTY_ARRAY = T.let(T.unsafe(nil), Array)
-
-# source://unparser//lib/unparser.rb#33
-Unparser::EMPTY_STRING = T.let(T.unsafe(nil), String)
-
-# RequireBLock
-#
-# source://unparser//lib/unparser/either.rb#21
-class Unparser::Either
- include ::Unparser::RequireBlock
- include ::Unparser::Equalizer::Methods
- include ::Unparser::Adamantium
- include ::Unparser::Adamantium::InstanceMethods
- extend ::Unparser::Adamantium::ModuleMethods
- extend ::Unparser::Adamantium::ClassMethods
-
- # Test for left constructor
- #
- # @return [Boolean]
- #
- # source://unparser//lib/unparser/either.rb#42
- def left?; end
-
- # Test for right constructor
- #
- # @return [Boolean]
- #
- # source://unparser//lib/unparser/either.rb#49
- def right?; end
-
- class << self
- # Execute block and wrap error in left
- #
- # @param exception [Class]
- # @return [Either]
- #
- # source://unparser//lib/unparser/either.rb#33
- def wrap_error(*exceptions); end
- end
-end
-
-# source://unparser//lib/unparser/either.rb#53
-class Unparser::Either::Left < ::Unparser::Either
- # Evaluate applicative block
- #
- # @return [Either::Left