Skip to content

Commit e5244f6

Browse files
authored
Move feature configuration to global state (#3613)
1 parent e456bdf commit e5244f6

File tree

9 files changed

+117
-99
lines changed

9 files changed

+117
-99
lines changed

lib/ruby_lsp/global_state.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ def initialize
5656
@enabled_feature_flags = {} #: Hash[Symbol, bool]
5757
@mutex = Mutex.new #: Mutex
5858
@telemetry_machine_id = nil #: String?
59+
@feature_configuration = {
60+
inlayHint: RequestConfig.new({
61+
enableAll: false,
62+
implicitRescue: false,
63+
implicitHashValue: false,
64+
}),
65+
} #: Hash[Symbol, RequestConfig]
5966
end
6067

6168
#: [T] { -> T } -> T
@@ -175,9 +182,19 @@ def apply_options(options)
175182
@enabled_feature_flags = enabled_flags if enabled_flags
176183

177184
@telemetry_machine_id = options.dig(:initializationOptions, :telemetryMachineId)
185+
186+
options.dig(:initializationOptions, :featuresConfiguration)&.each do |feature_name, config|
187+
@feature_configuration[feature_name]&.merge!(config)
188+
end
189+
178190
notifications
179191
end
180192

193+
#: (Symbol) -> RequestConfig?
194+
def feature_configuration(feature_name)
195+
@feature_configuration[feature_name]
196+
end
197+
181198
#: (Symbol flag) -> bool?
182199
def enabled_feature?(flag)
183200
@enabled_feature_flags[:all] || @enabled_feature_flags[flag]

lib/ruby_lsp/listeners/inlay_hints.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ class InlayHints
88

99
RESCUE_STRING_LENGTH = "rescue".length #: Integer
1010

11-
#: (ResponseBuilders::CollectionResponseBuilder[Interface::InlayHint] response_builder, RequestConfig hints_configuration, Prism::Dispatcher dispatcher) -> void
12-
def initialize(response_builder, hints_configuration, dispatcher)
11+
#: (GlobalState, ResponseBuilders::CollectionResponseBuilder[Interface::InlayHint], Prism::Dispatcher) -> void
12+
def initialize(global_state, response_builder, dispatcher)
1313
@response_builder = response_builder
14-
@hints_configuration = hints_configuration
14+
@hints_configuration = ( # rubocop:disable Style/RedundantParentheses
15+
global_state.feature_configuration(:inlayHint) #: as !nil
16+
) #: RequestConfig
1517

1618
dispatcher.register(self, :on_rescue_node_enter, :on_implicit_node_enter)
1719
end

lib/ruby_lsp/requests/inlay_hints.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ def provider
1616
end
1717
end
1818

19-
#: ((RubyDocument | ERBDocument) document, RequestConfig hints_configuration, Prism::Dispatcher dispatcher) -> void
20-
def initialize(document, hints_configuration, dispatcher)
19+
#: (GlobalState, (RubyDocument | ERBDocument), Prism::Dispatcher) -> void
20+
def initialize(global_state, document, dispatcher)
2121
super()
2222

2323
@response_builder = ResponseBuilders::CollectionResponseBuilder
2424
.new #: ResponseBuilders::CollectionResponseBuilder[Interface::InlayHint]
25-
Listeners::InlayHints.new(@response_builder, hints_configuration, dispatcher)
25+
Listeners::InlayHints.new(global_state, @response_builder, dispatcher)
2626
end
2727

2828
# @override

lib/ruby_lsp/server.rb

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,6 @@ def run_initialize(message)
209209

210210
configured_features = options.dig(:initializationOptions, :enabledFeatures)
211211

212-
configured_hints = options.dig(:initializationOptions, :featuresConfiguration, :inlayHint)
213-
@store.features_configuration.dig(:inlayHint) #: as !nil
214-
.configuration.merge!(configured_hints) if configured_hints
215-
216212
enabled_features = case configured_features
217213
when Array
218214
# If the configuration is using an array, then absent features are disabled and present ones are enabled. That's
@@ -479,8 +475,8 @@ def run_combined_requests(message)
479475
document_symbol = Requests::DocumentSymbol.new(uri, dispatcher)
480476
document_link = Requests::DocumentLink.new(uri, parse_result.comments, dispatcher)
481477
inlay_hint = Requests::InlayHints.new(
478+
@global_state,
482479
document,
483-
@store.features_configuration.dig(:inlayHint), #: as !nil
484480
dispatcher,
485481
)
486482

@@ -827,15 +823,14 @@ def text_document_inlay_hint(message)
827823
return
828824
end
829825

830-
hints_configurations = @store.features_configuration.dig(:inlayHint) #: as !nil
831826
dispatcher = Prism::Dispatcher.new
832827

833828
unless document.is_a?(RubyDocument) || document.is_a?(ERBDocument)
834829
send_empty_response(message[:id])
835830
return
836831
end
837832

838-
request = Requests::InlayHints.new(document, hints_configurations, dispatcher)
833+
request = Requests::InlayHints.new(@global_state, document, dispatcher)
839834
dispatcher.visit(document.ast)
840835
result = request.perform
841836
document.cache_set("textDocument/inlayHint", result)

lib/ruby_lsp/store.rb

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,13 @@ module RubyLsp
55
class Store
66
class NonExistingDocumentError < StandardError; end
77

8-
#: Hash[Symbol, RequestConfig]
9-
attr_accessor :features_configuration
10-
118
#: String
129
attr_accessor :client_name
1310

1411
#: (GlobalState global_state) -> void
1512
def initialize(global_state)
1613
@global_state = global_state
1714
@state = {} #: Hash[String, Document[untyped]]
18-
@features_configuration = {
19-
inlayHint: RequestConfig.new({
20-
enableAll: false,
21-
implicitRescue: false,
22-
implicitHashValue: false,
23-
}),
24-
} #: Hash[Symbol, RequestConfig]
2515
@client_name = "Unknown" #: String
2616
end
2717

lib/ruby_lsp/utils.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,9 +247,6 @@ def to_hash
247247

248248
# A request configuration, to turn on/off features
249249
class RequestConfig
250-
#: Hash[Symbol, bool]
251-
attr_accessor :configuration
252-
253250
#: (Hash[Symbol, bool] configuration) -> void
254251
def initialize(configuration)
255252
@configuration = configuration
@@ -259,6 +256,11 @@ def initialize(configuration)
259256
def enabled?(feature)
260257
@configuration[:enableAll] || @configuration[feature]
261258
end
259+
260+
#: (Hash[Symbol, bool]) -> void
261+
def merge!(hash)
262+
@configuration.merge!(hash)
263+
end
262264
end
263265

264266
class SorbetLevel

test/global_state_test.rb

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,67 @@ def test_saves_telemetry_machine_id
314314
assert_equal("test_machine_id", state.telemetry_machine_id)
315315
end
316316

317+
def test_default_feature_configuration
318+
state = GlobalState.new
319+
320+
inlay_hint_config = state.feature_configuration(:inlayHint) #: as !nil
321+
refute(inlay_hint_config.enabled?(:implicitRescue))
322+
refute(inlay_hint_config.enabled?(:implicitHashValue))
323+
end
324+
325+
def test_feature_configuration_with_provided_configuration
326+
state = GlobalState.new
327+
state.apply_options({
328+
initializationOptions: {
329+
featuresConfiguration: {
330+
inlayHint: {
331+
implicitRescue: true,
332+
implicitHashValue: true,
333+
},
334+
},
335+
},
336+
})
337+
338+
inlay_hint_config = state.feature_configuration(:inlayHint) #: as !nil
339+
assert(inlay_hint_config.enabled?(:implicitRescue))
340+
assert(inlay_hint_config.enabled?(:implicitHashValue))
341+
end
342+
343+
def test_feature_configuration_with_partially_provided_configuration
344+
state = GlobalState.new
345+
state.apply_options({
346+
initializationOptions: {
347+
featuresConfiguration: {
348+
inlayHint: {
349+
implicitHashValue: true,
350+
},
351+
},
352+
},
353+
})
354+
355+
inlay_hint_config = state.feature_configuration(:inlayHint) #: as !nil
356+
refute(inlay_hint_config.enabled?(:implicitRescue))
357+
assert(inlay_hint_config.enabled?(:implicitHashValue))
358+
end
359+
360+
def test_initialize_features_with_enable_all_configuration
361+
state = GlobalState.new
362+
state.apply_options({
363+
initializationOptions: {
364+
featuresConfiguration: {
365+
inlayHint: {
366+
enableAll: true,
367+
368+
},
369+
},
370+
},
371+
})
372+
373+
inlay_hint_config = state.feature_configuration(:inlayHint) #: as !nil
374+
assert(inlay_hint_config.enabled?(:implicitRescue))
375+
assert(inlay_hint_config.enabled?(:implicitHashValue))
376+
end
377+
317378
private
318379

319380
def stub_direct_dependencies(dependencies)

test/requests/inlay_hints_expectations_test.rb

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,14 @@ def run_expectations(source)
1313
document = RubyLsp::RubyDocument.new(source: source, version: 1, uri: uri, global_state: @global_state)
1414

1515
dispatcher = Prism::Dispatcher.new
16-
hints_configuration = RubyLsp::RequestConfig.new({ implicitRescue: true, implicitHashValue: true })
17-
request = RubyLsp::Requests::InlayHints.new(document, hints_configuration, dispatcher)
16+
@global_state.apply_options({
17+
initializationOptions: {
18+
featuresConfiguration: {
19+
inlayHint: { implicitRescue: true, implicitHashValue: true },
20+
},
21+
},
22+
})
23+
request = RubyLsp::Requests::InlayHints.new(@global_state, document, dispatcher)
1824
dispatcher.dispatch(document.ast)
1925
range = params.first
2026
ruby_range = range.dig(:start, :line)..range.dig(:end, :line)
@@ -35,8 +41,14 @@ def test_skip_implicit_hash_value
3541
RUBY
3642

3743
dispatcher = Prism::Dispatcher.new
38-
hints_configuration = RubyLsp::RequestConfig.new({ implicitRescue: true, implicitHashValue: false })
39-
request = RubyLsp::Requests::InlayHints.new(document, hints_configuration, dispatcher)
44+
@global_state.apply_options({
45+
initializationOptions: {
46+
featuresConfiguration: {
47+
inlayHint: { implicitRescue: true, implicitHashValue: false },
48+
},
49+
},
50+
})
51+
request = RubyLsp::Requests::InlayHints.new(@global_state, document, dispatcher)
4052
dispatcher.dispatch(document.ast)
4153
assert_empty(request.perform)
4254
end
@@ -50,8 +62,14 @@ def test_skip_implicit_rescue
5062
RUBY
5163

5264
dispatcher = Prism::Dispatcher.new
53-
hints_configuration = RubyLsp::RequestConfig.new({ implicitRescue: false, implicitHashValue: true })
54-
request = RubyLsp::Requests::InlayHints.new(document, hints_configuration, dispatcher)
65+
@global_state.apply_options({
66+
initializationOptions: {
67+
featuresConfiguration: {
68+
inlayHint: { implicitRescue: false, implicitHashValue: true },
69+
},
70+
},
71+
})
72+
request = RubyLsp::Requests::InlayHints.new(@global_state, document, dispatcher)
5573
dispatcher.dispatch(document.ast)
5674
assert_empty(request.perform)
5775
end

test/server_test.rb

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -294,73 +294,6 @@ def test_did_close_clears_diagnostics
294294
)
295295
end
296296

297-
def test_initialize_features_with_default_configuration
298-
capture_subprocess_io do
299-
@server.process_message({ method: "initialized" })
300-
end
301-
store = @server.instance_variable_get(:@store)
302-
303-
refute(store.features_configuration.dig(:inlayHint).enabled?(:implicitRescue))
304-
refute(store.features_configuration.dig(:inlayHint).enabled?(:implicitHashValue))
305-
end
306-
307-
def test_initialize_features_with_provided_configuration
308-
capture_subprocess_io do
309-
@server.process_message(id: 1, method: "initialize", params: {
310-
initializationOptions: {
311-
featuresConfiguration: {
312-
inlayHint: {
313-
implicitRescue: true,
314-
implicitHashValue: true,
315-
},
316-
},
317-
},
318-
})
319-
end
320-
321-
store = @server.instance_variable_get(:@store)
322-
assert(store.features_configuration.dig(:inlayHint).enabled?(:implicitRescue))
323-
assert(store.features_configuration.dig(:inlayHint).enabled?(:implicitHashValue))
324-
end
325-
326-
def test_initialize_features_with_partially_provided_configuration
327-
capture_subprocess_io do
328-
@server.process_message(id: 1, method: "initialize", params: {
329-
initializationOptions: {
330-
featuresConfiguration: {
331-
inlayHint: {
332-
implicitHashValue: true,
333-
},
334-
},
335-
},
336-
})
337-
end
338-
339-
store = @server.instance_variable_get(:@store)
340-
341-
refute(store.features_configuration.dig(:inlayHint).enabled?(:implicitRescue))
342-
assert(store.features_configuration.dig(:inlayHint).enabled?(:implicitHashValue))
343-
end
344-
345-
def test_initialize_features_with_enable_all_configuration
346-
capture_subprocess_io do
347-
@server.process_message(id: 1, method: "initialize", params: {
348-
initializationOptions: {
349-
featuresConfiguration: {
350-
inlayHint: {
351-
enableAll: true,
352-
},
353-
},
354-
},
355-
})
356-
end
357-
358-
store = @server.instance_variable_get(:@store)
359-
360-
assert(store.features_configuration.dig(:inlayHint).enabled?(:implicitRescue))
361-
assert(store.features_configuration.dig(:inlayHint).enabled?(:implicitHashValue))
362-
end
363-
364297
def test_handles_invalid_configuration
365298
File.write(".index.yml", "} invalid yaml")
366299

0 commit comments

Comments
 (0)