ruby-lsp 0.0.4 → 0.2.1

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 (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