# typed: strict# frozen_string_literal: truemoduleRubyLspclassGlobalState#: Stringattr_reader:test_library#: Stringattr_accessor:formatter#: boolattr_reader:has_type_checker#: RubyIndexer::Indexattr_reader:index#: Encodingattr_reader:encoding#: boolattr_reader:top_level_bundle#: TypeInferrerattr_reader:type_inferrer#: ClientCapabilitiesattr_reader:client_capabilities#: URI::Genericattr_reader:workspace_uri#: String?attr_reader:telemetry_machine_id#: -> voiddefinitialize@workspace_uri=URI::Generic.from_path(path: Dir.pwd)#: URI::Generic@encoding=Encoding::UTF_8#: Encoding@formatter="auto"#: String@linters=[]#: Array[String]@test_library="minitest"#: String@has_type_checker=true#: bool@index=RubyIndexer::Index.new#: RubyIndexer::Index@supported_formatters={}#: Hash[String, Requests::Support::Formatter]@type_inferrer=TypeInferrer.new(@index)#: TypeInferrer@addon_settings={}#: Hash[String, untyped]@top_level_bundle=beginBundler.with_original_env{Bundler.default_gemfile}truerescueBundler::GemfileNotFound,Bundler::GitErrorfalseend#: bool@client_capabilities=ClientCapabilities.new#: ClientCapabilities@enabled_feature_flags={}#: Hash[Symbol, bool]@mutex=Mutex.new#: Mutex@telemetry_machine_id=nil#: String?@feature_configuration={inlayHint: RequestConfig.new({enableAll: false,implicitRescue: false,implicitHashValue: false,}),codeLens: RequestConfig.new({enableAll: false,enableTestCodeLens: true,}),}#: Hash[Symbol, RequestConfig]end#: [T] { -> T } -> Tdefsynchronize(&block)@mutex.synchronize(&block)end#: (String addon_name) -> Hash[Symbol, untyped]?defsettings_for_addon(addon_name)@addon_settings[addon_name]end#: (String identifier, Requests::Support::Formatter instance) -> voiddefregister_formatter(identifier,instance)@supported_formatters[identifier]=instanceend#: -> Requests::Support::Formatter?defactive_formatter@supported_formatters[@formatter]end#: -> Array[Requests::Support::Formatter]defactive_linters@linters.filter_map{|name|@supported_formatters[name]}end# Applies the options provided by the editor and returns an array of notifications to send back to the client#: (Hash[Symbol, untyped] options) -> Array[Notification]defapply_options(options)notifications=[]direct_dependencies=gather_direct_dependenciesall_dependencies=gather_direct_and_indirect_dependenciesworkspace_uri=options.dig(:workspaceFolders,0,:uri)@workspace_uri=URI(workspace_uri)ifworkspace_urispecified_formatter=options.dig(:initializationOptions,:formatter)rubocop_has_addon=defined?(::RuboCop::Version::STRING)&&Gem::Requirement.new(">= 1.70.0").satisfied_by?(Gem::Version.new(::RuboCop::Version::STRING))ifspecified_formatter@formatter=specified_formatterifspecified_formatter!="auto"notifications<<Notification.window_log_message("Using formatter specified by user: #{@formatter}")end# If the user had originally configured to use `rubocop`, but their version doesn't provide the add-on yet,# fallback to the internal integrationifspecified_formatter=="rubocop"&&!rubocop_has_addon@formatter="rubocop_internal"endendif@formatter=="auto"@formatter=detect_formatter(direct_dependencies,all_dependencies)notifications<<Notification.window_log_message("Auto detected formatter: #{@formatter}")endspecified_linters=options.dig(:initializationOptions,:linters)ifspecified_formatter=="rubocop"||specified_linters&.include?("rubocop")notifications<<Notification.window_log_message(<<~MESSAGE,type: Constant::MessageType::WARNING)
Formatter is configured to be `rubocop`. As of RuboCop v1.70.0, this identifier activates the add-on
implemented in the rubocop gem itself instead of the internal integration provided by the Ruby LSP.
If you wish to use the internal integration, please configure the formatter as `rubocop_internal`.
MESSAGEend# If the user had originally configured to use `rubocop`, but their version doesn't provide the add-on yet,# fall back to the internal integrationifspecified_linters&.include?("rubocop")&&!rubocop_has_addonspecified_linters.delete("rubocop")specified_linters<<"rubocop_internal"end@linters=specified_linters||detect_linters(direct_dependencies,all_dependencies)notifications<<ifspecified_lintersNotification.window_log_message("Using linters specified by user: #{@linters.join(", ")}")elseNotification.window_log_message("Auto detected linters: #{@linters.join(", ")}")end@test_library=detect_test_library(direct_dependencies)notifications<<Notification.window_log_message("Detected test library: #{@test_library}")@has_type_checker=detect_typechecker(all_dependencies)if@has_type_checkernotifications<<Notification.window_log_message("Ruby LSP detected this is a Sorbet project and will defer to the Sorbet LSP for some functionality",)endencodings=options.dig(:capabilities,:general,:positionEncodings)@encoding=if!encodings||encodings.empty?Encoding::UTF_16LEelsifencodings.include?(Constant::PositionEncodingKind::UTF8)Encoding::UTF_8elsifencodings.include?(Constant::PositionEncodingKind::UTF16)Encoding::UTF_16LEelseEncoding::UTF_32end@index.configuration.encoding=@encoding@client_capabilities.apply_client_capabilities(options[:capabilities])ifoptions[:capabilities]addon_settings=options.dig(:initializationOptions,:addonSettings)ifaddon_settingsaddon_settings.transform_keys!(&:to_s)@addon_settings.merge!(addon_settings)endenabled_flags=options.dig(:initializationOptions,:enabledFeatureFlags)@enabled_feature_flags=enabled_flagsifenabled_flags@telemetry_machine_id=options.dig(:initializationOptions,:telemetryMachineId)options.dig(:initializationOptions,:featuresConfiguration)&.eachdo|feature_name,config|@feature_configuration[feature_name]&.merge!(config)endnotificationsend#: (Symbol) -> RequestConfig?deffeature_configuration(feature_name)@feature_configuration[feature_name]end#: (Symbol flag) -> bool?defenabled_feature?(flag)@enabled_feature_flags[:all]||@enabled_feature_flags[flag]end#: -> Stringdefworkspace_path@workspace_uri.to_standardized_path#: as !nilend#: -> Stringdefencoding_namecase@encodingwhenEncoding::UTF_8Constant::PositionEncodingKind::UTF8whenEncoding::UTF_16LEConstant::PositionEncodingKind::UTF16elseConstant::PositionEncodingKind::UTF32endend#: -> booldefsupports_watching_files@client_capabilities.supports_watching_filesendprivate#: (Array[String] direct_dependencies, Array[String] all_dependencies) -> Stringdefdetect_formatter(direct_dependencies,all_dependencies)# NOTE: Intentionally no $ at end, since we want to match rubocop-shopify, etc.return"rubocop_internal"ifdirect_dependencies.any?(/^rubocop/)syntax_tree_is_direct_dependency=direct_dependencies.include?("syntax_tree")return"syntax_tree"ifsyntax_tree_is_direct_dependencyrubocop_is_transitive_dependency=all_dependencies.include?("rubocop")return"rubocop_internal"ifdot_rubocop_yml_present&&rubocop_is_transitive_dependency"none"end# Try to detect if there are linters in the project's dependencies. For auto-detection, we always only consider a# single linter. To have multiple linters running, the user must configure them manually#: (Array[String] dependencies, Array[String] all_dependencies) -> Array[String]defdetect_linters(dependencies,all_dependencies)linters=[]ifdependencies.any?(/^rubocop/)||(all_dependencies.include?("rubocop")&&dot_rubocop_yml_present)linters<<"rubocop_internal"endlintersend#: (Array[String] dependencies) -> Stringdefdetect_test_library(dependencies)ifdependencies.any?(/^rspec/)"rspec"# A Rails app may have a dependency on minitest, but we would instead want to use the Rails test runner provided# by ruby-lsp-rails. A Rails app doesn't need to depend on the rails gem itself, individual components like# activestorage may be added to the gemfile so that other components aren't downloaded. Check for the presence# of bin/rails to support these cases.elsifbin_rails_present"rails"# NOTE: Intentionally ends with $ to avoid mis-matching minitest-reporters, etc. in a Rails app.elsifdependencies.any?(/^minitest$/)"minitest"elsifdependencies.any?(/^test-unit/)"test-unit"else"unknown"endend#: (Array[String] dependencies) -> booldefdetect_typechecker(dependencies)returnfalseifENV["RUBY_LSP_BYPASS_TYPECHECKER"]dependencies.any?(/^sorbet-static/)rescueBundler::GemfileNotFoundfalseend#: -> booldefbin_rails_presentFile.exist?(File.join(workspace_path,"bin/rails"))end#: -> booldefdot_rubocop_yml_presentFile.exist?(File.join(workspace_path,".rubocop.yml"))end#: -> Array[String]defgather_direct_dependenciesBundler.with_original_env{Bundler.default_gemfile}dependencies=Bundler.locked_gems&.dependencies&.keys||[]dependencies+gemspec_dependenciesrescueBundler::GemfileNotFound[]end#: -> Array[String]defgemspec_dependencies(Bundler.locked_gems&.sources||[]).grep(Bundler::Source::Gemspec).flat_map{_1.gemspec&.dependencies&.map(&:name)}end#: -> Array[String]defgather_direct_and_indirect_dependenciesBundler.with_original_env{Bundler.default_gemfile}Bundler.locked_gems&.specs&.map(&:name)||[]rescueBundler::GemfileNotFound[]endendend