ruby-lsp-ree 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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