klenod-lsp 0.0.15
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 +7 -0
- data/README.md +114 -0
- data/lib/klenod/lsp/analysis.rb +29 -0
- data/lib/klenod/lsp/cli.rb +33 -0
- data/lib/klenod/lsp/diagnostics.rb +110 -0
- data/lib/klenod/lsp/documents.rb +72 -0
- data/lib/klenod/lsp/graph_index.rb +193 -0
- data/lib/klenod/lsp/languages/css.rb +45 -0
- data/lib/klenod/lsp/languages/haml/classes.rb +202 -0
- data/lib/klenod/lsp/languages/haml/completion.rb +60 -0
- data/lib/klenod/lsp/languages/haml/props.rb +111 -0
- data/lib/klenod/lsp/languages/haml/rename.rb +42 -0
- data/lib/klenod/lsp/languages/haml/ruby_regions.rb +85 -0
- data/lib/klenod/lsp/languages/haml.rb +87 -0
- data/lib/klenod/lsp/languages/imports.rb +428 -0
- data/lib/klenod/lsp/languages/ruby.rb +41 -0
- data/lib/klenod/lsp/languages/syntax.rb +64 -0
- data/lib/klenod/lsp/languages.rb +38 -0
- data/lib/klenod/lsp/renames.rb +141 -0
- data/lib/klenod/lsp/routes.rb +105 -0
- data/lib/klenod/lsp/server.rb +568 -0
- data/lib/klenod/lsp/symbols.rb +177 -0
- data/lib/klenod/lsp/text.rb +78 -0
- data/lib/klenod/lsp/version.rb +7 -0
- data/lib/klenod/lsp/workspace.rb +155 -0
- data/lib/klenod/lsp.rb +9 -0
- metadata +96 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "language_server-protocol"
|
|
4
|
+
|
|
5
|
+
require "klenod/build/plugins/haml_plugin"
|
|
6
|
+
|
|
7
|
+
require_relative "languages/imports"
|
|
8
|
+
require_relative "text"
|
|
9
|
+
|
|
10
|
+
module Klenod
|
|
11
|
+
module LSP
|
|
12
|
+
# Outlines for documents and name search across the indexed graph.
|
|
13
|
+
module Symbols
|
|
14
|
+
Interface = LanguageServer::Protocol::Interface
|
|
15
|
+
Constant = LanguageServer::Protocol::Constant
|
|
16
|
+
|
|
17
|
+
COMPONENT_TAG = /%(?<name>[A-Z][A-Za-z0-9_:]*)/
|
|
18
|
+
ELEMENT_TAG = /%(?<name>[a-z][A-Za-z0-9_-]*)/
|
|
19
|
+
METHOD = /\A\s*def\s+(?<name>(?:self\.)?[A-Za-z_][A-Za-z0-9_]*[?!=]?)/
|
|
20
|
+
WORKSPACE_LIMIT = 200
|
|
21
|
+
|
|
22
|
+
module_function
|
|
23
|
+
|
|
24
|
+
# The outline of a Haml component: constants and methods from the
|
|
25
|
+
# leading `:ruby` filter, then the tag tree. Script lines such as
|
|
26
|
+
# `- if` are transparent, so their children appear at the same level.
|
|
27
|
+
def haml_document_symbols(source)
|
|
28
|
+
lines = source.lines(chomp: true)
|
|
29
|
+
root = Klenod::Build::Plugins::HamlPlugin.parse_haml(source)
|
|
30
|
+
symbols_for_nodes(root.children, lines)
|
|
31
|
+
rescue Klenod::Build::Error
|
|
32
|
+
[]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Constants bound to imports, for Ruby modules.
|
|
36
|
+
def binding_symbols(source)
|
|
37
|
+
lines = source.lines(chomp: true)
|
|
38
|
+
symbols = []
|
|
39
|
+
lines.each_with_index do |line_text, index|
|
|
40
|
+
Text.each_match(line_text, index, Languages::Imports::BINDING, group: :name) do |match, span|
|
|
41
|
+
symbols << symbol(match[:name], Constant::SymbolKind::CONSTANT, Text.line_span(lines, index), span, detail: match[:specifier])
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
symbols
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Modules under the source directory whose name or path matches the
|
|
48
|
+
# query, as SymbolInformation so every client can show them.
|
|
49
|
+
def workspace_symbols(query, index, workspace)
|
|
50
|
+
needle = query.to_s.downcase
|
|
51
|
+
matches = []
|
|
52
|
+
|
|
53
|
+
index.records.each_key do |module_id|
|
|
54
|
+
next unless module_id.scheme == :app && GraphIndex::ROOT_EXTENSIONS.include?(module_id.extname)
|
|
55
|
+
|
|
56
|
+
relative = module_id.relative_path
|
|
57
|
+
stylesheet = module_id.extname == ".css"
|
|
58
|
+
name = stylesheet ? File.basename(relative) : File.basename(relative, module_id.extname)
|
|
59
|
+
next unless needle.empty? || fuzzy_match?(name.downcase, needle) || relative.downcase.include?(needle)
|
|
60
|
+
|
|
61
|
+
uri = workspace.uri_for_module_id(module_id)
|
|
62
|
+
next unless uri
|
|
63
|
+
|
|
64
|
+
matches << Interface::SymbolInformation.new(
|
|
65
|
+
name: name,
|
|
66
|
+
kind: symbol_kind(module_id),
|
|
67
|
+
location: Interface::Location.new(uri: uri, range: Text.zero_range),
|
|
68
|
+
container_name: File.dirname(relative)
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
matches.sort_by { |symbol| [symbol.name.downcase, symbol.container_name] }.first(WORKSPACE_LIMIT)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def symbol_kind(module_id)
|
|
76
|
+
case module_id.extname
|
|
77
|
+
when ".haml" then Constant::SymbolKind::CLASS
|
|
78
|
+
when ".css" then Constant::SymbolKind::FILE
|
|
79
|
+
else Constant::SymbolKind::MODULE
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def symbols_for_nodes(nodes, lines)
|
|
84
|
+
nodes.flat_map do |node|
|
|
85
|
+
case node.type
|
|
86
|
+
when :tag
|
|
87
|
+
[tag_symbol(node, lines)]
|
|
88
|
+
when :filter
|
|
89
|
+
(node.value[:name] == "ruby") ? ruby_filter_symbols(node, lines) : []
|
|
90
|
+
when :script, :silent_script
|
|
91
|
+
symbols_for_nodes(node.children, lines)
|
|
92
|
+
else
|
|
93
|
+
[]
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def tag_symbol(node, lines)
|
|
99
|
+
name = node.value.fetch(:name)
|
|
100
|
+
line_index = node.line - 1
|
|
101
|
+
component = name.match?(/\A[A-Z]/)
|
|
102
|
+
span = tag_span(lines[line_index].to_s, line_index, component ? COMPONENT_TAG : ELEMENT_TAG, name)
|
|
103
|
+
|
|
104
|
+
symbol(
|
|
105
|
+
"%#{name}",
|
|
106
|
+
component ? Constant::SymbolKind::CLASS : Constant::SymbolKind::FIELD,
|
|
107
|
+
Text::Span.new(line_index, 0, 0).with(line: line_index),
|
|
108
|
+
span,
|
|
109
|
+
range_end: last_line(node),
|
|
110
|
+
children: symbols_for_nodes(node.children, lines),
|
|
111
|
+
lines: lines
|
|
112
|
+
)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def ruby_filter_symbols(node, lines)
|
|
116
|
+
symbols = []
|
|
117
|
+
node.value.fetch(:text).to_s.each_line.with_index(node.line) do |text, line_index|
|
|
118
|
+
if (match = Languages::Imports::BINDING.match(text))
|
|
119
|
+
Text.each_match(lines[line_index].to_s, line_index, Languages::Imports::BINDING, group: :name) do |_match, span|
|
|
120
|
+
symbols << symbol(match[:name], Constant::SymbolKind::CONSTANT, Text.line_span(lines, line_index), span, detail: match[:specifier])
|
|
121
|
+
end
|
|
122
|
+
elsif (match = METHOD.match(text))
|
|
123
|
+
Text.each_match(lines[line_index].to_s, line_index, METHOD, group: :name) do |_match, span|
|
|
124
|
+
symbols << symbol(match[:name], Constant::SymbolKind::METHOD, Text.line_span(lines, line_index), span)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
symbols
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def tag_span(line_text, line_index, pattern, name)
|
|
132
|
+
Text.each_match(line_text, line_index, pattern, group: :name) do |match, span|
|
|
133
|
+
return span if match[:name] == name
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
Text.line_span([line_text], 0).with(line: line_index)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def last_line(node)
|
|
140
|
+
[node.line, *node.children.map { |child| last_line(child) }].max
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def symbol(name, kind, full_span, selection_span, detail: nil, range_end: nil, children: nil, lines: nil)
|
|
144
|
+
range =
|
|
145
|
+
if range_end
|
|
146
|
+
end_index = range_end - 1
|
|
147
|
+
Interface::Range.new(
|
|
148
|
+
start: Interface::Position.new(line: full_span.line, character: 0),
|
|
149
|
+
end: Interface::Position.new(line: end_index, character: lines[end_index].to_s.length)
|
|
150
|
+
)
|
|
151
|
+
else
|
|
152
|
+
full_span.to_range
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
Interface::DocumentSymbol.new(
|
|
156
|
+
name: name,
|
|
157
|
+
detail: detail,
|
|
158
|
+
kind: kind,
|
|
159
|
+
range: range,
|
|
160
|
+
selection_range: selection_span.to_range,
|
|
161
|
+
children: (children.nil? || children.empty?) ? nil : children
|
|
162
|
+
)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def fuzzy_match?(name, needle)
|
|
166
|
+
position = 0
|
|
167
|
+
needle.each_char do |char|
|
|
168
|
+
position = name.index(char, position)
|
|
169
|
+
return false unless position
|
|
170
|
+
|
|
171
|
+
position += 1
|
|
172
|
+
end
|
|
173
|
+
true
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "language_server-protocol"
|
|
4
|
+
|
|
5
|
+
module Klenod
|
|
6
|
+
module LSP
|
|
7
|
+
# Line and character arithmetic shared by every language handler.
|
|
8
|
+
#
|
|
9
|
+
# Klenod's parsers report lines but not columns, so character ranges are
|
|
10
|
+
# recovered by scanning the original line text. Characters are counted as
|
|
11
|
+
# Ruby characters, which matches LSP's UTF-16 encoding for every character
|
|
12
|
+
# in the Basic Multilingual Plane.
|
|
13
|
+
module Text
|
|
14
|
+
Interface = LanguageServer::Protocol::Interface
|
|
15
|
+
|
|
16
|
+
Position = Data.define(:line, :character)
|
|
17
|
+
|
|
18
|
+
Span = Data.define(:line, :start_character, :end_character) do
|
|
19
|
+
# Cursor positions directly after the last character count as inside,
|
|
20
|
+
# which is where an editor places the caret at the end of a word.
|
|
21
|
+
def include?(position)
|
|
22
|
+
position.line == line && position.character.between?(start_character, end_character)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_range
|
|
26
|
+
Interface::Range.new(
|
|
27
|
+
start: Interface::Position.new(line: line, character: start_character),
|
|
28
|
+
end: Interface::Position.new(line: line, character: end_character)
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
module_function
|
|
34
|
+
|
|
35
|
+
def each_match(line_text, line_index, regex, group:)
|
|
36
|
+
offset = 0
|
|
37
|
+
while (match = regex.match(line_text, offset))
|
|
38
|
+
start_character = match.begin(group)
|
|
39
|
+
end_character = match.end(group)
|
|
40
|
+
yield match, Span.new(line_index, start_character, end_character)
|
|
41
|
+
offset = [match.end(0), offset + 1].max
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def line_span(lines, line_index)
|
|
46
|
+
line_index = line_index.clamp(0, [lines.length - 1, 0].max)
|
|
47
|
+
Span.new(line_index, 0, lines[line_index]&.length || 0)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def zero_range
|
|
51
|
+
Span.new(0, 0, 0).to_range
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def protocol_character(line_text, character, encoding)
|
|
55
|
+
prefix = line_text.each_char.first(character).join
|
|
56
|
+
case encoding
|
|
57
|
+
when "utf-8" then prefix.bytesize
|
|
58
|
+
when "utf-16" then prefix.encode(Encoding::UTF_16LE).bytesize / 2
|
|
59
|
+
else character
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def ruby_character(line_text, character, encoding)
|
|
64
|
+
return character if encoding == "utf-32"
|
|
65
|
+
|
|
66
|
+
units = 0
|
|
67
|
+
line_text.each_char.with_index do |char, index|
|
|
68
|
+
width = (encoding == "utf-8") ? char.bytesize : char.encode(Encoding::UTF_16LE).bytesize / 2
|
|
69
|
+
return index if units + width > character
|
|
70
|
+
|
|
71
|
+
units += width
|
|
72
|
+
return index + 1 if units == character
|
|
73
|
+
end
|
|
74
|
+
line_text.length
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "prism"
|
|
4
|
+
|
|
5
|
+
require "klenod/build/context"
|
|
6
|
+
|
|
7
|
+
require_relative "analysis"
|
|
8
|
+
require_relative "routes"
|
|
9
|
+
|
|
10
|
+
module Klenod
|
|
11
|
+
module LSP
|
|
12
|
+
# Adapts a Klenod::Build::Context to editor documents.
|
|
13
|
+
#
|
|
14
|
+
# The workspace only transforms and resolves; it never collects records
|
|
15
|
+
# or evaluates application code. That keeps unsaved editor text out of
|
|
16
|
+
# the graph and keeps the server responsive without a file watcher.
|
|
17
|
+
class Workspace
|
|
18
|
+
IMPORT_KIND = :haml_import
|
|
19
|
+
|
|
20
|
+
attr_reader :context, :source_dir
|
|
21
|
+
|
|
22
|
+
def initialize(context:)
|
|
23
|
+
@context = context
|
|
24
|
+
@graph = context.graph
|
|
25
|
+
@source_dir = File.expand_path(@graph.source_dir.to_s)
|
|
26
|
+
@routes = Routes.new(self)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
attr_reader :routes
|
|
30
|
+
|
|
31
|
+
def path_for_uri(uri)
|
|
32
|
+
return nil unless uri.start_with?("file://")
|
|
33
|
+
|
|
34
|
+
path = uri.delete_prefix("file://").split("?", 2).first.to_s
|
|
35
|
+
path = path.sub(/\A[^\/]+/, "") unless path.start_with?("/")
|
|
36
|
+
percent_decode(path)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def uri_for_path(path)
|
|
40
|
+
"file://#{path.split("/", -1).map { |segment| percent_encode(segment) }.join("/")}"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def module_id_for_uri(uri)
|
|
44
|
+
path = path_for_uri(uri)
|
|
45
|
+
path && module_id_for_path(path)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def module_id_for_path(path)
|
|
49
|
+
return nil unless path.start_with?("#{source_dir}/")
|
|
50
|
+
|
|
51
|
+
Klenod::Build::ModuleId.new("app:/#{path.delete_prefix("#{source_dir}/")}")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# App modules map through the resolver; gem modules through the gem
|
|
55
|
+
# import plugin, which reports the file in its resolution metadata.
|
|
56
|
+
def path_for_module_id(module_id)
|
|
57
|
+
case module_id.scheme
|
|
58
|
+
when :app
|
|
59
|
+
@graph.absolute_path(module_id).to_s
|
|
60
|
+
when :gem
|
|
61
|
+
dependency = Klenod::Build::Dependency.create(specifier: module_id.to_s, importer_id: nil, kind: IMPORT_KIND)
|
|
62
|
+
@graph.resolve_dependency(dependency).metadata[:path]&.to_s
|
|
63
|
+
end
|
|
64
|
+
rescue Klenod::Build::ResolveError
|
|
65
|
+
nil
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def uri_for_module_id(module_id)
|
|
69
|
+
path = path_for_module_id(module_id)
|
|
70
|
+
path && uri_for_path(path)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# The Haml plugin's `variables` mapping, e.g. `{global: "@__props"}`.
|
|
74
|
+
# Empty when no Haml plugin is configured or it maps nothing.
|
|
75
|
+
def haml_variables
|
|
76
|
+
plugin = @graph.plugins.find { |candidate| candidate.is_a?(Klenod::Build::Plugins::HamlPlugin::Plugin) }
|
|
77
|
+
plugin&.variables || {}
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def analyze(module_id, source)
|
|
81
|
+
transform = @graph.transform_source(module_id, source)
|
|
82
|
+
resolved_dependencies, resolve_errors = resolve_dependencies(module_id, transform)
|
|
83
|
+
|
|
84
|
+
Analysis.new(
|
|
85
|
+
module_id: module_id,
|
|
86
|
+
source: source,
|
|
87
|
+
transform: transform,
|
|
88
|
+
resolved_dependencies: resolved_dependencies,
|
|
89
|
+
build_error: nil,
|
|
90
|
+
ruby_errors: ruby_errors_for(transform),
|
|
91
|
+
resolve_errors: resolve_errors
|
|
92
|
+
)
|
|
93
|
+
rescue Klenod::Build::Error => error
|
|
94
|
+
failed_analysis(module_id, source, error)
|
|
95
|
+
rescue => error
|
|
96
|
+
# Plugins can raise their parser's own errors on half-typed source,
|
|
97
|
+
# e.g. SyntaxTree on an unterminated import string. Report them
|
|
98
|
+
# rather than dropping the document's diagnostics.
|
|
99
|
+
failed_analysis(module_id, source, error)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def resolve(specifier, importer_id:, kind: IMPORT_KIND)
|
|
103
|
+
dependency = Klenod::Build::Dependency.create(specifier: specifier, importer_id: importer_id, kind: kind)
|
|
104
|
+
@graph.resolve_dependency(dependency).module_id
|
|
105
|
+
rescue Klenod::Build::ResolveError
|
|
106
|
+
nil
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
def failed_analysis(module_id, source, error)
|
|
112
|
+
Analysis.new(
|
|
113
|
+
module_id: module_id,
|
|
114
|
+
source: source,
|
|
115
|
+
transform: nil,
|
|
116
|
+
resolved_dependencies: [],
|
|
117
|
+
build_error: error,
|
|
118
|
+
ruby_errors: [],
|
|
119
|
+
resolve_errors: []
|
|
120
|
+
)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def resolve_dependencies(module_id, transform)
|
|
124
|
+
resolved = []
|
|
125
|
+
errors = []
|
|
126
|
+
|
|
127
|
+
transform.dependencies.each do |dependency|
|
|
128
|
+
resolved << @graph.resolve_dependency(dependency)
|
|
129
|
+
rescue Klenod::Build::ResolveError => error
|
|
130
|
+
errors << error.with_resolution_context(dependency: dependency, importer_id: module_id)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
[resolved, errors]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Ruby modules are checked against their original source by RubyPlugin,
|
|
137
|
+
# which reports better locations than the generated code would.
|
|
138
|
+
def ruby_errors_for(transform)
|
|
139
|
+
return [] if transform.code.nil?
|
|
140
|
+
|
|
141
|
+
Prism.parse(transform.code).errors.map do |error|
|
|
142
|
+
RubyError.new(message: error.message, generated_line: error.location.start_line)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def percent_decode(value)
|
|
147
|
+
value.gsub(/%[0-9A-Fa-f]{2}/) { |escaped| escaped[1..].hex.chr }.force_encoding(Encoding::UTF_8)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def percent_encode(segment)
|
|
151
|
+
segment.b.gsub(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]/) { |byte| format("%%%02X", byte.ord) }
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
data/lib/klenod/lsp.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: klenod-lsp
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.15
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Andrés Alin
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: klenod-build
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - '='
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: 0.0.15
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - '='
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: 0.0.15
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: language_server-protocol
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '3.17'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '3.17'
|
|
40
|
+
description: Editor diagnostics and navigation for Klenod Haml modules over the Language
|
|
41
|
+
Server Protocol.
|
|
42
|
+
email:
|
|
43
|
+
- andreas.alin@gmail.com
|
|
44
|
+
executables: []
|
|
45
|
+
extensions: []
|
|
46
|
+
extra_rdoc_files: []
|
|
47
|
+
files:
|
|
48
|
+
- README.md
|
|
49
|
+
- lib/klenod/lsp.rb
|
|
50
|
+
- lib/klenod/lsp/analysis.rb
|
|
51
|
+
- lib/klenod/lsp/cli.rb
|
|
52
|
+
- lib/klenod/lsp/diagnostics.rb
|
|
53
|
+
- lib/klenod/lsp/documents.rb
|
|
54
|
+
- lib/klenod/lsp/graph_index.rb
|
|
55
|
+
- lib/klenod/lsp/languages.rb
|
|
56
|
+
- lib/klenod/lsp/languages/css.rb
|
|
57
|
+
- lib/klenod/lsp/languages/haml.rb
|
|
58
|
+
- lib/klenod/lsp/languages/haml/classes.rb
|
|
59
|
+
- lib/klenod/lsp/languages/haml/completion.rb
|
|
60
|
+
- lib/klenod/lsp/languages/haml/props.rb
|
|
61
|
+
- lib/klenod/lsp/languages/haml/rename.rb
|
|
62
|
+
- lib/klenod/lsp/languages/haml/ruby_regions.rb
|
|
63
|
+
- lib/klenod/lsp/languages/imports.rb
|
|
64
|
+
- lib/klenod/lsp/languages/ruby.rb
|
|
65
|
+
- lib/klenod/lsp/languages/syntax.rb
|
|
66
|
+
- lib/klenod/lsp/renames.rb
|
|
67
|
+
- lib/klenod/lsp/routes.rb
|
|
68
|
+
- lib/klenod/lsp/server.rb
|
|
69
|
+
- lib/klenod/lsp/symbols.rb
|
|
70
|
+
- lib/klenod/lsp/text.rb
|
|
71
|
+
- lib/klenod/lsp/version.rb
|
|
72
|
+
- lib/klenod/lsp/workspace.rb
|
|
73
|
+
homepage: https://github.com/aalin/klenod
|
|
74
|
+
licenses:
|
|
75
|
+
- MIT
|
|
76
|
+
metadata:
|
|
77
|
+
homepage_uri: https://github.com/aalin/klenod
|
|
78
|
+
source_code_uri: https://github.com/aalin/klenod/tree/main/gems/klenod-lsp
|
|
79
|
+
rdoc_options: []
|
|
80
|
+
require_paths:
|
|
81
|
+
- lib
|
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
83
|
+
requirements:
|
|
84
|
+
- - ">="
|
|
85
|
+
- !ruby/object:Gem::Version
|
|
86
|
+
version: '4.0'
|
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
88
|
+
requirements:
|
|
89
|
+
- - ">="
|
|
90
|
+
- !ruby/object:Gem::Version
|
|
91
|
+
version: '0'
|
|
92
|
+
requirements: []
|
|
93
|
+
rubygems_version: 4.0.16
|
|
94
|
+
specification_version: 4
|
|
95
|
+
summary: Language server for Klenod applications.
|
|
96
|
+
test_files: []
|