ruby-lsp 0.13.1 → 0.13.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +30 -0
  3. data/VERSION +1 -1
  4. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +1 -1
  5. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +30 -1
  6. data/lib/ruby_lsp/check_docs.rb +3 -3
  7. data/lib/ruby_lsp/document.rb +15 -7
  8. data/lib/ruby_lsp/executor.rb +85 -226
  9. data/lib/ruby_lsp/listener.rb +1 -50
  10. data/lib/ruby_lsp/listeners/code_lens.rb +233 -0
  11. data/lib/ruby_lsp/listeners/completion.rb +275 -0
  12. data/lib/ruby_lsp/listeners/definition.rb +158 -0
  13. data/lib/ruby_lsp/listeners/document_highlight.rb +556 -0
  14. data/lib/ruby_lsp/listeners/document_link.rb +162 -0
  15. data/lib/ruby_lsp/listeners/document_symbol.rb +223 -0
  16. data/lib/ruby_lsp/listeners/folding_ranges.rb +271 -0
  17. data/lib/ruby_lsp/listeners/hover.rb +152 -0
  18. data/lib/ruby_lsp/listeners/inlay_hints.rb +80 -0
  19. data/lib/ruby_lsp/listeners/semantic_highlighting.rb +430 -0
  20. data/lib/ruby_lsp/listeners/signature_help.rb +74 -0
  21. data/lib/ruby_lsp/requests/code_action_resolve.rb +5 -5
  22. data/lib/ruby_lsp/requests/code_actions.rb +15 -6
  23. data/lib/ruby_lsp/requests/code_lens.rb +21 -221
  24. data/lib/ruby_lsp/requests/completion.rb +64 -246
  25. data/lib/ruby_lsp/requests/definition.rb +34 -147
  26. data/lib/ruby_lsp/requests/diagnostics.rb +17 -5
  27. data/lib/ruby_lsp/requests/document_highlight.rb +12 -536
  28. data/lib/ruby_lsp/requests/document_link.rb +11 -132
  29. data/lib/ruby_lsp/requests/document_symbol.rb +23 -210
  30. data/lib/ruby_lsp/requests/folding_ranges.rb +16 -252
  31. data/lib/ruby_lsp/requests/formatting.rb +4 -4
  32. data/lib/ruby_lsp/requests/hover.rb +48 -92
  33. data/lib/ruby_lsp/requests/inlay_hints.rb +23 -56
  34. data/lib/ruby_lsp/requests/on_type_formatting.rb +18 -6
  35. data/lib/ruby_lsp/requests/request.rb +17 -0
  36. data/lib/ruby_lsp/requests/selection_ranges.rb +4 -3
  37. data/lib/ruby_lsp/requests/semantic_highlighting.rb +21 -408
  38. data/lib/ruby_lsp/requests/show_syntax_tree.rb +5 -5
  39. data/lib/ruby_lsp/requests/signature_help.rb +87 -0
  40. data/lib/ruby_lsp/requests/support/common.rb +3 -2
  41. data/lib/ruby_lsp/requests/support/dependency_detector.rb +2 -0
  42. data/lib/ruby_lsp/requests/support/selection_range.rb +1 -1
  43. data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +2 -2
  44. data/lib/ruby_lsp/requests/workspace_symbol.rb +5 -4
  45. data/lib/ruby_lsp/requests.rb +3 -1
  46. data/lib/ruby_lsp/store.rb +1 -1
  47. data/lib/ruby_lsp/utils.rb +8 -0
  48. metadata +20 -8
  49. data/lib/ruby_lsp/requests/base_request.rb +0 -24
@@ -0,0 +1,158 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module Listeners
6
+ class Definition < Listener
7
+ extend T::Sig
8
+ extend T::Generic
9
+
10
+ ResponseType = type_member { { fixed: T.nilable(T.any(T::Array[Interface::Location], Interface::Location)) } }
11
+
12
+ sig { override.returns(ResponseType) }
13
+ attr_reader :_response
14
+
15
+ sig do
16
+ params(
17
+ uri: URI::Generic,
18
+ nesting: T::Array[String],
19
+ index: RubyIndexer::Index,
20
+ dispatcher: Prism::Dispatcher,
21
+ typechecker_enabled: T::Boolean,
22
+ ).void
23
+ end
24
+ def initialize(uri, nesting, index, dispatcher, typechecker_enabled)
25
+ @uri = uri
26
+ @nesting = nesting
27
+ @index = index
28
+ @typechecker_enabled = typechecker_enabled
29
+ @_response = T.let(nil, ResponseType)
30
+
31
+ super(dispatcher)
32
+
33
+ dispatcher.register(
34
+ self,
35
+ :on_call_node_enter,
36
+ :on_constant_read_node_enter,
37
+ :on_constant_path_node_enter,
38
+ )
39
+ end
40
+
41
+ sig { params(node: Prism::CallNode).void }
42
+ def on_call_node_enter(node)
43
+ message = node.name
44
+
45
+ if message == :require || message == :require_relative
46
+ handle_require_definition(node)
47
+ else
48
+ handle_method_definition(node)
49
+ end
50
+ end
51
+
52
+ sig { params(node: Prism::ConstantPathNode).void }
53
+ def on_constant_path_node_enter(node)
54
+ find_in_index(node.slice)
55
+ end
56
+
57
+ sig { params(node: Prism::ConstantReadNode).void }
58
+ def on_constant_read_node_enter(node)
59
+ find_in_index(node.slice)
60
+ end
61
+
62
+ private
63
+
64
+ sig { params(node: Prism::CallNode).void }
65
+ def handle_method_definition(node)
66
+ return unless self_receiver?(node)
67
+
68
+ message = node.message
69
+ return unless message
70
+
71
+ target_method = @index.resolve_method(message, @nesting.join("::"))
72
+ return unless target_method
73
+
74
+ location = target_method.location
75
+ file_path = target_method.file_path
76
+ return if @typechecker_enabled && not_in_dependencies?(file_path)
77
+
78
+ @_response = Interface::Location.new(
79
+ uri: URI::Generic.from_path(path: file_path).to_s,
80
+ range: Interface::Range.new(
81
+ start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
82
+ end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
83
+ ),
84
+ )
85
+ end
86
+
87
+ sig { params(node: Prism::CallNode).void }
88
+ def handle_require_definition(node)
89
+ message = node.name
90
+ arguments = node.arguments
91
+ return unless arguments
92
+
93
+ argument = arguments.arguments.first
94
+ return unless argument.is_a?(Prism::StringNode)
95
+
96
+ case message
97
+ when :require
98
+ entry = @index.search_require_paths(argument.content).find do |indexable_path|
99
+ indexable_path.require_path == argument.content
100
+ end
101
+
102
+ if entry
103
+ candidate = entry.full_path
104
+
105
+ @_response = Interface::Location.new(
106
+ uri: URI::Generic.from_path(path: candidate).to_s,
107
+ range: Interface::Range.new(
108
+ start: Interface::Position.new(line: 0, character: 0),
109
+ end: Interface::Position.new(line: 0, character: 0),
110
+ ),
111
+ )
112
+ end
113
+ when :require_relative
114
+ required_file = "#{argument.content}.rb"
115
+ path = @uri.to_standardized_path
116
+ current_folder = path ? Pathname.new(CGI.unescape(path)).dirname : Dir.pwd
117
+ candidate = File.expand_path(File.join(current_folder, required_file))
118
+
119
+ @_response = Interface::Location.new(
120
+ uri: URI::Generic.from_path(path: candidate).to_s,
121
+ range: Interface::Range.new(
122
+ start: Interface::Position.new(line: 0, character: 0),
123
+ end: Interface::Position.new(line: 0, character: 0),
124
+ ),
125
+ )
126
+ end
127
+ end
128
+
129
+ sig { params(value: String).void }
130
+ def find_in_index(value)
131
+ entries = @index.resolve(value, @nesting)
132
+ return unless entries
133
+
134
+ # We should only allow jumping to the definition of private constants if the constant is defined in the same
135
+ # namespace as the reference
136
+ first_entry = T.must(entries.first)
137
+ return if first_entry.visibility == :private && first_entry.name != "#{@nesting.join("::")}::#{value}"
138
+
139
+ @_response = entries.filter_map do |entry|
140
+ location = entry.location
141
+ # If the project has Sorbet, then we only want to handle go to definition for constants defined in gems, as an
142
+ # additional behavior on top of jumping to RBIs. Sorbet can already handle go to definition for all constants
143
+ # in the project, even if the files are typed false
144
+ file_path = entry.file_path
145
+ next if @typechecker_enabled && not_in_dependencies?(file_path)
146
+
147
+ Interface::Location.new(
148
+ uri: URI::Generic.from_path(path: file_path).to_s,
149
+ range: Interface::Range.new(
150
+ start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
151
+ end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
152
+ ),
153
+ )
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end