ruby-lsp 0.1.0 → 0.2.2

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 (94) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +35 -0
  3. data/README.md +2 -1
  4. data/VERSION +1 -1
  5. data/exe/ruby-lsp +1 -3
  6. data/lib/ruby-lsp.rb +2 -2
  7. data/lib/ruby_lsp/document.rb +10 -3
  8. data/lib/ruby_lsp/handler.rb +30 -134
  9. data/lib/ruby_lsp/internal.rb +3 -1
  10. data/lib/ruby_lsp/requests/code_actions.rb +2 -0
  11. data/lib/ruby_lsp/requests/diagnostics.rb +14 -9
  12. data/lib/ruby_lsp/requests/document_highlight.rb +27 -42
  13. data/lib/ruby_lsp/requests/document_link.rb +59 -0
  14. data/lib/ruby_lsp/requests/document_symbol.rb +2 -0
  15. data/lib/ruby_lsp/requests/folding_ranges.rb +26 -21
  16. data/lib/ruby_lsp/requests/formatting.rb +21 -16
  17. data/lib/ruby_lsp/requests/selection_ranges.rb +2 -0
  18. data/lib/ruby_lsp/requests/semantic_highlighting.rb +85 -11
  19. data/lib/ruby_lsp/requests/support/highlight_target.rb +88 -0
  20. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +9 -2
  21. data/lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb +61 -0
  22. data/lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb +50 -0
  23. data/lib/ruby_lsp/requests.rb +14 -1
  24. data/lib/ruby_lsp/server.rb +192 -0
  25. data/lib/ruby_lsp/store.rb +12 -5
  26. metadata +10 -87
  27. data/.github/dependabot.yml +0 -11
  28. data/.github/probots.yml +0 -2
  29. data/.github/pull_request_template.md +0 -15
  30. data/.github/workflows/ci.yml +0 -31
  31. data/.github/workflows/publish_docs.yml +0 -32
  32. data/.gitignore +0 -9
  33. data/.rubocop.yml +0 -39
  34. data/.vscode/extensions.json +0 -5
  35. data/.vscode/settings.json +0 -5
  36. data/.vscode/tasks.json +0 -25
  37. data/CODE_OF_CONDUCT.md +0 -78
  38. data/Gemfile +0 -17
  39. data/Gemfile.lock +0 -124
  40. data/Rakefile +0 -21
  41. data/bin/rubocop +0 -29
  42. data/bin/tapioca +0 -29
  43. data/bin/test +0 -9
  44. data/dev.yml +0 -20
  45. data/lib/ruby_lsp/cli.rb +0 -88
  46. data/lib/ruby_lsp/requests/rubocop_request.rb +0 -60
  47. data/rakelib/check_docs.rake +0 -57
  48. data/ruby-lsp.gemspec +0 -26
  49. data/service.yml +0 -2
  50. data/sorbet/config +0 -4
  51. data/sorbet/rbi/.rubocop.yml +0 -8
  52. data/sorbet/rbi/gems/ansi@1.5.0.rbi +0 -338
  53. data/sorbet/rbi/gems/ast@2.4.2.rbi +0 -522
  54. data/sorbet/rbi/gems/builder@3.2.4.rbi +0 -418
  55. data/sorbet/rbi/gems/coderay@1.1.3.rbi +0 -8
  56. data/sorbet/rbi/gems/debug@1.5.0.rbi +0 -1273
  57. data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +0 -867
  58. data/sorbet/rbi/gems/io-console@0.5.11.rbi +0 -8
  59. data/sorbet/rbi/gems/irb@1.4.1.rbi +0 -376
  60. data/sorbet/rbi/gems/language_server-protocol@3.16.0.3.rbi +0 -7325
  61. data/sorbet/rbi/gems/method_source@1.0.0.rbi +0 -8
  62. data/sorbet/rbi/gems/minitest-reporters@1.5.0.rbi +0 -612
  63. data/sorbet/rbi/gems/minitest@5.15.0.rbi +0 -994
  64. data/sorbet/rbi/gems/parallel@1.22.1.rbi +0 -163
  65. data/sorbet/rbi/gems/parser@3.1.2.0.rbi +0 -3968
  66. data/sorbet/rbi/gems/prettier_print@0.1.0.rbi +0 -734
  67. data/sorbet/rbi/gems/pry@0.14.1.rbi +0 -8
  68. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +0 -227
  69. data/sorbet/rbi/gems/rake@13.0.6.rbi +0 -1853
  70. data/sorbet/rbi/gems/rbi@0.0.14.rbi +0 -2337
  71. data/sorbet/rbi/gems/regexp_parser@2.5.0.rbi +0 -1854
  72. data/sorbet/rbi/gems/reline@0.3.1.rbi +0 -1274
  73. data/sorbet/rbi/gems/rexml@3.2.5.rbi +0 -3852
  74. data/sorbet/rbi/gems/rubocop-ast@1.18.0.rbi +0 -4180
  75. data/sorbet/rbi/gems/rubocop-minitest@0.20.0.rbi +0 -1369
  76. data/sorbet/rbi/gems/rubocop-rake@0.6.0.rbi +0 -246
  77. data/sorbet/rbi/gems/rubocop-shopify@2.6.0.rbi +0 -8
  78. data/sorbet/rbi/gems/rubocop-sorbet@0.6.8.rbi +0 -652
  79. data/sorbet/rbi/gems/rubocop@1.30.0.rbi +0 -36729
  80. data/sorbet/rbi/gems/ruby-progressbar@1.11.0.rbi +0 -732
  81. data/sorbet/rbi/gems/spoom@1.1.11.rbi +0 -1600
  82. data/sorbet/rbi/gems/syntax_tree@2.7.1.rbi +0 -6777
  83. data/sorbet/rbi/gems/tapioca@0.8.1.rbi +0 -1972
  84. data/sorbet/rbi/gems/thor@1.2.1.rbi +0 -2921
  85. data/sorbet/rbi/gems/unicode-display_width@2.1.0.rbi +0 -27
  86. data/sorbet/rbi/gems/unparser@0.6.5.rbi +0 -2789
  87. data/sorbet/rbi/gems/webrick@1.7.0.rbi +0 -1779
  88. data/sorbet/rbi/gems/yard-sorbet@0.6.1.rbi +0 -289
  89. data/sorbet/rbi/gems/yard@0.9.27.rbi +0 -13048
  90. data/sorbet/rbi/shims/fiddle.rbi +0 -4
  91. data/sorbet/rbi/shims/hash.rbi +0 -6
  92. data/sorbet/rbi/shims/rdoc.rbi +0 -4
  93. data/sorbet/tapioca/config.yml +0 -13
  94. data/sorbet/tapioca/require.rb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b072ffa3ea73a83aba6d6c32b931c4de30b0de06fd70655d620c3ed95bd8aa4
4
- data.tar.gz: 24568688b20ffed38defcbc0b00708eb22a7dad20a9b5f397348242a64359bfd
3
+ metadata.gz: 0fefb041d92fb2000d3da23248ed622abd596a95264b421349f27d104b85f997
4
+ data.tar.gz: 312918f128e0a49a2f5b2066354df2fe45f9ed37af5e5eace6c76caa101155e5
5
5
  SHA512:
6
- metadata.gz: ea1830f0be08cb291e67d80bbe21dbe17f3e4b4d285b1d9112e004ca2feff32eaca85af755bc2635e3341ab4e64491710c3ba13c5bed617e34495534e1d7a5f8
7
- data.tar.gz: f84b1b27c5c17455d1e8423f1e52f98a754ed123e1722bd536ee7bfdc754952e5d6619c0f4402664a33dc278bdc2422a3e7a37c8de5f172e4456e7a6c08b7a67
6
+ metadata.gz: 7ab96bd356fe94e3a95572bec24053eed9b467c71acec431a80c600e87ea5a3c31f0f2aee20c7b3b407b5aabc9b5736e0bb385dedf2840747c892fe7ad090b69
7
+ data.tar.gz: 2ec3f3c88c851e86e7ef6485c7719a271dbda81717990446900fe121844daac905b5f554833b59769a4c6f626bb50579d5e51970e7a306d206c898d0a289d36c
data/CHANGELOG.md CHANGED
@@ -6,6 +6,41 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.2.2]
10
+
11
+ - Support document links (https://github.com/Shopify/ruby-lsp/pull/195)
12
+ - Avoid returning on request blocks (https://github.com/Shopify/ruby-lsp/pull/232)
13
+ - Better specify gemspec files (https://github.com/Shopify/ruby-lsp/pull/233)
14
+ - Include Kernel instance methods as special methods for semantic highlighting (https://github.com/Shopify/ruby-lsp/pull/231)
15
+ - Fix call processing when message is a :call symbol literal (https://github.com/Shopify/ruby-lsp/pull/236)
16
+ - Alert users about non auto-correctable diagnostics (https://github.com/Shopify/ruby-lsp/pull/230)
17
+ - Let clients pull diagnostics instead of pushing on edits (https://github.com/Shopify/ruby-lsp/pull/242)
18
+
19
+ ## [0.2.1]
20
+
21
+ - Implement the exit lifecycle request (https://github.com/Shopify/ruby-lsp/pull/198)
22
+ - Remove the Sorbet runtime from the gem's default load path (https://github.com/Shopify/ruby-lsp/pull/214)
23
+ - Return nil if the document is already formatted (https://github.com/Shopify/ruby-lsp/pull/216)
24
+ - Handle nameless keyword rest parameters in semantic highlighting (https://github.com/Shopify/ruby-lsp/pull/222)
25
+ - Display a warning on invalid RuboCop configuration (https://github.com/Shopify/ruby-lsp/pull/226)
26
+ - Centralize request handling logic in server.rb (https://github.com/Shopify/ruby-lsp/pull/221)
27
+ - Fix folding ranges for chained invocations involving an FCall (https://github.com/Shopify/ruby-lsp/pull/223)
28
+ - Fix handling of argument fowarding in semantic highlighting (https://github.com/Shopify/ruby-lsp/pull/228)
29
+ - Recover from initial syntax errors when opening documents (https://github.com/Shopify/ruby-lsp/pull/224)
30
+ - Highlight occurrences and definitions in document highlight (https://github.com/Shopify/ruby-lsp/pull/187)
31
+
32
+ ## [0.2.0]
33
+
34
+ - Add semantic token for keyword and keyword rest params (https://github.com/Shopify/ruby-lsp/pull/142)
35
+ - Return error responses on exceptions (https://github.com/Shopify/ruby-lsp/pull/160)
36
+ - Sanitize home directory for telemetry (https://github.com/Shopify/ruby-lsp/pull/171)
37
+ - Avoid adding semantic tokens for special methods (https://github.com/Shopify/ruby-lsp/pull/162)
38
+ - Properly respect excluded files in RuboCop requests (https://github.com/Shopify/ruby-lsp/pull/173)
39
+ - Clear diagnostics when closing files (https://github.com/Shopify/ruby-lsp/pull/174)
40
+ - Avoid pushing ranges for single line partial ranges (https://github.com/Shopify/ruby-lsp/pull/185)
41
+ - Change folding ranges to include closing tokens (https://github.com/Shopify/ruby-lsp/pull/181)
42
+ - Remove RuboCop dependency and fallback to SyntaxTree formatting (https://github.com/Shopify/ruby-lsp/pull/184)
43
+
9
44
  ## [0.1.0]
10
45
 
11
46
  - Implement token modifiers in SemanticTokenEncoder ([#112](https://github.com/Shopify/ruby-lsp/pull/112))
data/README.md CHANGED
@@ -17,7 +17,8 @@ end
17
17
  If using VS Code, install the [Ruby LSP plugin](https://github.com/Shopify/vscode-ruby-lsp) to get the extra features in
18
18
  the editor.
19
19
 
20
- See the [documentation](https://shopify.github.io/ruby-lsp) for supported features.
20
+ See the [documentation](https://shopify.github.io/ruby-lsp) for
21
+ [supported features](https://shopify.github.io/ruby-lsp/RubyLsp/Requests.html).
21
22
 
22
23
  ## Contributing
23
24
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.2
data/exe/ruby-lsp CHANGED
@@ -18,6 +18,4 @@ rescue
18
18
  nil
19
19
  end
20
20
 
21
- require_relative "../lib/ruby_lsp/internal"
22
-
23
- RubyLsp::Cli.start
21
+ require_relative "../lib/ruby_lsp/server"
data/lib/ruby-lsp.rb CHANGED
@@ -1,6 +1,6 @@
1
- # typed: strict
1
+ # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RubyLsp
5
- VERSION = T.let(File.read(File.expand_path("../VERSION", __dir__)).strip, String)
5
+ VERSION = File.read(File.expand_path("../VERSION", __dir__)).strip
6
6
  end
@@ -9,7 +9,7 @@ module RubyLsp
9
9
  RangeShape = T.type_alias { { start: PositionShape, end: PositionShape } }
10
10
  EditShape = T.type_alias { { range: RangeShape, text: String } }
11
11
 
12
- sig { returns(SyntaxTree::Node) }
12
+ sig { returns(T.nilable(SyntaxTree::Node)) }
13
13
  attr_reader :tree
14
14
 
15
15
  sig { returns(String) }
@@ -20,11 +20,13 @@ module RubyLsp
20
20
 
21
21
  sig { params(source: String).void }
22
22
  def initialize(source)
23
- @tree = T.let(SyntaxTree.parse(source), SyntaxTree::Node)
24
23
  @cache = T.let({}, T::Hash[Symbol, T.untyped])
25
24
  @syntax_error_edits = T.let([], T::Array[EditShape])
26
- @source = source
25
+ @source = T.let(source, String)
27
26
  @parsable_source = T.let(source.dup, String)
27
+ @tree = T.let(SyntaxTree.parse(@source), T.nilable(SyntaxTree::Node))
28
+ rescue SyntaxTree::Parser::ParseError
29
+ # Do not raise if we failed to parse
28
30
  end
29
31
 
30
32
  sig { params(other: Document).returns(T::Boolean) }
@@ -67,6 +69,11 @@ module RubyLsp
67
69
  @syntax_error_edits.any?
68
70
  end
69
71
 
72
+ sig { returns(T::Boolean) }
73
+ def parsed?
74
+ !@tree.nil?
75
+ end
76
+
70
77
  private
71
78
 
72
79
  sig { params(edits: T::Array[EditShape]).void }
@@ -6,17 +6,24 @@ require "ruby_lsp/store"
6
6
  require "benchmark"
7
7
 
8
8
  module RubyLsp
9
+ Interface = LanguageServer::Protocol::Interface
10
+ Constant = LanguageServer::Protocol::Constant
11
+ Transport = LanguageServer::Protocol::Transport
12
+
9
13
  class Handler
10
14
  extend T::Sig
11
15
  VOID = T.let(Object.new.freeze, Object)
12
16
 
17
+ sig { params(blk: T.proc.bind(Handler).params(arg0: T.untyped).void).void }
18
+ def self.start(&blk)
19
+ handler = new
20
+ handler.instance_exec(&blk)
21
+ handler.start
22
+ end
23
+
13
24
  sig { returns(Store) }
14
25
  attr_reader :store
15
26
 
16
- Interface = LanguageServer::Protocol::Interface
17
- Constant = LanguageServer::Protocol::Constant
18
- Transport = LanguageServer::Protocol::Transport
19
-
20
27
  sig { void }
21
28
  def initialize
22
29
  @writer = T.let(Transport::Stdio::Writer.new, Transport::Stdio::Writer)
@@ -31,11 +38,6 @@ module RubyLsp
31
38
  @reader.read { |request| handle(request) }
32
39
  end
33
40
 
34
- sig { params(blk: T.proc.bind(Handler).params(arg0: T.untyped).void).void }
35
- def config(&blk)
36
- instance_exec(&blk)
37
- end
38
-
39
41
  private
40
42
 
41
43
  sig do
@@ -62,7 +64,16 @@ module RubyLsp
62
64
  error = e
63
65
  end
64
66
 
65
- @writer.write(id: request[:id], result: result) unless result == VOID
67
+ if error
68
+ @writer.write(
69
+ {
70
+ id: request[:id],
71
+ error: { code: Constant::ErrorCodes::INTERNAL_ERROR, message: error.inspect, data: request.to_json },
72
+ }
73
+ )
74
+ elsif result != VOID
75
+ @writer.write(id: request[:id], result: result)
76
+ end
66
77
  end
67
78
  end
68
79
 
@@ -75,135 +86,20 @@ module RubyLsp
75
86
  store.clear
76
87
  end
77
88
 
78
- sig { params(enabled_features: T::Array[String]).returns(Interface::InitializeResult) }
79
- def respond_with_capabilities(enabled_features)
80
- document_symbol_provider = if enabled_features.include?("documentSymbols")
81
- Interface::DocumentSymbolClientCapabilities.new(
82
- hierarchical_document_symbol_support: true,
83
- symbol_kind: {
84
- value_set: Requests::DocumentSymbol::SYMBOL_KIND.values,
85
- }
86
- )
87
- end
88
-
89
- folding_ranges_provider = if enabled_features.include?("foldingRanges")
90
- Interface::FoldingRangeClientCapabilities.new(line_folding_only: true)
91
- end
92
-
93
- semantic_tokens_provider = if enabled_features.include?("semanticHighlighting")
94
- Interface::SemanticTokensRegistrationOptions.new(
95
- document_selector: { scheme: "file", language: "ruby" },
96
- legend: Interface::SemanticTokensLegend.new(
97
- token_types: Requests::SemanticHighlighting::TOKEN_TYPES,
98
- token_modifiers: Requests::SemanticHighlighting::TOKEN_MODIFIERS.keys
99
- ),
100
- range: false,
101
- full: {
102
- delta: true,
103
- }
104
- )
105
- end
106
-
107
- Interface::InitializeResult.new(
108
- capabilities: Interface::ServerCapabilities.new(
109
- text_document_sync: Interface::TextDocumentSyncOptions.new(
110
- change: Constant::TextDocumentSyncKind::INCREMENTAL,
111
- open_close: true,
112
- ),
113
- selection_range_provider: enabled_features.include?("selectionRanges"),
114
- document_symbol_provider: document_symbol_provider,
115
- folding_range_provider: folding_ranges_provider,
116
- semantic_tokens_provider: semantic_tokens_provider,
117
- document_formatting_provider: enabled_features.include?("formatting"),
118
- document_highlight_provider: enabled_features.include?("documentHighlights"),
119
- code_action_provider: enabled_features.include?("codeActions")
120
- )
121
- )
122
- end
123
-
124
- sig { params(uri: String).returns(T::Array[LanguageServer::Protocol::Interface::DocumentSymbol]) }
125
- def respond_with_document_symbol(uri)
126
- store.cache_fetch(uri, :document_symbol) do |document|
127
- RubyLsp::Requests::DocumentSymbol.new(document).run
128
- end
129
- end
130
-
131
- sig { params(uri: String).returns(T::Array[LanguageServer::Protocol::Interface::FoldingRange]) }
132
- def respond_with_folding_ranges(uri)
133
- store.cache_fetch(uri, :folding_ranges) do |document|
134
- Requests::FoldingRanges.new(document).run
135
- end
136
- end
137
-
138
- sig do
139
- params(
140
- uri: String,
141
- positions: T::Array[Document::PositionShape]
142
- ).returns(T::Array[T.nilable(RubyLsp::Requests::Support::SelectionRange)])
143
- end
144
- def respond_with_selection_ranges(uri, positions)
145
- ranges = store.cache_fetch(uri, :selection_ranges) do |document|
146
- Requests::SelectionRanges.new(document).run
147
- end
148
-
149
- # Per the selection range request spec (https://microsoft.github.io/language-server-protocol/specification#textDocument_selectionRange),
150
- # every position in the positions array should have an element at the same index in the response
151
- # array. For positions without a valid selection range, the corresponding element in the response
152
- # array will be nil.
153
- positions.map do |position|
154
- ranges.find do |range|
155
- range.cover?(position)
156
- end
157
- end
158
- end
159
-
160
- sig { params(uri: String).returns(LanguageServer::Protocol::Interface::SemanticTokens) }
161
- def respond_with_semantic_highlighting(uri)
162
- store.cache_fetch(uri, :semantic_highlighting) do |document|
163
- T.cast(
164
- Requests::SemanticHighlighting.new(document, encoder: Requests::Support::SemanticTokenEncoder.new).run,
165
- LanguageServer::Protocol::Interface::SemanticTokens
166
- )
167
- end
168
- end
169
-
170
- sig { params(uri: String).returns(T.nilable(T::Array[LanguageServer::Protocol::Interface::TextEdit])) }
171
- def respond_with_formatting(uri)
172
- Requests::Formatting.new(uri, store.get(uri)).run
173
- end
174
-
175
89
  sig { params(uri: String).void }
176
- def send_diagnostics(uri)
177
- response = store.cache_fetch(uri, :diagnostics) do |document|
178
- Requests::Diagnostics.new(uri, document).run
179
- end
180
-
90
+ def clear_diagnostics(uri)
181
91
  @writer.write(
182
92
  method: "textDocument/publishDiagnostics",
183
- params: Interface::PublishDiagnosticsParams.new(
184
- uri: uri,
185
- diagnostics: response.map(&:to_lsp_diagnostic)
186
- )
93
+ params: Interface::PublishDiagnosticsParams.new(uri: uri, diagnostics: [])
187
94
  )
188
95
  end
189
96
 
190
- sig do
191
- params(uri: String, range: T::Range[Integer]).returns(T::Array[LanguageServer::Protocol::Interface::CodeAction])
192
- end
193
- def respond_with_code_actions(uri, range)
194
- store.cache_fetch(uri, :code_actions) do |document|
195
- Requests::CodeActions.new(uri, document, range).run
196
- end
197
- end
198
-
199
- sig do
200
- params(
201
- uri: String,
202
- position: Document::PositionShape
203
- ).returns(T::Array[LanguageServer::Protocol::Interface::DocumentHighlight])
204
- end
205
- def respond_with_document_highlight(uri, position)
206
- Requests::DocumentHighlight.new(store.get(uri), position).run
97
+ sig { params(type: Integer, message: String).void }
98
+ def show_message(type, message)
99
+ @writer.write(
100
+ method: "window/showMessage",
101
+ params: Interface::ShowMessageParams.new(type: type, message: message)
102
+ )
207
103
  end
208
104
 
209
105
  sig do
@@ -227,7 +123,7 @@ module RubyLsp
227
123
  params[:errorMessage] = error.message
228
124
  end
229
125
 
230
- params[:uri] = uri if uri
126
+ params[:uri] = uri.sub(%r{.*://#{Dir.home}}, "~") if uri
231
127
  params
232
128
  end
233
129
  end
@@ -3,5 +3,7 @@
3
3
 
4
4
  require "sorbet-runtime"
5
5
  require "syntax_tree"
6
+ require "language_server-protocol"
7
+
6
8
  require "ruby-lsp"
7
- require "ruby_lsp/cli"
9
+ require "ruby_lsp/handler"
@@ -3,6 +3,8 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
+ # ![Code actions demo](../../misc/code_actions.gif)
7
+ #
6
8
  # The [code actions](https://microsoft.github.io/language-server-protocol/specification#textDocument_codeAction)
7
9
  # request informs the editor of RuboCop quick fixes that can be applied. These are accesible by hovering over a
8
10
  # specific diagnostic.
@@ -1,8 +1,12 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "ruby_lsp/requests/support/rubocop_diagnostics_runner"
5
+
4
6
  module RubyLsp
5
7
  module Requests
8
+ # ![Diagnostics demo](../../misc/diagnostics.gif)
9
+ #
6
10
  # The
7
11
  # [diagnostics](https://microsoft.github.io/language-server-protocol/specification#textDocument_publishDiagnostics)
8
12
  # request informs the editor of RuboCop offenses for a given file.
@@ -14,9 +18,16 @@ module RubyLsp
14
18
  # puts "Hello" # --> diagnostics: incorrect indentantion
15
19
  # end
16
20
  # ```
17
- class Diagnostics < RuboCopRequest
21
+ class Diagnostics < BaseRequest
18
22
  extend T::Sig
19
23
 
24
+ sig { params(uri: String, document: Document).void }
25
+ def initialize(uri, document)
26
+ super(document)
27
+
28
+ @uri = uri
29
+ end
30
+
20
31
  sig do
21
32
  override.returns(
22
33
  T.any(
@@ -27,15 +38,9 @@ module RubyLsp
27
38
  end
28
39
  def run
29
40
  return syntax_error_diagnostics if @document.syntax_errors?
41
+ return [] unless defined?(Support::RuboCopDiagnosticsRunner)
30
42
 
31
- super
32
-
33
- @diagnostics
34
- end
35
-
36
- sig { params(_file: String, offenses: T::Array[RuboCop::Cop::Offense]).void }
37
- def file_finished(_file, offenses)
38
- @diagnostics = offenses.map { |offense| Support::RuboCopDiagnostic.new(offense, @uri) }
43
+ Support::RuboCopDiagnosticsRunner.instance.run(@uri, @document)
39
44
  end
40
45
 
41
46
  private
@@ -3,6 +3,8 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
+ # ![Document highlight demo](../../misc/document_highlight.gif)
7
+ #
6
8
  # The [document highlight](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentHighlight)
7
9
  # informs the editor all relevant elements of the currently pointed item for highlighting. For example, when
8
10
  # the cursor is on the `F` of the constant `FOO`, the editor should identify other occurences of `FOO`
@@ -23,21 +25,11 @@ module RubyLsp
23
25
  class DocumentHighlight < BaseRequest
24
26
  extend T::Sig
25
27
 
26
- VarNodes = T.type_alias do
27
- T.any(
28
- SyntaxTree::GVar,
29
- SyntaxTree::Ident,
30
- SyntaxTree::IVar,
31
- SyntaxTree::Const,
32
- SyntaxTree::CVar
33
- )
34
- end
35
-
36
28
  sig { params(document: Document, position: Document::PositionShape).void }
37
29
  def initialize(document, position)
38
30
  @highlights = T.let([], T::Array[LanguageServer::Protocol::Interface::DocumentHighlight])
39
31
  position = Document::Scanner.new(document.source).find_position(position)
40
- @target = T.let(find(document.tree, position), T.nilable(VarNodes))
32
+ @target = T.let(find(T.must(document.tree), position), T.nilable(Support::HighlightTarget))
41
33
 
42
34
  super(document)
43
35
  end
@@ -51,33 +43,24 @@ module RubyLsp
51
43
  @highlights
52
44
  end
53
45
 
54
- sig { params(node: SyntaxTree::VarField).void }
55
- def visit_var_field(node)
56
- if matches_target?(node.value)
57
- add_highlight(
58
- node.value,
59
- LanguageServer::Protocol::Constant::DocumentHighlightKind::WRITE
60
- )
61
- end
46
+ sig { params(node: T.nilable(SyntaxTree::Node)).void }
47
+ def visit(node)
48
+ return if node.nil?
62
49
 
63
- super
64
- end
65
-
66
- sig { params(node: SyntaxTree::VarRef).void }
67
- def visit_var_ref(node)
68
- if matches_target?(node.value)
69
- add_highlight(
70
- node.value,
71
- LanguageServer::Protocol::Constant::DocumentHighlightKind::READ
72
- )
73
- end
50
+ match = T.must(@target).highlight_type(node)
51
+ add_highlight(match) if match
74
52
 
75
53
  super
76
54
  end
77
55
 
78
56
  private
79
57
 
80
- sig { params(node: SyntaxTree::Node, position: Integer).returns(T.nilable(VarNodes)) }
58
+ sig do
59
+ params(
60
+ node: SyntaxTree::Node,
61
+ position: Integer,
62
+ ).returns(T.nilable(Support::HighlightTarget))
63
+ end
81
64
  def find(node, position)
82
65
  matched =
83
66
  node.child_nodes.compact.bsearch do |child|
@@ -89,22 +72,24 @@ module RubyLsp
89
72
  end
90
73
 
91
74
  case matched
92
- when SyntaxTree::GVar, SyntaxTree::Ident, SyntaxTree::IVar, SyntaxTree::Const, SyntaxTree::CVar
93
- matched
75
+ when SyntaxTree::GVar,
76
+ SyntaxTree::IVar,
77
+ SyntaxTree::Const,
78
+ SyntaxTree::CVar,
79
+ SyntaxTree::VarField
80
+ Support::HighlightTarget.new(matched)
81
+ when SyntaxTree::Ident
82
+ relevant_node = node.is_a?(SyntaxTree::Params) ? matched : node
83
+ Support::HighlightTarget.new(relevant_node)
94
84
  when SyntaxTree::Node
95
85
  find(matched, position)
96
86
  end
97
87
  end
98
88
 
99
- sig { params(node: SyntaxTree::Node).returns(T::Boolean) }
100
- def matches_target?(node)
101
- node.is_a?(@target.class) && T.cast(node, VarNodes).value == T.must(@target).value
102
- end
103
-
104
- sig { params(node: SyntaxTree::Node, kind: Integer).void }
105
- def add_highlight(node, kind)
106
- range = range_from_syntax_tree_node(node)
107
- @highlights << LanguageServer::Protocol::Interface::DocumentHighlight.new(range: range, kind: kind)
89
+ sig { params(match: Support::HighlightTarget::HighlightMatch).void }
90
+ def add_highlight(match)
91
+ range = range_from_syntax_tree_node(match.node)
92
+ @highlights << LanguageServer::Protocol::Interface::DocumentHighlight.new(range: range, kind: match.type)
108
93
  end
109
94
  end
110
95
  end
@@ -0,0 +1,59 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module Requests
6
+ # ![Document link demo](../../misc/document_link.gif)
7
+ #
8
+ # The [document link](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentLink)
9
+ # makes `# source://PATH_TO_FILE:line` comments in a Ruby/RBI file clickable if the file exists.
10
+ # When the user clicks the link, it'll open that location.
11
+ #
12
+ # # Example
13
+ #
14
+ # ```ruby
15
+ # # source://syntax_tree-3.2.1/lib/syntax_tree.rb:51 <- it will be clickable and will take the user to that location
16
+ # def format(source, maxwidth = T.unsafe(nil))
17
+ # end
18
+ # ```
19
+ class DocumentLink < BaseRequest
20
+ extend T::Sig
21
+
22
+ RUBY_ROOT = "RUBY_ROOT"
23
+
24
+ sig { params(document: Document).void }
25
+ def initialize(document)
26
+ super
27
+
28
+ @links = T.let([], T::Array[LanguageServer::Protocol::Interface::DocumentLink])
29
+ end
30
+
31
+ sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::DocumentLink], Object)) }
32
+ def run
33
+ visit(@document.tree)
34
+ @links
35
+ end
36
+
37
+ sig { params(node: SyntaxTree::Comment).void }
38
+ def visit_comment(node)
39
+ match = node.value.match(%r{source://(?<path>.*):(?<line>\d+)$})
40
+ return unless match
41
+
42
+ file_path = if match[:path].start_with?(RUBY_ROOT)
43
+ match[:path].sub(RUBY_ROOT, RbConfig::CONFIG["rubylibdir"])
44
+ else
45
+ File.join(Bundler.bundle_path, "gems", match[:path])
46
+ end
47
+ return unless File.exist?(file_path)
48
+
49
+ target = "file://#{file_path}##{match[:line]}"
50
+
51
+ @links << LanguageServer::Protocol::Interface::DocumentLink.new(
52
+ range: range_from_syntax_tree_node(node),
53
+ target: target,
54
+ tooltip: "Jump to #{target.delete_prefix("file://")}"
55
+ )
56
+ end
57
+ end
58
+ end
59
+ end
@@ -3,6 +3,8 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
+ # ![Document symbol demo](../../misc/document_symbol.gif)
7
+ #
6
8
  # The [document
7
9
  # symbol](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol) request
8
10
  # informs the editor of all the important symbols, such as classes, variables, and methods, defined in a file. With