ruby-lsp 0.0.1 → 0.0.4
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/.github/dependabot.yml +7 -16
- data/.github/pull_request_template.md +15 -0
- data/.github/workflows/ci.yml +31 -0
- data/.github/workflows/publish_docs.yml +32 -0
- data/.gitignore +9 -12
- data/.rubocop.yml +20 -2
- data/.vscode/settings.json +5 -0
- data/CHANGELOG.md +29 -0
- data/Gemfile +8 -4
- data/Gemfile.lock +76 -14
- data/README.md +69 -2
- data/Rakefile +5 -0
- data/VERSION +1 -1
- data/bin/tapioca +29 -0
- data/bin/test +7 -1
- data/dev.yml +7 -7
- data/exe/ruby-lsp +19 -2
- data/lib/internal.rb +7 -0
- data/lib/ruby-lsp.rb +4 -1
- data/lib/ruby_lsp/cli.rb +88 -0
- data/lib/ruby_lsp/document.rb +113 -0
- data/lib/ruby_lsp/handler.rb +236 -0
- data/lib/ruby_lsp/requests/base_request.rb +33 -0
- data/lib/ruby_lsp/requests/code_actions.rb +37 -0
- data/lib/ruby_lsp/requests/diagnostics.rb +37 -0
- data/lib/ruby_lsp/requests/document_highlight.rb +96 -0
- data/lib/ruby_lsp/requests/document_symbol.rb +216 -0
- data/lib/ruby_lsp/requests/folding_ranges.rb +213 -0
- data/lib/ruby_lsp/requests/formatting.rb +52 -0
- data/lib/ruby_lsp/requests/rubocop_request.rb +50 -0
- data/lib/ruby_lsp/requests/selection_ranges.rb +103 -0
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +112 -0
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +88 -0
- data/lib/ruby_lsp/requests/support/selection_range.rb +17 -0
- data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +60 -0
- data/lib/ruby_lsp/requests/support/syntax_error_diagnostic.rb +27 -0
- data/lib/ruby_lsp/requests.rb +24 -0
- data/lib/ruby_lsp/store.rb +59 -0
- data/rakelib/check_docs.rake +56 -0
- data/ruby-lsp.gemspec +5 -1
- data/{shipit.yml → shipit.production.yml} +0 -0
- data/sorbet/config +4 -0
- data/sorbet/rbi/.rubocop.yml +8 -0
- data/sorbet/rbi/gems/ansi@1.5.0.rbi +338 -0
- data/sorbet/rbi/gems/ast@2.4.2.rbi +522 -0
- data/sorbet/rbi/gems/builder@3.2.4.rbi +418 -0
- data/sorbet/rbi/gems/coderay@1.1.3.rbi +8 -0
- data/sorbet/rbi/gems/debug@1.5.0.rbi +1273 -0
- data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +867 -0
- data/sorbet/rbi/gems/io-console@0.5.11.rbi +8 -0
- data/sorbet/rbi/gems/irb@1.4.1.rbi +376 -0
- data/sorbet/rbi/gems/language_server-protocol@3.16.0.3.rbi +7325 -0
- data/sorbet/rbi/gems/method_source@1.0.0.rbi +8 -0
- data/sorbet/rbi/gems/minitest-reporters@1.5.0.rbi +612 -0
- data/sorbet/rbi/gems/minitest@5.15.0.rbi +994 -0
- data/sorbet/rbi/gems/parallel@1.22.1.rbi +163 -0
- data/sorbet/rbi/gems/parser@3.1.2.0.rbi +3968 -0
- data/sorbet/rbi/gems/prettier_print@0.1.0.rbi +734 -0
- data/sorbet/rbi/gems/pry@0.14.1.rbi +8 -0
- data/sorbet/rbi/gems/rainbow@3.1.1.rbi +227 -0
- data/sorbet/rbi/gems/rake@13.0.6.rbi +1853 -0
- data/sorbet/rbi/gems/rbi@0.0.14.rbi +2337 -0
- data/sorbet/rbi/gems/regexp_parser@2.5.0.rbi +1854 -0
- data/sorbet/rbi/gems/reline@0.3.1.rbi +1274 -0
- data/sorbet/rbi/gems/rexml@3.2.5.rbi +3852 -0
- data/sorbet/rbi/gems/rubocop-ast@1.18.0.rbi +4180 -0
- data/sorbet/rbi/gems/rubocop-minitest@0.20.0.rbi +1369 -0
- data/sorbet/rbi/gems/rubocop-rake@0.6.0.rbi +246 -0
- data/sorbet/rbi/gems/rubocop-shopify@2.6.0.rbi +8 -0
- data/sorbet/rbi/gems/rubocop-sorbet@0.6.8.rbi +652 -0
- data/sorbet/rbi/gems/rubocop@1.30.0.rbi +36729 -0
- data/sorbet/rbi/gems/ruby-progressbar@1.11.0.rbi +732 -0
- data/sorbet/rbi/gems/spoom@1.1.11.rbi +1600 -0
- data/sorbet/rbi/gems/syntax_tree@2.7.1.rbi +6777 -0
- data/sorbet/rbi/gems/tapioca@0.8.1.rbi +1972 -0
- data/sorbet/rbi/gems/thor@1.2.1.rbi +2921 -0
- data/sorbet/rbi/gems/unicode-display_width@2.1.0.rbi +27 -0
- data/sorbet/rbi/gems/unparser@0.6.5.rbi +2789 -0
- data/sorbet/rbi/gems/webrick@1.7.0.rbi +1779 -0
- data/sorbet/rbi/gems/yard-sorbet@0.6.1.rbi +289 -0
- data/sorbet/rbi/gems/yard@0.9.27.rbi +13048 -0
- data/sorbet/rbi/shims/fiddle.rbi +4 -0
- data/sorbet/rbi/shims/hash.rbi +6 -0
- data/sorbet/rbi/shims/rdoc.rbi +4 -0
- data/sorbet/tapioca/config.yml +13 -0
- data/sorbet/tapioca/require.rb +7 -0
- metadata +119 -9
- data/.vscode/launch.json +0 -19
- data/bin/package_extension +0 -5
- data/bin/style +0 -10
- data/lib/ruby/lsp/cli.rb +0 -37
- data/lib/ruby/lsp.rb +0 -3
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module RubyLsp
|
|
5
|
+
module Requests
|
|
6
|
+
# The [semantic
|
|
7
|
+
# highlighting](https://microsoft.github.io/language-server-protocol/specification#textDocument_semanticTokens)
|
|
8
|
+
# request informs the editor of the correct token types to provide consistent and accurate highlighting for themes.
|
|
9
|
+
#
|
|
10
|
+
# # Example
|
|
11
|
+
#
|
|
12
|
+
# ```ruby
|
|
13
|
+
# def foo
|
|
14
|
+
# var = 1 # --> semantic highlighting: local variable
|
|
15
|
+
# some_invocation # --> semantic highlighting: method invocation
|
|
16
|
+
# var # --> semantic highlighting: local variable
|
|
17
|
+
# end
|
|
18
|
+
# ```
|
|
19
|
+
class SemanticHighlighting < BaseRequest
|
|
20
|
+
TOKEN_TYPES = [
|
|
21
|
+
:variable,
|
|
22
|
+
:method,
|
|
23
|
+
].freeze
|
|
24
|
+
|
|
25
|
+
TOKEN_MODIFIERS = {
|
|
26
|
+
declaration: 0,
|
|
27
|
+
definition: 1,
|
|
28
|
+
readonly: 2,
|
|
29
|
+
static: 3,
|
|
30
|
+
deprecated: 4,
|
|
31
|
+
abstract: 5,
|
|
32
|
+
async: 6,
|
|
33
|
+
modification: 7,
|
|
34
|
+
documentation: 8,
|
|
35
|
+
default_library: 9,
|
|
36
|
+
}.freeze
|
|
37
|
+
|
|
38
|
+
SemanticToken = Struct.new(:location, :length, :type, :modifier)
|
|
39
|
+
|
|
40
|
+
def initialize(document, encoder: nil)
|
|
41
|
+
super(document)
|
|
42
|
+
|
|
43
|
+
@encoder = encoder
|
|
44
|
+
@tokens = []
|
|
45
|
+
@tree = document.tree
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def run
|
|
49
|
+
visit(@tree)
|
|
50
|
+
return @tokens unless @encoder
|
|
51
|
+
|
|
52
|
+
@encoder.encode(@tokens)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def visit_m_assign(node)
|
|
56
|
+
node.target.parts.each do |var_ref|
|
|
57
|
+
add_token(var_ref.value.location, :variable)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def visit_var_field(node)
|
|
62
|
+
case node.value
|
|
63
|
+
when SyntaxTree::Ident
|
|
64
|
+
add_token(node.value.location, :variable)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def visit_var_ref(node)
|
|
69
|
+
case node.value
|
|
70
|
+
when SyntaxTree::Ident
|
|
71
|
+
add_token(node.value.location, :variable)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def visit_a_ref_field(node)
|
|
76
|
+
add_token(node.collection.value.location, :variable)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def visit_call(node)
|
|
80
|
+
visit(node.receiver)
|
|
81
|
+
add_token(node.message.location, :method)
|
|
82
|
+
visit(node.arguments)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def visit_command(node)
|
|
86
|
+
add_token(node.message.location, :method)
|
|
87
|
+
visit(node.arguments)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def visit_command_call(node)
|
|
91
|
+
visit(node.receiver)
|
|
92
|
+
add_token(node.message.location, :method)
|
|
93
|
+
visit(node.arguments)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def visit_fcall(node)
|
|
97
|
+
add_token(node.value.location, :method)
|
|
98
|
+
visit(node.arguments)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def visit_vcall(node)
|
|
102
|
+
add_token(node.value.location, :method)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def add_token(location, type, modifiers = [])
|
|
106
|
+
length = location.end_char - location.start_char
|
|
107
|
+
modifiers_indices = modifiers.filter_map { |modifier| TOKEN_MODIFIERS[modifier] }
|
|
108
|
+
@tokens.push(SemanticToken.new(location, length, TOKEN_TYPES.index(type), modifiers_indices))
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module RubyLsp
|
|
5
|
+
module Requests
|
|
6
|
+
module Support
|
|
7
|
+
class RuboCopDiagnostic
|
|
8
|
+
RUBOCOP_TO_LSP_SEVERITY = {
|
|
9
|
+
convention: LanguageServer::Protocol::Constant::DiagnosticSeverity::INFORMATION,
|
|
10
|
+
info: LanguageServer::Protocol::Constant::DiagnosticSeverity::INFORMATION,
|
|
11
|
+
refactor: LanguageServer::Protocol::Constant::DiagnosticSeverity::INFORMATION,
|
|
12
|
+
warning: LanguageServer::Protocol::Constant::DiagnosticSeverity::WARNING,
|
|
13
|
+
error: LanguageServer::Protocol::Constant::DiagnosticSeverity::ERROR,
|
|
14
|
+
fatal: LanguageServer::Protocol::Constant::DiagnosticSeverity::ERROR,
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
attr_reader :replacements
|
|
18
|
+
|
|
19
|
+
def initialize(offense, uri)
|
|
20
|
+
@offense = offense
|
|
21
|
+
@uri = uri
|
|
22
|
+
@replacements = offense.correctable? ? offense_replacements : []
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def correctable?
|
|
26
|
+
@offense.correctable?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def in_range?(range)
|
|
30
|
+
range.cover?(@offense.line - 1)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def to_lsp_code_action
|
|
34
|
+
LanguageServer::Protocol::Interface::CodeAction.new(
|
|
35
|
+
title: "Autocorrect #{@offense.cop_name}",
|
|
36
|
+
kind: LanguageServer::Protocol::Constant::CodeActionKind::QUICK_FIX,
|
|
37
|
+
edit: LanguageServer::Protocol::Interface::WorkspaceEdit.new(
|
|
38
|
+
document_changes: [
|
|
39
|
+
LanguageServer::Protocol::Interface::TextDocumentEdit.new(
|
|
40
|
+
text_document: LanguageServer::Protocol::Interface::OptionalVersionedTextDocumentIdentifier.new(
|
|
41
|
+
uri: @uri,
|
|
42
|
+
version: nil
|
|
43
|
+
),
|
|
44
|
+
edits: @replacements
|
|
45
|
+
),
|
|
46
|
+
]
|
|
47
|
+
),
|
|
48
|
+
is_preferred: true,
|
|
49
|
+
)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def to_lsp_diagnostic
|
|
53
|
+
LanguageServer::Protocol::Interface::Diagnostic.new(
|
|
54
|
+
message: @offense.message,
|
|
55
|
+
source: "RuboCop",
|
|
56
|
+
code: @offense.cop_name,
|
|
57
|
+
severity: RUBOCOP_TO_LSP_SEVERITY[@offense.severity.name],
|
|
58
|
+
range: LanguageServer::Protocol::Interface::Range.new(
|
|
59
|
+
start: LanguageServer::Protocol::Interface::Position.new(
|
|
60
|
+
line: @offense.line - 1,
|
|
61
|
+
character: @offense.column
|
|
62
|
+
),
|
|
63
|
+
end: LanguageServer::Protocol::Interface::Position.new(
|
|
64
|
+
line: @offense.last_line - 1,
|
|
65
|
+
character: @offense.last_column
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def offense_replacements
|
|
74
|
+
@offense.corrector.as_replacements.map do |range, replacement|
|
|
75
|
+
LanguageServer::Protocol::Interface::TextEdit.new(
|
|
76
|
+
range: LanguageServer::Protocol::Interface::Range.new(
|
|
77
|
+
start: LanguageServer::Protocol::Interface::Position.new(line: range.line - 1, character: range.column),
|
|
78
|
+
end: LanguageServer::Protocol::Interface::Position.new(line: range.last_line - 1,
|
|
79
|
+
character: range.last_column)
|
|
80
|
+
),
|
|
81
|
+
new_text: replacement
|
|
82
|
+
)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module RubyLsp
|
|
5
|
+
module Requests
|
|
6
|
+
module Support
|
|
7
|
+
class SelectionRange < LanguageServer::Protocol::Interface::SelectionRange
|
|
8
|
+
def cover?(position)
|
|
9
|
+
line_range = (range.start.line..range.end.line)
|
|
10
|
+
character_range = (range.start.character..range.end.character)
|
|
11
|
+
|
|
12
|
+
line_range.cover?(position[:line]) && character_range.cover?(position[:character])
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module RubyLsp
|
|
5
|
+
module Requests
|
|
6
|
+
module Support
|
|
7
|
+
class SemanticTokenEncoder
|
|
8
|
+
def initialize
|
|
9
|
+
@current_row = 0
|
|
10
|
+
@current_column = 0
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def encode(tokens)
|
|
14
|
+
delta = tokens
|
|
15
|
+
.sort_by do |token|
|
|
16
|
+
[token.location.start_line, token.location.start_column]
|
|
17
|
+
end
|
|
18
|
+
.flat_map do |token|
|
|
19
|
+
compute_delta(token)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
LanguageServer::Protocol::Interface::SemanticTokens.new(data: delta)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# The delta array is computed according to the LSP specification:
|
|
26
|
+
# > The protocol for the token format relative uses relative
|
|
27
|
+
# > positions, because most tokens remain stable relative to
|
|
28
|
+
# > each other when edits are made in a file. This simplifies
|
|
29
|
+
# > the computation of a delta if a server supports it. So each
|
|
30
|
+
# > token is represented using 5 integers.
|
|
31
|
+
|
|
32
|
+
# For more information on how each number is calculated, read:
|
|
33
|
+
# https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_semanticTokens
|
|
34
|
+
def compute_delta(token)
|
|
35
|
+
row = token.location.start_line - 1
|
|
36
|
+
column = token.location.start_column
|
|
37
|
+
delta_line = row - @current_row
|
|
38
|
+
|
|
39
|
+
delta_column = column
|
|
40
|
+
delta_column -= @current_column if delta_line == 0
|
|
41
|
+
|
|
42
|
+
[delta_line, delta_column, token.length, token.type, encode_modifiers(token.modifier)]
|
|
43
|
+
ensure
|
|
44
|
+
@current_row = row
|
|
45
|
+
@current_column = column
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Encode an array of modifiers to positions onto a bit flag
|
|
49
|
+
# For example, [:default_library] will be encoded as
|
|
50
|
+
# 0b1000000000, as :default_library is the 10th bit according
|
|
51
|
+
# to the token modifiers index map.
|
|
52
|
+
def encode_modifiers(modifiers)
|
|
53
|
+
modifiers.inject(0) do |encoded_modifiers, modifier|
|
|
54
|
+
encoded_modifiers | (1 << modifier)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module RubyLsp
|
|
5
|
+
module Requests
|
|
6
|
+
module Support
|
|
7
|
+
class SyntaxErrorDiagnostic
|
|
8
|
+
def initialize(edit)
|
|
9
|
+
@edit = edit
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def correctable?
|
|
13
|
+
false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_lsp_diagnostic
|
|
17
|
+
LanguageServer::Protocol::Interface::Diagnostic.new(
|
|
18
|
+
message: "Syntax error",
|
|
19
|
+
source: "SyntaxTree",
|
|
20
|
+
severity: LanguageServer::Protocol::Constant::DiagnosticSeverity::ERROR,
|
|
21
|
+
range: @edit[:range]
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module RubyLsp
|
|
5
|
+
module Requests
|
|
6
|
+
autoload :BaseRequest, "ruby_lsp/requests/base_request"
|
|
7
|
+
autoload :DocumentSymbol, "ruby_lsp/requests/document_symbol"
|
|
8
|
+
autoload :FoldingRanges, "ruby_lsp/requests/folding_ranges"
|
|
9
|
+
autoload :SelectionRanges, "ruby_lsp/requests/selection_ranges"
|
|
10
|
+
autoload :SemanticHighlighting, "ruby_lsp/requests/semantic_highlighting"
|
|
11
|
+
autoload :RuboCopRequest, "ruby_lsp/requests/rubocop_request"
|
|
12
|
+
autoload :Formatting, "ruby_lsp/requests/formatting"
|
|
13
|
+
autoload :Diagnostics, "ruby_lsp/requests/diagnostics"
|
|
14
|
+
autoload :CodeActions, "ruby_lsp/requests/code_actions"
|
|
15
|
+
autoload :DocumentHighlight, "ruby_lsp/requests/document_highlight"
|
|
16
|
+
|
|
17
|
+
module Support
|
|
18
|
+
autoload :RuboCopDiagnostic, "ruby_lsp/requests/support/rubocop_diagnostic"
|
|
19
|
+
autoload :SelectionRange, "ruby_lsp/requests/support/selection_range"
|
|
20
|
+
autoload :SemanticTokenEncoder, "ruby_lsp/requests/support/semantic_token_encoder"
|
|
21
|
+
autoload :SyntaxErrorDiagnostic, "ruby_lsp/requests/support/syntax_error_diagnostic"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "cgi"
|
|
5
|
+
require "uri"
|
|
6
|
+
require "ruby_lsp/document"
|
|
7
|
+
|
|
8
|
+
module RubyLsp
|
|
9
|
+
class Store
|
|
10
|
+
extend T::Sig
|
|
11
|
+
|
|
12
|
+
sig { void }
|
|
13
|
+
def initialize
|
|
14
|
+
@state = T.let({}, T::Hash[String, Document])
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
sig { params(uri: String).returns(Document) }
|
|
18
|
+
def get(uri)
|
|
19
|
+
document = @state[uri]
|
|
20
|
+
return document unless document.nil?
|
|
21
|
+
|
|
22
|
+
set(uri, File.binread(CGI.unescape(URI.parse(uri).path)))
|
|
23
|
+
T.must(@state[uri])
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
sig { params(uri: String, content: String).void }
|
|
27
|
+
def set(uri, content)
|
|
28
|
+
@state[uri] = Document.new(content)
|
|
29
|
+
rescue SyntaxTree::Parser::ParseError
|
|
30
|
+
# Do not update the store if there are syntax errors
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
sig { params(uri: String, edits: T::Array[Document::EditShape]).void }
|
|
34
|
+
def push_edits(uri, edits)
|
|
35
|
+
T.must(@state[uri]).push_edits(edits)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
sig { void }
|
|
39
|
+
def clear
|
|
40
|
+
@state.clear
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
sig { params(uri: String).void }
|
|
44
|
+
def delete(uri)
|
|
45
|
+
@state.delete(uri)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
sig do
|
|
49
|
+
params(
|
|
50
|
+
uri: String,
|
|
51
|
+
request_name: Symbol,
|
|
52
|
+
block: T.proc.params(document: Document).returns(T.untyped)
|
|
53
|
+
).returns(T.untyped)
|
|
54
|
+
end
|
|
55
|
+
def cache_fetch(uri, request_name, &block)
|
|
56
|
+
get(uri).cache_fetch(request_name, &block)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# typed: false
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
desc "Check if all LSP requests are documented"
|
|
5
|
+
task :check_docs do
|
|
6
|
+
require "language_server-protocol"
|
|
7
|
+
require "syntax_tree"
|
|
8
|
+
require "logger"
|
|
9
|
+
require "ruby_lsp/requests/base_request"
|
|
10
|
+
require "ruby_lsp/requests/rubocop_request"
|
|
11
|
+
|
|
12
|
+
Dir["#{Dir.pwd}/lib/ruby_lsp/requests/*.rb"].each do |file|
|
|
13
|
+
require(file)
|
|
14
|
+
YARD.parse(file, [], Logger::Severity::FATAL)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
spec_matcher = %r{\(https://microsoft.github.io/language-server-protocol/specification#.*\)}
|
|
18
|
+
error_messages = RubyLsp::Requests
|
|
19
|
+
.constants # rubocop:disable Sorbet/ConstantsFromStrings
|
|
20
|
+
.each_with_object(Hash.new { |h, k| h[k] = [] }) do |request, errors|
|
|
21
|
+
full_name = "RubyLsp::Requests::#{request}"
|
|
22
|
+
docs = YARD::Registry.at(full_name).docstring
|
|
23
|
+
next if /:nodoc:/.match?(docs)
|
|
24
|
+
|
|
25
|
+
if docs.empty?
|
|
26
|
+
errors[full_name] << "Missing documentation for request handler class"
|
|
27
|
+
elsif !spec_matcher.match?(docs)
|
|
28
|
+
errors[full_name] << <<~MESSAGE
|
|
29
|
+
Documentation for request handler classes must link to the official LSP specification.
|
|
30
|
+
|
|
31
|
+
For example, if your request handles text document hover, you should add a link to
|
|
32
|
+
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover.
|
|
33
|
+
MESSAGE
|
|
34
|
+
elsif !/# Example/.match?(docs)
|
|
35
|
+
errors[full_name] << <<~MESSAGE
|
|
36
|
+
Documentation for request handler class must contain an example.
|
|
37
|
+
|
|
38
|
+
= Example
|
|
39
|
+
def my_method # <-- something happens here
|
|
40
|
+
end
|
|
41
|
+
MESSAGE
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
formatted_errors = error_messages.map { |name, errors| "#{name}: #{errors.join(", ")}" }
|
|
46
|
+
|
|
47
|
+
if error_messages.any?
|
|
48
|
+
puts <<~MESSAGE
|
|
49
|
+
The following requests have invalid documentation:
|
|
50
|
+
|
|
51
|
+
#{formatted_errors.join("\n")}
|
|
52
|
+
MESSAGE
|
|
53
|
+
|
|
54
|
+
exit!
|
|
55
|
+
end
|
|
56
|
+
end
|
data/ruby-lsp.gemspec
CHANGED
|
@@ -10,6 +10,7 @@ Gem::Specification.new do |s|
|
|
|
10
10
|
s.summary = "A simple language server for ruby"
|
|
11
11
|
s.description = "A simple language server for ruby"
|
|
12
12
|
s.homepage = "https://github.com/Shopify/ruby-lsp"
|
|
13
|
+
s.license = "MIT"
|
|
13
14
|
|
|
14
15
|
s.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
15
16
|
%x(git ls-files -z).split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
|
@@ -18,5 +19,8 @@ Gem::Specification.new do |s|
|
|
|
18
19
|
s.executables = s.files.grep(/\Aexe/) { |f| File.basename(f) }
|
|
19
20
|
s.require_paths = ["lib"]
|
|
20
21
|
|
|
21
|
-
s.add_dependency
|
|
22
|
+
s.add_dependency("language_server-protocol")
|
|
23
|
+
s.add_dependency("rubocop", ">= 1.0")
|
|
24
|
+
s.add_dependency("sorbet-runtime")
|
|
25
|
+
s.add_dependency("syntax_tree", ">= 2.3")
|
|
22
26
|
end
|
|
File without changes
|
data/sorbet/config
ADDED