Skip to content

Replace .index.yml with .ruby-lsp.json for configuration #3417

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 17 additions & 19 deletions lib/ruby_lsp/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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
Expand Down
62 changes: 58 additions & 4 deletions test/server_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -356,20 +356,74 @@ 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: {})
end

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
Expand Down
Loading