ruby-lsp 0.1.0 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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