ruby-lsp 0.9.3 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +27 -15
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +68 -15
- data/lib/ruby_indexer/lib/ruby_indexer/indexable_path.rb +29 -0
- data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +153 -0
- data/lib/ruby_indexer/ruby_indexer.rb +2 -0
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +1 -1
- data/lib/ruby_indexer/test/configuration_test.rb +30 -24
- data/lib/ruby_indexer/test/index_test.rb +42 -9
- data/lib/ruby_indexer/test/prefix_tree_test.rb +150 -0
- data/lib/ruby_indexer/test/test_case.rb +1 -1
- data/lib/ruby_lsp/check_docs.rb +2 -1
- data/lib/ruby_lsp/event_emitter.rb +2 -0
- data/lib/ruby_lsp/executor.rb +33 -16
- data/lib/ruby_lsp/extension.rb +13 -1
- data/lib/ruby_lsp/listener.rb +43 -4
- data/lib/ruby_lsp/requests/code_lens.rb +15 -13
- data/lib/ruby_lsp/requests/completion.rb +168 -0
- data/lib/ruby_lsp/requests/definition.rb +43 -32
- data/lib/ruby_lsp/requests/document_highlight.rb +3 -3
- data/lib/ruby_lsp/requests/document_link.rb +3 -3
- data/lib/ruby_lsp/requests/document_symbol.rb +10 -9
- data/lib/ruby_lsp/requests/hover.rb +16 -33
- data/lib/ruby_lsp/requests/inlay_hints.rb +3 -3
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +4 -4
- data/lib/ruby_lsp/requests/support/common.rb +33 -0
- data/lib/ruby_lsp/requests.rb +2 -3
- metadata +9 -7
- data/lib/ruby_lsp/requests/path_completion.rb +0 -65
- data/lib/ruby_lsp/requests/support/prefix_tree.rb +0 -80
@@ -17,14 +17,14 @@ module RubyLsp
|
|
17
17
|
# require "some_gem/file" # <- Request go to definition on this string will take you to the file
|
18
18
|
# Product.new # <- Request go to definition on this class name will take you to its declaration.
|
19
19
|
# ```
|
20
|
-
class Definition <
|
20
|
+
class Definition < ExtensibleListener
|
21
21
|
extend T::Sig
|
22
22
|
extend T::Generic
|
23
23
|
|
24
24
|
ResponseType = type_member { { fixed: T.nilable(T.any(T::Array[Interface::Location], Interface::Location)) } }
|
25
25
|
|
26
26
|
sig { override.returns(ResponseType) }
|
27
|
-
attr_reader :
|
27
|
+
attr_reader :_response
|
28
28
|
|
29
29
|
sig do
|
30
30
|
params(
|
@@ -36,15 +36,37 @@ module RubyLsp
|
|
36
36
|
).void
|
37
37
|
end
|
38
38
|
def initialize(uri, nesting, index, emitter, message_queue)
|
39
|
-
super(emitter, message_queue)
|
40
|
-
|
41
39
|
@uri = uri
|
42
40
|
@nesting = nesting
|
43
41
|
@index = index
|
44
|
-
@
|
42
|
+
@_response = T.let(nil, ResponseType)
|
43
|
+
|
44
|
+
super(emitter, message_queue)
|
45
|
+
|
45
46
|
emitter.register(self, :on_command, :on_const, :on_const_path_ref)
|
46
47
|
end
|
47
48
|
|
49
|
+
sig { override.params(ext: Extension).returns(T.nilable(RubyLsp::Listener[ResponseType])) }
|
50
|
+
def initialize_external_listener(ext)
|
51
|
+
ext.create_definition_listener(@uri, @nesting, @index, @emitter, @message_queue)
|
52
|
+
end
|
53
|
+
|
54
|
+
sig { override.params(other: Listener[ResponseType]).returns(T.self_type) }
|
55
|
+
def merge_response!(other)
|
56
|
+
other_response = other._response
|
57
|
+
|
58
|
+
case @_response
|
59
|
+
when Interface::Location
|
60
|
+
@_response = [@_response, *other_response]
|
61
|
+
when Array
|
62
|
+
@_response.concat(Array(other_response))
|
63
|
+
when nil
|
64
|
+
@_response = other_response
|
65
|
+
end
|
66
|
+
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
48
70
|
sig { params(node: SyntaxTree::ConstPathRef).void }
|
49
71
|
def on_const_path_ref(node)
|
50
72
|
name = full_constant_name(node)
|
@@ -67,14 +89,16 @@ module RubyLsp
|
|
67
89
|
string = argument.parts.first
|
68
90
|
return unless string.is_a?(SyntaxTree::TStringContent)
|
69
91
|
|
70
|
-
required_file = "#{string.value}.rb"
|
71
|
-
|
72
92
|
case message
|
73
93
|
when "require"
|
74
|
-
|
94
|
+
entry = @index.search_require_paths(string.value).find do |indexable_path|
|
95
|
+
indexable_path.require_path == string.value
|
96
|
+
end
|
97
|
+
|
98
|
+
if entry
|
99
|
+
candidate = entry.full_path
|
75
100
|
|
76
|
-
|
77
|
-
@response = Interface::Location.new(
|
101
|
+
@_response = Interface::Location.new(
|
78
102
|
uri: URI::Generic.from_path(path: candidate).to_s,
|
79
103
|
range: Interface::Range.new(
|
80
104
|
start: Interface::Position.new(line: 0, character: 0),
|
@@ -83,19 +107,18 @@ module RubyLsp
|
|
83
107
|
)
|
84
108
|
end
|
85
109
|
when "require_relative"
|
110
|
+
required_file = "#{string.value}.rb"
|
86
111
|
path = @uri.to_standardized_path
|
87
112
|
current_folder = path ? Pathname.new(CGI.unescape(path)).dirname : Dir.pwd
|
88
113
|
candidate = File.expand_path(File.join(current_folder, required_file))
|
89
114
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
)
|
98
|
-
end
|
115
|
+
@_response = Interface::Location.new(
|
116
|
+
uri: URI::Generic.from_path(path: candidate).to_s,
|
117
|
+
range: Interface::Range.new(
|
118
|
+
start: Interface::Position.new(line: 0, character: 0),
|
119
|
+
end: Interface::Position.new(line: 0, character: 0),
|
120
|
+
),
|
121
|
+
)
|
99
122
|
end
|
100
123
|
end
|
101
124
|
|
@@ -112,7 +135,7 @@ module RubyLsp
|
|
112
135
|
nil
|
113
136
|
end
|
114
137
|
|
115
|
-
@
|
138
|
+
@_response = entries.filter_map do |entry|
|
116
139
|
location = entry.location
|
117
140
|
# If the project has Sorbet, then we only want to handle go to definition for constants defined in gems, as an
|
118
141
|
# additional behavior on top of jumping to RBIs. Sorbet can already handle go to definition for all constants
|
@@ -133,18 +156,6 @@ module RubyLsp
|
|
133
156
|
)
|
134
157
|
end
|
135
158
|
end
|
136
|
-
|
137
|
-
sig { params(file: String).returns(T.nilable(String)) }
|
138
|
-
def find_file_in_load_path(file)
|
139
|
-
return unless file.include?("/")
|
140
|
-
|
141
|
-
$LOAD_PATH.each do |p|
|
142
|
-
found = Dir.glob("**/#{file}", base: p).first
|
143
|
-
return "#{p}/#{found}" if found
|
144
|
-
end
|
145
|
-
|
146
|
-
nil
|
147
|
-
end
|
148
159
|
end
|
149
160
|
end
|
150
161
|
end
|
@@ -28,7 +28,7 @@ module RubyLsp
|
|
28
28
|
ResponseType = type_member { { fixed: T::Array[Interface::DocumentHighlight] } }
|
29
29
|
|
30
30
|
sig { override.returns(ResponseType) }
|
31
|
-
attr_reader :
|
31
|
+
attr_reader :_response
|
32
32
|
|
33
33
|
sig do
|
34
34
|
params(
|
@@ -41,7 +41,7 @@ module RubyLsp
|
|
41
41
|
def initialize(target, parent, emitter, message_queue)
|
42
42
|
super(emitter, message_queue)
|
43
43
|
|
44
|
-
@
|
44
|
+
@_response = T.let([], T::Array[Interface::DocumentHighlight])
|
45
45
|
|
46
46
|
return unless target && parent
|
47
47
|
|
@@ -83,7 +83,7 @@ module RubyLsp
|
|
83
83
|
sig { params(match: Support::HighlightTarget::HighlightMatch).void }
|
84
84
|
def add_highlight(match)
|
85
85
|
range = range_from_syntax_tree_node(match.node)
|
86
|
-
@
|
86
|
+
@_response << Interface::DocumentHighlight.new(range: range, kind: match.type)
|
87
87
|
end
|
88
88
|
end
|
89
89
|
end
|
@@ -73,7 +73,7 @@ module RubyLsp
|
|
73
73
|
end
|
74
74
|
|
75
75
|
sig { override.returns(ResponseType) }
|
76
|
-
attr_reader :
|
76
|
+
attr_reader :_response
|
77
77
|
|
78
78
|
sig { params(uri: URI::Generic, emitter: EventEmitter, message_queue: Thread::Queue).void }
|
79
79
|
def initialize(uri, emitter, message_queue)
|
@@ -84,7 +84,7 @@ module RubyLsp
|
|
84
84
|
path = uri.to_standardized_path
|
85
85
|
version_match = path ? /(?<=%40)[\d.]+(?=\.rbi$)/.match(path) : nil
|
86
86
|
@gem_version = T.let(version_match && version_match[0], T.nilable(String))
|
87
|
-
@
|
87
|
+
@_response = T.let([], T::Array[Interface::DocumentLink])
|
88
88
|
|
89
89
|
emitter.register(self, :on_comment)
|
90
90
|
end
|
@@ -99,7 +99,7 @@ module RubyLsp
|
|
99
99
|
file_path = self.class.gem_paths.dig(uri.gem_name, gem_version, CGI.unescape(uri.path))
|
100
100
|
return if file_path.nil?
|
101
101
|
|
102
|
-
@
|
102
|
+
@_response << Interface::DocumentLink.new(
|
103
103
|
range: range_from_syntax_tree_node(node),
|
104
104
|
target: "file://#{file_path}##{uri.line_number}",
|
105
105
|
tooltip: "Jump to #{file_path}##{uri.line_number}",
|
@@ -26,7 +26,7 @@ module RubyLsp
|
|
26
26
|
# end
|
27
27
|
# end
|
28
28
|
# ```
|
29
|
-
class DocumentSymbol <
|
29
|
+
class DocumentSymbol < ExtensibleListener
|
30
30
|
extend T::Sig
|
31
31
|
extend T::Generic
|
32
32
|
|
@@ -47,22 +47,18 @@ module RubyLsp
|
|
47
47
|
end
|
48
48
|
|
49
49
|
sig { override.returns(T::Array[Interface::DocumentSymbol]) }
|
50
|
-
attr_reader :
|
50
|
+
attr_reader :_response
|
51
51
|
|
52
52
|
sig { params(emitter: EventEmitter, message_queue: Thread::Queue).void }
|
53
53
|
def initialize(emitter, message_queue)
|
54
|
-
super
|
55
|
-
|
56
54
|
@root = T.let(SymbolHierarchyRoot.new, SymbolHierarchyRoot)
|
57
|
-
@
|
55
|
+
@_response = T.let(@root.children, T::Array[Interface::DocumentSymbol])
|
58
56
|
@stack = T.let(
|
59
57
|
[@root],
|
60
58
|
T::Array[T.any(SymbolHierarchyRoot, Interface::DocumentSymbol)],
|
61
59
|
)
|
62
60
|
|
63
|
-
|
64
|
-
Extension.extensions.filter_map { |ext| ext.create_document_symbol_listener(emitter, message_queue) },
|
65
|
-
)
|
61
|
+
super
|
66
62
|
|
67
63
|
emitter.register(
|
68
64
|
self,
|
@@ -79,10 +75,15 @@ module RubyLsp
|
|
79
75
|
)
|
80
76
|
end
|
81
77
|
|
78
|
+
sig { override.params(extension: RubyLsp::Extension).returns(T.nilable(Listener[ResponseType])) }
|
79
|
+
def initialize_external_listener(extension)
|
80
|
+
extension.create_document_symbol_listener(@emitter, @message_queue)
|
81
|
+
end
|
82
|
+
|
82
83
|
# Merges responses from other listeners
|
83
84
|
sig { override.params(other: Listener[ResponseType]).returns(T.self_type) }
|
84
85
|
def merge_response!(other)
|
85
|
-
@
|
86
|
+
@_response.concat(other.response)
|
86
87
|
self
|
87
88
|
end
|
88
89
|
|
@@ -13,7 +13,7 @@ module RubyLsp
|
|
13
13
|
# ```ruby
|
14
14
|
# String # -> Hovering over the class reference will show all declaration locations and the documentation
|
15
15
|
# ```
|
16
|
-
class Hover <
|
16
|
+
class Hover < ExtensibleListener
|
17
17
|
extend T::Sig
|
18
18
|
extend T::Generic
|
19
19
|
|
@@ -30,7 +30,7 @@ module RubyLsp
|
|
30
30
|
)
|
31
31
|
|
32
32
|
sig { override.returns(ResponseType) }
|
33
|
-
attr_reader :
|
33
|
+
attr_reader :_response
|
34
34
|
|
35
35
|
sig do
|
36
36
|
params(
|
@@ -41,27 +41,29 @@ module RubyLsp
|
|
41
41
|
).void
|
42
42
|
end
|
43
43
|
def initialize(index, nesting, emitter, message_queue)
|
44
|
-
super(emitter, message_queue)
|
45
|
-
|
46
44
|
@nesting = nesting
|
47
45
|
@index = index
|
48
|
-
@
|
49
|
-
|
50
|
-
)
|
51
|
-
@response = T.let(nil, ResponseType)
|
46
|
+
@_response = T.let(nil, ResponseType)
|
47
|
+
|
48
|
+
super(emitter, message_queue)
|
52
49
|
emitter.register(self, :on_const_path_ref, :on_const)
|
53
50
|
end
|
54
51
|
|
52
|
+
sig { override.params(extension: RubyLsp::Extension).returns(T.nilable(Listener[ResponseType])) }
|
53
|
+
def initialize_external_listener(extension)
|
54
|
+
extension.create_hover_listener(@emitter, @message_queue)
|
55
|
+
end
|
56
|
+
|
55
57
|
# Merges responses from other hover listeners
|
56
58
|
sig { override.params(other: Listener[ResponseType]).returns(T.self_type) }
|
57
59
|
def merge_response!(other)
|
58
60
|
other_response = other.response
|
59
61
|
return self unless other_response
|
60
62
|
|
61
|
-
if @
|
62
|
-
@
|
63
|
+
if @_response.nil?
|
64
|
+
@_response = other.response
|
63
65
|
else
|
64
|
-
@
|
66
|
+
@_response.contents.value << "\n\n" << other_response.contents.value
|
65
67
|
end
|
66
68
|
|
67
69
|
self
|
@@ -89,29 +91,10 @@ module RubyLsp
|
|
89
91
|
entries = @index.resolve(name, @nesting)
|
90
92
|
return unless entries
|
91
93
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
entries.each do |entry|
|
96
|
-
loc = entry.location
|
97
|
-
|
98
|
-
# We always handle locations as zero based. However, for file links in Markdown we need them to be one based,
|
99
|
-
# which is why instead of the usual subtraction of 1 to line numbers, we are actually adding 1 to columns. The
|
100
|
-
# format for VS Code file URIs is `file:///path/to/file.rb#Lstart_line,start_column-end_line,end_column`
|
101
|
-
uri = URI::Generic.from_path(
|
102
|
-
path: entry.file_path,
|
103
|
-
fragment: "L#{loc.start_line},#{loc.start_column + 1}-#{loc.end_line},#{loc.end_column + 1}",
|
104
|
-
)
|
105
|
-
|
106
|
-
definitions << "[#{entry.file_name}](#{uri})"
|
107
|
-
content << "\n\n#{entry.comments.join("\n")}" unless entry.comments.empty?
|
108
|
-
end
|
109
|
-
|
110
|
-
contents = Interface::MarkupContent.new(
|
111
|
-
kind: "markdown",
|
112
|
-
value: "#{title}\n\n**Definitions**: #{definitions.join(" | ")}\n\n#{content}",
|
94
|
+
@_response = Interface::Hover.new(
|
95
|
+
range: range_from_syntax_tree_node(node),
|
96
|
+
contents: markdown_from_index_entries(name, entries),
|
113
97
|
)
|
114
|
-
@response = Interface::Hover.new(range: range_from_syntax_tree_node(node), contents: contents)
|
115
98
|
end
|
116
99
|
end
|
117
100
|
end
|
@@ -27,13 +27,13 @@ module RubyLsp
|
|
27
27
|
RESCUE_STRING_LENGTH = T.let("rescue".length, Integer)
|
28
28
|
|
29
29
|
sig { override.returns(ResponseType) }
|
30
|
-
attr_reader :
|
30
|
+
attr_reader :_response
|
31
31
|
|
32
32
|
sig { params(range: T::Range[Integer], emitter: EventEmitter, message_queue: Thread::Queue).void }
|
33
33
|
def initialize(range, emitter, message_queue)
|
34
34
|
super(emitter, message_queue)
|
35
35
|
|
36
|
-
@
|
36
|
+
@_response = T.let([], ResponseType)
|
37
37
|
@range = range
|
38
38
|
|
39
39
|
emitter.register(self, :on_rescue)
|
@@ -47,7 +47,7 @@ module RubyLsp
|
|
47
47
|
loc = node.location
|
48
48
|
return unless visible?(node, @range)
|
49
49
|
|
50
|
-
@
|
50
|
+
@_response << Interface::InlayHint.new(
|
51
51
|
position: { line: loc.start_line - 1, character: loc.start_column + RESCUE_STRING_LENGTH },
|
52
52
|
label: "StandardError",
|
53
53
|
padding_left: true,
|
@@ -105,7 +105,7 @@ module RubyLsp
|
|
105
105
|
end
|
106
106
|
|
107
107
|
sig { override.returns(ResponseType) }
|
108
|
-
attr_reader :
|
108
|
+
attr_reader :_response
|
109
109
|
|
110
110
|
sig do
|
111
111
|
params(
|
@@ -117,7 +117,7 @@ module RubyLsp
|
|
117
117
|
def initialize(emitter, message_queue, range: nil)
|
118
118
|
super(emitter, message_queue)
|
119
119
|
|
120
|
-
@
|
120
|
+
@_response = T.let([], ResponseType)
|
121
121
|
@range = range
|
122
122
|
@special_methods = T.let(nil, T.nilable(T::Array[String]))
|
123
123
|
|
@@ -174,7 +174,7 @@ module RubyLsp
|
|
174
174
|
# When finding a module or class definition, we will have already pushed a token related to this constant. We
|
175
175
|
# need to look at the previous two tokens and if they match this locatione exactly, avoid pushing another token
|
176
176
|
# on top of the previous one
|
177
|
-
return if @
|
177
|
+
return if @_response.last(2).any? { |token| token.location == node.location }
|
178
178
|
|
179
179
|
add_token(node.location, :namespace)
|
180
180
|
end
|
@@ -327,7 +327,7 @@ module RubyLsp
|
|
327
327
|
def add_token(location, type, modifiers = [])
|
328
328
|
length = location.end_char - location.start_char
|
329
329
|
modifiers_indices = modifiers.filter_map { |modifier| TOKEN_MODIFIERS[modifier] }
|
330
|
-
@
|
330
|
+
@_response.push(
|
331
331
|
SemanticToken.new(
|
332
332
|
location: location,
|
333
333
|
length: length,
|
@@ -74,6 +74,39 @@ module RubyLsp
|
|
74
74
|
data: data,
|
75
75
|
)
|
76
76
|
end
|
77
|
+
|
78
|
+
sig { params(title: String, entries: T::Array[RubyIndexer::Index::Entry]).returns(Interface::MarkupContent) }
|
79
|
+
def markdown_from_index_entries(title, entries)
|
80
|
+
markdown_title = "```ruby\n#{title}\n```"
|
81
|
+
definitions = []
|
82
|
+
content = +""
|
83
|
+
entries.each do |entry|
|
84
|
+
loc = entry.location
|
85
|
+
|
86
|
+
# We always handle locations as zero based. However, for file links in Markdown we need them to be one
|
87
|
+
# based, which is why instead of the usual subtraction of 1 to line numbers, we are actually adding 1 to
|
88
|
+
# columns. The format for VS Code file URIs is
|
89
|
+
# `file:///path/to/file.rb#Lstart_line,start_column-end_line,end_column`
|
90
|
+
uri = URI::Generic.from_path(
|
91
|
+
path: entry.file_path,
|
92
|
+
fragment: "L#{loc.start_line},#{loc.start_column + 1}-#{loc.end_line},#{loc.end_column + 1}",
|
93
|
+
)
|
94
|
+
|
95
|
+
definitions << "[#{entry.file_name}](#{uri})"
|
96
|
+
content << "\n\n#{entry.comments.join("\n")}" unless entry.comments.empty?
|
97
|
+
end
|
98
|
+
|
99
|
+
Interface::MarkupContent.new(
|
100
|
+
kind: "markdown",
|
101
|
+
value: <<~MARKDOWN.chomp,
|
102
|
+
#{markdown_title}
|
103
|
+
|
104
|
+
**Definitions**: #{definitions.join(" | ")}
|
105
|
+
|
106
|
+
#{content}
|
107
|
+
MARKDOWN
|
108
|
+
)
|
109
|
+
end
|
77
110
|
end
|
78
111
|
end
|
79
112
|
end
|
data/lib/ruby_lsp/requests.rb
CHANGED
@@ -17,7 +17,7 @@ module RubyLsp
|
|
17
17
|
# - [CodeActionResolve](rdoc-ref:RubyLsp::Requests::CodeActionResolve)
|
18
18
|
# - [DocumentHighlight](rdoc-ref:RubyLsp::Requests::DocumentHighlight)
|
19
19
|
# - [InlayHint](rdoc-ref:RubyLsp::Requests::InlayHints)
|
20
|
-
# - [
|
20
|
+
# - [Completion](rdoc-ref:RubyLsp::Requests::Completion)
|
21
21
|
# - [CodeLens](rdoc-ref:RubyLsp::Requests::CodeLens)
|
22
22
|
# - [Definition](rdoc-ref:RubyLsp::Requests::Definition)
|
23
23
|
# - [ShowSyntaxTree](rdoc-ref:RubyLsp::Requests::ShowSyntaxTree)
|
@@ -38,7 +38,7 @@ module RubyLsp
|
|
38
38
|
autoload :CodeActionResolve, "ruby_lsp/requests/code_action_resolve"
|
39
39
|
autoload :DocumentHighlight, "ruby_lsp/requests/document_highlight"
|
40
40
|
autoload :InlayHints, "ruby_lsp/requests/inlay_hints"
|
41
|
-
autoload :
|
41
|
+
autoload :Completion, "ruby_lsp/requests/completion"
|
42
42
|
autoload :CodeLens, "ruby_lsp/requests/code_lens"
|
43
43
|
autoload :Definition, "ruby_lsp/requests/definition"
|
44
44
|
autoload :ShowSyntaxTree, "ruby_lsp/requests/show_syntax_tree"
|
@@ -53,7 +53,6 @@ module RubyLsp
|
|
53
53
|
autoload :Sorbet, "ruby_lsp/requests/support/sorbet"
|
54
54
|
autoload :HighlightTarget, "ruby_lsp/requests/support/highlight_target"
|
55
55
|
autoload :RailsDocumentClient, "ruby_lsp/requests/support/rails_document_client"
|
56
|
-
autoload :PrefixTree, "ruby_lsp/requests/support/prefix_tree"
|
57
56
|
autoload :Common, "ruby_lsp/requests/support/common"
|
58
57
|
autoload :FormatterRunner, "ruby_lsp/requests/support/formatter_runner"
|
59
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.10.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-09-
|
11
|
+
date: 2023-09-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: language_server-protocol
|
@@ -67,7 +67,7 @@ dependencies:
|
|
67
67
|
version: '0.9'
|
68
68
|
- - "<"
|
69
69
|
- !ruby/object:Gem::Version
|
70
|
-
version: '0.
|
70
|
+
version: '0.11'
|
71
71
|
type: :runtime
|
72
72
|
prerelease: false
|
73
73
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -77,7 +77,7 @@ dependencies:
|
|
77
77
|
version: '0.9'
|
78
78
|
- - "<"
|
79
79
|
- !ruby/object:Gem::Version
|
80
|
-
version: '0.
|
80
|
+
version: '0.11'
|
81
81
|
description: An opinionated language server for Ruby
|
82
82
|
email:
|
83
83
|
- ruby@shopify.com
|
@@ -97,12 +97,15 @@ files:
|
|
97
97
|
- lib/ruby-lsp.rb
|
98
98
|
- lib/ruby_indexer/lib/ruby_indexer/configuration.rb
|
99
99
|
- lib/ruby_indexer/lib/ruby_indexer/index.rb
|
100
|
+
- lib/ruby_indexer/lib/ruby_indexer/indexable_path.rb
|
101
|
+
- lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb
|
100
102
|
- lib/ruby_indexer/lib/ruby_indexer/visitor.rb
|
101
103
|
- lib/ruby_indexer/ruby_indexer.rb
|
102
104
|
- lib/ruby_indexer/test/classes_and_modules_test.rb
|
103
105
|
- lib/ruby_indexer/test/configuration_test.rb
|
104
106
|
- lib/ruby_indexer/test/constant_test.rb
|
105
107
|
- lib/ruby_indexer/test/index_test.rb
|
108
|
+
- lib/ruby_indexer/test/prefix_tree_test.rb
|
106
109
|
- lib/ruby_indexer/test/test_case.rb
|
107
110
|
- lib/ruby_lsp/check_docs.rb
|
108
111
|
- lib/ruby_lsp/document.rb
|
@@ -116,6 +119,7 @@ files:
|
|
116
119
|
- lib/ruby_lsp/requests/code_action_resolve.rb
|
117
120
|
- lib/ruby_lsp/requests/code_actions.rb
|
118
121
|
- lib/ruby_lsp/requests/code_lens.rb
|
122
|
+
- lib/ruby_lsp/requests/completion.rb
|
119
123
|
- lib/ruby_lsp/requests/definition.rb
|
120
124
|
- lib/ruby_lsp/requests/diagnostics.rb
|
121
125
|
- lib/ruby_lsp/requests/document_highlight.rb
|
@@ -126,7 +130,6 @@ files:
|
|
126
130
|
- lib/ruby_lsp/requests/hover.rb
|
127
131
|
- lib/ruby_lsp/requests/inlay_hints.rb
|
128
132
|
- lib/ruby_lsp/requests/on_type_formatting.rb
|
129
|
-
- lib/ruby_lsp/requests/path_completion.rb
|
130
133
|
- lib/ruby_lsp/requests/selection_ranges.rb
|
131
134
|
- lib/ruby_lsp/requests/semantic_highlighting.rb
|
132
135
|
- lib/ruby_lsp/requests/show_syntax_tree.rb
|
@@ -135,7 +138,6 @@ files:
|
|
135
138
|
- lib/ruby_lsp/requests/support/dependency_detector.rb
|
136
139
|
- lib/ruby_lsp/requests/support/formatter_runner.rb
|
137
140
|
- lib/ruby_lsp/requests/support/highlight_target.rb
|
138
|
-
- lib/ruby_lsp/requests/support/prefix_tree.rb
|
139
141
|
- lib/ruby_lsp/requests/support/rubocop_diagnostic.rb
|
140
142
|
- lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb
|
141
143
|
- lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb
|
@@ -170,7 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
170
172
|
- !ruby/object:Gem::Version
|
171
173
|
version: '0'
|
172
174
|
requirements: []
|
173
|
-
rubygems_version: 3.4.
|
175
|
+
rubygems_version: 3.4.19
|
174
176
|
signing_key:
|
175
177
|
specification_version: 4
|
176
178
|
summary: An opinionated language server for Ruby
|
@@ -1,65 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module RubyLsp
|
5
|
-
module Requests
|
6
|
-
# ![Path completion demo](../../path_completion.gif)
|
7
|
-
#
|
8
|
-
# The [completion](https://microsoft.github.io/language-server-protocol/specification#textDocument_completion)
|
9
|
-
# request looks up Ruby files in the $LOAD_PATH to suggest path completion inside `require` statements.
|
10
|
-
#
|
11
|
-
# # Example
|
12
|
-
#
|
13
|
-
# ```ruby
|
14
|
-
# require "ruby_lsp/requests" # --> completion: suggests `base_request`, `code_actions`, ...
|
15
|
-
# ```
|
16
|
-
class PathCompletion < Listener
|
17
|
-
extend T::Sig
|
18
|
-
extend T::Generic
|
19
|
-
|
20
|
-
ResponseType = type_member { { fixed: T::Array[Interface::CompletionItem] } }
|
21
|
-
|
22
|
-
sig { override.returns(ResponseType) }
|
23
|
-
attr_reader :response
|
24
|
-
|
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)
|
30
|
-
|
31
|
-
emitter.register(self, :on_tstring_content)
|
32
|
-
end
|
33
|
-
|
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)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
sig { returns(T::Array[String]) }
|
44
|
-
def collect_load_path_files
|
45
|
-
$LOAD_PATH.flat_map do |p|
|
46
|
-
Dir.glob("**/*.rb", base: p)
|
47
|
-
end.map! do |result|
|
48
|
-
result.delete_suffix!(".rb")
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
sig { params(label: String, node: SyntaxTree::TStringContent).returns(Interface::CompletionItem) }
|
53
|
-
def build_completion(label, node)
|
54
|
-
Interface::CompletionItem.new(
|
55
|
-
label: label,
|
56
|
-
text_edit: Interface::TextEdit.new(
|
57
|
-
range: range_from_syntax_tree_node(node),
|
58
|
-
new_text: label,
|
59
|
-
),
|
60
|
-
kind: Constant::CompletionItemKind::REFERENCE,
|
61
|
-
)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
@@ -1,80 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module RubyLsp
|
5
|
-
module Requests
|
6
|
-
module Support
|
7
|
-
class PrefixTree
|
8
|
-
extend T::Sig
|
9
|
-
|
10
|
-
sig { params(items: T::Array[String]).void }
|
11
|
-
def initialize(items)
|
12
|
-
@root = T.let(Node.new(""), Node)
|
13
|
-
|
14
|
-
items.each do |item|
|
15
|
-
insert(item)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
sig { params(prefix: String).returns(T::Array[String]) }
|
20
|
-
def search(prefix)
|
21
|
-
node = T.let(@root, Node)
|
22
|
-
|
23
|
-
prefix.each_char do |char|
|
24
|
-
snode = node.children[char]
|
25
|
-
return [] unless snode
|
26
|
-
|
27
|
-
node = snode
|
28
|
-
end
|
29
|
-
|
30
|
-
node.collect
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
sig { params(item: String).void }
|
36
|
-
def insert(item)
|
37
|
-
node = T.let(@root, Node)
|
38
|
-
|
39
|
-
item.each_char do |char|
|
40
|
-
node = node.children[char] ||= Node.new(node.value + char)
|
41
|
-
end
|
42
|
-
|
43
|
-
node.leaf = true
|
44
|
-
end
|
45
|
-
|
46
|
-
class Node
|
47
|
-
extend T::Sig
|
48
|
-
|
49
|
-
sig { returns(T::Hash[String, Node]) }
|
50
|
-
attr_reader :children
|
51
|
-
|
52
|
-
sig { returns(String) }
|
53
|
-
attr_reader :value
|
54
|
-
|
55
|
-
sig { returns(T::Boolean) }
|
56
|
-
attr_accessor :leaf
|
57
|
-
|
58
|
-
sig { params(value: String).void }
|
59
|
-
def initialize(value)
|
60
|
-
@children = T.let({}, T::Hash[String, Node])
|
61
|
-
@value = T.let(value, String)
|
62
|
-
@leaf = T.let(false, T::Boolean)
|
63
|
-
end
|
64
|
-
|
65
|
-
sig { returns(T::Array[String]) }
|
66
|
-
def collect
|
67
|
-
result = T.let([], T::Array[String])
|
68
|
-
result << value if leaf
|
69
|
-
|
70
|
-
children.each_value do |node|
|
71
|
-
result.concat(node.collect)
|
72
|
-
end
|
73
|
-
|
74
|
-
result
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|