ruby-lsp 0.2.2 → 0.2.3
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/CHANGELOG.md +4 -0
- data/VERSION +1 -1
- data/lib/ruby_lsp/requests/document_link.rb +77 -17
- data/lib/ruby_lsp/requests/support/source_uri.rb +82 -0
- data/lib/ruby_lsp/server.rb +3 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 96c21e90970f4cbf198609a42471cf554ce86a3b6af9296ded95994ad373317a
|
4
|
+
data.tar.gz: a28aa2c13ba4d79f53082160b0eca7e8461efad831b6c6cca2a6a4d34765a6c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ab1bf48ae4943a710f34ef0aace64c1d8991271bdca71482a2367c3a103299c52ebaef203fa32945236d689dda67d2bb1b5cc5ca9ffa698f5dd057dd62e242f
|
7
|
+
data.tar.gz: 8b9453d71b65634e1ea275f3a2552548f530dc144acd18cdcbcee493f153b824a13bc60bbbe5ac937a993d9e9c56ce8cb70773d354b5cea7acda3f4f44722ffd
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,10 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [0.2.3]
|
10
|
+
|
11
|
+
- Resolve generic source URIs for jump to gem source (https://github.com/Shopify/ruby-lsp/pull/237)
|
12
|
+
|
9
13
|
## [0.2.2]
|
10
14
|
|
11
15
|
- Support document links (https://github.com/Shopify/ruby-lsp/pull/195)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.3
|
@@ -1,30 +1,78 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "ruby_lsp/requests/support/source_uri"
|
5
|
+
|
4
6
|
module RubyLsp
|
5
7
|
module Requests
|
6
8
|
# 
|
7
9
|
#
|
8
10
|
# The [document link](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentLink)
|
9
|
-
# makes `# source://PATH_TO_FILE
|
11
|
+
# makes `# source://PATH_TO_FILE#line` comments in a Ruby/RBI file clickable if the file exists.
|
10
12
|
# When the user clicks the link, it'll open that location.
|
11
13
|
#
|
12
14
|
# # Example
|
13
15
|
#
|
14
16
|
# ```ruby
|
15
|
-
# # source://syntax_tree
|
17
|
+
# # source://syntax_tree/3.2.1/lib/syntax_tree.rb#51 <- it will be clickable and will take the user to that location
|
16
18
|
# def format(source, maxwidth = T.unsafe(nil))
|
17
19
|
# end
|
18
20
|
# ```
|
19
21
|
class DocumentLink < BaseRequest
|
20
22
|
extend T::Sig
|
21
23
|
|
22
|
-
|
24
|
+
GEM_TO_VERSION_MAP = T.let(
|
25
|
+
[*::Gem::Specification.default_stubs, *::Gem::Specification.stubs].map! do |s|
|
26
|
+
[s.name, s.version.to_s]
|
27
|
+
end.to_h.freeze,
|
28
|
+
T::Hash[String, String]
|
29
|
+
)
|
30
|
+
|
31
|
+
class << self
|
32
|
+
extend T::Sig
|
33
|
+
|
34
|
+
sig { returns(T::Hash[String, T::Array[String]]) }
|
35
|
+
def gem_paths
|
36
|
+
@gem_paths ||= T.let(begin
|
37
|
+
lookup = {}
|
38
|
+
|
39
|
+
Gem::Specification.stubs.each do |stub|
|
40
|
+
spec = stub.to_spec
|
41
|
+
lookup[spec.name] = {}
|
42
|
+
lookup[spec.name][spec.version.to_s] = {}
|
43
|
+
|
44
|
+
Dir.glob("**/*.rb", base: "#{spec.full_gem_path}/").each do |path|
|
45
|
+
lookup[spec.name][spec.version.to_s][path] = "#{spec.full_gem_path}/#{path}"
|
46
|
+
end
|
47
|
+
end
|
23
48
|
|
24
|
-
|
25
|
-
|
26
|
-
|
49
|
+
Gem::Specification.default_stubs.each do |stub|
|
50
|
+
spec = stub.to_spec
|
51
|
+
lookup[spec.name] = {}
|
52
|
+
lookup[spec.name][spec.version.to_s] = {}
|
53
|
+
prefix_matchers = [//]
|
54
|
+
prefix_matchers.concat(spec.require_paths.map { |rp| Regexp.new("^#{rp}/") })
|
55
|
+
prefix_matcher = Regexp.union(prefix_matchers)
|
56
|
+
|
57
|
+
spec.files.each do |file|
|
58
|
+
path = file.sub(prefix_matcher, "")
|
59
|
+
lookup[spec.name][spec.version.to_s][path] = "#{RbConfig::CONFIG["rubylibdir"]}/#{path}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
lookup
|
64
|
+
end, T.nilable(T::Hash[String, T::Array[String]]))
|
65
|
+
end
|
66
|
+
end
|
27
67
|
|
68
|
+
sig { params(uri: String, document: Document).void }
|
69
|
+
def initialize(uri, document)
|
70
|
+
super(document)
|
71
|
+
|
72
|
+
# Match the version based on the version in the RBI file name. Notice that the `@` symbol is sanitized to `%40`
|
73
|
+
# in the URI
|
74
|
+
version_match = /(?<=%40)[\d.]+(?=\.rbi$)/.match(uri)
|
75
|
+
@gem_version = T.let(version_match && version_match[0], T.nilable(String))
|
28
76
|
@links = T.let([], T::Array[LanguageServer::Protocol::Interface::DocumentLink])
|
29
77
|
end
|
30
78
|
|
@@ -36,24 +84,36 @@ module RubyLsp
|
|
36
84
|
|
37
85
|
sig { params(node: SyntaxTree::Comment).void }
|
38
86
|
def visit_comment(node)
|
39
|
-
match = node.value.match(%r{source
|
87
|
+
match = node.value.match(%r{source://.*#\d+$})
|
40
88
|
return unless match
|
41
89
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
return unless File.exist?(file_path)
|
48
|
-
|
49
|
-
target = "file://#{file_path}##{match[:line]}"
|
90
|
+
uri = T.cast(URI(match[0]), URI::Source)
|
91
|
+
gem_version = resolve_version(uri)
|
92
|
+
file_path = self.class.gem_paths.dig(uri.gem_name, gem_version, uri.path)
|
93
|
+
return if file_path.nil?
|
50
94
|
|
51
95
|
@links << LanguageServer::Protocol::Interface::DocumentLink.new(
|
52
96
|
range: range_from_syntax_tree_node(node),
|
53
|
-
target:
|
54
|
-
tooltip: "Jump to #{
|
97
|
+
target: "file://#{file_path}##{uri.line_number}",
|
98
|
+
tooltip: "Jump to #{file_path}##{uri.line_number}"
|
55
99
|
)
|
56
100
|
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
# Try to figure out the gem version for a source:// link. The order of precedence is:
|
105
|
+
# 1. The version in the URI
|
106
|
+
# 2. The version in the RBI file name
|
107
|
+
# 3. The version from the gemspec
|
108
|
+
sig { params(uri: URI::Source).returns(T.nilable(String)) }
|
109
|
+
def resolve_version(uri)
|
110
|
+
version = uri.gem_version
|
111
|
+
return version unless version.nil? || version.empty?
|
112
|
+
|
113
|
+
return @gem_version unless @gem_version.nil? || @gem_version.empty?
|
114
|
+
|
115
|
+
GEM_TO_VERSION_MAP[uri.gem_name]
|
116
|
+
end
|
57
117
|
end
|
58
118
|
end
|
59
119
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "uri/file"
|
5
|
+
|
6
|
+
module URI
|
7
|
+
# Must be kept in sync with the one in Tapioca
|
8
|
+
class Source < URI::File
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
COMPONENT = T.let([
|
12
|
+
:scheme,
|
13
|
+
:gem_name,
|
14
|
+
:gem_version,
|
15
|
+
:path,
|
16
|
+
:line_number,
|
17
|
+
].freeze, T::Array[Symbol])
|
18
|
+
|
19
|
+
T.unsafe(self).alias_method(:gem_name, :host)
|
20
|
+
T.unsafe(self).alias_method(:line_number, :fragment)
|
21
|
+
|
22
|
+
sig { returns(T.nilable(String)) }
|
23
|
+
attr_reader :gem_version
|
24
|
+
|
25
|
+
class << self
|
26
|
+
extend T::Sig
|
27
|
+
|
28
|
+
sig do
|
29
|
+
params(
|
30
|
+
gem_name: String,
|
31
|
+
gem_version: T.nilable(String),
|
32
|
+
path: String,
|
33
|
+
line_number: T.nilable(String)
|
34
|
+
).returns(URI::Source)
|
35
|
+
end
|
36
|
+
def build(gem_name:, gem_version:, path:, line_number:)
|
37
|
+
super(
|
38
|
+
{
|
39
|
+
scheme: "source",
|
40
|
+
host: gem_name,
|
41
|
+
path: DEFAULT_PARSER.escape("/#{gem_version}/#{path}"),
|
42
|
+
fragment: line_number,
|
43
|
+
}
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
sig { params(v: T.nilable(String)).void }
|
49
|
+
def set_path(v) # rubocop:disable Naming/AccessorMethodName
|
50
|
+
return if v.nil?
|
51
|
+
|
52
|
+
gem_version, path = v.delete_prefix("/").split("/", 2)
|
53
|
+
|
54
|
+
@gem_version = T.let(gem_version, T.nilable(String))
|
55
|
+
@path = T.let(path, T.nilable(String))
|
56
|
+
end
|
57
|
+
|
58
|
+
sig { params(v: T.nilable(String)).returns(T::Boolean) }
|
59
|
+
def check_host(v)
|
60
|
+
return true unless v
|
61
|
+
|
62
|
+
if /[A-Za-z][A-Za-z0-9\-_]*/ !~ v
|
63
|
+
raise InvalidComponentError,
|
64
|
+
"bad component(expected gem name): #{v}"
|
65
|
+
end
|
66
|
+
|
67
|
+
true
|
68
|
+
end
|
69
|
+
|
70
|
+
sig { returns(String) }
|
71
|
+
def to_s
|
72
|
+
"source://#{gem_name}/#{gem_version}#{path}##{line_number}"
|
73
|
+
end
|
74
|
+
|
75
|
+
if URI.respond_to?(:register_scheme)
|
76
|
+
URI.register_scheme("SOURCE", self)
|
77
|
+
else
|
78
|
+
@@schemes = T.let(@@schemes, T::Hash[String, Class]) # rubocop:disable Style/ClassVars
|
79
|
+
@@schemes["SOURCE"] = self
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/ruby_lsp/server.rb
CHANGED
@@ -98,8 +98,9 @@ module RubyLsp
|
|
98
98
|
end
|
99
99
|
|
100
100
|
on("textDocument/documentLink") do |request|
|
101
|
-
|
102
|
-
|
101
|
+
uri = request.dig(:params, :textDocument, :uri)
|
102
|
+
store.cache_fetch(uri, :document_link) do |document|
|
103
|
+
RubyLsp::Requests::DocumentLink.new(uri, document).run
|
103
104
|
end
|
104
105
|
end
|
105
106
|
|
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.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-08-
|
11
|
+
date: 2022-08-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: language_server-protocol
|
@@ -86,6 +86,7 @@ files:
|
|
86
86
|
- lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb
|
87
87
|
- lib/ruby_lsp/requests/support/selection_range.rb
|
88
88
|
- lib/ruby_lsp/requests/support/semantic_token_encoder.rb
|
89
|
+
- lib/ruby_lsp/requests/support/source_uri.rb
|
89
90
|
- lib/ruby_lsp/requests/support/syntax_error_diagnostic.rb
|
90
91
|
- lib/ruby_lsp/server.rb
|
91
92
|
- lib/ruby_lsp/store.rb
|