ruby-lsp-ree 0.1.2 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1104f2c78afb874d9277a4e2d1c8b5adaf925bdb4fb9abb23b08a9e5a27aff9
4
- data.tar.gz: 061f2b31a9aac045d279797b7561597db1825e396547b5afd94d6bfc4015af1e
3
+ metadata.gz: 8eb134e8d6b0ac3bf5321789ed6617ea1347ee096b1e642f953885b398524030
4
+ data.tar.gz: 460f2cc171155affbafe236535604b116d0af15bbcf14c3925470a8ff3616211
5
5
  SHA512:
6
- metadata.gz: 7f29b69bb720eadc44261c63719ca950cec24db996d0d4d83117c20c3a145bb6be8934420acb850ba92841feefe4985f0e0c1caa7129cd50a41a4419f3a2ca1e
7
- data.tar.gz: fea1f33dd0bcdfe401afe15304797fca57c254cf8472b34a8ef40d7f011d2bb60edb1010177129671fcbfc0f7ca69b212832c2c70ef8b8f125025a20be0ca17a
6
+ metadata.gz: cf49632399253b97f3b3df77ae7767008141900552461de8bca6b7395ac0d48fa4dbc5a353d2245f50147d7d119059b3f4d5a3f55aa41ae4fd11521d58b7930d
7
+ data.tar.gz: 0f392c77bbe2bdee9e9f613bc856c1d93b9bb9a2c87a93078017388fb253b27325d244ba289b36c24ff7e71e9f72b4f9c11abb663a7a2f675b5a9661aae29554
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.3.0
data/CHANGELOG.md CHANGED
@@ -1,8 +1,20 @@
1
- ## [Unreleased]
1
+ ## [0.1.3] - 2025-02-21
2
2
 
3
- ## [0.1.0] - 2025-01-31
3
+ - improved Go To Definition for ree object methods and imported constants
4
+ - support for :mapper objects
5
+ - support for :aggregate objects
6
+ - improved autocompletion for imported constants
7
+ - basic hover information for ree objects
4
8
 
5
- - Initial release
9
+ ## [0.1.2] - 2025-02-14
10
+
11
+ - support for :bean objects
12
+ - Go To Definition for imported constants
13
+ - use current (not saved) version of the document in autocomplete
14
+ - use current (not saved) version of the document in definition
15
+ - increase autocomplete list limits (affects short functions)
16
+ - improved const autocomplete
17
+ - improved ree errors handling
6
18
 
7
19
  ## [0.1.1] - 2025-02-10
8
20
 
@@ -21,12 +33,8 @@
21
33
  - autocomplete for ree dao
22
34
  - autocomplete for dao filters
23
35
 
24
- ## [0.1.2] - 2025-02-14
36
+ ## [0.1.0] - 2025-01-31
25
37
 
26
- - support for :bean objects
27
- - Go To Definition for imported constants
28
- - use current (no saved) version of the document in autocomplete
29
- - use current (no saved) version of the document in definition
30
- - increase autocomplete list limits (affects short functions)
31
- - improved const autocomplete
32
- - improved ree errors handling
38
+ - Initial release
39
+
40
+ ## [Unreleased]
data/Gemfile CHANGED
@@ -6,3 +6,9 @@ source "https://rubygems.org"
6
6
  gemspec
7
7
 
8
8
  gem "rake", "~> 13.0"
9
+
10
+ group :test do
11
+ gem 'rspec'
12
+ gem 'ruby-lsp'
13
+ gem "sorbet-static-and-runtime"
14
+ end
data/Gemfile.lock CHANGED
@@ -1,12 +1,44 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby-lsp-ree (0.1.2)
4
+ ruby-lsp-ree (0.1.3)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
+ diff-lcs (1.6.0)
10
+ language_server-protocol (3.17.0.4)
11
+ logger (1.6.6)
12
+ prism (1.3.0)
9
13
  rake (13.2.1)
14
+ rbs (3.8.1)
15
+ logger
16
+ rspec (3.13.0)
17
+ rspec-core (~> 3.13.0)
18
+ rspec-expectations (~> 3.13.0)
19
+ rspec-mocks (~> 3.13.0)
20
+ rspec-core (3.13.3)
21
+ rspec-support (~> 3.13.0)
22
+ rspec-expectations (3.13.3)
23
+ diff-lcs (>= 1.2.0, < 2.0)
24
+ rspec-support (~> 3.13.0)
25
+ rspec-mocks (3.13.2)
26
+ diff-lcs (>= 1.2.0, < 2.0)
27
+ rspec-support (~> 3.13.0)
28
+ rspec-support (3.13.2)
29
+ ruby-lsp (0.23.11)
30
+ language_server-protocol (~> 3.17.0)
31
+ prism (>= 1.2, < 2.0)
32
+ rbs (>= 3, < 4)
33
+ sorbet-runtime (>= 0.5.10782)
34
+ sorbet (0.5.11835)
35
+ sorbet-static (= 0.5.11835)
36
+ sorbet-runtime (0.5.11835)
37
+ sorbet-static (0.5.11835-universal-darwin)
38
+ sorbet-static (0.5.11835-x86_64-linux)
39
+ sorbet-static-and-runtime (0.5.11835)
40
+ sorbet (= 0.5.11835)
41
+ sorbet-runtime (= 0.5.11835)
10
42
 
11
43
  PLATFORMS
12
44
  x86_64-darwin-23
@@ -14,7 +46,10 @@ PLATFORMS
14
46
 
15
47
  DEPENDENCIES
16
48
  rake (~> 13.0)
49
+ rspec
50
+ ruby-lsp
17
51
  ruby-lsp-ree!
52
+ sorbet-static-and-runtime
18
53
 
19
54
  BUNDLED WITH
20
55
  2.6.3
data/Rakefile CHANGED
@@ -1,4 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bundler/gem_tasks"
4
- task default: %i[]
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: %i[spec]
@@ -1,8 +1,9 @@
1
1
  require "ruby_lsp/addon"
2
- require_relative "definition"
3
- require_relative "completion"
2
+ require_relative "listeners/definition_listener"
3
+ require_relative "listeners/completion_listener"
4
+ require_relative "listeners/hover_listener"
4
5
  require_relative "ree_indexing_enhancement"
5
- require_relative "ree_lsp_utils"
6
+ require_relative "utils/ree_lsp_utils"
6
7
  require_relative "ree_formatter"
7
8
  require_relative "parsing/parsed_document_builder"
8
9
 
@@ -25,12 +26,17 @@ module RubyLsp
25
26
 
26
27
  def create_definition_listener(response_builder, uri, node_context, dispatcher)
27
28
  index = @global_state.index
28
- RubyLsp::Ree::Definition.new(response_builder, node_context, index, dispatcher, uri)
29
+ RubyLsp::Ree::DefinitionListener.new(response_builder, node_context, index, dispatcher, uri)
29
30
  end
30
31
 
31
32
  def create_completion_listener(response_builder, node_context, dispatcher, uri)
32
33
  index = @global_state.index
33
- RubyLsp::Ree::Completion.new(response_builder, node_context, index, dispatcher, uri)
34
+ RubyLsp::Ree::CompletionListener.new(response_builder, node_context, index, dispatcher, uri)
35
+ end
36
+
37
+ def create_hover_listener(response_builder, node_context, dispatcher)
38
+ index = @global_state.index
39
+ RubyLsp::Ree::HoverListener.new(response_builder, node_context, index, dispatcher)
34
40
  end
35
41
  end
36
42
  end
@@ -1,11 +1,43 @@
1
- require_relative "ree_lsp_utils"
1
+ require_relative "../utils/ree_lsp_utils"
2
+ require_relative "../ree_object_finder"
2
3
 
3
4
  module RubyLsp
4
5
  module Ree
5
- module CompletionUtils
6
+ class CompletionHandler
6
7
  include Requests::Support::Common
7
8
  include RubyLsp::Ree::ReeLspUtils
8
9
 
10
+ RECEIVER_OBJECT_TYPES = [:enum, :dao, :bean]
11
+ CANDIDATES_LIMIT = 100
12
+
13
+ def initialize(index, uri, node_context)
14
+ @index = index
15
+ @uri = uri
16
+ @node_context = node_context
17
+ @finder = ReeObjectFinder.new(@index)
18
+ end
19
+
20
+ def get_ree_receiver(receiver_node)
21
+ return if !receiver_node || !receiver_node.is_a?(Prism::CallNode)
22
+
23
+ @finder.find_objects_by_types(receiver_node.name.to_s, RECEIVER_OBJECT_TYPES).first
24
+ end
25
+
26
+ def get_ree_object_methods_completions_items(ree_receiver, receiver_node, node)
27
+ location = receiver_node.location
28
+
29
+ case @finder.object_type(ree_receiver)
30
+ when :enum
31
+ get_enum_values_completion_items(ree_receiver, location)
32
+ when :bean
33
+ get_bean_methods_completion_items(ree_receiver, location)
34
+ when :dao
35
+ get_dao_filters_completion_items(ree_receiver, location)
36
+ else
37
+ []
38
+ end
39
+ end
40
+
9
41
  def get_bean_methods_completion_items(bean_obj, location)
10
42
  bean_node = RubyLsp::Ree::ParsedDocumentBuilder.build_from_uri(bean_obj.uri, :bean)
11
43
 
@@ -107,34 +139,75 @@ module RubyLsp
107
139
  end
108
140
  end
109
141
 
110
- def get_class_name_completion_items(class_name_objects, parsed_doc, node, index, limit)
111
- class_name_objects.take(limit).map do |full_class_name|
112
- entry = index[full_class_name].first
113
- class_name = full_class_name.split('::').last
114
-
115
- package_name = package_name_from_uri(entry.uri)
116
- file_name = File.basename(entry.uri.to_s)
117
-
118
- label_details = Interface::CompletionItemLabelDetails.new(
119
- description: "from: :#{package_name}",
120
- detail: " #{file_name}"
121
- )
122
-
123
- Interface::CompletionItem.new(
124
- label: class_name,
125
- label_details: label_details,
126
- filter_text: class_name,
127
- text_edit: Interface::TextEdit.new(
128
- range: range_from_location(node.location),
129
- new_text: class_name,
130
- ),
131
- kind: Constant::CompletionItemKind::CLASS,
132
- additional_text_edits: get_additional_text_edits_for_constant(parsed_doc, class_name, package_name, entry)
133
- )
142
+ def get_class_name_completion_items(node)
143
+ node_name = node.name.to_s
144
+ class_name_objects = @finder.search_class_objects(node_name)
145
+
146
+ return [] if class_name_objects.size == 0
147
+
148
+ parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@node_context.parent, @uri)
149
+
150
+ imported_consts = []
151
+ not_imported_consts = []
152
+
153
+ class_name_objects.take(CANDIDATES_LIMIT).each do |full_class_name|
154
+ entries = @index[full_class_name]
155
+
156
+ entries.each do |entry|
157
+ class_name = full_class_name.split('::').last
158
+ package_name = package_name_from_uri(entry.uri)
159
+ file_name = File.basename(entry.uri.to_s)
160
+
161
+ matched_import = parsed_doc.find_import_for_package(class_name, package_name)
162
+
163
+ if matched_import
164
+ label_details = Interface::CompletionItemLabelDetails.new(
165
+ description: "imported from: :#{package_name}",
166
+ detail: ""
167
+ )
168
+
169
+ imported_consts << Interface::CompletionItem.new(
170
+ label: class_name,
171
+ label_details: label_details,
172
+ filter_text: class_name,
173
+ text_edit: Interface::TextEdit.new(
174
+ range: range_from_location(node.location),
175
+ new_text: class_name,
176
+ ),
177
+ kind: Constant::CompletionItemKind::CLASS,
178
+ additional_text_edits: []
179
+ )
180
+ else
181
+ label_details = Interface::CompletionItemLabelDetails.new(
182
+ description: "from: :#{package_name}",
183
+ detail: " #{file_name}"
184
+ )
185
+
186
+ not_imported_consts << Interface::CompletionItem.new(
187
+ label: class_name,
188
+ label_details: label_details,
189
+ filter_text: class_name,
190
+ text_edit: Interface::TextEdit.new(
191
+ range: range_from_location(node.location),
192
+ new_text: class_name,
193
+ ),
194
+ kind: Constant::CompletionItemKind::CLASS,
195
+ additional_text_edits: get_additional_text_edits_for_constant(parsed_doc, class_name, package_name, entry)
196
+ )
197
+ end
198
+ end
134
199
  end
200
+
201
+ imported_consts + not_imported_consts
135
202
  end
136
203
 
137
- def get_ree_objects_completions_items(ree_objects, parsed_doc, node)
204
+ def get_ree_objects_completions_items(node)
205
+ ree_objects = @finder.search_objects(node.name.to_s, CANDIDATES_LIMIT)
206
+
207
+ return [] if ree_objects.size == 0
208
+
209
+ parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@node_context.parent, @uri)
210
+
138
211
  ree_objects.map do |ree_object|
139
212
  ree_object_name = ree_object.name
140
213
  package_name = package_name_from_uri(ree_object.uri)
@@ -254,6 +327,7 @@ module RubyLsp
254
327
  end
255
328
 
256
329
  range = get_range_for_fn_insert(parsed_doc, link_text)
330
+ return unless range
257
331
 
258
332
  [
259
333
  Interface::TextEdit.new(
@@ -0,0 +1,49 @@
1
+ require_relative "../handlers/completion_handler"
2
+
3
+ module RubyLsp
4
+ module Ree
5
+ class CompletionListener
6
+ include Requests::Support::Common
7
+
8
+ CHARS_COUNT = 1
9
+
10
+ def initialize(response_builder, node_context, index, dispatcher, uri)
11
+ @response_builder = response_builder
12
+ @handler = RubyLsp::Ree::CompletionHandler.new(index, uri, node_context)
13
+
14
+ dispatcher.register(self, :on_call_node_enter)
15
+ dispatcher.register(self, :on_constant_read_node_enter)
16
+ end
17
+
18
+ def on_constant_read_node_enter(node)
19
+ node_name = node.name.to_s
20
+ return if node_name.size < CHARS_COUNT
21
+
22
+ completion_items = @handler.get_class_name_completion_items(node)
23
+ put_items_into_response(completion_items)
24
+ end
25
+
26
+ def on_call_node_enter(node)
27
+ completion_items = []
28
+ ree_receiver = @handler.get_ree_receiver(node.receiver)
29
+
30
+ if ree_receiver
31
+ completion_items = @handler.get_ree_object_methods_completions_items(ree_receiver, node.receiver, node)
32
+ else
33
+ return if node.receiver
34
+ return if node.name.to_s.size < CHARS_COUNT
35
+
36
+ completion_items = @handler.get_ree_objects_completions_items(node)
37
+ end
38
+
39
+ put_items_into_response(completion_items)
40
+ end
41
+
42
+ def put_items_into_response(items)
43
+ items.each do |item|
44
+ @response_builder << item
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,9 +1,11 @@
1
- require_relative "ree_lsp_utils"
2
- require_relative "parsing/parsed_link_node"
1
+ require_relative "../utils/ree_lsp_utils"
2
+ require_relative "../parsing/parsed_link_node"
3
+ require_relative "../parsing/parsed_document_builder"
4
+ require_relative "../ree_object_finder"
3
5
 
4
6
  module RubyLsp
5
7
  module Ree
6
- class Definition
8
+ class DefinitionListener
7
9
  include Requests::Support::Common
8
10
  include RubyLsp::Ree::ReeLspUtils
9
11
 
@@ -18,13 +20,18 @@ module RubyLsp
18
20
  end
19
21
 
20
22
  def on_constant_read_node_enter(node)
21
- link_nodes = if @node_context.parent.is_a?(Prism::CallNode)
23
+ link_nodes = if @node_context.parent.is_a?(Prism::CallNode) && @node_context.parent.name == :link
22
24
  # inside link node
23
25
  link_node = RubyLsp::Ree::ParsedLinkNode.new(@node_context.parent)
24
26
  link_node.parse_imports
25
27
  [link_node]
26
28
  else
27
- parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@node_context.parent, @uri)
29
+ parsed_doc = if @node_context.parent.is_a?(Prism::CallNode)
30
+ RubyLsp::Ree::ParsedDocumentBuilder.build_from_uri(@uri)
31
+ else
32
+ RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@node_context.parent, @uri)
33
+ end
34
+
28
35
  parsed_doc.link_nodes
29
36
  end
30
37
 
@@ -63,11 +70,20 @@ module RubyLsp
63
70
  message = node.message
64
71
  return unless message
65
72
 
66
- method = @index[message].detect{ !_1.location.nil? }
67
- return unless method
73
+ definition_uri = nil
74
+
75
+ if node.receiver
76
+ # ruby lsp handles such cases itself
77
+ return
78
+ else
79
+ definition_item = ReeObjectFinder.new(@index).find_object(message)
80
+ definition_uri = definition_item.uri.to_s
81
+ end
82
+
83
+ return unless definition_uri
68
84
 
69
85
  @response_builder << Interface::Location.new(
70
- uri: method.uri.to_s,
86
+ uri: definition_uri,
71
87
  range: Interface::Range.new(
72
88
  start: Interface::Position.new(line: 0, character: 0),
73
89
  end: Interface::Position.new(line: 0, character: 0),
@@ -0,0 +1,65 @@
1
+ require_relative "../ree_object_finder"
2
+ require_relative "../parsing/parsed_document_builder"
3
+ require_relative "../parsing/parsed_link_node"
4
+ require_relative "../utils/ree_lsp_utils"
5
+
6
+ module RubyLsp
7
+ module Ree
8
+ class HoverListener
9
+ include RubyLsp::Ree::ReeLspUtils
10
+
11
+ def initialize(response_builder, node_context, index, dispatcher)
12
+ @response_builder = response_builder
13
+ @node_context = node_context
14
+ @finder = ReeObjectFinder.new(index)
15
+
16
+ dispatcher.register(self, :on_call_node_enter)
17
+ dispatcher.register(self, :on_constant_read_node_enter)
18
+ end
19
+
20
+ def on_constant_read_node_enter(node)
21
+ # ree_object = @finder.search_classes(node.name.to_s).first
22
+
23
+ # $stderr.puts("ree_object #{ree_object.inspect}")
24
+
25
+ # return unless ree_object
26
+
27
+ # $stderr.puts("ree_object comm #{ree_object.comments.to_s}")
28
+
29
+ # @response_builder.push(ree_object.comments.to_s, category: :documentation)
30
+ end
31
+
32
+ def on_call_node_enter(node)
33
+ ree_object = @finder.find_object(node.name.to_s)
34
+
35
+ return unless ree_object
36
+
37
+ documentation = <<~DOC
38
+ Ree object, type: :#{@finder.object_type(ree_object)}
39
+
40
+ usage: #{node.name.to_s}#{get_detail_string(ree_object)}
41
+
42
+ package: #{package_name_from_uri(ree_object.uri)}
43
+
44
+ file: #{path_from_package_folder(ree_object.uri)}
45
+ DOC
46
+
47
+ $stderr.puts(documentation)
48
+
49
+ @response_builder.push(documentation, category: :documentation)
50
+ end
51
+
52
+ def get_detail_string(ree_object)
53
+ return '' if ree_object.signatures.size == 0
54
+
55
+ "(#{get_parameters_string(ree_object.signatures.first)})"
56
+ end
57
+
58
+ def get_parameters_string(signature)
59
+ return '' unless signature
60
+
61
+ signature.parameters.map(&:decorated_name).join(', ')
62
+ end
63
+ end
64
+ end
65
+ end
@@ -5,20 +5,17 @@ class RubyLsp::Ree::ParsedDocument
5
5
 
6
6
  LINK_DSL_MODULE = 'Ree::LinkDSL'
7
7
 
8
- attr_reader :ast, :package_name, :class_node, :fn_node, :fn_block_node, :class_includes,
9
- :link_nodes, :values, :action_node, :action_block_node, :dao_node, :dao_block_node, :filters,
10
- :bean_node, :bean_block_node, :bean_methods
8
+ attr_reader :ast, :package_name, :class_node, :fn_node, :class_includes,
9
+ :link_nodes, :values, :action_node, :dao_node, :filters,
10
+ :bean_node, :bean_methods, :mapper_node, :links_container_block_node, :aggregate_node
11
11
 
12
12
  def initialize(ast)
13
13
  @ast = ast
14
14
  end
15
15
 
16
16
  def links_container_node
17
- @fn_node || @action_node || @dao_node || @bean_node
18
- end
19
-
20
- def links_container_block_node
21
- @fn_block_node || @action_block_node || @dao_block_node || @bean_block_node
17
+ # TODO don't use separate node, use one field for all and additional type field: links_container_node_type
18
+ @fn_node || @action_node || @dao_node || @bean_node || @mapper_node || @aggregate_node
22
19
  end
23
20
 
24
21
  def includes_link_dsl?
@@ -33,8 +30,24 @@ class RubyLsp::Ree::ParsedDocument
33
30
  @link_nodes.map(&:name).include?(obj_name)
34
31
  end
35
32
 
33
+ def find_link_node(name)
34
+ @link_nodes.detect{ _1.name == name }
35
+ end
36
+
37
+ def find_link_with_imported_object(name)
38
+ @link_nodes.detect do |link_node|
39
+ link_node.imports.include?(name)
40
+ end
41
+ end
42
+
43
+ def find_import_for_package(name, package_name)
44
+ @link_nodes.detect do |link_node|
45
+ link_node.imports.include?(name) && link_node.link_package_name == package_name
46
+ end
47
+ end
48
+
36
49
  def has_blank_links_container?
37
- links_container_node && !links_container_block_node
50
+ links_container_node && !@links_container_block_node
38
51
  end
39
52
 
40
53
  def set_package_name(package_name)
@@ -49,28 +62,42 @@ class RubyLsp::Ree::ParsedDocument
49
62
  return unless class_node
50
63
 
51
64
  @fn_node ||= class_node.body.body.detect{ |node| node.name == :fn }
52
- @fn_block_node = @fn_node&.block
65
+ @links_container_block_node ||= @fn_node&.block
53
66
  end
54
67
 
55
68
  def parse_action_node
56
69
  return unless class_node
57
70
 
58
71
  @action_node ||= class_node.body.body.detect{ |node| node.name == :action }
59
- @action_block_node = @action_node&.block
72
+ @links_container_block_node ||= @action_node&.block
60
73
  end
61
74
 
62
75
  def parse_dao_node
63
76
  return unless class_node
64
77
 
65
78
  @dao_node ||= class_node.body.body.detect{ |node| node.name == :dao }
66
- @dao_block_node = @dao_node&.block
79
+ @links_container_block_node ||= @dao_node&.block
67
80
  end
68
81
 
69
82
  def parse_bean_node
70
83
  return unless class_node
71
84
 
72
85
  @bean_node ||= class_node.body.body.detect{ |node| node.name == :bean }
73
- @bean_block_node = @bean_node&.block
86
+ @links_container_block_node ||= @bean_node&.block
87
+ end
88
+
89
+ def parse_mapper_node
90
+ return unless class_node
91
+
92
+ @mapper_node ||= class_node.body.body.detect{ |node| node.name == :mapper }
93
+ @links_container_block_node ||= @mapper_node&.block
94
+ end
95
+
96
+ def parse_aggregate_node
97
+ return unless class_node
98
+
99
+ @aggregate_node ||= class_node.body.body.detect{ |node| node.name == :aggregate }
100
+ @links_container_block_node ||= @aggregate_node&.block
74
101
  end
75
102
 
76
103
  def parse_class_includes
@@ -89,8 +116,8 @@ class RubyLsp::Ree::ParsedDocument
89
116
  def parse_links
90
117
  return unless class_node
91
118
 
92
- nodes = if links_container_node && links_container_block_node.body
93
- links_container_block_node.body.body.select{ |node| node.name == :link }
119
+ nodes = if links_container_node && @links_container_block_node.body
120
+ @links_container_block_node.body.body.select{ |node| node.name == :link }
94
121
  elsif class_includes.any?{ _1.name == LINK_DSL_MODULE }
95
122
  class_node.body.body.select{ |node| node.name == :link }
96
123
  else
@@ -47,6 +47,8 @@ class RubyLsp::Ree::ParsedDocumentBuilder
47
47
  document.parse_action_node
48
48
  document.parse_bean_node
49
49
  document.parse_dao_node
50
+ document.parse_mapper_node
51
+ document.parse_aggregate_node
50
52
  document.parse_class_includes
51
53
  document.parse_links
52
54
 
@@ -13,7 +13,12 @@ class RubyLsp::Ree::ParsedLinkNode
13
13
  end
14
14
 
15
15
  def link_package_name
16
- from_arg_value || document_package
16
+ case link_type
17
+ when :object_name
18
+ from_arg_value || document_package
19
+ when :file_path
20
+ @name.split('/').first
21
+ end
17
22
  end
18
23
 
19
24
  def location
@@ -1,12 +1,12 @@
1
1
  require 'prism'
2
- require_relative "ree_lsp_utils"
2
+ require_relative "utils/ree_lsp_utils"
3
3
 
4
4
  module RubyLsp
5
5
  module Ree
6
6
  class ReeIndexingEnhancement < RubyIndexer::Enhancement
7
7
  include RubyLsp::Ree::ReeLspUtils
8
8
 
9
- REE_INDEXED_OBJECTS = [:fn, :enum, :action, :dao, :bean]
9
+ REE_INDEXED_OBJECTS = [:fn, :enum, :action, :dao, :bean, :mapper, :aggregate]
10
10
 
11
11
  def on_call_node_enter(node)
12
12
  return unless @listener.current_owner
@@ -7,9 +7,15 @@ module RubyLsp
7
7
  ENUM_TYPE_STRING = 'type: :enum'
8
8
  DAO_TYPE_STRING = 'type: :dao'
9
9
  BEAN_TYPE_STRING = 'type: :bean'
10
+ MAPPER_TYPE_STRING = 'type: :mapper'
11
+ AGGREGATE_TYPE_STRING = 'type: :aggregate'
10
12
 
11
- def self.search_objects(index, name, limit)
12
- index.prefix_search(name)
13
+ def initialize(index)
14
+ @index = index
15
+ end
16
+
17
+ def search_objects(name, limit)
18
+ @index.prefix_search(name)
13
19
  .take(MAX_LIMIT)
14
20
  .flatten
15
21
  .select{ _1.comments }
@@ -18,26 +24,69 @@ module RubyLsp
18
24
  .take(limit)
19
25
  end
20
26
 
21
- def self.find_enum(index, name)
22
- objects_by_name = index[name]
27
+ def search_class_objects(name)
28
+ @index
29
+ .names
30
+ .select{ _1.split('::').last[0...name.size] == name}
31
+ end
32
+
33
+ def search_classes(name)
34
+ keys = search_class_objects(name)
35
+ @index.instance_variable_get(:@entries).values_at(*keys)
36
+ end
37
+
38
+ def find_object(name)
39
+ objects_by_name = @index[name]
40
+ return unless objects_by_name
41
+
42
+ objects_by_name.detect{ _1.comments.to_s.lines.first&.chomp == REE_OBJECT_STRING }
43
+ end
44
+
45
+ def find_objects_by_types(name, types)
46
+ objects_by_name = @index[name]
47
+ return [] unless objects_by_name
48
+
49
+ objects_by_name.select{ types.include?(object_type(_1)) }
50
+ end
51
+
52
+ def find_enum(name)
53
+ objects_by_name = @index[name]
23
54
  return unless objects_by_name
24
55
 
25
56
  objects_by_name.detect{ _1.comments.lines[1]&.chomp == ENUM_TYPE_STRING }
26
57
  end
27
58
 
28
- def self.find_dao(index, name)
29
- objects_by_name = index[name]
59
+ def find_dao(name)
60
+ objects_by_name = @index[name]
30
61
  return unless objects_by_name
31
62
 
32
63
  objects_by_name.detect{ _1.comments.lines[1]&.chomp == DAO_TYPE_STRING }
33
64
  end
34
65
 
35
- def self.find_bean(index, name)
36
- objects_by_name = index[name]
66
+ def find_bean(index, name)
67
+ objects_by_name = @index[name]
37
68
  return unless objects_by_name
38
69
 
39
70
  objects_by_name.detect{ _1.comments.lines[1]&.chomp == BEAN_TYPE_STRING }
40
71
  end
72
+
73
+ def object_type(ree_object)
74
+ # TODO rewrite to use string split
75
+ case ree_object.comments.lines[1]&.chomp
76
+ when DAO_TYPE_STRING
77
+ :dao
78
+ when BEAN_TYPE_STRING
79
+ :bean
80
+ when ENUM_TYPE_STRING
81
+ :enum
82
+ when MAPPER_TYPE_STRING
83
+ :mapper
84
+ when AGGREGATE_TYPE_STRING
85
+ :aggregate
86
+ else
87
+ nil
88
+ end
89
+ end
41
90
  end
42
91
  end
43
92
  end
@@ -18,7 +18,7 @@ module RubyLsp
18
18
  end
19
19
 
20
20
  def path_from_package_folder(uri)
21
- uri_parts = uri.chomp(File.extname(uri)).split('/')
21
+ uri_parts = uri.to_s.chomp(File.extname(uri)).split('/')
22
22
 
23
23
  package_folder_index = uri_parts.index('package')
24
24
  return unless package_folder_index
@@ -49,6 +49,8 @@ module RubyLsp
49
49
  elsif parsed_doc.includes_link_dsl?
50
50
  fn_line = parsed_doc.link_nodes.first.location.start_line - 1
51
51
  position = parsed_doc.link_nodes.first.location.start_column
52
+ else
53
+ return nil
52
54
  end
53
55
 
54
56
  Interface::Range.new(
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Ruby
4
- module Lsp
5
- module Ree
6
- VERSION = "0.1.2"
7
- end
3
+ module RubyLsp
4
+ module Ree
5
+ VERSION = "0.1.3"
8
6
  end
9
7
  end
data/ruby-lsp-ree.gemspec CHANGED
@@ -4,7 +4,7 @@ require_relative "lib/ruby_lsp_ree/version"
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "ruby-lsp-ree"
7
- spec.version = Ruby::Lsp::Ree::VERSION
7
+ spec.version = RubyLsp::Ree::VERSION
8
8
  spec.authors = ["Ruslan Gatiyatov"]
9
9
  spec.email = ["ruslan.gatiyatov@gmail.com"]
10
10
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lsp-ree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruslan Gatiyatov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-02-14 00:00:00.000000000 Z
11
+ date: 2025-02-21 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A Ruby LSP addon that adds extra editor functionality for Ree applications
14
14
  email:
@@ -17,6 +17,7 @@ executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
+ - ".ruby-version"
20
21
  - CHANGELOG.md
21
22
  - CODE_OF_CONDUCT.md
22
23
  - Gemfile
@@ -25,16 +26,17 @@ files:
25
26
  - README.md
26
27
  - Rakefile
27
28
  - lib/ruby_lsp/ruby_lsp_ree/addon.rb
28
- - lib/ruby_lsp/ruby_lsp_ree/completion.rb
29
- - lib/ruby_lsp/ruby_lsp_ree/completion_utils.rb
30
- - lib/ruby_lsp/ruby_lsp_ree/definition.rb
29
+ - lib/ruby_lsp/ruby_lsp_ree/handlers/completion_handler.rb
30
+ - lib/ruby_lsp/ruby_lsp_ree/listeners/completion_listener.rb
31
+ - lib/ruby_lsp/ruby_lsp_ree/listeners/definition_listener.rb
32
+ - lib/ruby_lsp/ruby_lsp_ree/listeners/hover_listener.rb
31
33
  - lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_document.rb
32
34
  - lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_document_builder.rb
33
35
  - lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_link_node.rb
34
36
  - lib/ruby_lsp/ruby_lsp_ree/ree_formatter.rb
35
37
  - lib/ruby_lsp/ruby_lsp_ree/ree_indexing_enhancement.rb
36
- - lib/ruby_lsp/ruby_lsp_ree/ree_lsp_utils.rb
37
38
  - lib/ruby_lsp/ruby_lsp_ree/ree_object_finder.rb
39
+ - lib/ruby_lsp/ruby_lsp_ree/utils/ree_lsp_utils.rb
38
40
  - lib/ruby_lsp_ree.rb
39
41
  - lib/ruby_lsp_ree/version.rb
40
42
  - ruby-lsp-ree.gemspec
@@ -61,7 +63,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
61
63
  - !ruby/object:Gem::Version
62
64
  version: '0'
63
65
  requirements: []
64
- rubygems_version: 3.4.1
66
+ rubygems_version: 3.5.3
65
67
  signing_key:
66
68
  specification_version: 4
67
69
  summary: Ruby LSP addon for Ree framework.
@@ -1,108 +0,0 @@
1
- require_relative "ree_lsp_utils"
2
- require_relative "completion_utils"
3
- require_relative "ree_object_finder"
4
-
5
- module RubyLsp
6
- module Ree
7
- class Completion
8
- include Requests::Support::Common
9
- include RubyLsp::Ree::ReeLspUtils
10
- include RubyLsp::Ree::CompletionUtils
11
-
12
- CHARS_COUNT = 1
13
- CANDIDATES_LIMIT = 100
14
-
15
- def initialize(response_builder, node_context, index, dispatcher, uri)
16
- @response_builder = response_builder
17
- @index = index
18
- @uri = uri
19
- @node_context = node_context
20
-
21
- dispatcher.register(self, :on_call_node_enter)
22
- dispatcher.register(self, :on_constant_read_node_enter)
23
- end
24
-
25
- def on_constant_read_node_enter(node)
26
- node_name = node.name.to_s
27
- return if node_name.size < CHARS_COUNT
28
-
29
- class_name_objects = @index.instance_variable_get(:@entries).keys.select{ _1.split('::').last[0...node_name.size] == node_name}
30
- return if class_name_objects.size == 0
31
-
32
- parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@node_context.parent, @uri)
33
-
34
- completion_items = get_class_name_completion_items(class_name_objects, parsed_doc, node, @index, CANDIDATES_LIMIT)
35
- put_items_into_response(completion_items)
36
- end
37
-
38
- def on_call_node_enter(node)
39
- if receiver_is_enum?(node)
40
- return enum_value_completion(node)
41
- end
42
-
43
- if receiver_is_dao?(node)
44
- return dao_filter_completion(node)
45
- end
46
-
47
- if receiver_is_bean?(node)
48
- return bean_method_completion(node)
49
- end
50
-
51
- return if node.receiver
52
- return if node.name.to_s.size < CHARS_COUNT
53
-
54
- ree_objects = ReeObjectFinder.search_objects(@index, node.name.to_s, CANDIDATES_LIMIT)
55
-
56
- return if ree_objects.size == 0
57
-
58
- parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@node_context.parent, @uri)
59
-
60
- completion_items = get_ree_objects_completions_items(ree_objects, parsed_doc, node)
61
- put_items_into_response(completion_items)
62
- end
63
-
64
- def receiver_is_enum?(node)
65
- node.receiver && node.receiver.is_a?(Prism::CallNode) && ReeObjectFinder.find_enum(@index, node.receiver.name.to_s)
66
- end
67
-
68
- def receiver_is_dao?(node)
69
- node.receiver && node.receiver.is_a?(Prism::CallNode) && ReeObjectFinder.find_dao(@index, node.receiver.name.to_s)
70
- end
71
-
72
- def receiver_is_bean?(node)
73
- node.receiver && node.receiver.is_a?(Prism::CallNode) && ReeObjectFinder.find_bean(@index, node.receiver.name.to_s)
74
- end
75
-
76
- def enum_value_completion(node)
77
- enum_obj = ReeObjectFinder.find_enum(@index, node.receiver.name.to_s)
78
- location = node.receiver.location
79
-
80
- completion_items = get_enum_values_completion_items(enum_obj, location)
81
- put_items_into_response(completion_items)
82
- end
83
-
84
- def dao_filter_completion(node)
85
- dao_obj = ReeObjectFinder.find_dao(@index, node.receiver.name.to_s)
86
- location = node.receiver.location
87
-
88
- completion_items = get_dao_filters_completion_items(dao_obj, location)
89
- put_items_into_response(completion_items)
90
- end
91
-
92
- def bean_method_completion(node)
93
- bean_obj = ReeObjectFinder.find_bean(@index, node.receiver.name.to_s)
94
- location = node.receiver.location
95
-
96
- completion_items = get_bean_methods_completion_items(bean_obj, location)
97
-
98
- put_items_into_response(completion_items)
99
- end
100
-
101
- def put_items_into_response(items)
102
- items.each do |item|
103
- @response_builder << item
104
- end
105
- end
106
- end
107
- end
108
- end