ruby-lsp 0.27.0.beta2 → 0.27.0.beta4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/exe/ruby-lsp +0 -46
  4. data/exe/ruby-lsp-check +0 -15
  5. data/lib/ruby_lsp/base_server.rb +2 -0
  6. data/lib/ruby_lsp/global_state.rb +0 -5
  7. data/lib/ruby_lsp/internal.rb +2 -1
  8. data/lib/ruby_lsp/listeners/code_lens.rb +1 -1
  9. data/lib/ruby_lsp/listeners/completion.rb +244 -383
  10. data/lib/ruby_lsp/listeners/definition.rb +6 -9
  11. data/lib/ruby_lsp/listeners/hover.rb +11 -9
  12. data/lib/ruby_lsp/listeners/signature_help.rb +11 -12
  13. data/lib/ruby_lsp/listeners/test_discovery.rb +17 -1
  14. data/lib/ruby_lsp/listeners/test_style.rb +1 -1
  15. data/lib/ruby_lsp/requests/completion_resolve.rb +49 -29
  16. data/lib/ruby_lsp/requests/references.rb +21 -7
  17. data/lib/ruby_lsp/requests/rename.rb +1 -1
  18. data/lib/ruby_lsp/requests/support/common.rb +79 -68
  19. data/lib/ruby_lsp/ruby_document.rb +0 -73
  20. data/lib/ruby_lsp/rubydex/declaration.rb +128 -2
  21. data/lib/ruby_lsp/rubydex/definition.rb +16 -0
  22. data/lib/ruby_lsp/rubydex/signature.rb +107 -0
  23. data/lib/ruby_lsp/scripts/compose_bundle.rb +1 -1
  24. data/lib/ruby_lsp/server.rb +40 -168
  25. data/lib/ruby_lsp/setup_bundler.rb +1 -1
  26. data/lib/ruby_lsp/test_helper.rb +0 -1
  27. data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +1 -1
  28. data/lib/ruby_lsp/type_inferrer.rb +58 -40
  29. metadata +14 -17
  30. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +0 -276
  31. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +0 -1101
  32. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +0 -44
  33. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +0 -605
  34. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +0 -1077
  35. data/lib/ruby_indexer/lib/ruby_indexer/location.rb +0 -37
  36. data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +0 -149
  37. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +0 -294
  38. data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +0 -32
  39. data/lib/ruby_indexer/ruby_indexer.rb +0 -19
  40. /data/lib/{ruby_indexer/lib/ruby_indexer → ruby_lsp}/uri.rb +0 -0
@@ -2,12 +2,13 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Rubydex
5
+ # @abstract
5
6
  class Declaration
6
7
  # Detail text shown on a `TypeHierarchyItem` for this declaration. Hints at multiplicity
7
8
  # when the declaration spans more than one re-open; otherwise falls back to the primary
8
9
  # definition's file name so users can quickly see where the type comes from.
9
10
  #
10
- #: () -> String?
11
+ #: -> String?
11
12
  def lsp_type_hierarchy_detail
12
13
  defs = definitions
13
14
  count = defs.count
@@ -20,13 +21,20 @@ module Rubydex
20
21
  path = uri.full_path
21
22
  path ? File.basename(path) : uri.to_s
22
23
  end
24
+
25
+ # @abstract
26
+ #: -> Integer
27
+ def to_lsp_completion_kind
28
+ raise RubyLsp::AbstractMethodInvokedError
29
+ end
23
30
  end
24
31
 
32
+ # @abstract
25
33
  class Namespace
26
34
  # Resolved, deduplicated direct supertypes across every re-open of this declaration.
27
35
  # Aggregates each definition's own `superclass`/`include`/`prepend` references and drops
28
36
  # unresolved ones. Order is stable (first-seen across definitions).
29
- #: () -> Array[Rubydex::Namespace]
37
+ #: -> Array[Rubydex::Namespace]
30
38
  def direct_supertypes
31
39
  seen = {} #: Hash[String, Rubydex::Namespace]
32
40
 
@@ -45,4 +53,122 @@ module Rubydex
45
53
  seen.values
46
54
  end
47
55
  end
56
+
57
+ class Class
58
+ # @override
59
+ #: -> Integer
60
+ def to_lsp_completion_kind
61
+ RubyLsp::Constant::CompletionItemKind::CLASS
62
+ end
63
+ end
64
+
65
+ class Module
66
+ # @override
67
+ #: -> Integer
68
+ def to_lsp_completion_kind
69
+ RubyLsp::Constant::CompletionItemKind::MODULE
70
+ end
71
+ end
72
+
73
+ class SingletonClass
74
+ # @override
75
+ #: -> Integer
76
+ def to_lsp_completion_kind
77
+ RubyLsp::Constant::CompletionItemKind::CLASS
78
+ end
79
+ end
80
+
81
+ class Todo
82
+ # @override
83
+ #: -> Integer
84
+ def to_lsp_completion_kind
85
+ RubyLsp::Constant::CompletionItemKind::CLASS
86
+ end
87
+ end
88
+
89
+ class Constant
90
+ # @override
91
+ #: -> Integer
92
+ def to_lsp_completion_kind
93
+ RubyLsp::Constant::CompletionItemKind::CONSTANT
94
+ end
95
+ end
96
+
97
+ class ConstantAlias
98
+ # @override
99
+ #: -> Integer
100
+ def to_lsp_completion_kind
101
+ RubyLsp::Constant::CompletionItemKind::CONSTANT
102
+ end
103
+ end
104
+
105
+ class Method
106
+ # @override
107
+ #: -> Integer
108
+ def to_lsp_completion_kind
109
+ RubyLsp::Constant::CompletionItemKind::METHOD
110
+ end
111
+
112
+ # All signatures collected across every definition (re-opens, RBS overloads, alias targets) of this method.
113
+ #: () -> Array[Rubydex::Signature]
114
+ def signatures
115
+ definitions.flat_map do |defn|
116
+ case defn
117
+ when Rubydex::MethodDefinition, Rubydex::MethodAliasDefinition
118
+ defn.signatures
119
+ else
120
+ []
121
+ end
122
+ end
123
+ end
124
+
125
+ # Decorated parameter list of the first signature, e.g. `(a, b = <default>, &block)`. Returns `()` when there are
126
+ # no signatures (e.g. an unresolved alias).
127
+ #: () -> String
128
+ def decorated_parameters
129
+ first = signatures.first
130
+ return "()" unless first
131
+
132
+ "(#{first.format})"
133
+ end
134
+
135
+ # Suffix line that hints at additional overloads beyond the first signature, matching the legacy index entry
136
+ # rendering used in hover.
137
+ #: () -> String
138
+ def formatted_signatures
139
+ count = signatures.size
140
+ case count
141
+ when 0, 1
142
+ ""
143
+ when 2
144
+ "\n(+1 overload)"
145
+ else
146
+ "\n(+#{count - 1} overloads)"
147
+ end
148
+ end
149
+ end
150
+
151
+ class InstanceVariable
152
+ # @override
153
+ #: -> Integer
154
+ def to_lsp_completion_kind
155
+ RubyLsp::Constant::CompletionItemKind::FIELD
156
+ end
157
+ end
158
+
159
+ class ClassVariable
160
+ # @override
161
+ #: -> Integer
162
+ def to_lsp_completion_kind
163
+ RubyLsp::Constant::CompletionItemKind::FIELD
164
+ end
165
+ end
166
+
167
+ class GlobalVariable
168
+ # @override
169
+ #: -> Integer
170
+ def to_lsp_completion_kind
171
+ RubyLsp::Constant::CompletionItemKind::VARIABLE
172
+ end
173
+ end
48
174
  end
@@ -183,6 +183,14 @@ module Rubydex
183
183
  end
184
184
  end
185
185
 
186
+ class ConstantVisibilityDefinition
187
+ # @override
188
+ #: () -> Integer
189
+ def to_lsp_kind
190
+ RubyLsp::Constant::SymbolKind::CONSTANT
191
+ end
192
+ end
193
+
186
194
  class MethodDefinition
187
195
  # @override
188
196
  #: () -> Integer
@@ -199,6 +207,14 @@ module Rubydex
199
207
  end
200
208
  end
201
209
 
210
+ class MethodVisibilityDefinition
211
+ # @override
212
+ #: () -> Integer
213
+ def to_lsp_kind
214
+ RubyLsp::Constant::SymbolKind::METHOD
215
+ end
216
+ end
217
+
202
218
  class AttrReaderDefinition
203
219
  # @override
204
220
  #: () -> Integer
@@ -0,0 +1,107 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Rubydex
5
+ class Signature
6
+ # Returns a string with the decorated names of the parameters of this signature, e.g.
7
+ # `(a, b = <default>, *c, d, e:, f: <default>, **g, &h)`.
8
+ #: () -> String
9
+ def format
10
+ parameters.map { |param| decorated_name(param) }.join(", ")
11
+ end
12
+
13
+ # Returns `true` if the given call node arguments array matches this signature. The matching is intentionally lenient
14
+ # because this method is used to detect which overload should be displayed in signature help while the user is still
15
+ # typing the call. We prefer returning `true` for situations that cannot be analyzed statically (e.g. presence of
16
+ # splats, keyword splats, forwarding) and accept missing arguments since the user may not be done typing yet.
17
+ #: (Array[Prism::Node] arguments) -> bool
18
+ def matches?(arguments)
19
+ min_pos = 0
20
+ max_pos = 0 #: (Integer | Float)
21
+ names = []
22
+ has_forward = false #: bool
23
+ has_keyword_rest = false #: bool
24
+
25
+ parameters.each do |param|
26
+ case param
27
+ when PositionalParameter, PostParameter
28
+ min_pos += 1
29
+ max_pos += 1
30
+ when OptionalPositionalParameter
31
+ max_pos += 1
32
+ when RestPositionalParameter
33
+ max_pos = Float::INFINITY
34
+ when ForwardParameter
35
+ max_pos = Float::INFINITY
36
+ has_forward = true
37
+ when KeywordParameter, OptionalKeywordParameter
38
+ names << param.name
39
+ when RestKeywordParameter
40
+ has_keyword_rest = true
41
+ end
42
+ end
43
+
44
+ keyword_hash_nodes, positional_args = arguments.partition { |arg| arg.is_a?(Prism::KeywordHashNode) }
45
+ keyword_args = keyword_hash_nodes.first #: as Prism::KeywordHashNode?
46
+ &.elements
47
+ forwarding_arguments, positionals = positional_args.partition do |arg|
48
+ arg.is_a?(Prism::ForwardingArgumentsNode)
49
+ end
50
+
51
+ return true if has_forward && min_pos == 0
52
+
53
+ # If the only argument passed is a forwarding argument, then anything will match
54
+ (positionals.empty? && forwarding_arguments.any?) ||
55
+ (
56
+ positional_arguments_match?(positionals, forwarding_arguments, keyword_args, min_pos, max_pos) &&
57
+ (has_forward || has_keyword_rest || keyword_arguments_match?(keyword_args, names))
58
+ )
59
+ end
60
+
61
+ private
62
+
63
+ #: (Parameter) -> String
64
+ def decorated_name(param)
65
+ case param
66
+ when OptionalPositionalParameter
67
+ "#{param.name} = <default>"
68
+ when RestPositionalParameter
69
+ "*#{param.name}"
70
+ when KeywordParameter
71
+ "#{param.name}:"
72
+ when OptionalKeywordParameter
73
+ "#{param.name}: <default>"
74
+ when RestKeywordParameter
75
+ "**#{param.name}"
76
+ when BlockParameter
77
+ "&#{param.name}"
78
+ else
79
+ param.name.to_s
80
+ end
81
+ end
82
+
83
+ #: (Array[Prism::Node] positional_args, Array[Prism::Node] forwarding_arguments, Array[Prism::Node]? keyword_args, Integer min_pos, (Integer | Float) max_pos) -> bool
84
+ def positional_arguments_match?(positional_args, forwarding_arguments, keyword_args, min_pos, max_pos)
85
+ (min_pos > 0 && positional_args.any? { |arg| arg.is_a?(Prism::SplatNode) }) ||
86
+ (min_pos - positional_args.length > 0 && keyword_args&.any? { |arg| arg.is_a?(Prism::AssocSplatNode) }) ||
87
+ (min_pos - positional_args.length > 0 && forwarding_arguments.any?) ||
88
+ (min_pos > 0 && positional_args.length <= max_pos) ||
89
+ (min_pos == 0 && positional_args.empty?)
90
+ end
91
+
92
+ #: (Array[Prism::Node]? args, Array[Symbol] names) -> bool
93
+ def keyword_arguments_match?(args, names)
94
+ return true unless args
95
+ return true if args.any? { |arg| arg.is_a?(Prism::AssocSplatNode) }
96
+
97
+ arg_names = args.filter_map do |arg|
98
+ next unless arg.is_a?(Prism::AssocNode)
99
+
100
+ key = arg.key
101
+ key.value&.to_sym if key.is_a?(Prism::SymbolNode)
102
+ end
103
+
104
+ (arg_names - names).empty?
105
+ end
106
+ end
107
+ end
@@ -5,7 +5,7 @@ def compose(raw_initialize, **options)
5
5
  require_relative "../setup_bundler"
6
6
  require "json"
7
7
  require "uri"
8
- require_relative "../../ruby_indexer/lib/ruby_indexer/uri"
8
+ require_relative "../uri"
9
9
 
10
10
  initialize_request = JSON.parse(raw_initialize, symbolize_names: true)
11
11
  workspace_uri = initialize_request.dig(:params, :workspaceFolders, 0, :uri)
@@ -325,8 +325,6 @@ module RubyLsp
325
325
  ))
326
326
  end
327
327
 
328
- process_indexing_configuration(options.dig(:initializationOptions, :indexing))
329
-
330
328
  begin_progress("indexing-progress", "Ruby LSP: indexing files")
331
329
 
332
330
  global_state_notifications.each { |notification| send_message(notification) }
@@ -373,6 +371,7 @@ module RubyLsp
373
371
  end
374
372
  end
375
373
 
374
+ load_rubydex_config
376
375
  perform_initial_indexing
377
376
  check_formatter_is_available
378
377
  update_server if @global_state.enabled_feature?(:launcher)
@@ -437,10 +436,15 @@ module RubyLsp
437
436
  if [:ruby, :rbs].include?(language_id)
438
437
  graph = @global_state.graph
439
438
 
440
- benchmark("index_source") do
441
- graph.index_source(text_document[:uri].to_s, document.source, language_id.to_s)
442
- end
439
+ begin_progress("incremental-indexing-progress", "Ruby LSP: indexing files")
440
+
441
+ progress("incremental-indexing-progress", message: "Indexing file...")
442
+ benchmark("index_source") { graph.index_source(text_document[:uri].to_s, document.source, language_id.to_s) }
443
+
444
+ progress("incremental-indexing-progress", message: "Resolving graph...")
443
445
  benchmark("incremental_resolve") { graph.resolve }
446
+
447
+ end_progress("incremental-indexing-progress")
444
448
  end
445
449
  end
446
450
 
@@ -499,39 +503,15 @@ module RubyLsp
499
503
  document,
500
504
  dispatcher,
501
505
  )
502
-
503
- # The code lens listener requires the index to be populated, so the DeclarationListener must be inserted first in
504
- # the dispatcher's state
505
- code_lens = nil #: Requests::CodeLens?
506
-
507
- if document.is_a?(RubyDocument) && document.should_index?
508
- # Re-index the file as it is modified. This mode of indexing updates entries only. Require path trees are only
509
- # updated on save
510
- @global_state.synchronize do
511
- send_log_message("Determined that document should be indexed: #{uri}")
512
-
513
- @global_state.index.handle_change(uri) do |index|
514
- index.delete(uri, skip_require_paths_tree: true)
515
- RubyIndexer::DeclarationListener.new(index, dispatcher, parse_result, uri, collect_comments: true)
516
- code_lens = Requests::CodeLens.new(@global_state, document, dispatcher)
517
- dispatcher.dispatch(document.ast)
518
- end
519
- end
520
- else
521
- code_lens = Requests::CodeLens.new(@global_state, document, dispatcher)
522
- dispatcher.dispatch(document.ast)
523
- end
506
+ code_lens = Requests::CodeLens.new(@global_state, document, dispatcher)
507
+ dispatcher.dispatch(document.ast)
524
508
 
525
509
  # Store all responses retrieve in this round of visits in the cache and then return the response for the request
526
510
  # we actually received
527
511
  document.cache_set("textDocument/foldingRange", folding_range.perform)
528
512
  document.cache_set("textDocument/documentSymbol", document_symbol.perform)
529
513
  document.cache_set("textDocument/documentLink", document_link.perform)
530
- document.cache_set(
531
- "textDocument/codeLens",
532
- code_lens #: as !nil
533
- .perform,
534
- )
514
+ document.cache_set("textDocument/codeLens", code_lens.perform)
535
515
  document.cache_set("textDocument/inlayHint", inlay_hint.perform)
536
516
 
537
517
  send_message(Result.new(id: message[:id], response: document.cache_get(message[:method])))
@@ -1038,21 +1018,6 @@ module RubyLsp
1038
1018
 
1039
1019
  #: (Hash[Symbol, untyped] message) -> void
1040
1020
  def workspace_did_change_watched_files(message)
1041
- # If indexing is not complete yet, delay processing did change watched file notifications. We need initial
1042
- # indexing to be in place so that we can handle file changes appropriately without risking duplicates. We also
1043
- # have to sleep before re-inserting the notification in the queue otherwise the worker can get stuck in its own
1044
- # loop of pushing and popping the same notification
1045
- unless @global_state.index.initial_indexing_completed
1046
- Thread.new do
1047
- sleep(2)
1048
- # We have to ensure that the queue is not closed yet, since nothing stops the user from saving a file and then
1049
- # immediately telling the LSP to shutdown
1050
- @incoming_queue << message unless @incoming_queue.closed?
1051
- end
1052
-
1053
- return
1054
- end
1055
-
1056
1021
  changes = message.dig(:params, :changes)
1057
1022
  # We allow add-ons to register for watching files and we have no restrictions for what they register for. If the
1058
1023
  # same pattern is registered more than once, the LSP will receive duplicate change notifications. Receiving them
@@ -1073,21 +1038,23 @@ module RubyLsp
1073
1038
  acc << path
1074
1039
  end
1075
1040
  end
1041
+
1042
+ begin_progress("incremental-indexing-progress", "Ruby LSP: indexing files")
1043
+
1044
+ progress("incremental-indexing-progress", message: "Indexing files...")
1076
1045
  benchmark("index_all") { graph.index_all(additions_and_changes) }
1046
+
1047
+ progress("incremental-indexing-progress", message: "Resolving graph...")
1077
1048
  benchmark("incremental_resolve") { graph.resolve }
1078
1049
 
1079
- index = @global_state.index
1050
+ end_progress("incremental-indexing-progress")
1051
+
1080
1052
  changes.each do |change|
1081
1053
  # File change events include folders, but we're only interested in files
1082
1054
  uri = URI(change[:uri])
1083
1055
  file_path = uri.to_standardized_path
1084
1056
  next if file_path.nil? || File.directory?(file_path)
1085
1057
 
1086
- if file_path.end_with?(".rb")
1087
- handle_ruby_file_change(index, file_path, change[:type])
1088
- next
1089
- end
1090
-
1091
1058
  file_name = File.basename(file_path)
1092
1059
 
1093
1060
  if file_name == ".rubocop.yml" || file_name == ".rubocop" || file_name == ".rubocop_todo.yml"
@@ -1106,33 +1073,6 @@ module RubyLsp
1106
1073
  end
1107
1074
  end
1108
1075
 
1109
- #: (RubyIndexer::Index index, String file_path, Integer change_type) -> void
1110
- def handle_ruby_file_change(index, file_path, change_type)
1111
- @global_state.synchronize do
1112
- load_path_entry = $LOAD_PATH.find { |load_path| file_path.start_with?(load_path) }
1113
- uri = URI::Generic.from_path(load_path_entry: load_path_entry, path: file_path)
1114
-
1115
- case change_type
1116
- when Constant::FileChangeType::CREATED
1117
- content = File.read(file_path)
1118
- # If we receive a late created notification for a file that has already been claimed by the client, we want to
1119
- # handle change for that URI so that the require path tree is updated
1120
- @store.key?(uri) ? index.handle_change(uri, content) : index.index_single(uri, content)
1121
- when Constant::FileChangeType::CHANGED
1122
- content = File.read(file_path)
1123
- # We only handle changes on file watched notifications if the client is not the one managing this URI.
1124
- # Otherwise, these changes are handled when running the combined requests
1125
- index.handle_change(uri, content) unless @store.key?(uri)
1126
- when Constant::FileChangeType::DELETED
1127
- index.delete(uri)
1128
- end
1129
- rescue Errno::ENOENT
1130
- # If a file is created and then delete immediately afterwards, we will process the created notification before
1131
- # we receive the deleted one, but the file no longer exists. This may happen when running a test suite that
1132
- # creates and deletes files automatically.
1133
- end
1134
- end
1135
-
1136
1076
  #: (URI::Generic uri) -> void
1137
1077
  def handle_rubocop_config_change(uri)
1138
1078
  return unless defined?(Requests::Support::RuboCopFormatter)
@@ -1271,60 +1211,20 @@ module RubyLsp
1271
1211
 
1272
1212
  #: -> void
1273
1213
  def perform_initial_indexing
1214
+ # Index
1274
1215
  progress("indexing-progress", message: "Indexing workspace...")
1275
1216
  benchmark("index_workspace") { @global_state.graph.index_workspace }
1276
1217
 
1218
+ # Resolve
1277
1219
  progress("indexing-progress", message: "Resolving graph...")
1278
1220
  benchmark("full_resolve") { @global_state.graph.resolve }
1279
1221
 
1280
- # The begin progress invocation happens during `initialize`, so that the notification is sent before we are
1281
- # stuck indexing files
1282
- Thread.new do
1283
- begin
1284
- @global_state.index.index_all do |percentage|
1285
- progress("indexing-progress", percentage: percentage)
1286
- true
1287
- rescue ClosedQueueError
1288
- # Since we run indexing on a separate thread, it's possible to kill the server before indexing is complete.
1289
- # In those cases, the message queue will be closed and raise a ClosedQueueError. By returning `false`, we
1290
- # tell the index to stop working immediately
1291
- false
1292
- end
1293
- rescue StandardError => error
1294
- message = "Error while indexing (see [troubleshooting steps]" \
1295
- "(https://shopify.github.io/ruby-lsp/troubleshooting#indexing)): #{error.message}"
1296
- send_message(Notification.window_show_message(message, type: Constant::MessageType::ERROR))
1297
- end
1298
-
1299
- # Indexing produces a high number of short lived object allocations. That might lead to some fragmentation and
1300
- # an unnecessarily expanded heap. Compacting ensures that the heap is as small as possible and that future
1301
- # allocations and garbage collections are faster
1302
- GC.compact unless @test_mode
1303
-
1304
- @global_state.synchronize do
1305
- # If we linearize ancestors while the index is not fully populated, we may end up caching incorrect results
1306
- # that were missing namespaces. After indexing is complete, we need to clear the ancestors cache and start
1307
- # again
1308
- @global_state.index.clear_ancestors
1309
-
1310
- # The results for code lens depend on ancestor linearization, so we need to clear any previously computed
1311
- # responses
1312
- @store.each { |_uri, document| document.clear_cache("textDocument/codeLens") }
1313
- end
1314
-
1315
- # Always end the progress notification even if indexing failed or else it never goes away and the user has no
1316
- # way of dismissing it
1317
- end_progress("indexing-progress")
1318
-
1319
- # Request a code lens refresh if we populated them before all test parent classes were indexed
1320
- if @global_state.client_capabilities.supports_code_lens_refresh
1321
- send_message(Request.new(id: @current_request_id, method: "workspace/codeLens/refresh", params: nil))
1322
- end
1323
- end
1222
+ # End
1223
+ end_progress("indexing-progress")
1324
1224
  end
1325
1225
 
1326
- #: (String id, String title, ?percentage: Integer) -> void
1327
- def begin_progress(id, title, percentage: 0)
1226
+ #: (String id, String title, ?percentage: Integer?, ?message: String?) -> void
1227
+ def begin_progress(id, title, percentage: nil, message: nil)
1328
1228
  return unless @global_state.client_capabilities.supports_progress
1329
1229
 
1330
1230
  send_message(Request.new(
@@ -1333,7 +1233,10 @@ module RubyLsp
1333
1233
  params: Interface::WorkDoneProgressCreateParams.new(token: id),
1334
1234
  ))
1335
1235
 
1336
- send_message(Notification.progress_begin(id, title, percentage: percentage, message: "#{percentage}% completed"))
1236
+ # Omitting the percentage tells the client to show indefinite progress. Only fabricate a "% completed" message
1237
+ # when a caller reports incremental percentages and didn't provide an explicit message
1238
+ message ||= "#{percentage}% completed" if percentage
1239
+ send_message(Notification.progress_begin(id, title, percentage: percentage, message: message))
1337
1240
  end
1338
1241
 
1339
1242
  #: (String, ?message: String?, ?percentage: Integer?) -> void
@@ -1373,47 +1276,6 @@ module RubyLsp
1373
1276
  end
1374
1277
  end
1375
1278
 
1376
- #: (Hash[Symbol, untyped]? indexing_options) -> void
1377
- def process_indexing_configuration(indexing_options)
1378
- # Need to use the workspace URI, otherwise, this will fail for people working on a project that is a symlink.
1379
- index_path = File.join(@global_state.workspace_path, ".index.yml")
1380
-
1381
- if File.exist?(index_path)
1382
- begin
1383
- @global_state.index.configuration.apply_config(YAML.parse_file(index_path).to_ruby)
1384
- send_message(
1385
- Notification.new(
1386
- method: "window/showMessage",
1387
- params: Interface::ShowMessageParams.new(
1388
- type: Constant::MessageType::WARNING,
1389
- message: "The .index.yml configuration file is deprecated. " \
1390
- "Please use editor settings to configure the index",
1391
- ),
1392
- ),
1393
- )
1394
- rescue Psych::SyntaxError => e
1395
- message = "Syntax error while loading configuration: #{e.message}"
1396
- send_message(
1397
- Notification.new(
1398
- method: "window/showMessage",
1399
- params: Interface::ShowMessageParams.new(
1400
- type: Constant::MessageType::WARNING,
1401
- message: message,
1402
- ),
1403
- ),
1404
- )
1405
- end
1406
- return
1407
- end
1408
-
1409
- configuration = @global_state.index.configuration
1410
- configuration.workspace_path = @global_state.workspace_path
1411
- return unless indexing_options
1412
-
1413
- # The index expects snake case configurations, but VS Code standardizes on camel case settings
1414
- configuration.apply_config(indexing_options.transform_keys { |key| key.to_s.gsub(/([A-Z])/, "_\\1").downcase })
1415
- end
1416
-
1417
1279
  #: (Hash[Symbol, untyped] message) -> void
1418
1280
  def window_show_message_request(message)
1419
1281
  result = message[:result]
@@ -1598,5 +1460,15 @@ module RubyLsp
1598
1460
 
1599
1461
  result
1600
1462
  end
1463
+
1464
+ #: () -> void
1465
+ def load_rubydex_config
1466
+ @global_state.graph.load_config
1467
+ rescue Rubydex::ConfigError => e
1468
+ send_message(Notification.window_show_message(
1469
+ "Error loading rubydex config: #{e.message}",
1470
+ type: Constant::MessageType::ERROR,
1471
+ ))
1472
+ end
1601
1473
  end
1602
1474
  end
@@ -445,7 +445,7 @@ module RubyLsp
445
445
  requirement = Gem::Requirement.new(@bundler_version.to_s)
446
446
  return if Gem::Specification.any? { |s| s.name == "bundler" && requirement =~ s.version }
447
447
 
448
- Gem.install("bundler", @bundler_version.to_s)
448
+ Gem.install("bundler", @bundler_version.to_s, env_shebang: true)
449
449
  end
450
450
 
451
451
  #: -> bool
@@ -29,7 +29,6 @@ module RubyLsp
29
29
  },
30
30
  })
31
31
 
32
- server.global_state.index.index_single(uri, source)
33
32
  graph = server.global_state.graph
34
33
  graph.index_source(uri.to_s, source, "ruby")
35
34
  graph.resolve
@@ -5,7 +5,7 @@ require "English"
5
5
  require "json"
6
6
  require "socket"
7
7
  require "tmpdir"
8
- require_relative "../../ruby_indexer/lib/ruby_indexer/uri"
8
+ require_relative "../uri"
9
9
 
10
10
  module RubyLsp
11
11
  class LspReporter