From e33bc3927d89760c86064f979adcd69eee3059d3 Mon Sep 17 00:00:00 2001 From: Glenn Sarti Date: Tue, 4 Dec 2018 16:48:21 +0800 Subject: [PATCH 1/2] (GH-88) Add a workspace symbol provider The object cache contains all of the type, function and class information so it should be easily be able to be queried and then emit these results as part of a workspace symbol request (as opposed to document symbol). This commit adds the provider and cache methods to support querying all objects in the cache. --- lib/languageserver/document_symbol.rb | 58 +++++++++++++++++++ .../manifest/document_symbol_provider.rb | 50 ++++++++++++++++ lib/puppet-languageserver/message_router.rb | 11 ++++ lib/puppet-languageserver/puppet_helper.rb | 8 +++ .../puppet_helper/cache.rb | 7 +++ .../server_capabilities.rb | 11 ++-- 6 files changed, 140 insertions(+), 5 deletions(-) diff --git a/lib/languageserver/document_symbol.rb b/lib/languageserver/document_symbol.rb index d8560bfa..455c33d7 100644 --- a/lib/languageserver/document_symbol.rb +++ b/lib/languageserver/document_symbol.rb @@ -76,4 +76,62 @@ def self.create(options) result end end + + # /** + # * Represents information about programming constructs like variables, classes, + # * interfaces etc. + # */ + # interface SymbolInformation { + # /** + # * The name of this symbol. + # */ + # name: string; + + # /** + # * The kind of this symbol. + # */ + # kind: number; + + # /** + # * Indicates if this symbol is deprecated. + # */ + # deprecated?: boolean; + + # /** + # * The location of this symbol. The location's range is used by a tool + # * to reveal the location in the editor. If the symbol is selected in the + # * tool the range's start information is used to position the cursor. So + # * the range usually spans more then the actual symbol's name and does + # * normally include things like visibility modifiers. + # * + # * The range doesn't have to denote a node range in the sense of a abstract + # * syntax tree. It can therefore not be used to re-construct a hierarchy of + # * the symbols. + # */ + # location: Location; + + # /** + # * The name of the symbol containing this symbol. This information is for + # * user interface purposes (e.g. to render a qualifier in the user interface + # * if necessary). It can't be used to re-infer a hierarchy for the document + # * symbols. + # */ + # containerName?: string; + # } + module SymbolInformation + def self.create(options) + result = {} + raise('name is a required field for SymbolInformation') if options['name'].nil? + raise('kind is a required field for SymbolInformation') if options['kind'].nil? + raise('location is a required field for DocumentSymbol') if options['location'].nil? + + result['name'] = options['name'] + result['kind'] = options['kind'] + result['deprecated'] = options['deprecated'] unless options['deprecated'].nil? + result['location'] = options['location'] + result['containerName'] = options['containerName'] unless options['containerName'].nil? + + result + end + end end diff --git a/lib/puppet-languageserver/manifest/document_symbol_provider.rb b/lib/puppet-languageserver/manifest/document_symbol_provider.rb index bd322ddb..9889b9ef 100644 --- a/lib/puppet-languageserver/manifest/document_symbol_provider.rb +++ b/lib/puppet-languageserver/manifest/document_symbol_provider.rb @@ -1,6 +1,56 @@ module PuppetLanguageServer module Manifest module DocumentSymbolProvider + def self.workspace_symbols(query) + query = '' if query.nil? + result = [] + PuppetLanguageServer::PuppetHelper.all_objects do |key, item| + key_string = key.to_s + next unless key_string.include?(query) + case item + when PuppetLanguageServer::PuppetHelper::PuppetType + result << LanguageServer::SymbolInformation.create( + 'name' => key_string, + 'kind' => LanguageServer::SYMBOLKIND_METHOD, + 'location' => LanguageServer::Location.create( + 'uri' => PuppetLanguageServer::UriHelper.build_file_uri(item.source), + 'fromline' => item.line, + 'fromchar' => 0, # Don't have char pos for types + 'toline' => item.line, + 'tochar' => 1024, # Don't have char pos for types + ) + ) + + when PuppetLanguageServer::PuppetHelper::PuppetFunction + result << LanguageServer::SymbolInformation.create( + 'name' => key_string, + 'kind' => LanguageServer::SYMBOLKIND_FUNCTION, + 'location' => LanguageServer::Location.create( + 'uri' => PuppetLanguageServer::UriHelper.build_file_uri(item.source), + 'fromline' => item.line, + 'fromchar' => 0, # Don't have char pos for functions + 'toline' => item.line, + 'tochar' => 1024, # Don't have char pos for functions + ) + ) + + when PuppetLanguageServer::PuppetHelper::PuppetClass + result << LanguageServer::SymbolInformation.create( + 'name' => key_string, + 'kind' => LanguageServer::SYMBOLKIND_CLASS, + 'location' => LanguageServer::Location.create( + 'uri' => PuppetLanguageServer::UriHelper.build_file_uri(item.source), + 'fromline' => item.line, + 'fromchar' => 0, # Don't have char pos for classes + 'toline' => item.line, + 'tochar' => 1024, # Don't have char pos for classes + ) + ) + end + end + result + end + def self.extract_document_symbols(content) parser = Puppet::Pops::Parser::Parser.new result = parser.parse_string(content, '') diff --git a/lib/puppet-languageserver/message_router.rb b/lib/puppet-languageserver/message_router.rb index a8add497..5f2dee52 100644 --- a/lib/puppet-languageserver/message_router.rb +++ b/lib/puppet-languageserver/message_router.rb @@ -164,6 +164,17 @@ def receive_request(request) PuppetLanguageServer.log_message(:error, "(textDocument/documentSymbol) #{exception}") request.reply_result(nil) end + + when 'workspace/symbol' + begin + result = [] + result.concat(PuppetLanguageServer::Manifest::DocumentSymbolProvider.workspace_symbols(request.params['query'])) + request.reply_result(result) + rescue StandardError => exception + PuppetLanguageServer.log_message(:error, "(workspace/symbol) #{exception}") + request.reply_result([]) + end + else PuppetLanguageServer.log_message(:error, "Unknown RPC method #{request.rpc_method}") end diff --git a/lib/puppet-languageserver/puppet_helper.rb b/lib/puppet-languageserver/puppet_helper.rb index 15d59404..d7f3d4f4 100644 --- a/lib/puppet-languageserver/puppet_helper.rb +++ b/lib/puppet-languageserver/puppet_helper.rb @@ -26,6 +26,14 @@ def self.initialize_helper(options = {}) sidecar_queue.cache = @inmemory_cache end + def self.all_objects(&_block) + return nil if @default_types_loaded == false + raise('Puppet Helper Cache has not been configured') if @inmemory_cache.nil? + @inmemory_cache.all_objects do |key, item| + yield key, item + end + end + # Node Graph def self.get_node_graph(content, local_workspace) with_temporary_file(content) do |filepath| diff --git a/lib/puppet-languageserver/puppet_helper/cache.rb b/lib/puppet-languageserver/puppet_helper/cache.rb index e804c0ce..404b9adf 100644 --- a/lib/puppet-languageserver/puppet_helper/cache.rb +++ b/lib/puppet-languageserver/puppet_helper/cache.rb @@ -75,6 +75,13 @@ def objects_by_section(section, &_block) end end + def all_objects(&_block) + @cache_lock.synchronize do + @inmemory_cache.each do |item| + yield item.key, item + end + end + end private # diff --git a/lib/puppet-languageserver/server_capabilities.rb b/lib/puppet-languageserver/server_capabilities.rb index 9eb01485..53ce85a9 100644 --- a/lib/puppet-languageserver/server_capabilities.rb +++ b/lib/puppet-languageserver/server_capabilities.rb @@ -4,14 +4,15 @@ def self.capabilities # https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#initialize-request { - 'textDocumentSync' => LanguageServer::TEXTDOCUMENTSYNCKIND_FULL, - 'hoverProvider' => true, - 'completionProvider' => { + 'textDocumentSync' => LanguageServer::TEXTDOCUMENTSYNCKIND_FULL, + 'hoverProvider' => true, + 'completionProvider' => { 'resolveProvider' => true, 'triggerCharacters' => ['>', '$', '[', '='] }, - 'definitionProvider' => true, - 'documentSymbolProvider' => true + 'definitionProvider' => true, + 'documentSymbolProvider' => true, + 'workspaceSymbolProvider' => true } end end From 24fbfddbf3f0350e4108caa8d28cc2de33db6774 Mon Sep 17 00:00:00 2001 From: Glenn Sarti Date: Tue, 11 Dec 2018 11:37:39 +0800 Subject: [PATCH 2/2] (maint) Fix rubocop violations and test timeout This commit updates new rubocop violations and increases the test timeout due to failures on Travis. --- lib/puppet-languageserver/puppet_helper/cache.rb | 1 + spec/languageserver/spec_helper.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/puppet-languageserver/puppet_helper/cache.rb b/lib/puppet-languageserver/puppet_helper/cache.rb index 404b9adf..6834be1f 100644 --- a/lib/puppet-languageserver/puppet_helper/cache.rb +++ b/lib/puppet-languageserver/puppet_helper/cache.rb @@ -82,6 +82,7 @@ def all_objects(&_block) end end end + private # diff --git a/spec/languageserver/spec_helper.rb b/spec/languageserver/spec_helper.rb index 815bba64..679a57e3 100644 --- a/spec/languageserver/spec_helper.rb +++ b/spec/languageserver/spec_helper.rb @@ -24,7 +24,7 @@ def wait_for_puppet_loading PuppetLanguageServer::PuppetHelper.default_classes_loaded? sleep(1) interation += 1 - next if interation < 60 + next if interation < 90 raise <<-ERRORMSG Puppet has not be initialised in time: functions_loaded? = #{PuppetLanguageServer::PuppetHelper.default_functions_loaded?}