ruby-lsp 0.0.3 → 0.0.4

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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +6 -0
  3. data/.rubocop.yml +16 -0
  4. data/CHANGELOG.md +13 -0
  5. data/Gemfile +8 -5
  6. data/Gemfile.lock +55 -10
  7. data/README.md +40 -0
  8. data/VERSION +1 -1
  9. data/bin/tapioca +29 -0
  10. data/dev.yml +3 -0
  11. data/exe/ruby-lsp +19 -4
  12. data/lib/internal.rb +7 -0
  13. data/lib/ruby-lsp.rb +1 -0
  14. data/lib/ruby_lsp/cli.rb +12 -5
  15. data/lib/ruby_lsp/document.rb +37 -14
  16. data/lib/ruby_lsp/handler.rb +78 -23
  17. data/lib/ruby_lsp/requests/base_request.rb +11 -0
  18. data/lib/ruby_lsp/requests/code_actions.rb +1 -0
  19. data/lib/ruby_lsp/requests/diagnostics.rb +1 -0
  20. data/lib/ruby_lsp/requests/document_highlight.rb +96 -0
  21. data/lib/ruby_lsp/requests/document_symbol.rb +1 -10
  22. data/lib/ruby_lsp/requests/folding_ranges.rb +3 -2
  23. data/lib/ruby_lsp/requests/formatting.rb +2 -1
  24. data/lib/ruby_lsp/requests/rubocop_request.rb +1 -0
  25. data/lib/ruby_lsp/requests/selection_ranges.rb +1 -0
  26. data/lib/ruby_lsp/requests/semantic_highlighting.rb +17 -3
  27. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +1 -0
  28. data/lib/ruby_lsp/requests/support/selection_range.rb +1 -0
  29. data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +12 -1
  30. data/lib/ruby_lsp/requests/support/syntax_error_diagnostic.rb +1 -0
  31. data/lib/ruby_lsp/requests.rb +2 -0
  32. data/lib/ruby_lsp/store.rb +19 -3
  33. data/rakelib/check_docs.rake +4 -1
  34. data/ruby-lsp.gemspec +1 -0
  35. data/sorbet/config +4 -0
  36. data/sorbet/rbi/.rubocop.yml +8 -0
  37. data/sorbet/rbi/gems/ansi@1.5.0.rbi +338 -0
  38. data/sorbet/rbi/gems/ast@2.4.2.rbi +522 -0
  39. data/sorbet/rbi/gems/builder@3.2.4.rbi +418 -0
  40. data/sorbet/rbi/gems/coderay@1.1.3.rbi +8 -0
  41. data/sorbet/rbi/gems/debug@1.5.0.rbi +1273 -0
  42. data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +867 -0
  43. data/sorbet/rbi/gems/io-console@0.5.11.rbi +8 -0
  44. data/sorbet/rbi/gems/irb@1.4.1.rbi +376 -0
  45. data/sorbet/rbi/gems/language_server-protocol@3.16.0.3.rbi +7325 -0
  46. data/sorbet/rbi/gems/method_source@1.0.0.rbi +8 -0
  47. data/sorbet/rbi/gems/minitest-reporters@1.5.0.rbi +612 -0
  48. data/sorbet/rbi/gems/minitest@5.15.0.rbi +994 -0
  49. data/sorbet/rbi/gems/parallel@1.22.1.rbi +163 -0
  50. data/sorbet/rbi/gems/parser@3.1.2.0.rbi +3968 -0
  51. data/sorbet/rbi/gems/prettier_print@0.1.0.rbi +734 -0
  52. data/sorbet/rbi/gems/pry@0.14.1.rbi +8 -0
  53. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +227 -0
  54. data/sorbet/rbi/gems/rake@13.0.6.rbi +1853 -0
  55. data/sorbet/rbi/gems/rbi@0.0.14.rbi +2337 -0
  56. data/sorbet/rbi/gems/regexp_parser@2.5.0.rbi +1854 -0
  57. data/sorbet/rbi/gems/reline@0.3.1.rbi +1274 -0
  58. data/sorbet/rbi/gems/rexml@3.2.5.rbi +3852 -0
  59. data/sorbet/rbi/gems/rubocop-ast@1.18.0.rbi +4180 -0
  60. data/sorbet/rbi/gems/rubocop-minitest@0.20.0.rbi +1369 -0
  61. data/sorbet/rbi/gems/rubocop-rake@0.6.0.rbi +246 -0
  62. data/sorbet/rbi/gems/rubocop-shopify@2.6.0.rbi +8 -0
  63. data/sorbet/rbi/gems/rubocop-sorbet@0.6.8.rbi +652 -0
  64. data/sorbet/rbi/gems/rubocop@1.30.0.rbi +36729 -0
  65. data/sorbet/rbi/gems/ruby-progressbar@1.11.0.rbi +732 -0
  66. data/sorbet/rbi/gems/spoom@1.1.11.rbi +1600 -0
  67. data/sorbet/rbi/gems/syntax_tree@2.7.1.rbi +6777 -0
  68. data/sorbet/rbi/gems/tapioca@0.8.1.rbi +1972 -0
  69. data/sorbet/rbi/gems/thor@1.2.1.rbi +2921 -0
  70. data/sorbet/rbi/gems/unicode-display_width@2.1.0.rbi +27 -0
  71. data/sorbet/rbi/gems/unparser@0.6.5.rbi +2789 -0
  72. data/sorbet/rbi/gems/webrick@1.7.0.rbi +1779 -0
  73. data/sorbet/rbi/gems/yard-sorbet@0.6.1.rbi +289 -0
  74. data/sorbet/rbi/gems/yard@0.9.27.rbi +13048 -0
  75. data/sorbet/rbi/shims/fiddle.rbi +4 -0
  76. data/sorbet/rbi/shims/hash.rbi +6 -0
  77. data/sorbet/rbi/shims/rdoc.rbi +4 -0
  78. data/sorbet/tapioca/config.yml +13 -0
  79. data/sorbet/tapioca/require.rb +7 -0
  80. metadata +64 -2
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require "ruby_lsp/requests"
@@ -6,24 +7,25 @@ require "benchmark"
6
7
 
7
8
  module RubyLsp
8
9
  class Handler
9
- IGNORED_FOR_TELEMETRY = [
10
- "initialized",
11
- "$/cancelRequest",
12
- ].freeze
10
+ extend T::Sig
11
+ VOID = T.let(Object.new.freeze, Object)
13
12
 
13
+ sig { returns(Store) }
14
14
  attr_reader :store
15
15
 
16
16
  Interface = LanguageServer::Protocol::Interface
17
17
  Constant = LanguageServer::Protocol::Constant
18
18
  Transport = LanguageServer::Protocol::Transport
19
19
 
20
+ sig { void }
20
21
  def initialize
21
- @writer = Transport::Stdio::Writer.new
22
- @reader = Transport::Stdio::Reader.new
23
- @handlers = {}
24
- @store = Store.new
22
+ @writer = T.let(Transport::Stdio::Writer.new, Transport::Stdio::Writer)
23
+ @reader = T.let(Transport::Stdio::Reader.new, Transport::Stdio::Reader)
24
+ @handlers = T.let({}, T::Hash[String, T.proc.params(request: T::Hash[Symbol, T.untyped]).returns(T.untyped)])
25
+ @store = T.let(Store.new, Store)
25
26
  end
26
27
 
28
+ sig { void }
27
29
  def start
28
30
  $stderr.puts "Starting Ruby LSP..."
29
31
  @reader.read do |request|
@@ -31,26 +33,39 @@ module RubyLsp
31
33
  end
32
34
  end
33
35
 
36
+ sig { params(blk: T.proc.bind(Handler).params(arg0: T.untyped).void).void }
34
37
  def config(&blk)
35
38
  instance_exec(&blk)
36
39
  end
37
40
 
38
41
  private
39
42
 
43
+ sig do
44
+ params(
45
+ msg: String,
46
+ blk: T.proc.bind(Handler).params(request: T::Hash[Symbol, T.untyped]).returns(T.untyped)
47
+ ).void
48
+ end
40
49
  def on(msg, &blk)
41
- @handlers[msg.to_s] = blk
50
+ @handlers[msg] = blk
42
51
  end
43
52
 
53
+ sig { params(request: T::Hash[Symbol, T.untyped]).void }
44
54
  def handle(request)
45
- result = @handlers[request[:method]]&.call(request)
46
- @writer.write(id: request[:id], result: result) if result
55
+ handler = @handlers[request[:method]]
56
+ return unless handler
57
+
58
+ result = handler.call(request)
59
+ @writer.write(id: request[:id], result: result) unless result == VOID
47
60
  end
48
61
 
62
+ sig { void }
49
63
  def shutdown
50
64
  $stderr.puts "Shutting down Ruby LSP..."
51
65
  store.clear
52
66
  end
53
67
 
68
+ sig { params(enabled_features: T::Array[String]).returns(Interface::InitializeResult) }
54
69
  def respond_with_capabilities(enabled_features)
55
70
  document_symbol_provider = if enabled_features.include?("documentSymbols")
56
71
  Interface::DocumentSymbolClientCapabilities.new(
@@ -70,7 +85,7 @@ module RubyLsp
70
85
  document_selector: { scheme: "file", language: "ruby" },
71
86
  legend: Interface::SemanticTokensLegend.new(
72
87
  token_types: Requests::SemanticHighlighting::TOKEN_TYPES,
73
- token_modifiers: Requests::SemanticHighlighting::TOKEN_MODIFIERS
88
+ token_modifiers: Requests::SemanticHighlighting::TOKEN_MODIFIERS.keys
74
89
  ),
75
90
  range: false,
76
91
  full: {
@@ -90,23 +105,32 @@ module RubyLsp
90
105
  folding_range_provider: folding_ranges_provider,
91
106
  semantic_tokens_provider: semantic_tokens_provider,
92
107
  document_formatting_provider: enabled_features.include?("formatting"),
108
+ document_highlight_provider: enabled_features.include?("documentHighlights"),
93
109
  code_action_provider: enabled_features.include?("codeActions")
94
110
  )
95
111
  )
96
112
  end
97
113
 
114
+ sig { params(uri: String).returns(T::Array[LanguageServer::Protocol::Interface::DocumentSymbol]) }
98
115
  def respond_with_document_symbol(uri)
99
116
  store.cache_fetch(uri, :document_symbol) do |document|
100
117
  RubyLsp::Requests::DocumentSymbol.run(document)
101
118
  end
102
119
  end
103
120
 
121
+ sig { params(uri: String).returns(T::Array[LanguageServer::Protocol::Interface::FoldingRange]) }
104
122
  def respond_with_folding_ranges(uri)
105
123
  store.cache_fetch(uri, :folding_ranges) do |document|
106
124
  Requests::FoldingRanges.run(document)
107
125
  end
108
126
  end
109
127
 
128
+ sig do
129
+ params(
130
+ uri: String,
131
+ positions: T::Array[Document::PositionShape]
132
+ ).returns(T::Array[RubyLsp::Requests::Support::SelectionRange])
133
+ end
110
134
  def respond_with_selection_ranges(uri, positions)
111
135
  ranges = store.cache_fetch(uri, :selection_ranges) do |document|
112
136
  Requests::SelectionRanges.run(document)
@@ -123,16 +147,19 @@ module RubyLsp
123
147
  end
124
148
  end
125
149
 
150
+ sig { params(uri: String).returns(LanguageServer::Protocol::Interface::SemanticTokens) }
126
151
  def respond_with_semantic_highlighting(uri)
127
152
  store.cache_fetch(uri, :semantic_highlighting) do |document|
128
153
  Requests::SemanticHighlighting.new(document, encoder: Requests::Support::SemanticTokenEncoder.new).run
129
154
  end
130
155
  end
131
156
 
157
+ sig { params(uri: String).returns(T::Array[LanguageServer::Protocol::Interface::TextEdit]) }
132
158
  def respond_with_formatting(uri)
133
159
  Requests::Formatting.run(uri, store.get(uri))
134
160
  end
135
161
 
162
+ sig { params(uri: String).void }
136
163
  def send_diagnostics(uri)
137
164
  response = store.cache_fetch(uri, :diagnostics) do |document|
138
165
  Requests::Diagnostics.run(uri, document)
@@ -147,35 +174,63 @@ module RubyLsp
147
174
  )
148
175
  end
149
176
 
177
+ sig do
178
+ params(uri: String, range: T::Range[Integer]).returns(T::Array[LanguageServer::Protocol::Interface::Diagnostic])
179
+ end
150
180
  def respond_with_code_actions(uri, range)
151
181
  store.cache_fetch(uri, :code_actions) do |document|
152
182
  Requests::CodeActions.run(uri, document, range)
153
183
  end
154
184
  end
155
185
 
156
- def configure_options(initialization_options)
157
- @telemetry_enabled = initialization_options.fetch(:telemetryEnabled, false)
186
+ sig do
187
+ params(
188
+ uri: String,
189
+ position: Document::PositionShape
190
+ ).returns(T::Array[LanguageServer::Protocol::Interface::DocumentHighlight])
191
+ end
192
+ def respond_with_document_highlight(uri, position)
193
+ Requests::DocumentHighlight.run(store.get(uri), position)
158
194
  end
159
195
 
160
- def with_telemetry(request)
161
- return yield unless @telemetry_enabled && !IGNORED_FOR_TELEMETRY.include?(request[:method])
196
+ sig { params(request: T::Hash[Symbol, T.untyped], block: T.proc.void).returns(T.untyped) }
197
+ def with_telemetry(request, &block)
198
+ result = T.let(nil, T.untyped)
199
+ error = T.let(nil, T.nilable(StandardError))
162
200
 
163
- result = nil
164
201
  request_time = Benchmark.realtime do
165
- result = yield
202
+ result = block.call
203
+ rescue StandardError => e
204
+ error = e
166
205
  end
167
206
 
207
+ @writer.write(method: "telemetry/event", params: telemetry_params(request, request_time, error))
208
+ result
209
+ end
210
+
211
+ sig do
212
+ params(
213
+ request: T::Hash[Symbol, T.untyped],
214
+ request_time: Float,
215
+ error: T.nilable(StandardError)
216
+ ).returns(T::Hash[Symbol, T.any(String, Float)])
217
+ end
218
+ def telemetry_params(request, request_time, error)
219
+ uri = request.dig(:params, :textDocument, :uri)
220
+
168
221
  params = {
169
222
  request: request[:method],
170
- requestTime: request_time,
171
223
  lspVersion: RubyLsp::VERSION,
224
+ requestTime: request_time,
172
225
  }
173
226
 
174
- uri = request.dig(:params, :textDocument, :uri)
175
- params[:uri] = uri if uri
227
+ if error
228
+ params[:errorClass] = error.class.name
229
+ params[:errorMessage] = error.message
230
+ end
176
231
 
177
- @writer.write(method: "telemetry/event", params: params)
178
- result
232
+ params[:uri] = uri if uri
233
+ params
179
234
  end
180
235
  end
181
236
  end
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module RubyLsp
@@ -17,6 +18,16 @@ module RubyLsp
17
18
  def run
18
19
  raise NotImplementedError, "#{self.class}#run must be implemented"
19
20
  end
21
+
22
+ def range_from_syntax_tree_node(node)
23
+ loc = node.location
24
+
25
+ LanguageServer::Protocol::Interface::Range.new(
26
+ start: LanguageServer::Protocol::Interface::Position.new(line: loc.start_line - 1,
27
+ character: loc.start_column),
28
+ end: LanguageServer::Protocol::Interface::Position.new(line: loc.end_line - 1, character: loc.end_column),
29
+ )
30
+ end
20
31
  end
21
32
  end
22
33
  end
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module RubyLsp
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module RubyLsp
@@ -0,0 +1,96 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module Requests
6
+ # The [document highlight](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentHighlight)
7
+ # informs the editor all relevant elements of the currently pointed item for highlighting. For example, when
8
+ # the cursor is on the `F` of the constant `FOO`, the editor should identify other occurences of `FOO`
9
+ # and highlight them.
10
+ #
11
+ # For writable elements like constants or variables, their read/write occurrences should be highlighted differently.
12
+ # This is achieved by sending different "kind" attributes to the editor (2 for read and 3 for write).
13
+ #
14
+ # # Example
15
+ #
16
+ # ```ruby
17
+ # FOO = 1 # should be highlighted as "write"
18
+ #
19
+ # def foo
20
+ # FOO # should be highlighted as "read"
21
+ # end
22
+ # ```
23
+ class DocumentHighlight < BaseRequest
24
+ def self.run(document, position)
25
+ new(document, position).run
26
+ end
27
+
28
+ def initialize(document, position)
29
+ @highlights = []
30
+ position = Document::Scanner.new(document.source).find_position(position)
31
+ @target = find(document.tree, position)
32
+
33
+ super(document)
34
+ end
35
+
36
+ def run
37
+ # no @target means the target is not highlightable
38
+ return [] unless @target
39
+
40
+ visit(@document.tree)
41
+ @highlights
42
+ end
43
+
44
+ def visit_var_field(node)
45
+ if matches_target?(node.value)
46
+ add_highlight(
47
+ node.value,
48
+ LanguageServer::Protocol::Constant::DocumentHighlightKind::WRITE
49
+ )
50
+ end
51
+
52
+ super
53
+ end
54
+
55
+ def visit_var_ref(node)
56
+ if matches_target?(node.value)
57
+ add_highlight(
58
+ node.value,
59
+ LanguageServer::Protocol::Constant::DocumentHighlightKind::READ
60
+ )
61
+ end
62
+
63
+ super
64
+ end
65
+
66
+ private
67
+
68
+ def find(node, position)
69
+ matched =
70
+ node.child_nodes.compact.bsearch do |child|
71
+ if (child.location.start_char...child.location.end_char).cover?(position)
72
+ 0
73
+ else
74
+ position <=> child.location.start_char
75
+ end
76
+ end
77
+
78
+ case matched
79
+ when SyntaxTree::GVar, SyntaxTree::Ident, SyntaxTree::IVar, SyntaxTree::Const, SyntaxTree::CVar
80
+ matched
81
+ when SyntaxTree::Node
82
+ find(matched, position)
83
+ end
84
+ end
85
+
86
+ def matches_target?(node)
87
+ node.is_a?(@target.class) && node.value == @target.value
88
+ end
89
+
90
+ def add_highlight(node, kind)
91
+ range = range_from_syntax_tree_node(node)
92
+ @highlights << LanguageServer::Protocol::Interface::DocumentHighlight.new(range: range, kind: kind)
93
+ end
94
+ end
95
+ end
96
+ end
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module RubyLsp
@@ -210,16 +211,6 @@ module RubyLsp
210
211
 
211
212
  symbol
212
213
  end
213
-
214
- def range_from_syntax_tree_node(node)
215
- loc = node.location
216
-
217
- LanguageServer::Protocol::Interface::Range.new(
218
- start: LanguageServer::Protocol::Interface::Position.new(line: loc.start_line - 1,
219
- character: loc.start_column),
220
- end: LanguageServer::Protocol::Interface::Position.new(line: loc.end_line - 1, character: loc.end_column),
221
- )
222
- end
223
214
  end
224
215
  end
225
216
  end
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module RubyLsp
@@ -148,7 +149,7 @@ module RubyLsp
148
149
  end
149
150
 
150
151
  def add_call_range(node)
151
- receiver = node.receiver
152
+ receiver = T.let(node.receiver, SyntaxTree::Node)
152
153
  loop do
153
154
  case receiver
154
155
  when SyntaxTree::Call
@@ -184,7 +185,7 @@ module RubyLsp
184
185
  end
185
186
 
186
187
  def add_string_concat(node)
187
- left = node.left
188
+ left = T.let(node.left, SyntaxTree::Node)
188
189
  left = left.left while left.is_a?(SyntaxTree::StringConcat)
189
190
 
190
191
  add_lines_range(left.location.start_line, node.right.location.end_line)
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module RubyLsp
@@ -14,7 +15,7 @@ module RubyLsp
14
15
  # end
15
16
  # ```
16
17
  class Formatting < RuboCopRequest
17
- RUBOCOP_FLAGS = (COMMON_RUBOCOP_FLAGS + ["--auto-correct"]).freeze
18
+ RUBOCOP_FLAGS = (COMMON_RUBOCOP_FLAGS + ["--autocorrect"]).freeze
18
19
 
19
20
  def initialize(uri, document)
20
21
  super
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require "rubocop"
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module RubyLsp
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module RubyLsp
@@ -20,7 +21,19 @@ module RubyLsp
20
21
  :variable,
21
22
  :method,
22
23
  ].freeze
23
- TOKEN_MODIFIERS = [].freeze
24
+
25
+ TOKEN_MODIFIERS = {
26
+ declaration: 0,
27
+ definition: 1,
28
+ readonly: 2,
29
+ static: 3,
30
+ deprecated: 4,
31
+ abstract: 5,
32
+ async: 6,
33
+ modification: 7,
34
+ documentation: 8,
35
+ default_library: 9,
36
+ }.freeze
24
37
 
25
38
  SemanticToken = Struct.new(:location, :length, :type, :modifier)
26
39
 
@@ -89,9 +102,10 @@ module RubyLsp
89
102
  add_token(node.value.location, :method)
90
103
  end
91
104
 
92
- def add_token(location, type)
105
+ def add_token(location, type, modifiers = [])
93
106
  length = location.end_char - location.start_char
94
- @tokens.push(SemanticToken.new(location, length, TOKEN_TYPES.index(type), 0))
107
+ modifiers_indices = modifiers.filter_map { |modifier| TOKEN_MODIFIERS[modifier] }
108
+ @tokens.push(SemanticToken.new(location, length, TOKEN_TYPES.index(type), modifiers_indices))
95
109
  end
96
110
  end
97
111
  end
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module RubyLsp
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module RubyLsp
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module RubyLsp
@@ -38,11 +39,21 @@ module RubyLsp
38
39
  delta_column = column
39
40
  delta_column -= @current_column if delta_line == 0
40
41
 
41
- [delta_line, delta_column, token.length, token.type, token.modifier]
42
+ [delta_line, delta_column, token.length, token.type, encode_modifiers(token.modifier)]
42
43
  ensure
43
44
  @current_row = row
44
45
  @current_column = column
45
46
  end
47
+
48
+ # Encode an array of modifiers to positions onto a bit flag
49
+ # For example, [:default_library] will be encoded as
50
+ # 0b1000000000, as :default_library is the 10th bit according
51
+ # to the token modifiers index map.
52
+ def encode_modifiers(modifiers)
53
+ modifiers.inject(0) do |encoded_modifiers, modifier|
54
+ encoded_modifiers | (1 << modifier)
55
+ end
56
+ end
46
57
  end
47
58
  end
48
59
  end
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module RubyLsp
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module RubyLsp
@@ -11,6 +12,7 @@ module RubyLsp
11
12
  autoload :Formatting, "ruby_lsp/requests/formatting"
12
13
  autoload :Diagnostics, "ruby_lsp/requests/diagnostics"
13
14
  autoload :CodeActions, "ruby_lsp/requests/code_actions"
15
+ autoload :DocumentHighlight, "ruby_lsp/requests/document_highlight"
14
16
 
15
17
  module Support
16
18
  autoload :RuboCopDiagnostic, "ruby_lsp/requests/support/rubocop_diagnostic"
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require "cgi"
@@ -6,36 +7,51 @@ require "ruby_lsp/document"
6
7
 
7
8
  module RubyLsp
8
9
  class Store
10
+ extend T::Sig
11
+
12
+ sig { void }
9
13
  def initialize
10
- @state = {}
14
+ @state = T.let({}, T::Hash[String, Document])
11
15
  end
12
16
 
17
+ sig { params(uri: String).returns(Document) }
13
18
  def get(uri)
14
19
  document = @state[uri]
15
20
  return document unless document.nil?
16
21
 
17
22
  set(uri, File.binread(CGI.unescape(URI.parse(uri).path)))
18
- @state[uri]
23
+ T.must(@state[uri])
19
24
  end
20
25
 
26
+ sig { params(uri: String, content: String).void }
21
27
  def set(uri, content)
22
28
  @state[uri] = Document.new(content)
23
29
  rescue SyntaxTree::Parser::ParseError
24
30
  # Do not update the store if there are syntax errors
25
31
  end
26
32
 
33
+ sig { params(uri: String, edits: T::Array[Document::EditShape]).void }
27
34
  def push_edits(uri, edits)
28
- @state[uri].push_edits(edits)
35
+ T.must(@state[uri]).push_edits(edits)
29
36
  end
30
37
 
38
+ sig { void }
31
39
  def clear
32
40
  @state.clear
33
41
  end
34
42
 
43
+ sig { params(uri: String).void }
35
44
  def delete(uri)
36
45
  @state.delete(uri)
37
46
  end
38
47
 
48
+ sig do
49
+ params(
50
+ uri: String,
51
+ request_name: Symbol,
52
+ block: T.proc.params(document: Document).returns(T.untyped)
53
+ ).returns(T.untyped)
54
+ end
39
55
  def cache_fetch(uri, request_name, &block)
40
56
  get(uri).cache_fetch(request_name, &block)
41
57
  end
@@ -1,3 +1,4 @@
1
+ # typed: false
1
2
  # frozen_string_literal: true
2
3
 
3
4
  desc "Check if all LSP requests are documented"
@@ -14,7 +15,9 @@ task :check_docs do
14
15
  end
15
16
 
16
17
  spec_matcher = %r{\(https://microsoft.github.io/language-server-protocol/specification#.*\)}
17
- error_messages = RubyLsp::Requests.constants.each_with_object(Hash.new { |h, k| h[k] = [] }) do |request, errors|
18
+ error_messages = RubyLsp::Requests
19
+ .constants # rubocop:disable Sorbet/ConstantsFromStrings
20
+ .each_with_object(Hash.new { |h, k| h[k] = [] }) do |request, errors|
18
21
  full_name = "RubyLsp::Requests::#{request}"
19
22
  docs = YARD::Registry.at(full_name).docstring
20
23
  next if /:nodoc:/.match?(docs)
data/ruby-lsp.gemspec CHANGED
@@ -21,5 +21,6 @@ Gem::Specification.new do |s|
21
21
 
22
22
  s.add_dependency("language_server-protocol")
23
23
  s.add_dependency("rubocop", ">= 1.0")
24
+ s.add_dependency("sorbet-runtime")
24
25
  s.add_dependency("syntax_tree", ">= 2.3")
25
26
  end
data/sorbet/config ADDED
@@ -0,0 +1,4 @@
1
+ --dir
2
+ .
3
+ --ignore=vendor/
4
+ --ignore=test/fixtures/
@@ -0,0 +1,8 @@
1
+ inherit_gem:
2
+ rubocop-sorbet: config/rbi.yml
3
+
4
+ Lint/EmptyFile:
5
+ Enabled: false
6
+
7
+ Sorbet/TypeAliasName:
8
+ Enabled: false