ruby-lsp 0.14.3 → 0.14.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +0 -1
- data/README.md +38 -19
- data/VERSION +1 -1
- data/lib/ruby_lsp/executor.rb +9 -50
- data/lib/ruby_lsp/listeners/completion.rb +57 -12
- data/lib/ruby_lsp/requests/completion.rb +2 -15
- data/lib/ruby_lsp/requests/diagnostics.rb +42 -8
- data/lib/ruby_lsp/requests/on_type_formatting.rb +1 -1
- data/lib/ruby_lsp/utils.rb +16 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4fc74feb692f2c2e902e213dc61a4b3d58f14bcc4520fc7db60bdae022484e6f
|
4
|
+
data.tar.gz: 98f6d5b939bb945119169e2ca3ce060f275b961d421e752774ebea1c25b74c2d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c33776eb483463d1052cdd5a82d1f66d5d507325b09848d0c5d78cea310c218b056bef834f6f6f03e17d87088b65c8cd77f7c214735390e8b5d244a059ea9e7
|
7
|
+
data.tar.gz: 7e57548a8dede5695774c27137b6ab23c8029f8ff8c0551bef8b1cf8f6dd920e9bdb423d4905c6a7f9ac360433da99cdec31efc885a120f4c1684acbd3da9582
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
<p align="center">
|
2
|
+
<img alt="Ruby LSP logo" width="200" src="vscode/icon.png" />
|
3
|
+
</p>
|
4
|
+
|
1
5
|
[![Build Status](https://github.com/Shopify/ruby-lsp/workflows/CI/badge.svg)](https://github.com/Shopify/ruby-lsp/actions/workflows/ci.yml)
|
2
6
|
[![Ruby LSP extension](https://img.shields.io/badge/VS%20Code-Ruby%20LSP-success?logo=visual-studio-code)](https://marketplace.visualstudio.com/items?itemName=Shopify.ruby-lsp)
|
3
7
|
[![Ruby DX Slack](https://img.shields.io/badge/Slack-Ruby%20DX-success?logo=slack)](https://join.slack.com/t/ruby-dx/shared_invite/zt-2c8zjlir6-uUDJl8oIwcen_FS_aA~b6Q)
|
@@ -11,12 +15,38 @@ experience to Ruby developers using modern standards for cross-editor features,
|
|
11
15
|
Want to discuss Ruby developer experience? Consider joining the public
|
12
16
|
[Ruby DX Slack workspace](https://join.slack.com/t/ruby-dx/shared_invite/zt-2c8zjlir6-uUDJl8oIwcen_FS_aA~b6Q).
|
13
17
|
|
18
|
+
## Features
|
19
|
+
|
20
|
+
![Ruby LSP demo](vscode/extras/ruby_lsp_demo.gif)
|
21
|
+
|
22
|
+
The Ruby LSP features include
|
23
|
+
|
24
|
+
- Semantic highlighting
|
25
|
+
- Symbol search and code outline
|
26
|
+
- RuboCop errors and warnings (diagnostics)
|
27
|
+
- Format on save (with RuboCop or Syntax Tree)
|
28
|
+
- Format on type
|
29
|
+
- Debugging support
|
30
|
+
- Running and debugging tests through VS Code's UI
|
31
|
+
- Go to definition for classes, modules, constants and required files
|
32
|
+
- Showing documentaton on hover for classes, modules and constants
|
33
|
+
- Completion for classes, modules, constants and require paths
|
34
|
+
- Fuzzy search classes, modules and constants anywhere in the project and its dependencies (workspace symbol)
|
35
|
+
|
36
|
+
Adding method support for definition, completion, hover and workspace symbol is planned, but not yet completed.
|
37
|
+
|
38
|
+
See complete information about features [here](https://shopify.github.io/ruby-lsp/RubyLsp/Requests.html).
|
39
|
+
|
40
|
+
If you experience issues, please see the [troubleshooting
|
41
|
+
guide](https://github.com/Shopify/ruby-lsp/blob/main/TROUBLESHOOTING.md).
|
42
|
+
|
14
43
|
## Usage
|
15
44
|
|
16
45
|
### With VS Code
|
17
46
|
|
18
|
-
If using VS Code, all you have to do is install the [Ruby LSP
|
19
|
-
get the extra features in the
|
47
|
+
If using VS Code, all you have to do is install the [Ruby LSP
|
48
|
+
extension](https://marketplace.visualstudio.com/items?itemName=Shopify.ruby-lsp) to get the extra features in the
|
49
|
+
editor. Do not install the `ruby-lsp` gem manually.
|
20
50
|
|
21
51
|
### With other editors
|
22
52
|
|
@@ -27,16 +57,8 @@ The gem can be installed by doing
|
|
27
57
|
gem install ruby-lsp
|
28
58
|
```
|
29
59
|
|
30
|
-
|
31
|
-
|
32
|
-
application (e.g.: the correct RuboCop version).
|
33
|
-
|
34
|
-
For older versions, if you decide to add the gem to the bundle, it is not necessary to require it.
|
35
|
-
```ruby
|
36
|
-
group :development do
|
37
|
-
gem "ruby-lsp", require: false
|
38
|
-
end
|
39
|
-
```
|
60
|
+
and the language server can be launched running `ruby-lsp` (without bundle exec in order to properly hook into your
|
61
|
+
project's dependencies).
|
40
62
|
|
41
63
|
### Documentation
|
42
64
|
|
@@ -98,16 +120,13 @@ For instructions on how to create addons, see the [addons documentation](ADDONS.
|
|
98
120
|
|
99
121
|
## Contributing
|
100
122
|
|
101
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/ruby-lsp.
|
102
|
-
|
103
|
-
|
104
|
-
[Contributor Covenant](CODE_OF_CONDUCT.md)
|
105
|
-
code of conduct.
|
123
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/ruby-lsp. This project is intended to
|
124
|
+
be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor
|
125
|
+
Covenant](CODE_OF_CONDUCT.md) code of conduct.
|
106
126
|
|
107
127
|
If you wish to contribute, see [CONTRIBUTING](CONTRIBUTING.md) for development instructions and check out our pinned
|
108
128
|
[roadmap issue](https://github.com/Shopify/ruby-lsp/issues) for a list of tasks to get started.
|
109
129
|
|
110
130
|
## License
|
111
131
|
|
112
|
-
The gem is available as open source under the terms of the
|
113
|
-
[MIT License](LICENSE.txt).
|
132
|
+
The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.14.
|
1
|
+
0.14.4
|
data/lib/ruby_lsp/executor.rb
CHANGED
@@ -121,24 +121,10 @@ module RubyLsp
|
|
121
121
|
begin
|
122
122
|
formatting(uri)
|
123
123
|
rescue Requests::Formatting::InvalidFormatter => error
|
124
|
-
@message_queue << Notification.
|
125
|
-
message: "window/showMessage",
|
126
|
-
params: Interface::ShowMessageParams.new(
|
127
|
-
type: Constant::MessageType::ERROR,
|
128
|
-
message: "Configuration error: #{error.message}",
|
129
|
-
),
|
130
|
-
)
|
131
|
-
|
124
|
+
@message_queue << Notification.window_show_error("Configuration error: #{error.message}")
|
132
125
|
nil
|
133
126
|
rescue StandardError, LoadError => error
|
134
|
-
@message_queue << Notification.
|
135
|
-
message: "window/showMessage",
|
136
|
-
params: Interface::ShowMessageParams.new(
|
137
|
-
type: Constant::MessageType::ERROR,
|
138
|
-
message: "Formatting error: #{error.message}",
|
139
|
-
),
|
140
|
-
)
|
141
|
-
|
127
|
+
@message_queue << Notification.window_show_error("Formatting error: #{error.message}")
|
142
128
|
nil
|
143
129
|
end
|
144
130
|
when "textDocument/documentHighlight"
|
@@ -174,14 +160,7 @@ module RubyLsp
|
|
174
160
|
begin
|
175
161
|
diagnostic(uri)
|
176
162
|
rescue StandardError, LoadError => error
|
177
|
-
@message_queue << Notification.
|
178
|
-
message: "window/showMessage",
|
179
|
-
params: Interface::ShowMessageParams.new(
|
180
|
-
type: Constant::MessageType::ERROR,
|
181
|
-
message: "Error running diagnostics: #{error.message}",
|
182
|
-
),
|
183
|
-
)
|
184
|
-
|
163
|
+
@message_queue << Notification.window_show_error("Error running diagnostics: #{error.message}")
|
185
164
|
nil
|
186
165
|
end
|
187
166
|
when "textDocument/completion"
|
@@ -287,13 +266,7 @@ module RubyLsp
|
|
287
266
|
false
|
288
267
|
end
|
289
268
|
rescue StandardError => error
|
290
|
-
@message_queue << Notification.
|
291
|
-
message: "window/showMessage",
|
292
|
-
params: Interface::ShowMessageParams.new(
|
293
|
-
type: Constant::MessageType::ERROR,
|
294
|
-
message: "Error while indexing: #{error.message}",
|
295
|
-
),
|
296
|
-
)
|
269
|
+
@message_queue << Notification.window_show_error("Error while indexing: #{error.message}")
|
297
270
|
end
|
298
271
|
|
299
272
|
# Always end the progress notification even if indexing failed or else it never goes away and the user has no
|
@@ -402,21 +375,11 @@ module RubyLsp
|
|
402
375
|
|
403
376
|
case result
|
404
377
|
when Requests::CodeActionResolve::Error::EmptySelection
|
405
|
-
@message_queue << Notification.
|
406
|
-
message: "window/showMessage",
|
407
|
-
params: Interface::ShowMessageParams.new(
|
408
|
-
type: Constant::MessageType::ERROR,
|
409
|
-
message: "Invalid selection for Extract Variable refactor",
|
410
|
-
),
|
411
|
-
)
|
378
|
+
@message_queue << Notification.window_show_error("Invalid selection for Extract Variable refactor")
|
412
379
|
raise Requests::CodeActionResolve::CodeActionError
|
413
380
|
when Requests::CodeActionResolve::Error::InvalidTargetRange
|
414
|
-
@message_queue << Notification.
|
415
|
-
|
416
|
-
params: Interface::ShowMessageParams.new(
|
417
|
-
type: Constant::MessageType::ERROR,
|
418
|
-
message: "Couldn't find an appropriate location to place extracted refactor",
|
419
|
-
),
|
381
|
+
@message_queue << Notification.window_show_error(
|
382
|
+
"Couldn't find an appropriate location to place extracted refactor",
|
420
383
|
)
|
421
384
|
raise Requests::CodeActionResolve::CodeActionError
|
422
385
|
else
|
@@ -639,12 +602,8 @@ module RubyLsp
|
|
639
602
|
unless defined?(RubyLsp::Requests::Support::RuboCopRunner)
|
640
603
|
@store.formatter = "none"
|
641
604
|
|
642
|
-
@message_queue << Notification.
|
643
|
-
|
644
|
-
params: Interface::ShowMessageParams.new(
|
645
|
-
type: Constant::MessageType::ERROR,
|
646
|
-
message: "Ruby LSP formatter is set to `rubocop` but RuboCop was not found in the Gemfile or gemspec.",
|
647
|
-
),
|
605
|
+
@message_queue << Notification.window_show_error(
|
606
|
+
"Ruby LSP formatter is set to `rubocop` but RuboCop was not found in the Gemfile or gemspec.",
|
648
607
|
)
|
649
608
|
end
|
650
609
|
end
|
@@ -14,30 +14,24 @@ module RubyLsp
|
|
14
14
|
nesting: T::Array[String],
|
15
15
|
typechecker_enabled: T::Boolean,
|
16
16
|
dispatcher: Prism::Dispatcher,
|
17
|
+
uri: URI::Generic,
|
17
18
|
).void
|
18
19
|
end
|
19
|
-
def initialize(response_builder, index, nesting, typechecker_enabled, dispatcher)
|
20
|
+
def initialize(response_builder, index, nesting, typechecker_enabled, dispatcher, uri) # rubocop:disable Metrics/ParameterLists
|
20
21
|
@response_builder = response_builder
|
21
22
|
@index = index
|
22
23
|
@nesting = nesting
|
23
24
|
@typechecker_enabled = typechecker_enabled
|
25
|
+
@uri = uri
|
24
26
|
|
25
27
|
dispatcher.register(
|
26
28
|
self,
|
27
|
-
:on_string_node_enter,
|
28
29
|
:on_constant_path_node_enter,
|
29
30
|
:on_constant_read_node_enter,
|
30
31
|
:on_call_node_enter,
|
31
32
|
)
|
32
33
|
end
|
33
34
|
|
34
|
-
sig { params(node: Prism::StringNode).void }
|
35
|
-
def on_string_node_enter(node)
|
36
|
-
@index.search_require_paths(node.content).map!(&:require_path).sort!.each do |path|
|
37
|
-
@response_builder << build_completion(T.must(path), node)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
35
|
# Handle completion on regular constant references (e.g. `Bar`)
|
42
36
|
sig { params(node: Prism::ConstantReadNode).void }
|
43
37
|
def on_constant_read_node_enter(node)
|
@@ -107,11 +101,64 @@ module RubyLsp
|
|
107
101
|
sig { params(node: Prism::CallNode).void }
|
108
102
|
def on_call_node_enter(node)
|
109
103
|
return if @typechecker_enabled
|
110
|
-
return unless self_receiver?(node)
|
111
104
|
|
112
105
|
name = node.message
|
113
106
|
return unless name
|
114
107
|
|
108
|
+
case name
|
109
|
+
when "require"
|
110
|
+
complete_require(node)
|
111
|
+
when "require_relative"
|
112
|
+
complete_require_relative(node)
|
113
|
+
else
|
114
|
+
complete_self_receiver_method(node, name) if self_receiver?(node)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
sig { params(node: Prism::CallNode).void }
|
121
|
+
def complete_require(node)
|
122
|
+
arguments_node = node.arguments
|
123
|
+
return unless arguments_node
|
124
|
+
|
125
|
+
path_node_to_complete = arguments_node.arguments.first
|
126
|
+
|
127
|
+
return unless path_node_to_complete.is_a?(Prism::StringNode)
|
128
|
+
|
129
|
+
@index.search_require_paths(path_node_to_complete.content).map!(&:require_path).sort!.each do |path|
|
130
|
+
@response_builder << build_completion(T.must(path), path_node_to_complete)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
sig { params(node: Prism::CallNode).void }
|
135
|
+
def complete_require_relative(node)
|
136
|
+
arguments_node = node.arguments
|
137
|
+
return unless arguments_node
|
138
|
+
|
139
|
+
path_node_to_complete = arguments_node.arguments.first
|
140
|
+
|
141
|
+
return unless path_node_to_complete.is_a?(Prism::StringNode)
|
142
|
+
|
143
|
+
origin_dir = Pathname.new(@uri.to_standardized_path).dirname
|
144
|
+
|
145
|
+
path_query = path_node_to_complete.content
|
146
|
+
# if the path is not a directory, glob all possible next characters
|
147
|
+
# for example ../somethi| (where | is the cursor position)
|
148
|
+
# should find files for ../somethi*/
|
149
|
+
path_query += "*/" unless path_query.end_with?("/")
|
150
|
+
path_query += "**/*.rb"
|
151
|
+
|
152
|
+
Dir.glob(path_query, base: origin_dir).sort!.each do |path|
|
153
|
+
@response_builder << build_completion(
|
154
|
+
path.delete_suffix(".rb"),
|
155
|
+
path_node_to_complete,
|
156
|
+
)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
sig { params(node: Prism::CallNode, name: String).void }
|
161
|
+
def complete_self_receiver_method(node, name)
|
115
162
|
receiver_entries = @index[@nesting.join("::")]
|
116
163
|
return unless receiver_entries
|
117
164
|
|
@@ -125,8 +172,6 @@ module RubyLsp
|
|
125
172
|
end
|
126
173
|
end
|
127
174
|
|
128
|
-
private
|
129
|
-
|
130
175
|
sig do
|
131
176
|
params(
|
132
177
|
entry: RubyIndexer::Entry::Member,
|
@@ -68,26 +68,13 @@ module RubyLsp
|
|
68
68
|
ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem],
|
69
69
|
)
|
70
70
|
|
71
|
-
Listeners::Completion.new(@response_builder, index, nesting, typechecker_enabled, dispatcher)
|
71
|
+
Listeners::Completion.new(@response_builder, index, nesting, typechecker_enabled, dispatcher, document.uri)
|
72
72
|
|
73
73
|
return unless matched && parent
|
74
74
|
|
75
75
|
@target = case matched
|
76
76
|
when Prism::CallNode
|
77
|
-
|
78
|
-
|
79
|
-
if message == "require"
|
80
|
-
args = matched.arguments&.arguments
|
81
|
-
return if args.nil? || args.is_a?(Prism::ForwardingArgumentsNode)
|
82
|
-
|
83
|
-
argument = args.first
|
84
|
-
return unless argument.is_a?(Prism::StringNode)
|
85
|
-
return unless (argument.location.start_offset..argument.location.end_offset).cover?(char_position)
|
86
|
-
|
87
|
-
argument
|
88
|
-
else
|
89
|
-
matched
|
90
|
-
end
|
77
|
+
matched
|
91
78
|
when Prism::ConstantReadNode, Prism::ConstantPathNode
|
92
79
|
if parent.is_a?(Prism::ConstantPathNode) && matched.is_a?(Prism::ConstantReadNode)
|
93
80
|
parent
|
@@ -42,27 +42,61 @@ module RubyLsp
|
|
42
42
|
|
43
43
|
sig { override.returns(T.nilable(T.all(T::Array[Interface::Diagnostic], Object))) }
|
44
44
|
def perform
|
45
|
+
diagnostics = []
|
46
|
+
diagnostics.concat(syntax_error_diagnostics, syntax_warning_diagnostics)
|
47
|
+
|
45
48
|
# Running RuboCop is slow, so to avoid excessive runs we only do so if the file is syntactically valid
|
46
|
-
return
|
47
|
-
|
49
|
+
return diagnostics if @document.syntax_error?
|
50
|
+
|
51
|
+
diagnostics.concat(
|
52
|
+
Support::RuboCopDiagnosticsRunner.instance.run(
|
53
|
+
@uri,
|
54
|
+
@document,
|
55
|
+
).map!(&:to_lsp_diagnostic),
|
56
|
+
) if defined?(Support::RuboCopDiagnosticsRunner)
|
48
57
|
|
49
|
-
|
58
|
+
diagnostics
|
50
59
|
end
|
51
60
|
|
52
61
|
private
|
53
62
|
|
54
|
-
sig { returns(T
|
63
|
+
sig { returns(T::Array[Interface::Diagnostic]) }
|
64
|
+
def syntax_warning_diagnostics
|
65
|
+
@document.parse_result.warnings.map do |warning|
|
66
|
+
location = warning.location
|
67
|
+
|
68
|
+
Interface::Diagnostic.new(
|
69
|
+
source: "Prism",
|
70
|
+
message: warning.message,
|
71
|
+
severity: Constant::DiagnosticSeverity::WARNING,
|
72
|
+
range: Interface::Range.new(
|
73
|
+
start: Interface::Position.new(
|
74
|
+
line: location.start_line - 1,
|
75
|
+
character: location.start_column,
|
76
|
+
),
|
77
|
+
end: Interface::Position.new(
|
78
|
+
line: location.end_line - 1,
|
79
|
+
character: location.end_column,
|
80
|
+
),
|
81
|
+
),
|
82
|
+
)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
sig { returns(T::Array[Interface::Diagnostic]) }
|
55
87
|
def syntax_error_diagnostics
|
56
88
|
@document.parse_result.errors.map do |error|
|
89
|
+
location = error.location
|
90
|
+
|
57
91
|
Interface::Diagnostic.new(
|
58
92
|
range: Interface::Range.new(
|
59
93
|
start: Interface::Position.new(
|
60
|
-
line:
|
61
|
-
character:
|
94
|
+
line: location.start_line - 1,
|
95
|
+
character: location.start_column,
|
62
96
|
),
|
63
97
|
end: Interface::Position.new(
|
64
|
-
line:
|
65
|
-
character:
|
98
|
+
line: location.end_line - 1,
|
99
|
+
character: location.end_column,
|
66
100
|
),
|
67
101
|
),
|
68
102
|
message: error.message,
|
@@ -178,7 +178,7 @@ module RubyLsp
|
|
178
178
|
|
179
179
|
sig { params(line: Integer, character: Integer).void }
|
180
180
|
def move_cursor_to(line, character)
|
181
|
-
return
|
181
|
+
return unless @client_name.start_with?("Visual Studio Code")
|
182
182
|
|
183
183
|
position = Interface::Position.new(
|
184
184
|
line: line,
|
data/lib/ruby_lsp/utils.rb
CHANGED
@@ -41,7 +41,22 @@ module RubyLsp
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
class Notification < Message
|
44
|
+
class Notification < Message
|
45
|
+
class << self
|
46
|
+
extend T::Sig
|
47
|
+
sig { params(message: String).returns(Notification) }
|
48
|
+
def window_show_error(message)
|
49
|
+
new(
|
50
|
+
message: "window/showMessage",
|
51
|
+
params: Interface::ShowMessageParams.new(
|
52
|
+
type: Constant::MessageType::ERROR,
|
53
|
+
message: message,
|
54
|
+
),
|
55
|
+
)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
45
60
|
class Request < Message; end
|
46
61
|
|
47
62
|
# The final result of running a request before its IO is finalized
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-lsp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.14.
|
4
|
+
version: 0.14.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-03-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: language_server-protocol
|