7
7
module RubyLsp
8
8
module Rails
9
9
module FactoryBot
10
+ # The listener that is created when the user requests autocomplete at the relevant time.
11
+ #
12
+ # NOTE: autocompletion is only triggered on certain node types - almost exclusively call nodes
13
+ # and constants IIRC, so you cannot currently receive autocomplete options for symbols (eg.
14
+ # factory or trait names) :/
10
15
class Completion
11
16
include RubyLsp ::Requests ::Support ::Common
12
17
13
- # TODO: Avoid duplication with other class
14
- FACTORY_BOT_METHODS = %i[
15
- create
16
- build
17
- build_stubbed
18
- attributes_for
19
- ] . flat_map { |attr | [ attr , :"#{ attr } _list" , :"#{ attr } _pair" ] } . freeze
20
-
21
18
def initialize ( response_builder , node_context , dispatcher , server_client )
22
19
@response_builder = response_builder
23
20
@node_context = node_context
@@ -27,112 +24,104 @@ def initialize(response_builder, node_context, dispatcher, server_client)
27
24
end
28
25
29
26
def on_call_node_enter ( node )
30
- return unless FACTORY_BOT_METHODS . include? ( node . name ) ||
31
- FACTORY_BOT_METHODS . include? ( @node_context . parent . name )
27
+ return unless FactoryBot ::FACTORY_BOT_METHODS . include? ( node . name ) ||
28
+ FactoryBot ::FACTORY_BOT_METHODS . include? ( @node_context . parent . name )
29
+
30
+ process_arguments_pattern ( node , node . arguments )
31
+ rescue StandardError => e
32
+ $stderr. write ( e , e . backtrace )
33
+ end
34
+
35
+ private
32
36
33
- case node . arguments
37
+ def process_arguments_pattern ( node , arguments ) # rubocop:disable Metrics/MethodLength
38
+ case arguments
34
39
in [ Prism ::SymbolNode => factory_name_node ]
35
- handle_factory ( factory_name_node , factory_name_node . value . to_s )
40
+ handle_factory ( factory_name_node , node_string_value ( factory_name_node ) )
36
41
37
42
in [ Prism ::SymbolNode => factory_name_node , *, Prism ::SymbolNode => trait_node ]
38
- handle_trait ( factory_name_node . value . to_s , node , trait_node . value . to_s )
39
-
40
- in [ Prism ::SymbolNode => factory_name_node , *, Prism ::CallNode => call_node ]
41
- handle_attribute ( factory_name_node . value . to_s , node , call_node . message )
42
-
43
- in [ Prism ::SymbolNode => factory_name_node , *, Prism ::KeywordHashNode => kw_node ]
44
- handle_attribute (
45
- factory_name_node . value . to_s , node , kw_node . elements . last . key . value &.to_s
46
- )
47
- in [ Prism ::SymbolNode => factory_name_node , *, Prism ::HashNode => hash_node ]
48
- handle_attribute (
49
- factory_name_node . value . to_s , node , hash_node . elements . last . key . value &.to_s
50
- )
43
+ handle_trait ( node_string_value ( factory_name_node ) , node , node_string_value ( trait_node ) )
44
+
45
+ in [ Prism ::SymbolNode => _factory_name_node , *, Prism ::KeywordHashNode => _kw_node ] |
46
+ [ Prism ::SymbolNode => _factory_name_node , *, Prism ::HashNode => _kw_node ] |
47
+ [ Prism ::SymbolNode => _factory_name_node , *, Prism ::CallNode => _call_node ]
48
+
49
+ attr_name = _call_node ? _call_node . message : _kw_node . elements . last . key . value &.to_s
50
+ handle_attribute ( node_string_value ( _factory_name_node ) , node , attr_name )
51
51
else
52
- $stderr. write node . arguments
53
52
nil
54
53
end
55
- rescue => e
56
- $stderr. write ( e , e . backtrace )
57
54
end
58
55
59
- private
56
+ def node_string_value ( node )
57
+ node . value . to_s
58
+ end
60
59
61
60
def handle_attribute ( factory_name , node , value = "" )
62
- make_request (
63
- :attributes ,
64
- factory_name : factory_name , name : value
65
- ) &.each do |attr |
66
- label_details = Interface ::CompletionItemLabelDetails . new (
67
- description : attr [ :type ] ,
68
- )
69
- range = range_from_node ( node )
61
+ range = range_from_node ( node )
62
+ make_request ( :attributes , factory_name : factory_name , name : value ) &.each do |attr |
63
+ label_details = Interface ::CompletionItemLabelDetails . new ( description : attr [ :type ] )
70
64
71
- @response_builder << Interface ::CompletionItem . new (
72
- label : attr [ :name ] ,
73
- filter_text : attr [ :name ] ,
74
- label_details : label_details ,
75
- text_edit : Interface ::TextEdit . new ( range : range , new_text : attr [ :name ] ) ,
76
- kind : Constant ::CompletionItemKind ::PROPERTY ,
77
- data : {
78
- owner_name : attr [ :owner ] ,
79
- guessed_type : attr [ :owner ] , # the type of the owner, not the attribute
80
- } ,
81
- )
65
+ @response_builder << serialise_attribute ( attr [ :name ] , label_details , attr [ :owner ] , range )
82
66
end
83
67
end
84
68
69
+ def serialise_attribute ( name , label_details , owner , range )
70
+ Interface ::CompletionItem . new (
71
+ label : name ,
72
+ filter_text : name ,
73
+ label_details : label_details ,
74
+ text_edit : Interface ::TextEdit . new ( range : range , new_text : name ) ,
75
+ kind : Constant ::CompletionItemKind ::PROPERTY ,
76
+ data : { owner_name : owner , guessed_type : owner } , # the type of the owner, not the attribute
77
+ )
78
+ end
79
+
85
80
def handle_trait ( factory_name , node , value = "" )
86
- make_request (
87
- :traits ,
88
- factory_name : factory_name , name : value
89
- ) &.each do |tr |
90
- label_details = Interface ::CompletionItemLabelDetails . new (
91
- description : tr [ :owner ] ,
92
- )
81
+ make_request ( :traits , factory_name : factory_name , name : value ) &.each do |tr |
82
+ label_details = Interface ::CompletionItemLabelDetails . new ( description : tr [ :owner ] )
93
83
range = range_from_node ( node )
94
-
95
84
name = tr [ :name ]
96
85
97
- @response_builder << Interface ::CompletionItem . new (
98
- label : name ,
99
- filter_text : name ,
100
- label_details : label_details ,
101
- text_edit : Interface ::TextEdit . new ( range : range , new_text : name ) ,
102
- kind : Constant ::CompletionItemKind ::PROPERTY ,
103
- data : {
104
- owner_name : nil ,
105
- guessed_type : tr [ :owner ] # the type of the owner
106
- } ,
107
- )
86
+ @response_builder << serialise_trait ( name , range , label_details )
108
87
end
109
88
end
110
89
90
+ def serialise_trait ( name , range , label_details )
91
+ Interface ::CompletionItem . new (
92
+ label : name ,
93
+ filter_text : name ,
94
+ label_details : label_details ,
95
+ text_edit : Interface ::TextEdit . new ( range : range , new_text : name ) ,
96
+ kind : Constant ::CompletionItemKind ::PROPERTY ,
97
+ data : { owner_name : nil , guessed_type : tr [ :owner ] } ,
98
+ )
99
+ end
100
+
111
101
def handle_factory ( node , name )
102
+ range = range_from_node ( node )
112
103
make_request ( :factories , name : name ) &.each do |fact |
113
- @response_builder << Interface ::CompletionItem . new (
114
- label : fact [ :name ] ,
115
- filter_text : fact [ :name ] ,
116
- label_details : Interface ::CompletionItemLabelDetails . new (
117
- description : fact [ :model_class ]
118
- ) ,
119
- text_edit : Interface ::TextEdit . new (
120
- range : range_from_node ( node ) ,
121
- new_text : fact [ :name ] ,
122
- ) ,
123
- kind : Constant ::CompletionItemKind ::CLASS ,
124
- data : {
125
- guessed_type : fact [ :model_class ]
126
- }
127
- )
104
+ @response_builder << serialise_factory ( fact [ :name ] , fact [ :model_class ] , range )
128
105
end
129
106
end
130
107
131
108
def make_request ( request_name , **params )
132
- @server_client . delegate_request (
109
+ resp = @server_client . delegate_request (
133
110
server_addon_name : FactoryBot ::ADDON_NAME ,
134
- request_name : request_name ,
135
- **params
111
+ request_name : request_name . to_s ,
112
+ **params ,
113
+ )
114
+ resp [ :result ] if resp
115
+ end
116
+
117
+ def serialise_factory ( name , model_class , range )
118
+ Interface ::CompletionItem . new (
119
+ label : name ,
120
+ filter_text : name ,
121
+ label_details : Interface ::CompletionItemLabelDetails . new ( description : model_class ) ,
122
+ text_edit : Interface ::TextEdit . new ( range : range , new_text : name ) ,
123
+ kind : Constant ::CompletionItemKind ::CLASS ,
124
+ data : { guessed_type : model_class } ,
136
125
)
137
126
end
138
127
end
0 commit comments