ruby-lsp 0.14.6 → 0.16.5
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 +1 -1
- data/VERSION +1 -1
- data/exe/ruby-lsp +1 -16
- data/exe/ruby-lsp-check +13 -22
- data/exe/ruby-lsp-doctor +9 -0
- data/lib/ruby_indexer/lib/ruby_indexer/collector.rb +14 -1
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +11 -23
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +32 -8
- data/lib/ruby_indexer/lib/ruby_indexer/location.rb +26 -0
- data/lib/ruby_indexer/ruby_indexer.rb +1 -0
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +46 -0
- data/lib/ruby_indexer/test/configuration_test.rb +2 -11
- data/lib/ruby_lsp/addon.rb +18 -9
- data/lib/ruby_lsp/base_server.rb +149 -0
- data/lib/ruby_lsp/document.rb +6 -11
- data/lib/ruby_lsp/global_state.rb +180 -0
- data/lib/ruby_lsp/internal.rb +4 -1
- data/lib/ruby_lsp/listeners/code_lens.rb +22 -13
- data/lib/ruby_lsp/listeners/completion.rb +13 -14
- data/lib/ruby_lsp/listeners/definition.rb +14 -6
- data/lib/ruby_lsp/listeners/document_symbol.rb +91 -3
- data/lib/ruby_lsp/listeners/hover.rb +6 -5
- data/lib/ruby_lsp/listeners/signature_help.rb +7 -4
- data/lib/ruby_lsp/load_sorbet.rb +62 -0
- data/lib/ruby_lsp/requests/code_lens.rb +3 -2
- data/lib/ruby_lsp/requests/completion.rb +15 -4
- data/lib/ruby_lsp/requests/completion_resolve.rb +56 -0
- data/lib/ruby_lsp/requests/definition.rb +11 -4
- data/lib/ruby_lsp/requests/diagnostics.rb +8 -11
- data/lib/ruby_lsp/requests/document_symbol.rb +3 -3
- data/lib/ruby_lsp/requests/formatting.rb +7 -43
- data/lib/ruby_lsp/requests/hover.rb +4 -4
- data/lib/ruby_lsp/requests/request.rb +2 -0
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +7 -4
- data/lib/ruby_lsp/requests/signature_help.rb +4 -3
- data/lib/ruby_lsp/requests/support/common.rb +16 -5
- data/lib/ruby_lsp/requests/support/formatter.rb +26 -0
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +1 -1
- data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +47 -0
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +4 -0
- data/lib/ruby_lsp/requests/support/{syntax_tree_formatting_runner.rb → syntax_tree_formatter.rb} +13 -6
- data/lib/ruby_lsp/requests/workspace_symbol.rb +5 -4
- data/lib/ruby_lsp/requests.rb +3 -1
- data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +36 -13
- data/lib/ruby_lsp/server.rb +763 -142
- data/lib/ruby_lsp/setup_bundler.rb +13 -1
- data/lib/ruby_lsp/store.rb +3 -15
- data/lib/ruby_lsp/test_helper.rb +52 -0
- data/lib/ruby_lsp/utils.rb +68 -33
- metadata +16 -13
- data/lib/ruby_lsp/executor.rb +0 -614
- data/lib/ruby_lsp/requests/support/dependency_detector.rb +0 -93
- data/lib/ruby_lsp/requests/support/formatter_runner.rb +0 -18
- data/lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb +0 -34
- data/lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb +0 -35
@@ -86,13 +86,16 @@ module RubyLsp
|
|
86
86
|
params(
|
87
87
|
title: String,
|
88
88
|
entries: T.any(T::Array[RubyIndexer::Entry], RubyIndexer::Entry),
|
89
|
+
max_entries: T.nilable(Integer),
|
89
90
|
).returns(T::Hash[Symbol, String])
|
90
91
|
end
|
91
|
-
def categorized_markdown_from_index_entries(title, entries)
|
92
|
+
def categorized_markdown_from_index_entries(title, entries, max_entries = nil)
|
92
93
|
markdown_title = "```ruby\n#{title}\n```"
|
93
94
|
definitions = []
|
94
95
|
content = +""
|
95
|
-
Array(entries)
|
96
|
+
entries = Array(entries)
|
97
|
+
entries_to_format = max_entries ? entries.take(max_entries) : entries
|
98
|
+
entries_to_format.each do |entry|
|
96
99
|
loc = entry.location
|
97
100
|
|
98
101
|
# We always handle locations as zero based. However, for file links in Markdown we need them to be one
|
@@ -108,9 +111,16 @@ module RubyLsp
|
|
108
111
|
content << "\n\n#{entry.comments.join("\n")}" unless entry.comments.empty?
|
109
112
|
end
|
110
113
|
|
114
|
+
additional_entries_text = if max_entries && entries.length > max_entries
|
115
|
+
additional = entries.length - max_entries
|
116
|
+
" | #{additional} other#{additional > 1 ? "s" : ""}"
|
117
|
+
else
|
118
|
+
""
|
119
|
+
end
|
120
|
+
|
111
121
|
{
|
112
122
|
title: markdown_title,
|
113
|
-
links: "**Definitions**: #{definitions.join(" | ")}",
|
123
|
+
links: "**Definitions**: #{definitions.join(" | ")}#{additional_entries_text}",
|
114
124
|
documentation: content,
|
115
125
|
}
|
116
126
|
end
|
@@ -119,10 +129,11 @@ module RubyLsp
|
|
119
129
|
params(
|
120
130
|
title: String,
|
121
131
|
entries: T.any(T::Array[RubyIndexer::Entry], RubyIndexer::Entry),
|
132
|
+
max_entries: T.nilable(Integer),
|
122
133
|
).returns(String)
|
123
134
|
end
|
124
|
-
def markdown_from_index_entries(title, entries)
|
125
|
-
categorized_markdown = categorized_markdown_from_index_entries(title, entries)
|
135
|
+
def markdown_from_index_entries(title, entries, max_entries = nil)
|
136
|
+
categorized_markdown = categorized_markdown_from_index_entries(title, entries, max_entries)
|
126
137
|
|
127
138
|
<<~MARKDOWN.chomp
|
128
139
|
#{categorized_markdown[:title]}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Requests
|
6
|
+
module Support
|
7
|
+
module Formatter
|
8
|
+
extend T::Sig
|
9
|
+
extend T::Helpers
|
10
|
+
|
11
|
+
interface!
|
12
|
+
|
13
|
+
sig { abstract.params(uri: URI::Generic, document: Document).returns(T.nilable(String)) }
|
14
|
+
def run_formatting(uri, document); end
|
15
|
+
|
16
|
+
sig do
|
17
|
+
abstract.params(
|
18
|
+
uri: URI::Generic,
|
19
|
+
document: Document,
|
20
|
+
).returns(T.nilable(T::Array[Interface::Diagnostic]))
|
21
|
+
end
|
22
|
+
def run_diagnostic(uri, document); end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -163,7 +163,7 @@ module RubyLsp
|
|
163
163
|
|
164
164
|
sig { params(line: String).returns(Integer) }
|
165
165
|
def length_of_line(line)
|
166
|
-
if @document.encoding ==
|
166
|
+
if @document.encoding == Encoding::UTF_16LE
|
167
167
|
line_length = 0
|
168
168
|
line.codepoints.each do |codepoint|
|
169
169
|
line_length += 1
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
return unless defined?(RubyLsp::Requests::Support::RuboCopRunner)
|
5
|
+
|
6
|
+
module RubyLsp
|
7
|
+
module Requests
|
8
|
+
module Support
|
9
|
+
class RuboCopFormatter
|
10
|
+
extend T::Sig
|
11
|
+
include Formatter
|
12
|
+
|
13
|
+
sig { void }
|
14
|
+
def initialize
|
15
|
+
@diagnostic_runner = T.let(RuboCopRunner.new, RuboCopRunner)
|
16
|
+
# -a is for "--auto-correct" (or "--autocorrect" on newer versions of RuboCop)
|
17
|
+
@format_runner = T.let(RuboCopRunner.new("-a"), RuboCopRunner)
|
18
|
+
end
|
19
|
+
|
20
|
+
sig { override.params(uri: URI::Generic, document: Document).returns(T.nilable(String)) }
|
21
|
+
def run_formatting(uri, document)
|
22
|
+
filename = T.must(uri.to_standardized_path || uri.opaque)
|
23
|
+
|
24
|
+
# Invoke RuboCop with just this file in `paths`
|
25
|
+
@format_runner.run(filename, document.source)
|
26
|
+
@format_runner.formatted_source
|
27
|
+
end
|
28
|
+
|
29
|
+
sig do
|
30
|
+
override.params(
|
31
|
+
uri: URI::Generic,
|
32
|
+
document: Document,
|
33
|
+
).returns(T.nilable(T::Array[Interface::Diagnostic]))
|
34
|
+
end
|
35
|
+
def run_diagnostic(uri, document)
|
36
|
+
filename = T.must(uri.to_standardized_path || uri.opaque)
|
37
|
+
# Invoke RuboCop with just this file in `paths`
|
38
|
+
@diagnostic_runner.run(filename, document.source)
|
39
|
+
|
40
|
+
@diagnostic_runner.offenses.map do |offense|
|
41
|
+
Support::RuboCopDiagnostic.new(document, offense, uri).to_lsp_diagnostic
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -92,6 +92,10 @@ module RubyLsp
|
|
92
92
|
@options[:stdin] = contents
|
93
93
|
|
94
94
|
super([path])
|
95
|
+
|
96
|
+
# RuboCop rescues interrupts and then sets the `@aborting` variable to true. We don't want them to be rescued,
|
97
|
+
# so here we re-raise in case RuboCop received an interrupt.
|
98
|
+
raise Interrupt if aborting?
|
95
99
|
rescue RuboCop::Runner::InfiniteCorrectionLoop => error
|
96
100
|
raise Formatting::Error, error.message
|
97
101
|
rescue RuboCop::ValidationError => error
|
data/lib/ruby_lsp/requests/support/{syntax_tree_formatting_runner.rb → syntax_tree_formatter.rb}
RENAMED
@@ -8,16 +8,13 @@ rescue LoadError
|
|
8
8
|
return
|
9
9
|
end
|
10
10
|
|
11
|
-
require "singleton"
|
12
|
-
|
13
11
|
module RubyLsp
|
14
12
|
module Requests
|
15
13
|
module Support
|
16
14
|
# :nodoc:
|
17
|
-
class
|
15
|
+
class SyntaxTreeFormatter
|
18
16
|
extend T::Sig
|
19
|
-
include
|
20
|
-
include Support::FormatterRunner
|
17
|
+
include Support::Formatter
|
21
18
|
|
22
19
|
sig { void }
|
23
20
|
def initialize
|
@@ -33,12 +30,22 @@ module RubyLsp
|
|
33
30
|
end
|
34
31
|
|
35
32
|
sig { override.params(uri: URI::Generic, document: Document).returns(T.nilable(String)) }
|
36
|
-
def
|
33
|
+
def run_formatting(uri, document)
|
37
34
|
path = uri.to_standardized_path
|
38
35
|
return if path && @options.ignore_files.any? { |pattern| File.fnmatch?("*/#{pattern}", path) }
|
39
36
|
|
40
37
|
SyntaxTree.format(document.source, @options.print_width, options: @options.formatter_options)
|
41
38
|
end
|
39
|
+
|
40
|
+
sig do
|
41
|
+
override.params(
|
42
|
+
uri: URI::Generic,
|
43
|
+
document: Document,
|
44
|
+
).returns(T.nilable(T::Array[Interface::Diagnostic]))
|
45
|
+
end
|
46
|
+
def run_diagnostic(uri, document)
|
47
|
+
nil
|
48
|
+
end
|
42
49
|
end
|
43
50
|
end
|
44
51
|
end
|
@@ -22,11 +22,12 @@ module RubyLsp
|
|
22
22
|
extend T::Sig
|
23
23
|
include Support::Common
|
24
24
|
|
25
|
-
sig { params(query: T.nilable(String)
|
26
|
-
def initialize(
|
25
|
+
sig { params(global_state: GlobalState, query: T.nilable(String)).void }
|
26
|
+
def initialize(global_state, query)
|
27
27
|
super()
|
28
|
+
@global_state = global_state
|
28
29
|
@query = query
|
29
|
-
@index = index
|
30
|
+
@index = T.let(global_state.index, RubyIndexer::Index)
|
30
31
|
end
|
31
32
|
|
32
33
|
sig { override.returns(T::Array[Interface::WorkspaceSymbol]) }
|
@@ -35,7 +36,7 @@ module RubyLsp
|
|
35
36
|
# If the project is using Sorbet, we let Sorbet handle symbols defined inside the project itself and RBIs, but
|
36
37
|
# we still return entries defined in gems to allow developers to jump directly to the source
|
37
38
|
file_path = entry.file_path
|
38
|
-
next if
|
39
|
+
next if @global_state.typechecker && not_in_dependencies?(file_path)
|
39
40
|
|
40
41
|
# We should never show private symbols when searching the entire workspace
|
41
42
|
next if entry.visibility == :private
|
data/lib/ruby_lsp/requests.rb
CHANGED
@@ -18,6 +18,7 @@ module RubyLsp
|
|
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
|
+
# - [CompletionResolve](rdoc-ref:RubyLsp::Requests::CompletionResolve)
|
21
22
|
# - [CodeLens](rdoc-ref:RubyLsp::Requests::CodeLens)
|
22
23
|
# - [Definition](rdoc-ref:RubyLsp::Requests::Definition)
|
23
24
|
# - [ShowSyntaxTree](rdoc-ref:RubyLsp::Requests::ShowSyntaxTree)
|
@@ -40,6 +41,7 @@ module RubyLsp
|
|
40
41
|
autoload :DocumentHighlight, "ruby_lsp/requests/document_highlight"
|
41
42
|
autoload :InlayHints, "ruby_lsp/requests/inlay_hints"
|
42
43
|
autoload :Completion, "ruby_lsp/requests/completion"
|
44
|
+
autoload :CompletionResolve, "ruby_lsp/requests/completion_resolve"
|
43
45
|
autoload :CodeLens, "ruby_lsp/requests/code_lens"
|
44
46
|
autoload :Definition, "ruby_lsp/requests/definition"
|
45
47
|
autoload :ShowSyntaxTree, "ruby_lsp/requests/show_syntax_tree"
|
@@ -54,7 +56,7 @@ module RubyLsp
|
|
54
56
|
autoload :Sorbet, "ruby_lsp/requests/support/sorbet"
|
55
57
|
autoload :RailsDocumentClient, "ruby_lsp/requests/support/rails_document_client"
|
56
58
|
autoload :Common, "ruby_lsp/requests/support/common"
|
57
|
-
autoload :
|
59
|
+
autoload :Formatter, "ruby_lsp/requests/support/formatter"
|
58
60
|
end
|
59
61
|
end
|
60
62
|
end
|
@@ -55,19 +55,21 @@ module RubyLsp
|
|
55
55
|
|
56
56
|
ResponseType = type_member { { fixed: Interface::SemanticTokens } }
|
57
57
|
|
58
|
-
sig { void }
|
59
|
-
def initialize
|
60
|
-
super
|
58
|
+
sig { params(encoding: Encoding).void }
|
59
|
+
def initialize(encoding)
|
60
|
+
super()
|
61
|
+
@encoding = encoding
|
61
62
|
@stack = T.let([], T::Array[SemanticToken])
|
62
63
|
end
|
63
64
|
|
64
65
|
sig { params(location: Prism::Location, type: Symbol, modifiers: T::Array[Symbol]).void }
|
65
66
|
def add_token(location, type, modifiers = [])
|
66
|
-
length = location.
|
67
|
+
length = location.end_code_units_offset(@encoding) - location.start_code_units_offset(@encoding)
|
67
68
|
modifiers_indices = modifiers.filter_map { |modifier| TOKEN_MODIFIERS[modifier] }
|
68
69
|
@stack.push(
|
69
70
|
SemanticToken.new(
|
70
|
-
|
71
|
+
start_line: location.start_line,
|
72
|
+
start_code_unit_column: location.start_code_units_column(@encoding),
|
71
73
|
length: length,
|
72
74
|
type: T.must(TOKEN_TYPES[type]),
|
73
75
|
modifier: modifiers_indices,
|
@@ -75,6 +77,15 @@ module RubyLsp
|
|
75
77
|
)
|
76
78
|
end
|
77
79
|
|
80
|
+
sig { params(location: Prism::Location).returns(T::Boolean) }
|
81
|
+
def last_token_matches?(location)
|
82
|
+
token = @stack.last
|
83
|
+
return false unless token
|
84
|
+
|
85
|
+
token.start_line == location.start_line &&
|
86
|
+
token.start_code_unit_column == location.start_code_units_column(@encoding)
|
87
|
+
end
|
88
|
+
|
78
89
|
sig { returns(T.nilable(SemanticToken)) }
|
79
90
|
def last
|
80
91
|
@stack.last
|
@@ -88,8 +99,11 @@ module RubyLsp
|
|
88
99
|
class SemanticToken
|
89
100
|
extend T::Sig
|
90
101
|
|
91
|
-
sig { returns(
|
92
|
-
attr_reader :
|
102
|
+
sig { returns(Integer) }
|
103
|
+
attr_reader :start_line
|
104
|
+
|
105
|
+
sig { returns(Integer) }
|
106
|
+
attr_reader :start_code_unit_column
|
93
107
|
|
94
108
|
sig { returns(Integer) }
|
95
109
|
attr_reader :length
|
@@ -100,9 +114,18 @@ module RubyLsp
|
|
100
114
|
sig { returns(T::Array[Integer]) }
|
101
115
|
attr_reader :modifier
|
102
116
|
|
103
|
-
sig
|
104
|
-
|
105
|
-
|
117
|
+
sig do
|
118
|
+
params(
|
119
|
+
start_line: Integer,
|
120
|
+
start_code_unit_column: Integer,
|
121
|
+
length: Integer,
|
122
|
+
type: Integer,
|
123
|
+
modifier: T::Array[Integer],
|
124
|
+
).void
|
125
|
+
end
|
126
|
+
def initialize(start_line:, start_code_unit_column:, length:, type:, modifier:)
|
127
|
+
@start_line = start_line
|
128
|
+
@start_code_unit_column = start_code_unit_column
|
106
129
|
@length = length
|
107
130
|
@type = type
|
108
131
|
@modifier = modifier
|
@@ -146,7 +169,7 @@ module RubyLsp
|
|
146
169
|
# Enumerable#sort_by is not deterministic when the compared values are equal.
|
147
170
|
# When that happens, we need to use the index as a tie breaker to ensure
|
148
171
|
# that the order of the tokens is always the same.
|
149
|
-
[token.
|
172
|
+
[token.start_line, token.start_code_unit_column, index]
|
150
173
|
end
|
151
174
|
|
152
175
|
delta = sorted_tokens.flat_map do |token|
|
@@ -167,8 +190,8 @@ module RubyLsp
|
|
167
190
|
# https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_semanticTokens
|
168
191
|
sig { params(token: SemanticToken).returns(T::Array[Integer]) }
|
169
192
|
def compute_delta(token)
|
170
|
-
row = token.
|
171
|
-
column = token.
|
193
|
+
row = token.start_line - 1
|
194
|
+
column = token.start_code_unit_column
|
172
195
|
|
173
196
|
begin
|
174
197
|
delta_line = row - @current_row
|