klenod-lsp 0.0.31 → 0.0.33
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 -2
- data/lib/klenod/lsp/languages/haml/classes.rb +96 -15
- data/lib/klenod/lsp/languages/haml/props.rb +34 -13
- data/lib/klenod/lsp/languages/haml/rename.rb +7 -3
- data/lib/klenod/lsp/languages/haml.rb +10 -1
- data/lib/klenod/lsp/languages/imports.rb +10 -2
- data/lib/klenod/lsp/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 96ad37bd6ec750e9c26613eddc39034c1ee2b93837d4ef4d9b5427ca72b1072c
|
|
4
|
+
data.tar.gz: e17b0235f5cf7a6142cf5d6042a0f09a75158cf5aa21fb949f1460b0477772e4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a933f96338104e6e505e1a28aecf759215b989c86487c6bb173628d97d52a0898c73e4bedff36270aa6d9fd35d31d91256b103ab5398b9650d781768b956e3dd
|
|
7
|
+
data.tar.gz: 497c4009b5f27f79c08a18f3b9022cb55376f3184152eacfa8f44fe3c039fcc986ba77a5f62dd4daba557fcc5cafcfc4d9ca7b69f76d5aa7444438efe5da6e92
|
data/README.md
CHANGED
|
@@ -17,8 +17,11 @@ application code.
|
|
|
17
17
|
- Symbol rename within a Haml or Ruby file and import-preserving edits when
|
|
18
18
|
files or directories move.
|
|
19
19
|
- Prop and slot information for Haml components, including spelling suggestions
|
|
20
|
-
for unknown props.
|
|
21
|
-
|
|
20
|
+
for unknown props. Prop checks inspect the outer attribute hash and leave
|
|
21
|
+
nested hash keys and text inside values alone.
|
|
22
|
+
- Scoped CSS class definition, hover, completion, and validation in Haml, for
|
|
23
|
+
`.name` shorthand, symbols in `class:` attributes such as
|
|
24
|
+
`class: [:name, { active: open? }]`, and `ClassNames[:name]` lookups.
|
|
22
25
|
- Route lenses and hovers when `RouterPlugin` is configured.
|
|
23
26
|
|
|
24
27
|
Ruby support is intentionally limited to Klenod imports and their bound
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "language_server-protocol"
|
|
4
|
+
require "prism"
|
|
4
5
|
|
|
5
6
|
require_relative "../../text"
|
|
7
|
+
require_relative "ruby_regions"
|
|
6
8
|
|
|
7
9
|
module Klenod
|
|
8
10
|
module LSP
|
|
9
11
|
module Languages
|
|
10
12
|
class Haml
|
|
11
|
-
# CSS class names in a Haml component: the `.name` shorthand on tags
|
|
12
|
-
# and `ClassNames[:name]`
|
|
13
|
-
#
|
|
14
|
-
# comes from the graph's
|
|
13
|
+
# CSS class names in a Haml component: the `.name` shorthand on tags,
|
|
14
|
+
# symbols in a tag's `class:` attribute, and `ClassNames[:name]`
|
|
15
|
+
# lookups, checked against the class map of the companion stylesheet
|
|
16
|
+
# and any inline `:css` filters. The map comes from the graph's
|
|
17
|
+
# records, collected on demand.
|
|
15
18
|
module Classes
|
|
16
19
|
Interface = LanguageServer::Protocol::Interface
|
|
17
20
|
Constant = LanguageServer::Protocol::Constant
|
|
@@ -21,8 +24,12 @@ module Klenod
|
|
|
21
24
|
LOOKUP = /ClassNames\[:(?<name>[\w-]+)\]/
|
|
22
25
|
SHORTHAND_PREFIX = /\A\s*(?:%[A-Za-z][\w:-]*)?(?:[.#][\w-]+)*\.(?<partial>[\w-]*)\z/
|
|
23
26
|
LOOKUP_PREFIX = /ClassNames\[:(?<partial>[\w-]*)\z/
|
|
27
|
+
CLASS_KEY_PREFIX = /(?:(?<![\w:])class:|:class\s*=>|["']class["']\s*(?::|=>))/
|
|
28
|
+
SYMBOL_PREFIX = /(?:\A|[\s\[,]):(?<partial>[\w-]*)\z/
|
|
29
|
+
OPENERS = "[{("
|
|
30
|
+
CLOSERS = "]})"
|
|
24
31
|
STYLE_KINDS = %i[companion_style inline_style].freeze
|
|
25
|
-
FILTER_HEAD = /\A\s
|
|
32
|
+
FILTER_HEAD = /\A\s*:(?<name>\w+)/
|
|
26
33
|
|
|
27
34
|
Occurrence = Data.define(:name, :span)
|
|
28
35
|
Definition = Data.define(:module_id, :generated)
|
|
@@ -65,24 +72,76 @@ module Klenod
|
|
|
65
72
|
end
|
|
66
73
|
end
|
|
67
74
|
|
|
68
|
-
# Shorthand classes are only read outside
|
|
69
|
-
# method chain such as `.freeze` is not a
|
|
70
|
-
# lookups count everywhere.
|
|
75
|
+
# Shorthand and `class:` attribute classes are only read outside
|
|
76
|
+
# filters, so a `:ruby` method chain such as `.freeze` is not a
|
|
77
|
+
# class. `ClassNames[:name]` lookups count everywhere.
|
|
71
78
|
def occurrences(lines)
|
|
72
79
|
filter_body = filter_body_lines(lines)
|
|
73
80
|
lines.each_with_index.flat_map do |line_text, index|
|
|
74
81
|
found = []
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
82
|
+
unless filter_body.include?(index)
|
|
83
|
+
if (head = TAG_HEAD.match(line_text))
|
|
84
|
+
offset = head.begin(:shorthand)
|
|
85
|
+
Text.each_match(head[:shorthand], index, SHORTHAND_CLASS, group: :name) do |match, span|
|
|
86
|
+
found << Occurrence.new(match[:name], span.with(start_character: span.start_character + offset, end_character: span.end_character + offset))
|
|
87
|
+
end
|
|
79
88
|
end
|
|
89
|
+
found.concat(attribute_occurrences(line_text, index))
|
|
80
90
|
end
|
|
81
91
|
Text.each_match(line_text, index, LOOKUP, group: :name) { |match, span| found << Occurrence.new(match[:name], span) }
|
|
82
92
|
found
|
|
83
93
|
end
|
|
84
94
|
end
|
|
85
95
|
|
|
96
|
+
# Symbols in the `class:` value of an attribute hash closed on the
|
|
97
|
+
# tag line: `class: :name`, `:class => :name`, symbols in an array,
|
|
98
|
+
# and symbol keys of a conditional hash such as `{ active: open? }`.
|
|
99
|
+
# Computed values are left alone, and strings are unscoped classes.
|
|
100
|
+
def attribute_occurrences(line_text, line_index)
|
|
101
|
+
head = RubyRegions::TAG_HEAD.match(line_text)
|
|
102
|
+
return [] unless head
|
|
103
|
+
|
|
104
|
+
RubyRegions.attribute_regions(line_text[head.end(0)..].to_s).flat_map do |region_offset, region|
|
|
105
|
+
next [] unless region.start_with?("{")
|
|
106
|
+
|
|
107
|
+
result = Prism.parse(region)
|
|
108
|
+
hash = result.value.statements.body.first
|
|
109
|
+
next [] unless result.success? && hash.is_a?(Prism::HashNode)
|
|
110
|
+
|
|
111
|
+
offset = head.end(0) + region_offset
|
|
112
|
+
hash.elements.flat_map do |element|
|
|
113
|
+
next [] unless element.is_a?(Prism::AssocNode) && class_key?(element.key)
|
|
114
|
+
|
|
115
|
+
class_symbols(element.value).map do |symbol|
|
|
116
|
+
location = symbol.value_loc
|
|
117
|
+
Occurrence.new(
|
|
118
|
+
symbol.unescaped,
|
|
119
|
+
Text::Span.new(line_index, offset + location.start_character_offset, offset + location.end_character_offset)
|
|
120
|
+
)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def class_key?(node)
|
|
127
|
+
(node.is_a?(Prism::SymbolNode) || node.is_a?(Prism::StringNode)) && node.unescaped == "class"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def class_symbols(node)
|
|
131
|
+
case node
|
|
132
|
+
when Prism::SymbolNode
|
|
133
|
+
node.value_loc ? [node] : []
|
|
134
|
+
when Prism::ArrayNode
|
|
135
|
+
node.elements.flat_map { class_symbols(it) }
|
|
136
|
+
when Prism::HashNode, Prism::KeywordHashNode
|
|
137
|
+
node.elements.flat_map do |element|
|
|
138
|
+
(element.is_a?(Prism::AssocNode) && element.key.is_a?(Prism::SymbolNode)) ? class_symbols(element.key) : []
|
|
139
|
+
end
|
|
140
|
+
else
|
|
141
|
+
[]
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
86
145
|
def occurrence_at(lines, position)
|
|
87
146
|
return nil unless lines[position.line]
|
|
88
147
|
|
|
@@ -92,14 +151,16 @@ module Klenod
|
|
|
92
151
|
# Indexes of the lines inside filters: every line after a `:name`
|
|
93
152
|
# line that is blank or indented deeper than it, as Haml reads them.
|
|
94
153
|
# Indentation alone also works while the document does not parse.
|
|
95
|
-
|
|
154
|
+
# Filters named in `except` are left out.
|
|
155
|
+
def filter_body_lines(lines, except: [])
|
|
96
156
|
filter_indent = nil
|
|
97
157
|
lines.each_with_index.with_object(Set.new) do |(line_text, index), body|
|
|
98
158
|
indent = line_text[/\A\s*/].length
|
|
99
159
|
if filter_indent && (line_text.strip.empty? || indent > filter_indent)
|
|
100
160
|
body << index
|
|
101
161
|
else
|
|
102
|
-
|
|
162
|
+
head = FILTER_HEAD.match(line_text)
|
|
163
|
+
filter_indent = (head && !except.include?(head[:name])) ? indent : nil
|
|
103
164
|
end
|
|
104
165
|
end
|
|
105
166
|
end
|
|
@@ -146,7 +207,7 @@ module Klenod
|
|
|
146
207
|
|
|
147
208
|
def completion_items(prefix, position, analysis, workspace, index)
|
|
148
209
|
in_filter = filter_body_lines(analysis.lines).include?(position.line)
|
|
149
|
-
match = (!in_filter && SHORTHAND_PREFIX.match(prefix)) || LOOKUP_PREFIX.match(prefix)
|
|
210
|
+
match = (!in_filter && (SHORTHAND_PREFIX.match(prefix) || class_symbol_prefix(prefix))) || LOOKUP_PREFIX.match(prefix)
|
|
150
211
|
return nil unless match
|
|
151
212
|
|
|
152
213
|
map = map(analysis, workspace, index)
|
|
@@ -166,6 +227,26 @@ module Klenod
|
|
|
166
227
|
end
|
|
167
228
|
end
|
|
168
229
|
|
|
230
|
+
# A symbol being typed in a tag's `class:` value, such as
|
|
231
|
+
# `%p{ class: [:lead, :k`. A comma outside brackets ends the value,
|
|
232
|
+
# so the next attribute's symbols are not completed as classes.
|
|
233
|
+
def class_symbol_prefix(prefix)
|
|
234
|
+
return nil unless RubyRegions::TAG_HEAD.match?(prefix)
|
|
235
|
+
|
|
236
|
+
key = prefix.to_enum(:scan, CLASS_KEY_PREFIX).map { Regexp.last_match }.last
|
|
237
|
+
return nil unless key
|
|
238
|
+
|
|
239
|
+
value = prefix[key.end(0)..]
|
|
240
|
+
depth = 0
|
|
241
|
+
value.each_char do |char|
|
|
242
|
+
depth += 1 if OPENERS.include?(char)
|
|
243
|
+
depth -= 1 if CLOSERS.include?(char)
|
|
244
|
+
return nil if depth.negative? || (depth.zero? && char == ",")
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
SYMBOL_PREFIX.match(value)
|
|
248
|
+
end
|
|
249
|
+
|
|
169
250
|
def style_record(module_id, workspace, index)
|
|
170
251
|
index.record(module_id) || workspace.context.graph.collect_module(module_id)
|
|
171
252
|
rescue StandardError, ScriptError
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
require "did_you_mean"
|
|
4
4
|
require "language_server-protocol"
|
|
5
|
+
require "prism"
|
|
5
6
|
|
|
6
7
|
require_relative "../../text"
|
|
7
8
|
require_relative "../imports"
|
|
9
|
+
require_relative "classes"
|
|
8
10
|
require_relative "ruby_regions"
|
|
9
11
|
|
|
10
12
|
module Klenod
|
|
@@ -24,13 +26,6 @@ module Klenod
|
|
|
24
26
|
# `key="value"`, `key=value`, or a bare boolean `key`; a consumed
|
|
25
27
|
# value cannot be mistaken for the next key.
|
|
26
28
|
HTML_KEY = /(?<![\w-])(?<key>[A-Za-z_][\w-]*)(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s()]+))?/
|
|
27
|
-
HASH_KEYS = [
|
|
28
|
-
/(?<=[{,]|\A)\s*(?<key>[A-Za-z_]\w*):(?!:)/,
|
|
29
|
-
/(?<=[{,]|\A)\s*"(?<key>[^"]+)":/,
|
|
30
|
-
/(?<=[{,]|\A)\s*:(?<key>\w+)\s*=>/,
|
|
31
|
-
/(?<=[{,]|\A)\s*"(?<key>[^"]+)"\s*=>/
|
|
32
|
-
].freeze
|
|
33
|
-
SPLAT = /\*\*/
|
|
34
29
|
CLOSERS = {"{" => "}", "(" => ")", "[" => "]"}.freeze
|
|
35
30
|
# Props every component accepts: Haml passes `children`, `%Foo[item]`
|
|
36
31
|
# passes `key`, and `slot` places the component in its parent's slot.
|
|
@@ -42,10 +37,13 @@ module Klenod
|
|
|
42
37
|
|
|
43
38
|
def diagnostics(analysis, workspace, index)
|
|
44
39
|
lines = analysis.lines
|
|
45
|
-
bindings =
|
|
40
|
+
bindings = Haml.bindings(lines)
|
|
46
41
|
props_cache = {}
|
|
42
|
+
filter_body = Classes.filter_body_lines(lines)
|
|
47
43
|
|
|
48
44
|
lines.each_with_index.flat_map do |line_text, line_index|
|
|
45
|
+
next [] if filter_body.include?(line_index)
|
|
46
|
+
|
|
49
47
|
tag = TAG_LINE.match(line_text)
|
|
50
48
|
next [] unless tag
|
|
51
49
|
|
|
@@ -75,13 +73,15 @@ module Klenod
|
|
|
75
73
|
def explicit_keys(rest, line_index, offset)
|
|
76
74
|
keys = []
|
|
77
75
|
RubyRegions.attribute_regions(rest).each do |region_offset, region|
|
|
78
|
-
return nil if region.start_with?("{") && region.match?(SPLAT)
|
|
79
76
|
return nil unless region.end_with?(CLOSERS.fetch(region[0]))
|
|
80
77
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
78
|
+
if region.start_with?("{")
|
|
79
|
+
hash_keys = explicit_hash_keys(region, line_index, offset + region_offset)
|
|
80
|
+
return nil unless hash_keys
|
|
81
|
+
|
|
82
|
+
keys.concat(hash_keys)
|
|
83
|
+
elsif region.start_with?("(")
|
|
84
|
+
Text.each_match(region[1...-1], line_index, HTML_KEY, group: :key) do |match, span|
|
|
85
85
|
start = offset + region_offset + 1 + span.start_character
|
|
86
86
|
keys << Key.new(match[:key], Text::Span.new(line_index, start, start + match[:key].length))
|
|
87
87
|
end
|
|
@@ -90,6 +90,27 @@ module Klenod
|
|
|
90
90
|
keys.uniq { |key| key.span.start_character }
|
|
91
91
|
end
|
|
92
92
|
|
|
93
|
+
# Only the outer hash supplies props. Keys in nested hashes, blocks,
|
|
94
|
+
# and strings belong to values, and only an outer splat prevents us
|
|
95
|
+
# from knowing which props the component receives.
|
|
96
|
+
def explicit_hash_keys(source, line_index, offset)
|
|
97
|
+
result = Prism.parse(source, partial_script: true)
|
|
98
|
+
hash = result.value.statements.body.first
|
|
99
|
+
return nil unless result.success? && hash.is_a?(Prism::HashNode)
|
|
100
|
+
return nil if hash.elements.any? { |element| element.is_a?(Prism::AssocSplatNode) }
|
|
101
|
+
|
|
102
|
+
hash.elements.filter_map do |element|
|
|
103
|
+
name, location =
|
|
104
|
+
case (key = element.key)
|
|
105
|
+
when Prism::SymbolNode then [key.value, key.value_loc]
|
|
106
|
+
when Prism::StringNode then [key.unescaped, key.content_loc]
|
|
107
|
+
else next
|
|
108
|
+
end
|
|
109
|
+
start = offset + source.byteslice(0, location.start_offset).length
|
|
110
|
+
Key.new(name, Text::Span.new(line_index, start, start + location.slice.length))
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
93
114
|
def component_props(specifier, analysis, workspace, index)
|
|
94
115
|
module_id = analysis.resolved_module_id_for(specifier) || workspace.resolve(specifier, importer_id: analysis.module_id)
|
|
95
116
|
return nil unless module_id
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "../../text"
|
|
4
4
|
require_relative "../imports"
|
|
5
|
+
require_relative "classes"
|
|
5
6
|
require_relative "ruby_regions"
|
|
6
7
|
|
|
7
8
|
module Klenod
|
|
@@ -9,9 +10,9 @@ module Klenod
|
|
|
9
10
|
module Languages
|
|
10
11
|
class Haml
|
|
11
12
|
# Where a bound constant appears in a Haml document: the `%Name` tags
|
|
12
|
-
# and the whole-word uses inside Ruby, meaning `:ruby`
|
|
13
|
-
# lines, tag attributes, and printed tag content.
|
|
14
|
-
# its words.
|
|
13
|
+
# outside filters and the whole-word uses inside Ruby, meaning `:ruby`
|
|
14
|
+
# filters, script lines, tag attributes, and printed tag content.
|
|
15
|
+
# Plain text keeps its words.
|
|
15
16
|
module Rename
|
|
16
17
|
module_function
|
|
17
18
|
|
|
@@ -25,7 +26,10 @@ module Klenod
|
|
|
25
26
|
end
|
|
26
27
|
end
|
|
27
28
|
|
|
29
|
+
filter_body = Classes.filter_body_lines(lines)
|
|
28
30
|
lines.each_with_index do |line_text, index|
|
|
31
|
+
next if filter_body.include?(index)
|
|
32
|
+
|
|
29
33
|
Text.each_match(line_text, index, Haml::COMPONENT_TAG, group: :name) do |match, span|
|
|
30
34
|
next unless match[:name].split("::").first == name
|
|
31
35
|
|
|
@@ -68,13 +68,22 @@ module Klenod
|
|
|
68
68
|
|
|
69
69
|
# `%Details` compiles to the constant `Details`, bound by an import in
|
|
70
70
|
# the leading `:ruby` filter such as `Details = import("/components/Details")`.
|
|
71
|
+
# Imports in other filters, such as code samples in `:markdown`, are
|
|
72
|
+
# text.
|
|
71
73
|
def self.bindings(lines)
|
|
72
|
-
|
|
74
|
+
text = Classes.filter_body_lines(lines, except: %w[ruby])
|
|
75
|
+
Imports.bindings(lines.reject.with_index { |_line_text, index| text.include?(index) })
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def bindings(lines)
|
|
79
|
+
self.class.bindings(lines)
|
|
73
80
|
end
|
|
74
81
|
|
|
75
82
|
private
|
|
76
83
|
|
|
77
84
|
def component_target_at(line_text, position, lines)
|
|
85
|
+
return nil if Classes.filter_body_lines(lines).include?(position.line)
|
|
86
|
+
|
|
78
87
|
Text.each_match(line_text, position.line, COMPONENT_TAG, group: :name) do |match, span|
|
|
79
88
|
next unless span.include?(position)
|
|
80
89
|
|
|
@@ -218,6 +218,11 @@ module Klenod
|
|
|
218
218
|
Syntax::Ruby
|
|
219
219
|
end
|
|
220
220
|
|
|
221
|
+
# Constant names bound to imports in a document, keyed by name.
|
|
222
|
+
def bindings(lines)
|
|
223
|
+
Imports.bindings(lines)
|
|
224
|
+
end
|
|
225
|
+
|
|
221
226
|
def definition(analysis, position, workspace, _index = nil)
|
|
222
227
|
target = target_at(analysis, position)
|
|
223
228
|
module_id = target && Imports.resolve(target, analysis, workspace)
|
|
@@ -376,11 +381,14 @@ module Klenod
|
|
|
376
381
|
def usage_spans(importer_id, lines, specifiers)
|
|
377
382
|
return [] unless importer_id.extname == ".haml"
|
|
378
383
|
|
|
379
|
-
names =
|
|
384
|
+
names = Languages::Haml.bindings(lines).select { |_name, specifier| specifiers.include?(specifier) }.keys
|
|
380
385
|
return [] if names.empty?
|
|
381
386
|
|
|
382
387
|
spans = []
|
|
388
|
+
filter_body = Languages::Haml::Classes.filter_body_lines(lines)
|
|
383
389
|
lines.each_with_index do |line_text, index|
|
|
390
|
+
next if filter_body.include?(index)
|
|
391
|
+
|
|
384
392
|
Text.each_match(line_text, index, Languages::Haml::COMPONENT_TAG, group: :name) do |match, span|
|
|
385
393
|
spans << span if names.include?(match[:name].split("::").first)
|
|
386
394
|
end
|
|
@@ -391,7 +399,7 @@ module Klenod
|
|
|
391
399
|
# Bindings whose constant is never used in the file. Languages give
|
|
392
400
|
# the spans a constant occupies, the binding included.
|
|
393
401
|
def unused_binding_diagnostics(analysis)
|
|
394
|
-
|
|
402
|
+
bindings(analysis.lines).filter_map do |name, _specifier|
|
|
395
403
|
spans = rename_spans(analysis, name)
|
|
396
404
|
next if spans.length > 1
|
|
397
405
|
|
data/lib/klenod/lsp/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: klenod-lsp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.33
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrés Alin
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.0.
|
|
18
|
+
version: 0.0.33
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - '='
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.0.
|
|
25
|
+
version: 0.0.33
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: language_server-protocol
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|