ruby-lsp-ree 0.1.3 → 0.1.4

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: 8eb134e8d6b0ac3bf5321789ed6617ea1347ee096b1e642f953885b398524030
4
- data.tar.gz: 460f2cc171155affbafe236535604b116d0af15bbcf14c3925470a8ff3616211
3
+ metadata.gz: a1d126a7d0c8462f33b63113cf86ae134f8cb029da147273bdb2f8cb76cb448e
4
+ data.tar.gz: dbb25c53fc012b487a3ed9555ad470c10445603e808aa3f44442070b4fc57851
5
5
  SHA512:
6
- metadata.gz: cf49632399253b97f3b3df77ae7767008141900552461de8bca6b7395ac0d48fa4dbc5a353d2245f50147d7d119059b3f4d5a3f55aa41ae4fd11521d58b7930d
7
- data.tar.gz: 0f392c77bbe2bdee9e9f613bc856c1d93b9bb9a2c87a93078017388fb253b27325d244ba289b36c24ff7e71e9f72b4f9c11abb663a7a2f675b5a9661aae29554
6
+ metadata.gz: 50d85fbda0c61e33709823c7e8b5f263d94eba2d6822b1e84f011ad0b058adf6d5766a5fe27b6613c537b2e36f878a8ef50ddf7fad7dd41cfd954011fe90c156
7
+ data.tar.gz: 66c76a82263258d76fcc7cc604e6aa499deb209ae80c6ae8a5bad1dd486f7ee70c9e0af896277c0cc01631ad99c91f5b5b827e18337b0d95e4d18622d1c2c389
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [0.1.4] - 2025-02-25
2
+
3
+ - autocompletion in spec files
4
+ - Add Link in spec files
5
+ - improved support of new files and unsaved documents
6
+
1
7
  ## [0.1.3] - 2025-02-21
2
8
 
3
9
  - improved Go To Definition for ree object methods and imported constants
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby-lsp-ree (0.1.3)
4
+ ruby-lsp-ree (0.1.4)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -14,6 +14,7 @@ module RubyLsp
14
14
  @index = index
15
15
  @uri = uri
16
16
  @node_context = node_context
17
+ @root_node = @node_context.instance_variable_get(:@nesting_nodes).first
17
18
  @finder = ReeObjectFinder.new(@index)
18
19
  end
19
20
 
@@ -145,7 +146,7 @@ module RubyLsp
145
146
 
146
147
  return [] if class_name_objects.size == 0
147
148
 
148
- parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@node_context.parent, @uri)
149
+ parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@root_node, @uri)
149
150
 
150
151
  imported_consts = []
151
152
  not_imported_consts = []
@@ -206,7 +207,7 @@ module RubyLsp
206
207
 
207
208
  return [] if ree_objects.size == 0
208
209
 
209
- parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@node_context.parent, @uri)
210
+ parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@root_node, @uri)
210
211
 
211
212
  ree_objects.map do |ree_object|
212
213
  ree_object_name = ree_object.name
@@ -306,6 +307,8 @@ module RubyLsp
306
307
  end
307
308
 
308
309
  def get_additional_text_edits_for_method(parsed_doc, fn_name, package_name)
310
+ return [] unless parsed_doc
311
+
309
312
  if parsed_doc.includes_linked_object?(fn_name)
310
313
  return []
311
314
  end
@@ -0,0 +1,132 @@
1
+ require_relative "../utils/ree_lsp_utils"
2
+ require_relative "../ree_object_finder"
3
+ require_relative "../parsing/parsed_link_node"
4
+ require_relative "../parsing/parsed_document_builder"
5
+
6
+ module RubyLsp
7
+ module Ree
8
+ class DefinitionHandler
9
+ include Requests::Support::Common
10
+ include RubyLsp::Ree::ReeLspUtils
11
+
12
+ def initialize(index, uri, node_context)
13
+ @index = index
14
+ @uri = uri
15
+ @node_context = node_context
16
+ @finder = ReeObjectFinder.new(@index)
17
+ end
18
+
19
+ def get_constant_definition_items(node)
20
+ result = []
21
+
22
+ link_nodes = if @node_context.parent.is_a?(Prism::CallNode) && @node_context.parent.name == :link
23
+ # inside link node
24
+ link_node = RubyLsp::Ree::ParsedLinkNode.new(@node_context.parent)
25
+ link_node.parse_imports
26
+ [link_node]
27
+ else
28
+ parsed_doc = if @node_context.parent.is_a?(Prism::CallNode)
29
+ RubyLsp::Ree::ParsedDocumentBuilder.build_from_uri(@uri)
30
+ else
31
+ RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@node_context.parent, @uri)
32
+ end
33
+
34
+ parsed_doc.link_nodes
35
+ end
36
+
37
+ link_nodes.each do |link_node|
38
+ if link_node.imports.include?(node.name.to_s)
39
+ uri = ''
40
+ if link_node.file_path_type?
41
+ path = find_local_file_path(link_node.name)
42
+ next unless path
43
+
44
+ uri = File.join(Dir.pwd, path)
45
+ else
46
+ package_name = link_node.link_package_name || package_name_from_uri(@uri)
47
+
48
+ method_candidates = @index[link_node.name]
49
+ next if !method_candidates || method_candidates.size == 0
50
+
51
+ method = method_candidates.detect{ package_name_from_uri(_1.uri) == package_name }
52
+ next unless method
53
+
54
+ uri = method.uri.to_s
55
+ end
56
+
57
+ result << Interface::Location.new(
58
+ uri: uri,
59
+ range: Interface::Range.new(
60
+ start: Interface::Position.new(line: 0, character: 0),
61
+ end: Interface::Position.new(line: 0, character: 0),
62
+ ),
63
+ )
64
+ end
65
+ end
66
+
67
+ result
68
+ end
69
+
70
+ def get_ree_objects_definition_items(node)
71
+ message = node.message
72
+ result = []
73
+
74
+ definition_item = ReeObjectFinder.new(@index).find_object(message)
75
+ return [] unless definition_item
76
+
77
+ definition_uri = definition_item.uri.to_s
78
+ return [] unless definition_uri
79
+
80
+ result << Interface::Location.new(
81
+ uri: definition_uri,
82
+ range: Interface::Range.new(
83
+ start: Interface::Position.new(line: 0, character: 0),
84
+ end: Interface::Position.new(line: 0, character: 0),
85
+ ),
86
+ )
87
+
88
+ result
89
+ end
90
+
91
+ def get_linked_object_definition_items(node)
92
+ result = []
93
+ parent_node = @node_context.parent
94
+ return [] unless parent_node.name == :link
95
+
96
+ link_node = RubyLsp::Ree::ParsedLinkNode.new(parent_node, package_name_from_uri(@uri))
97
+ package_name = link_node.link_package_name
98
+
99
+ method_candidates = @index[node.unescaped]
100
+ return [] if !method_candidates || method_candidates.size == 0
101
+
102
+ method = method_candidates.detect{ package_name_from_uri(_1.uri) == package_name }
103
+ return [] unless method
104
+
105
+ result << Interface::Location.new(
106
+ uri: method.uri.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
+
113
+ result
114
+ end
115
+
116
+ def get_linked_filepath_definition_items(node)
117
+ result = []
118
+ local_path = find_local_file_path(node.unescaped)
119
+
120
+ return [] unless local_path
121
+
122
+ result << Interface::Location.new(
123
+ uri: File.join(Dir.pwd, local_path),
124
+ range: Interface::Range.new(
125
+ start: Interface::Position.new(line: 0, character: 0),
126
+ end: Interface::Position.new(line: 0, character: 0),
127
+ ),
128
+ )
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,49 @@
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 HoverHandler
9
+ include Requests::Support::Common
10
+ include RubyLsp::Ree::ReeLspUtils
11
+
12
+ def initialize(index, node_context)
13
+ @index = index
14
+ @node_context = node_context
15
+ @finder = ReeObjectFinder.new(@index)
16
+ end
17
+
18
+ def get_ree_object_hover_items(node)
19
+ ree_object = @finder.find_object(node.name.to_s)
20
+
21
+ return [] unless ree_object
22
+
23
+ documentation = <<~DOC
24
+ Ree object, type: :#{@finder.object_type(ree_object)}
25
+
26
+ usage: #{node.name.to_s}#{get_detail_string(ree_object)}
27
+
28
+ package: #{package_name_from_uri(ree_object.uri)}
29
+
30
+ file: #{path_from_package_folder(ree_object.uri)}
31
+ DOC
32
+
33
+ [documentation]
34
+ end
35
+
36
+ def get_detail_string(ree_object)
37
+ return '' if ree_object.signatures.size == 0
38
+
39
+ "(#{get_parameters_string(ree_object.signatures.first)})"
40
+ end
41
+
42
+ def get_parameters_string(signature)
43
+ return '' unless signature
44
+
45
+ signature.parameters.map(&:decorated_name).join(', ')
46
+ end
47
+ end
48
+ end
49
+ end
@@ -21,6 +21,8 @@ module RubyLsp
21
21
 
22
22
  completion_items = @handler.get_class_name_completion_items(node)
23
23
  put_items_into_response(completion_items)
24
+ rescue => e
25
+ $stderr.puts("error in completion listener(on_constant_read_node_enter): #{e.message} : #{e.backtrace.first}")
24
26
  end
25
27
 
26
28
  def on_call_node_enter(node)
@@ -37,6 +39,8 @@ module RubyLsp
37
39
  end
38
40
 
39
41
  put_items_into_response(completion_items)
42
+ rescue => e
43
+ $stderr.puts("error in completion listener(on_call_node_enter): #{e.message} : #{e.backtrace.first}")
40
44
  end
41
45
 
42
46
  def put_items_into_response(items)
@@ -1,136 +1,62 @@
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"
1
+ require_relative "../handlers/definition_handler"
5
2
 
6
3
  module RubyLsp
7
4
  module Ree
8
5
  class DefinitionListener
9
6
  include Requests::Support::Common
10
- include RubyLsp::Ree::ReeLspUtils
11
7
 
12
8
  def initialize(response_builder, node_context, index, dispatcher, uri)
13
9
  @response_builder = response_builder
14
- @node_context = node_context
15
- @nesting = node_context.nesting
16
- @index = index
17
- @uri = uri
18
-
19
- dispatcher.register(self, :on_call_node_enter, :on_symbol_node_enter, :on_string_node_enter, :on_constant_read_node_enter)
10
+ @handler = RubyLsp::Ree::DefinitionHandler.new(index, uri, node_context)
11
+
12
+ dispatcher.register(
13
+ self,
14
+ :on_call_node_enter,
15
+ :on_symbol_node_enter,
16
+ :on_string_node_enter,
17
+ :on_constant_read_node_enter
18
+ )
20
19
  end
21
20
 
22
21
  def on_constant_read_node_enter(node)
23
- link_nodes = if @node_context.parent.is_a?(Prism::CallNode) && @node_context.parent.name == :link
24
- # inside link node
25
- link_node = RubyLsp::Ree::ParsedLinkNode.new(@node_context.parent)
26
- link_node.parse_imports
27
- [link_node]
28
- else
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
-
35
- parsed_doc.link_nodes
36
- end
37
-
38
- link_nodes.each do |link_node|
39
- if link_node.imports.include?(node.name.to_s)
40
- uri = ''
41
- if link_node.file_path_type?
42
- path = find_local_file_path(link_node.name)
43
- next unless path
44
-
45
- uri = File.join(Dir.pwd, path)
46
- else
47
- package_name = link_node.link_package_name || package_name_from_uri(@uri)
48
-
49
- method_candidates = @index[link_node.name]
50
- next if !method_candidates || method_candidates.size == 0
51
-
52
- method = method_candidates.detect{ package_name_from_uri(_1.uri) == package_name }
53
- next unless method
54
-
55
- uri = method.uri.to_s
56
- end
57
-
58
- @response_builder << Interface::Location.new(
59
- uri: uri,
60
- range: Interface::Range.new(
61
- start: Interface::Position.new(line: 0, character: 0),
62
- end: Interface::Position.new(line: 0, character: 0),
63
- ),
64
- )
65
- end
66
- end
22
+ definition_items = @handler.get_constant_definition_items(node)
23
+ put_items_into_response(definition_items)
24
+ rescue => e
25
+ $stderr.puts("error in definition listener(on_constant_read_node_enter): #{e.message} : #{e.backtrace.first}")
67
26
  end
68
27
 
69
28
  def on_call_node_enter(node)
70
- message = node.message
71
- return unless message
72
-
73
- definition_uri = nil
29
+ return unless node.message
74
30
 
75
31
  if node.receiver
76
32
  # ruby lsp handles such cases itself
77
33
  return
78
34
  else
79
- definition_item = ReeObjectFinder.new(@index).find_object(message)
80
- definition_uri = definition_item.uri.to_s
35
+ definition_items = @handler.get_ree_objects_definition_items(node)
36
+ put_items_into_response(definition_items)
81
37
  end
82
-
83
- return unless definition_uri
84
-
85
- @response_builder << Interface::Location.new(
86
- uri: definition_uri,
87
- range: Interface::Range.new(
88
- start: Interface::Position.new(line: 0, character: 0),
89
- end: Interface::Position.new(line: 0, character: 0),
90
- ),
91
- )
92
-
93
- nil
38
+ rescue => e
39
+ $stderr.puts("error in definition listener(on_call_node_enter): #{e.message} : #{e.backtrace.first}")
94
40
  end
95
41
 
96
42
  def on_symbol_node_enter(node)
97
- parent_node = @node_context.parent
98
- return unless parent_node.name == :link
99
-
100
- link_node = RubyLsp::Ree::ParsedLinkNode.new(parent_node, package_name_from_uri(@uri))
101
- package_name = link_node.link_package_name
102
-
103
- method_candidates = @index[node.unescaped]
104
- return if !method_candidates || method_candidates.size == 0
105
-
106
- method = method_candidates.detect{ package_name_from_uri(_1.uri) == package_name }
107
- return unless method
108
-
109
- @response_builder << Interface::Location.new(
110
- uri: method.uri.to_s,
111
- range: Interface::Range.new(
112
- start: Interface::Position.new(line: 0, character: 0),
113
- end: Interface::Position.new(line: 0, character: 0),
114
- ),
115
- )
116
-
117
- nil
43
+ definition_items = @handler.get_linked_object_definition_items(node)
44
+ put_items_into_response(definition_items)
45
+ rescue => e
46
+ $stderr.puts("error in definition listener(on_symbol_node_enter): #{e.message} : #{e.backtrace.first}")
118
47
  end
119
48
 
120
49
  def on_string_node_enter(node)
121
- local_path = find_local_file_path(node.unescaped)
50
+ definition_items = @handler.get_linked_filepath_definition_items(node)
51
+ put_items_into_response(definition_items)
52
+ rescue => e
53
+ $stderr.puts("error in definition listener(on_string_node_enter): #{e.message} : #{e.backtrace.first}")
54
+ end
122
55
 
123
- if local_path
124
- @response_builder << Interface::Location.new(
125
- uri: File.join(Dir.pwd, local_path),
126
- range: Interface::Range.new(
127
- start: Interface::Position.new(line: 0, character: 0),
128
- end: Interface::Position.new(line: 0, character: 0),
129
- ),
130
- )
56
+ def put_items_into_response(items)
57
+ items.each do |item|
58
+ @response_builder << item
131
59
  end
132
-
133
- nil
134
60
  end
135
61
  end
136
62
  end
@@ -1,7 +1,4 @@
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"
1
+ require_relative "../handlers/hover_handler"
5
2
 
6
3
  module RubyLsp
7
4
  module Ree
@@ -10,8 +7,7 @@ module RubyLsp
10
7
 
11
8
  def initialize(response_builder, node_context, index, dispatcher)
12
9
  @response_builder = response_builder
13
- @node_context = node_context
14
- @finder = ReeObjectFinder.new(index)
10
+ @handler = RubyLsp::Ree::HoverHandler.new(index, node_context)
15
11
 
16
12
  dispatcher.register(self, :on_call_node_enter)
17
13
  dispatcher.register(self, :on_constant_read_node_enter)
@@ -30,35 +26,16 @@ module RubyLsp
30
26
  end
31
27
 
32
28
  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)
29
+ hover_items = @handler.get_ree_object_hover_items(node)
30
+ put_items_into_response(hover_items)
31
+ rescue => e
32
+ $stderr.puts("error in hover listener(on_call_node_enter): #{e.message} : #{e.backtrace.first}")
50
33
  end
51
34
 
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(', ')
35
+ def put_items_into_response(items)
36
+ items.each do |item|
37
+ @response_builder.push(item, category: :documentation)
38
+ end
62
39
  end
63
40
  end
64
41
  end
@@ -1,4 +1,5 @@
1
1
  require_relative 'parsed_link_node'
2
+ require 'ostruct'
2
3
 
3
4
  class RubyLsp::Ree::ParsedDocument
4
5
  include RubyLsp::Ree::ReeLspUtils
@@ -18,8 +19,12 @@ class RubyLsp::Ree::ParsedDocument
18
19
  @fn_node || @action_node || @dao_node || @bean_node || @mapper_node || @aggregate_node
19
20
  end
20
21
 
22
+ def allows_root_links?
23
+ false
24
+ end
25
+
21
26
  def includes_link_dsl?
22
- @class_includes.any?{ _1.name == LINK_DSL_MODULE }
27
+ @class_includes.any?{ node_name(_1) == LINK_DSL_MODULE }
23
28
  end
24
29
 
25
30
  def includes_linked_constant?(const_name)
@@ -27,11 +32,11 @@ class RubyLsp::Ree::ParsedDocument
27
32
  end
28
33
 
29
34
  def includes_linked_object?(obj_name)
30
- @link_nodes.map(&:name).include?(obj_name)
35
+ @link_nodes.map{ node_name(_1) }.include?(obj_name)
31
36
  end
32
37
 
33
38
  def find_link_node(name)
34
- @link_nodes.detect{ _1.name == name }
39
+ @link_nodes.detect{ node_name(_1) == name }
35
40
  end
36
41
 
37
42
  def find_link_with_imported_object(name)
@@ -61,49 +66,49 @@ class RubyLsp::Ree::ParsedDocument
61
66
  def parse_fn_node
62
67
  return unless class_node
63
68
 
64
- @fn_node ||= class_node.body.body.detect{ |node| node.name == :fn }
69
+ @fn_node ||= class_node.body.body.detect{ |node| node_name(node) == :fn }
65
70
  @links_container_block_node ||= @fn_node&.block
66
71
  end
67
72
 
68
73
  def parse_action_node
69
74
  return unless class_node
70
75
 
71
- @action_node ||= class_node.body.body.detect{ |node| node.name == :action }
76
+ @action_node ||= class_node.body.body.detect{ |node| node_name(node) == :action }
72
77
  @links_container_block_node ||= @action_node&.block
73
78
  end
74
79
 
75
80
  def parse_dao_node
76
81
  return unless class_node
77
82
 
78
- @dao_node ||= class_node.body.body.detect{ |node| node.name == :dao }
83
+ @dao_node ||= class_node.body.body.detect{ |node| node_name(node) == :dao }
79
84
  @links_container_block_node ||= @dao_node&.block
80
85
  end
81
86
 
82
87
  def parse_bean_node
83
88
  return unless class_node
84
89
 
85
- @bean_node ||= class_node.body.body.detect{ |node| node.name == :bean }
90
+ @bean_node ||= class_node.body.body.detect{ |node| node_name(node) == :bean }
86
91
  @links_container_block_node ||= @bean_node&.block
87
92
  end
88
93
 
89
94
  def parse_mapper_node
90
95
  return unless class_node
91
96
 
92
- @mapper_node ||= class_node.body.body.detect{ |node| node.name == :mapper }
97
+ @mapper_node ||= class_node.body.body.detect{ |node| node_name(node) == :mapper }
93
98
  @links_container_block_node ||= @mapper_node&.block
94
99
  end
95
100
 
96
101
  def parse_aggregate_node
97
102
  return unless class_node
98
103
 
99
- @aggregate_node ||= class_node.body.body.detect{ |node| node.name == :aggregate }
104
+ @aggregate_node ||= class_node.body.body.detect{ |node| node_name(node) == :aggregate }
100
105
  @links_container_block_node ||= @aggregate_node&.block
101
106
  end
102
107
 
103
108
  def parse_class_includes
104
109
  return unless class_node
105
110
 
106
- @class_includes ||= class_node.body.body.select{ _1.name == :include }.map do |class_include|
111
+ @class_includes ||= class_node.body.body.select{ node_name(_1) == :include }.map do |class_include|
107
112
  parent_name = class_include.arguments.arguments.first.parent.name.to_s
108
113
  module_name = class_include.arguments.arguments.first.name
109
114
 
@@ -116,10 +121,10 @@ class RubyLsp::Ree::ParsedDocument
116
121
  def parse_links
117
122
  return unless class_node
118
123
 
119
- nodes = if links_container_node && @links_container_block_node.body
120
- @links_container_block_node.body.body.select{ |node| node.name == :link }
121
- elsif class_includes.any?{ _1.name == LINK_DSL_MODULE }
122
- class_node.body.body.select{ |node| node.name == :link }
124
+ nodes = if links_container_node && @links_container_block_node && @links_container_block_node.body
125
+ @links_container_block_node.body.body.select{ |node| node_name(node) == :link }
126
+ elsif class_includes.any?{ node_name(_1) == LINK_DSL_MODULE }
127
+ class_node.body.body.select{ |node| node_name(node) == :link }
123
128
  else
124
129
  []
125
130
  end
@@ -135,7 +140,7 @@ class RubyLsp::Ree::ParsedDocument
135
140
  return unless class_node
136
141
 
137
142
  @values ||= class_node.body.body
138
- .select{ _1.name == :val }
143
+ .select{ node_name(_1) == :val }
139
144
  .map{ OpenStruct.new(name: _1.arguments.arguments.first.unescaped) }
140
145
  end
141
146
 
@@ -143,7 +148,7 @@ class RubyLsp::Ree::ParsedDocument
143
148
  return unless class_node
144
149
 
145
150
  @filters ||= class_node.body.body
146
- .select{ _1.name == :filter }
151
+ .select{ node_name(_1) == :filter }
147
152
  .map{ OpenStruct.new(name: _1.arguments.arguments.first.unescaped, signatures: parse_filter_signature(_1)) }
148
153
 
149
154
  end
@@ -153,7 +158,7 @@ class RubyLsp::Ree::ParsedDocument
153
158
 
154
159
  @bean_methods ||= class_node.body.body
155
160
  .select{ _1.is_a?(Prism::DefNode) }
156
- .map{ OpenStruct.new(name: _1.name.to_s, signatures: parse_signatures_from_params(_1.parameters)) }
161
+ .map{ OpenStruct.new(name: node_name(_1).to_s, signatures: parse_signatures_from_params(_1.parameters)) }
157
162
  end
158
163
 
159
164
  def parse_filter_signature(filter_node)
@@ -174,4 +179,10 @@ class RubyLsp::Ree::ParsedDocument
174
179
  name_parts = [class_node.constant_path&.parent&.name, class_node.constant_path.name]
175
180
  name_parts.compact.map(&:to_s).join('::')
176
181
  end
182
+
183
+ def node_name(node)
184
+ return nil unless node.respond_to?(:name)
185
+
186
+ node.name
187
+ end
177
188
  end
@@ -1,5 +1,6 @@
1
1
  require 'prism'
2
2
  require_relative 'parsed_document'
3
+ require_relative 'parsed_rspec_document'
3
4
 
4
5
  class RubyLsp::Ree::ParsedDocumentBuilder
5
6
  extend RubyLsp::Ree::ReeLspUtils
@@ -7,6 +8,7 @@ class RubyLsp::Ree::ParsedDocumentBuilder
7
8
  def self.build_from_uri(uri, type = nil)
8
9
  ast = Prism.parse_file(uri.path).value
9
10
  document = build_document(ast, type)
11
+ return unless document
10
12
 
11
13
  document.set_package_name(package_name_from_uri(uri))
12
14
 
@@ -15,6 +17,7 @@ class RubyLsp::Ree::ParsedDocumentBuilder
15
17
 
16
18
  def self.build_from_ast(ast, uri, type = nil)
17
19
  document = build_document(ast, type)
20
+ return unless document
18
21
 
19
22
  document.set_package_name(package_name_from_uri(uri))
20
23
 
@@ -35,10 +38,37 @@ class RubyLsp::Ree::ParsedDocumentBuilder
35
38
  when :bean
36
39
  build_bean_document(ast)
37
40
  else
41
+ build_detected_doument_type(ast)
42
+ end
43
+ end
44
+
45
+ def self.build_detected_doument_type(ast)
46
+ if has_root_class?(ast)
38
47
  build_regular_document(ast)
48
+ elsif has_root_rspec_call?(ast)
49
+ build_rspec_document(ast)
50
+ else
51
+ nil
39
52
  end
40
53
  end
41
54
 
55
+ def self.has_root_class?(ast)
56
+ ast.statements.body.detect{ |node| node.is_a?(Prism::ClassNode) }
57
+ end
58
+
59
+ def self.has_root_rspec_call?(ast)
60
+ ast.statements.body.detect{ |node| node.is_a?(Prism::CallNode) && node.name == :describe }
61
+ end
62
+
63
+ def self.build_rspec_document(ast)
64
+ document = RubyLsp::Ree::ParsedRspecDocument.new(ast)
65
+
66
+ document.parse_describe_node
67
+ document.parse_links
68
+
69
+ document
70
+ end
71
+
42
72
  def self.build_regular_document(ast)
43
73
  document = RubyLsp::Ree::ParsedDocument.new(ast)
44
74
 
@@ -0,0 +1,57 @@
1
+ require_relative 'parsed_link_node'
2
+ require 'ostruct'
3
+
4
+ class RubyLsp::Ree::ParsedRspecDocument
5
+ include RubyLsp::Ree::ReeLspUtils
6
+
7
+ attr_reader :ast, :package_name, :describe_node
8
+
9
+ def initialize(ast)
10
+ @ast = ast
11
+ end
12
+
13
+ def set_package_name(package_name)
14
+ @package_name = package_name
15
+ end
16
+
17
+ def allows_root_links?
18
+ true
19
+ end
20
+
21
+ def includes_linked_object?(obj_name)
22
+ @link_nodes.map(&:name).include?(obj_name)
23
+ end
24
+
25
+ def links_container_node
26
+ nil
27
+ end
28
+
29
+ def root_node_line_location
30
+ OpenStruct.new(
31
+ start_line: @describe_node.location.start_line,
32
+ end_column: @describe_node.block.opening_loc.end_column
33
+ )
34
+ end
35
+
36
+ def has_blank_links_container?
37
+ false
38
+ end
39
+
40
+ def includes_link_dsl?
41
+ false
42
+ end
43
+
44
+ def parse_describe_node
45
+ @describe_node ||= @ast.statements.body.detect{ |node| node.is_a?(Prism::CallNode) && node.name == :describe }
46
+ end
47
+
48
+ def parse_links
49
+ nodes = @describe_node.block.body.body.select{ |node| node.name == :link }
50
+
51
+ @link_nodes = nodes.map do |link_node|
52
+ link_node = RubyLsp::Ree::ParsedLinkNode.new(link_node, package_name)
53
+ link_node.parse_imports
54
+ link_node
55
+ end
56
+ end
57
+ end
@@ -10,6 +10,8 @@ module RubyLsp
10
10
  def run_formatting(uri, document)
11
11
  source = document.source
12
12
  sort_links(source)
13
+ rescue => e
14
+ $stderr.puts("error in ree_formatter: #{e.message} : #{e.backtrace.first}")
13
15
  end
14
16
 
15
17
  private
@@ -33,8 +33,8 @@ module RubyLsp
33
33
  private
34
34
 
35
35
  def parse_signatures(fn_name)
36
- uri = @listener.instance_variable_get(:@uri)
37
- ast = Prism.parse_file(uri.path).value
36
+ source = @listener.instance_variable_get(:@source_lines).join
37
+ ast = Prism.parse(source).value
38
38
 
39
39
  class_node = ast.statements.body.detect{ |node| node.is_a?(Prism::ClassNode) }
40
40
  return [] unless class_node
@@ -49,6 +49,11 @@ 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
+ elsif parsed_doc.allows_root_links?
53
+ root_node_location = parsed_doc.root_node_line_location
54
+
55
+ fn_line = root_node_location.start_line
56
+ position = root_node_location.end_column + 1
52
57
  else
53
58
  return nil
54
59
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RubyLsp
4
4
  module Ree
5
- VERSION = "0.1.3"
5
+ VERSION = "0.1.4"
6
6
  end
7
7
  end
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.3
4
+ version: 0.1.4
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-21 00:00:00.000000000 Z
11
+ date: 2025-02-25 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:
@@ -27,12 +27,15 @@ files:
27
27
  - Rakefile
28
28
  - lib/ruby_lsp/ruby_lsp_ree/addon.rb
29
29
  - lib/ruby_lsp/ruby_lsp_ree/handlers/completion_handler.rb
30
+ - lib/ruby_lsp/ruby_lsp_ree/handlers/definition_handler.rb
31
+ - lib/ruby_lsp/ruby_lsp_ree/handlers/hover_handler.rb
30
32
  - lib/ruby_lsp/ruby_lsp_ree/listeners/completion_listener.rb
31
33
  - lib/ruby_lsp/ruby_lsp_ree/listeners/definition_listener.rb
32
34
  - lib/ruby_lsp/ruby_lsp_ree/listeners/hover_listener.rb
33
35
  - lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_document.rb
34
36
  - lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_document_builder.rb
35
37
  - lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_link_node.rb
38
+ - lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_rspec_document.rb
36
39
  - lib/ruby_lsp/ruby_lsp_ree/ree_formatter.rb
37
40
  - lib/ruby_lsp/ruby_lsp_ree/ree_indexing_enhancement.rb
38
41
  - lib/ruby_lsp/ruby_lsp_ree/ree_object_finder.rb