Module: PuppetLanguageServer::Manifest::CompletionProvider
- Defined in:
- lib/puppet-languageserver/manifest/completion_provider.rb
Class Method Summary collapse
- .all_facts(session_state, &block) ⇒ Object
- .all_functions(session_state, tasks_mode, &block) ⇒ Object
- .all_resources(session_state, &block) ⇒ Object
- .complete(session_state, content, line_num, char_num, options = {}) ⇒ Object
-
.keywords(keywords = [], &block) ⇒ Object
BEGIN CompletionItem Helpers.
-
.resolve(session_state, completion_item) ⇒ Object
completion_item is an instance of LSP::CompletionItem.
Class Method Details
.all_facts(session_state, &block) ⇒ Object
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/puppet-languageserver/manifest/completion_provider.rb', line 146 def self.all_facts(session_state, &block) PuppetLanguageServer::FacterHelper.fact_names(session_state).each do |name| item = LSP::CompletionItem.new( 'label' => name.to_s, 'insertText' => "'#{name}'", 'kind' => LSP::CompletionItemKind::VARIABLE, 'detail' => 'Fact', 'data' => { 'type' => 'variable_expr_fact', 'expr' => name } ) yield(item) if block end end |
.all_functions(session_state, tasks_mode, &block) ⇒ Object
187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/puppet-languageserver/manifest/completion_provider.rb', line 187 def self.all_functions(session_state, tasks_mode, &block) PuppetLanguageServer::PuppetHelper.function_names(session_state, tasks_mode).each do |name| item = LSP::CompletionItem.new( 'label' => name.to_s, 'kind' => LSP::CompletionItemKind::FUNCTION, 'detail' => 'Function', 'data' => { 'type' => 'function', 'name' => name.to_s } ) yield(item) if block end end |
.all_resources(session_state, &block) ⇒ Object
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/puppet-languageserver/manifest/completion_provider.rb', line 162 def self.all_resources(session_state, &block) # Find Puppet Types PuppetLanguageServer::PuppetHelper.type_names(session_state).each do |pup_type| item = LSP::CompletionItem.new( 'label' => pup_type, 'kind' => LSP::CompletionItemKind::MODULE, 'detail' => 'Resource', 'data' => { 'type' => 'resource_type', 'name' => pup_type } ) yield(item) if block end # Find Puppet Classes/Defined Types PuppetLanguageServer::PuppetHelper.class_names(session_state).each do |pup_class| item = LSP::CompletionItem.new('label' => pup_class, 'kind' => LSP::CompletionItemKind::MODULE, 'detail' => 'Resource', 'data' => { 'type' => 'resource_class', 'name' => pup_class }) yield(item) if block end end |
.complete(session_state, content, line_num, char_num, options = {}) ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/puppet-languageserver/manifest/completion_provider.rb', line 6 def self.complete(session_state, content, line_num, char_num, = {}) = { tasks_mode: false, context: nil # LSP::CompletionContext object }.merge() items = [] incomplete = false is_trigger_char = ![:context].nil? && [:context].triggerKind == LSP::CompletionTriggerKind::TRIGGERCHARACTER result = PuppetLanguageServer::PuppetParserHelper.object_under_cursor(content, line_num, char_num, multiple_attempts: true, disallowed_classes: [Puppet::Pops::Model::QualifiedName, Puppet::Pops::Model::BlockExpression], tasks_mode: [:tasks_mode], remove_trigger_char: is_trigger_char) if result.nil? # We are in the root of the document. # Add keywords keywords(%w[class define node application site]) { |x| items << x } keywords(%w[plan]) { |x| items << x } if [:tasks_mode] # Add resources all_resources(session_state) { |x| items << x } all_functions(session_state, [:tasks_mode]) { |x| items << x } response = LSP::CompletionList.new response.items = items response.isIncomplete = incomplete return response end item = result[:model] case item.class.to_s when 'Puppet::Pops::Model::VariableExpression' expr = item.expr.value # Complete for `$facts[...` all_facts(session_state) { |x| items << x } if expr == 'facts' when 'Puppet::Pops::Model::HostClassDefinition', 'Puppet::Pops::Model::ResourceTypeDefinition' # We are in the root of a `class` or `define` statement # Add keywords keywords(%w[require contain]) { |x| items << x } # Add resources all_resources(session_state) { |x| items << x } when 'Puppet::Pops::Model::PlanDefinition' # We are in the root of a `plan` statement # Add resources all_resources(session_state) { |x| items << x } all_functions(session_state, [:tasks_mode]) { |x| items << x } when 'Puppet::Pops::Model::ResourceExpression' # We are inside a resource definition. Should display all available # properities and parameters. # Try Types first # The `class` pseudo resource type is actually used to set properties/params for the puppet type # specified in the resource title. # Ref: https://puppet.com/docs/puppet/5.3/lang_classes.html#using-resource-like-declarations item_value = item.type_name.value == 'class' && item.bodies.length == 1 ? item.bodies[0].title.value : item.type_name.value item_object = PuppetLanguageServer::PuppetHelper.get_type(session_state, item_value) unless item_object.nil? # Add Parameters item_object.attributes.select { |_name, data| data[:type] == :param }.each_key do |name| items << LSP::CompletionItem.new( 'label' => name.to_s, 'kind' => LSP::CompletionItemKind::PROPERTY, 'detail' => 'Parameter', 'data' => { 'type' => 'resource_parameter', 'param' => name.to_s, 'resource_type' => item_value } ) end # Add Properties item_object.attributes.select { |_name, data| data[:type] == :property }.each_key do |name| items << LSP::CompletionItem.new( 'label' => name.to_s, 'kind' => LSP::CompletionItemKind::PROPERTY, 'detail' => 'Property', 'data' => { 'type' => 'resource_property', 'prop' => name.to_s, 'resource_type' => item_value } ) end # TODO: What about meta parameters? end if item_object.nil? # Try Classes/Defined Types item_object = PuppetLanguageServer::PuppetHelper.get_class(session_state, item_value) unless item_object.nil? # Add Parameters item_object.parameters.each_key do |name| items << LSP::CompletionItem.new( 'label' => name.to_s, 'kind' => LSP::CompletionItemKind::PROPERTY, 'detail' => 'Parameter', 'data' => { 'type' => 'resource_class_parameter', 'param' => name.to_s, 'resource_type' => item_value } ) end end end end response = LSP::CompletionList.new response.items = items response.isIncomplete = incomplete response end |
.keywords(keywords = [], &block) ⇒ Object
BEGIN CompletionItem Helpers
131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/puppet-languageserver/manifest/completion_provider.rb', line 131 def self.keywords(keywords = [], &block) keywords.each do |keyword| item = LSP::CompletionItem.new( 'label' => keyword, 'kind' => LSP::CompletionItemKind::KEYWORD, 'detail' => 'Keyword', 'data' => { 'type' => 'keyword', 'name' => keyword } ) yield(item) if block end end |
.resolve(session_state, completion_item) ⇒ Object
completion_item is an instance of LSP::CompletionItem
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
# File 'lib/puppet-languageserver/manifest/completion_provider.rb', line 204 def self.resolve(session_state, completion_item) result = completion_item.clone data = result.data case data['type'] when 'variable_expr_fact' value = PuppetLanguageServer::FacterHelper.fact_value(session_state, data['expr']) # TODO: More things? result.documentation = value.to_s when 'keyword' case data['name'] when 'class' result.documentation = 'Classes are named blocks of Puppet code that are stored in modules for later use and ' \ 'are not applied until they are invoked by name. They can be added to a node’s catalog ' \ 'by either declaring them in your manifests or assigning them from an ENC.' result.insertText = "# Class: $1\n#\n#\nclass ${1:name} {\n\t${2:# resources}\n}$0" result.insertTextFormat = LSP::InsertTextFormat::SNIPPET when 'define' result.documentation = 'Defined resource types (also called defined types or defines) are blocks of Puppet code ' \ 'that can be evaluated multiple times with different parameters. Once defined, they act ' \ 'like a new resource type: you can cause the block to be evaluated by declaring a resource ' \ 'of that new resource type.' result.insertText = "define ${1:name} () {\n\t${2:# resources}\n}$0" result.insertTextFormat = LSP::InsertTextFormat::SNIPPET when 'application' result.detail = 'Orchestrator' result.documentation = 'Application definitions are a lot like a defined resource type except that instead of defining ' \ 'a chunk of reusable configuration that applies to a single node, the application definition ' \ 'operates at a higher level. The components you declare inside an application can be individually ' \ 'assigned to separate nodes you manage with Puppet.' result.insertText = "application ${1:name} () {\n\t${2:# resources}\n}$0" result.insertTextFormat = LSP::InsertTextFormat::SNIPPET when 'site' result.detail = 'Orchestrator' result.documentation = 'Within the site block, applications are declared like defined types. They can be declared any ' \ 'number of times, but their type and title combination must be unique within an environment.' result.insertText = "site ${1:name} () {\n\t${2:# applications}\n}$0" result.insertTextFormat = LSP::InsertTextFormat::SNIPPET end when 'function' # We don't know if this resolution is coming from a plan or not, so just assume it is item_type = PuppetLanguageServer::PuppetHelper.function(session_state, data['name'], true) return result if item_type.nil? result.documentation = item_type.doc unless item_type.doc.nil? unless item_type.nil? || item_type.signatures.count.zero? result.detail = item_type.signatures.map(&:key).join("\n\n") # The signature provider should handle suggestions after this, so just place the cursor ready for an opening bracket result.insertText = data['name'].to_s result.insertTextFormat = LSP::InsertTextFormat::PLAINTEXT end when 'resource_type' item_type = PuppetLanguageServer::PuppetHelper.get_type(session_state, data['name']) return result if item_type.nil? attr_names = [] # Add required attributes. Ignore namevars as they come from the resource title item_type.attributes.each { |name, item| attr_names.push(name.to_s) if item[:required?] && item[:isnamevar?] != true } # Remove the'ensure' param/property for now, and we'll re-add later attr_names.reject! { |item| item == 'ensure' } # The param/property list should initially sorted alphabetically attr_names.sort! # Add the 'ensure' param/property at the top if the resource supports it attr_names.insert(0, 'ensure') unless item_type.attributes.keys.find_index(:ensure).nil? # Get the longest string length for later hash-rocket padding max_length = -1 attr_names.each { |name| max_length = name.length if name.length > max_length } # Generate the text snippet snippet = "#{data['name']} { '${1:title}':\n" attr_names.each_index do |index| name = attr_names[index] value_text = (name == 'ensure') ? 'present' : 'value' # rubocop:disable Style/TernaryParentheses In this case it's easier to read. snippet += "\t#{name.ljust(max_length, ' ')} => '${#{index + 2}:#{value_text}}'\n" end snippet += '}' result.documentation = item_type.doc unless item_type.doc.nil? result.insertText = snippet result.insertTextFormat = LSP::InsertTextFormat::SNIPPET when 'resource_parameter' item_type = PuppetLanguageServer::PuppetHelper.get_type(session_state, data['resource_type']) return result if item_type.nil? param_type = item_type.attributes[data['param'].intern] unless param_type.nil? # TODO: More things? result.documentation = param_type[:doc] unless param_type[:doc].nil? result.insertText = "#{data['param']} => ," end when 'resource_property' item_type = PuppetLanguageServer::PuppetHelper.get_type(session_state, data['resource_type']) return result if item_type.nil? prop_type = item_type.attributes[data['prop'].intern] unless prop_type.nil? # TODO: More things? result.documentation = prop_type[:doc] unless prop_type[:doc].nil? result.insertText = "#{data['prop']} => ," end when 'resource_class' item_class = PuppetLanguageServer::PuppetHelper.get_class(session_state, data['name']) return result if item_class.nil? result.insertText = "#{data['name']} { '${1:title}':\n\t$0\n}" result.insertTextFormat = LSP::InsertTextFormat::SNIPPET when 'resource_class_parameter' item_class = PuppetLanguageServer::PuppetHelper.get_class(session_state, data['resource_type']) return result if item_class.nil? param_type = item_class.parameters[data['param']] unless param_type.nil? doc = '' doc += param_type[:type] unless param_type[:type].nil? doc += "---\n#{param_type[:doc]}" unless param_type[:doc].nil? result.documentation = doc result.insertText = "#{data['param']} => ," end end result end |