ruby-lsp 0.4.4 → 0.5.0
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.
- checksums.yaml +4 -4
- data/README.md +5 -86
- data/VERSION +1 -1
- data/exe/ruby-lsp +10 -1
- data/lib/ruby_lsp/check_docs.rb +112 -0
- data/lib/ruby_lsp/document.rb +13 -2
- data/lib/ruby_lsp/event_emitter.rb +86 -18
- data/lib/ruby_lsp/executor.rb +146 -45
- data/lib/ruby_lsp/extension.rb +104 -0
- data/lib/ruby_lsp/internal.rb +2 -0
- data/lib/ruby_lsp/listener.rb +14 -11
- data/lib/ruby_lsp/requests/base_request.rb +0 -5
- data/lib/ruby_lsp/requests/code_action_resolve.rb +1 -1
- data/lib/ruby_lsp/requests/code_actions.rb +1 -1
- data/lib/ruby_lsp/requests/code_lens.rb +82 -66
- data/lib/ruby_lsp/requests/diagnostics.rb +2 -2
- data/lib/ruby_lsp/requests/document_highlight.rb +1 -1
- data/lib/ruby_lsp/requests/document_link.rb +17 -15
- data/lib/ruby_lsp/requests/document_symbol.rb +51 -31
- data/lib/ruby_lsp/requests/folding_ranges.rb +1 -1
- data/lib/ruby_lsp/requests/formatting.rb +10 -11
- data/lib/ruby_lsp/requests/hover.rb +34 -19
- data/lib/ruby_lsp/requests/inlay_hints.rb +1 -1
- data/lib/ruby_lsp/requests/on_type_formatting.rb +5 -1
- data/lib/ruby_lsp/requests/path_completion.rb +21 -57
- data/lib/ruby_lsp/requests/selection_ranges.rb +1 -1
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +1 -1
- data/lib/ruby_lsp/requests/support/common.rb +36 -0
- data/lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb +0 -1
- data/lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb +0 -1
- data/lib/ruby_lsp/requests/support/syntax_tree_formatting_runner.rb +5 -2
- data/lib/ruby_lsp/requests.rb +15 -15
- data/lib/ruby_lsp/server.rb +44 -11
- data/lib/ruby_lsp/store.rb +1 -1
- data/lib/ruby_lsp/utils.rb +9 -8
- metadata +5 -3
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
module RubyLsp
|
5
5
|
module Requests
|
6
|
-
# 
|
7
7
|
#
|
8
8
|
# The [completion](https://microsoft.github.io/language-server-protocol/specification#textDocument_completion)
|
9
9
|
# request looks up Ruby files in the $LOAD_PATH to suggest path completion inside `require` statements.
|
@@ -13,29 +13,28 @@ module RubyLsp
|
|
13
13
|
# ```ruby
|
14
14
|
# require "ruby_lsp/requests" # --> completion: suggests `base_request`, `code_actions`, ...
|
15
15
|
# ```
|
16
|
-
class PathCompletion <
|
16
|
+
class PathCompletion < Listener
|
17
17
|
extend T::Sig
|
18
|
+
extend T::Generic
|
18
19
|
|
19
|
-
|
20
|
-
def initialize(document, position)
|
21
|
-
super(document)
|
20
|
+
ResponseType = type_member { { fixed: T::Array[Interface::CompletionItem] } }
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
end
|
22
|
+
sig { override.returns(ResponseType) }
|
23
|
+
attr_reader :response
|
26
24
|
|
27
|
-
sig {
|
28
|
-
def
|
29
|
-
|
30
|
-
|
25
|
+
sig { params(emitter: EventEmitter, message_queue: Thread::Queue).void }
|
26
|
+
def initialize(emitter, message_queue)
|
27
|
+
super
|
28
|
+
@response = T.let([], ResponseType)
|
29
|
+
@tree = T.let(Support::PrefixTree.new(collect_load_path_files), Support::PrefixTree)
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
return [] unless target
|
31
|
+
emitter.register(self, :on_tstring_content)
|
32
|
+
end
|
35
33
|
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
sig { params(node: SyntaxTree::TStringContent).void }
|
35
|
+
def on_tstring_content(node)
|
36
|
+
@tree.search(node.value).sort.each do |path|
|
37
|
+
@response << build_completion(path, node)
|
39
38
|
end
|
40
39
|
end
|
41
40
|
|
@@ -50,48 +49,13 @@ module RubyLsp
|
|
50
49
|
end
|
51
50
|
end
|
52
51
|
|
53
|
-
sig {
|
54
|
-
def
|
55
|
-
char_position = @document.create_scanner.find_char_position(@position)
|
56
|
-
matched, parent = @document.locate(
|
57
|
-
T.must(@document.tree),
|
58
|
-
char_position,
|
59
|
-
node_types: [SyntaxTree::Command, SyntaxTree::CommandCall, SyntaxTree::CallNode],
|
60
|
-
)
|
61
|
-
|
62
|
-
return unless matched && parent
|
63
|
-
|
64
|
-
case matched
|
65
|
-
when SyntaxTree::Command, SyntaxTree::CallNode, SyntaxTree::CommandCall
|
66
|
-
message = matched.message
|
67
|
-
return if message.is_a?(Symbol)
|
68
|
-
return unless message.value == "require"
|
69
|
-
|
70
|
-
args = matched.arguments
|
71
|
-
args = args.arguments if args.is_a?(SyntaxTree::ArgParen)
|
72
|
-
return if args.nil? || args.is_a?(SyntaxTree::ArgsForward)
|
73
|
-
|
74
|
-
argument = args.parts.first
|
75
|
-
return unless argument.is_a?(SyntaxTree::StringLiteral)
|
76
|
-
|
77
|
-
path_node = argument.parts.first
|
78
|
-
return unless path_node.is_a?(SyntaxTree::TStringContent)
|
79
|
-
return unless (path_node.location.start_char..path_node.location.end_char).cover?(char_position)
|
80
|
-
|
81
|
-
path_node
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
sig { params(label: String, insert_text: String).returns(Interface::CompletionItem) }
|
86
|
-
def build_completion(label, insert_text)
|
52
|
+
sig { params(label: String, node: SyntaxTree::TStringContent).returns(Interface::CompletionItem) }
|
53
|
+
def build_completion(label, node)
|
87
54
|
Interface::CompletionItem.new(
|
88
55
|
label: label,
|
89
56
|
text_edit: Interface::TextEdit.new(
|
90
|
-
range:
|
91
|
-
|
92
|
-
end: @position,
|
93
|
-
),
|
94
|
-
new_text: insert_text,
|
57
|
+
range: range_from_syntax_tree_node(node),
|
58
|
+
new_text: label,
|
95
59
|
),
|
96
60
|
kind: Constant::CompletionItemKind::REFERENCE,
|
97
61
|
)
|
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
module RubyLsp
|
5
5
|
module Requests
|
6
|
-
# 
|
7
7
|
#
|
8
8
|
# The [selection ranges](https://microsoft.github.io/language-server-protocol/specification#textDocument_selectionRange)
|
9
9
|
# request informs the editor of ranges that the user may want to select based on the location(s)
|
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
module RubyLsp
|
5
5
|
module Requests
|
6
|
-
# 
|
7
7
|
#
|
8
8
|
# The [semantic
|
9
9
|
# highlighting](https://microsoft.github.io/language-server-protocol/specification#textDocument_semanticTokens)
|
@@ -49,6 +49,42 @@ module RubyLsp
|
|
49
49
|
loc = node.location
|
50
50
|
range.cover?(loc.start_line - 1) && range.cover?(loc.end_line - 1)
|
51
51
|
end
|
52
|
+
|
53
|
+
sig do
|
54
|
+
params(
|
55
|
+
node: SyntaxTree::Node,
|
56
|
+
title: String,
|
57
|
+
command_name: String,
|
58
|
+
path: String,
|
59
|
+
name: String,
|
60
|
+
test_command: String,
|
61
|
+
type: String,
|
62
|
+
).returns(Interface::CodeLens)
|
63
|
+
end
|
64
|
+
def create_code_lens(node, title:, command_name:, path:, name:, test_command:, type:)
|
65
|
+
range = range_from_syntax_tree_node(node)
|
66
|
+
arguments = [
|
67
|
+
path,
|
68
|
+
name,
|
69
|
+
test_command,
|
70
|
+
{
|
71
|
+
start_line: node.location.start_line - 1,
|
72
|
+
start_column: node.location.start_column,
|
73
|
+
end_line: node.location.end_line - 1,
|
74
|
+
end_column: node.location.end_column,
|
75
|
+
},
|
76
|
+
]
|
77
|
+
|
78
|
+
Interface::CodeLens.new(
|
79
|
+
range: range,
|
80
|
+
command: Interface::Command.new(
|
81
|
+
title: title,
|
82
|
+
command: command_name,
|
83
|
+
arguments: arguments,
|
84
|
+
),
|
85
|
+
data: { type: type },
|
86
|
+
)
|
87
|
+
end
|
52
88
|
end
|
53
89
|
end
|
54
90
|
end
|
@@ -25,8 +25,11 @@ module RubyLsp
|
|
25
25
|
)
|
26
26
|
end
|
27
27
|
|
28
|
-
sig { params(
|
29
|
-
def run(
|
28
|
+
sig { params(uri: String, document: Document).returns(T.nilable(String)) }
|
29
|
+
def run(uri, document)
|
30
|
+
relative_path = Pathname.new(URI(uri).path).relative_path_from(T.must(WORKSPACE_URI.path))
|
31
|
+
return if @options.ignore_files.any? { |pattern| File.fnmatch(pattern, relative_path) }
|
32
|
+
|
30
33
|
SyntaxTree.format(
|
31
34
|
document.source,
|
32
35
|
@options.print_width,
|
data/lib/ruby_lsp/requests.rb
CHANGED
@@ -4,21 +4,21 @@
|
|
4
4
|
module RubyLsp
|
5
5
|
# Supported features
|
6
6
|
#
|
7
|
-
# -
|
8
|
-
# -
|
9
|
-
# -
|
10
|
-
# -
|
11
|
-
# -
|
12
|
-
# -
|
13
|
-
# -
|
14
|
-
# -
|
15
|
-
# -
|
16
|
-
# -
|
17
|
-
# -
|
18
|
-
# -
|
19
|
-
# -
|
20
|
-
# -
|
21
|
-
# -
|
7
|
+
# - [DocumentSymbol](rdoc-ref:RubyLsp::Requests::DocumentSymbol)
|
8
|
+
# - [DocumentLink](rdoc-ref:RubyLsp::Requests::DocumentLink)
|
9
|
+
# - [Hover](rdoc-ref:RubyLsp::Requests::Hover)
|
10
|
+
# - [FoldingRange](rdoc-ref:RubyLsp::Requests::FoldingRanges)
|
11
|
+
# - [SelectionRange](rdoc-ref:RubyLsp::Requests::SelectionRanges)
|
12
|
+
# - [SemanticHighlighting](rdoc-ref:RubyLsp::Requests::SemanticHighlighting)
|
13
|
+
# - [Formatting](rdoc-ref:RubyLsp::Requests::Formatting)
|
14
|
+
# - [OnTypeFormatting](rdoc-ref:RubyLsp::Requests::OnTypeFormatting)
|
15
|
+
# - [Diagnostic](rdoc-ref:RubyLsp::Requests::Diagnostics)
|
16
|
+
# - [CodeAction](rdoc-ref:RubyLsp::Requests::CodeActions)
|
17
|
+
# - [CodeActionResolve](rdoc-ref:RubyLsp::Requests::CodeActionResolve)
|
18
|
+
# - [DocumentHighlight](rdoc-ref:RubyLsp::Requests::DocumentHighlight)
|
19
|
+
# - [InlayHint](rdoc-ref:RubyLsp::Requests::InlayHints)
|
20
|
+
# - [PathCompletion](rdoc-ref:RubyLsp::Requests::PathCompletion)
|
21
|
+
# - [CodeLens](rdoc-ref:RubyLsp::Requests::CodeLens)
|
22
22
|
|
23
23
|
module Requests
|
24
24
|
autoload :BaseRequest, "ruby_lsp/requests/base_request"
|
data/lib/ruby_lsp/server.rb
CHANGED
@@ -24,6 +24,32 @@ module RubyLsp
|
|
24
24
|
@mutex = T.let(Mutex.new, Mutex)
|
25
25
|
@worker = T.let(new_worker, Thread)
|
26
26
|
|
27
|
+
# The messages queue includes requests and notifications to be sent to the client
|
28
|
+
@message_queue = T.let(Thread::Queue.new, Thread::Queue)
|
29
|
+
|
30
|
+
# Create a thread to watch the messages queue and send them to the client
|
31
|
+
@message_dispatcher = T.let(
|
32
|
+
Thread.new do
|
33
|
+
current_request_id = 1
|
34
|
+
|
35
|
+
loop do
|
36
|
+
message = @message_queue.pop
|
37
|
+
break if message.nil?
|
38
|
+
|
39
|
+
@mutex.synchronize do
|
40
|
+
case message
|
41
|
+
when Notification
|
42
|
+
@writer.write(method: message.message, params: message.params)
|
43
|
+
when Request
|
44
|
+
@writer.write(id: current_request_id, method: message.message, params: message.params)
|
45
|
+
current_request_id += 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end,
|
50
|
+
Thread,
|
51
|
+
)
|
52
|
+
|
27
53
|
Thread.main.priority = 1
|
28
54
|
end
|
29
55
|
|
@@ -35,9 +61,8 @@ module RubyLsp
|
|
35
61
|
# fall under the else branch which just pushes requests to the queue
|
36
62
|
@reader.read do |request|
|
37
63
|
case request[:method]
|
38
|
-
when "initialize", "initialized", "textDocument/didOpen", "textDocument/didClose", "textDocument/didChange"
|
39
|
-
|
40
|
-
result = Executor.new(@store).execute(request)
|
64
|
+
when "initialize", "initialized", "textDocument/didOpen", "textDocument/didClose", "textDocument/didChange"
|
65
|
+
result = Executor.new(@store, @message_queue).execute(request)
|
41
66
|
finalize_request(result, request)
|
42
67
|
when "$/cancelRequest"
|
43
68
|
# Cancel the job if it's still in the queue
|
@@ -45,6 +70,7 @@ module RubyLsp
|
|
45
70
|
when "shutdown"
|
46
71
|
warn("Shutting down Ruby LSP...")
|
47
72
|
|
73
|
+
@message_queue.close
|
48
74
|
# Close the queue so that we can no longer receive items
|
49
75
|
@job_queue.close
|
50
76
|
# Clear any remaining jobs so that the thread can terminate
|
@@ -52,9 +78,10 @@ module RubyLsp
|
|
52
78
|
@jobs.clear
|
53
79
|
# Wait until the thread is finished
|
54
80
|
@worker.join
|
81
|
+
@message_dispatcher.join
|
55
82
|
@store.clear
|
56
83
|
|
57
|
-
finalize_request(Result.new(response: nil
|
84
|
+
finalize_request(Result.new(response: nil), request)
|
58
85
|
when "exit"
|
59
86
|
# We return zero if shutdown has already been received or one otherwise as per the recommendation in the spec
|
60
87
|
# https://microsoft.github.io/language-server-protocol/specification/#exit
|
@@ -65,8 +92,17 @@ module RubyLsp
|
|
65
92
|
# Default case: push the request to the queue to be executed by the worker
|
66
93
|
job = Job.new(request: request, cancelled: false)
|
67
94
|
|
68
|
-
|
69
|
-
|
95
|
+
@mutex.synchronize do
|
96
|
+
# Remember a handle to the job, so that we can cancel it
|
97
|
+
@jobs[request[:id]] = job
|
98
|
+
|
99
|
+
# We must parse the document under a mutex lock or else we might switch threads and accept text edits in the
|
100
|
+
# source. Altering the source reference during parsing will put the parser in an invalid internal state,
|
101
|
+
# since it started parsing with one source but then it changed in the middle
|
102
|
+
uri = request.dig(:params, :textDocument, :uri)
|
103
|
+
@store.get(uri).parse if uri
|
104
|
+
end
|
105
|
+
|
70
106
|
@job_queue << job
|
71
107
|
end
|
72
108
|
end
|
@@ -88,9 +124,9 @@ module RubyLsp
|
|
88
124
|
|
89
125
|
result = if job.cancelled
|
90
126
|
# We need to return nil to the client even if the request was cancelled
|
91
|
-
Result.new(response: nil
|
127
|
+
Result.new(response: nil)
|
92
128
|
else
|
93
|
-
Executor.new(@store).execute(request)
|
129
|
+
Executor.new(@store, @message_queue).execute(request)
|
94
130
|
end
|
95
131
|
|
96
132
|
finalize_request(result, request)
|
@@ -105,9 +141,6 @@ module RubyLsp
|
|
105
141
|
error = result.error
|
106
142
|
response = result.response
|
107
143
|
|
108
|
-
# If the response include any notifications, go through them and publish each one
|
109
|
-
result.notifications.each { |n| @writer.write(method: n.message, params: n.params) }
|
110
|
-
|
111
144
|
if error
|
112
145
|
@writer.write(
|
113
146
|
id: request[:id],
|
data/lib/ruby_lsp/store.rb
CHANGED
data/lib/ruby_lsp/utils.rb
CHANGED
@@ -6,11 +6,14 @@ module RubyLsp
|
|
6
6
|
VOID = T.let(Object.new.freeze, Object)
|
7
7
|
|
8
8
|
# This freeze is not redundant since the interpolated string is mutable
|
9
|
-
WORKSPACE_URI = T.let("file://#{Dir.pwd}".freeze,
|
9
|
+
WORKSPACE_URI = T.let(URI("file://#{Dir.pwd}".freeze), URI::Generic) # rubocop:disable Style/RedundantFreeze
|
10
10
|
|
11
11
|
# A notification to be sent to the client
|
12
|
-
class
|
12
|
+
class Message
|
13
13
|
extend T::Sig
|
14
|
+
extend T::Helpers
|
15
|
+
|
16
|
+
abstract!
|
14
17
|
|
15
18
|
sig { returns(String) }
|
16
19
|
attr_reader :message
|
@@ -25,6 +28,9 @@ module RubyLsp
|
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
31
|
+
class Notification < Message; end
|
32
|
+
class Request < Message; end
|
33
|
+
|
28
34
|
# The final result of running a request before its IO is finalized
|
29
35
|
class Result
|
30
36
|
extend T::Sig
|
@@ -32,9 +38,6 @@ module RubyLsp
|
|
32
38
|
sig { returns(T.untyped) }
|
33
39
|
attr_reader :response
|
34
40
|
|
35
|
-
sig { returns(T::Array[Notification]) }
|
36
|
-
attr_reader :notifications
|
37
|
-
|
38
41
|
sig { returns(T.nilable(Exception)) }
|
39
42
|
attr_reader :error
|
40
43
|
|
@@ -44,14 +47,12 @@ module RubyLsp
|
|
44
47
|
sig do
|
45
48
|
params(
|
46
49
|
response: T.untyped,
|
47
|
-
notifications: T::Array[Notification],
|
48
50
|
error: T.nilable(Exception),
|
49
51
|
request_time: T.nilable(Float),
|
50
52
|
).void
|
51
53
|
end
|
52
|
-
def initialize(response:,
|
54
|
+
def initialize(response:, error: nil, request_time: nil)
|
53
55
|
@response = response
|
54
|
-
@notifications = notifications
|
55
56
|
@error = error
|
56
57
|
@request_time = request_time
|
57
58
|
end
|
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.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-04
|
11
|
+
date: 2023-05-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: language_server-protocol
|
@@ -72,9 +72,11 @@ files:
|
|
72
72
|
- exe/ruby-lsp
|
73
73
|
- lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb
|
74
74
|
- lib/ruby-lsp.rb
|
75
|
+
- lib/ruby_lsp/check_docs.rb
|
75
76
|
- lib/ruby_lsp/document.rb
|
76
77
|
- lib/ruby_lsp/event_emitter.rb
|
77
78
|
- lib/ruby_lsp/executor.rb
|
79
|
+
- lib/ruby_lsp/extension.rb
|
78
80
|
- lib/ruby_lsp/internal.rb
|
79
81
|
- lib/ruby_lsp/listener.rb
|
80
82
|
- lib/ruby_lsp/requests.rb
|
@@ -131,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
133
|
- !ruby/object:Gem::Version
|
132
134
|
version: '0'
|
133
135
|
requirements: []
|
134
|
-
rubygems_version: 3.4.
|
136
|
+
rubygems_version: 3.4.12
|
135
137
|
signing_key:
|
136
138
|
specification_version: 4
|
137
139
|
summary: An opinionated language server for Ruby
|