ruby-lsp 0.0.4 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +11 -1
  3. data/CHANGELOG.md +35 -0
  4. data/Gemfile +4 -3
  5. data/Gemfile.lock +26 -24
  6. data/README.md +3 -2
  7. data/Rakefile +8 -1
  8. data/VERSION +1 -1
  9. data/bin/console +19 -0
  10. data/exe/ruby-lsp +1 -3
  11. data/lib/ruby_lsp/document.rb +17 -4
  12. data/lib/ruby_lsp/handler.rb +54 -141
  13. data/lib/{internal.rb → ruby_lsp/internal.rb} +4 -2
  14. data/lib/ruby_lsp/requests/base_request.rb +9 -7
  15. data/lib/ruby_lsp/requests/code_actions.rb +20 -9
  16. data/lib/ruby_lsp/requests/diagnostics.rb +25 -8
  17. data/lib/ruby_lsp/requests/document_highlight.rb +32 -32
  18. data/lib/ruby_lsp/requests/document_symbol.rb +59 -10
  19. data/lib/ruby_lsp/requests/folding_ranges.rb +73 -34
  20. data/lib/ruby_lsp/requests/formatting.rb +25 -15
  21. data/lib/ruby_lsp/requests/selection_ranges.rb +18 -5
  22. data/lib/ruby_lsp/requests/semantic_highlighting.rb +179 -36
  23. data/lib/ruby_lsp/requests/support/highlight_target.rb +87 -0
  24. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +16 -4
  25. data/lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb +61 -0
  26. data/lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb +50 -0
  27. data/lib/ruby_lsp/requests/support/selection_range.rb +4 -1
  28. data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +13 -3
  29. data/lib/ruby_lsp/requests/support/syntax_error_diagnostic.rb +6 -1
  30. data/lib/ruby_lsp/requests.rb +13 -2
  31. data/lib/ruby_lsp/server.rb +160 -0
  32. data/lib/ruby_lsp/store.rb +17 -9
  33. data/rakelib/check_docs.rake +30 -5
  34. data/ruby-lsp.gemspec +6 -5
  35. data/sorbet/tapioca/require.rb +1 -1
  36. metadata +14 -26
  37. data/lib/ruby_lsp/cli.rb +0 -88
  38. data/lib/ruby_lsp/requests/rubocop_request.rb +0 -50
  39. data/shipit.production.yml +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab0e94532c080cf6e443c95d9ca7ccb16f548ec45768dc58e95fd691c907a965
4
- data.tar.gz: 856df7b413ef111e100ee42da541856843d966184f9dbe1dfe2ee5a50da1e802
3
+ metadata.gz: d067270389ee6b02bb03fb6363e272b6808e7c3d27d77354442801d09a617149
4
+ data.tar.gz: 74e7cd206a790a8c139969f5167ab3d38686f78646c619488153fd8ab139892e
5
5
  SHA512:
6
- metadata.gz: fde4cd9c5e556ff926b22d316d1bfcc5d31c089850d4558ac7d954fe33df4c8d2b8f8c14e55d1dcc2898087d0d29e8b12fc2f768e2b14935fa727f9620ff5c9e
7
- data.tar.gz: 24fb12213f36edcee13fe65d53a94977737b251566d2503dc857dc276192d6f570f93147f57fc5e3b23c8d90b2c1f96f4cc7e308d5b969a02705d39444676f95
6
+ metadata.gz: 8d65637f892541a79fde71e3f523dfc37c887ec4892315ffe58b450718c8fa6e2a342036c394c28f5a94da0a1348948a104609881109c5621488b9d23a581bc1
7
+ data.tar.gz: 1d25dbac214c23c2af2bd991d4c57bdae9dce488ac886cc700d7ab10a7e3b4a0e72ddc2c1d4be459b332e9cdfac69588d42eac11ff78023d365e0d5ef6701f78
data/.rubocop.yml CHANGED
@@ -25,6 +25,16 @@ Sorbet/FalseSigil:
25
25
  Sorbet/TrueSigil:
26
26
  Enabled: true
27
27
  Include:
28
- - "**/*.rb"
28
+ - "test/**/*.rb"
29
29
  Exclude:
30
30
  - "**/*.rake"
31
+ - "lib/**/*.rb"
32
+
33
+ Sorbet/StrictSigil:
34
+ Enabled: true
35
+ Include:
36
+ - "lib/**/*.rb"
37
+ Exclude:
38
+ - "**/*.rake"
39
+ - "test/**/*.rb"
40
+ - "lib/ruby-lsp.rb"
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.1]
10
+
11
+ - Implement the exit lifecycle request (https://github.com/Shopify/ruby-lsp/pull/198)
12
+ - Remove the Sorbet runtime from the gem's default load path (https://github.com/Shopify/ruby-lsp/pull/214)
13
+ - Return nil if the document is already formatted (https://github.com/Shopify/ruby-lsp/pull/216)
14
+ - Handle nameless keyword rest parameters in semantic highlighting (https://github.com/Shopify/ruby-lsp/pull/222)
15
+ - Display a warning on invalid RuboCop configuration (https://github.com/Shopify/ruby-lsp/pull/226)
16
+ - Centralize request handling logic in server.rb (https://github.com/Shopify/ruby-lsp/pull/221)
17
+ - Fix folding ranges for chained invocations involving an FCall (https://github.com/Shopify/ruby-lsp/pull/223)
18
+ - Fix handling of argument fowarding in semantic highlighting (https://github.com/Shopify/ruby-lsp/pull/228)
19
+ - Recover from initial syntax errors when opening documents (https://github.com/Shopify/ruby-lsp/pull/224)
20
+ - Highlight occurrences and definitions in document highlight (https://github.com/Shopify/ruby-lsp/pull/187)
21
+
22
+ ## [0.2.0]
23
+
24
+ - Add semantic token for keyword and keyword rest params (https://github.com/Shopify/ruby-lsp/pull/142)
25
+ - Return error responses on exceptions (https://github.com/Shopify/ruby-lsp/pull/160)
26
+ - Sanitize home directory for telemetry (https://github.com/Shopify/ruby-lsp/pull/171)
27
+ - Avoid adding semantic tokens for special methods (https://github.com/Shopify/ruby-lsp/pull/162)
28
+ - Properly respect excluded files in RuboCop requests (https://github.com/Shopify/ruby-lsp/pull/173)
29
+ - Clear diagnostics when closing files (https://github.com/Shopify/ruby-lsp/pull/174)
30
+ - Avoid pushing ranges for single line partial ranges (https://github.com/Shopify/ruby-lsp/pull/185)
31
+ - Change folding ranges to include closing tokens (https://github.com/Shopify/ruby-lsp/pull/181)
32
+ - Remove RuboCop dependency and fallback to SyntaxTree formatting (https://github.com/Shopify/ruby-lsp/pull/184)
33
+
34
+ ## [0.1.0]
35
+
36
+ - Implement token modifiers in SemanticTokenEncoder ([#112](https://github.com/Shopify/ruby-lsp/pull/112))
37
+ - Add semantic token for name in a method definition ([#133](https://github.com/Shopify/ruby-lsp/pull/133))
38
+ - Add semantic highighting for def endless and singleton method names ([#134](https://github.com/Shopify/ruby-lsp/pull/134))
39
+ - Add semantic token for keyword self ([#137](https://github.com/Shopify/ruby-lsp/pull/137))
40
+ - Add semantic token for constants ([#138](https://github.com/Shopify/ruby-lsp/pull/138))
41
+ - Improve error handling + fix formatting hanging issue ([#149](https://github.com/Shopify/ruby-lsp/pull/149))
42
+ - Set the minimum syntax_tree version to 2.4 ([#151](https://github.com/Shopify/ruby-lsp/pull/151))
43
+
9
44
  ## [0.0.4]
10
45
 
11
46
  - Add basic document highlight (https://github.com/Shopify/ruby-lsp/pull/91)
data/Gemfile CHANGED
@@ -5,11 +5,12 @@ source "https://rubygems.org"
5
5
  gemspec
6
6
 
7
7
  gem "debug", "~> 1.5", require: false
8
- gem "minitest", "~> 5.15"
8
+ gem "minitest", "~> 5.16"
9
9
  gem "minitest-reporters", "~> 1.5"
10
10
  gem "rake", "~> 13.0"
11
- gem "rubocop-shopify", "~> 2.7", require: false
12
- gem "rubocop-minitest", "~> 0.20.0", require: false
11
+ gem "rubocop", ">= 1.0.0"
12
+ gem "rubocop-shopify", "~> 2.8", require: false
13
+ gem "rubocop-minitest", "~> 0.20.1", require: false
13
14
  gem "rubocop-rake", "~> 0.6.0", require: false
14
15
  gem "rubocop-sorbet", "~> 0.6", require: false
15
16
  gem "sorbet-static-and-runtime"
data/Gemfile.lock CHANGED
@@ -1,11 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby-lsp (0.0.4)
4
+ ruby-lsp (0.2.1)
5
5
  language_server-protocol
6
- rubocop (>= 1.0)
7
6
  sorbet-runtime
8
- syntax_tree (>= 2.3)
7
+ syntax_tree (>= 2.4)
9
8
 
10
9
  GEM
11
10
  remote: https://rubygems.org/
@@ -21,9 +20,10 @@ GEM
21
20
  io-console (0.5.11)
22
21
  irb (1.4.1)
23
22
  reline (>= 0.3.0)
23
+ json (2.6.2)
24
24
  language_server-protocol (3.16.0.3)
25
25
  method_source (1.0.0)
26
- minitest (5.15.0)
26
+ minitest (5.16.2)
27
27
  minitest-reporters (1.5.0)
28
28
  ansi
29
29
  builder
@@ -38,7 +38,7 @@ GEM
38
38
  method_source (~> 1.0)
39
39
  rainbow (3.1.1)
40
40
  rake (13.0.6)
41
- rbi (0.0.14)
41
+ rbi (0.0.15)
42
42
  ast
43
43
  parser (>= 2.6.4.0)
44
44
  sorbet-runtime (>= 0.5.9204)
@@ -47,7 +47,8 @@ GEM
47
47
  reline (0.3.1)
48
48
  io-console (~> 0.5)
49
49
  rexml (3.2.5)
50
- rubocop (1.30.0)
50
+ rubocop (1.31.1)
51
+ json (~> 2.3)
51
52
  parallel (~> 1.10)
52
53
  parser (>= 3.1.0.0)
53
54
  rainbow (>= 2.2.2, < 4.0)
@@ -58,30 +59,30 @@ GEM
58
59
  unicode-display_width (>= 1.4.0, < 3.0)
59
60
  rubocop-ast (1.18.0)
60
61
  parser (>= 3.1.1.0)
61
- rubocop-minitest (0.20.0)
62
+ rubocop-minitest (0.20.1)
62
63
  rubocop (>= 0.90, < 2.0)
63
64
  rubocop-rake (0.6.0)
64
65
  rubocop (~> 1.0)
65
- rubocop-shopify (2.7.0)
66
- rubocop (~> 1.30)
67
- rubocop-sorbet (0.6.8)
66
+ rubocop-shopify (2.8.0)
67
+ rubocop (~> 1.31)
68
+ rubocop-sorbet (0.6.11)
68
69
  rubocop (>= 0.90.0)
69
70
  ruby-progressbar (1.11.0)
70
- sorbet (0.5.10073)
71
- sorbet-static (= 0.5.10073)
72
- sorbet-runtime (0.5.10073)
73
- sorbet-static (0.5.10073-universal-darwin-21)
74
- sorbet-static (0.5.10073-x86_64-linux)
75
- sorbet-static-and-runtime (0.5.10073)
76
- sorbet (= 0.5.10073)
77
- sorbet-runtime (= 0.5.10073)
71
+ sorbet (0.5.10139)
72
+ sorbet-static (= 0.5.10139)
73
+ sorbet-runtime (0.5.10139)
74
+ sorbet-static (0.5.10139-universal-darwin-21)
75
+ sorbet-static (0.5.10139-x86_64-linux)
76
+ sorbet-static-and-runtime (0.5.10139)
77
+ sorbet (= 0.5.10139)
78
+ sorbet-runtime (= 0.5.10139)
78
79
  spoom (1.1.11)
79
80
  sorbet (>= 0.5.9204)
80
81
  sorbet-runtime (>= 0.5.9204)
81
82
  thor (>= 0.19.2)
82
- syntax_tree (2.7.1)
83
+ syntax_tree (2.8.0)
83
84
  prettier_print
84
- tapioca (0.8.1)
85
+ tapioca (0.8.3)
85
86
  bundler (>= 1.17.3)
86
87
  parallel (>= 1.21.0)
87
88
  pry (>= 0.12.2)
@@ -91,7 +92,7 @@ GEM
91
92
  thor (>= 1.2.0)
92
93
  yard-sorbet
93
94
  thor (1.2.1)
94
- unicode-display_width (2.1.0)
95
+ unicode-display_width (2.2.0)
95
96
  unparser (0.6.5)
96
97
  diff-lcs (~> 1.3)
97
98
  parser (>= 3.1.0)
@@ -108,12 +109,13 @@ PLATFORMS
108
109
 
109
110
  DEPENDENCIES
110
111
  debug (~> 1.5)
111
- minitest (~> 5.15)
112
+ minitest (~> 5.16)
112
113
  minitest-reporters (~> 1.5)
113
114
  rake (~> 13.0)
114
- rubocop-minitest (~> 0.20.0)
115
+ rubocop (>= 1.0.0)
116
+ rubocop-minitest (~> 0.20.1)
115
117
  rubocop-rake (~> 0.6.0)
116
- rubocop-shopify (~> 2.7)
118
+ rubocop-shopify (~> 2.8)
117
119
  rubocop-sorbet (~> 0.6)
118
120
  ruby-lsp!
119
121
  sorbet-static-and-runtime
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
 
@@ -50,7 +51,7 @@ To add a new expectations test runner for a new request handler:
50
51
  require "expectations/expectations_test_runner"
51
52
 
52
53
  class $HANDLERExpectationsTest < ExpectationsTestRunner
53
- expectations_tests RubyLsp::Requests::$HANDLER, "$EXPECTATIONS_DIR"
54
+ expectations_tests RubyLsp::Requests::$HANDLER, "$EXPECTATIONS_DIR"
54
55
  end
55
56
  ```
56
57
 
data/Rakefile CHANGED
@@ -11,7 +11,14 @@ Rake::TestTask.new(:test) do |t|
11
11
  end
12
12
 
13
13
  YARD::Rake::YardocTask.new do |t|
14
- t.options = ["--markup", "markdown", "--output-dir", "docs"]
14
+ t.options = [
15
+ "--markup",
16
+ "markdown",
17
+ "--output-dir",
18
+ "docs",
19
+ "--asset",
20
+ "misc",
21
+ ]
15
22
  end
16
23
 
17
24
  require "rubocop/rake_task"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.4
1
+ 0.2.1
data/bin/console ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ # typed: strict
3
+ # frozen_string_literal: true
4
+
5
+ require "bundler/setup"
6
+ require_relative "../lib/ruby_lsp/internal"
7
+ require "irb"
8
+
9
+ extend T::Sig
10
+
11
+ sig { params(source: String).returns(RubyLsp::Document) }
12
+ def new_doc(source)
13
+ RubyLsp::Document.new(source)
14
+ end
15
+
16
+ @source = T.let(File.read(File.expand_path("../lib/ruby_lsp/handler.rb", __dir__)), String)
17
+ @document = T.let(new_doc(@source), RubyLsp::Document)
18
+
19
+ IRB.start(__FILE__)
data/exe/ruby-lsp CHANGED
@@ -18,6 +18,4 @@ rescue
18
18
  nil
19
19
  end
20
20
 
21
- require_relative "../lib/internal"
22
-
23
- RubyLsp::Cli.start
21
+ require_relative "../lib/ruby_lsp/server"
@@ -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) }
@@ -32,7 +34,13 @@ module RubyLsp
32
34
  @source == other.source
33
35
  end
34
36
 
35
- sig { params(request_name: Symbol, block: T.proc.params(document: Document).returns(T.untyped)).returns(T.untyped) }
37
+ sig do
38
+ type_parameters(:T)
39
+ .params(
40
+ request_name: Symbol,
41
+ block: T.proc.params(document: Document).returns(T.type_parameter(:T))
42
+ ).returns(T.type_parameter(:T))
43
+ end
36
44
  def cache_fetch(request_name, &block)
37
45
  cached = @cache[request_name]
38
46
  return cached if cached
@@ -61,6 +69,11 @@ module RubyLsp
61
69
  @syntax_error_edits.any?
62
70
  end
63
71
 
72
+ sig { returns(T::Boolean) }
73
+ def parsed?
74
+ !@tree.nil?
75
+ end
76
+
64
77
  private
65
78
 
66
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)
@@ -28,14 +35,7 @@ module RubyLsp
28
35
  sig { void }
29
36
  def start
30
37
  $stderr.puts "Starting Ruby LSP..."
31
- @reader.read do |request|
32
- with_telemetry(request) { handle(request) }
33
- end
34
- end
35
-
36
- sig { params(blk: T.proc.bind(Handler).params(arg0: T.untyped).void).void }
37
- def config(&blk)
38
- instance_exec(&blk)
38
+ @reader.read { |request| handle(request) }
39
39
  end
40
40
 
41
41
  private
@@ -52,11 +52,32 @@ module RubyLsp
52
52
 
53
53
  sig { params(request: T::Hash[Symbol, T.untyped]).void }
54
54
  def handle(request)
55
+ result = T.let(nil, T.untyped)
56
+ error = T.let(nil, T.nilable(StandardError))
55
57
  handler = @handlers[request[:method]]
56
- return unless handler
57
58
 
58
- result = handler.call(request)
59
- @writer.write(id: request[:id], result: result) unless result == VOID
59
+ request_time = Benchmark.realtime do
60
+ if handler
61
+ begin
62
+ result = handler.call(request)
63
+ rescue StandardError => e
64
+ error = e
65
+ end
66
+
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
77
+ end
78
+ end
79
+
80
+ @writer.write(method: "telemetry/event", params: telemetry_params(request, request_time, error))
60
81
  end
61
82
 
62
83
  sig { void }
@@ -65,106 +86,14 @@ module RubyLsp
65
86
  store.clear
66
87
  end
67
88
 
68
- sig { params(enabled_features: T::Array[String]).returns(Interface::InitializeResult) }
69
- def respond_with_capabilities(enabled_features)
70
- document_symbol_provider = if enabled_features.include?("documentSymbols")
71
- Interface::DocumentSymbolClientCapabilities.new(
72
- hierarchical_document_symbol_support: true,
73
- symbol_kind: {
74
- value_set: Requests::DocumentSymbol::SYMBOL_KIND.values,
75
- }
76
- )
77
- end
78
-
79
- folding_ranges_provider = if enabled_features.include?("foldingRanges")
80
- Interface::FoldingRangeClientCapabilities.new(line_folding_only: true)
81
- end
82
-
83
- semantic_tokens_provider = if enabled_features.include?("semanticHighlighting")
84
- Interface::SemanticTokensRegistrationOptions.new(
85
- document_selector: { scheme: "file", language: "ruby" },
86
- legend: Interface::SemanticTokensLegend.new(
87
- token_types: Requests::SemanticHighlighting::TOKEN_TYPES,
88
- token_modifiers: Requests::SemanticHighlighting::TOKEN_MODIFIERS.keys
89
- ),
90
- range: false,
91
- full: {
92
- delta: true,
93
- }
94
- )
95
- end
96
-
97
- Interface::InitializeResult.new(
98
- capabilities: Interface::ServerCapabilities.new(
99
- text_document_sync: Interface::TextDocumentSyncOptions.new(
100
- change: Constant::TextDocumentSyncKind::INCREMENTAL,
101
- open_close: true,
102
- ),
103
- selection_range_provider: enabled_features.include?("selectionRanges"),
104
- document_symbol_provider: document_symbol_provider,
105
- folding_range_provider: folding_ranges_provider,
106
- semantic_tokens_provider: semantic_tokens_provider,
107
- document_formatting_provider: enabled_features.include?("formatting"),
108
- document_highlight_provider: enabled_features.include?("documentHighlights"),
109
- code_action_provider: enabled_features.include?("codeActions")
110
- )
111
- )
112
- end
113
-
114
- sig { params(uri: String).returns(T::Array[LanguageServer::Protocol::Interface::DocumentSymbol]) }
115
- def respond_with_document_symbol(uri)
116
- store.cache_fetch(uri, :document_symbol) do |document|
117
- RubyLsp::Requests::DocumentSymbol.run(document)
118
- end
119
- end
120
-
121
- sig { params(uri: String).returns(T::Array[LanguageServer::Protocol::Interface::FoldingRange]) }
122
- def respond_with_folding_ranges(uri)
123
- store.cache_fetch(uri, :folding_ranges) do |document|
124
- Requests::FoldingRanges.run(document)
125
- end
126
- end
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
134
- def respond_with_selection_ranges(uri, positions)
135
- ranges = store.cache_fetch(uri, :selection_ranges) do |document|
136
- Requests::SelectionRanges.run(document)
137
- end
138
-
139
- # Per the selection range request spec (https://microsoft.github.io/language-server-protocol/specification#textDocument_selectionRange),
140
- # every position in the positions array should have an element at the same index in the response
141
- # array. For positions without a valid selection range, the corresponding element in the response
142
- # array will be nil.
143
- positions.map do |position|
144
- ranges.find do |range|
145
- range.cover?(position)
146
- end
147
- end
148
- end
149
-
150
- sig { params(uri: String).returns(LanguageServer::Protocol::Interface::SemanticTokens) }
151
- def respond_with_semantic_highlighting(uri)
152
- store.cache_fetch(uri, :semantic_highlighting) do |document|
153
- Requests::SemanticHighlighting.new(document, encoder: Requests::Support::SemanticTokenEncoder.new).run
154
- end
155
- end
156
-
157
- sig { params(uri: String).returns(T::Array[LanguageServer::Protocol::Interface::TextEdit]) }
158
- def respond_with_formatting(uri)
159
- Requests::Formatting.run(uri, store.get(uri))
160
- end
161
-
162
89
  sig { params(uri: String).void }
163
90
  def send_diagnostics(uri)
164
91
  response = store.cache_fetch(uri, :diagnostics) do |document|
165
- Requests::Diagnostics.run(uri, document)
92
+ Requests::Diagnostics.new(uri, document).run
166
93
  end
167
94
 
95
+ return if response.nil?
96
+
168
97
  @writer.write(
169
98
  method: "textDocument/publishDiagnostics",
170
99
  params: Interface::PublishDiagnosticsParams.new(
@@ -172,40 +101,24 @@ module RubyLsp
172
101
  diagnostics: response.map(&:to_lsp_diagnostic)
173
102
  )
174
103
  )
104
+ rescue RuboCop::ValidationError => e
105
+ show_message(Constant::MessageType::ERROR, "Error in RuboCop configuration file: #{e.message}")
175
106
  end
176
107
 
177
- sig do
178
- params(uri: String, range: T::Range[Integer]).returns(T::Array[LanguageServer::Protocol::Interface::Diagnostic])
179
- end
180
- def respond_with_code_actions(uri, range)
181
- store.cache_fetch(uri, :code_actions) do |document|
182
- Requests::CodeActions.run(uri, document, range)
183
- end
184
- end
185
-
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)
108
+ sig { params(uri: String).void }
109
+ def clear_diagnostics(uri)
110
+ @writer.write(
111
+ method: "textDocument/publishDiagnostics",
112
+ params: Interface::PublishDiagnosticsParams.new(uri: uri, diagnostics: [])
113
+ )
194
114
  end
195
115
 
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))
200
-
201
- request_time = Benchmark.realtime do
202
- result = block.call
203
- rescue StandardError => e
204
- error = e
205
- end
206
-
207
- @writer.write(method: "telemetry/event", params: telemetry_params(request, request_time, error))
208
- result
116
+ sig { params(type: Integer, message: String).void }
117
+ def show_message(type, message)
118
+ @writer.write(
119
+ method: "window/showMessage",
120
+ params: Interface::ShowMessageParams.new(type: type, message: message)
121
+ )
209
122
  end
210
123
 
211
124
  sig do
@@ -229,7 +142,7 @@ module RubyLsp
229
142
  params[:errorMessage] = error.message
230
143
  end
231
144
 
232
- params[:uri] = uri if uri
145
+ params[:uri] = uri.sub(%r{.*://#{Dir.home}}, "~") if uri
233
146
  params
234
147
  end
235
148
  end
@@ -1,7 +1,9 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
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"
@@ -1,24 +1,26 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
6
  # :nodoc:
7
7
  class BaseRequest < SyntaxTree::Visitor
8
- def self.run(document)
9
- new(document).run
10
- end
8
+ extend T::Sig
9
+ extend T::Helpers
10
+
11
+ abstract!
11
12
 
13
+ sig { params(document: Document).void }
12
14
  def initialize(document)
13
15
  @document = document
14
16
 
15
17
  super()
16
18
  end
17
19
 
18
- def run
19
- raise NotImplementedError, "#{self.class}#run must be implemented"
20
- end
20
+ sig { abstract.returns(Object) }
21
+ def run; end
21
22
 
23
+ sig { params(node: SyntaxTree::Node).returns(LanguageServer::Protocol::Interface::Range) }
22
24
  def range_from_syntax_tree_node(node)
23
25
  loc = node.location
24
26
 
@@ -1,8 +1,10 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
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.
@@ -14,23 +16,32 @@ module RubyLsp
14
16
  # puts "Hello" # --> code action: quick fix indentation
15
17
  # end
16
18
  # ```
17
- class CodeActions
18
- def self.run(uri, document, range)
19
- new(uri, document, range).run
20
- end
19
+ class CodeActions < BaseRequest
20
+ extend T::Sig
21
21
 
22
+ sig do
23
+ params(
24
+ uri: String,
25
+ document: Document,
26
+ range: T::Range[Integer]
27
+ ).void
28
+ end
22
29
  def initialize(uri, document, range)
23
- @document = document
30
+ super(document)
31
+
24
32
  @uri = uri
25
33
  @range = range
26
34
  end
27
35
 
36
+ sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::CodeAction], Object)) }
28
37
  def run
29
- diagnostics = Diagnostics.run(@uri, @document)
30
- corrections = diagnostics.select { |diagnostic| diagnostic.correctable? && diagnostic.in_range?(@range) }
38
+ diagnostics = Diagnostics.new(@uri, @document).run
39
+ corrections = diagnostics.select do |diagnostic|
40
+ diagnostic.correctable? && T.cast(diagnostic, Support::RuboCopDiagnostic).in_range?(@range)
41
+ end
31
42
  return [] if corrections.empty?
32
43
 
33
- corrections.map!(&:to_lsp_code_action)
44
+ T.cast(corrections, T::Array[Support::RuboCopDiagnostic]).map!(&:to_lsp_code_action)
34
45
  end
35
46
  end
36
47
  end