ruby-lsp 0.14.0 → 0.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +3 -0
- data/VERSION +1 -1
- data/exe/ruby-lsp-doctor +2 -0
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +5 -5
- data/lib/ruby_indexer/test/index_test.rb +33 -9
- data/lib/ruby_lsp/addon.rb +13 -7
- data/lib/ruby_lsp/internal.rb +7 -5
- data/lib/ruby_lsp/listeners/completion.rb +5 -2
- data/lib/ruby_lsp/listeners/definition.rb +22 -14
- data/lib/ruby_lsp/listeners/document_symbol.rb +111 -12
- data/lib/ruby_lsp/listeners/hover.rb +11 -5
- data/lib/ruby_lsp/listeners/signature_help.rb +5 -2
- data/lib/ruby_lsp/requests/code_lens.rb +2 -2
- data/lib/ruby_lsp/requests/support/common.rb +15 -0
- data/lib/ruby_lsp/setup_bundler.rb +34 -18
- metadata +7 -6
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 293c03761c9b7d497045546e3bf7ca88a08ed5556ad0ba52c205a9798e820ce5
         | 
| 4 | 
            +
              data.tar.gz: 38157f012f3f1dc944186ac1530dc660d8662cb59ca7b12ad3b117655e0c1709
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: c4996e277088f015004df0f82e2cc47dc2f979f6658f9dfac19fe495c8c4deced3028b021e330ac0681dbfd79048e9033037c7ce93e6cc044c8ae6d91087e0df
         | 
| 7 | 
            +
              data.tar.gz: 67c5c31c97c279f192b0b3d6c729c97a19f7aac4581eca037c0e5355cc0f3d3ed69fb4007a5f32985e046980324575e2e35a92ce81e8078b41ee5b6db711ac88
         | 
    
        data/README.md
    CHANGED
    
    | @@ -85,6 +85,9 @@ features. This is the mechanism that powers addons like | |
| 85 85 | 
             
            - [Ruby LSP RSpec](https://github.com/st0012/ruby-lsp-rspec)
         | 
| 86 86 | 
             
            - [Ruby LSP rubyfmt](https://github.com/jscharf/ruby-lsp-rubyfmt)
         | 
| 87 87 |  | 
| 88 | 
            +
            Other community driven addons can be found in [rubygems](https://rubygems.org/search?query=name%3A+ruby-lsp) by
         | 
| 89 | 
            +
            searching for the `ruby-lsp` prefix.
         | 
| 90 | 
            +
             | 
| 88 91 | 
             
            For instructions on how to create addons, see the [addons documentation](ADDONS.md).
         | 
| 89 92 |  | 
| 90 93 | 
             
            ## Learn More
         | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            0.14. | 
| 1 | 
            +
            0.14.2
         | 
    
        data/exe/ruby-lsp-doctor
    CHANGED
    
    
| @@ -237,9 +237,9 @@ module RubyIndexer | |
| 237 237 | 
             
                  real_parts.join("::")
         | 
| 238 238 | 
             
                end
         | 
| 239 239 |  | 
| 240 | 
            -
                # Attempts to find  | 
| 241 | 
            -
                # exist on that receiver
         | 
| 242 | 
            -
                sig { params(method_name: String, receiver_name: String).returns(T.nilable(Entry::Member)) }
         | 
| 240 | 
            +
                # Attempts to find methods for a resolved fully qualified receiver name.
         | 
| 241 | 
            +
                # Returns `nil` if the method does not exist on that receiver
         | 
| 242 | 
            +
                sig { params(method_name: String, receiver_name: String).returns(T.nilable(T::Array[Entry::Member])) }
         | 
| 243 243 | 
             
                def resolve_method(method_name, receiver_name)
         | 
| 244 244 | 
             
                  method_entries = self[method_name]
         | 
| 245 245 | 
             
                  owner_entries = self[receiver_name]
         | 
| @@ -247,10 +247,10 @@ module RubyIndexer | |
| 247 247 |  | 
| 248 248 | 
             
                  owner_name = T.must(owner_entries.first).name
         | 
| 249 249 | 
             
                  T.cast(
         | 
| 250 | 
            -
                    method_entries.grep(Entry::Member). | 
| 250 | 
            +
                    method_entries.grep(Entry::Member).select do |entry|
         | 
| 251 251 | 
             
                      T.cast(entry, Entry::Member).owner&.name == owner_name
         | 
| 252 252 | 
             
                    end,
         | 
| 253 | 
            -
                    T | 
| 253 | 
            +
                    T::Array[Entry::Member],
         | 
| 254 254 | 
             
                  )
         | 
| 255 255 | 
             
                end
         | 
| 256 256 |  | 
| @@ -226,9 +226,9 @@ module RubyIndexer | |
| 226 226 | 
             
                    end
         | 
| 227 227 | 
             
                  RUBY
         | 
| 228 228 |  | 
| 229 | 
            -
                   | 
| 230 | 
            -
                  assert_equal("baz",  | 
| 231 | 
            -
                  assert_equal("Foo::Bar", T.must( | 
| 229 | 
            +
                  entries = T.must(@index.resolve_method("baz", "Foo::Bar"))
         | 
| 230 | 
            +
                  assert_equal("baz", entries.first.name)
         | 
| 231 | 
            +
                  assert_equal("Foo::Bar", T.must(entries.first.owner).name)
         | 
| 232 232 | 
             
                end
         | 
| 233 233 |  | 
| 234 234 | 
             
                def test_resolve_method_with_class_name_conflict
         | 
| @@ -241,9 +241,9 @@ module RubyIndexer | |
| 241 241 | 
             
                    end
         | 
| 242 242 | 
             
                  RUBY
         | 
| 243 243 |  | 
| 244 | 
            -
                   | 
| 245 | 
            -
                  assert_equal("Array",  | 
| 246 | 
            -
                  assert_equal("Foo", T.must( | 
| 244 | 
            +
                  entries = T.must(@index.resolve_method("Array", "Foo"))
         | 
| 245 | 
            +
                  assert_equal("Array", entries.first.name)
         | 
| 246 | 
            +
                  assert_equal("Foo", T.must(entries.first.owner).name)
         | 
| 247 247 | 
             
                end
         | 
| 248 248 |  | 
| 249 249 | 
             
                def test_resolve_method_attribute
         | 
| @@ -253,9 +253,33 @@ module RubyIndexer | |
| 253 253 | 
             
                    end
         | 
| 254 254 | 
             
                  RUBY
         | 
| 255 255 |  | 
| 256 | 
            -
                   | 
| 257 | 
            -
                  assert_equal("bar",  | 
| 258 | 
            -
                  assert_equal("Foo", T.must( | 
| 256 | 
            +
                  entries = T.must(@index.resolve_method("bar", "Foo"))
         | 
| 257 | 
            +
                  assert_equal("bar", entries.first.name)
         | 
| 258 | 
            +
                  assert_equal("Foo", T.must(entries.first.owner).name)
         | 
| 259 | 
            +
                end
         | 
| 260 | 
            +
             | 
| 261 | 
            +
                def test_resolve_method_with_two_definitions
         | 
| 262 | 
            +
                  index(<<~RUBY)
         | 
| 263 | 
            +
                    class Foo
         | 
| 264 | 
            +
                      # Hello from first `bar`
         | 
| 265 | 
            +
                      def bar; end
         | 
| 266 | 
            +
                    end
         | 
| 267 | 
            +
             | 
| 268 | 
            +
                    class Foo
         | 
| 269 | 
            +
                      # Hello from second `bar`
         | 
| 270 | 
            +
                      def bar; end
         | 
| 271 | 
            +
                    end
         | 
| 272 | 
            +
                  RUBY
         | 
| 273 | 
            +
             | 
| 274 | 
            +
                  first_entry, second_entry = T.must(@index.resolve_method("bar", "Foo"))
         | 
| 275 | 
            +
             | 
| 276 | 
            +
                  assert_equal("bar", first_entry.name)
         | 
| 277 | 
            +
                  assert_equal("Foo", T.must(first_entry.owner).name)
         | 
| 278 | 
            +
                  assert_includes(first_entry.comments, "Hello from first `bar`")
         | 
| 279 | 
            +
             | 
| 280 | 
            +
                  assert_equal("bar", second_entry.name)
         | 
| 281 | 
            +
                  assert_equal("Foo", T.must(second_entry.owner).name)
         | 
| 282 | 
            +
                  assert_includes(second_entry.comments, "Hello from second `bar`")
         | 
| 259 283 | 
             
                end
         | 
| 260 284 |  | 
| 261 285 | 
             
                def test_prefix_search_for_methods
         | 
    
        data/lib/ruby_lsp/addon.rb
    CHANGED
    
    | @@ -25,21 +25,25 @@ module RubyLsp | |
| 25 25 |  | 
| 26 26 | 
             
                abstract!
         | 
| 27 27 |  | 
| 28 | 
            +
                @addons = T.let([], T::Array[Addon])
         | 
| 29 | 
            +
                @addon_classes = T.let([], T::Array[T.class_of(Addon)])
         | 
| 30 | 
            +
             | 
| 28 31 | 
             
                class << self
         | 
| 29 32 | 
             
                  extend T::Sig
         | 
| 30 33 |  | 
| 34 | 
            +
                  sig { returns(T::Array[Addon]) }
         | 
| 35 | 
            +
                  attr_accessor :addons
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  sig { returns(T::Array[T.class_of(Addon)]) }
         | 
| 38 | 
            +
                  attr_reader :addon_classes
         | 
| 39 | 
            +
             | 
| 31 40 | 
             
                  # Automatically track and instantiate addon classes
         | 
| 32 41 | 
             
                  sig { params(child_class: T.class_of(Addon)).void }
         | 
| 33 42 | 
             
                  def inherited(child_class)
         | 
| 34 | 
            -
                     | 
| 43 | 
            +
                    addon_classes << child_class
         | 
| 35 44 | 
             
                    super
         | 
| 36 45 | 
             
                  end
         | 
| 37 46 |  | 
| 38 | 
            -
                  sig { returns(T::Array[Addon]) }
         | 
| 39 | 
            -
                  def addons
         | 
| 40 | 
            -
                    @addons ||= T.let([], T.nilable(T::Array[Addon]))
         | 
| 41 | 
            -
                  end
         | 
| 42 | 
            -
             | 
| 43 47 | 
             
                  # Discovers and loads all addons. Returns the list of activated addons
         | 
| 44 48 | 
             
                  sig { params(message_queue: Thread::Queue).returns(T::Array[Addon]) }
         | 
| 45 49 | 
             
                  def load_addons(message_queue)
         | 
| @@ -51,11 +55,13 @@ module RubyLsp | |
| 51 55 | 
             
                      $stderr.puts(e.full_message)
         | 
| 52 56 | 
             
                    end
         | 
| 53 57 |  | 
| 58 | 
            +
                    # Instantiate all discovered addon classes
         | 
| 59 | 
            +
                    self.addons = addon_classes.map(&:new)
         | 
| 60 | 
            +
             | 
| 54 61 | 
             
                    # Activate each one of the discovered addons. If any problems occur in the addons, we don't want to
         | 
| 55 62 | 
             
                    # fail to boot the server
         | 
| 56 63 | 
             
                    addons.each do |addon|
         | 
| 57 64 | 
             
                      addon.activate(message_queue)
         | 
| 58 | 
            -
                      nil
         | 
| 59 65 | 
             
                    rescue => e
         | 
| 60 66 | 
             
                      addon.add_error(e)
         | 
| 61 67 | 
             
                    end
         | 
    
        data/lib/ruby_lsp/internal.rb
    CHANGED
    
    | @@ -7,13 +7,17 @@ yarp_require_paths = Gem.loaded_specs["yarp"]&.full_require_paths | |
| 7 7 | 
             
            $LOAD_PATH.delete_if { |path| yarp_require_paths.include?(path) } if yarp_require_paths
         | 
| 8 8 |  | 
| 9 9 | 
             
            require "sorbet-runtime"
         | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
            require "language_server-protocol"
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            # Set Bundler's UI level to silent as soon as possible to prevent any prints to STDOUT
         | 
| 13 12 | 
             
            require "bundler"
         | 
| 13 | 
            +
            Bundler.ui.level = :silent
         | 
| 14 | 
            +
             | 
| 14 15 | 
             
            require "uri"
         | 
| 15 16 | 
             
            require "cgi"
         | 
| 16 17 | 
             
            require "set"
         | 
| 18 | 
            +
            require "prism"
         | 
| 19 | 
            +
            require "prism/visitor"
         | 
| 20 | 
            +
            require "language_server-protocol"
         | 
| 17 21 |  | 
| 18 22 | 
             
            require "ruby-lsp"
         | 
| 19 23 | 
             
            require "ruby_indexer/ruby_indexer"
         | 
| @@ -29,5 +33,3 @@ require "ruby_lsp/ruby_document" | |
| 29 33 | 
             
            require "ruby_lsp/store"
         | 
| 30 34 | 
             
            require "ruby_lsp/addon"
         | 
| 31 35 | 
             
            require "ruby_lsp/requests/support/rubocop_runner"
         | 
| 32 | 
            -
             | 
| 33 | 
            -
            Bundler.ui.level = :silent
         | 
| @@ -43,7 +43,9 @@ module RubyLsp | |
| 43 43 | 
             
                  def on_constant_read_node_enter(node)
         | 
| 44 44 | 
             
                    return if DependencyDetector.instance.typechecker
         | 
| 45 45 |  | 
| 46 | 
            -
                    name = node | 
| 46 | 
            +
                    name = constant_name(node)
         | 
| 47 | 
            +
                    return if name.nil?
         | 
| 48 | 
            +
             | 
| 47 49 | 
             
                    candidates = @index.prefix_search(name, @nesting)
         | 
| 48 50 | 
             
                    candidates.each do |entries|
         | 
| 49 51 | 
             
                      complete_name = T.must(entries.first).name
         | 
| @@ -62,7 +64,8 @@ module RubyLsp | |
| 62 64 | 
             
                  def on_constant_path_node_enter(node)
         | 
| 63 65 | 
             
                    return if DependencyDetector.instance.typechecker
         | 
| 64 66 |  | 
| 65 | 
            -
                    name = node | 
| 67 | 
            +
                    name = constant_name(node)
         | 
| 68 | 
            +
                    return if name.nil?
         | 
| 66 69 |  | 
| 67 70 | 
             
                    top_level_reference = if name.start_with?("::")
         | 
| 68 71 | 
             
                      name = name.delete_prefix("::")
         | 
| @@ -45,12 +45,18 @@ module RubyLsp | |
| 45 45 |  | 
| 46 46 | 
             
                  sig { params(node: Prism::ConstantPathNode).void }
         | 
| 47 47 | 
             
                  def on_constant_path_node_enter(node)
         | 
| 48 | 
            -
                     | 
| 48 | 
            +
                    name = constant_name(node)
         | 
| 49 | 
            +
                    return if name.nil?
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                    find_in_index(name)
         | 
| 49 52 | 
             
                  end
         | 
| 50 53 |  | 
| 51 54 | 
             
                  sig { params(node: Prism::ConstantReadNode).void }
         | 
| 52 55 | 
             
                  def on_constant_read_node_enter(node)
         | 
| 53 | 
            -
                     | 
| 56 | 
            +
                    name = constant_name(node)
         | 
| 57 | 
            +
                    return if name.nil?
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                    find_in_index(name)
         | 
| 54 60 | 
             
                  end
         | 
| 55 61 |  | 
| 56 62 | 
             
                  private
         | 
| @@ -62,20 +68,22 @@ module RubyLsp | |
| 62 68 | 
             
                    message = node.message
         | 
| 63 69 | 
             
                    return unless message
         | 
| 64 70 |  | 
| 65 | 
            -
                     | 
| 66 | 
            -
                    return unless  | 
| 71 | 
            +
                    methods = @index.resolve_method(message, @nesting.join("::"))
         | 
| 72 | 
            +
                    return unless methods
         | 
| 67 73 |  | 
| 68 | 
            -
                     | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 74 | 
            +
                    methods.each do |target_method|
         | 
| 75 | 
            +
                      location = target_method.location
         | 
| 76 | 
            +
                      file_path = target_method.file_path
         | 
| 77 | 
            +
                      next if @typechecker_enabled && not_in_dependencies?(file_path)
         | 
| 71 78 |  | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 79 | 
            +
                      @response_builder << Interface::Location.new(
         | 
| 80 | 
            +
                        uri: URI::Generic.from_path(path: file_path).to_s,
         | 
| 81 | 
            +
                        range: Interface::Range.new(
         | 
| 82 | 
            +
                          start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
         | 
| 83 | 
            +
                          end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
         | 
| 84 | 
            +
                        ),
         | 
| 85 | 
            +
                      )
         | 
| 86 | 
            +
                    end
         | 
| 79 87 | 
             
                  end
         | 
| 80 88 |  | 
| 81 89 | 
             
                  sig { params(node: Prism::CallNode).void }
         | 
| @@ -25,6 +25,14 @@ module RubyLsp | |
| 25 25 | 
             
                      :on_call_node_enter,
         | 
| 26 26 | 
             
                      :on_constant_path_write_node_enter,
         | 
| 27 27 | 
             
                      :on_constant_write_node_enter,
         | 
| 28 | 
            +
                      :on_constant_path_or_write_node_enter,
         | 
| 29 | 
            +
                      :on_constant_path_operator_write_node_enter,
         | 
| 30 | 
            +
                      :on_constant_path_and_write_node_enter,
         | 
| 31 | 
            +
                      :on_constant_or_write_node_enter,
         | 
| 32 | 
            +
                      :on_constant_operator_write_node_enter,
         | 
| 33 | 
            +
                      :on_constant_and_write_node_enter,
         | 
| 34 | 
            +
                      :on_constant_target_node_enter,
         | 
| 35 | 
            +
                      :on_constant_path_target_node_enter,
         | 
| 28 36 | 
             
                      :on_def_node_enter,
         | 
| 29 37 | 
             
                      :on_def_node_leave,
         | 
| 30 38 | 
             
                      :on_module_node_enter,
         | 
| @@ -98,6 +106,86 @@ module RubyLsp | |
| 98 106 | 
             
                    )
         | 
| 99 107 | 
             
                  end
         | 
| 100 108 |  | 
| 109 | 
            +
                  sig { params(node: Prism::ConstantPathAndWriteNode).void }
         | 
| 110 | 
            +
                  def on_constant_path_and_write_node_enter(node)
         | 
| 111 | 
            +
                    create_document_symbol(
         | 
| 112 | 
            +
                      name: node.target.location.slice,
         | 
| 113 | 
            +
                      kind: Constant::SymbolKind::CONSTANT,
         | 
| 114 | 
            +
                      range_location: node.location,
         | 
| 115 | 
            +
                      selection_range_location: node.target.location,
         | 
| 116 | 
            +
                    )
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                  sig { params(node: Prism::ConstantPathOrWriteNode).void }
         | 
| 120 | 
            +
                  def on_constant_path_or_write_node_enter(node)
         | 
| 121 | 
            +
                    create_document_symbol(
         | 
| 122 | 
            +
                      name: node.target.location.slice,
         | 
| 123 | 
            +
                      kind: Constant::SymbolKind::CONSTANT,
         | 
| 124 | 
            +
                      range_location: node.location,
         | 
| 125 | 
            +
                      selection_range_location: node.target.location,
         | 
| 126 | 
            +
                    )
         | 
| 127 | 
            +
                  end
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                  sig { params(node: Prism::ConstantPathOperatorWriteNode).void }
         | 
| 130 | 
            +
                  def on_constant_path_operator_write_node_enter(node)
         | 
| 131 | 
            +
                    create_document_symbol(
         | 
| 132 | 
            +
                      name: node.target.location.slice,
         | 
| 133 | 
            +
                      kind: Constant::SymbolKind::CONSTANT,
         | 
| 134 | 
            +
                      range_location: node.location,
         | 
| 135 | 
            +
                      selection_range_location: node.target.location,
         | 
| 136 | 
            +
                    )
         | 
| 137 | 
            +
                  end
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                  sig { params(node: Prism::ConstantOrWriteNode).void }
         | 
| 140 | 
            +
                  def on_constant_or_write_node_enter(node)
         | 
| 141 | 
            +
                    create_document_symbol(
         | 
| 142 | 
            +
                      name: node.name.to_s,
         | 
| 143 | 
            +
                      kind: Constant::SymbolKind::CONSTANT,
         | 
| 144 | 
            +
                      range_location: node.location,
         | 
| 145 | 
            +
                      selection_range_location: node.name_loc,
         | 
| 146 | 
            +
                    )
         | 
| 147 | 
            +
                  end
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                  sig { params(node: Prism::ConstantAndWriteNode).void }
         | 
| 150 | 
            +
                  def on_constant_and_write_node_enter(node)
         | 
| 151 | 
            +
                    create_document_symbol(
         | 
| 152 | 
            +
                      name: node.name.to_s,
         | 
| 153 | 
            +
                      kind: Constant::SymbolKind::CONSTANT,
         | 
| 154 | 
            +
                      range_location: node.location,
         | 
| 155 | 
            +
                      selection_range_location: node.name_loc,
         | 
| 156 | 
            +
                    )
         | 
| 157 | 
            +
                  end
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                  sig { params(node: Prism::ConstantOperatorWriteNode).void }
         | 
| 160 | 
            +
                  def on_constant_operator_write_node_enter(node)
         | 
| 161 | 
            +
                    create_document_symbol(
         | 
| 162 | 
            +
                      name: node.name.to_s,
         | 
| 163 | 
            +
                      kind: Constant::SymbolKind::CONSTANT,
         | 
| 164 | 
            +
                      range_location: node.location,
         | 
| 165 | 
            +
                      selection_range_location: node.name_loc,
         | 
| 166 | 
            +
                    )
         | 
| 167 | 
            +
                  end
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                  sig { params(node: Prism::ConstantTargetNode).void }
         | 
| 170 | 
            +
                  def on_constant_target_node_enter(node)
         | 
| 171 | 
            +
                    create_document_symbol(
         | 
| 172 | 
            +
                      name: node.name.to_s,
         | 
| 173 | 
            +
                      kind: Constant::SymbolKind::CONSTANT,
         | 
| 174 | 
            +
                      range_location: node.location,
         | 
| 175 | 
            +
                      selection_range_location: node.location,
         | 
| 176 | 
            +
                    )
         | 
| 177 | 
            +
                  end
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                  sig { params(node: Prism::ConstantPathTargetNode).void }
         | 
| 180 | 
            +
                  def on_constant_path_target_node_enter(node)
         | 
| 181 | 
            +
                    create_document_symbol(
         | 
| 182 | 
            +
                      name: node.slice,
         | 
| 183 | 
            +
                      kind: Constant::SymbolKind::CONSTANT,
         | 
| 184 | 
            +
                      range_location: node.location,
         | 
| 185 | 
            +
                      selection_range_location: node.location,
         | 
| 186 | 
            +
                    )
         | 
| 187 | 
            +
                  end
         | 
| 188 | 
            +
             | 
| 101 189 | 
             
                  sig { params(node: Prism::DefNode).void }
         | 
| 102 190 | 
             
                  def on_def_node_leave(node)
         | 
| 103 191 | 
             
                    @response_builder.pop
         | 
| @@ -206,23 +294,34 @@ module RubyLsp | |
| 206 294 |  | 
| 207 295 | 
             
                  sig { params(node: Prism::CallNode).void }
         | 
| 208 296 | 
             
                  def handle_attr_accessor(node)
         | 
| 209 | 
            -
                     | 
| 297 | 
            +
                    receiver = node.receiver
         | 
| 298 | 
            +
                    return if receiver && !receiver.is_a?(Prism::SelfNode)
         | 
| 210 299 |  | 
| 211 300 | 
             
                    arguments = node.arguments
         | 
| 212 301 | 
             
                    return unless arguments
         | 
| 213 302 |  | 
| 214 303 | 
             
                    arguments.arguments.each do |argument|
         | 
| 215 | 
            -
                       | 
| 216 | 
            -
             | 
| 217 | 
            -
             | 
| 218 | 
            -
             | 
| 219 | 
            -
             | 
| 220 | 
            -
             | 
| 221 | 
            -
             | 
| 222 | 
            -
             | 
| 223 | 
            -
             | 
| 224 | 
            -
                         | 
| 225 | 
            -
                      )
         | 
| 304 | 
            +
                      if argument.is_a?(Prism::SymbolNode)
         | 
| 305 | 
            +
                        name = argument.value
         | 
| 306 | 
            +
                        next unless name
         | 
| 307 | 
            +
             | 
| 308 | 
            +
                        create_document_symbol(
         | 
| 309 | 
            +
                          name: name,
         | 
| 310 | 
            +
                          kind: Constant::SymbolKind::FIELD,
         | 
| 311 | 
            +
                          range_location: argument.location,
         | 
| 312 | 
            +
                          selection_range_location: T.must(argument.value_loc),
         | 
| 313 | 
            +
                        )
         | 
| 314 | 
            +
                      elsif argument.is_a?(Prism::StringNode)
         | 
| 315 | 
            +
                        name = argument.content
         | 
| 316 | 
            +
                        next if name.empty?
         | 
| 317 | 
            +
             | 
| 318 | 
            +
                        create_document_symbol(
         | 
| 319 | 
            +
                          name: name,
         | 
| 320 | 
            +
                          kind: Constant::SymbolKind::FIELD,
         | 
| 321 | 
            +
                          range_location: argument.location,
         | 
| 322 | 
            +
                          selection_range_location: argument.content_loc,
         | 
| 323 | 
            +
                        )
         | 
| 324 | 
            +
                      end
         | 
| 226 325 | 
             
                    end
         | 
| 227 326 | 
             
                  end
         | 
| 228 327 |  | 
| @@ -55,7 +55,10 @@ module RubyLsp | |
| 55 55 | 
             
                  def on_constant_read_node_enter(node)
         | 
| 56 56 | 
             
                    return if @typechecker_enabled
         | 
| 57 57 |  | 
| 58 | 
            -
                     | 
| 58 | 
            +
                    name = constant_name(node)
         | 
| 59 | 
            +
                    return if name.nil?
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                    generate_hover(name, node.location)
         | 
| 59 62 | 
             
                  end
         | 
| 60 63 |  | 
| 61 64 | 
             
                  sig { params(node: Prism::ConstantWriteNode).void }
         | 
| @@ -69,7 +72,10 @@ module RubyLsp | |
| 69 72 | 
             
                  def on_constant_path_node_enter(node)
         | 
| 70 73 | 
             
                    return if DependencyDetector.instance.typechecker
         | 
| 71 74 |  | 
| 72 | 
            -
                     | 
| 75 | 
            +
                    name = constant_name(node)
         | 
| 76 | 
            +
                    return if name.nil?
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                    generate_hover(name, node.location)
         | 
| 73 79 | 
             
                  end
         | 
| 74 80 |  | 
| 75 81 | 
             
                  sig { params(node: Prism::CallNode).void }
         | 
| @@ -86,10 +92,10 @@ module RubyLsp | |
| 86 92 | 
             
                    message = node.message
         | 
| 87 93 | 
             
                    return unless message
         | 
| 88 94 |  | 
| 89 | 
            -
                     | 
| 90 | 
            -
                    return unless  | 
| 95 | 
            +
                    methods = @index.resolve_method(message, @nesting.join("::"))
         | 
| 96 | 
            +
                    return unless methods
         | 
| 91 97 |  | 
| 92 | 
            -
                    categorized_markdown_from_index_entries(message,  | 
| 98 | 
            +
                    categorized_markdown_from_index_entries(message, methods).each do |category, content|
         | 
| 93 99 | 
             
                      @response_builder.push(content, category: category)
         | 
| 94 100 | 
             
                    end
         | 
| 95 101 | 
             
                  end
         | 
| @@ -30,7 +30,10 @@ module RubyLsp | |
| 30 30 | 
             
                    message = node.message
         | 
| 31 31 | 
             
                    return unless message
         | 
| 32 32 |  | 
| 33 | 
            -
                     | 
| 33 | 
            +
                    methods = @index.resolve_method(message, @nesting.join("::"))
         | 
| 34 | 
            +
                    return unless methods
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                    target_method = methods.first
         | 
| 34 37 | 
             
                    return unless target_method
         | 
| 35 38 |  | 
| 36 39 | 
             
                    parameters = target_method.parameters
         | 
| @@ -59,7 +62,7 @@ module RubyLsp | |
| 59 62 | 
             
                          parameters: parameters.map { |param| Interface::ParameterInformation.new(label: param.name) },
         | 
| 60 63 | 
             
                          documentation: Interface::MarkupContent.new(
         | 
| 61 64 | 
             
                            kind: "markdown",
         | 
| 62 | 
            -
                            value: markdown_from_index_entries("",  | 
| 65 | 
            +
                            value: markdown_from_index_entries("", methods),
         | 
| 63 66 | 
             
                          ),
         | 
| 64 67 | 
             
                        ),
         | 
| 65 68 | 
             
                      ],
         | 
| @@ -11,12 +11,12 @@ module RubyLsp | |
| 11 11 | 
             
                #
         | 
| 12 12 | 
             
                # The
         | 
| 13 13 | 
             
                # [code lens](https://microsoft.github.io/language-server-protocol/specification#textDocument_codeLens)
         | 
| 14 | 
            -
                # request informs the editor of runnable commands such as  | 
| 14 | 
            +
                # request informs the editor of runnable commands such as testing and debugging
         | 
| 15 15 | 
             
                #
         | 
| 16 16 | 
             
                # # Example
         | 
| 17 17 | 
             
                #
         | 
| 18 18 | 
             
                # ```ruby
         | 
| 19 | 
            -
                # # Run
         | 
| 19 | 
            +
                # # Run | Run in Terminal | Debug
         | 
| 20 20 | 
             
                # class Test < Minitest::Test
         | 
| 21 21 | 
             
                # end
         | 
| 22 22 | 
             
                # ```
         | 
| @@ -132,6 +132,21 @@ module RubyLsp | |
| 132 132 | 
             
                        #{categorized_markdown[:documentation]}
         | 
| 133 133 | 
             
                      MARKDOWN
         | 
| 134 134 | 
             
                    end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                    sig do
         | 
| 137 | 
            +
                      params(
         | 
| 138 | 
            +
                        node: T.any(
         | 
| 139 | 
            +
                          Prism::ConstantPathNode,
         | 
| 140 | 
            +
                          Prism::ConstantReadNode,
         | 
| 141 | 
            +
                          Prism::ConstantPathTargetNode,
         | 
| 142 | 
            +
                        ),
         | 
| 143 | 
            +
                      ).returns(T.nilable(String))
         | 
| 144 | 
            +
                    end
         | 
| 145 | 
            +
                    def constant_name(node)
         | 
| 146 | 
            +
                      node.full_name
         | 
| 147 | 
            +
                    rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError
         | 
| 148 | 
            +
                      nil
         | 
| 149 | 
            +
                    end
         | 
| 135 150 | 
             
                  end
         | 
| 136 151 | 
             
                end
         | 
| 137 152 | 
             
              end
         | 
| @@ -57,15 +57,18 @@ module RubyLsp | |
| 57 57 | 
             
                def setup!
         | 
| 58 58 | 
             
                  raise BundleNotLocked if @gemfile&.exist? && !@lockfile&.exist?
         | 
| 59 59 |  | 
| 60 | 
            -
                  # Do not  | 
| 61 | 
            -
                  if @dependencies["ruby-lsp"] && | 
| 60 | 
            +
                  # Do not set up a custom bundle if LSP dependencies are already in the Gemfile
         | 
| 61 | 
            +
                  if @dependencies["ruby-lsp"] &&
         | 
| 62 | 
            +
                      @dependencies["debug"] &&
         | 
| 63 | 
            +
                      (@dependencies["rails"] ? @dependencies["ruby-lsp-rails"] : true)
         | 
| 62 64 | 
             
                    $stderr.puts(
         | 
| 63 | 
            -
                      "Ruby LSP> Skipping custom bundle setup since  | 
| 65 | 
            +
                      "Ruby LSP> Skipping custom bundle setup since LSP dependencies are already in #{@gemfile}",
         | 
| 64 66 | 
             
                    )
         | 
| 65 67 |  | 
| 66 | 
            -
                    # If the user decided to add  | 
| 67 | 
            -
                    # then we need to remove the `.ruby-lsp` folder, otherwise we will run `bundle | 
| 68 | 
            -
                    # try to execute the Ruby LSP using the custom bundle, which will fail since the | 
| 68 | 
            +
                    # If the user decided to add `ruby-lsp` and `debug` (and potentially `ruby-lsp-rails`) to their Gemfile after
         | 
| 69 | 
            +
                    # having already run the Ruby LSP, then we need to remove the `.ruby-lsp` folder, otherwise we will run `bundle
         | 
| 70 | 
            +
                    # install` for the top level and try to execute the Ruby LSP using the custom bundle, which will fail since the
         | 
| 71 | 
            +
                    # gems are not installed there
         | 
| 69 72 | 
             
                    @custom_dir.rmtree if @custom_dir.exist?
         | 
| 70 73 | 
             
                    return run_bundle_install
         | 
| 71 74 | 
             
                  end
         | 
| @@ -143,6 +146,10 @@ module RubyLsp | |
| 143 146 | 
             
                    parts << 'gem "debug", require: false, group: :development, platforms: :mri'
         | 
| 144 147 | 
             
                  end
         | 
| 145 148 |  | 
| 149 | 
            +
                  if @dependencies["rails"] && !@dependencies["ruby-lsp-rails"]
         | 
| 150 | 
            +
                    parts << 'gem "ruby-lsp-rails", require: false, group: :development'
         | 
| 151 | 
            +
                  end
         | 
| 152 | 
            +
             | 
| 146 153 | 
             
                  content = parts.join("\n")
         | 
| 147 154 | 
             
                  @custom_gemfile.write(content) unless @custom_gemfile.exist? && @custom_gemfile.read == content
         | 
| 148 155 | 
             
                end
         | 
| @@ -183,22 +190,24 @@ module RubyLsp | |
| 183 190 | 
             
                  local_config_path = File.join(Dir.pwd, ".bundle")
         | 
| 184 191 | 
             
                  env["BUNDLE_APP_CONFIG"] = local_config_path if Dir.exist?(local_config_path)
         | 
| 185 192 |  | 
| 186 | 
            -
                  # If  | 
| 187 | 
            -
                  # produce undesired source control changes. If the custom bundle was just created | 
| 188 | 
            -
                  # weren't a part of the Gemfile, then we need to run `bundle | 
| 189 | 
            -
                  # Gemfile.lock with them included or else Bundler will complain that | 
| 190 | 
            -
                  # custom `.ruby-lsp/Gemfile.lock` already exists and includes  | 
| 193 | 
            +
                  # If `ruby-lsp` and `debug` (and potentially `ruby-lsp-rails`) are already in the Gemfile, then we shouldn't try
         | 
| 194 | 
            +
                  # to upgrade them or else we'll produce undesired source control changes. If the custom bundle was just created
         | 
| 195 | 
            +
                  # and any of `ruby-lsp`, `ruby-lsp-rails` or `debug` weren't a part of the Gemfile, then we need to run `bundle
         | 
| 196 | 
            +
                  # install` for the first time to generate the Gemfile.lock with them included or else Bundler will complain that
         | 
| 197 | 
            +
                  # they're missing. We can only update if the custom `.ruby-lsp/Gemfile.lock` already exists and includes all gems
         | 
| 191 198 |  | 
| 192 199 | 
             
                  # When not updating, we run `(bundle check || bundle install)`
         | 
| 193 200 | 
             
                  # When updating, we run `((bundle check && bundle update ruby-lsp debug) || bundle install)`
         | 
| 194 201 | 
             
                  command = +"(bundle check"
         | 
| 195 202 |  | 
| 196 203 | 
             
                  if should_bundle_update?
         | 
| 197 | 
            -
                    # If ruby-lsp or debug are not in the Gemfile, try to update them to the latest | 
| 204 | 
            +
                    # If any of `ruby-lsp`, `ruby-lsp-rails` or `debug` are not in the Gemfile, try to update them to the latest
         | 
| 205 | 
            +
                    # version
         | 
| 198 206 | 
             
                    command.prepend("(")
         | 
| 199 207 | 
             
                    command << " && bundle update "
         | 
| 200 208 | 
             
                    command << "ruby-lsp " unless @dependencies["ruby-lsp"]
         | 
| 201 209 | 
             
                    command << "debug " unless @dependencies["debug"]
         | 
| 210 | 
            +
                    command << "ruby-lsp-rails " if @dependencies["rails"] && !@dependencies["ruby-lsp-rails"]
         | 
| 202 211 | 
             
                    command << "--pre" if @experimental
         | 
| 203 212 | 
             
                    command.delete_suffix!(" ")
         | 
| 204 213 | 
             
                    command << ")"
         | 
| @@ -221,13 +230,20 @@ module RubyLsp | |
| 221 230 |  | 
| 222 231 | 
             
                sig { returns(T::Boolean) }
         | 
| 223 232 | 
             
                def should_bundle_update?
         | 
| 224 | 
            -
                  # If  | 
| 225 | 
            -
                  # version control changes
         | 
| 226 | 
            -
                   | 
| 233 | 
            +
                  # If `ruby-lsp`, `ruby-lsp-rails` and `debug` are in the Gemfile, then we shouldn't try to upgrade them or else it
         | 
| 234 | 
            +
                  # will produce version control changes
         | 
| 235 | 
            +
                  if @dependencies["rails"]
         | 
| 236 | 
            +
                    return false if @dependencies.values_at("ruby-lsp", "ruby-lsp-rails", "debug").all?
         | 
| 237 | 
            +
             | 
| 238 | 
            +
                    # If the custom lockfile doesn't include `ruby-lsp`, `ruby-lsp-rails` or `debug`, we need to run bundle install
         | 
| 239 | 
            +
                    # before updating
         | 
| 240 | 
            +
                    return false if custom_bundle_dependencies.values_at("ruby-lsp", "debug", "ruby-lsp-rails").any?(&:nil?)
         | 
| 241 | 
            +
                  else
         | 
| 242 | 
            +
                    return false if @dependencies.values_at("ruby-lsp", "debug").all?
         | 
| 227 243 |  | 
| 228 | 
            -
             | 
| 229 | 
            -
             | 
| 230 | 
            -
                   | 
| 244 | 
            +
                    # If the custom lockfile doesn't include `ruby-lsp` or `debug`, we need to run bundle install before updating
         | 
| 245 | 
            +
                    return false if custom_bundle_dependencies.values_at("ruby-lsp", "debug").any?(&:nil?)
         | 
| 246 | 
            +
                  end
         | 
| 231 247 |  | 
| 232 248 | 
             
                  # If the last updated file doesn't exist or was updated more than 4 hours ago, we should update
         | 
| 233 249 | 
             
                  !@last_updated_path.exist? || Time.parse(@last_updated_path.read) < (Time.now - FOUR_HOURS)
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: ruby-lsp
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.14. | 
| 4 | 
            +
              version: 0.14.2
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Shopify
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2024-02- | 
| 11 | 
            +
            date: 2024-02-22 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: language_server-protocol
         | 
| @@ -30,20 +30,20 @@ dependencies: | |
| 30 30 | 
             
                requirements:
         | 
| 31 31 | 
             
                - - ">="
         | 
| 32 32 | 
             
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            -
                    version: 0. | 
| 33 | 
            +
                    version: 0.22.0
         | 
| 34 34 | 
             
                - - "<"
         | 
| 35 35 | 
             
                  - !ruby/object:Gem::Version
         | 
| 36 | 
            -
                    version: '0. | 
| 36 | 
            +
                    version: '0.25'
         | 
| 37 37 | 
             
              type: :runtime
         | 
| 38 38 | 
             
              prerelease: false
         | 
| 39 39 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 40 40 | 
             
                requirements:
         | 
| 41 41 | 
             
                - - ">="
         | 
| 42 42 | 
             
                  - !ruby/object:Gem::Version
         | 
| 43 | 
            -
                    version: 0. | 
| 43 | 
            +
                    version: 0.22.0
         | 
| 44 44 | 
             
                - - "<"
         | 
| 45 45 | 
             
                  - !ruby/object:Gem::Version
         | 
| 46 | 
            -
                    version: '0. | 
| 46 | 
            +
                    version: '0.25'
         | 
| 47 47 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 48 48 | 
             
              name: sorbet-runtime
         | 
| 49 49 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -159,6 +159,7 @@ licenses: | |
| 159 159 | 
             
            - MIT
         | 
| 160 160 | 
             
            metadata:
         | 
| 161 161 | 
             
              allowed_push_host: https://rubygems.org
         | 
| 162 | 
            +
              documentation_uri: https://shopify.github.io/ruby-lsp/
         | 
| 162 163 | 
             
            post_install_message: 
         | 
| 163 164 | 
             
            rdoc_options: []
         | 
| 164 165 | 
             
            require_paths:
         |