ruby-lsp 0.17.11 → 0.17.13
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/VERSION +1 -1
- data/exe/ruby-lsp +4 -4
- data/exe/ruby-lsp-check +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +20 -3
- data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +26 -0
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +23 -0
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +76 -2
- data/lib/ruby_indexer/ruby_indexer.rb +1 -8
- data/lib/ruby_indexer/test/configuration_test.rb +1 -1
- data/lib/ruby_indexer/test/enhancements_test.rb +197 -0
- data/lib/ruby_lsp/addon.rb +9 -4
- data/lib/ruby_lsp/base_server.rb +7 -2
- data/lib/ruby_lsp/document.rb +0 -30
- data/lib/ruby_lsp/global_state.rb +33 -13
- data/lib/ruby_lsp/listeners/completion.rb +5 -5
- data/lib/ruby_lsp/listeners/definition.rb +3 -3
- data/lib/ruby_lsp/listeners/hover.rb +9 -6
- data/lib/ruby_lsp/listeners/signature_help.rb +1 -1
- data/lib/ruby_lsp/requests/code_action_resolve.rb +105 -7
- data/lib/ruby_lsp/requests/code_actions.rb +6 -0
- data/lib/ruby_lsp/requests/completion.rb +1 -1
- data/lib/ruby_lsp/requests/completion_resolve.rb +1 -0
- data/lib/ruby_lsp/requests/definition.rb +1 -1
- data/lib/ruby_lsp/requests/hover.rb +1 -1
- data/lib/ruby_lsp/requests/signature_help.rb +1 -1
- data/lib/ruby_lsp/requests/support/common.rb +2 -2
- data/lib/ruby_lsp/ruby_document.rb +64 -0
- data/lib/ruby_lsp/server.rb +33 -11
- data/lib/ruby_lsp/utils.rb +12 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 042725d7afce428b5c024933a7101151f2f69c57cbb40b4f938384c13d6c974b
|
4
|
+
data.tar.gz: bec8636d402451e1009e87ddd98e6fdedc062643e614b596a0698ffcfcc9b271
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a6adb40a9ccaaf916f46c041f3eb2cc7a81be73c5d3bf7c05a45472cd9d08e5a9dd04d804b8e15f091645d420037e324368ccbcc619311a1c60c81f241c1b89
|
7
|
+
data.tar.gz: d6b19c8d02cfab8dca9e4d675e8ee549e8b392631a6080757c0413da29a07d1db411d9360b7553a798805d9e6faac7318863e35ba664488c5eb41c869a7e734a
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.17.
|
1
|
+
0.17.13
|
data/exe/ruby-lsp
CHANGED
@@ -112,20 +112,20 @@ if options[:time_index]
|
|
112
112
|
end
|
113
113
|
|
114
114
|
if options[:doctor]
|
115
|
+
index = RubyIndexer::Index.new
|
116
|
+
|
115
117
|
if File.exist?(".index.yml")
|
116
118
|
begin
|
117
119
|
config = YAML.parse_file(".index.yml").to_ruby
|
118
120
|
rescue => e
|
119
121
|
abort("Error parsing config: #{e.message}")
|
120
122
|
end
|
121
|
-
|
123
|
+
index.configuration.apply_config(config)
|
122
124
|
end
|
123
125
|
|
124
|
-
index = RubyIndexer::Index.new
|
125
|
-
|
126
126
|
puts "Globbing for indexable files"
|
127
127
|
|
128
|
-
|
128
|
+
index.configuration.indexables.each do |indexable|
|
129
129
|
puts "indexing: #{indexable.full_path}"
|
130
130
|
index.index_single(indexable)
|
131
131
|
end
|
data/exe/ruby-lsp-check
CHANGED
@@ -44,7 +44,7 @@ puts "\n"
|
|
44
44
|
puts "Verifying that indexing executes successfully. This may take a while..."
|
45
45
|
|
46
46
|
index = RubyIndexer::Index.new
|
47
|
-
indexables =
|
47
|
+
indexables = index.configuration.indexables
|
48
48
|
|
49
49
|
indexables.each_with_index do |indexable, i|
|
50
50
|
index.index_single(indexable)
|
@@ -8,12 +8,22 @@ module RubyIndexer
|
|
8
8
|
OBJECT_NESTING = T.let(["Object"].freeze, T::Array[String])
|
9
9
|
BASIC_OBJECT_NESTING = T.let(["BasicObject"].freeze, T::Array[String])
|
10
10
|
|
11
|
+
sig { returns(T::Array[String]) }
|
12
|
+
attr_reader :indexing_errors
|
13
|
+
|
11
14
|
sig do
|
12
|
-
params(
|
15
|
+
params(
|
16
|
+
index: Index,
|
17
|
+
dispatcher: Prism::Dispatcher,
|
18
|
+
parse_result: Prism::ParseResult,
|
19
|
+
file_path: String,
|
20
|
+
enhancements: T::Array[Enhancement],
|
21
|
+
).void
|
13
22
|
end
|
14
|
-
def initialize(index, dispatcher, parse_result, file_path)
|
23
|
+
def initialize(index, dispatcher, parse_result, file_path, enhancements: [])
|
15
24
|
@index = index
|
16
25
|
@file_path = file_path
|
26
|
+
@enhancements = enhancements
|
17
27
|
@visibility_stack = T.let([Entry::Visibility::PUBLIC], T::Array[Entry::Visibility])
|
18
28
|
@comments_by_line = T.let(
|
19
29
|
parse_result.comments.to_h do |c|
|
@@ -29,6 +39,7 @@ module RubyIndexer
|
|
29
39
|
|
30
40
|
# A stack of namespace entries that represent where we currently are. Used to properly assign methods to an owner
|
31
41
|
@owner_stack = T.let([], T::Array[Entry::Namespace])
|
42
|
+
@indexing_errors = T.let([], T::Array[String])
|
32
43
|
|
33
44
|
dispatcher.register(
|
34
45
|
self,
|
@@ -279,6 +290,12 @@ module RubyIndexer
|
|
279
290
|
when :private
|
280
291
|
@visibility_stack.push(Entry::Visibility::PRIVATE)
|
281
292
|
end
|
293
|
+
|
294
|
+
@enhancements.each do |enhancement|
|
295
|
+
enhancement.on_call_node(@index, @owner_stack.last, node, @file_path)
|
296
|
+
rescue StandardError => e
|
297
|
+
@indexing_errors << "Indexing error in #{@file_path} with '#{enhancement.class.name}' enhancement: #{e.message}"
|
298
|
+
end
|
282
299
|
end
|
283
300
|
|
284
301
|
sig { params(node: Prism::CallNode).void }
|
@@ -535,7 +552,7 @@ module RubyIndexer
|
|
535
552
|
comment_content = comment.location.slice.chomp
|
536
553
|
|
537
554
|
# invalid encodings would raise an "invalid byte sequence" exception
|
538
|
-
if !comment_content.valid_encoding? || comment_content.match?(
|
555
|
+
if !comment_content.valid_encoding? || comment_content.match?(@index.configuration.magic_comment_regex)
|
539
556
|
next
|
540
557
|
end
|
541
558
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyIndexer
|
5
|
+
module Enhancement
|
6
|
+
extend T::Sig
|
7
|
+
extend T::Helpers
|
8
|
+
|
9
|
+
interface!
|
10
|
+
|
11
|
+
requires_ancestor { Object }
|
12
|
+
|
13
|
+
# The `on_extend` indexing enhancement is invoked whenever an extend is encountered in the code. It can be used to
|
14
|
+
# register for an included callback, similar to what `ActiveSupport::Concern` does in order to auto-extend the
|
15
|
+
# `ClassMethods` modules
|
16
|
+
sig do
|
17
|
+
abstract.params(
|
18
|
+
index: Index,
|
19
|
+
owner: T.nilable(Entry::Namespace),
|
20
|
+
node: Prism::CallNode,
|
21
|
+
file_path: String,
|
22
|
+
).void
|
23
|
+
end
|
24
|
+
def on_call_node(index, owner, node, file_path); end
|
25
|
+
end
|
26
|
+
end
|
@@ -342,6 +342,19 @@ module RubyIndexer
|
|
342
342
|
|
343
343
|
"(#{first_signature.format})"
|
344
344
|
end
|
345
|
+
|
346
|
+
sig { returns(String) }
|
347
|
+
def formatted_signatures
|
348
|
+
overloads_count = signatures.size
|
349
|
+
case overloads_count
|
350
|
+
when 1
|
351
|
+
""
|
352
|
+
when 2
|
353
|
+
"\n(+1 overload)"
|
354
|
+
else
|
355
|
+
"\n(+#{overloads_count - 1} overloads)"
|
356
|
+
end
|
357
|
+
end
|
345
358
|
end
|
346
359
|
|
347
360
|
class Accessor < Member
|
@@ -542,6 +555,16 @@ module RubyIndexer
|
|
542
555
|
def decorated_parameters
|
543
556
|
@target.decorated_parameters
|
544
557
|
end
|
558
|
+
|
559
|
+
sig { returns(String) }
|
560
|
+
def formatted_signatures
|
561
|
+
@target.formatted_signatures
|
562
|
+
end
|
563
|
+
|
564
|
+
sig { returns(T::Array[Signature]) }
|
565
|
+
def signatures
|
566
|
+
@target.signatures
|
567
|
+
end
|
545
568
|
end
|
546
569
|
|
547
570
|
# Ruby doesn't support method overloading, so a method will have only one signature.
|
@@ -11,6 +11,9 @@ module RubyIndexer
|
|
11
11
|
# The minimum Jaro-Winkler similarity score for an entry to be considered a match for a given fuzzy search query
|
12
12
|
ENTRY_SIMILARITY_THRESHOLD = 0.7
|
13
13
|
|
14
|
+
sig { returns(Configuration) }
|
15
|
+
attr_reader :configuration
|
16
|
+
|
14
17
|
sig { void }
|
15
18
|
def initialize
|
16
19
|
# Holds all entries in the index using the following format:
|
@@ -35,6 +38,29 @@ module RubyIndexer
|
|
35
38
|
|
36
39
|
# Holds the linearized ancestors list for every namespace
|
37
40
|
@ancestors = T.let({}, T::Hash[String, T::Array[String]])
|
41
|
+
|
42
|
+
# List of classes that are enhancing the index
|
43
|
+
@enhancements = T.let([], T::Array[Enhancement])
|
44
|
+
|
45
|
+
# Map of module name to included hooks that have to be executed when we include the given module
|
46
|
+
@included_hooks = T.let(
|
47
|
+
{},
|
48
|
+
T::Hash[String, T::Array[T.proc.params(index: Index, base: Entry::Namespace).void]],
|
49
|
+
)
|
50
|
+
|
51
|
+
@configuration = T.let(RubyIndexer::Configuration.new, Configuration)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Register an enhancement to the index. Enhancements must conform to the `Enhancement` interface
|
55
|
+
sig { params(enhancement: Enhancement).void }
|
56
|
+
def register_enhancement(enhancement)
|
57
|
+
@enhancements << enhancement
|
58
|
+
end
|
59
|
+
|
60
|
+
# Register an included `hook` that will be executed when `module_name` is included into any namespace
|
61
|
+
sig { params(module_name: String, hook: T.proc.params(index: Index, base: Entry::Namespace).void).void }
|
62
|
+
def register_included_hook(module_name, &hook)
|
63
|
+
(@included_hooks[module_name] ||= []) << hook
|
38
64
|
end
|
39
65
|
|
40
66
|
sig { params(indexable: IndexablePath).void }
|
@@ -275,7 +301,7 @@ module RubyIndexer
|
|
275
301
|
block: T.nilable(T.proc.params(progress: Integer).returns(T::Boolean)),
|
276
302
|
).void
|
277
303
|
end
|
278
|
-
def index_all(indexable_paths:
|
304
|
+
def index_all(indexable_paths: @configuration.indexables, &block)
|
279
305
|
RBSIndexer.new(self).index_ruby_core
|
280
306
|
# Calculate how many paths are worth 1% of progress
|
281
307
|
progress_step = (indexable_paths.length / 100.0).ceil
|
@@ -296,11 +322,25 @@ module RubyIndexer
|
|
296
322
|
dispatcher = Prism::Dispatcher.new
|
297
323
|
|
298
324
|
result = Prism.parse(content)
|
299
|
-
DeclarationListener.new(
|
325
|
+
listener = DeclarationListener.new(
|
326
|
+
self,
|
327
|
+
dispatcher,
|
328
|
+
result,
|
329
|
+
indexable_path.full_path,
|
330
|
+
enhancements: @enhancements,
|
331
|
+
)
|
300
332
|
dispatcher.dispatch(result.value)
|
301
333
|
|
334
|
+
indexing_errors = listener.indexing_errors.uniq
|
335
|
+
|
302
336
|
require_path = indexable_path.require_path
|
303
337
|
@require_paths_tree.insert(require_path, indexable_path) if require_path
|
338
|
+
|
339
|
+
if indexing_errors.any?
|
340
|
+
indexing_errors.each do |error|
|
341
|
+
$stderr.puts error
|
342
|
+
end
|
343
|
+
end
|
304
344
|
rescue Errno::EISDIR, Errno::ENOENT
|
305
345
|
# If `path` is a directory, just ignore it and continue indexing. If the file doesn't exist, then we also ignore
|
306
346
|
# it
|
@@ -457,6 +497,12 @@ module RubyIndexer
|
|
457
497
|
end
|
458
498
|
end
|
459
499
|
|
500
|
+
# We only need to run included hooks when linearizing singleton classes. Included hooks are typically used to add
|
501
|
+
# new singleton methods or to extend a module through an include. There's no need to support instance methods, the
|
502
|
+
# inclusion of another module or the prepending of another module, because those features are already a part of
|
503
|
+
# Ruby and can be used directly without any metaprogramming
|
504
|
+
run_included_hooks(attached_class_name, nesting) if singleton_levels > 0
|
505
|
+
|
460
506
|
linearize_mixins(ancestors, namespaces, nesting)
|
461
507
|
linearize_superclass(
|
462
508
|
ancestors,
|
@@ -570,6 +616,34 @@ module RubyIndexer
|
|
570
616
|
|
571
617
|
private
|
572
618
|
|
619
|
+
# Runs the registered included hooks
|
620
|
+
sig { params(fully_qualified_name: String, nesting: T::Array[String]).void }
|
621
|
+
def run_included_hooks(fully_qualified_name, nesting)
|
622
|
+
return if @included_hooks.empty?
|
623
|
+
|
624
|
+
namespaces = self[fully_qualified_name]&.grep(Entry::Namespace)
|
625
|
+
return unless namespaces
|
626
|
+
|
627
|
+
namespaces.each do |namespace|
|
628
|
+
namespace.mixin_operations.each do |operation|
|
629
|
+
next unless operation.is_a?(Entry::Include)
|
630
|
+
|
631
|
+
# First we resolve the include name, so that we know the actual module being referred to in the include
|
632
|
+
resolved_modules = resolve(operation.module_name, nesting)
|
633
|
+
next unless resolved_modules
|
634
|
+
|
635
|
+
module_name = T.must(resolved_modules.first).name
|
636
|
+
|
637
|
+
# Then we grab any hooks registered for that module
|
638
|
+
hooks = @included_hooks[module_name]
|
639
|
+
next unless hooks
|
640
|
+
|
641
|
+
# We invoke the hooks with the index and the namespace that included the module
|
642
|
+
hooks.each { |hook| hook.call(self, namespace) }
|
643
|
+
end
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
573
647
|
# Linearize mixins for an array of namespace entries. This method will mutate the `ancestors` array with the
|
574
648
|
# linearized ancestors of the mixins
|
575
649
|
sig do
|
@@ -6,6 +6,7 @@ require "did_you_mean"
|
|
6
6
|
|
7
7
|
require "ruby_indexer/lib/ruby_indexer/indexable_path"
|
8
8
|
require "ruby_indexer/lib/ruby_indexer/declaration_listener"
|
9
|
+
require "ruby_indexer/lib/ruby_indexer/enhancement"
|
9
10
|
require "ruby_indexer/lib/ruby_indexer/index"
|
10
11
|
require "ruby_indexer/lib/ruby_indexer/entry"
|
11
12
|
require "ruby_indexer/lib/ruby_indexer/configuration"
|
@@ -14,12 +15,4 @@ require "ruby_indexer/lib/ruby_indexer/location"
|
|
14
15
|
require "ruby_indexer/lib/ruby_indexer/rbs_indexer"
|
15
16
|
|
16
17
|
module RubyIndexer
|
17
|
-
@configuration = T.let(Configuration.new, Configuration)
|
18
|
-
|
19
|
-
class << self
|
20
|
-
extend T::Sig
|
21
|
-
|
22
|
-
sig { returns(Configuration) }
|
23
|
-
attr_reader :configuration
|
24
|
-
end
|
25
18
|
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative "test_case"
|
5
|
+
|
6
|
+
module RubyIndexer
|
7
|
+
class EnhancementTest < TestCase
|
8
|
+
def test_enhancing_indexing_included_hook
|
9
|
+
enhancement_class = Class.new do
|
10
|
+
include Enhancement
|
11
|
+
|
12
|
+
def on_call_node(index, owner, node, file_path)
|
13
|
+
return unless owner
|
14
|
+
return unless node.name == :extend
|
15
|
+
|
16
|
+
arguments = node.arguments&.arguments
|
17
|
+
return unless arguments
|
18
|
+
|
19
|
+
location = node.location
|
20
|
+
|
21
|
+
arguments.each do |node|
|
22
|
+
next unless node.is_a?(Prism::ConstantReadNode) || node.is_a?(Prism::ConstantPathNode)
|
23
|
+
|
24
|
+
module_name = node.full_name
|
25
|
+
next unless module_name == "ActiveSupport::Concern"
|
26
|
+
|
27
|
+
index.register_included_hook(owner.name) do |index, base|
|
28
|
+
class_methods_name = "#{owner.name}::ClassMethods"
|
29
|
+
|
30
|
+
if index.indexed?(class_methods_name)
|
31
|
+
singleton = index.existing_or_new_singleton_class(base.name)
|
32
|
+
singleton.mixin_operations << Entry::Include.new(class_methods_name)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
index.add(Entry::Method.new(
|
37
|
+
"new_method",
|
38
|
+
file_path,
|
39
|
+
location,
|
40
|
+
location,
|
41
|
+
[],
|
42
|
+
[Entry::Signature.new([Entry::RequiredParameter.new(name: :a)])],
|
43
|
+
Entry::Visibility::PUBLIC,
|
44
|
+
owner,
|
45
|
+
))
|
46
|
+
rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError,
|
47
|
+
Prism::ConstantPathNode::MissingNodesInConstantPathError
|
48
|
+
# Do nothing
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
@index.register_enhancement(enhancement_class.new)
|
54
|
+
index(<<~RUBY)
|
55
|
+
module ActiveSupport
|
56
|
+
module Concern
|
57
|
+
def self.extended(base)
|
58
|
+
base.class_eval("def new_method(a); end")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
module ActiveRecord
|
64
|
+
module Associations
|
65
|
+
extend ActiveSupport::Concern
|
66
|
+
|
67
|
+
module ClassMethods
|
68
|
+
def belongs_to(something); end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class Base
|
73
|
+
include Associations
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class User < ActiveRecord::Base
|
78
|
+
end
|
79
|
+
RUBY
|
80
|
+
|
81
|
+
assert_equal(
|
82
|
+
[
|
83
|
+
"User::<Class:User>",
|
84
|
+
"ActiveRecord::Base::<Class:Base>",
|
85
|
+
"ActiveRecord::Associations::ClassMethods",
|
86
|
+
"Object::<Class:Object>",
|
87
|
+
"BasicObject::<Class:BasicObject>",
|
88
|
+
"Class",
|
89
|
+
"Module",
|
90
|
+
"Object",
|
91
|
+
"Kernel",
|
92
|
+
"BasicObject",
|
93
|
+
],
|
94
|
+
@index.linearized_ancestors_of("User::<Class:User>"),
|
95
|
+
)
|
96
|
+
|
97
|
+
assert_entry("new_method", Entry::Method, "/fake/path/foo.rb:10-4:10-33")
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_enhancing_indexing_configuration_dsl
|
101
|
+
enhancement_class = Class.new do
|
102
|
+
include Enhancement
|
103
|
+
|
104
|
+
def on_call_node(index, owner, node, file_path)
|
105
|
+
return unless owner
|
106
|
+
|
107
|
+
name = node.name
|
108
|
+
return unless name == :has_many
|
109
|
+
|
110
|
+
arguments = node.arguments&.arguments
|
111
|
+
return unless arguments
|
112
|
+
|
113
|
+
association_name = arguments.first
|
114
|
+
return unless association_name.is_a?(Prism::SymbolNode)
|
115
|
+
|
116
|
+
location = association_name.location
|
117
|
+
|
118
|
+
index.add(Entry::Method.new(
|
119
|
+
T.must(association_name.value),
|
120
|
+
file_path,
|
121
|
+
location,
|
122
|
+
location,
|
123
|
+
[],
|
124
|
+
[],
|
125
|
+
Entry::Visibility::PUBLIC,
|
126
|
+
owner,
|
127
|
+
))
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
@index.register_enhancement(enhancement_class.new)
|
132
|
+
index(<<~RUBY)
|
133
|
+
module ActiveSupport
|
134
|
+
module Concern
|
135
|
+
def self.extended(base)
|
136
|
+
base.class_eval("def new_method(a); end")
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
module ActiveRecord
|
142
|
+
module Associations
|
143
|
+
extend ActiveSupport::Concern
|
144
|
+
|
145
|
+
module ClassMethods
|
146
|
+
def belongs_to(something); end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class Base
|
151
|
+
include Associations
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
class User < ActiveRecord::Base
|
156
|
+
has_many :posts
|
157
|
+
end
|
158
|
+
RUBY
|
159
|
+
|
160
|
+
assert_entry("posts", Entry::Method, "/fake/path/foo.rb:23-11:23-17")
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_error_handling_in_enhancement
|
164
|
+
enhancement_class = Class.new do
|
165
|
+
include Enhancement
|
166
|
+
|
167
|
+
def on_call_node(index, owner, node, file_path)
|
168
|
+
raise "Error"
|
169
|
+
end
|
170
|
+
|
171
|
+
class << self
|
172
|
+
def name
|
173
|
+
"TestEnhancement"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
@index.register_enhancement(enhancement_class.new)
|
179
|
+
|
180
|
+
_stdout, stderr = capture_io do
|
181
|
+
index(<<~RUBY)
|
182
|
+
module ActiveSupport
|
183
|
+
module Concern
|
184
|
+
def self.extended(base)
|
185
|
+
base.class_eval("def new_method(a); end")
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
RUBY
|
190
|
+
end
|
191
|
+
|
192
|
+
assert_match(%r{Indexing error in /fake/path/foo\.rb with 'TestEnhancement' enhancement}, stderr)
|
193
|
+
# The module should still be indexed
|
194
|
+
assert_entry("ActiveSupport::Concern", Entry::Module, "/fake/path/foo.rb:1-2:5-5")
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
data/lib/ruby_lsp/addon.rb
CHANGED
@@ -49,15 +49,18 @@ module RubyLsp
|
|
49
49
|
super
|
50
50
|
end
|
51
51
|
|
52
|
-
# Discovers and loads all addons. Returns
|
53
|
-
sig
|
52
|
+
# Discovers and loads all addons. Returns a list of errors when trying to require addons
|
53
|
+
sig do
|
54
|
+
params(global_state: GlobalState, outgoing_queue: Thread::Queue).returns(T::Array[StandardError])
|
55
|
+
end
|
54
56
|
def load_addons(global_state, outgoing_queue)
|
55
57
|
# Require all addons entry points, which should be placed under
|
56
58
|
# `some_gem/lib/ruby_lsp/your_gem_name/addon.rb`
|
57
|
-
Gem.find_files("ruby_lsp/**/addon.rb").
|
59
|
+
errors = Gem.find_files("ruby_lsp/**/addon.rb").filter_map do |addon|
|
58
60
|
require File.expand_path(addon)
|
61
|
+
nil
|
59
62
|
rescue => e
|
60
|
-
|
63
|
+
e
|
61
64
|
end
|
62
65
|
|
63
66
|
# Instantiate all discovered addon classes
|
@@ -71,6 +74,8 @@ module RubyLsp
|
|
71
74
|
rescue => e
|
72
75
|
addon.add_error(e)
|
73
76
|
end
|
77
|
+
|
78
|
+
errors
|
74
79
|
end
|
75
80
|
|
76
81
|
# Intended for use by tests for addons
|
data/lib/ruby_lsp/base_server.rb
CHANGED
@@ -65,7 +65,7 @@ module RubyLsp
|
|
65
65
|
when "initialize", "initialized", "textDocument/didOpen", "textDocument/didClose", "textDocument/didChange"
|
66
66
|
process_message(message)
|
67
67
|
when "shutdown"
|
68
|
-
|
68
|
+
send_log_message("Shutting down Ruby LSP...")
|
69
69
|
|
70
70
|
shutdown
|
71
71
|
|
@@ -76,7 +76,7 @@ module RubyLsp
|
|
76
76
|
when "exit"
|
77
77
|
@mutex.synchronize do
|
78
78
|
status = @incoming_queue.closed? ? 0 : 1
|
79
|
-
|
79
|
+
send_log_message("Shutdown complete with status #{status}")
|
80
80
|
exit(status)
|
81
81
|
end
|
82
82
|
else
|
@@ -145,5 +145,10 @@ module RubyLsp
|
|
145
145
|
def send_empty_response(id)
|
146
146
|
send_message(Result.new(id: id, response: nil))
|
147
147
|
end
|
148
|
+
|
149
|
+
sig { params(message: String, type: Integer).void }
|
150
|
+
def send_log_message(message, type: Constant::MessageType::LOG)
|
151
|
+
send_message(Notification.window_log_message(message, type: Constant::MessageType::LOG))
|
152
|
+
end
|
148
153
|
end
|
149
154
|
end
|
data/lib/ruby_lsp/document.rb
CHANGED
@@ -10,16 +10,6 @@ module RubyLsp
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
class SorbetLevel < T::Enum
|
14
|
-
enums do
|
15
|
-
None = new("none")
|
16
|
-
Ignore = new("ignore")
|
17
|
-
False = new("false")
|
18
|
-
True = new("true")
|
19
|
-
Strict = new("strict")
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
13
|
extend T::Sig
|
24
14
|
extend T::Helpers
|
25
15
|
|
@@ -223,26 +213,6 @@ module RubyLsp
|
|
223
213
|
NodeContext.new(closest, parent, nesting_nodes, call_node)
|
224
214
|
end
|
225
215
|
|
226
|
-
sig { returns(SorbetLevel) }
|
227
|
-
def sorbet_level
|
228
|
-
sigil = parse_result.magic_comments.find do |comment|
|
229
|
-
comment.key == "typed"
|
230
|
-
end&.value
|
231
|
-
|
232
|
-
case sigil
|
233
|
-
when "ignore"
|
234
|
-
SorbetLevel::Ignore
|
235
|
-
when "false"
|
236
|
-
SorbetLevel::False
|
237
|
-
when "true"
|
238
|
-
SorbetLevel::True
|
239
|
-
when "strict", "strong"
|
240
|
-
SorbetLevel::Strict
|
241
|
-
else
|
242
|
-
SorbetLevel::None
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
216
|
class Scanner
|
247
217
|
extend T::Sig
|
248
218
|
|