Skip to content

Commit 8366d21

Browse files
committed
(GH-236) Implement a fake object layer for Puppet assets
Previously the Language Server would query Puppet directly for lists of objects such as types or functions. However this meant for simple query operations the entire object had to be parsed and loaded. his commit introduces an object system that can be populated from Puppet and then be consumed by the Language Server (faux_objects.rb).
1 parent 90aaf8f commit 8366d21

File tree

12 files changed

+750
-239
lines changed

12 files changed

+750
-239
lines changed

server/lib/puppet-languageserver/completion_provider.rb

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -44,29 +44,26 @@ def self.complete(content, line_num, char_num)
4444
# We are inside a resource definition. Should display all available
4545
# properities and parameters.
4646

47-
# TODO: Should really cache all of the resources and params/props for quick
48-
# searching and then only actually instatiate when needed. For the moment,
49-
# instantiate all the things!
50-
51-
item_type = Puppet::Type.type(item.type_name.value)
47+
item_type = PuppetLanguageServer::PuppetHelper.get_type(item.type_name.value)
5248
# Add Parameters
53-
item_type.parameters.each do |param|
54-
items << LanguageServer::CompletionItem.create('label' => param.to_s,
49+
item_type.parameters.each_key do |name|
50+
items << LanguageServer::CompletionItem.create('label' => name.to_s,
5551
'kind' => LanguageServer::COMPLETIONITEMKIND_PROPERTY,
5652
'detail' => 'Parameter',
5753
'data' => { 'type' => 'resource_parameter',
58-
'param' => param.to_s,
54+
'param' => name.to_s,
5955
'resource_type' => item.type_name.value })
6056
end
6157
# Add Properties
62-
item_type.properties.each do |prop|
63-
items << LanguageServer::CompletionItem.create('label' => prop.name.to_s,
58+
item_type.properties.each_key do |name|
59+
items << LanguageServer::CompletionItem.create('label' => name.to_s,
6460
'kind' => LanguageServer::COMPLETIONITEMKIND_PROPERTY,
6561
'detail' => 'Property',
6662
'data' => { 'type' => 'resource_property',
67-
'prop' => prop.name.to_s,
63+
'prop' => name.to_s,
6864
'resource_type' => item.type_name.value })
6965
end
66+
# TODO: What about meta parameters?
7067
end
7168

7269
LanguageServer::CompletionList.create('isIncomplete' => incomplete,
@@ -110,12 +107,12 @@ def self.all_resources(&block)
110107

111108
def self.all_statement_functions(&block)
112109
# Find functions which don't return values i.e. statements
113-
PuppetLanguageServer::PuppetHelper.functions.select { |_key, obj| obj[:type] == :statement }.each_key do |key|
114-
item = LanguageServer::CompletionItem.create('label' => key.to_s,
110+
PuppetLanguageServer::PuppetHelper.filtered_function_names { |_name, data| data.type == :statement }.each do |name|
111+
item = LanguageServer::CompletionItem.create('label' => name.to_s,
115112
'kind' => LanguageServer::COMPLETIONITEMKIND_FUNCTION,
116113
'detail' => 'Function',
117114
'data' => { 'type' => 'function',
118-
'name' => key.to_s })
115+
'name' => name.to_s })
119116
block.call(item) if block
120117
end
121118
end
@@ -162,32 +159,36 @@ def self.resolve(completion_item)
162159

163160
when 'function'
164161
item_type = PuppetLanguageServer::PuppetHelper.function(data['name'])
165-
completion_item['documentation'] = item_type[:doc] unless item_type[:doc].nil?
162+
completion_item['documentation'] = item_type.doc unless item_type.doc.nil?
166163
completion_item['insertText'] = "#{data['name']}(${1:value}"
167-
(2..item_type[:arity]).each do |index|
164+
(2..item_type.arity).each do |index|
168165
completion_item['insertText'] += ", ${#{index}:value}"
169166
end
170167
completion_item['insertText'] += ')'
171168
completion_item['insertTextFormat'] = LanguageServer::INSERTTEXTFORMAT_SNIPPET
172169

173170
when 'resource_type'
174-
item_type = Puppet::Type.type(data['name'])
171+
item_type = PuppetLanguageServer::PuppetHelper.get_type(data['name'])
175172
# TODO: More things?
176173
completion_item['documentation'] = item_type.doc unless item_type.doc.nil?
177174
completion_item['insertText'] = "#{data['name']} { '${1:title}':\n\tensure => '${2:present}'\n}"
178175
completion_item['insertTextFormat'] = LanguageServer::INSERTTEXTFORMAT_SNIPPET
179176
when 'resource_parameter'
180-
item_type = Puppet::Type.type(data['resource_type'])
181-
param_type = item_type.attrclass(data['param'].intern)
182-
# TODO: More things?
183-
completion_item['documentation'] = param_type.doc unless param_type.doc.nil?
184-
completion_item['insertText'] = "#{data['param']} => "
177+
item_type = PuppetLanguageServer::PuppetHelper.get_type(data['resource_type'])
178+
param_type = item_type.parameters[data['param'].intern]
179+
unless param_type.nil?
180+
# TODO: More things?
181+
completion_item['documentation'] = param_type[:doc] unless param_type[:doc].nil?
182+
completion_item['insertText'] = "#{data['param']} => "
183+
end
185184
when 'resource_property'
186-
item_type = Puppet::Type.type(data['resource_type'])
187-
prop_type = item_type.attrclass(data['prop'].intern)
188-
# TODO: More things?
189-
completion_item['documentation'] = prop_type.doc unless prop_type.doc.nil?
190-
completion_item['insertText'] = "#{data['prop']} => "
185+
item_type = PuppetLanguageServer::PuppetHelper.get_type(data['resource_type'])
186+
prop_type = item_type.properties[data['prop'].intern]
187+
unless prop_type.nil?
188+
# TODO: More things?
189+
completion_item['documentation'] = prop_type[:doc] unless prop_type[:doc].nil?
190+
completion_item['insertText'] = "#{data['prop']} => "
191+
end
191192
end
192193

193194
LanguageServer::CompletionItem.create(completion_item)

server/lib/puppet-languageserver/definition_provider.rb

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,14 @@ def self.find_definition(content, line_num, char_num)
6565
def self.type_or_class(resource_name)
6666
# Strip the leading double-colons for root resource names
6767
resource_name = resource_name.slice(2, resource_name.length - 2) if resource_name.start_with?('::')
68-
location = PuppetLanguageServer::PuppetHelper.type_load_info(resource_name)
69-
location = PuppetLanguageServer::PuppetHelper.class_load_info(resource_name) if location.nil?
70-
unless location.nil?
68+
item = PuppetLanguageServer::PuppetHelper.get_type(resource_name)
69+
item = PuppetLanguageServer::PuppetHelper.get_class(resource_name) if item.nil?
70+
unless item.nil?
7171
return LanguageServer::Location.create(
72-
'uri' => 'file:///' + location['source'],
73-
'fromline' => location['line'],
72+
'uri' => 'file:///' + item.source,
73+
'fromline' => item.line,
7474
'fromchar' => 0,
75-
'toline' => location['line'],
75+
'toline' => item.line,
7676
'tochar' => 1024
7777
)
7878
end
@@ -81,17 +81,15 @@ def self.type_or_class(resource_name)
8181
private_class_method :type_or_class
8282

8383
def self.function_name(func_name)
84-
location = PuppetLanguageServer::PuppetHelper.function_load_info(func_name)
85-
unless location.nil?
86-
return LanguageServer::Location.create(
87-
'uri' => 'file:///' + location['source'],
88-
'fromline' => location['line'],
89-
'fromchar' => 0,
90-
'toline' => location['line'],
91-
'tochar' => 1024
92-
)
93-
end
94-
nil
84+
item = PuppetLanguageServer::PuppetHelper.function(func_name)
85+
return nil if item.nil? || item.source.nil? || item.line.nil?
86+
LanguageServer::Location.create(
87+
'uri' => 'file:///' + item.source,
88+
'fromline' => item.line,
89+
'fromchar' => 0,
90+
'toline' => item.line,
91+
'tochar' => 1024
92+
)
9593
end
9694
private_class_method :function_name
9795
end

server/lib/puppet-languageserver/hover_provider.rb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ def self.resolve(content, line_num, char_num)
4040
item_type = PuppetLanguageServer::PuppetHelper.get_type(path[distance_up_ast - 1].type_name.value)
4141
raise "#{path[distance_up_ast - 1].type_name.value} is not a valid puppet type" if item_type.nil?
4242
# Check if it's a property
43-
attribute = item_type.validproperty?(item.attribute_name)
43+
attribute = item_type.properties.keys.include?(item.attribute_name.intern)
4444
if attribute != false
4545
content = get_attribute_property_content(item_type, item.attribute_name.intern)
46-
elsif item_type.validparameter?(item.attribute_name.intern)
46+
elsif item_type.parameters.keys.include?(item.attribute_name.intern)
4747
content = get_attribute_parameter_content(item_type, item.attribute_name.intern)
4848
end
4949

@@ -102,17 +102,17 @@ def self.get_fact_content(factname)
102102
end
103103

104104
def self.get_attribute_parameter_content(item_type, param)
105-
param_type = item_type.attrclass(param)
105+
param_type = item_type.parameters[param]
106106
content = "**#{param}** Parameter"
107-
content += "\n\n#{param_type.doc}" unless param_type.doc.nil?
107+
content += "\n\n#{param_type[:doc]}" unless param_type[:doc].nil?
108108
content
109109
end
110110

111111
def self.get_attribute_property_content(item_type, property)
112-
prop_type = item_type.attrclass(property)
112+
prop_type = item_type.properties[property]
113113
content = "**#{property}** Property"
114-
content += "\n\n(_required_)" if prop_type.required?
115-
content += "\n\n#{prop_type.doc}" unless prop_type.doc.nil?
114+
content += "\n\n(_required_)" if prop_type[:required?]
115+
content += "\n\n#{prop_type[:doc]}" unless prop_type[:doc].nil?
116116
content
117117
end
118118

@@ -124,7 +124,7 @@ def self.get_call_named_function_expression_content(item)
124124

125125
# TODO: what about rvalue?
126126
content = "**#{func_name}** Function\n\n" # TODO: Do I add in the params from the arity number?
127-
content += func_info[:doc]
127+
content += func_info.doc
128128

129129
content
130130
end

0 commit comments

Comments
 (0)