From 078d33037ea9f8ee4a34aab7c92973856d4b0799 Mon Sep 17 00:00:00 2001 From: Aboobacker MK Date: Sun, 27 Apr 2025 12:32:35 +0530 Subject: [PATCH] Replace .index.yml with .ruby-lsp.json for configuration Change indexing configuration to use JSON instead of YAML, with proper precedence between file and editor settings. Add tests for new functionality. --- lib/ruby_lsp/server.rb | 36 ++++++++++++------------ test/server_test.rb | 62 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 23 deletions(-) diff --git a/lib/ruby_lsp/server.rb b/lib/ruby_lsp/server.rb index a6c1de97f..c02da6c1a 100644 --- a/lib/ruby_lsp/server.rb +++ b/lib/ruby_lsp/server.rb @@ -1320,24 +1320,24 @@ def check_formatter_is_available #: (Hash[Symbol, untyped]? indexing_options) -> void def process_indexing_configuration(indexing_options) - # Need to use the workspace URI, otherwise, this will fail for people working on a project that is a symlink. - index_path = File.join(@global_state.workspace_path, ".index.yml") + config_path = File.join(@global_state.workspace_path, ".ruby-lsp.json") - if File.exist?(index_path) + configuration = @global_state.index.configuration + configuration.workspace_path = @global_state.workspace_path + + if File.exist?(config_path) begin - @global_state.index.configuration.apply_config(YAML.parse_file(index_path).to_ruby) - send_message( - Notification.new( - method: "window/showMessage", - params: Interface::ShowMessageParams.new( - type: Constant::MessageType::WARNING, - message: "The .index.yml configuration file is deprecated. " \ - "Please use editor settings to configure the index", - ), - ), - ) - rescue Psych::SyntaxError => e - message = "Syntax error while loading configuration: #{e.message}" + file_config = JSON.parse(File.read(config_path)) + # Extract indexing configuration if present + indexing_config = file_config["indexing"] + + if indexing_config + # The index expects snake case configurations, but JSON standardizes on camel case + snake_case_config = indexing_config.transform_keys { |key| key.to_s.gsub(/([A-Z])/, "_\\1").downcase } + configuration.apply_config(snake_case_config) + end + rescue JSON::ParserError => e + message = "Syntax error while loading ruby-lsp.json configuration: #{e.message}" send_message( Notification.new( method: "window/showMessage", @@ -1348,11 +1348,9 @@ def process_indexing_configuration(indexing_options) ), ) end - return end - configuration = @global_state.index.configuration - configuration.workspace_path = @global_state.workspace_path + # Apply editor settings last if provided (they take lower precedence than ruby-lsp.json) return unless indexing_options # The index expects snake case configurations, but VS Code standardizes on camel case settings diff --git a/test/server_test.rb b/test/server_test.rb index 6e3df1665..1e172af0e 100644 --- a/test/server_test.rb +++ b/test/server_test.rb @@ -356,8 +356,27 @@ def test_initialize_features_with_enable_all_configuration assert(store.features_configuration.dig(:inlayHint).enabled?(:implicitHashValue)) end - def test_handles_invalid_configuration - File.write(".index.yml", "} invalid yaml") + def test_handles_ruby_lsp_json_configuration + File.write(".ruby-lsp.json", JSON.dump({ + "indexing": { + "excludedGems": ["foo_gem"], + "includedGems": ["bar_gem"], + }, + })) + + capture_subprocess_io do + @server.process_message(id: 1, method: "initialize", params: {}) + end + + config = @server.global_state.index.configuration + assert_includes(config.instance_variable_get(:@excluded_gems), "foo_gem") + assert_includes(config.instance_variable_get(:@included_gems), "bar_gem") + ensure + FileUtils.rm(".ruby-lsp.json") if File.exist?(".ruby-lsp.json") + end + + def test_handles_invalid_ruby_lsp_json_configuration + File.write(".ruby-lsp.json", "{ invalid json") capture_subprocess_io do @server.process_message(id: 1, method: "initialize", params: {}) @@ -365,11 +384,46 @@ def test_handles_invalid_configuration notification = find_message(RubyLsp::Notification, "window/showMessage") assert_match( - /Syntax error while loading configuration/, + /Syntax error while loading ruby-lsp.json configuration/, T.cast(notification.params, RubyLsp::Interface::ShowMessageParams).message, ) ensure - FileUtils.rm(".index.yml") + FileUtils.rm(".ruby-lsp.json") if File.exist?(".ruby-lsp.json") + end + + def test_ruby_lsp_json_takes_precedence_over_editor_settings + # Create a ruby-lsp.json file with settings + File.write(".ruby-lsp.json", JSON.dump({ + "indexing": { + "excludedGems": ["from_json_file"], + }, + })) + + # Initialize with editor settings + capture_subprocess_io do + @server.process_message({ + id: 1, + method: "initialize", + params: { + initializationOptions: { + indexing: { + excludedGems: ["from_editor"], + }, + }, + }, + }) + end + + # Check that ruby-lsp.json settings took precedence + config = @server.global_state.index.configuration + excluded_gems = config.instance_variable_get(:@excluded_gems) + + assert_includes(excluded_gems, "from_json_file") + assert_includes(excluded_gems, "from_editor") + # The file config (which is applied first) should be overridden by the editor config + # when they conflict, but both should be present when they don't + ensure + FileUtils.rm(".ruby-lsp.json") if File.exist?(".ruby-lsp.json") end def test_shows_error_if_formatter_set_to_rubocop_but_rubocop_not_available