diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9f2a3a3f..41145d88 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,8 +13,8 @@ jobs: fail-fast: false matrix: ruby_version: - - '2.5' - '2.7' + - '3.2' runs_on: - 'ubuntu-latest' - 'windows-latest' @@ -32,8 +32,13 @@ jobs: fail-fast: false matrix: ruby_version: - - '2.5' - '2.7' + - '3.2' + include: + - ruby_version: '2.7' + puppet_version: '~> 7.0' + - ruby_version: '3.2' + puppet_version: '~> 8.0' runs_on: - 'ubuntu-latest' - 'windows-latest' @@ -45,16 +50,22 @@ jobs: ruby_version: ${{ matrix.ruby_version }} runs_on: ${{ matrix.runs_on }} rake_task: 'gem_revendor acceptance_languageserver' - puppet_version: '~> 7.24' + puppet_version: ${{ matrix.puppet_version }} build: - name: "Build Editor Service" + strategy: + fail-fast: false + matrix: + ruby_version: + - '2.7' + - '3.2' + name: "Build Editor Service (Ruby ${{ matrix.ruby_version }})" runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: - ruby-version: '2.7' + ruby-version: ${{ matrix.ruby_version }} bundler-cache: true - name: Set build version shell: pwsh diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 668289fa..b3dd5667 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -12,8 +12,8 @@ jobs: fail-fast: false matrix: ruby_version: - - '2.5' - '2.7' + - '3.2' runs_on: - 'ubuntu-latest' - 'windows-latest' @@ -31,8 +31,13 @@ jobs: fail-fast: false matrix: ruby_version: - - '2.5' - '2.7' + - '3.2' + include: + - ruby_version: '2.7' + puppet_version: '~> 7.0' + - ruby_version: '3.2' + puppet_version: '~> 8.0' runs_on: - 'ubuntu-latest' - 'windows-latest' @@ -44,16 +49,22 @@ jobs: ruby_version: ${{ matrix.ruby_version }} runs_on: ${{ matrix.runs_on }} rake_task: 'gem_revendor acceptance_languageserver' - puppet_version: '~> 7.24' + puppet_version: ${{ matrix.puppet_version }} build: - name: "Build Editor Service" + strategy: + fail-fast: false + matrix: + ruby_version: + - '2.7' + - '3.2' + name: "Build Editor Service (Ruby ${{ matrix.ruby_version }})" runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: - ruby-version: '2.7' + ruby-version: ${{ matrix.ruby_version }} bundler-cache: true - name: Set build version shell: pwsh @@ -67,3 +78,4 @@ jobs: name: puppet-editor-services path: output/*.zip retention-days: 2 + diff --git a/.rubocop.yml b/.rubocop.yml index 8f495485..163f91b1 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,5 +1,9 @@ inherit_from: .rubocop_todo.yml +require: + - rubocop-performance + - rubocop-rspec + AllCops: Include: - 'lib/**/*.rb' @@ -10,108 +14,9 @@ AllCops: - 'vendor/**/*' - Gemfile - Rakefile - -Style/Documentation: - Enabled: false -Style/NumericLiterals: - Enabled: false - -# Length is not useful indicator -Layout/LineLength: - Enabled: false -Metrics/MethodLength: - Enabled: false -Metrics/ModuleLength: - Enabled: false -Metrics/ClassLength: - Enabled: false -Metrics/BlockLength: - Enabled: false -Metrics/AbcSize: - Enabled: false -Metrics/PerceivedComplexity: - Enabled: false -Metrics/CyclomaticComplexity: - Enabled: false - -# Empty method definitions over more than one line is ok -Style/EmptyMethod: - Enabled: false - -# Either sytnax for regex is ok -Style/RegexpLiteral: - Enabled: false - -# Sometimes, I actually want both! -Style/DateTime: - Enabled: false - -# Please don't fail at failing. -Lint/RedundantCopDisableDirective: - Enabled: false - -# Don't care -Naming/MemoizedInstanceVariableName: - Enabled: false -Layout/EmptyLineAfterGuardClause: - Enabled: false -Metrics/ParameterLists: - Enabled: false - -# In some cases readability is better without these cops enabled -Style/ConditionalAssignment: - Enabled: false -Style/Next: - Enabled: false - -# Line endings are just a mess -Layout/EndOfLine: - Enabled: false - -# We only alias for monkey patching -Style/Alias: - Enabled: false - -# Harder to read when on -Style/SymbolProc: - Enabled: false -Style/HashSyntax: - Enabled: false - -Layout/HashAlignment: - EnforcedHashRocketStyle: table - -Naming/RescuedExceptionsVariableName: - PreferredName: e - -# There's no benefit to this and can make things harder to read. -Style/NumericPredicate: - Enabled: false - -# This is not valid on Ruby 2.1 -Style/SafeNavigation: - Enabled: false - -# This is not valid on Ruby 2.1 -Layout/HeredocIndentation: - Enabled: false - -# Rubocop 0.80.0 rules -Style/HashEachMethods: - Enabled: false - -Style/HashTransformKeys: - Enabled: true - -Style/HashTransformValues: - Enabled: true - -# Rubocop 0.80.1 rules -Lint/RaiseException: - Enabled: true - -Lint/StructNewOverride: - Enabled: true - -Style/OptionalBooleanParameter: + NewCops: enable + SuggestExtensions: false + TargetRubyVersion: '2.7' +# Disabled +Style/ClassAndModuleChildren: Enabled: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index b1cfe267..14b6b6a1 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1 +1,218 @@ -# Empty \ No newline at end of file +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2023-09-26 10:42:02 UTC using RuboCop version 1.48.1. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + + + + +# Offense count: 1 +# Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches. +Lint/DuplicateBranch: + Exclude: + - 'lib/puppet-languageserver-sidecar/puppet_helper.rb' + +# Offense count: 2 +# Configuration parameters: AllowComments, AllowEmptyLambdas. +Lint/EmptyBlock: + Exclude: + - 'lib/puppet_languageserver.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Lint/IncompatibleIoSelectWithFiberScheduler: + Exclude: + - 'lib/puppet_editor_services/server/stdio.rb' + +# Offense count: 2 +# This cop supports unsafe autocorrection (--autocorrect-all). +Lint/NonAtomicFileOperation: + Exclude: + - 'lib/puppet-languageserver-sidecar/cache/filesystem.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Lint/OrAssignmentToConstant: + Exclude: + - 'lib/puppet-languageserver/session_state/document_store.rb' +# Offense count: 169 +# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. +Metrics/AbcSize: + Max: 152 + +# Offense count: 7 +# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode. +# AllowedMethods: refine +Metrics/BlockLength: + Max: 50 + +# Offense count: 12 +# Configuration parameters: CountComments, CountAsOne. +Metrics/ClassLength: + Max: 330 + +# Offense count: 53 +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/CyclomaticComplexity: + Max: 42 + +# Offense count: 139 +# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. +Metrics/MethodLength: + Max: 100 + +# Offense count: 10 +# Configuration parameters: CountComments, CountAsOne. +Metrics/ModuleLength: + Max: 252 + +# Offense count: 1 +# Configuration parameters: CountKeywordArgs, MaxOptionalParameters. +Metrics/ParameterLists: + Max: 6 + +# Offense count: 42 +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/PerceivedComplexity: + Max: 32 + +# Offense count: 2 +# Configuration parameters: EnforcedStyleForLeadingUnderscores. +# SupportedStylesForLeadingUnderscores: disallowed, required, optional +Naming/MemoizedInstanceVariableName: + Exclude: + - 'lib/puppet-languageserver-sidecar/puppet_strings_monkey_patches.rb' + - 'lib/puppet-languageserver/server_capabilities.rb' + + +# Offense count: 3 +# Configuration parameters: MinSize. +Performance/CollectionLiteralInLoop: + Exclude: + - 'lib/puppet-languageserver/sidecar_protocol.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Performance/Count: + Exclude: + - 'lib/puppet-languageserver/session_state/language_client.rb' + + + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Security/IoMethods: + Exclude: + - 'lib/puppet-debugserver/debug_session/break_points.rb' + + + +# Offense count: 104 +# Configuration parameters: AllowedConstants. +Style/Documentation: + Enabled: false + + + + +# Offense count: 4 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: AllowedReceivers. +# AllowedReceivers: Thread.current +Style/HashEachMethods: + Exclude: + - 'lib/puppet-languageserver-sidecar/facter_helper.rb' + - 'lib/puppet-languageserver-sidecar/puppet_modulepath_monkey_patches.rb' + - 'lib/puppet-languageserver-sidecar/puppet_strings_helper.rb' + - 'lib/puppet-languageserver/manifest/folding_provider.rb' + + + + + +# Offense count: 7 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle, AllowedMethods, AllowedPatterns. +# SupportedStyles: predicate, comparison +Style/NumericPredicate: + Exclude: + - 'spec/**/*' + - 'lib/puppet-debugserver/puppet_debug_session.rb' + - 'lib/puppet-languageserver/manifest/signature_provider.rb' + - 'lib/puppet-languageserver/message_handler.rb' + - 'lib/puppet-languageserver/puppet_parser_helper.rb' + - 'lib/puppet-languageserver/session_state/language_client.rb' + - 'lib/puppet_editor_services/server/tcp.rb' + +# Offense count: 11 +# Configuration parameters: AllowedMethods. +# AllowedMethods: respond_to_missing? +Style/OptionalBooleanParameter: + Exclude: + - 'lib/puppet-languageserver/client_session_state.rb' + - 'lib/puppet-languageserver/manifest/folding_provider.rb' + - 'lib/puppet-languageserver/puppet_helper.rb' + - 'lib/puppet-languageserver/puppet_monkey_patches.rb' + - 'lib/puppet-languageserver/session_state/language_client.rb' + - 'lib/puppet-languageserver/uri_helper.rb' + - 'lib/puppet_editor_services/server/tcp.rb' + + +# Offense count: 34 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods, MaxChainLength. +# AllowedMethods: present?, blank?, presence, try, try! +Style/SafeNavigation: + Exclude: + - 'lib/puppet-debugserver/hooks.rb' + - 'lib/puppet-debugserver/puppet_debug_session.rb' + - 'lib/puppet-languageserver-sidecar/puppet_environment_monkey_patches.rb' + - 'lib/puppet-languageserver-sidecar/puppet_strings_helper.rb' + - 'lib/puppet-languageserver/facter_helper.rb' + - 'lib/puppet-languageserver/global_queues/validation_queue.rb' + - 'lib/puppet-languageserver/manifest/completion_provider.rb' + - 'lib/puppet-languageserver/manifest/validation_provider.rb' + - 'lib/puppet-languageserver/puppet_helper.rb' + - 'lib/puppet-languageserver/session_state/document_store.rb' + - 'lib/puppet-languageserver/sidecar_protocol.rb' + - 'lib/puppet_editor_services/connection/tcp.rb' + - 'lib/puppet_editor_services/logging.rb' + - 'lib/puppet_editor_services/protocol/base.rb' + +# Offense count: 2 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/SlicingWithRange: + Exclude: + - 'lib/puppet-languageserver/manifest/hover_provider.rb' + - 'lib/puppet-languageserver/puppet_lexer_helper.rb' + +# Offense count: 6 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: AllowMethodsWithArguments, AllowedMethods, AllowedPatterns, AllowComments. +# AllowedMethods: define_method +Style/SymbolProc: + Exclude: + - 'lib/dsp/dsp_base.rb' + - 'lib/puppet-languageserver-sidecar/cache/filesystem.rb' + - 'lib/puppet-languageserver-sidecar/puppet_helper.rb' + - 'lib/puppet-languageserver/client_session_state.rb' + - 'lib/puppet-languageserver/session_state/object_cache.rb' + - 'lib/puppet_languageserver_sidecar.rb' + +# Offense count: 3 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/ZeroLengthPredicate: + Exclude: + - 'lib/puppet-debugserver/debug_session/hook_handlers.rb' + - 'lib/puppet-languageserver/message_handler.rb' + - 'lib/puppet_editor_services/server/tcp.rb' + +# Offense count: 629 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns. +# URISchemes: http, https +Layout/LineLength: + Max: 1529 diff --git a/Gemfile b/Gemfile index b8114163..38aef2b8 100644 --- a/Gemfile +++ b/Gemfile @@ -11,13 +11,13 @@ source ENV['GEM_SOURCE'] || "https://rubygems.org" group :development do gem 'rake', '>= 10.4', :require => false gem 'rspec', '>= 3.2', :require => false - gem 'puppet-lint', '~> 3.3', :require => false + gem 'puppet-lint', '~> 4.0', :require => false gem 'puppetfile-resolver', '~> 0.6.2', :require => false gem 'yard', '~> 0.9.28', :require => false - - gem "rubocop", '= 1.6.1', require: false - gem "rubocop-performance", '= 1.9.1', require: false - gem "rubocop-rspec", '= 2.0.1', require: false + gem 'ffi', '= 1.15.2', :require => false + gem "rubocop", '~> 1.48.1', require: false + gem "rubocop-performance", '~> 1.16', require: false + gem "rubocop-rspec", '~> 2.19', require: false if ENV['PUPPET_GEM_VERSION'] gem 'puppet', ENV['PUPPET_GEM_VERSION'], :require => false diff --git a/README.md b/README.md index 377d3d93..793dfd7b 100644 --- a/README.md +++ b/README.md @@ -4,22 +4,19 @@ ![ci](https://github.com/puppetlabs/puppet-editor-services/actions/workflows/ci.yml/badge.svg) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/puppetlabs/puppet-editor-services) - A ruby based implementation of a [Language Server](https://github.com/Microsoft/language-server-protocol) and [Debug Server](TODO) for the Puppet Language. ## Requirements -* Puppet 5 or above - -* Ruby 2.4 or above +* Puppet 7 or above -**Note** that Puppet 4 (Ruby 2.1) is not supported +* Ruby 2.7 or above ## Setting up editor services for development -* Ensure a modern ruby is installed (2.4+) +* Ensure a modern ruby is installed (2.7+) - The editor services support Puppet 5.0.0 and above + The editor services support Puppet 7.0.0 and above * Clone this repository @@ -299,7 +296,3 @@ Usage: puppet-debugserver.rb [options] ## Why are there vendored gems and why only native ruby When used by editors this language server will be running using the Ruby runtime provided by Puppet Agent. That means no native extensions and no bundler. Also, only the gems provided by Puppet Agent would be available by default. To work around this limitation all runtime dependencies should be re-vendored and then the load path modified appropriately. - -## Known Issues - -* [PUP-7668](https://tickets.puppetlabs.com/browse/PUP-7668) Due to incorrect offsets, hover documentation can be displayed when the user is not actually hovering over the resource that the documentation is for. diff --git a/Rakefile b/Rakefile index 33d1cb1f..8f608d16 100644 --- a/Rakefile +++ b/Rakefile @@ -55,7 +55,7 @@ task :gem_revendor do { :directory => 'puppet-lint', :github_repo => 'https://github.com/puppetlabs/puppet-lint.git', - :github_ref => '2.5.2', + :github_ref => 'v4.2.0', }, { :directory => 'hiera-eyaml', @@ -64,8 +64,8 @@ task :gem_revendor do }, { :directory => 'puppetfile-resolver', - :github_repo => 'https://github.com/glennsarti/puppetfile-resolver.git', - :github_ref => '0.3.0', + :github_repo => 'https://github.com/jordanbreen28/puppetfile-resolver.git', + :github_ref => 'd058f6b8b285dba2af0aeb59722ea5de23c3c13f', }, { :directory => 'molinillo', @@ -75,7 +75,7 @@ task :gem_revendor do { :directory => 'puppet-strings', :github_repo => 'https://github.com/puppetlabs/puppet-strings.git', - :github_ref => 'v2.4.0', + :github_ref => 'v4.1.0', }, { :directory => 'yard', @@ -89,9 +89,9 @@ task :gem_revendor do vendor_dir = File.join(File.dirname(__FILE__),'vendor') gem_list.each do |vendor| gem_dir = File.join(vendor_dir,vendor[:directory]) - FileUtils.rm_rf(gem_dir) if Dir.exists?(gem_dir) + FileUtils.rm_rf(gem_dir) if Dir.exist?(gem_dir) end - Dir.mkdir(vendor_dir) unless Dir.exists?(vendor_dir) + Dir.mkdir(vendor_dir) unless Dir.exist?(vendor_dir) gem_list.each do |vendor| puts "Vendoring #{vendor[:directory]}..." @@ -143,11 +143,11 @@ task build: [:gem_revendor] do file_list = ['lib', 'vendor', 'puppet-languageserver', 'puppet-debugserver', 'puppet-languageserver-sidecar', 'LICENSE'] # Remove files in the list that do not exist. - file_list.reject! { |filepath| !File.exists?(filepath) } + file_list.reject! { |filepath| !File.exist?(filepath) } puts "Cleaning output directory..." - FileUtils.rm_rf Dir.glob("#{output_dir}/*") if Dir.exists?(output_dir) - Dir.mkdir(output_dir) unless Dir.exists?(output_dir) + FileUtils.rm_rf Dir.glob("#{output_dir}/*") if Dir.exist?(output_dir) + Dir.mkdir(output_dir) unless Dir.exist?(output_dir) puts "Fetch editor services version..." require_relative 'lib/puppet_editor_services/version' diff --git a/lib/dsp/dsp.rb b/lib/dsp/dsp.rb index 962aa488..52a20a30 100644 --- a/lib/dsp/dsp.rb +++ b/lib/dsp/dsp.rb @@ -1,9 +1,7 @@ # frozen_string_literal: true %w[dsp_base dsp_protocol].each do |lib| - begin - require "dsp/#{lib}" - rescue LoadError - require File.expand_path(File.join(__dir__, lib)) - end + require "dsp/#{lib}" +rescue LoadError + require File.expand_path(File.join(__dir__, lib)) end diff --git a/lib/dsp/dsp_base.rb b/lib/dsp/dsp_base.rb index 08ba294e..985c4a34 100644 --- a/lib/dsp/dsp_base.rb +++ b/lib/dsp/dsp_base.rb @@ -26,8 +26,7 @@ def to_h value end - def from_h!(value) - end + def from_h!(value); end def to_json(*options) to_h.to_json(options) @@ -51,11 +50,11 @@ def to_typed_aray(val, expected_type) def self.create_range(from_line, from_char, to_line, to_char) { 'start' => { - 'line' => from_line, + 'line' => from_line, 'character' => from_char }, - 'end' => { - 'line' => to_line, + 'end' => { + 'line' => to_line, 'character' => to_char } } diff --git a/lib/dsp/dsp_protocol.rb b/lib/dsp/dsp_protocol.rb index b730529a..293d3afe 100644 --- a/lib/dsp/dsp_protocol.rb +++ b/lib/dsp/dsp_protocol.rb @@ -5,7 +5,6 @@ # rubocop:disable Layout/EmptyLinesAroundClassBody # rubocop:disable Lint/UselessAssignment -# rubocop:disable Style/AsciiComments # rubocop:disable Layout/TrailingWhitespace # rubocop:disable Naming/MethodName diff --git a/lib/lsp/lsp.rb b/lib/lsp/lsp.rb index 5224e485..36682f88 100644 --- a/lib/lsp/lsp.rb +++ b/lib/lsp/lsp.rb @@ -4,9 +4,7 @@ # See tools/lsp_introspect/index.js %w[lsp_base lsp_custom lsp_types lsp_enums lsp_protocol_callhierarchy.proposed lsp_protocol_colorprovider lsp_protocol_configuration lsp_protocol lsp_protocol_declaration lsp_protocol_foldingrange lsp_protocol_implementation lsp_protocol_progress lsp_protocol_selectionrange lsp_protocol_sematictokens.proposed lsp_protocol_typedefinition lsp_protocol_workspacefolders].each do |lib| - begin - require "lsp/#{lib}" - rescue LoadError - require File.expand_path(File.join(File.dirname(__FILE__), lib)) - end + require "lsp/#{lib}" +rescue LoadError + require File.expand_path(File.join(File.dirname(__FILE__), lib)) end diff --git a/lib/lsp/lsp_base.rb b/lib/lsp/lsp_base.rb index c36a817d..0034f4a2 100644 --- a/lib/lsp/lsp_base.rb +++ b/lib/lsp/lsp_base.rb @@ -27,8 +27,7 @@ def to_h value end - def from_h!(value) - end + def from_h!(value); end def to_json(*options) to_h.to_json(options) @@ -52,11 +51,11 @@ def to_typed_aray(val, expected_type) def self.create_range(from_line, from_char, to_line, to_char) { 'start' => { - 'line' => from_line, + 'line' => from_line, 'character' => from_char }, - 'end' => { - 'line' => to_line, + 'end' => { + 'line' => to_line, 'character' => to_char } } diff --git a/lib/lsp/lsp_enums.rb b/lib/lsp/lsp_enums.rb index d42716a9..5689925a 100644 --- a/lib/lsp/lsp_enums.rb +++ b/lib/lsp/lsp_enums.rb @@ -3,11 +3,6 @@ # DO NOT MODIFY. This file is built automatically # LSP Enumerations -# rubocop:disable Layout/EmptyLinesAroundClassBody -# rubocop:disable Lint/UselessAssignment -# rubocop:disable Style/AsciiComments -# rubocop:disable Naming/MethodName - module LSP module DiagnosticSeverity ERROR = 1 @@ -145,7 +140,4 @@ module CompletionTriggerKind end end -# rubocop:enable Layout/EmptyLinesAroundClassBody -# rubocop:enable Lint/UselessAssignment # rubocop:enable Style/AsciiComments -# rubocop:enable Naming/MethodName diff --git a/lib/lsp/lsp_protocol.rb b/lib/lsp/lsp_protocol.rb index 4792f911..0986a662 100644 --- a/lib/lsp/lsp_protocol.rb +++ b/lib/lsp/lsp_protocol.rb @@ -5,7 +5,6 @@ # rubocop:disable Layout/EmptyLinesAroundClassBody # rubocop:disable Lint/UselessAssignment -# rubocop:disable Style/AsciiComments # rubocop:disable Naming/MethodName module LSP diff --git a/lib/lsp/lsp_protocol_callhierarchy.proposed.rb b/lib/lsp/lsp_protocol_callhierarchy.proposed.rb index d49dec40..2bef8c73 100644 --- a/lib/lsp/lsp_protocol_callhierarchy.proposed.rb +++ b/lib/lsp/lsp_protocol_callhierarchy.proposed.rb @@ -5,7 +5,6 @@ # rubocop:disable Layout/EmptyLinesAroundClassBody # rubocop:disable Lint/UselessAssignment -# rubocop:disable Style/AsciiComments # rubocop:disable Naming/MethodName module LSP diff --git a/lib/lsp/lsp_protocol_colorprovider.rb b/lib/lsp/lsp_protocol_colorprovider.rb index ffd81d53..f6e9f87b 100644 --- a/lib/lsp/lsp_protocol_colorprovider.rb +++ b/lib/lsp/lsp_protocol_colorprovider.rb @@ -5,7 +5,6 @@ # rubocop:disable Layout/EmptyLinesAroundClassBody # rubocop:disable Lint/UselessAssignment -# rubocop:disable Style/AsciiComments # rubocop:disable Naming/MethodName module LSP diff --git a/lib/lsp/lsp_protocol_configuration.rb b/lib/lsp/lsp_protocol_configuration.rb index b1e6c625..d2867670 100644 --- a/lib/lsp/lsp_protocol_configuration.rb +++ b/lib/lsp/lsp_protocol_configuration.rb @@ -3,9 +3,6 @@ # DO NOT MODIFY. This file is built automatically # LSP Protocol: vscode-languageserver-protocol/lib/protocol.configuration.d.ts -# rubocop:disable Layout/EmptyLinesAroundClassBody -# rubocop:disable Lint/UselessAssignment -# rubocop:disable Style/AsciiComments # rubocop:disable Naming/MethodName module LSP @@ -81,7 +78,5 @@ def from_h!(value) end end -# rubocop:enable Layout/EmptyLinesAroundClassBody -# rubocop:enable Lint/UselessAssignment # rubocop:enable Style/AsciiComments # rubocop:enable Naming/MethodName diff --git a/lib/lsp/lsp_protocol_declaration.rb b/lib/lsp/lsp_protocol_declaration.rb index d8793f52..1d46963c 100644 --- a/lib/lsp/lsp_protocol_declaration.rb +++ b/lib/lsp/lsp_protocol_declaration.rb @@ -5,7 +5,6 @@ # rubocop:disable Layout/EmptyLinesAroundClassBody # rubocop:disable Lint/UselessAssignment -# rubocop:disable Style/AsciiComments # rubocop:disable Naming/MethodName module LSP diff --git a/lib/lsp/lsp_protocol_foldingrange.rb b/lib/lsp/lsp_protocol_foldingrange.rb index b58ca6c0..d42dae27 100644 --- a/lib/lsp/lsp_protocol_foldingrange.rb +++ b/lib/lsp/lsp_protocol_foldingrange.rb @@ -5,7 +5,6 @@ # rubocop:disable Layout/EmptyLinesAroundClassBody # rubocop:disable Lint/UselessAssignment -# rubocop:disable Style/AsciiComments # rubocop:disable Naming/MethodName module LSP diff --git a/lib/lsp/lsp_protocol_implementation.rb b/lib/lsp/lsp_protocol_implementation.rb index 9ea1f210..2abba8e6 100644 --- a/lib/lsp/lsp_protocol_implementation.rb +++ b/lib/lsp/lsp_protocol_implementation.rb @@ -5,7 +5,6 @@ # rubocop:disable Layout/EmptyLinesAroundClassBody # rubocop:disable Lint/UselessAssignment -# rubocop:disable Style/AsciiComments # rubocop:disable Naming/MethodName module LSP diff --git a/lib/lsp/lsp_protocol_progress.rb b/lib/lsp/lsp_protocol_progress.rb index ed9fe40f..52990b54 100644 --- a/lib/lsp/lsp_protocol_progress.rb +++ b/lib/lsp/lsp_protocol_progress.rb @@ -3,11 +3,6 @@ # DO NOT MODIFY. This file is built automatically # LSP Protocol: vscode-languageserver-protocol/lib/protocol.progress.d.ts -# rubocop:disable Layout/EmptyLinesAroundClassBody -# rubocop:disable Lint/UselessAssignment -# rubocop:disable Style/AsciiComments -# rubocop:disable Naming/MethodName - module LSP # export interface WorkDoneProgressClientCapabilities { # /** @@ -202,7 +197,4 @@ def from_h!(value) end end -# rubocop:enable Layout/EmptyLinesAroundClassBody -# rubocop:enable Lint/UselessAssignment # rubocop:enable Style/AsciiComments -# rubocop:enable Naming/MethodName diff --git a/lib/lsp/lsp_protocol_selectionrange.rb b/lib/lsp/lsp_protocol_selectionrange.rb index 864af74a..b752b06b 100644 --- a/lib/lsp/lsp_protocol_selectionrange.rb +++ b/lib/lsp/lsp_protocol_selectionrange.rb @@ -5,7 +5,6 @@ # rubocop:disable Layout/EmptyLinesAroundClassBody # rubocop:disable Lint/UselessAssignment -# rubocop:disable Style/AsciiComments # rubocop:disable Naming/MethodName module LSP diff --git a/lib/lsp/lsp_protocol_sematictokens.proposed.rb b/lib/lsp/lsp_protocol_sematictokens.proposed.rb index 8c3fcee5..2349d9b4 100644 --- a/lib/lsp/lsp_protocol_sematictokens.proposed.rb +++ b/lib/lsp/lsp_protocol_sematictokens.proposed.rb @@ -3,9 +3,6 @@ # DO NOT MODIFY. This file is built automatically # LSP Protocol: vscode-languageserver-protocol/lib/protocol.sematicTokens.proposed.d.ts -# rubocop:disable Layout/EmptyLinesAroundClassBody -# rubocop:disable Lint/UselessAssignment -# rubocop:disable Style/AsciiComments # rubocop:disable Naming/MethodName module LSP @@ -339,7 +336,5 @@ def from_h!(value) end end -# rubocop:enable Layout/EmptyLinesAroundClassBody -# rubocop:enable Lint/UselessAssignment # rubocop:enable Style/AsciiComments # rubocop:enable Naming/MethodName diff --git a/lib/lsp/lsp_protocol_typedefinition.rb b/lib/lsp/lsp_protocol_typedefinition.rb index 4a9e082f..8dcdab91 100644 --- a/lib/lsp/lsp_protocol_typedefinition.rb +++ b/lib/lsp/lsp_protocol_typedefinition.rb @@ -5,7 +5,6 @@ # rubocop:disable Layout/EmptyLinesAroundClassBody # rubocop:disable Lint/UselessAssignment -# rubocop:disable Style/AsciiComments # rubocop:disable Naming/MethodName module LSP diff --git a/lib/lsp/lsp_protocol_workspacefolders.rb b/lib/lsp/lsp_protocol_workspacefolders.rb index fbc23b7b..168deedd 100644 --- a/lib/lsp/lsp_protocol_workspacefolders.rb +++ b/lib/lsp/lsp_protocol_workspacefolders.rb @@ -3,9 +3,6 @@ # DO NOT MODIFY. This file is built automatically # LSP Protocol: vscode-languageserver-protocol/lib/protocol.workspaceFolders.d.ts -# rubocop:disable Layout/EmptyLinesAroundClassBody -# rubocop:disable Lint/UselessAssignment -# rubocop:disable Style/AsciiComments # rubocop:disable Naming/MethodName module LSP @@ -173,7 +170,5 @@ def from_h!(value) end end -# rubocop:enable Layout/EmptyLinesAroundClassBody -# rubocop:enable Lint/UselessAssignment # rubocop:enable Style/AsciiComments # rubocop:enable Naming/MethodName diff --git a/lib/lsp/lsp_types.rb b/lib/lsp/lsp_types.rb index 4e96f4ee..7ca5aac3 100644 --- a/lib/lsp/lsp_types.rb +++ b/lib/lsp/lsp_types.rb @@ -5,7 +5,6 @@ # rubocop:disable Layout/EmptyLinesAroundClassBody # rubocop:disable Lint/UselessAssignment -# rubocop:disable Style/AsciiComments # rubocop:disable Naming/MethodName module LSP diff --git a/lib/puppet-debugserver/debug_session/break_points.rb b/lib/puppet-debugserver/debug_session/break_points.rb index 9c57d136..e924d5b3 100644 --- a/lib/puppet-debugserver/debug_session/break_points.rb +++ b/lib/puppet-debugserver/debug_session/break_points.rb @@ -29,7 +29,7 @@ def process_set_breakpoints_request!(arguments) begin # TODO: This could be slow on big files.... - IO.foreach(file_path, :mode => 'rb', :encoding => 'UTF-8').each_with_index do |item, index| + IO.foreach(file_path, mode: 'rb', encoding: 'UTF-8').each_with_index do |item, index| # index here zero-based whereas we want one-based indexing file_contents[index + 1] = item if line_list.include?(index + 1) end @@ -44,7 +44,7 @@ def process_set_breakpoints_request!(arguments) break_points = arguments.breakpoints.map do DSP::Breakpoint.new.from_h!( 'verified' => false, - 'source' => arguments.source.to_h + 'source' => arguments.source.to_h ) end @@ -103,6 +103,7 @@ def process_set_function_breakpoints_request!(arguments) # @return [Array] All of the line breakpoints. Returns empty array if there no breakpoints. def line_breakpoints(file_path) return [] if @source_breakpoints[canonical_file_path(file_path)].nil? + @source_breakpoints[canonical_file_path(file_path)].map(&:line) end diff --git a/lib/puppet-debugserver/debug_session/flow_control.rb b/lib/puppet-debugserver/debug_session/flow_control.rb index 93a998b1..22a9a8f5 100644 --- a/lib/puppet-debugserver/debug_session/flow_control.rb +++ b/lib/puppet-debugserver/debug_session/flow_control.rb @@ -15,13 +15,13 @@ def initialize(debug_session) @flag_mutex = Mutex.new @flags = { - :start_puppet => false, - :puppet_started => false, - :session_paused => false, - :client_completed_configuration => false, - :session_setup => false, - :terminate => false, - :suppress_log_messages => false + start_puppet: false, + puppet_started: false, + session_paused: false, + client_completed_configuration: false, + session_setup: false, + terminate: false, + suppress_log_messages: false } @run_mode = PuppetDebugServer::DebugSession::PuppetSessionRunMode.new @@ -75,6 +75,7 @@ def assert_flag(flag_name) # @param flag_name [Symbol] The name of the flag def unassert_flag(flag_name) return if flag_name == :terminate # Can never unset the terminate flag + @flag_mutex.synchronize do @flags[flag_name] = false PuppetDebugServer.log_message(:debug, "Unasserting flag #{flag_name} is true") @@ -119,8 +120,8 @@ def raise_stopped_event_and_wait(reason, description, text, session_state) @debug_session.send_stopped_event( reason, 'description' => description, - 'text' => text, - 'threadId' => @debug_session.puppet_thread_id + 'text' => text, + 'threadId' => @debug_session.puppet_thread_id ) # Spin-wait for the session to be unpaused... diff --git a/lib/puppet-debugserver/debug_session/hook_handlers.rb b/lib/puppet-debugserver/debug_session/hook_handlers.rb index a07b537f..61c51d1c 100644 --- a/lib/puppet-debugserver/debug_session/hook_handlers.rb +++ b/lib/puppet-debugserver/debug_session/hook_handlers.rb @@ -43,7 +43,7 @@ def on_hook_after_parser_function_reset(args) # This mimics the break function from puppet-debugger # https://github.com/nwops/puppet-debug#usage - func_object.newfunction(:'debug::break', :type => :rvalue, :arity => -1, :doc => 'Breakpoint Function') do |arguments| + func_object.newfunction(:'debug::break', type: :rvalue, arity: -1, doc: 'Breakpoint Function') do |arguments| # This function is just a place holder. It gets interpretted at the # pops_evaluate hooks but the function itself still needs to exist though. end @@ -69,7 +69,7 @@ def on_hook_before_apply_exit(args) @debug_session.send_exited_event(option) @debug_session.send_output_event( 'category' => 'console', - 'output' => "puppet exited with #{option}" + 'output' => "puppet exited with #{option}" ) @debug_session.flow_control.unassert_flag(:puppet_started) @@ -89,6 +89,7 @@ def on_hook_before_compile(args) # Spin-wait for the configurationDone message from the client before we continue compilation return if @debug_session.flow_control.flag?(:client_completed_configuration) + sleep(0.5) until @debug_session.flow_control.flag?(:client_completed_configuration) end @@ -105,12 +106,14 @@ def on_hook_before_pops_evaluate(args) target = args[1] # Ignore this if there is no positioning information available return unless target.is_a?(Puppet::Pops::Model::Positioned) + target_loc = @debug_session.get_location_from_pops_object(target) # Even if it's positioned, it can still contain invalid information. Ignore it if # it's missing required information. This can happen when evaluting strings (e.g. watches from VSCode) # i.e. not a file on disk return if target_loc.file.nil? || target_loc.file.empty? + target_classname = @debug_session.get_puppet_class_name(target) ast_classname = get_ast_class_name(target) @@ -183,8 +186,8 @@ def on_hook_exception(args) 'exception', 'Compilation Exception', error_detail.basic_message, - :session_exception => error_detail, - :puppet_stacktrace => Puppet::Pops::PuppetStack.stacktrace_from_backtrace(error_detail) + session_exception: error_detail, + puppet_stacktrace: Puppet::Pops::PuppetStack.stacktrace_from_backtrace(error_detail) ) end @@ -215,7 +218,7 @@ def on_hook_log_message(args) @debug_session.send_output_event( 'category' => category, - 'output' => "#{level}: #{str}\n" + 'output' => "#{level}: #{str}\n" ) end @@ -239,6 +242,7 @@ def on_hook_step_breakpoint(args) def process_breakpoint_hook(reason, args) # If the debug session is paused no need to process return if @debug_session.flow_control.session_paused? + break_display_text = args[0] # TODO: REALLY don't like all this magic array stuff. Real Object? Hash? break_description = args[1] @@ -267,10 +271,10 @@ def process_breakpoint_hook(reason, args) reason, break_display_text, break_description, - :pops_target => pops_target_object, - :scope => scope_object, - :pops_depth_level => pops_depth_level, - :puppet_stacktrace => stack_trace + pops_target: pops_target_object, + scope: scope_object, + pops_depth_level: pops_depth_level, + puppet_stacktrace: stack_trace ) end @@ -282,6 +286,7 @@ def process_breakpoint_hook(reason, args) def get_ast_class_name(obj) # Puppet 5 has PCore Types return obj._pcore_type.name if obj.respond_to?(:_pcore_type) + # .. otherwise revert to Pops classname obj.class.to_s end diff --git a/lib/puppet-debugserver/debug_session/puppet_session_run_mode.rb b/lib/puppet-debugserver/debug_session/puppet_session_run_mode.rb index cf111209..63573ee0 100644 --- a/lib/puppet-debugserver/debug_session/puppet_session_run_mode.rb +++ b/lib/puppet-debugserver/debug_session/puppet_session_run_mode.rb @@ -17,6 +17,7 @@ class PuppetSessionRunMode # @param options See options def initialize(mode = :run, options = {}) raise "Invalid mode #{mode}" unless %i[run stepin next stepout].include?(mode) + @mode = mode @options = options @@ -37,7 +38,7 @@ def next!(pops_depth_level) @run_mode_mutex.synchronize do @mode = :next @options = { - :pops_depth_level => pops_depth_level + pops_depth_level: pops_depth_level } end end @@ -56,7 +57,7 @@ def step_out!(pops_depth_level) @run_mode_mutex.synchronize do @mode = :stepout @options = { - :pops_depth_level => pops_depth_level + pops_depth_level: pops_depth_level } end end diff --git a/lib/puppet-debugserver/hooks.rb b/lib/puppet-debugserver/hooks.rb index ac316d7c..76586d2e 100644 --- a/lib/puppet-debugserver/hooks.rb +++ b/lib/puppet-debugserver/hooks.rb @@ -60,12 +60,10 @@ def add_hook(event_name, hook_name, callable = nil, &block) def exec_hook(event_name, *args, &block) PuppetDebugServer.log_message(:debug, "Starting to execute hook #{event_name}") unless event_name == :hook_log_message @hooks[event_name.to_s].map do |_hook_name, callable| - begin - callable.call(*args, &block) - rescue ::RuntimeError => e - errors << e - e - end + callable.call(*args, &block) + rescue ::RuntimeError => e + errors << e + e end.last PuppetDebugServer.log_message(:debug, "Finished executing hook #{event_name}") unless event_name == :hook_log_message end @@ -91,7 +89,7 @@ def get_hook(event_name, hook_name) # @note Modifying the returned hash does not alter the hooks, use # `add_hook`/`delete_hook` for that. def get_hooks(event_name) - Hash[@hooks[event_name.to_s]] + (@hooks[event_name.to_s]).to_h end # @param [Symbol] event_name The name of the event. diff --git a/lib/puppet-debugserver/message_handler.rb b/lib/puppet-debugserver/message_handler.rb index c36a69f2..8e7bd3db 100644 --- a/lib/puppet-debugserver/message_handler.rb +++ b/lib/puppet-debugserver/message_handler.rb @@ -74,6 +74,7 @@ def request_evaluate(_connection_id, request_message) PuppetDebugServer.log_message(:debug, 'Received evaluate request.') debug_session = PuppetDebugServer::PuppetDebugSession.instance return PuppetEditorServices::Protocol::DebugAdapterMessages.reply_error(request_message) unless debug_session.flow_control.session_active? + obj = DSP::EvaluateRequest.new(request_message.to_h) begin PuppetEditorServices::Protocol::DebugAdapterMessages.reply_success( @@ -164,6 +165,7 @@ def request_next(_connection_id, request_message) debug_session = PuppetDebugServer::PuppetDebugSession.instance obj = DSP::NextRequest.new(request_message.to_h) return PuppetEditorServices::Protocol::DebugAdapterMessages.reply_error(request_message) if debug_session.puppet_thread_id.nil? || debug_session.puppet_thread_id != obj.arguments.threadId + # Stepout the debug session debug_session.flow_control.next! PuppetEditorServices::Protocol::DebugAdapterMessages.reply_success(request_message) @@ -173,6 +175,7 @@ def request_scopes(_connection_id, request_message) PuppetDebugServer.log_message(:debug, 'Received scopes request.') debug_session = PuppetDebugServer::PuppetDebugSession.instance return PuppetEditorServices::Protocol::DebugAdapterMessages.reply_error(request_message) unless debug_session.flow_control.session_active? + obj = DSP::ScopesRequest.new(request_message.to_h) PuppetEditorServices::Protocol::DebugAdapterMessages.reply_success( @@ -229,6 +232,7 @@ def request_stepin(_connection_id, request_message) debug_session = PuppetDebugServer::PuppetDebugSession.instance obj = DSP::StepInRequest.new(request_message.to_h) return PuppetEditorServices::Protocol::DebugAdapterMessages.reply_error(request_message) if debug_session.puppet_thread_id.nil? || debug_session.puppet_thread_id != obj.arguments.threadId + # Stepin the debug session debug_session.flow_control.step_in! PuppetEditorServices::Protocol::DebugAdapterMessages.reply_success(request_message) @@ -239,6 +243,7 @@ def request_stepout(_connection_id, request_message) debug_session = PuppetDebugServer::PuppetDebugSession.instance obj = DSP::StepOutRequest.new(request_message.to_h) return PuppetEditorServices::Protocol::DebugAdapterMessages.reply_error(request_message) if debug_session.puppet_thread_id.nil? || debug_session.puppet_thread_id != obj.arguments.threadId + # Stepout the debug session debug_session.flow_control.step_out! PuppetEditorServices::Protocol::DebugAdapterMessages.reply_success(request_message) @@ -260,6 +265,7 @@ def request_variables(_connection_id, request_message) PuppetDebugServer.log_message(:debug, 'Received variables request.') debug_session = PuppetDebugServer::PuppetDebugSession.instance return PuppetEditorServices::Protocol::DebugAdapterMessages.reply_error(request_message) unless debug_session.flow_control.session_active? + obj = DSP::VariablesRequest.new(request_message.to_h) PuppetEditorServices::Protocol::DebugAdapterMessages.reply_success( diff --git a/lib/puppet-debugserver/puppet_debug_session.rb b/lib/puppet-debugserver/puppet_debug_session.rb index f29617b4..e9655b64 100644 --- a/lib/puppet-debugserver/puppet_debug_session.rb +++ b/lib/puppet-debugserver/puppet_debug_session.rb @@ -42,7 +42,8 @@ class PuppetDebugSession # Creates a debug session def self.instance # This can be called from any thread - return @@session_instance unless @@session_instance.nil? # rubocop:disable Style/ClassVars This class method (not instance) should be inherited + return @@session_instance unless @@session_instance.nil? # This class method (not instance) should be inherited + @@session_instance = PuppetDebugSession.new # rubocop:disable Style/ClassVars This class method (not instance) should be inherited end @@ -134,7 +135,7 @@ def run_puppet send_output_event( 'category' => 'console', - 'output' => "puppet #{cmd_args.join(' ')}\n" + 'output' => "puppet #{cmd_args.join(' ')}\n" ) send_thread_event('started', @puppet_thread_id) @@ -153,9 +154,9 @@ def generate_stackframe_list target = state.pops_target frame = DSP::StackFrame.new.from_h!( - 'id' => stack_frames.count, - 'name' => get_puppet_class_name(target), - 'line' => 0, + 'id' => stack_frames.count, + 'name' => get_puppet_class_name(target), + 'line' => 0, 'column' => 0 ) @@ -181,9 +182,9 @@ def generate_stackframe_list unless state.exception.nil? err = state.exception frame = DSP::StackFrame.new.from_h!( - 'id' => stack_frames.count, - 'name' => err.class.to_s, - 'line' => 0, + 'id' => stack_frames.count, + 'name' => err.class.to_s, + 'line' => 0, 'column' => 0 ) @@ -205,10 +206,10 @@ def generate_stackframe_list source_line = pup_stack[1] frame = DSP::StackFrame.new.from_h!( - 'id' => stack_frames.count, - 'name' => source_file.to_s, + 'id' => stack_frames.count, + 'name' => source_file.to_s, 'source' => { 'path' => source_file }, - 'line' => source_line, + 'line' => source_line, 'column' => 0 ) stack_frames << frame @@ -227,25 +228,22 @@ def generate_scopes_list(frame_id) result = [] - this_scope = puppet_session_state.saved.scope - # rubocop:disable Lint/Void Go home rubocop, you're drunk. + this_scope = puppet_session_state.saved.scope # Go home rubocop, you're drunk. until this_scope.nil? || this_scope.is_topscope? result << DSP::Scope.new.from_h!( - 'name' => this_scope.to_s, + 'name' => this_scope.to_s, 'variablesReference' => this_scope.object_id, - 'namedVariables' => this_scope.to_hash(false).count, - 'expensive' => false + 'namedVariables' => this_scope.to_hash(false).count, + 'expensive' => false ) this_scope = this_scope.parent end - # rubocop:enable Lint/Void - unless puppet_session_state.actual.compiler.nil? result << DSP::Scope.new.from_h!( - 'name' => puppet_session_state.actual.compiler.topscope.to_s, + 'name' => puppet_session_state.actual.compiler.topscope.to_s, 'variablesReference' => VARIABLES_REFERENCE_TOP_SCOPE, - 'namedVariables' => puppet_session_state.actual.compiler.topscope.to_hash(false).count, - 'expensive' => false + 'namedVariables' => puppet_session_state.actual.compiler.topscope.to_hash(false).count, + 'expensive' => false ) end result @@ -354,6 +352,7 @@ def force_terminate def get_puppet_class_name(obj) # Puppet 5+ has PCore Types return obj._pcore_type.simple_name if obj.respond_to?(:_pcore_type) + # .. otherwise revert to simple naive text splitting # e.g. Puppet::Pops::Model::CallNamedFunctionExpression becomes CallNamedFunctionExpression obj.class.to_s.split('::').last @@ -481,8 +480,8 @@ def variable_from_ruby_object(name, value) end DSP::Variable.new.from_h!( - 'name' => name, - 'value' => out_value, + 'name' => name, + 'value' => out_value, 'variablesReference' => var_ref ) end @@ -524,12 +523,14 @@ def initialize(hook_manager) # Start aggregating log messages def start! return if @started + @hook_manager.add_hook(:hook_log_message, @hook_id) { |args| on_hook_log_message(args) } end # Stop aggregating log messages def stop! return unless @started + @hook_manager.delete_hook(:hook_log_message, @hook_id) end diff --git a/lib/puppet-debugserver/puppet_monkey_patches.rb b/lib/puppet-debugserver/puppet_monkey_patches.rb index 7cf6c69a..0e7986e2 100644 --- a/lib/puppet-debugserver/puppet_monkey_patches.rb +++ b/lib/puppet-debugserver/puppet_monkey_patches.rb @@ -25,7 +25,7 @@ def exit(option) module Puppet module Parser class Compiler - alias_method :original_compile, :compile + alias original_compile compile def compile PuppetDebugServer::PuppetDebugSession.instance.execute_hook(:hook_before_compile, [self]) @@ -36,6 +36,7 @@ def compile # TODO: Potential issue here with 4.10.x not implementing .file on the Positioned class # Just re-raise if there is no Puppet manifest file associated with the error raise if e.file.nil? || e.line.nil? || e.pos.nil? + PuppetDebugServer::PuppetDebugSession.instance.execute_hook(:hook_exception, [e]) raise end @@ -49,7 +50,7 @@ module Puppet module Pops module Evaluator class EvaluatorImpl - alias_method :original_evaluate, :evaluate + alias original_evaluate evaluate def evaluate(target, scope) PuppetDebugServer::PuppetDebugSession.instance.execute_hook(:hook_before_pops_evaluate, [self, target, scope]) @@ -95,7 +96,7 @@ module Puppet module Parser module Functions class << self - alias_method :original_reset, :reset + alias original_reset reset def reset result = original_reset diff --git a/lib/puppet-languageserver-sidecar/cache/filesystem.rb b/lib/puppet-languageserver-sidecar/cache/filesystem.rb index be926586..ba3ac5ba 100644 --- a/lib/puppet-languageserver-sidecar/cache/filesystem.rb +++ b/lib/puppet-languageserver-sidecar/cache/filesystem.rb @@ -26,6 +26,7 @@ def active? def load(absolute_path, section) return nil unless active? + file_key = file_key(absolute_path, section) cache_file = File.join(cache_dir, cache_filename(file_key)) @@ -56,6 +57,7 @@ def load(absolute_path, section) def save(absolute_path, section, content_string) return false unless active? + file_key = file_key(absolute_path, section) cache_file = File.join(cache_dir, cache_filename(file_key)) @@ -73,8 +75,9 @@ def save(absolute_path, section, content_string) def clear! return unless active? + PuppetLanguageServerSidecar.log_message(:warn, '[PuppetLanguageServerSidecar::Cache::FileSystem.clear] Filesystem based cache is being cleared') - FileUtils.rm(Dir.glob(File.join(cache_dir, '*')), :force => true) + FileUtils.rm(Dir.glob(File.join(cache_dir, '*')), force: true) end private @@ -88,11 +91,11 @@ def file_key(filepath, section) def read_file(filepath) return nil unless File.exist?(filepath) - File.open(filepath, 'rb') { |file| file.read } + File.binread(filepath) end def save_file(filepath, content) - File.open(filepath, 'wb') { |file| file.write(content) } + File.binwrite(filepath, content) true end diff --git a/lib/puppet-languageserver-sidecar/puppet_environment_monkey_patches.rb b/lib/puppet-languageserver-sidecar/puppet_environment_monkey_patches.rb index 56acb2a2..5b6df961 100644 --- a/lib/puppet-languageserver-sidecar/puppet_environment_monkey_patches.rb +++ b/lib/puppet-languageserver-sidecar/puppet_environment_monkey_patches.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true -module Puppet::Environments # rubocop:disable Style/ClassAndModuleChildren +module Puppet::Environments class Directories # Monkey patch the environment loader. When it attempts to load the special sidecar # environment, create a new Puppet::Node::Environment object for the workspace - alias_method :original_get, :get + alias original_get get def get(name) if name.intern == PuppetLanguageServerSidecar::PuppetHelper::SIDECAR_PUPPET_ENVIRONMENT.intern env_symbol = name.intern @@ -24,7 +24,7 @@ def get(name) # Monkey patch the environment loader. When it attempts to load the special sidecar # environment.conf file, create a new Puppet::Settings::EnvironmentConf object # from the workspace. - alias_method :original_get_conf, :get_conf + alias original_get_conf get_conf def get_conf(name) if name.intern == PuppetLanguageServerSidecar::PuppetHelper::SIDECAR_PUPPET_ENVIRONMENT.intern conf = Puppet::Settings::EnvironmentConf.load_from(PuppetLanguageServerSidecar::Workspace.root_path, @global_module_path) @@ -45,7 +45,7 @@ def get_conf(name) # Monkey patch the environment. Normally it's not possible to modify environment settings. # Add a method to get the underlying environment settings which can be used to modify # settings on the fly. -class Puppet::Settings::EnvironmentConf # rubocop:disable Style/ClassAndModuleChildren +class Puppet::Settings::EnvironmentConf def get_raw_setting(setting_name) section.setting(setting_name) if section end diff --git a/lib/puppet-languageserver-sidecar/puppet_helper.rb b/lib/puppet-languageserver-sidecar/puppet_helper.rb index 2b435034..edd62df4 100644 --- a/lib/puppet-languageserver-sidecar/puppet_helper.rb +++ b/lib/puppet-languageserver-sidecar/puppet_helper.rb @@ -16,12 +16,13 @@ module PuppetHelper # Resource Face def self.get_puppet_resource(typename, title = nil) result = PuppetLanguageServer::Sidecar::Protocol::PuppetClassList.new - if title.nil? - resources = Puppet::Face[:resource, '0.0.1'].search(typename) - else - resources = Puppet::Face[:resource, '0.0.1'].find("#{typename}/#{title}") - end + resources = if title.nil? + Puppet::Face[:resource, '0.0.1'].search(typename) + else + Puppet::Face[:resource, '0.0.1'].find("#{typename}/#{title}") + end return result if resources.nil? + resources = [resources] unless resources.is_a?(Array) prune_resource_parameters(resources).each do |item| obj = PuppetLanguageServer::Sidecar::Protocol::Resource.new @@ -53,6 +54,7 @@ def self.retrieve_default_data_types next if IGNORE_DATATYPE_NAMES.include?(thing.simple_name) # Don't need duplicates next if name_list.include?(thing.simple_name) + name_list << thing.simple_name obj = PuppetLanguageServer::Sidecar::Protocol::PuppetDataType.new @@ -102,10 +104,10 @@ def self.retrieve_via_puppet_strings(cache, options = {}) if object_types.include?(:function) # rubocop:disable Style/IfUnlessModifier This reads better file_doc.functions.each { |item| result.append!(item) } end - if object_types.include?(:type) - file_doc.types.each do |item| - result.append!(item) unless name == 'whit' || name == 'component' # rubocop:disable Style/MultipleComparison - end + next unless object_types.include?(:type) + + file_doc.types.each do |item| + result.append!(item) unless name == 'whit' || name == 'component' end end @@ -189,13 +191,16 @@ def find(from_root_path = nil) search_paths.each do |search_root| PuppetLanguageServerSidecar.log_message(:debug, "[PuppetPathFinder] Potential search root '#{search_root}'") next if search_root.nil? + # We need absolute paths from here on in. search_root = File.expand_path(search_root) next unless path_in_root?(from_root_path, search_root) && Dir.exist?(search_root) + PuppetLanguageServerSidecar.log_message(:debug, "[PuppetPathFinder] Using '#{search_root}' as a directory to search") all_object_info.each do |object_type, paths_to_search| next unless object_types.include?(object_type) + # TODO: next unless object_type is included paths_to_search.each do |path_info| path = File.join(search_root, path_info[:relative_dir]) @@ -240,19 +245,19 @@ def path_in_root?(root, path) # @return [Hash[Symbol => Hash[Symbol => String]]] def all_object_info { - :class => [ + class: [ { relative_dir: 'manifests', glob: '/**/*.pp' } # Pretty much everything in most modules ], - :datatype => [ + datatype: [ { relative_dir: 'lib/puppet/datatypes', glob: '/**/*.rb' }, # Custom Data Types { relative_dir: 'types', glob: '/**/*.pp' } # Data Type aliases ], - :function => [ + function: [ { relative_dir: 'functions', glob: '/**/*.pp' }, # Contains custom functions written in the Puppet language. { relative_dir: 'lib/puppet/functions', glob: '/**/*.rb' }, # Contains functions written in Ruby for the modern Puppet::Functions API { relative_dir: 'lib/puppet/parser/functions', glob: '/**/*.rb' } # Contains functions written in Ruby for the legacy Puppet::Parser::Functions API ], - :type => [ + type: [ { relative_dir: 'lib/puppet/type', glob: '/*.rb' } # Contains Puppet resource types. We don't care about providers. Types cannot exist in subdirs ] } diff --git a/lib/puppet-languageserver-sidecar/puppet_modulepath_monkey_patches.rb b/lib/puppet-languageserver-sidecar/puppet_modulepath_monkey_patches.rb index 723636a5..4d5e9b65 100644 --- a/lib/puppet-languageserver-sidecar/puppet_modulepath_monkey_patches.rb +++ b/lib/puppet-languageserver-sidecar/puppet_modulepath_monkey_patches.rb @@ -6,10 +6,11 @@ module Puppet module Util class Autoload class << self - alias_method :original_module_directories, :module_directories + alias original_module_directories module_directories def module_directories(env) result = original_module_directories(env) return result unless PuppetLanguageServerSidecar::Workspace.has_module_metadata? + workspace_lib = File.join(PuppetLanguageServerSidecar::Workspace.root_path, 'lib') return result unless FileTest.directory?(workspace_lib) @@ -25,9 +26,9 @@ def module_directories(env) # Monkey patch the module loader and inject a workspace module # into the modules memoization variable require 'puppet/node/environment' -class Puppet::Node::Environment # rubocop:disable Style/ClassAndModuleChildren - alias_method :original_modules, :modules - alias_method :original_modules_by_path, :modules_by_path +class Puppet::Node::Environment + alias original_modules modules + alias original_modules_by_path modules_by_path # The Puppet::Util::Json class doesn't exist in all puppet version. Instead # just vendor the code here as it's a simple JSON loader only for metadata.json. @@ -55,8 +56,9 @@ def create_workspace_module_object(path) # Read the metadata to find the actual module name md_file = File.join(PuppetLanguageServerSidecar::Workspace.root_path, 'metadata.json') begin - metadata = workspace_load_json(File.read(md_file, :encoding => 'utf-8')) + metadata = workspace_load_json(File.read(md_file, encoding: 'utf-8')) return nil if metadata['name'].nil? + # Extract the actual module name if Puppet::Module.is_module_directory_name?(metadata['name']) module_name = metadata['name'] @@ -72,7 +74,8 @@ def create_workspace_module_object(path) # The Puppet::Module initializer was changed in # https://github.com/puppetlabs/puppet/commit/935c0311dbaf1df03937822525c36b26de5390ef # We need to switch the creation based on whether the modules_strict_semver? method is available - return Puppet::Module.new(module_name, path, self, modules_strict_semver?) if respond_to?('modules_strict_semver?') + return Puppet::Module.new(module_name, path, self, modules_strict_semver?) if respond_to?(:modules_strict_semver?) + Puppet::Module.new(module_name, path, self) rescue StandardError nil @@ -81,7 +84,7 @@ def create_workspace_module_object(path) def modules if @modules.nil? - original_modules # rubocop:disable Style/IdenticalConditionalBranches + original_modules if PuppetLanguageServerSidecar::Workspace.has_module_metadata? workspace_module = create_workspace_module_object(PuppetLanguageServerSidecar::Workspace.root_path) @modules << workspace_module unless workspace_module.nil? @@ -89,7 +92,7 @@ def modules @modules else - original_modules # rubocop:disable Style/IdenticalConditionalBranches + original_modules end end @@ -109,8 +112,8 @@ def modules_by_path # Inject the workspace as a module in all modulepaths require 'puppet/settings/environment_conf' -class Puppet::Settings::EnvironmentConf # rubocop:disable Style/ClassAndModuleChildren - alias_method :original_modulepath, :modulepath +class Puppet::Settings::EnvironmentConf + alias original_modulepath modulepath def modulepath result = original_modulepath @@ -125,9 +128,9 @@ def modulepath # Inject the workspace into the facter search paths require 'puppet/indirector/facts/facter' -class Puppet::Node::Facts::Facter # rubocop:disable Style/ClassAndModuleChildren +class Puppet::Node::Facts::Facter class << self - alias_method :original_setup_search_paths, :setup_search_paths + alias original_setup_search_paths setup_search_paths def setup_search_paths(request) result = original_setup_search_paths(request) return result unless PuppetLanguageServerSidecar::Workspace.has_module_metadata? @@ -136,6 +139,7 @@ def setup_search_paths(request) .select { |path| FileTest.directory?(path) } return result if additional_dirs.empty? + Facter.search(*additional_dirs) end end diff --git a/lib/puppet-languageserver-sidecar/puppet_strings_helper.rb b/lib/puppet-languageserver-sidecar/puppet_strings_helper.rb index 48e3be59..41b65620 100644 --- a/lib/puppet-languageserver-sidecar/puppet_strings_helper.rb +++ b/lib/puppet-languageserver-sidecar/puppet_strings_helper.rb @@ -12,6 +12,7 @@ def self.file_documentation(path, cache = nil) def self.require_puppet_strings return @puppet_strings_loaded unless @puppet_strings_loaded.nil? + begin require 'puppet-strings' require 'puppet-strings/yard' @@ -41,6 +42,7 @@ class Helper # @return [FileDocumentation, nil] Returns the documentation for the path, or nil if it cannot be extracted def file_documentation(path, cache = nil) return nil unless PuppetLanguageServerSidecar::PuppetStringsHelper.require_puppet_strings + @helper_cache = FileDocumentationCache.new if @helper_cache.nil? return @helper_cache.document(path) if @helper_cache.path_exists?(path) @@ -143,8 +145,8 @@ def populate_classes_from_yard_registry! item[:docstring][:tags].select { |tag| tag[:tag_name] == 'param' && tag.key?(:types) }.each do |tag| param_name = tag[:name] obj.parameters[param_name] = { - :doc => tag[:text], - :type => tag[:types]&.join(', ') + doc: tag[:text], + type: tag[:types]&.join(', ') } end end @@ -173,10 +175,10 @@ def populate_data_types_from_yard_registry! unless item[:docstring][:tags].nil? item[:docstring][:tags].select { |tag| tag[:tag_name] == 'param' }.each do |tag| obj.attributes << PuppetLanguageServer::Sidecar::Protocol::PuppetDataTypeAttribute.new.from_h!( - 'key' => tag[:name], + 'key' => tag[:name], 'default_value' => defaults[tag[:name]], - 'doc' => tag[:text], - 'types' => tag[:types].nil? ? nil : tag[:types].join(', ') + 'doc' => tag[:text], + 'types' => tag[:types].nil? ? nil : tag[:types].join(', ') ) end end @@ -236,9 +238,9 @@ def populate_functions_from_yard_registry! case tag[:tag_name] when 'param' sig.parameters << PuppetLanguageServer::Sidecar::Protocol::PuppetFunctionSignatureParameter.new.from_h!( - 'name' => tag[:name], + 'name' => tag[:name], 'types' => tag[:types], - 'doc' => tag[:text] + 'doc' => tag[:text] ) when 'return' sig.return_types = tag[:types] @@ -278,17 +280,17 @@ def populate_types_from_yard_registry! unless item[:properties].nil? item[:properties].each do |prop| obj.attributes[prop[:name]] = { - :type => :property, - :doc => prop[:description] + type: :property, + doc: prop[:description] } end end unless item[:parameters].nil? item[:parameters].each do |prop| obj.attributes[prop[:name]] = { - :type => :param, - :doc => prop[:description], - :isnamevar? => prop[:isnamevar] + type: :param, + doc: prop[:description], + isnamevar?: prop[:isnamevar] } end end @@ -306,7 +308,7 @@ def calculate_signature_parameter_locations!(sig) name = param.name.dup # Don't want to modify the original object # Munge the parameter name to what it appears in the signature key # Ref - https://github.com/puppetlabs/puppet-strings/blob/2987558bb3170bc37e6077aab1b60efb17161eff/lib/puppet-strings/yard/handlers/ruby/function_handler.rb#L293-L317 - if name.start_with?('*') || name.start_with?('&') + if name.start_with?('*', '&') name.insert(1, '$') else name = "$#{name}" @@ -352,11 +354,11 @@ def initialize(path = nil) # Serialisation def to_h { - 'path' => path, - 'classes' => classes, + 'path' => path, + 'classes' => classes, 'datatypes' => datatypes, 'functions' => functions, - 'types' => types + 'types' => types } end diff --git a/lib/puppet-languageserver-sidecar/workspace.rb b/lib/puppet-languageserver-sidecar/workspace.rb index cd094e12..18705f02 100644 --- a/lib/puppet-languageserver-sidecar/workspace.rb +++ b/lib/puppet-languageserver-sidecar/workspace.rb @@ -29,6 +29,7 @@ def self.has_environmentconf? # rubocop:disable Naming/PredicateName # root of the module/control repo actually is def self.find_root_path(path) return nil if path.nil? + filepath = File.expand_path(path) if dir_exist?(filepath) @@ -41,13 +42,14 @@ def self.find_root_path(path) until directory.nil? break if file_exist?(File.join(directory, 'metadata.json')) || file_exist?(File.join(directory, 'environment.conf')) + parent = File.dirname(directory) # If the parent is the same as the original, then we've reached the end of the path chain - if parent == directory - directory = nil - else - directory = parent - end + directory = if parent == directory + nil + else + parent + end end directory @@ -56,9 +58,9 @@ def self.find_root_path(path) def self.process_workspace(path) result = { - :root_path => nil, - :has_environmentconf => false, - :has_metadatajson => false + root_path: nil, + has_environmentconf: false, + has_metadatajson: false } return result if path.nil? diff --git a/lib/puppet-languageserver/client_session_state.rb b/lib/puppet-languageserver/client_session_state.rb index e4a9772c..ea57efc0 100644 --- a/lib/puppet-languageserver/client_session_state.rb +++ b/lib/puppet-languageserver/client_session_state.rb @@ -70,6 +70,7 @@ def load_static_data!(async = true) def load_workspace_data!(async = true) return true if documents.store_root_path.nil? + action_args = ['--local-workspace', documents.store_root_path] PuppetLanguageServer.log_message(:info, "Loading Workspace Data via aggregate #{'(Async)' if async}...") if async diff --git a/lib/puppet-languageserver/crash_dump.rb b/lib/puppet-languageserver/crash_dump.rb index 9d7df3dd..01468695 100644 --- a/lib/puppet-languageserver/crash_dump.rb +++ b/lib/puppet-languageserver/crash_dump.rb @@ -9,29 +9,26 @@ def self.default_crash_file def self.write_crash_file(err, session_state, filename = nil, additional = {}) # Create the crash text - puppet_version = Puppet.version rescue 'Unknown' # rubocop:disable Lint/RescueWithoutErrorClass, Style/RescueModifier - facter_version = Facter.version rescue 'Unknown' # rubocop:disable Lint/RescueWithoutErrorClass, Style/RescueModifier - languageserver_version = PuppetLanguageServer.version rescue 'Unknown' # rubocop:disable Lint/RescueWithoutErrorClass, Style/RescueModifier - - # rubocop:disable Layout/IndentHeredoc, Layout/ClosingHeredocIndentation, Style/FormatStringToken - crashtext = <<-TEXT -Puppet Language Server Crash File --=--=--=--=--=--=--=--=--=--=--=- -#{DateTime.now.strftime('%a %b %e %Y %H:%M:%S %Z')} -Puppet Version #{puppet_version} -Facter Version #{facter_version} -Ruby Version #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} -Language Server Version #{languageserver_version} - -Error: #{err} - -Backtrace ---------- -#{err.backtrace.join("\n")} - -TEXT - # rubocop:enable Layout/IndentHeredoc, Layout/ClosingHeredocIndentation, Style/FormatStringToken - + puppet_version = Puppet.version rescue 'Unknown' # rubocop:disable Style/RescueModifier + facter_version = Facter.version rescue 'Unknown' # rubocop:disable Style/RescueModifier + languageserver_version = PuppetLanguageServer.version rescue 'Unknown' # rubocop:disable Style/RescueModifier + + crashtext = <<~TEXT + Puppet Language Server Crash File + -=--=--=--=--=--=--=--=--=--=--=- + #{DateTime.now.strftime('%a %b %e %Y %H:%M:%S %Z')} + Puppet Version #{puppet_version} + Facter Version #{facter_version} + Ruby Version #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} + Language Server Version #{languageserver_version} + + Error: #{err} + + Backtrace + --------- + #{err.backtrace.join("\n")} + + TEXT # Append the documents in the cache session_state.documents.document_uris.each do |uri| crashtext += "Document - #{uri}\n---\n#{session_state.documents.document_content(uri)}\n\n" @@ -42,8 +39,8 @@ def self.write_crash_file(err, session_state, filename = nil, additional = {}) end crash_file = filename.nil? ? default_crash_file : filename - File.open(crash_file, 'wb') { |file| file.write(crashtext) } - rescue # rubocop:disable Style/RescueStandardError, Lint/SuppressedException + File.binwrite(crash_file, crashtext) + rescue # rubocop:disable Style/RescueStandardError # Swallow all errors. Errors in the error handler should not # terminate the application end diff --git a/lib/puppet-languageserver/epp/validation_provider.rb b/lib/puppet-languageserver/epp/validation_provider.rb index 04baf43a..1f77cd07 100644 --- a/lib/puppet-languageserver/epp/validation_provider.rb +++ b/lib/puppet-languageserver/epp/validation_provider.rb @@ -22,9 +22,9 @@ def self.validate(content, _max_problems = 100) unless ex_line.nil? || ex_pos.nil? || message.nil? result << LSP::Diagnostic.new('severity' => LSP::DiagnosticSeverity::ERROR, - 'range' => LSP.create_range(ex_line, ex_pos, ex_line, ex_pos + 1), - 'source' => 'Puppet', - 'message' => message) + 'range' => LSP.create_range(ex_line, ex_pos, ex_line, ex_pos + 1), + 'source' => 'Puppet', + 'message' => message) end end result diff --git a/lib/puppet-languageserver/global_queues/sidecar_queue.rb b/lib/puppet-languageserver/global_queues/sidecar_queue.rb index 95ee3778..13241a3b 100644 --- a/lib/puppet-languageserver/global_queues/sidecar_queue.rb +++ b/lib/puppet-languageserver/global_queues/sidecar_queue.rb @@ -34,6 +34,7 @@ def execute_job(job_object) super(job_object) connection = connection_from_connection_id(job_object.connection_id) raise "Connection is not available for connection id #{job_object.connection_id}" if connection.nil? + sidecar_path = File.expand_path(File.join(__dir__, '..', '..', '..', 'puppet-languageserver-sidecar')) args = ['--action', job_object.action].concat(job_object.additional_args).concat(sidecar_args_from_connection(connection)) cmd = ['ruby', sidecar_path].concat(args) @@ -45,8 +46,10 @@ def execute_job(job_object) # It's possible server has closed the connection while the sidecar is running. # So raise if the connection is no longer available raise "Connection is no longer available for connection id #{job_object.connection_id}" if connection_from_connection_id(job_object.connection_id).nil? + session_state = session_state_from_connection(connection) raise "Session state is not available for connection id #{job_object.connection_id}" if session_state.nil? + cache = session_state.object_cache # Correctly encode the result as UTF8 @@ -141,6 +144,7 @@ def execute_job(job_object) true rescue StandardError => e raise unless job_object.handle_errors + PuppetLanguageServer.log_message(:error, "SidecarQueue Thread: Error running action #{job_object.action}. #{e}\n#{e.backtrace}") nil end @@ -153,6 +157,7 @@ def connection_from_connection_id(connection_id) def session_state_from_connection(connection) return if connection.nil? + handler = connection.protocol.handler handler.respond_to?(:session_state) ? handler.session_state : nil end @@ -184,8 +189,10 @@ def run_sidecar(cmd) def sidecar_args_from_connection(connection) return nil if connection.nil? + options = connection.server.handler_options return [] if options.nil? + result = [] result << '--no-cache' if options[:disable_sidecar_cache] result << "--puppet-version=#{Puppet.version}" diff --git a/lib/puppet-languageserver/global_queues/single_instance_queue.rb b/lib/puppet-languageserver/global_queues/single_instance_queue.rb index 49d9fcb0..bddab7af 100644 --- a/lib/puppet-languageserver/global_queues/single_instance_queue.rb +++ b/lib/puppet-languageserver/global_queues/single_instance_queue.rb @@ -59,12 +59,10 @@ def enqueue_job(job_object) # Append a new thread if we have space if @queue_threads.count < max_queue_threads @queue_threads << Thread.new do - begin - thread_worker - rescue => e # rubocop:disable Style/RescueStandardError - PuppetLanguageServer.log_message(:error, "Error in #{self.class} Thread: #{e}") - raise - end + thread_worker + rescue => e # rubocop:disable Style/RescueStandardError + PuppetLanguageServer.log_message(:error, "Error in #{self.class} Thread: #{e}") + raise end end end @@ -108,6 +106,7 @@ def thread_worker loop do @queue_mutex.synchronize do return if @queue.empty? + work_item = @queue.shift end return if work_item.nil? diff --git a/lib/puppet-languageserver/global_queues/validation_queue.rb b/lib/puppet-languageserver/global_queues/validation_queue.rb index de48aca4..05c9d3b2 100644 --- a/lib/puppet-languageserver/global_queues/validation_queue.rb +++ b/lib/puppet-languageserver/global_queues/validation_queue.rb @@ -75,6 +75,7 @@ def execute_job(job_object) def session_state_from_connection_id(connection_id) connection = PuppetEditorServices::Server.current_server.connection(connection_id) return if connection.nil? + handler = connection.protocol.handler handler.respond_to?(:session_state) ? handler.session_state : nil end diff --git a/lib/puppet-languageserver/manifest/completion_provider.rb b/lib/puppet-languageserver/manifest/completion_provider.rb index e505b29f..9c246d76 100644 --- a/lib/puppet-languageserver/manifest/completion_provider.rb +++ b/lib/puppet-languageserver/manifest/completion_provider.rb @@ -5,18 +5,18 @@ module Manifest module CompletionProvider def self.complete(session_state, content, line_num, char_num, options = {}) options = { - :tasks_mode => false, - :context => nil # LSP::CompletionContext object + tasks_mode: false, + context: nil # LSP::CompletionContext object }.merge(options) items = [] incomplete = false is_trigger_char = !options[:context].nil? && options[: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 => options[:tasks_mode], - :remove_trigger_char => is_trigger_char) + multiple_attempts: true, + disallowed_classes: [Puppet::Pops::Model::QualifiedName, Puppet::Pops::Model::BlockExpression], + tasks_mode: options[:tasks_mode], + remove_trigger_char: is_trigger_char) if result.nil? # We are in the root of the document. @@ -75,12 +75,12 @@ def self.complete(session_state, content, line_num, char_num, options = {}) # 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, + 'label' => name.to_s, + 'kind' => LSP::CompletionItemKind::PROPERTY, 'detail' => 'Parameter', - 'data' => { - 'type' => 'resource_parameter', - 'param' => name.to_s, + 'data' => { + 'type' => 'resource_parameter', + 'param' => name.to_s, 'resource_type' => item_value } ) @@ -88,12 +88,12 @@ def self.complete(session_state, content, line_num, char_num, options = {}) # 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, + 'label' => name.to_s, + 'kind' => LSP::CompletionItemKind::PROPERTY, 'detail' => 'Property', - 'data' => { - 'type' => 'resource_property', - 'prop' => name.to_s, + 'data' => { + 'type' => 'resource_property', + 'prop' => name.to_s, 'resource_type' => item_value } ) @@ -107,12 +107,12 @@ def self.complete(session_state, content, line_num, char_num, options = {}) # Add Parameters item_object.parameters.each_key do |name| items << LSP::CompletionItem.new( - 'label' => name.to_s, - 'kind' => LSP::CompletionItemKind::PROPERTY, + 'label' => name.to_s, + 'kind' => LSP::CompletionItemKind::PROPERTY, 'detail' => 'Parameter', - 'data' => { - 'type' => 'resource_class_parameter', - 'param' => name.to_s, + 'data' => { + 'type' => 'resource_class_parameter', + 'param' => name.to_s, 'resource_type' => item_value } ) @@ -131,31 +131,31 @@ def self.complete(session_state, content, line_num, char_num, options = {}) def self.keywords(keywords = [], &block) keywords.each do |keyword| item = LSP::CompletionItem.new( - 'label' => keyword, - 'kind' => LSP::CompletionItemKind::KEYWORD, + 'label' => keyword, + 'kind' => LSP::CompletionItemKind::KEYWORD, 'detail' => 'Keyword', - 'data' => { + 'data' => { 'type' => 'keyword', 'name' => keyword } ) - block.call(item) if block + yield(item) if block end end def self.all_facts(session_state, &block) PuppetLanguageServer::FacterHelper.fact_names(session_state).each do |name| item = LSP::CompletionItem.new( - 'label' => name.to_s, + 'label' => name.to_s, 'insertText' => "'#{name}'", - 'kind' => LSP::CompletionItemKind::VARIABLE, - 'detail' => 'Fact', - 'data' => { + 'kind' => LSP::CompletionItemKind::VARIABLE, + 'detail' => 'Fact', + 'data' => { 'type' => 'variable_expr_fact', 'expr' => name } ) - block.call(item) if block + yield(item) if block end end @@ -163,39 +163,39 @@ 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, + 'label' => pup_type, + 'kind' => LSP::CompletionItemKind::MODULE, 'detail' => 'Resource', - 'data' => { + 'data' => { 'type' => 'resource_type', 'name' => pup_type } ) - block.call(item) if block + 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, + item = LSP::CompletionItem.new('label' => pup_class, + 'kind' => LSP::CompletionItemKind::MODULE, 'detail' => 'Resource', - 'data' => { 'type' => 'resource_class', - 'name' => pup_class }) - block.call(item) if block + 'data' => { 'type' => 'resource_class', + 'name' => pup_class }) + yield(item) if block end end 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, + 'label' => name.to_s, + 'kind' => LSP::CompletionItemKind::FUNCTION, 'detail' => 'Function', - 'data' => { + 'data' => { 'type' => 'function', 'name' => name.to_s } ) - block.call(item) if block + yield(item) if block end end # END Helpers @@ -229,7 +229,7 @@ def self.resolve(session_state, completion_item) 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 '\ + '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 @@ -245,6 +245,7 @@ def self.resolve(session_state, completion_item) # 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") @@ -285,6 +286,7 @@ def self.resolve(session_state, completion_item) 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? @@ -294,6 +296,7 @@ def self.resolve(session_state, completion_item) 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? @@ -310,6 +313,7 @@ def self.resolve(session_state, completion_item) 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 = '' diff --git a/lib/puppet-languageserver/manifest/definition_provider.rb b/lib/puppet-languageserver/manifest/definition_provider.rb index 8c98956a..0a98b957 100644 --- a/lib/puppet-languageserver/manifest/definition_provider.rb +++ b/lib/puppet-languageserver/manifest/definition_provider.rb @@ -5,11 +5,11 @@ module Manifest module DefinitionProvider def self.find_definition(session_state, content, line_num, char_num, options = {}) options = { - :tasks_mode => false + tasks_mode: false }.merge(options) result = PuppetLanguageServer::PuppetParserHelper.object_under_cursor(content, line_num, char_num, - :disallowed_classes => [Puppet::Pops::Model::BlockExpression], - :tasks_mode => options[:tasks_mode]) + disallowed_classes: [Puppet::Pops::Model::BlockExpression], + tasks_mode: options[:tasks_mode]) return nil if result.nil? path = result[:path] @@ -76,7 +76,7 @@ def self.type_or_class(session_state, resource_name) item = PuppetLanguageServer::PuppetHelper.get_class(session_state, resource_name) if item.nil? unless item.nil? return LSP::Location.new( - 'uri' => PuppetLanguageServer::UriHelper.build_file_uri(item.source), + 'uri' => PuppetLanguageServer::UriHelper.build_file_uri(item.source), 'range' => LSP.create_range(item.line, 0, item.line, 1024) ) end @@ -87,8 +87,9 @@ def self.type_or_class(session_state, resource_name) def self.function_name(session_state, func_name) item = PuppetLanguageServer::PuppetHelper.function(session_state, func_name) return nil if item.nil? || item.source.nil? || item.line.nil? + LSP::Location.new( - 'uri' => "file:///#{item.source}", + 'uri' => "file:///#{item.source}", 'range' => LSP.create_range(item.line, 0, item.line, 1024) ) end diff --git a/lib/puppet-languageserver/manifest/document_symbol_provider.rb b/lib/puppet-languageserver/manifest/document_symbol_provider.rb index 4fb1cd07..427c1fac 100644 --- a/lib/puppet-languageserver/manifest/document_symbol_provider.rb +++ b/lib/puppet-languageserver/manifest/document_symbol_provider.rb @@ -9,13 +9,14 @@ def self.workspace_symbols(query, object_cache) object_cache.all_objects do |key, item| key_string = key.to_s next unless query.empty? || key_string.include?(query) + case item when PuppetLanguageServer::Sidecar::Protocol::PuppetType result << LSP::SymbolInformation.new( - 'name' => key_string, - 'kind' => LSP::SymbolKind::METHOD, + 'name' => key_string, + 'kind' => LSP::SymbolKind::METHOD, 'location' => { - 'uri' => PuppetLanguageServer::UriHelper.build_file_uri(item.source), + 'uri' => PuppetLanguageServer::UriHelper.build_file_uri(item.source), # Don't have char pos for types so just pick extreme values 'range' => LSP.create_range(item.line, 0, item.line, 1024) } @@ -23,10 +24,10 @@ def self.workspace_symbols(query, object_cache) when PuppetLanguageServer::Sidecar::Protocol::PuppetFunction result << LSP::SymbolInformation.new( - 'name' => key_string, - 'kind' => LSP::SymbolKind::FUNCTION, + 'name' => key_string, + 'kind' => LSP::SymbolKind::FUNCTION, 'location' => { - 'uri' => PuppetLanguageServer::UriHelper.build_file_uri(item.source), + 'uri' => PuppetLanguageServer::UriHelper.build_file_uri(item.source), # Don't have char pos for functions so just pick extreme values 'range' => LSP.create_range(item.line, 0, item.line, 1024) } @@ -34,10 +35,10 @@ def self.workspace_symbols(query, object_cache) when PuppetLanguageServer::Sidecar::Protocol::PuppetClass result << LSP::SymbolInformation.new( - 'name' => key_string, - 'kind' => LSP::SymbolKind::CLASS, + 'name' => key_string, + 'kind' => LSP::SymbolKind::CLASS, 'location' => { - 'uri' => PuppetLanguageServer::UriHelper.build_file_uri(item.source), + 'uri' => PuppetLanguageServer::UriHelper.build_file_uri(item.source), # Don't have char pos for classes so just pick extreme values 'range' => LSP.create_range(item.line, 0, item.line, 1024) } @@ -45,10 +46,10 @@ def self.workspace_symbols(query, object_cache) when PuppetLanguageServer::Sidecar::Protocol::PuppetDataType result << LSP::SymbolInformation.new( - 'name' => key_string, - 'kind' => LSP::SymbolKind::NAMESPACE, + 'name' => key_string, + 'kind' => LSP::SymbolKind::NAMESPACE, 'location' => { - 'uri' => PuppetLanguageServer::UriHelper.build_file_uri(item.source), + 'uri' => PuppetLanguageServer::UriHelper.build_file_uri(item.source), # Don't have char pos for data types so just pick extreme values 'range' => LSP.create_range(item.line, 0, item.line, 1024) } @@ -66,7 +67,7 @@ def self.workspace_symbols(query, object_cache) def self.extract_document_symbols(content, options = {}) options = { - :tasks_mode => false + tasks_mode: false }.merge(options) parser = Puppet::Pops::Parser::Parser.new result = parser.singleton_parse_string(content, options[:tasks_mode], '') @@ -75,6 +76,7 @@ def self.extract_document_symbols(content, options = {}) # We are unable to build a document symbol tree for Puppet 4 AST return [] end + symbols = [] recurse_document_symbols(result.model, '', nil, symbols) # [] @@ -107,12 +109,12 @@ def self.recurse_document_symbols(object, path, parentsymbol, symbollist) # Puppet Resources when 'Puppet::Pops::Model::ResourceExpression' this_symbol = LSP::DocumentSymbol.new( - 'name' => object.type_name.value, - 'kind' => LSP::SymbolKind::METHOD, - 'detail' => object.type_name.value, - 'range' => create_range(object.offset, object.length, object.locator), + 'name' => object.type_name.value, + 'kind' => LSP::SymbolKind::METHOD, + 'detail' => object.type_name.value, + 'range' => create_range(object.offset, object.length, object.locator), 'selectionRange' => create_range(object.offset, object.length, object.locator), - 'children' => [] + 'children' => [] ) when 'Puppet::Pops::Model::ResourceBody' @@ -125,33 +127,33 @@ def self.recurse_document_symbols(object, path, parentsymbol, symbollist) when 'Puppet::Pops::Model::AttributeOperation' attr_name = object.attribute_name this_symbol = LSP::DocumentSymbol.new( - 'name' => attr_name, - 'kind' => LSP::SymbolKind::VARIABLE, - 'detail' => attr_name, - 'range' => create_range(object.offset, object.length, object.locator), + 'name' => attr_name, + 'kind' => LSP::SymbolKind::VARIABLE, + 'detail' => attr_name, + 'range' => create_range(object.offset, object.length, object.locator), 'selectionRange' => create_range(object.offset, attr_name.length, object.locator), - 'children' => [] + 'children' => [] ) # Puppet Class when 'Puppet::Pops::Model::HostClassDefinition' this_symbol = LSP::DocumentSymbol.new( - 'name' => object.name, - 'kind' => LSP::SymbolKind::CLASS, - 'detail' => object.name, - 'range' => create_range(object.offset, object.length, object.locator), + 'name' => object.name, + 'kind' => LSP::SymbolKind::CLASS, + 'detail' => object.name, + 'range' => create_range(object.offset, object.length, object.locator), 'selectionRange' => create_range(object.offset, object.length, object.locator), - 'children' => [] + 'children' => [] ) # Load in the class parameters object.parameters.each do |param| param_symbol = LSP::DocumentSymbol.new( - 'name' => "$#{param.name}", - 'kind' => LSP::SymbolKind::PROPERTY, - 'detail' => "$#{param.name}", - 'range' => create_range(param.offset, param.length, param.locator), + 'name' => "$#{param.name}", + 'kind' => LSP::SymbolKind::PROPERTY, + 'detail' => "$#{param.name}", + 'range' => create_range(param.offset, param.length, param.locator), 'selectionRange' => create_range(param.offset, param.length, param.locator), - 'children' => [] + 'children' => [] ) this_symbol.children.push(param_symbol) end @@ -159,55 +161,55 @@ def self.recurse_document_symbols(object, path, parentsymbol, symbollist) # Puppet Defined Type when 'Puppet::Pops::Model::ResourceTypeDefinition' this_symbol = LSP::DocumentSymbol.new( - 'name' => object.name, - 'kind' => LSP::SymbolKind::CLASS, - 'detail' => object.name, - 'range' => create_range(object.offset, object.length, object.locator), + 'name' => object.name, + 'kind' => LSP::SymbolKind::CLASS, + 'detail' => object.name, + 'range' => create_range(object.offset, object.length, object.locator), 'selectionRange' => create_range(object.offset, object.length, object.locator), - 'children' => [] + 'children' => [] ) # Load in the class parameters object.parameters.each do |param| param_symbol = LSP::DocumentSymbol.new( - 'name' => "$#{param.name}", - 'kind' => LSP::SymbolKind::FIELD, - 'detail' => "$#{param.name}", - 'range' => create_range(param.offset, param.length, param.locator), + 'name' => "$#{param.name}", + 'kind' => LSP::SymbolKind::FIELD, + 'detail' => "$#{param.name}", + 'range' => create_range(param.offset, param.length, param.locator), 'selectionRange' => create_range(param.offset, param.length, param.locator), - 'children' => [] + 'children' => [] ) this_symbol.children.push(param_symbol) end when 'Puppet::Pops::Model::AssignmentExpression' this_symbol = LSP::DocumentSymbol.new( - 'name' => "$#{object.left_expr.expr.value}", - 'kind' => LSP::SymbolKind::VARIABLE, - 'detail' => "$#{object.left_expr.expr.value}", - 'range' => create_range(object.left_expr.offset, object.left_expr.length, object.left_expr.locator), + 'name' => "$#{object.left_expr.expr.value}", + 'kind' => LSP::SymbolKind::VARIABLE, + 'detail' => "$#{object.left_expr.expr.value}", + 'range' => create_range(object.left_expr.offset, object.left_expr.length, object.left_expr.locator), 'selectionRange' => create_range(object.left_expr.offset, object.left_expr.length, object.left_expr.locator), - 'children' => [] + 'children' => [] ) # Puppet Plan when 'Puppet::Pops::Model::PlanDefinition' this_symbol = LSP::DocumentSymbol.new( - 'name' => object.name, - 'kind' => LSP::SymbolKind::CLASS, - 'detail' => object.name, - 'range' => create_range(object.offset, object.length, object.locator), + 'name' => object.name, + 'kind' => LSP::SymbolKind::CLASS, + 'detail' => object.name, + 'range' => create_range(object.offset, object.length, object.locator), 'selectionRange' => create_range(object.offset, object.length, object.locator), - 'children' => [] + 'children' => [] ) # Load in the class parameters object.parameters.each do |param| param_symbol = LSP::DocumentSymbol.new( - 'name' => "$#{param.name}", - 'kind' => LSP::SymbolKind::CLASS, - 'detail' => "$#{param.name}", - 'range' => create_range(param.offset, param.length, param.locator), + 'name' => "$#{param.name}", + 'kind' => LSP::SymbolKind::CLASS, + 'detail' => "$#{param.name}", + 'range' => create_range(param.offset, param.length, param.locator), 'selectionRange' => create_range(param.offset, param.length, param.locator), - 'children' => [] + 'children' => [] ) this_symbol.children.push(param_symbol) end @@ -218,6 +220,7 @@ def self.recurse_document_symbols(object, path, parentsymbol, symbollist) end return if this_symbol.nil? + parentsymbol.nil? ? symbollist.push(this_symbol) : parentsymbol.children.push(this_symbol) end end diff --git a/lib/puppet-languageserver/manifest/folding_provider.rb b/lib/puppet-languageserver/manifest/folding_provider.rb index ed082a82..c6aa693c 100644 --- a/lib/puppet-languageserver/manifest/folding_provider.rb +++ b/lib/puppet-languageserver/manifest/folding_provider.rb @@ -23,15 +23,16 @@ def supported? REGION_REGION = 'region' def start_region?(text) - !(text =~ %r{^#\s*region\b}).nil? + !(text =~ /^#\s*region\b/).nil? end def end_region?(text) - !(text =~ %r{^#\s*endregion\b}).nil? + !(text =~ /^#\s*endregion\b/).nil? end def folding_ranges(tokens, show_last_line = false) return nil unless self.class.supported? + ranges = {} brace_stack = [] @@ -127,12 +128,13 @@ def create_range_span_tokens(start_token, end_token, kind) start_line = line_for_offset(start_token) - 1 end_line = line_for_offset(end_token) - 1 return nil if start_line == end_line + LSP::FoldingRange.new({ - 'startLine' => start_line, + 'startLine' => start_line, 'startCharacter' => pos_on_line(start_token) - 1, - 'endLine' => end_line, - 'endCharacter' => pos_on_line(end_token, end_token.offset + end_token.length) - 1, - 'kind' => kind + 'endLine' => end_line, + 'endCharacter' => pos_on_line(end_token, end_token.offset + end_token.length) - 1, + 'kind' => kind }) end @@ -141,12 +143,13 @@ def create_range_whole_token(token, kind) start_line = line_for_offset(token) - 1 end_line = line_for_offset(token, token.offset + token.length) - 1 return nil if start_line == end_line + LSP::FoldingRange.new({ - 'startLine' => start_line, + 'startLine' => start_line, 'startCharacter' => pos_on_line(token) - 1, - 'endLine' => end_line, - 'endCharacter' => pos_on_line(token, token.offset + token.length) - 1, - 'kind' => kind + 'endLine' => end_line, + 'endCharacter' => pos_on_line(token, token.offset + token.length) - 1, + 'kind' => kind }) end @@ -157,13 +160,14 @@ def create_range_heredoc(heredoc_token, subloc_token, kind) # use the heredoc sublocator endline and add one end_line = line_for_offset(heredoc_token, heredoc_token.offset + heredoc_token.length + subloc_token.length) return nil if start_line == end_line + LSP::FoldingRange.new({ - 'startLine' => start_line, + 'startLine' => start_line, 'startCharacter' => pos_on_line(heredoc_token) - 1, - 'endLine' => end_line, + 'endLine' => end_line, # We don't know where the end token for the Heredoc is, so just assume it's at the start of the line - 'endCharacter' => 0, - 'kind' => kind + 'endCharacter' => 0, + 'kind' => kind }) end @@ -174,6 +178,7 @@ def add_range!(range, ranges) # Ignore the range if there is an existing one which is bigger return nil unless ranges[range.startLine].nil? || ranges[range.startLine].endLine < range.endLine + ranges[range.startLine] = range nil end @@ -184,12 +189,15 @@ def process_block_comment!(index, tokens, ranges) line_num = line_for_offset(tokens[index][1]) while index < tokens.length - 2 break unless tokens[index + 1][0] == :TOKEN_COMMENT + next_line = line_for_offset(tokens[index + 1][1]) # Tokens must be on contiguous lines break unless next_line == line_num + 1 + # Must not be a region comment comment = extract_text(tokens[index + 1][1]) break if start_region?(comment) || end_region?(comment) + # It's a block comment line_num = next_line index += 1 @@ -206,6 +214,7 @@ def block_comment?(index, tokens) return false unless tokens[index][0] == :TOKEN_COMMENT # If it's the first token then it has to be at the start of a line return true if index.zero? + # It has to be the first token on this line this_token_line = line_for_offset(tokens[index][1]) prev_token_line = line_for_offset(tokens[index - 1][1]) diff --git a/lib/puppet-languageserver/manifest/format_on_type_provider.rb b/lib/puppet-languageserver/manifest/format_on_type_provider.rb index a32bef8a..22964926 100644 --- a/lib/puppet-languageserver/manifest/format_on_type_provider.rb +++ b/lib/puppet-languageserver/manifest/format_on_type_provider.rb @@ -49,6 +49,7 @@ def format(content, line, char, trigger_character, formatting_options, max_files break if farrow_token.line == end_brace.line && farrow_token.character > end_brace.character # Check for multiple hashrockets on the same line. If we find some, then we can't do any automated indentation return result if lines.include?(farrow_token.line) + lines << farrow_token.line farrows << { token: farrow_token } end @@ -70,6 +71,7 @@ def format(content, line, char, trigger_character, formatting_options, max_files farrows.each do |info| # Ignore invalid hashrockets next if info[:indent] == -1 + end_name_token = info[:name_token].column + info[:name_token].to_manifest.length begin_farrow_token = info[:token].column new_whitespace = max_indent - end_name_token @@ -79,7 +81,7 @@ def format(content, line, char, trigger_character, formatting_options, max_files # Create the TextEdit result << LSP::TextEdit.new.from_h!( 'newText' => ' ' * new_whitespace, - 'range' => LSP.create_range(info[:token].line - 1, end_name_token - 1, info[:token].line - 1, begin_farrow_token - 1) + 'range' => LSP.create_range(info[:token].line - 1, end_name_token - 1, info[:token].line - 1, begin_farrow_token - 1) ) end result @@ -91,6 +93,7 @@ def format(content, line, char, trigger_character, formatting_options, max_files def find_token_by_location(tokens, line, character) return nil if tokens.empty? + # Puppet Lint uses base 1, but LSP is base 0, so adjust accordingly cursor_line = line + 1 cursor_column = character + 1 @@ -105,6 +108,7 @@ def find_token_by_location(tokens, line, character) return nil if tokens[idx].column > cursor_column # return the token if it starts on the cursor column we are interested in return tokens[idx] if tokens[idx].column == cursor_column + end_column = tokens[idx].column + tokens[idx].to_manifest.length # return the token it the cursor column is within the token string return tokens[idx] if cursor_column <= end_column @@ -117,6 +121,7 @@ def calculate_indentation_info(farrow_token) result = { indent: -1 } # This is not a valid hashrocket if there's no previous tokens return result if farrow_token.prev_token.nil? + if VALID_TOKEN_TYPES.include?(farrow_token.prev_token.type) # Someone forgot the whitespace! e.g. ensure=> result[:indent] = farrow_token.column + 1 @@ -127,6 +132,7 @@ def calculate_indentation_info(farrow_token) # If the whitespace has no previous token (which shouldn't happen) or the thing before the whitespace is not a property name this it not a valid hashrocket return result if farrow_token.prev_token.prev_token.nil? return result unless VALID_TOKEN_TYPES.include?(farrow_token.prev_token.prev_token.type) + result[:name_token] = farrow_token.prev_token.prev_token result[:indent] = farrow_token.prev_token.column + 1 # The indent is the whitespace column + 1 end diff --git a/lib/puppet-languageserver/manifest/hover_provider.rb b/lib/puppet-languageserver/manifest/hover_provider.rb index 26d42b3b..f18777f3 100644 --- a/lib/puppet-languageserver/manifest/hover_provider.rb +++ b/lib/puppet-languageserver/manifest/hover_provider.rb @@ -5,11 +5,11 @@ module Manifest module HoverProvider def self.resolve(session_state, content, line_num, char_num, options = {}) options = { - :tasks_mode => false + tasks_mode: false }.merge(options) result = PuppetLanguageServer::PuppetParserHelper.object_under_cursor(content, line_num, char_num, - :disallowed_classes => [Puppet::Pops::Model::BlockExpression], - :tasks_mode => options[:tasks_mode]) + disallowed_classes: [Puppet::Pops::Model::BlockExpression], + tasks_mode: options[:tasks_mode]) return nil if result.nil? path = result[:path] @@ -70,7 +70,7 @@ def self.resolve(session_state, content, line_num, char_num, options = {}) when 'Puppet::Pops::Model::QualifiedReference' # https://github.com/puppetlabs/puppet-specifications/blob/master/language/names.md#names # Datatypes have to start with uppercase and can be fully qualified - if item.cased_value =~ /^[A-Z][a-zA-Z:0-9]*$/ # rubocop:disable Style/GuardClause + if /^[A-Z][a-zA-Z:0-9]*$/.match?(item.cased_value) # rubocop:disable Style/GuardClause content = get_puppet_datatype_content(session_state, item, options[:tasks_mode]) else raise "#{item.cased_value} is an unknown QualifiedReference" @@ -80,6 +80,7 @@ def self.resolve(session_state, content, line_num, char_num, options = {}) end return nil if content.nil? + LSP::Hover.new('contents' => content) end @@ -115,6 +116,7 @@ def self.get_hover_content_for_access_expression(session_state, path, expr) def self.get_fact_content(session_state, factname) fact = PuppetLanguageServer::FacterHelper.fact(session_state, factname) return nil if fact.nil? + value = fact.value content = "**#{factname}** Fact\n\n" @@ -145,6 +147,7 @@ def self.get_attribute_type_property_content(item_type, property) def self.get_attribute_class_parameter_content(item_class, param) param_type = item_class.parameters[param] return nil if param_type.nil? + content = "**#{param}** Parameter" content += "\n\n#{param_type[:doc]}" unless param_type[:doc].nil? content @@ -169,8 +172,10 @@ def self.get_resource_expression_content(session_state, item) # Get an instance of the type item_object = PuppetLanguageServer::PuppetHelper.get_type(session_state, name) return get_puppet_type_content(item_object) unless item_object.nil? + item_object = PuppetLanguageServer::PuppetHelper.get_class(session_state, name) return get_puppet_class_content(item_object) unless item_object.nil? + raise "#{name} is not a valid puppet type" end diff --git a/lib/puppet-languageserver/manifest/signature_provider.rb b/lib/puppet-languageserver/manifest/signature_provider.rb index 33d46fb5..c6f43011 100644 --- a/lib/puppet-languageserver/manifest/signature_provider.rb +++ b/lib/puppet-languageserver/manifest/signature_provider.rb @@ -5,13 +5,13 @@ module Manifest module SignatureProvider def self.signature_help(session_state, content, line_num, char_num, options = {}) options = { - :tasks_mode => false + tasks_mode: false }.merge(options) result = PuppetLanguageServer::PuppetParserHelper.object_under_cursor(content, line_num, char_num, - :multiple_attempts => false, - :tasks_mode => options[:tasks_mode], - :remove_trigger_char => false) + multiple_attempts: false, + tasks_mode: options[:tasks_mode], + remove_trigger_char: false) response = LSP::SignatureHelp.new.from_h!('signatures' => [], 'activeSignature' => nil, 'activeParameter' => nil) # We are in the root of the document so no signatures here. return response if result.nil? @@ -42,11 +42,11 @@ def self.signature_help(session_state, content, line_num, char_num, options = {} # result.line_offsets contains an array of the offsets on a per line basis e.g. # [0, 14, 34, 36] means line number 2 starts at absolute offset 34 # Once we know the line offset, we can simply add on the char_num to get the absolute offset - if function_ast_object.respond_to?(:locator) - line_offset = function_ast_object.locator.line_index[line_num] - else - line_offset = locator.line_index[line_num] - end + line_offset = if function_ast_object.respond_to?(:locator) + function_ast_object.locator.line_index[line_num] + else + locator.line_index[line_num] + end abs_offset = line_offset + char_num # We need to use offsets here in case functions span lines @@ -58,14 +58,14 @@ def self.signature_help(session_state, content, line_num, char_num, options = {} func_info.signatures.each do |sig| lsp_sig = LSP::SignatureInformation.new.from_h!( - 'label' => sig.key, + 'label' => sig.key, 'documentation' => sig.doc, - 'parameters' => [] + 'parameters' => [] ) sig.parameters.each do |param| lsp_sig.parameters << LSP::ParameterInformation.new.from_h!( - 'label' => param.signature_key_offset.nil? || param.signature_key_length.nil? ? param.name : [param.signature_key_offset, param.signature_key_offset + param.signature_key_length], + 'label' => param.signature_key_offset.nil? || param.signature_key_length.nil? ? param.name : [param.signature_key_offset, param.signature_key_offset + param.signature_key_length], 'documentation' => param.doc ) end @@ -111,6 +111,7 @@ def self.param_number_from_ast(char_offset, function_ast_object, locator) return nil if char_offset >= function_offset + function_length # Does the function even have arguments? then the cursor HAS to be in the first parameter return 0 if function_ast_object.arguments.count.zero? + # Is the cursor within any of the function argument locations? if so, return the parameter number we're in param_number = function_ast_object.arguments.find_index { |arg| char_offset >= arg.offset && char_offset <= arg.offset + arg.length } return param_number unless param_number.nil? @@ -137,6 +138,7 @@ def self.param_number_from_ast(char_offset, function_ast_object, locator) # Now we now the char_offset exists between two existing locators. Determine the location by finding which argument is AFTER the cursor after_index = function_ast_object.arguments.find_index { |arg| char_offset < arg.offset } return nil if after_index.nil? || after_index.zero? # This should never happen but, you never know. + before_index = after_index - 1 # Now we know between which arguments (before_index and after_index) the char_offset lies diff --git a/lib/puppet-languageserver/manifest/validation_provider.rb b/lib/puppet-languageserver/manifest/validation_provider.rb index 0f2476e4..2daa3298 100644 --- a/lib/puppet-languageserver/manifest/validation_provider.rb +++ b/lib/puppet-languageserver/manifest/validation_provider.rb @@ -25,8 +25,8 @@ def self.fix_validate_errors(session_state, content) def self.validate(session_state, content, options = {}) options = { - :max_problems => 100, - :tasks_mode => false + max_problems: 100, + tasks_mode: false }.merge(options) result = [] @@ -60,50 +60,43 @@ def self.validate(session_state, content, options = {}) endpos = problem[:column] - 1 + problem[:token].to_manifest.length unless problem[:token].nil? || problem[:token].value.nil? result << LSP::Diagnostic.new('severity' => severity, - 'code' => problem[:check].to_s, - 'range' => LSP.create_range(problem[:line] - 1, problem[:column] - 1, problem[:line] - 1, endpos), - 'source' => 'Puppet', - 'message' => problem[:message]) + 'code' => problem[:check].to_s, + 'range' => LSP.create_range(problem[:line] - 1, problem[:column] - 1, problem[:line] - 1, endpos), + 'source' => 'Puppet', + 'message' => problem[:message]) end end - # rubocop:disable Lint/SuppressedException rescue StandardError # If anything catastrophic happens we resort to puppet parsing anyway end - # rubocop:enable Lint/SuppressedException - # TODO: Should I wrap this thing in a big rescue block? Puppet[:code] = content env = Puppet.lookup(:current_environment) loaders = Puppet::Pops::Loaders.new(env) Puppet.override({ loaders: loaders }, 'For puppet parser validate') do - begin - validation_environment = env - $PuppetParserMutex.synchronize do # rubocop:disable Style/GlobalVars - begin - original_taskmode = Puppet[:tasks] if Puppet.tasks_supported? - Puppet[:tasks] = options[:tasks_mode] if Puppet.tasks_supported? - validation_environment.check_for_reparse - validation_environment.known_resource_types.clear - ensure - Puppet[:tasks] = original_taskmode if Puppet.tasks_supported? - end - end - rescue StandardError => e - # Sometimes the error is in the cause not the root object itself - e = e.cause if !e.respond_to?(:line) && e.respond_to?(:cause) - ex_line = e.respond_to?(:line) && !e.line.nil? ? e.line - 1 : nil # Line numbers from puppet exceptions are base 1 - ex_pos = e.respond_to?(:pos) && !e.pos.nil? ? e.pos : nil # Pos numbers from puppet are base 1 - - message = e.respond_to?(:message) ? e.message : nil - message = e.basic_message if message.nil? && e.respond_to?(:basic_message) - - unless ex_line.nil? || ex_pos.nil? || message.nil? - result << LSP::Diagnostic.new('severity' => LSP::DiagnosticSeverity::ERROR, - 'range' => LSP.create_range(ex_line, ex_pos, ex_line, ex_pos + 1), - 'source' => 'Puppet', - 'message' => message) - end + validation_environment = env + $PuppetParserMutex.synchronize do # rubocop:disable Style/GlobalVars + original_taskmode = Puppet[:tasks] if Puppet.tasks_supported? + Puppet[:tasks] = options[:tasks_mode] if Puppet.tasks_supported? + validation_environment.check_for_reparse + validation_environment.known_resource_types.clear + ensure + Puppet[:tasks] = original_taskmode if Puppet.tasks_supported? + end + rescue StandardError => e + # Sometimes the error is in the cause not the root object itself + e = e.cause if !e.respond_to?(:line) && e.respond_to?(:cause) + ex_line = e.respond_to?(:line) && !e.line.nil? ? e.line - 1 : nil # Line numbers from puppet exceptions are base 1 + ex_pos = e.respond_to?(:pos) && !e.pos.nil? ? e.pos : nil # Pos numbers from puppet are base 1 + + message = e.respond_to?(:message) ? e.message : nil + message = e.basic_message if message.nil? && e.respond_to?(:basic_message) + + unless ex_line.nil? || ex_pos.nil? || message.nil? + result << LSP::Diagnostic.new('severity' => LSP::DiagnosticSeverity::ERROR, + 'range' => LSP.create_range(ex_line, ex_pos, ex_line, ex_pos + 1), + 'source' => 'Puppet', + 'message' => message) end end diff --git a/lib/puppet-languageserver/message_handler.rb b/lib/puppet-languageserver/message_handler.rb index 9108be29..a92ea3c9 100644 --- a/lib/puppet-languageserver/message_handler.rb +++ b/lib/puppet-languageserver/message_handler.rb @@ -33,13 +33,13 @@ def request_initialize(_, json_rpc_message) PuppetLanguageServer::ServerCapabilites.folding_provider_supported? # Setup static registrations if dynamic registration is not available info = { - :documentOnTypeFormattingProvider => !language_client.client_capability('textDocument', 'onTypeFormatting', 'dynamicRegistration'), - :foldingRangeProvider => static_folding_provider + documentOnTypeFormattingProvider: !language_client.client_capability('textDocument', 'onTypeFormatting', 'dynamicRegistration'), + foldingRangeProvider: static_folding_provider } # Configure the document store documents.initialize_store( - :workspace => workspace_root_from_initialize_params(json_rpc_message.params) + workspace: workspace_root_from_initialize_params(json_rpc_message.params) ) # Initiate loading the object_cache @@ -60,12 +60,12 @@ def request_shutdown(_, _json_rpc_message) def request_puppet_getversion(_, _json_rpc_message) LSP::PuppetVersion.new( 'languageServerVersion' => PuppetEditorServices.version, - 'puppetVersion' => Puppet.version, - 'facterVersion' => Facter.version, - 'factsLoaded' => session_state.facts_loaded?, - 'functionsLoaded' => session_state.default_functions_loaded?, - 'typesLoaded' => session_state.default_types_loaded?, - 'classesLoaded' => session_state.default_classes_loaded? + 'puppetVersion' => Puppet.version, + 'facterVersion' => Facter.version, + 'factsLoaded' => session_state.facts_loaded?, + 'functionsLoaded' => session_state.default_functions_loaded?, + 'typesLoaded' => session_state.default_types_loaded?, + 'classesLoaded' => session_state.default_classes_loaded? ) end @@ -89,13 +89,14 @@ def request_puppet_getresource(_, json_rpc_message) def request_puppet_compilenodegraph(_, json_rpc_message) file_uri = json_rpc_message.params['external'] return LSP::PuppetNodeGraphResponse.new('error' => 'Files of this type can not be used to create a node graph.') unless documents.document_type(file_uri) == :manifest + document = documents.document(file_uri) begin node_graph = PuppetLanguageServer::PuppetHelper.get_node_graph(session_state, document.content, documents.store_root_path) LSP::PuppetNodeGraphResponse.new('vertices' => node_graph.vertices, - 'edges' => node_graph.edges, - 'error' => node_graph.error_content) + 'edges' => node_graph.edges, + 'error' => node_graph.error_content) rescue StandardError => e PuppetLanguageServer.log_message(:error, "(puppet/compileNodeGraph) Error generating node graph. #{e}") LSP::PuppetNodeGraphResponse.new('error' => 'An internal error occured while generating the the node graph. Please see the debug log files for more information.') @@ -132,17 +133,17 @@ def request_puppet_fixdiagnosticerrors(_, json_rpc_message) end LSP::PuppetFixDiagnosticErrorsResponse.new( - 'documentUri' => formatted_request.documentUri, + 'documentUri' => formatted_request.documentUri, 'fixesApplied' => changes, - 'newContent' => changes > 0 || formatted_request.alwaysReturnContent ? new_content : nil + 'newContent' => changes > 0 || formatted_request.alwaysReturnContent ? new_content : nil ) rescue StandardError => e PuppetLanguageServer.log_message(:error, "(puppet/fixDiagnosticErrors) #{e}") unless formatted_request.nil? LSP::PuppetFixDiagnosticErrorsResponse.new( - 'documentUri' => formatted_request.documentUri, + 'documentUri' => formatted_request.documentUri, 'fixesApplied' => 0, - 'newContent' => formatted_request.alwaysReturnContent ? content : nil # rubocop:disable Metrics/BlockNesting + 'newContent' => formatted_request.alwaysReturnContent ? content : nil ) end end @@ -156,7 +157,7 @@ def request_textdocument_completion(_, json_rpc_message) case documents.document_type(file_uri) when :manifest - PuppetLanguageServer::Manifest::CompletionProvider.complete(session_state, content, line_num, char_num, :context => context, :tasks_mode => documents.plan_file?(file_uri)) + PuppetLanguageServer::Manifest::CompletionProvider.complete(session_state, content, line_num, char_num, context: context, tasks_mode: documents.plan_file?(file_uri)) else raise "Unable to provide completion on #{file_uri}" end @@ -167,6 +168,7 @@ def request_textdocument_completion(_, json_rpc_message) def request_textdocument_foldingrange(_, json_rpc_message) return nil unless language_client.folding_range + file_uri = json_rpc_message.params['textDocument']['uri'] case documents.document_type(file_uri) when :manifest @@ -194,7 +196,7 @@ def request_textdocument_hover(_, json_rpc_message) content = documents.document_content(file_uri) case documents.document_type(file_uri) when :manifest - PuppetLanguageServer::Manifest::HoverProvider.resolve(session_state, content, line_num, char_num, :tasks_mode => documents.plan_file?(file_uri)) + PuppetLanguageServer::Manifest::HoverProvider.resolve(session_state, content, line_num, char_num, tasks_mode: documents.plan_file?(file_uri)) else raise "Unable to provide hover on #{file_uri}" end @@ -211,7 +213,7 @@ def request_textdocument_definition(_, json_rpc_message) case documents.document_type(file_uri) when :manifest - PuppetLanguageServer::Manifest::DefinitionProvider.find_definition(session_state, content, line_num, char_num, :tasks_mode => documents.plan_file?(file_uri)) + PuppetLanguageServer::Manifest::DefinitionProvider.find_definition(session_state, content, line_num, char_num, tasks_mode: documents.plan_file?(file_uri)) else raise "Unable to provide definition on #{file_uri}" end @@ -226,7 +228,7 @@ def request_textdocument_documentsymbol(_, json_rpc_message) case documents.document_type(file_uri) when :manifest - PuppetLanguageServer::Manifest::DocumentSymbolProvider.extract_document_symbols(content, :tasks_mode => documents.plan_file?(file_uri)) + PuppetLanguageServer::Manifest::DocumentSymbolProvider.extract_document_symbols(content, tasks_mode: documents.plan_file?(file_uri)) else raise "Unable to provide definition on #{file_uri}" end @@ -237,6 +239,7 @@ def request_textdocument_documentsymbol(_, json_rpc_message) def request_textdocument_ontypeformatting(_, json_rpc_message) return nil unless language_client.format_on_type + file_uri = json_rpc_message.params['textDocument']['uri'] line_num = json_rpc_message.params['position']['line'] char_num = json_rpc_message.params['position']['character'] @@ -273,7 +276,7 @@ def request_textdocument_signaturehelp(_, json_rpc_message) content, line_num, char_num, - :tasks_mode => documents.plan_file?(file_uri) + tasks_mode: documents.plan_file?(file_uri) ) else raise "Unable to provide signatures on #{file_uri}" @@ -373,6 +376,7 @@ def response_client_unregistercapability(_, json_rpc_message, original_request) def response_workspace_configuration(_, json_rpc_message, original_request) return unless json_rpc_message.is_successful + original_request.params.items.each_with_index do |item, index| # The response from the client strips the section name so we need to re-add it language_client.parse_lsp_configuration_settings!(item.section => json_rpc_message.result[index]) @@ -399,10 +403,12 @@ def enqueue_validation(file_uri, doc_version, client_handler_id) def workspace_root_from_initialize_params(params) if params.key?('workspaceFolders') return nil if params['workspaceFolders'].nil? || params['workspaceFolders'].empty? + # We don't support multiple workspace folders yet, so just select the first one return UriHelper.uri_path(params['workspaceFolders'][0]['uri']) end return UriHelper.uri_path(params['rootUri']) if params.key?('rootUri') && !params['rootUri'].nil? + params['rootPath'] end end @@ -424,12 +430,12 @@ def request_puppet_getversion(_, _json_rpc_message) # case just fake the response that we are fully loaded with unknown gem versions LSP::PuppetVersion.new( 'languageServerVersion' => PuppetEditorServices.version, - 'puppetVersion' => 'Unknown', - 'facterVersion' => 'Unknown', - 'factsLoaded' => true, - 'functionsLoaded' => true, - 'typesLoaded' => true, - 'classesLoaded' => true + 'puppetVersion' => 'Unknown', + 'facterVersion' => 'Unknown', + 'factsLoaded' => true, + 'functionsLoaded' => true, + 'typesLoaded' => true, + 'classesLoaded' => true ) end @@ -439,7 +445,7 @@ def notification_initialized(_, _json_rpc_message) protocol.encode_and_send( ::PuppetEditorServices::Protocol::JsonRPCMessages.new_notification( 'window/showMessage', - 'type' => LSP::MessageType::WARNING, + 'type' => LSP::MessageType::WARNING, 'message' => 'An error occured while starting the Language Server. The server has been disabled.' ) ) diff --git a/lib/puppet-languageserver/providers.rb b/lib/puppet-languageserver/providers.rb index f7e6185e..566a9419 100644 --- a/lib/puppet-languageserver/providers.rb +++ b/lib/puppet-languageserver/providers.rb @@ -12,9 +12,7 @@ manifest/hover_provider puppetfile/validation_provider ].each do |lib| - begin - require "puppet-languageserver/#{lib}" - rescue LoadError - require File.expand_path(File.join(File.dirname(__FILE__), lib)) - end + require "puppet-languageserver/#{lib}" +rescue LoadError + require File.expand_path(File.join(File.dirname(__FILE__), lib)) end diff --git a/lib/puppet-languageserver/puppet_helper.rb b/lib/puppet-languageserver/puppet_helper.rb index 3eb58b56..b41ccc07 100644 --- a/lib/puppet-languageserver/puppet_helper.rb +++ b/lib/puppet-languageserver/puppet_helper.rb @@ -9,6 +9,7 @@ module PuppetLanguageServer module PuppetHelper def self.module_path return @module_path unless @module_path.nil? + # TODO: It would be nice if this wasn't using the whole puppet environment to calculate the modulepath directoties # In the meantime memoize it. Currently you can't change the modulepath mid-process. begin @@ -17,6 +18,7 @@ def self.module_path env = Puppet.lookup(:current_environment) end return [] if env.nil? + @module_path = env.modulepath end @@ -57,14 +59,14 @@ def self.function(session_state, name, tasks_mode = false) session_state.object_cache.object_by_name( :function, name, - :fuzzy_match => true, - :exclude_origins => exclude_origins + fuzzy_match: true, + exclude_origins: exclude_origins ) end def self.function_names(session_state, tasks_mode = false) exclude_origins = tasks_mode ? [] : [:bolt] - session_state.object_cache.object_names_by_section(:function, :exclude_origins => exclude_origins).map(&:to_s) + session_state.object_cache.object_names_by_section(:function, exclude_origins: exclude_origins).map(&:to_s) end def self.get_class(session_state, name) @@ -80,8 +82,8 @@ def self.datatype(session_state, name, tasks_mode = false) session_state.object_cache.object_by_name( :datatype, name, - :fuzzy_match => true, - :exclude_origins => exclude_origins + fuzzy_match: true, + exclude_origins: exclude_origins ) end diff --git a/lib/puppet-languageserver/puppet_lexer_helper.rb b/lib/puppet-languageserver/puppet_lexer_helper.rb index 765ad950..bb6818bd 100644 --- a/lib/puppet-languageserver/puppet_lexer_helper.rb +++ b/lib/puppet-languageserver/puppet_lexer_helper.rb @@ -9,7 +9,7 @@ module Parser class Lexer2WithComments < Puppet::Pops::Parser::Lexer2 # The PATTERN_COMMENT in lexer2 also consumes the trailing \r in the token and # we don't want that. - PATTERN_COMMENT_NO_WS = %r{#[^\r\n]*}.freeze + PATTERN_COMMENT_NO_WS = /#[^\r\n]*/.freeze TOKEN_COMMENT = [:COMMENT, '#', 1].freeze TOKEN_MLCOMMENT = [:MLCOMMENT, nil, 0].freeze diff --git a/lib/puppet-languageserver/puppet_monkey_patches.rb b/lib/puppet-languageserver/puppet_monkey_patches.rb index 58c1e687..2641a2cd 100644 --- a/lib/puppet-languageserver/puppet_monkey_patches.rb +++ b/lib/puppet-languageserver/puppet_monkey_patches.rb @@ -11,13 +11,11 @@ module Parser class Parser def singleton_parse_string(code, task_mode = false, path = nil) $PuppetParserMutex.synchronize do # rubocop:disable Style/GlobalVars - begin - original_taskmode = Puppet[:tasks] if Puppet.tasks_supported? - Puppet[:tasks] = task_mode if Puppet.tasks_supported? - return parse_string(code, path) - ensure - Puppet[:tasks] = original_taskmode if Puppet.tasks_supported? - end + original_taskmode = Puppet[:tasks] if Puppet.tasks_supported? + Puppet[:tasks] = task_mode if Puppet.tasks_supported? + return parse_string(code, path) + ensure + Puppet[:tasks] = original_taskmode if Puppet.tasks_supported? end end end diff --git a/lib/puppet-languageserver/puppet_parser_helper.rb b/lib/puppet-languageserver/puppet_parser_helper.rb index 3c48be79..ce22da98 100644 --- a/lib/puppet-languageserver/puppet_parser_helper.rb +++ b/lib/puppet-languageserver/puppet_parser_helper.rb @@ -28,6 +28,7 @@ def self.insert_text_at(content, line_offsets, line_num, char_num, text) # This helps due to syntax errors like `$facts[]` or `ensure =>` line_offset = line_offsets[line_num] raise if line_offset.nil? + # Insert the text content.slice(0, line_offset + char_num) + text + content.slice(line_offset + char_num, content.length - 1) end @@ -39,7 +40,8 @@ def self.line_offsets(content) loop do line_offset = content.index("\n", line_offset + 1) break if line_offset.nil? - line_offsets << line_offset + 1 + + line_offsets << (line_offset + 1) end line_offsets end @@ -56,10 +58,10 @@ def self.get_line_at(content, line_offsets, line_num) def self.object_under_cursor(content, line_num, char_num, options) options = { - :multiple_attempts => false, - :disallowed_classes => [], - :tasks_mode => false, - :remove_trigger_char => true + multiple_attempts: false, + disallowed_classes: [], + tasks_mode: false, + remove_trigger_char: true }.merge(options) # Use Puppet to generate the AST @@ -78,10 +80,12 @@ def self.object_under_cursor(content, line_num, char_num, options) new_content = content when :remove_char next if line_num.zero? && char_num.zero? + new_content = remove_char_at(content, line_offsets, line_num, char_num) move_offset = -1 when :remove_word next if line_num.zero? && char_num.zero? + next_char = get_char_at(content, line_offsets, line_num, char_num) while /[[:word:]]/ =~ next_char @@ -117,6 +121,7 @@ def self.object_under_cursor(content, line_num, char_num, options) break rescue Puppet::ParseErrorWithIssue next if options[:multiple_attempts] + raise end end @@ -127,11 +132,11 @@ def self.object_under_cursor(content, line_num, char_num, options) # [0, 14, 34, 36] means line number 2 starts at absolute offset 34 # Once we know the line offset, we can simply add on the char_num to get the absolute offset # If during paring we modified the source we may need to change the cursor location - if result.respond_to?(:line_offsets) - line_offset = result.line_offsets[line_num] - else - line_offset = result['locator'].line_index[line_num] - end + line_offset = if result.respond_to?(:line_offsets) + result.line_offsets[line_num] + else + result['locator'].line_index[line_num] + end abs_offset = line_offset + char_num + move_offset # Typically we're completing after something was typed, so go back one char by default abs_offset -= 1 if options[:remove_trigger_char] @@ -163,6 +168,7 @@ def self.object_under_cursor(content, line_num, char_num, options) end # nil means the root of the document return nil if valid_models.empty? + response = valid_models[0] if response.respond_to? :eAllContents # rubocop:disable Style/IfUnlessModifier Nicer to read like this diff --git a/lib/puppet-languageserver/puppetfile/validation_provider.rb b/lib/puppet-languageserver/puppetfile/validation_provider.rb index d6e8ef5e..8a848c09 100644 --- a/lib/puppet-languageserver/puppetfile/validation_provider.rb +++ b/lib/puppet-languageserver/puppetfile/validation_provider.rb @@ -12,10 +12,10 @@ def self.max_line_length def self.validate(content, options = {}) options = { - :max_problems => 100, - :resolve_puppetfile => true, - :module_path => [], - :document_uri => '???' + max_problems: 100, + resolve_puppetfile: true, + module_path: [], + document_uri: '???' }.merge(options) result = [] @@ -33,9 +33,9 @@ def self.validate(content, options = {}) rescue PuppetfileResolver::Puppetfile::Parser::ParserError => e result << LSP::Diagnostic.new( 'severity' => LSP::DiagnosticSeverity::ERROR, - 'range' => document_location_to_lsp_range(e.location), - 'source' => 'Puppet', - 'message' => e.to_s + 'range' => document_location_to_lsp_range(e.location), + 'source' => 'Puppet', + 'message' => e.to_s ) puppetfile = nil end @@ -48,19 +48,19 @@ def self.validate(content, options = {}) related_information = validation_error.duplicates.map do |dup_mod| { 'location' => { - 'uri' => options[:document_uri], + 'uri' => options[:document_uri], 'range' => document_location_to_lsp_range(dup_mod.location) }, - 'message' => validation_error.message + 'message' => validation_error.message } end end result << LSP::Diagnostic.new( - 'severity' => LSP::DiagnosticSeverity::ERROR, - 'range' => document_location_to_lsp_range(validation_error.puppet_module.location), - 'source' => 'Puppet', - 'message' => validation_error.message, + 'severity' => LSP::DiagnosticSeverity::ERROR, + 'range' => document_location_to_lsp_range(validation_error.puppet_module.location), + 'source' => 'Puppet', + 'message' => validation_error.message, 'relatedInformation' => related_information ) end @@ -82,9 +82,9 @@ def self.validate_resolution(puppetfile_document, document_uri, cache, module_pa rescue PuppetfileResolver::Puppetfile::DocumentResolveError => e return [LSP::Diagnostic.new( 'severity' => LSP::DiagnosticSeverity::ERROR, - 'range' => LSP.create_range(0, 0, 0, max_line_length), - 'source' => 'Puppet', - 'message' => e.message + 'range' => LSP.create_range(0, 0, 0, max_line_length), + 'source' => 'Puppet', + 'message' => e.message )] end @@ -99,9 +99,9 @@ def self.validate_resolution(puppetfile_document, document_uri, cache, module_pa end LSP::Diagnostic.new( 'severity' => severity, - 'range' => document_location_to_lsp_range(error.puppet_module.location), - 'source' => 'Puppet', - 'message' => error.message + 'range' => document_location_to_lsp_range(error.puppet_module.location), + 'source' => 'Puppet', + 'message' => error.message ) end end @@ -134,6 +134,7 @@ def self.find_dependencies(content) def self.resolver_cache return @resolver_cache unless @resolver_cache.nil? + require 'puppetfile-resolver/cache/base' # TODO: The cache should probably not cache local module information though # Share a cache between resolution calls to speed-up lookups @@ -145,27 +146,27 @@ def self.document_error_to_diagnostic(document_uri, error) if error.puppetfile_modules.count.zero? return LSP::Diagnostic.new( 'severity' => LSP::DiagnosticSeverity::ERROR, - 'range' => LSP.create_range(0, 0, 0, max_line_length), - 'source' => 'Puppet', - 'message' => error.message + 'range' => LSP.create_range(0, 0, 0, max_line_length), + 'source' => 'Puppet', + 'message' => error.message ) end related_information = error.puppetfile_modules.slice(1..-1).map do |dup_mod| { 'location' => { - 'uri' => document_uri, + 'uri' => document_uri, 'range' => document_location_to_lsp_range(dup_mod.location) }, - 'message' => "Module definition for #{dup_mod.name}" + 'message' => "Module definition for #{dup_mod.name}" } end LSP::Diagnostic.new( - 'severity' => LSP::DiagnosticSeverity::ERROR, - 'range' => document_location_to_lsp_range(error.puppetfile_modules[0].location), - 'source' => 'Puppet', - 'message' => error.message, + 'severity' => LSP::DiagnosticSeverity::ERROR, + 'range' => document_location_to_lsp_range(error.puppetfile_modules[0].location), + 'source' => 'Puppet', + 'message' => error.message, 'relatedInformation' => related_information.empty? ? nil : related_information ) end diff --git a/lib/puppet-languageserver/server_capabilities.rb b/lib/puppet-languageserver/server_capabilities.rb index cdf0e73b..839387c5 100644 --- a/lib/puppet-languageserver/server_capabilities.rb +++ b/lib/puppet-languageserver/server_capabilities.rb @@ -12,16 +12,16 @@ def self.capabilities(options = {}) # https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#initialize-request value = { - 'textDocumentSync' => LSP::TextDocumentSyncKind::FULL, - 'hoverProvider' => true, - 'completionProvider' => { - 'resolveProvider' => true, + 'textDocumentSync' => LSP::TextDocumentSyncKind::FULL, + 'hoverProvider' => true, + 'completionProvider' => { + 'resolveProvider' => true, 'triggerCharacters' => ['>', '$', '[', '='] }, - 'definitionProvider' => true, - 'documentSymbolProvider' => true, + 'definitionProvider' => true, + 'documentSymbolProvider' => true, 'workspaceSymbolProvider' => true, - 'signatureHelpProvider' => { + 'signatureHelpProvider' => { 'triggerCharacters' => ['(', ','] } } @@ -42,8 +42,7 @@ def self.folding_range_provider_options def self.no_capabilities # Any empty hash denotes no capabilities at all - { - } + {} end end end diff --git a/lib/puppet-languageserver/session_state/document_store.rb b/lib/puppet-languageserver/session_state/document_store.rb index 041d312b..ff60190e 100644 --- a/lib/puppet-languageserver/session_state/document_store.rb +++ b/lib/puppet-languageserver/session_state/document_store.rb @@ -76,6 +76,7 @@ def document(uri, doc_version = nil) @doc_mutex.synchronize do return nil if @documents[uri].nil? return nil unless doc_version.nil? || @documents[uri].version == doc_version + @documents[uri] end end @@ -90,6 +91,7 @@ def document_tokens(uri, doc_version = nil) return nil if @documents[uri].nil? return nil unless doc_version.nil? || @documents[uri].version == doc_version return @documents[uri].tokens unless @documents[uri].tokens.nil? + return @documents[uri].calculate_tokens! end end @@ -105,7 +107,7 @@ def document_uris def document_type(uri) case uri - when /\/Puppetfile$/i + when %r{/Puppetfile$}i :puppetfile when /\.pp$/i :manifest @@ -124,6 +126,7 @@ def document_type(uri) def plan_file?(uri) uri_path = PuppetLanguageServer::UriHelper.uri_path(uri) return false if uri_path.nil? + # For the text searching below we need a leading slash. That way # we don't need to use regexes which is slower uri_path = "/#{uri_path}" unless uri_path.start_with?('/') @@ -145,7 +148,7 @@ def plan_file?(uri) def initialize_store(options = {}) @workspace_path = options[:workspace] @workspace_info_cache = { - :expires => Time.new - 120 + expires: Time.new - 120 } end @@ -173,6 +176,7 @@ def store_has_environmentconf? # root of the module/control repo actually is def find_root_path(path) return nil if path.nil? + filepath = File.expand_path(path) if dir_exist?(filepath) @@ -185,13 +189,14 @@ def find_root_path(path) until directory.nil? break if file_exist?(File.join(directory, 'metadata.json')) || file_exist?(File.join(directory, 'environment.conf')) + parent = File.dirname(directory) # If the parent is the same as the original, then we've reached the end of the path chain - if parent == directory - directory = nil - else - directory = parent - end + directory = if parent == directory + nil + else + parent + end end directory @@ -199,12 +204,13 @@ def find_root_path(path) def store_details return @workspace_info_cache unless @workspace_info_cache[:never_expires] || @workspace_info_cache[:expires] < Time.new + # TTL has expired, time to calculate the document store details new_cache = { - :root_path => nil, - :has_environmentconf => false, - :has_metadatajson => false + root_path: nil, + has_environmentconf: false, + has_metadatajson: false } if @workspace_path.nil? # If we have never been given a local workspace path on the command line then there is really no @@ -240,7 +246,7 @@ def dir_exist?(path) def windows? # Ruby only sets File::ALT_SEPARATOR on Windows and the Ruby standard # library uses that to test what platform it's on. - !!File::ALT_SEPARATOR # rubocop:disable Style/DoubleNegation + !!File::ALT_SEPARATOR end # Creates a document object based on the Uri diff --git a/lib/puppet-languageserver/session_state/language_client.rb b/lib/puppet-languageserver/session_state/language_client.rb index 3f60e710..73be637b 100644 --- a/lib/puppet-languageserver/session_state/language_client.rb +++ b/lib/puppet-languageserver/session_state/language_client.rb @@ -55,7 +55,7 @@ def parse_lsp_initialize!(initialize_params = {}) def parse_lsp_configuration_settings!(settings = {}) # format on type enabled value = to_boolean(safe_hash_traverse(settings, 'puppet', 'editorService', 'formatOnType', 'enable'), DEFAULT_FORMAT_ON_TYPE_ENABLE) - unless value == @format_on_type # rubocop:disable Style/GuardClause Ummm no. + unless value == @format_on_type # Ummm no. # Is dynamic registration available? if client_capability('textDocument', 'onTypeFormatting', 'dynamicRegistration') == true if value @@ -74,7 +74,7 @@ def parse_lsp_configuration_settings!(settings = {}) # folding range enabled value = to_boolean(safe_hash_traverse(settings, 'puppet', 'editorService', 'foldingRange', 'enable'), DEFAULT_FOLDING_RANGE_ENABLE) && PuppetLanguageServer::ServerCapabilites.folding_provider_supported? - unless value == @folding_range # rubocop:disable Style/GuardClause Ummm no. + unless value == @folding_range # Ummm no. # Is dynamic registration available? if client_capability('textDocument', 'foldingRange', 'dynamicRegistration') == true if value @@ -90,7 +90,8 @@ def parse_lsp_configuration_settings!(settings = {}) end def capability_registrations(method) - return [{ :registered => false, :state => :complete }] if @registrations[method].nil? || @registrations[method].empty? + return [{ registered: false, state: :complete }] if @registrations[method].nil? || @registrations[method].empty? + @registrations[method].dup end @@ -110,7 +111,7 @@ def register_capability(method, options = {}) # Note - Don't put more than one method per request even though you can. It makes decoding errors much harder! @registrations[method] = [] if @registrations[method].nil? - @registrations[method] << { :registered => false, :state => :pending, :id => id } + @registrations[method] << { registered: false, state: :pending, id: id } message_handler.protocol.send_client_request('client/registerCapability', params) true @@ -125,9 +126,11 @@ def unregister_capability(method) params = LSP::UnregistrationParams.new.from_h!('unregisterations' => []) @registrations[method].each do |reg| next if reg[:id].nil? + PuppetLanguageServer.log_message(:warn, "A dynamic registration/deregistration for the #{method} method, with id #{reg[:id]} is already in progress") if reg[:state] == :pending # Ignore registrations that don't need to be unregistered next if reg[:state] == :complete && !reg[:registered] + params.unregisterations << LSP::Unregistration.new.from_h!('id' => reg[:id], 'method' => method) reg[:state] = :pending end @@ -197,15 +200,18 @@ def parse_unregister_capability_response!(response, original_request) def to_boolean(value, default = false) return default if value.nil? return value if value == true || value == false # rubocop:disable Style/MultipleComparison + value.to_s =~ %r{^(true|t|yes|y|1)$/i} end def to_integer(value, default = nil, min = nil, max = nil) return default if value.nil? + begin intv = Integer(value) return default if !min.nil? && intv < min return default if !max.nil? && intv > max + intv rescue ArgumentError default @@ -218,6 +224,7 @@ def new_request_id def safe_hash_traverse(hash, *names) return nil if names.empty? || hash.nil? || hash.empty? + item = nil loop do name = names.shift diff --git a/lib/puppet-languageserver/session_state/object_cache.rb b/lib/puppet-languageserver/session_state/object_cache.rb index 114e3f1e..e013f3f8 100644 --- a/lib/puppet-languageserver/session_state/object_cache.rb +++ b/lib/puppet-languageserver/session_state/object_cache.rb @@ -16,6 +16,7 @@ def initialize(_options = {}) def import_sidecar_list!(list, section, origin) return if origin.nil? return if section.nil? + list = [] if list.nil? @cache_lock.synchronize do @@ -51,6 +52,7 @@ def origin_exist?(origin) def section_in_origin_exist?(section, origin) @cache_lock.synchronize do return false if @inmemory_cache[origin].nil? || @inmemory_cache[origin].empty? + @inmemory_cache[origin].key?(section) end end @@ -60,16 +62,18 @@ def object_by_name(section, name, options = {}) # options[:exclude_origins] # options[:fuzzy_match] options = { - :exclude_origins => [], - :fuzzy_match => false + exclude_origins: [], + fuzzy_match: false }.merge(options) name = name.intern if name.is_a?(String) return nil if section.nil? + @cache_lock.synchronize do @inmemory_cache.each do |origin, sections| next if sections.nil? || sections[section].nil? || sections[section].empty? next if options[:exclude_origins].include?(origin) + sections[section].each do |item| match = options[:fuzzy_match] ? fuzzy_match?(item.key, name) : item.key == name return item if match @@ -102,14 +106,16 @@ def fuzzy_match?(obj, test_obj) # options[:exclude_origins] def object_names_by_section(section, options = {}) options = { - :exclude_origins => [] + exclude_origins: [] }.merge(options) result = [] return result if section.nil? + @cache_lock.synchronize do @inmemory_cache.each do |origin, sections| next if sections.nil? || sections[section].nil? || sections[section].empty? next if options[:exclude_origins].include?(origin) + result.concat(sections[section].map { |i| i.key }) end end @@ -120,9 +126,11 @@ def object_names_by_section(section, options = {}) # section => def objects_by_section(section, &_block) return if section.nil? + @cache_lock.synchronize do @inmemory_cache.each do |_, sections| next if sections.nil? || sections[section].nil? || sections[section].empty? + sections[section].each { |i| yield i.key, i } end end @@ -132,6 +140,7 @@ def all_objects(&_block) @cache_lock.synchronize do @inmemory_cache.each do |_origin, sections| next if sections.nil? + sections.each do |_section_name, list| list.each { |i| yield i.key, i } end @@ -144,6 +153,7 @@ def all_objects(&_block) def remove_section_impl(section, origin = nil) @inmemory_cache.each do |list_origin, sections| next unless origin.nil? || list_origin == origin + sections[section].clear unless sections.nil? || sections[section].nil? end end diff --git a/lib/puppet-languageserver/sidecar_protocol.rb b/lib/puppet-languageserver/sidecar_protocol.rb index e6e39b00..adff1d48 100644 --- a/lib/puppet-languageserver/sidecar_protocol.rb +++ b/lib/puppet-languageserver/sidecar_protocol.rb @@ -42,9 +42,10 @@ def from_json!(json_string) def ==(other) return false unless other.class == self.class + self.class .instance_methods(false) - .reject { |name| name.to_s.end_with?('=') || name.to_s.end_with?('!') } + .reject { |name| name.to_s.end_with?('=', '!') } .reject { |name| %i[to_h to_json].include?(name) } .each do |method_name| return false unless send(method_name) == other.send(method_name) @@ -54,9 +55,10 @@ def ==(other) def eql?(other) return false unless other.class == self.class + self.class .instance_methods(false) - .reject { |name| name.to_s.end_with?('=') || name.to_s.end_with?('!') } + .reject { |name| name.to_s.end_with?('=', '!') } .reject { |name| %i[to_h to_json].include?(name) } .each do |method_name| return false unless send(method_name).eql?(other.send(method_name)) @@ -68,7 +70,7 @@ def hash props = [] self.class .instance_methods(false) - .reject { |name| name.to_s.end_with?('=') || name.to_s.end_with?('!') } + .reject { |name| name.to_s.end_with?('=', '!') } .reject { |name| %i[to_h to_json].include?(name) } .each do |method_name| props << send(method_name).hash @@ -88,12 +90,12 @@ class BasePuppetObject < BaseClass def to_h { - 'key' => key, + 'key' => key, 'calling_source' => calling_source, - 'source' => source, - 'line' => line, - 'char' => char, - 'length' => length + 'source' => source, + 'line' => line, + 'char' => char, + 'length' => length } end @@ -141,8 +143,8 @@ class PuppetNodeGraph < BaseClass def to_json(*options) { - 'vertices' => vertices, - 'edges' => edges, + 'vertices' => vertices, + 'edges' => edges, 'error_content' => error_content }.to_json(options) end @@ -161,7 +163,7 @@ class PuppetClass < BasePuppetObject def to_h super.to_h.merge( - 'doc' => doc, + 'doc' => doc, 'parameters' => parameters ) end @@ -175,8 +177,8 @@ def from_h!(value) value['parameters'].each do |attr_name, obj_attr| # TODO: This should be a class, not a hash parameters[attr_name] = { - :type => value_from_hash(obj_attr, :type), - :doc => value_from_hash(obj_attr, :doc) + type: value_from_hash(obj_attr, :type), + doc: value_from_hash(obj_attr, :doc) } end end @@ -200,9 +202,9 @@ def initialize def to_h super.to_h.merge( - 'doc' => doc, - 'alias_of' => alias_of, - 'attributes' => attributes.map(&:to_h), + 'doc' => doc, + 'alias_of' => alias_of, + 'attributes' => attributes.map(&:to_h), 'is_type_alias' => is_type_alias ) end @@ -229,10 +231,10 @@ class PuppetDataTypeAttribute < BaseClass def to_h { - 'key' => key, + 'key' => key, 'default_value' => default_value, - 'doc' => doc, - 'types' => types + 'doc' => doc, + 'types' => types } end @@ -263,9 +265,9 @@ def initialize def to_h super.to_h.merge( - 'doc' => doc, + 'doc' => doc, 'function_version' => function_version, - 'signatures' => signatures.map(&:to_h) + 'signatures' => signatures.map(&:to_h) ) end @@ -295,10 +297,10 @@ def initialize def to_h { - 'key' => key, - 'doc' => doc, + 'key' => key, + 'doc' => doc, 'return_types' => return_types, - 'parameters' => parameters.map(&:to_h) + 'parameters' => parameters.map(&:to_h) } end @@ -322,9 +324,9 @@ class PuppetFunctionSignatureParameter < BaseClass def to_h { - 'name' => name, - 'doc' => doc, - 'types' => types, + 'name' => name, + 'doc' => doc, + 'types' => types, 'signature_key_offset' => signature_key_offset, 'signature_key_length' => signature_key_length } @@ -351,7 +353,7 @@ class PuppetType < BasePuppetObject def to_h super.to_h.merge( - 'doc' => doc, + 'doc' => doc, 'attributes' => attributes ) end @@ -365,10 +367,10 @@ def from_h!(value) value['attributes'].each do |attr_name, obj_attr| attributes[attr_name.intern] = { # TODO: This should be a class, not a hash - :type => value_from_hash(obj_attr, :type).intern, - :doc => value_from_hash(obj_attr, :doc), - :required? => value_from_hash(obj_attr, :required?), - :isnamevar? => value_from_hash(obj_attr, :isnamevar?) + type: value_from_hash(obj_attr, :type).intern, + doc: value_from_hash(obj_attr, :doc), + required?: value_from_hash(obj_attr, :required?), + isnamevar?: value_from_hash(obj_attr, :isnamevar?) } end end @@ -438,6 +440,7 @@ def types def concat!(array) return if array.nil? || array.empty? + array.each { |item| append!(item) } end @@ -454,6 +457,7 @@ def from_json!(json_string) obj.each do |key, value| info = METADATA_LIST[key.intern] next if info.nil? + list = list_for_object_class(info[:item_class]) value.each { |i| list << info[:item_class].new.from_h!(i) } end @@ -461,7 +465,8 @@ def from_json!(json_string) end def each_list(&block) - return unless block_given? + return unless block + @aggregate.each(&block) end @@ -471,21 +476,21 @@ def each_list(&block) # - Add to the information to this hash # - Add a method to access the aggregate METADATA_LIST = { - :classes => { - :item_class => PuppetClass, - :list_class => PuppetClassList + classes: { + item_class: PuppetClass, + list_class: PuppetClassList }, - :datatypes => { - :item_class => PuppetDataType, - :list_class => PuppetDataTypeList + datatypes: { + item_class: PuppetDataType, + list_class: PuppetDataTypeList }, - :functions => { - :item_class => PuppetFunction, - :list_class => PuppetFunctionList + functions: { + item_class: PuppetFunction, + list_class: PuppetFunctionList }, - :types => { - :item_class => PuppetType, - :list_class => PuppetTypeList + types: { + item_class: PuppetType, + list_class: PuppetTypeList } }.freeze diff --git a/lib/puppet-languageserver/uri_helper.rb b/lib/puppet-languageserver/uri_helper.rb index 3862272a..6f8d17a1 100644 --- a/lib/puppet-languageserver/uri_helper.rb +++ b/lib/puppet-languageserver/uri_helper.rb @@ -29,10 +29,11 @@ def self.relative_uri_path(root_uri, uri, case_sensitive = true) return nil unless actual_root.scheme == actual_uri.scheme # CGI.unescape doesn't handle space rules properly in uri paths - # URI.unescape does, but returns strings in their original encoding + # URI::parser.unescape does, but returns strings in their original encoding # Mostly safe here as we're only worried about file based URIs - root_path = URI.unescape(actual_root.path) # rubocop:disable Lint/UriEscapeUnescape - uri_path = URI.unescape(actual_uri.path) # rubocop:disable Lint/UriEscapeUnescape + parser = URI::DEFAULT_PARSER + root_path = parser.unescape(actual_root.path) + uri_path = parser.unescape(actual_uri.path) if case_sensitive return nil unless uri_path.slice(0, root_path.length) == root_path else diff --git a/lib/puppet_debugserver.rb b/lib/puppet_debugserver.rb index ef81e265..2de55b8b 100644 --- a/lib/puppet_debugserver.rb +++ b/lib/puppet_debugserver.rb @@ -40,11 +40,9 @@ def self.require_gems(options) debug_session/puppet_session_state puppet_monkey_patches ].each do |lib| - begin - require "puppet-debugserver/#{lib}" - rescue LoadError - require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-debugserver', lib)) - end + require "puppet-debugserver/#{lib}" + rescue LoadError + require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-debugserver', lib)) end ensure $VERBOSE = original_verbose @@ -128,8 +126,8 @@ def self.rpc_server_async(options) require 'puppet_editor_services/server/tcp' server_options = options.dup - protocol_options = { :class => PuppetEditorServices::Protocol::DebugAdapter }.merge(options) - handler_options = { :class => PuppetDebugServer::MessageHandler }.merge(options) + protocol_options = { class: PuppetEditorServices::Protocol::DebugAdapter }.merge(options) + handler_options = { class: PuppetDebugServer::MessageHandler }.merge(options) # TODO: Add max threads? server_options[:servicename] = 'DEBUG SERVER' @@ -155,9 +153,11 @@ def self.execute(rpc_thread) # TODO: Can I use a real mutex here? might be hard with the rpc_thread.alive? call sleep(0.5) while !debug_session.flow_control.flag?(:start_puppet) && rpc_thread.alive? && !debug_session.flow_control.terminate? return unless rpc_thread.alive? || debug_session.flow_control.terminate? + debug_session.run_puppet return unless rpc_thread.alive? + debug_session.close rpc_thread.join end diff --git a/lib/puppet_editor_services/connection/tcp.rb b/lib/puppet_editor_services/connection/tcp.rb index 6e561722..e4886702 100644 --- a/lib/puppet_editor_services/connection/tcp.rb +++ b/lib/puppet_editor_services/connection/tcp.rb @@ -14,6 +14,7 @@ def initialize(server, socket) def send_data(data) return false if socket.nil? + socket.write(data) true end diff --git a/lib/puppet_editor_services/handler/debug_adapter.rb b/lib/puppet_editor_services/handler/debug_adapter.rb index 95c97ce8..d284bffb 100644 --- a/lib/puppet_editor_services/handler/debug_adapter.rb +++ b/lib/puppet_editor_services/handler/debug_adapter.rb @@ -40,10 +40,10 @@ def handle_request(request_message, _context) result = send(method_name, protocol.connection.id, request_message) protocol.encode_and_send(result) unless result.nil? rescue NoMethodError, LoadError => e - unhandled_exception(e, :source => :request, :message => request_message) + unhandled_exception(e, source: :request, message: request_message) raise rescue StandardError => e - unhandled_exception(e, :source => :request, :message => request_message) + unhandled_exception(e, source: :request, message: request_message) end return true end diff --git a/lib/puppet_editor_services/handler/json_rpc.rb b/lib/puppet_editor_services/handler/json_rpc.rb index d10078d2..294d4ff5 100644 --- a/lib/puppet_editor_services/handler/json_rpc.rb +++ b/lib/puppet_editor_services/handler/json_rpc.rb @@ -66,7 +66,7 @@ def handle_request(request_message, _context) ) ) rescue StandardError => e - unhandled_exception(e, :source => :request, :message => request_message) + unhandled_exception(e, source: :request, message: request_message) end return true end @@ -88,7 +88,7 @@ def handle_notification(notification_message, _context) begin send(method_name, protocol.connection.id, notification_message) rescue StandardError => e - unhandled_exception(e, :source => :notification, :message => notification_message) + unhandled_exception(e, source: :notification, message: notification_message) end return true end @@ -106,6 +106,7 @@ def handle_notification(notification_message, _context) def handle_response(response_message, context) original_request = context[:request] return false if original_request.nil? + unless response_message.is_successful # rubocop:disable Style/IfUnlessModifier Line is too long otherwise PuppetEditorServices.log_message(:error, "Response for method '#{original_request.rpc_method}' with id '#{original_request.id}' failed with #{response_message.error}") end @@ -114,7 +115,7 @@ def handle_response(response_message, context) begin send(method_name, protocol.connection.id, response_message, original_request) rescue StandardError => e - unhandled_exception(e, :source => :response, :message => response_message) + unhandled_exception(e, source: :response, message: response_message) end return true end diff --git a/lib/puppet_editor_services/protocol/base.rb b/lib/puppet_editor_services/protocol/base.rb index 0fc3bdd2..1b7f5917 100644 --- a/lib/puppet_editor_services/protocol/base.rb +++ b/lib/puppet_editor_services/protocol/base.rb @@ -19,6 +19,7 @@ def close_connection def connection_error? return false if connection.nil? + connection.error? end end diff --git a/lib/puppet_editor_services/protocol/debug_adapter.rb b/lib/puppet_editor_services/protocol/debug_adapter.rb index 25dfd37e..586e0d50 100644 --- a/lib/puppet_editor_services/protocol/debug_adapter.rb +++ b/lib/puppet_editor_services/protocol/debug_adapter.rb @@ -51,6 +51,7 @@ def receive_data(data) offset = 0 while offset < @buffer.length - 4 break if @buffer[offset] == 13 && @buffer[offset + 1] == 10 && @buffer[offset + 2] == 13 && @buffer[offset + 3] == 10 + offset += 1 end return unless offset < @buffer.length - 4 @@ -85,6 +86,7 @@ def send_json_string(string) def encode_and_send(object) # Inject the sequence ID. raise "#{object.class} is not a PuppetEditorServices::Protocol::DebugAdapterMessages::ProtocolMessage" unless object.is_a?(PuppetEditorServices::Protocol::DebugAdapterMessages::ProtocolMessage) + object.seq = next_sequence_id! send_json_string(::JSON.generate(object)) end @@ -94,6 +96,7 @@ def receive_json_message_as_string(content) json_obj = ::JSON.parse(content) return receive_json_message_as_hash(json_obj) if json_obj.is_a?(Hash) return unless json_obj.is_a?(Array) + # Batch: multiple requests/notifications in an array. # NOTE: Not implemented as it doesn't make sense using JSON RPC over pure TCP / UnixSocket. diff --git a/lib/puppet_editor_services/protocol/debug_adapter_messages.rb b/lib/puppet_editor_services/protocol/debug_adapter_messages.rb index 49cf6979..39b72693 100644 --- a/lib/puppet_editor_services/protocol/debug_adapter_messages.rb +++ b/lib/puppet_editor_services/protocol/debug_adapter_messages.rb @@ -25,7 +25,7 @@ def to_json(*options) def to_h { - 'seq' => seq, + 'seq' => seq, 'type' => type } end @@ -145,8 +145,8 @@ def to_h def self.reply_error(request, message = nil, message_object = nil) Response.new( 'request_seq' => request.seq, - 'command' => request.command, - 'success' => false + 'command' => request.command, + 'success' => false ).tap do |resp| resp.message = message unless message.nil? resp.body = { 'error' => message_object } unless message_object.nil? @@ -156,8 +156,8 @@ def self.reply_error(request, message = nil, message_object = nil) def self.reply_success(request, body_content = nil) Response.new( 'request_seq' => request.seq, - 'command' => request.command, - 'success' => true + 'command' => request.command, + 'success' => true ).tap { |resp| resp.body = body_content unless body_content.nil? } end diff --git a/lib/puppet_editor_services/protocol/json_rpc.rb b/lib/puppet_editor_services/protocol/json_rpc.rb index 4e8a5579..0d2fbab2 100644 --- a/lib/puppet_editor_services/protocol/json_rpc.rb +++ b/lib/puppet_editor_services/protocol/json_rpc.rb @@ -8,31 +8,31 @@ module PuppetEditorServices module Protocol class JsonRPC < ::PuppetEditorServices::Protocol::Base - CODE_INVALID_JSON = -32700 + CODE_INVALID_JSON = -32_700 MSG_INVALID_JSON = 'invalid JSON' - CODE_INVALID_REQUEST = -32600 + CODE_INVALID_REQUEST = -32_600 MSG_INVALID_REQ_JSONRPC = "invalid request: doesn't include \"jsonrpc\": \"2.0\"" MSG_INVALID_REQ_ID = 'invalid request: wrong id' MSG_INVALID_REQ_METHOD = 'invalid request: wrong method' MSG_INVALID_REQ_PARAMS = 'invalid request: wrong params' - CODE_METHOD_NOT_FOUND = -32601 + CODE_METHOD_NOT_FOUND = -32_601 MSG_METHOD_NOT_FOUND = 'method not found' - CODE_INVALID_PARAMS = -32602 + CODE_INVALID_PARAMS = -32_602 MSG_INVALID_PARAMS = 'invalid parameter(s)' - CODE_INTERNAL_ERROR = -32603 + CODE_INTERNAL_ERROR = -32_603 MSG_INTERNAL_ERROR = 'internal error' - PARSING_ERROR_RESPONSE = '{"jsonrpc":"2.0","id":null,"error":{' \ - "\"code\":#{CODE_INVALID_JSON}," \ - "\"message\":\"#{MSG_INVALID_JSON}\"}}" + PARSING_ERROR_RESPONSE = '{"jsonrpc":"2.0","id":null,"error":{' \ + "\"code\":#{CODE_INVALID_JSON}," \ + "\"message\":\"#{MSG_INVALID_JSON}\"}}" BATCH_NOT_SUPPORTED_RESPONSE = '{"jsonrpc":"2.0","id":null,"error":{' \ - '"code":-32099,' \ - '"message":"batch mode not implemented"}}' + '"code":-32099,' \ + '"message":"batch mode not implemented"}}' KEY_JSONRPC = 'jsonrpc' JSONRPC_VERSION = '2.0' @@ -85,6 +85,7 @@ def receive_data(data) offset = 0 while offset < @buffer.length - 4 break if @buffer[offset] == 13 && @buffer[offset + 1] == 10 && @buffer[offset + 2] == 13 && @buffer[offset + 3] == 10 + offset += 1 end return unless offset < @buffer.length - 4 @@ -125,6 +126,7 @@ def receive_json_message_as_string(content) json_obj = ::JSON.parse(content) return receive_json_message_as_hash(json_obj) if json_obj.is_a?(Hash) return unless json_obj.is_a?(Array) + # Batch: multiple requests/notifications in an array. # NOTE: Not implemented as it doesn't make sense using JSON RPC over pure TCP / UnixSocket. @@ -185,7 +187,7 @@ def receive_json_message_as_hash(json_obj) return true elsif is_response # Responses are special as they need the context of the original request - handler.handle(PuppetEditorServices::Protocol::JsonRPCMessages::ResponseMessage.new(json_obj), :request => original_request) + handler.handle(PuppetEditorServices::Protocol::JsonRPCMessages::ResponseMessage.new(json_obj), request: original_request) return true end false diff --git a/lib/puppet_editor_services/protocol/json_rpc_messages.rb b/lib/puppet_editor_services/protocol/json_rpc_messages.rb index 86c5999a..97adcb1c 100644 --- a/lib/puppet_editor_services/protocol/json_rpc_messages.rb +++ b/lib/puppet_editor_services/protocol/json_rpc_messages.rb @@ -16,6 +16,7 @@ def initialize(initial_hash = nil) def from_h!(value) return self if value.nil? || value.empty? + # jsonrpc is a little special. Don't override it with nil. This # allows `.new.from_h!(..)` to use the default without knowing exactly # what version is used. @@ -66,7 +67,7 @@ def from_h!(value) def to_h super.merge( - 'id' => id, + 'id' => id, 'method' => rpc_method, 'params' => params ) @@ -171,9 +172,9 @@ def self.reply_error_by_id(id, code, message) # Note - Strictly speaking the error should be typed object, however as this hidden behind # this method it's easier to just pass in a known hash construct ResponseMessage.new.from_h!( - 'id' => id, + 'id' => id, 'error' => { - 'code' => code, + 'code' => code, 'message' => message } ) diff --git a/lib/puppet_editor_services/server.rb b/lib/puppet_editor_services/server.rb index 8be42f61..e2346516 100644 --- a/lib/puppet_editor_services/server.rb +++ b/lib/puppet_editor_services/server.rb @@ -5,7 +5,7 @@ module PuppetEditorServices module Server def self.current_server - @@current_server # rubocop:disable Style/ClassVars This is fine + @@current_server # This is fine end def self.current_server=(value) diff --git a/lib/puppet_editor_services/server/stdio.rb b/lib/puppet_editor_services/server/stdio.rb index b0b5e93a..2108447f 100644 --- a/lib/puppet_editor_services/server/stdio.rb +++ b/lib/puppet_editor_services/server/stdio.rb @@ -38,6 +38,7 @@ def start inbound_data = nil read_from_pipe($stdin, 2) { |data| inbound_data = data } break if @exiting + @client_connection.receive_data(inbound_data) unless inbound_data.nil? break if @exiting end @@ -70,7 +71,7 @@ def read_from_pipe(pipe, timeout = 0.1, &_block) rescue EOFError log('Reading from pipe has reached End of File. Exiting STDIO server') stop - rescue # rubocop:disable Style/RescueStandardError, Lint/SuppressedException + rescue # rubocop:disable Style/RescueStandardError # Any errors here should be swallowed because the pipe could be in any state end # since readpartial may return a nil at EOF, skip returning that value diff --git a/lib/puppet_editor_services/server/tcp.rb b/lib/puppet_editor_services/server/tcp.rb index cc3eee26..4922788a 100644 --- a/lib/puppet_editor_services/server/tcp.rb +++ b/lib/puppet_editor_services/server/tcp.rb @@ -42,8 +42,9 @@ def name # this code will be called when a socket recieves data. # @api private def get_data(io, connection_data) - data = io.recv_nonblock(1048576) # with maximum number of bytes to read at a time... + data = io.recv_nonblock(1_048_576) # with maximum number of bytes to read at a time... raise 'Received a 0byte payload' if data.length.zero? + # We're already in a callback so no need to invoke as a callback connection_data[:handler].receive_data(data) rescue StandardError => e @@ -164,6 +165,7 @@ def callback(object, method, *args, &block) def fire_event event = self.class.e_locker.synchronize { self.class.events.shift } return false unless event + begin event[0].call(*event[1]) rescue OpenSSL::SSL::SSLError @@ -186,15 +188,17 @@ def fire_event def io_review self.class.io_locker.synchronize do return false unless self.class.events.empty? + united = self.class.services.keys + self.class.io_connection_dic.keys return false if united.empty? + io_r = IO.select(united, nil, united, 0.1) if io_r io_r[0].each do |io| if self.class.services[io] begin callback(self, :add_connection, io.accept_nonblock, self.class.services[io]) - rescue Errno::EWOULDBLOCK # rubocop:disable Lint/SuppressedException + rescue Errno::EWOULDBLOCK # There's nothing to handle. Swallow the error rescue StandardError => e log(e.message) @@ -208,12 +212,10 @@ def io_review end end io_r[2].each do |io| - begin - (remove_connection(io) || self.class.services.delete(io)).close - rescue # rubocop:disable Style/RescueStandardError - # Swallow all errors - true - end + (remove_connection(io) || self.class.services.delete(io)).close + rescue # rubocop:disable Style/RescueStandardError + # Swallow all errors + true end end end @@ -274,12 +276,10 @@ def remove_connection_async(io) def stop_connections self.class.c_locker.synchronize do self.class.io_connection_dic.each_key do |io| - begin - io.close - rescue # rubocop:disable Style/RescueStandardError - # Swallow all errors - true - end + io.close + rescue # rubocop:disable Style/RescueStandardError + # Swallow all errors + true end self.class.io_connection_dic.clear end @@ -331,6 +331,7 @@ def remove_connection(io) end return unless connection_count.zero? && !@server_options[:stop_on_client_exit].nil? && @server_options[:stop_on_client_exit] + callback(self, :log, 'All clients have disconnected. Shutting down server.') callback(self, :stop_services) end diff --git a/lib/puppet_languageserver.rb b/lib/puppet_languageserver.rb index 2a1cf1fd..2e148f97 100644 --- a/lib/puppet_languageserver.rb +++ b/lib/puppet_languageserver.rb @@ -34,6 +34,7 @@ def self.configure_featureflags(flags) def self.featureflag?(flagname) return false if @flags.nil? || @flags.empty? + @flags.include?(flagname) end @@ -62,11 +63,9 @@ def self.require_gems(options) message_handler server_capabilities ].each do |lib| - begin - require "puppet-languageserver/#{lib}" - rescue LoadError - require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver', lib)) - end + require "puppet-languageserver/#{lib}" + rescue LoadError + require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver', lib)) end begin @@ -90,11 +89,9 @@ def self.require_gems(options) puppet_monkey_patches providers ].each do |lib| - begin - require "puppet-languageserver/#{lib}" - rescue LoadError - require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver', lib)) - end + require "puppet-languageserver/#{lib}" + rescue LoadError + require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver', lib)) end # Validate the feature flags @@ -239,8 +236,8 @@ def self.rpc_server(options) require 'puppet_editor_services/protocol/json_rpc' server_options = options - protocol_options = { :class => PuppetEditorServices::Protocol::JsonRPC }.merge(options) - handler_options = { :class => PuppetLanguageServer::MessageHandler }.merge(options) + protocol_options = { class: PuppetEditorServices::Protocol::JsonRPC }.merge(options) + handler_options = { class: PuppetLanguageServer::MessageHandler }.merge(options) unless active? handler_options[:class] = PuppetLanguageServer::DisabledMessageHandler diff --git a/lib/puppet_languageserver_sidecar.rb b/lib/puppet_languageserver_sidecar.rb index 507c493f..ddcaba77 100644 --- a/lib/puppet_languageserver_sidecar.rb +++ b/lib/puppet_languageserver_sidecar.rb @@ -12,11 +12,9 @@ %w[ sidecar_protocol ].each do |lib| - begin - require "puppet-languageserver/#{lib}" - rescue LoadError - require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver', lib)) - end + require "puppet-languageserver/#{lib}" + rescue LoadError + require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver', lib)) end ensure $VERBOSE = original_verbose @@ -33,6 +31,7 @@ def self.configure_featureflags(flags) def self.featureflag?(flagname) return false if @flags.nil? || @flags.empty? + @flags.include?(flagname) end @@ -76,11 +75,9 @@ def self.require_gems(options) ] require_list.each do |lib| - begin - require "puppet-languageserver-sidecar/#{lib}" - rescue LoadError - require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver-sidecar', lib)) - end + require "puppet-languageserver-sidecar/#{lib}" + rescue LoadError + require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver-sidecar', lib)) end ensure $VERBOSE = original_verbose @@ -213,11 +210,9 @@ def self.inject_workspace_as_module return false unless PuppetLanguageServerSidecar::Workspace.has_module_metadata? %w[puppet_modulepath_monkey_patches].each do |lib| - begin - require "puppet-languageserver-sidecar/#{lib}" - rescue LoadError - require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver-sidecar', lib)) - end + require "puppet-languageserver-sidecar/#{lib}" + rescue LoadError + require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver-sidecar', lib)) end log_message(:debug, 'Injected the workspace into the module loader') @@ -230,11 +225,9 @@ def self.inject_workspace_as_environment Puppet.settings[:environment] = PuppetLanguageServerSidecar::PuppetHelper::SIDECAR_PUPPET_ENVIRONMENT %w[puppet_environment_monkey_patches].each do |lib| - begin - require "puppet-languageserver-sidecar/#{lib}" - rescue LoadError - require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver-sidecar', lib)) - end + require "puppet-languageserver-sidecar/#{lib}" + rescue LoadError + require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver-sidecar', lib)) end log_message(:debug, 'Injected the workspace into the environment loader') @@ -254,23 +247,23 @@ def self.execute(options) when 'default_aggregate' cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new - PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, :object_types => PuppetLanguageServerSidecar::PuppetHelper.available_documentation_types) + PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, object_types: PuppetLanguageServerSidecar::PuppetHelper.available_documentation_types) when 'default_classes' cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new - PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, :object_types => [:class]).classes + PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, object_types: [:class]).classes when 'default_datatypes' cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new - PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, :object_types => [:datatype]).datatypes + PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, object_types: [:datatype]).datatypes when 'default_functions' cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new - PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, :object_types => [:function]).functions + PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, object_types: [:function]).functions when 'default_types' cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new - PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, :object_types => [:type]).types + PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, object_types: [:type]).types when 'node_graph' inject_workspace_as_module || inject_workspace_as_environment @@ -299,38 +292,43 @@ def self.execute(options) when 'workspace_aggregate' return nil unless inject_workspace_as_module || inject_workspace_as_environment + cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, - :object_types => PuppetLanguageServerSidecar::PuppetHelper.available_documentation_types, - :root_path => PuppetLanguageServerSidecar::Workspace.root_path) + object_types: PuppetLanguageServerSidecar::PuppetHelper.available_documentation_types, + root_path: PuppetLanguageServerSidecar::Workspace.root_path) when 'workspace_classes' return nil unless inject_workspace_as_module || inject_workspace_as_environment + cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, - :object_types => [:class], - :root_path => PuppetLanguageServerSidecar::Workspace.root_path).classes + object_types: [:class], + root_path: PuppetLanguageServerSidecar::Workspace.root_path).classes when 'workspace_datatypes' return nil unless inject_workspace_as_module || inject_workspace_as_environment + cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, - :object_types => [:datatype], - :root_path => PuppetLanguageServerSidecar::Workspace.root_path).datatypes + object_types: [:datatype], + root_path: PuppetLanguageServerSidecar::Workspace.root_path).datatypes when 'workspace_functions' return nil unless inject_workspace_as_module || inject_workspace_as_environment + cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, - :object_types => [:function], - :root_path => PuppetLanguageServerSidecar::Workspace.root_path).functions + object_types: [:function], + root_path: PuppetLanguageServerSidecar::Workspace.root_path).functions when 'workspace_types' return nil unless inject_workspace_as_module || inject_workspace_as_environment + cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, - :object_types => [:type], - :root_path => PuppetLanguageServerSidecar::Workspace.root_path).types + object_types: [:type], + root_path: PuppetLanguageServerSidecar::Workspace.root_path).types when 'facts' # Can't cache for facts diff --git a/spec/languageserver-sidecar/integration/puppet-languageserver-sidecar/puppet-languageserver-sidecar_spec.rb b/spec/languageserver-sidecar/integration/puppet-languageserver-sidecar/puppet-languageserver-sidecar_spec.rb index c5f749ff..c30281dc 100644 --- a/spec/languageserver-sidecar/integration/puppet-languageserver-sidecar/puppet-languageserver-sidecar_spec.rb +++ b/spec/languageserver-sidecar/integration/puppet-languageserver-sidecar/puppet-languageserver-sidecar_spec.rb @@ -73,7 +73,7 @@ def should_not_contain_default_functions(deserial) def expect_empty_cache cache = PuppetLanguageServerSidecar::Cache::FileSystem.new - expect(Dir.exists?(cache.cache_dir)).to eq(true), "Expected the cache directory #{cache.cache_dir} to exist" + expect(Dir.exist?(cache.cache_dir)).to eq(true), "Expected the cache directory #{cache.cache_dir} to exist" expect(Dir.glob(File.join(cache.cache_dir,'*')).count).to eq(0), "Expected the cache directory #{cache.cache_dir} to be empty" end diff --git a/spec/languageserver/acceptance/end_to_end_spec.rb b/spec/languageserver/acceptance/end_to_end_spec.rb index 8289cd07..7df0aff5 100644 --- a/spec/languageserver/acceptance/end_to_end_spec.rb +++ b/spec/languageserver/acceptance/end_to_end_spec.rb @@ -149,7 +149,7 @@ def path_to_uri(path) # Puppet Resource request @client.clear_messages! @client.send_data(@client.puppet_getresource_request(@client.next_seq_id, 'user')) - expect(@client).to receive_message_with_request_id_within_timeout([@client.current_seq_id, 15]) + expect(@client).to receive_message_with_request_id_within_timeout([@client.current_seq_id, 25]) result = @client.data_from_request_seq_id(@client.current_seq_id) # Expect something to be returned expect(result['result']['data']).not_to be_nil @@ -158,7 +158,7 @@ def path_to_uri(path) # Node Graph request @client.clear_messages! @client.send_data(@client.puppet_compilenodegraph_request(@client.next_seq_id, manifest_uri)) - expect(@client).to receive_message_with_request_id_within_timeout([@client.current_seq_id, 5]) + expect(@client).to receive_message_with_request_id_within_timeout([@client.current_seq_id, 25]) result = @client.data_from_request_seq_id(@client.current_seq_id) # Expect something to be returned expect(result['result']['edges']).to be_empty diff --git a/spec/languageserver/unit/puppet-languageserver/puppetfile/validation_provider_spec.rb b/spec/languageserver/unit/puppet-languageserver/puppetfile/validation_provider_spec.rb index f6068fbd..06ef22b1 100644 --- a/spec/languageserver/unit/puppet-languageserver/puppetfile/validation_provider_spec.rb +++ b/spec/languageserver/unit/puppet-languageserver/puppetfile/validation_provider_spec.rb @@ -466,7 +466,8 @@ def load(name) :owner=>"puppetlabs", :start_line=>3, :title=>"puppetlabs-somemodule", - :version=>"1.0.0"}]) + :version=>"=1.0.0"}]) + # version requirements returned explicity by puppetfile-resolver since https://github.com/glennsarti/puppetfile-resolver/pull/16 end end diff --git a/vendor/README.md b/vendor/README.md index b0199b74..a59dbf41 100644 --- a/vendor/README.md +++ b/vendor/README.md @@ -11,10 +11,10 @@ Note - To improve the packaging size, test files etc. were stripped from the Gem Gem List -------- -* puppet-lint (https://github.com/puppetlabs/puppet-lint.git ref 2.5.2) +* puppet-lint (https://github.com/puppetlabs/puppet-lint.git ref v4.2.0) * hiera-eyaml (https://github.com/voxpupuli/hiera-eyaml ref v2.1.0) * puppetfile-resolver (https://github.com/glennsarti/puppetfile-resolver.git ref 0.3.0) * molinillo (https://github.com/CocoaPods/Molinillo.git ref 0.6.6) -* puppet-strings (https://github.com/puppetlabs/puppet-strings.git ref v2.4.0) +* puppet-strings (https://github.com/puppetlabs/puppet-strings.git ref v4.1.0) * yard (https://github.com/lsegal/yard.git ref v0.9.24)