ruby-lsp-ree 0.1.15 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/lib/ruby_lsp/ruby_lsp_ree/completion/method_additional_text_edits_creator.rb +1 -1
- data/lib/ruby_lsp/ruby_lsp_ree/formatters/base_formatter.rb +1 -1
- data/lib/ruby_lsp/ruby_lsp_ree/formatters/missing_imports_formatter.rb +63 -0
- data/lib/ruby_lsp/ruby_lsp_ree/parsing/body_parsers/call_objects_parser.rb +104 -0
- data/lib/ruby_lsp/ruby_lsp_ree/parsing/body_parsers/local_variables_parser.rb +52 -0
- data/lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_class_document.rb +11 -0
- data/lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_method_node.rb +27 -0
- data/lib/ruby_lsp/ruby_lsp_ree/ree_formatter.rb +3 -1
- data/lib/ruby_lsp/ruby_lsp_ree/ree_source_editor.rb +30 -0
- data/lib/ruby_lsp_ree/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d1b2bf9c373c729b6412704fd6daf364ed4c8b278405f52b4c1fc32b256570c
|
4
|
+
data.tar.gz: 0bde5c4413ec6d4ccfd807dc6e6eb33d1e47ab018dfbfaad47200775b2c3badb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a97047d4924f208415ba6c5ed45e6abb57141e74fd44ad79368a9a7dd025a2ce0c36cfe2ca95db6fd0dab9586d9a1c5484be2e930ab129ab6acb7975fce310f
|
7
|
+
data.tar.gz: 17daba371512607775021704c56895bcc9e41666e598c9603c7da22ebac567de1cc7a2957f050a6657429057557dcbbc86654141eba98faa8c7ddde6e892a030
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -32,7 +32,7 @@ To switch off/on formatter features, use Ruby LSP addon settings:
|
|
32
32
|
}
|
33
33
|
}
|
34
34
|
```
|
35
|
-
available formatters: `SortLinksFormatter`, `MissingErrorDefinitionsFormatter`, `MissingErrorContractsFormatter`, `MissingErrorLocalesFormatter`, `UnusedLinksFormatter`
|
35
|
+
available formatters: `SortLinksFormatter`, `MissingErrorDefinitionsFormatter`, `MissingErrorContractsFormatter`, `MissingErrorLocalesFormatter`, `UnusedLinksFormatter`, `MissingImportsFormatter`
|
36
36
|
|
37
37
|
## Functions
|
38
38
|
|
@@ -4,7 +4,7 @@ module RubyLsp
|
|
4
4
|
def self.call(source, uri, message_queue, index)
|
5
5
|
new(message_queue, index).call(source, uri)
|
6
6
|
rescue => e
|
7
|
-
$stderr.puts("error in #{self
|
7
|
+
$stderr.puts("error in #{self}: #{e.message} : #{e.backtrace.first}")
|
8
8
|
source
|
9
9
|
end
|
10
10
|
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require_relative 'base_formatter'
|
2
|
+
require_relative "../ree_object_finder"
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Ree
|
6
|
+
class MissingImportsFormatter < BaseFormatter
|
7
|
+
include RubyLsp::Ree::ReeLspUtils
|
8
|
+
|
9
|
+
def call(source, uri)
|
10
|
+
return source unless @index
|
11
|
+
|
12
|
+
parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_source(source)
|
13
|
+
return source if !parsed_doc || !parsed_doc.has_root_class?
|
14
|
+
|
15
|
+
finder = ReeObjectFinder.new(@index)
|
16
|
+
editor = RubyLsp::Ree::ReeSourceEditor.new(source)
|
17
|
+
|
18
|
+
current_package = package_name_from_uri(uri)
|
19
|
+
|
20
|
+
fn_calls = parsed_doc.parse_fn_calls
|
21
|
+
filtered_fn_calls = filter_fn_calls(parsed_doc, fn_calls)
|
22
|
+
objects_to_add = filtered_fn_calls.map{ |fn_call|
|
23
|
+
finder.find_object(fn_call.name.to_s)
|
24
|
+
}.compact
|
25
|
+
|
26
|
+
bean_calls = parsed_doc.parse_bean_calls
|
27
|
+
filtered_bean_calls = filter_bean_calls(parsed_doc, bean_calls)
|
28
|
+
objects_to_add += filtered_bean_calls.map{ |bean_call|
|
29
|
+
finder.find_object(bean_call.receiver_name.to_s)
|
30
|
+
}.compact
|
31
|
+
|
32
|
+
objects_to_add.uniq!{ |obj| obj.name }
|
33
|
+
objects_to_add.reject!{ |obj| parsed_doc.includes_linked_object?(obj.name) }
|
34
|
+
return editor.source if objects_to_add.size == 0
|
35
|
+
|
36
|
+
editor.add_links(parsed_doc, objects_to_add, current_package)
|
37
|
+
editor.source
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def filter_fn_calls(parsed_doc, fn_calls)
|
43
|
+
parsed_doc.parse_instance_methods
|
44
|
+
|
45
|
+
fn_calls.reject{ |fn_call|
|
46
|
+
parsed_doc.doc_instance_methods.map(&:name).include?(fn_call.name)
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def filter_bean_calls(parsed_doc, bean_calls)
|
51
|
+
bean_calls.select do |bean_call|
|
52
|
+
if !bean_call.method_name
|
53
|
+
true
|
54
|
+
else
|
55
|
+
method_obj = parsed_doc.doc_instance_methods.detect{ _1.name == bean_call.method_name }
|
56
|
+
local_variables = method_obj.parse_local_variables
|
57
|
+
!local_variables.map(&:name).include?(bean_call.receiver_name)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
class RubyLsp::Ree::CallObjectsParser
|
2
|
+
attr_reader :parsed_doc
|
3
|
+
|
4
|
+
class CallObject
|
5
|
+
attr_reader :name, :type, :receiver_name, :method_name
|
6
|
+
|
7
|
+
def initialize(name:, type:, receiver_name: nil)
|
8
|
+
@name = name
|
9
|
+
@type = type
|
10
|
+
@receiver_name = receiver_name
|
11
|
+
@method_name = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def set_method_name(method_name)
|
15
|
+
@method_name = method_name
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(parsed_doc)
|
20
|
+
@parsed_doc = parsed_doc
|
21
|
+
end
|
22
|
+
|
23
|
+
def class_call_objects
|
24
|
+
call_objects = []
|
25
|
+
return unless parsed_doc.has_body?
|
26
|
+
|
27
|
+
call_objects += parse_body_call_objects(parsed_doc.class_node.body.body)
|
28
|
+
|
29
|
+
parsed_doc.parse_instance_methods
|
30
|
+
|
31
|
+
parsed_doc.doc_instance_methods.each do |doc_instance_method|
|
32
|
+
call_objects += method_call_objects(doc_instance_method)
|
33
|
+
end
|
34
|
+
|
35
|
+
call_objects
|
36
|
+
end
|
37
|
+
|
38
|
+
def method_call_objects(method_object)
|
39
|
+
method_body = method_object.method_body
|
40
|
+
return [] unless method_body
|
41
|
+
|
42
|
+
call_nodes = parse_body_call_objects(method_body)
|
43
|
+
call_expressions = [] # don't parse call expressions for now parse_body_call_expressions(method_body)
|
44
|
+
|
45
|
+
call_objects = call_nodes + call_expressions
|
46
|
+
|
47
|
+
call_objects.each{ |call_object| call_object.set_method_name(method_object.name) }
|
48
|
+
call_objects
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def parse_body_call_objects(node_body)
|
54
|
+
call_objects = []
|
55
|
+
|
56
|
+
node_body.each do |node|
|
57
|
+
if node.is_a?(Prism::CallNode)
|
58
|
+
receiver = get_first_receiver(node)
|
59
|
+
receiver_name = receiver.respond_to?(:name) ? receiver.name : nil
|
60
|
+
call_objects << CallObject.new(name: node.name, type: :method_call, receiver_name: receiver_name)
|
61
|
+
elsif node.respond_to?(:statements)
|
62
|
+
call_objects += parse_body_call_objects(node.statements.body)
|
63
|
+
elsif node.respond_to?(:block) && node.block && node.block.is_a?(Prism::BlockNode)
|
64
|
+
call_objects += parse_body_call_objects(get_method_body(node.block))
|
65
|
+
elsif node.respond_to?(:value) && node.value
|
66
|
+
call_objects += parse_body_call_objects([node.value])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
call_objects
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_body_call_expressions(node_body)
|
74
|
+
call_expressions = []
|
75
|
+
|
76
|
+
node_body.each do |node|
|
77
|
+
if node.respond_to?(:block) && node.block && node.block.is_a?(Prism::BlockArgumentNode) && node.block.expression.is_a?(Prism::SymbolNode)
|
78
|
+
call_expressions << CallObject.new(name: node.block.expression.unescaped.to_sym, type: :proc_to_sym)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
call_expressions
|
83
|
+
end
|
84
|
+
|
85
|
+
def get_method_body(node)
|
86
|
+
return unless node.body
|
87
|
+
|
88
|
+
if node.body.is_a?(Prism::BeginNode)
|
89
|
+
node.body.statements.body
|
90
|
+
else
|
91
|
+
node.body.body
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_first_receiver(node)
|
96
|
+
return nil unless node.receiver
|
97
|
+
|
98
|
+
if node.receiver.is_a?(Prism::CallNode) && node.receiver.receiver
|
99
|
+
return get_first_receiver(node.receiver)
|
100
|
+
end
|
101
|
+
|
102
|
+
node.receiver
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class RubyLsp::Ree::LocalVariablesParser
|
2
|
+
attr_reader :parsed_doc, :method_object
|
3
|
+
|
4
|
+
class LocalVariable
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def initialize(name:)
|
8
|
+
@name = name
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(method_obj)
|
13
|
+
@method_object = method_obj
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_local_variables
|
17
|
+
method_body = method_object.method_body
|
18
|
+
return [] unless method_body
|
19
|
+
|
20
|
+
parse_body_local_variables(method_body)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def parse_body_local_variables(node_body)
|
26
|
+
local_variables = []
|
27
|
+
|
28
|
+
node_body.each do |node|
|
29
|
+
if node.is_a?(Prism::LocalVariableWriteNode)
|
30
|
+
local_variables << LocalVariable.new(name: node.name)
|
31
|
+
elsif node.is_a?(Prism::MultiWriteNode)
|
32
|
+
local_variables += node.lefts.map{ |x| LocalVariable.new(name: x.name) }
|
33
|
+
elsif node.respond_to?(:statements)
|
34
|
+
local_variables += parse_body_local_variables(node.statements.body)
|
35
|
+
elsif node.respond_to?(:block) && node.block && node.block.is_a?(Prism::BlockNode)
|
36
|
+
local_variables += parse_body_local_variables(get_method_body(node.block))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
local_variables
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_method_body(node)
|
44
|
+
return unless node.body
|
45
|
+
|
46
|
+
if node.body.is_a?(Prism::BeginNode)
|
47
|
+
node.body.statements.body
|
48
|
+
else
|
49
|
+
node.body.body
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -2,6 +2,8 @@ require_relative 'parsed_base_document'
|
|
2
2
|
require_relative 'parsed_link_node'
|
3
3
|
require_relative 'parsed_method_node'
|
4
4
|
require_relative "../ree_constants"
|
5
|
+
require_relative "body_parsers/call_objects_parser"
|
6
|
+
|
5
7
|
require 'ostruct'
|
6
8
|
|
7
9
|
class RubyLsp::Ree::ParsedClassDocument < RubyLsp::Ree::ParsedBaseDocument
|
@@ -142,6 +144,7 @@ class RubyLsp::Ree::ParsedClassDocument < RubyLsp::Ree::ParsedBaseDocument
|
|
142
144
|
end
|
143
145
|
|
144
146
|
def parse_instance_methods
|
147
|
+
return if @doc_instance_methods
|
145
148
|
@doc_instance_methods = []
|
146
149
|
|
147
150
|
current_contract_node = nil
|
@@ -202,6 +205,14 @@ class RubyLsp::Ree::ParsedClassDocument < RubyLsp::Ree::ParsedBaseDocument
|
|
202
205
|
.map(&:name)
|
203
206
|
end
|
204
207
|
|
208
|
+
def parse_fn_calls
|
209
|
+
RubyLsp::Ree::CallObjectsParser.new(self).class_call_objects.select{ !_1.receiver_name }
|
210
|
+
end
|
211
|
+
|
212
|
+
def parse_bean_calls
|
213
|
+
RubyLsp::Ree::CallObjectsParser.new(self).class_call_objects.select{ _1.receiver_name }
|
214
|
+
end
|
215
|
+
|
205
216
|
def class_name
|
206
217
|
class_node.constant_path.name.to_s
|
207
218
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'prism'
|
2
|
+
require_relative "body_parsers/local_variables_parser"
|
2
3
|
|
3
4
|
class RubyLsp::Ree::ParsedMethodNode
|
4
5
|
attr_reader :method_node, :contract_node, :nested_local_methods
|
@@ -24,6 +25,10 @@ class RubyLsp::Ree::ParsedMethodNode
|
|
24
25
|
@method_node.location.end_line - 1
|
25
26
|
end
|
26
27
|
|
28
|
+
def method_body
|
29
|
+
get_method_body(@method_node)
|
30
|
+
end
|
31
|
+
|
27
32
|
def raised_errors_nested
|
28
33
|
return @raised_errors_nested if @raised_errors_nested
|
29
34
|
raised = raised_errors
|
@@ -94,6 +99,10 @@ class RubyLsp::Ree::ParsedMethodNode
|
|
94
99
|
def contract_in_parentheses?
|
95
100
|
@contract_node.opening == '(' && @contract_node.closing == ')'
|
96
101
|
end
|
102
|
+
|
103
|
+
def parse_local_variables
|
104
|
+
RubyLsp::Ree::LocalVariablesParser.new(self).method_local_variables
|
105
|
+
end
|
97
106
|
|
98
107
|
def parse_nested_local_methods(local_methods)
|
99
108
|
unless @method_node.body
|
@@ -111,6 +120,20 @@ class RubyLsp::Ree::ParsedMethodNode
|
|
111
120
|
@nested_local_methods.each{ _1.parse_nested_local_methods(local_methods) }
|
112
121
|
end
|
113
122
|
|
123
|
+
def parse_call_objects
|
124
|
+
method_body = get_method_body(@method_node)
|
125
|
+
return [] unless method_body
|
126
|
+
|
127
|
+
call_nodes = parse_body_call_objects(method_body)
|
128
|
+
call_expressions = parse_body_call_expressions(method_body)
|
129
|
+
|
130
|
+
call_node_names = call_nodes.map(&:name) + call_expressions
|
131
|
+
|
132
|
+
call_node_names
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
114
137
|
def parse_body_call_objects(node_body)
|
115
138
|
call_nodes = []
|
116
139
|
|
@@ -121,6 +144,8 @@ class RubyLsp::Ree::ParsedMethodNode
|
|
121
144
|
call_nodes += parse_body_call_objects(node.statements.body)
|
122
145
|
elsif node.respond_to?(:block) && node.block && node.block.is_a?(Prism::BlockNode)
|
123
146
|
call_nodes += parse_body_call_objects(get_method_body(node.block))
|
147
|
+
elsif node.respond_to?(:value) && node.value
|
148
|
+
call_nodes += parse_body_call_objects([node.value])
|
124
149
|
end
|
125
150
|
end
|
126
151
|
|
@@ -140,6 +165,8 @@ class RubyLsp::Ree::ParsedMethodNode
|
|
140
165
|
end
|
141
166
|
|
142
167
|
def get_method_body(node)
|
168
|
+
return unless node.body
|
169
|
+
|
143
170
|
if node.body.is_a?(Prism::BeginNode)
|
144
171
|
node.body.statements.body
|
145
172
|
else
|
@@ -3,6 +3,7 @@ require_relative 'formatters/missing_error_definitions_formatter'
|
|
3
3
|
require_relative 'formatters/missing_error_contracts_formatter'
|
4
4
|
require_relative 'formatters/missing_error_locales_formatter'
|
5
5
|
require_relative 'formatters/unused_links_formatter'
|
6
|
+
require_relative 'formatters/missing_imports_formatter'
|
6
7
|
|
7
8
|
module RubyLsp
|
8
9
|
module Ree
|
@@ -23,11 +24,12 @@ module RubyLsp
|
|
23
24
|
source = document.source
|
24
25
|
|
25
26
|
formatters = [
|
26
|
-
RubyLsp::Ree::SortLinksFormatter,
|
27
27
|
RubyLsp::Ree::MissingErrorDefinitionsFormatter,
|
28
28
|
RubyLsp::Ree::MissingErrorContractsFormatter,
|
29
29
|
RubyLsp::Ree::MissingErrorLocalesFormatter,
|
30
30
|
RubyLsp::Ree::UnusedLinksFormatter,
|
31
|
+
RubyLsp::Ree::MissingImportsFormatter,
|
32
|
+
RubyLsp::Ree::SortLinksFormatter,
|
31
33
|
].select do |formatter|
|
32
34
|
formatter_name = formatter.name.split('::').last.to_sym
|
33
35
|
@settings[formatter_name] != false
|
@@ -63,6 +63,36 @@ module RubyLsp
|
|
63
63
|
source_lines[i] = ''
|
64
64
|
end
|
65
65
|
end
|
66
|
+
|
67
|
+
def add_links(parsed_doc, ree_objects, current_package)
|
68
|
+
new_text = ''
|
69
|
+
|
70
|
+
ree_objects.each do |ree_object|
|
71
|
+
object_package = package_name_from_uri(ree_object.uri)
|
72
|
+
|
73
|
+
link_text = if current_package == object_package
|
74
|
+
"\s\slink :#{ree_object.name}"
|
75
|
+
else
|
76
|
+
"\s\slink :#{ree_object.name}, from: :#{object_package}"
|
77
|
+
end
|
78
|
+
|
79
|
+
if parsed_doc.links_container_node
|
80
|
+
link_text = "\s\s" + link_text
|
81
|
+
end
|
82
|
+
|
83
|
+
new_text += "\n" + link_text
|
84
|
+
end
|
85
|
+
|
86
|
+
new_text += "\n"
|
87
|
+
|
88
|
+
if parsed_doc.has_blank_links_container?
|
89
|
+
new_text = "\sdo#{new_text}\s\send\n"
|
90
|
+
end
|
91
|
+
|
92
|
+
line = parsed_doc.links_container_node.location.start_line - 1
|
93
|
+
|
94
|
+
source_lines[line] = source_lines[line].chomp + new_text
|
95
|
+
end
|
66
96
|
end
|
67
97
|
end
|
68
98
|
end
|
data/lib/ruby_lsp_ree/version.rb
CHANGED
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.
|
4
|
+
version: 0.1.16
|
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-04-
|
11
|
+
date: 2025-04-24 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:
|
@@ -33,6 +33,7 @@ files:
|
|
33
33
|
- lib/ruby_lsp/ruby_lsp_ree/formatters/missing_error_contracts_formatter.rb
|
34
34
|
- lib/ruby_lsp/ruby_lsp_ree/formatters/missing_error_definitions_formatter.rb
|
35
35
|
- lib/ruby_lsp/ruby_lsp_ree/formatters/missing_error_locales_formatter.rb
|
36
|
+
- lib/ruby_lsp/ruby_lsp_ree/formatters/missing_imports_formatter.rb
|
36
37
|
- lib/ruby_lsp/ruby_lsp_ree/formatters/sort_links_formatter.rb
|
37
38
|
- lib/ruby_lsp/ruby_lsp_ree/formatters/unused_links_formatter.rb
|
38
39
|
- lib/ruby_lsp/ruby_lsp_ree/handlers/completion_handler.rb
|
@@ -41,6 +42,8 @@ files:
|
|
41
42
|
- lib/ruby_lsp/ruby_lsp_ree/listeners/completion_listener.rb
|
42
43
|
- lib/ruby_lsp/ruby_lsp_ree/listeners/definition_listener.rb
|
43
44
|
- lib/ruby_lsp/ruby_lsp_ree/listeners/hover_listener.rb
|
45
|
+
- lib/ruby_lsp/ruby_lsp_ree/parsing/body_parsers/call_objects_parser.rb
|
46
|
+
- lib/ruby_lsp/ruby_lsp_ree/parsing/body_parsers/local_variables_parser.rb
|
44
47
|
- lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_base_document.rb
|
45
48
|
- lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_class_document.rb
|
46
49
|
- lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_document_builder.rb
|