rubydex 0.2.4-aarch64-linux → 0.2.5-aarch64-linux
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/exe/rubydex_mcp +17 -0
- data/ext/rubydex/definition.c +56 -0
- data/ext/rubydex/extconf.rb +8 -0
- data/lib/rubydex/3.2/rubydex.so +0 -0
- data/lib/rubydex/3.3/rubydex.so +0 -0
- data/lib/rubydex/3.4/rubydex.so +0 -0
- data/lib/rubydex/4.0/rubydex.so +0 -0
- data/lib/rubydex/bin/rubydex_mcp +0 -0
- data/lib/rubydex/declaration.rb +3 -3
- data/lib/rubydex/graph.rb +3 -1
- data/lib/rubydex/librubydex_sys.so +0 -0
- data/lib/rubydex/version.rb +1 -1
- data/rbi/rubydex.rbi +8 -2
- data/rust/rubydex/src/indexing/local_graph.rs +38 -0
- data/rust/rubydex/src/indexing/ruby_indexer.rs +6 -0
- data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +5 -1
- data/rust/rubydex/src/indexing.rs +38 -12
- data/rust/rubydex/src/lib.rs +1 -0
- data/rust/rubydex/src/listing.rs +14 -3
- data/rust/rubydex/src/main.rs +27 -2
- data/rust/rubydex/src/model/definitions.rs +7 -18
- data/rust/rubydex/src/model/ids.rs +27 -1
- data/rust/rubydex/src/operation/applier.rs +519 -0
- data/rust/rubydex/src/operation/mod.rs +284 -0
- data/rust/rubydex/src/operation/printer.rs +260 -0
- data/rust/rubydex/src/operation/ruby_builder.rs +2915 -0
- data/rust/rubydex/src/resolution.rs +6 -1
- data/rust/rubydex/src/resolution_tests.rs +217 -209
- data/rust/rubydex/src/test_utils/graph_test.rs +19 -4
- data/rust/rubydex/src/test_utils/local_graph_test.rs +7 -6
- data/rust/rubydex-mcp/src/server.rs +5 -1
- data/rust/rubydex-sys/src/definition_api.rs +24 -0
- data/rust/rubydex-sys/src/graph_api.rs +1 -1
- metadata +9 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 96c428371246628899d384b7e650919ee41c9eaa42413af5244175c9972fb44b
|
|
4
|
+
data.tar.gz: 702b06d961ffdd5da12dcb7eb074f83b4d2bc30d3e06bc29a4749a39d0501d58
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d9aed2a16df08353c7b66d1dbfb652746f2241c4c6782fb714d89c4ae9b64487e552c5f0b418bfd36b6d01a1477f2cc445e8be68ce0083501edad77220f9b8f8
|
|
7
|
+
data.tar.gz: c6f95989ccb6da1bed31659e052f5b83ac8b2870c24d2ca59ac10003b60dc199cba778e0f67188f58389f6dd7fddae295ded50b3ad1f9e4fbb2b720526a2ccd9
|
data/exe/rubydex_mcp
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "rbconfig"
|
|
5
|
+
|
|
6
|
+
host_os = RbConfig::CONFIG.fetch("host_os")
|
|
7
|
+
executable = host_os.match?(/mswin|mingw|cygwin/) ? "rubydex_mcp.exe" : "rubydex_mcp"
|
|
8
|
+
binary = File.expand_path("../lib/rubydex/bin/#{executable}", __dir__)
|
|
9
|
+
|
|
10
|
+
unless File.executable?(binary)
|
|
11
|
+
abort(<<~MESSAGE.chomp)
|
|
12
|
+
rubydex_mcp is not available at #{binary}.
|
|
13
|
+
Install a precompiled rubydex gem, or reinstall rubydex with Cargo available so the MCP executable can be built locally.
|
|
14
|
+
MESSAGE
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
exec(binary, *ARGV)
|
data/ext/rubydex/definition.c
CHANGED
|
@@ -195,6 +195,60 @@ static VALUE rdxr_definition_declaration(VALUE self) {
|
|
|
195
195
|
return rb_class_new_instance(2, argv, decl_class);
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
+
static VALUE rdxi_build_definition(VALUE graph_obj, void *graph, uint64_t definition_id) {
|
|
199
|
+
DefinitionKind kind = rdx_definition_kind(graph, definition_id);
|
|
200
|
+
VALUE defn_class = rdxi_definition_class_for_kind(kind);
|
|
201
|
+
VALUE argv[] = {graph_obj, ULL2NUM(definition_id)};
|
|
202
|
+
|
|
203
|
+
return rb_class_new_instance(2, argv, defn_class);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Definition#lexical_owner -> Rubydex::Definition?
|
|
207
|
+
// Returns the lexically enclosing definition, if any.
|
|
208
|
+
static VALUE rdxr_definition_lexical_owner(VALUE self) {
|
|
209
|
+
HandleData *data;
|
|
210
|
+
TypedData_Get_Struct(self, HandleData, &handle_type, data);
|
|
211
|
+
|
|
212
|
+
void *graph;
|
|
213
|
+
TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
|
|
214
|
+
|
|
215
|
+
const uint64_t *owner_id = rdx_definition_lexical_nesting_id(graph, data->id);
|
|
216
|
+
if (owner_id == NULL) {
|
|
217
|
+
return Qnil;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
VALUE owner = rdxi_build_definition(data->graph_obj, graph, *owner_id);
|
|
221
|
+
free_u64(owner_id);
|
|
222
|
+
|
|
223
|
+
return owner;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Definition#lexical_nesting -> Array<Rubydex::Definition>
|
|
227
|
+
// Returns the lexical nesting from the direct owner up to the root.
|
|
228
|
+
static VALUE rdxr_definition_lexical_nesting(VALUE self) {
|
|
229
|
+
HandleData *data;
|
|
230
|
+
TypedData_Get_Struct(self, HandleData, &handle_type, data);
|
|
231
|
+
|
|
232
|
+
void *graph;
|
|
233
|
+
TypedData_Get_Struct(data->graph_obj, void *, &graph_type, graph);
|
|
234
|
+
|
|
235
|
+
VALUE nesting = rb_ary_new();
|
|
236
|
+
uint64_t definition_id = data->id;
|
|
237
|
+
|
|
238
|
+
while (true) {
|
|
239
|
+
const uint64_t *owner_id = rdx_definition_lexical_nesting_id(graph, definition_id);
|
|
240
|
+
if (owner_id == NULL) {
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
rb_ary_push(nesting, rdxi_build_definition(data->graph_obj, graph, *owner_id));
|
|
245
|
+
definition_id = *owner_id;
|
|
246
|
+
free_u64(owner_id);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return nesting;
|
|
250
|
+
}
|
|
251
|
+
|
|
198
252
|
static VALUE rdxi_build_constant_reference(VALUE graph_obj, const CConstantReference *cref) {
|
|
199
253
|
VALUE ref_class = (cref->declaration_id == 0)
|
|
200
254
|
? cUnresolvedConstantReference
|
|
@@ -306,6 +360,8 @@ void rdxi_initialize_definition(VALUE mod) {
|
|
|
306
360
|
rb_define_method(cDefinition, "deprecated?", rdxr_definition_deprecated, 0);
|
|
307
361
|
rb_define_method(cDefinition, "name_location", rdxr_definition_name_location, 0);
|
|
308
362
|
rb_define_method(cDefinition, "declaration", rdxr_definition_declaration, 0);
|
|
363
|
+
rb_define_method(cDefinition, "lexical_owner", rdxr_definition_lexical_owner, 0);
|
|
364
|
+
rb_define_method(cDefinition, "lexical_nesting", rdxr_definition_lexical_nesting, 0);
|
|
309
365
|
|
|
310
366
|
cClassDefinition = rb_define_class_under(mRubydex, "ClassDefinition", cDefinition);
|
|
311
367
|
rb_define_method(cClassDefinition, "superclass", rdxr_class_definition_superclass, 0);
|
data/ext/rubydex/extconf.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "mkmf"
|
|
4
|
+
require "fileutils"
|
|
4
5
|
require "pathname"
|
|
5
6
|
|
|
6
7
|
unless system("cargo", "--version", out: File::NULL, err: File::NULL)
|
|
@@ -81,6 +82,12 @@ else
|
|
|
81
82
|
end
|
|
82
83
|
|
|
83
84
|
lib_dir = gem_dir.join("lib").join("rubydex")
|
|
85
|
+
mcp_bin_dir = lib_dir.join("bin")
|
|
86
|
+
FileUtils.mkdir_p(mcp_bin_dir)
|
|
87
|
+
|
|
88
|
+
mcp_executable = Gem.win_platform? ? "rubydex_mcp.exe" : "rubydex_mcp"
|
|
89
|
+
mcp_src = target_dir.join(mcp_executable)
|
|
90
|
+
mcp_dst = mcp_bin_dir.join(mcp_executable)
|
|
84
91
|
|
|
85
92
|
copy_dylib_commands = if Gem.win_platform?
|
|
86
93
|
""
|
|
@@ -107,6 +114,7 @@ new_makefile = makefile.gsub("$(OBJS): $(HDRS) $(ruby_headers)", <<~MAKEFILE.cho
|
|
|
107
114
|
.rust_built: $(RUST_SRCS)
|
|
108
115
|
\t#{cargo_command} || (echo "Compiling Rust failed" && exit 1)
|
|
109
116
|
\t$(COPY) #{bindings_path} #{__dir__}
|
|
117
|
+
\t$(COPY) #{mcp_src} #{mcp_dst}
|
|
110
118
|
\ttouch $@
|
|
111
119
|
|
|
112
120
|
compile_rust: .rust_built
|
data/lib/rubydex/3.2/rubydex.so
CHANGED
|
Binary file
|
data/lib/rubydex/3.3/rubydex.so
CHANGED
|
Binary file
|
data/lib/rubydex/3.4/rubydex.so
CHANGED
|
Binary file
|
data/lib/rubydex/4.0/rubydex.so
CHANGED
|
Binary file
|
|
Binary file
|
data/lib/rubydex/declaration.rb
CHANGED
|
@@ -21,9 +21,9 @@ module Rubydex
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
class Namespace < Declaration
|
|
24
|
-
#: (String
|
|
25
|
-
def has_ancestor?(
|
|
26
|
-
ancestors.any? { |ancestor| ancestor.name
|
|
24
|
+
#: (*String ancestor_names) -> bool
|
|
25
|
+
def has_ancestor?(*ancestor_names)
|
|
26
|
+
ancestors.any? { |ancestor| ancestor_names.include?(ancestor.name) }
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
data/lib/rubydex/graph.rb
CHANGED
|
@@ -17,6 +17,8 @@ module Rubydex
|
|
|
17
17
|
"tmp",
|
|
18
18
|
].freeze
|
|
19
19
|
|
|
20
|
+
INDEXABLE_EXTENSIONS = [".rb", ".rake", ".rbs", ".ru"].freeze
|
|
21
|
+
|
|
20
22
|
#: String
|
|
21
23
|
attr_accessor :workspace_path
|
|
22
24
|
|
|
@@ -45,7 +47,7 @@ module Rubydex
|
|
|
45
47
|
|
|
46
48
|
if File.directory?(full_path)
|
|
47
49
|
paths << full_path unless IGNORED_DIRECTORIES.include?(entry)
|
|
48
|
-
elsif File.extname(entry)
|
|
50
|
+
elsif INDEXABLE_EXTENSIONS.include?(File.extname(entry))
|
|
49
51
|
paths << full_path
|
|
50
52
|
end
|
|
51
53
|
end
|
|
Binary file
|
data/lib/rubydex/version.rb
CHANGED
data/rbi/rubydex.rbi
CHANGED
|
@@ -104,8 +104,8 @@ class Rubydex::Namespace < Rubydex::Declaration
|
|
|
104
104
|
sig { returns(T::Enumerable[Rubydex::Namespace]) }
|
|
105
105
|
def ancestors; end
|
|
106
106
|
|
|
107
|
-
sig { params(
|
|
108
|
-
def has_ancestor?(
|
|
107
|
+
sig { params(ancestor_names: String).returns(T::Boolean) }
|
|
108
|
+
def has_ancestor?(*ancestor_names); end
|
|
109
109
|
|
|
110
110
|
sig { returns(T::Enumerable[Rubydex::Namespace]) }
|
|
111
111
|
def descendants; end
|
|
@@ -152,6 +152,12 @@ class Rubydex::Definition
|
|
|
152
152
|
sig { returns(T.nilable(Rubydex::Declaration)) }
|
|
153
153
|
def declaration; end
|
|
154
154
|
|
|
155
|
+
sig { returns(T.nilable(Rubydex::Definition)) }
|
|
156
|
+
def lexical_owner; end
|
|
157
|
+
|
|
158
|
+
sig { returns(T::Array[Rubydex::Definition]) }
|
|
159
|
+
def lexical_nesting; end
|
|
160
|
+
|
|
155
161
|
class << self
|
|
156
162
|
private
|
|
157
163
|
|
|
@@ -206,6 +206,44 @@ impl LocalGraph {
|
|
|
206
206
|
&self.name_dependents
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
/// Creates a `LocalGraph` from pre-built parts (used by the operation applier pipeline).
|
|
210
|
+
#[must_use]
|
|
211
|
+
pub fn from_parts(
|
|
212
|
+
uri_id: UriId,
|
|
213
|
+
document: Document,
|
|
214
|
+
strings: IdentityHashMap<StringId, StringRef>,
|
|
215
|
+
names: IdentityHashMap<NameId, NameRef>,
|
|
216
|
+
) -> Self {
|
|
217
|
+
let mut name_dependents: IdentityHashMap<NameId, Vec<NameDependent>> = IdentityHashMap::default();
|
|
218
|
+
for (name_id, name_ref) in &names {
|
|
219
|
+
if let NameRef::Unresolved(name) = name_ref {
|
|
220
|
+
if let Some(&parent_scope) = name.parent_scope().as_ref() {
|
|
221
|
+
name_dependents
|
|
222
|
+
.entry(parent_scope)
|
|
223
|
+
.or_default()
|
|
224
|
+
.push(NameDependent::ChildName(*name_id));
|
|
225
|
+
}
|
|
226
|
+
if let Some(&nesting_id) = name.nesting().as_ref() {
|
|
227
|
+
name_dependents
|
|
228
|
+
.entry(nesting_id)
|
|
229
|
+
.or_default()
|
|
230
|
+
.push(NameDependent::NestedName(*name_id));
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
Self {
|
|
236
|
+
uri_id,
|
|
237
|
+
document,
|
|
238
|
+
definitions: IdentityHashMap::default(),
|
|
239
|
+
strings,
|
|
240
|
+
names,
|
|
241
|
+
constant_references: IdentityHashMap::default(),
|
|
242
|
+
method_references: IdentityHashMap::default(),
|
|
243
|
+
name_dependents,
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
209
247
|
// Into parts
|
|
210
248
|
|
|
211
249
|
#[must_use]
|
|
@@ -2481,5 +2481,11 @@ impl Visit<'_> for RubyIndexer<'_> {
|
|
|
2481
2481
|
}
|
|
2482
2482
|
|
|
2483
2483
|
#[cfg(test)]
|
|
2484
|
+
fn backend() -> super::IndexerBackend {
|
|
2485
|
+
super::IndexerBackend::RubyIndexer
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2488
|
+
#[cfg(test)]
|
|
2489
|
+
#[allow(clippy::duplicate_mod)]
|
|
2484
2490
|
#[path = "ruby_indexer_tests.rs"]
|
|
2485
2491
|
mod tests;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// This file is included via #[path] by both ruby_indexer.rs and operation/applier.rs
|
|
2
|
+
// to run the same tests against both indexing backends. Each parent module provides
|
|
3
|
+
// a `backend()` function that `index_source` calls via `super::backend()`.
|
|
4
|
+
|
|
1
5
|
use crate::{
|
|
2
6
|
assert_def_comments_eq, assert_def_mixins_eq, assert_def_name_eq, assert_def_name_offset_eq, assert_def_str_eq,
|
|
3
7
|
assert_def_superclass_ref_eq, assert_definition_at, assert_dependents, assert_local_diagnostics_eq,
|
|
@@ -86,7 +90,7 @@ macro_rules! assert_method_references_eq {
|
|
|
86
90
|
}
|
|
87
91
|
|
|
88
92
|
fn index_source(source: &str) -> LocalGraphTest {
|
|
89
|
-
LocalGraphTest::
|
|
93
|
+
LocalGraphTest::new_with_backend("file:///foo.rb", source, super::backend())
|
|
90
94
|
}
|
|
91
95
|
|
|
92
96
|
mod constant_tests {
|
|
@@ -3,6 +3,7 @@ use crate::{
|
|
|
3
3
|
indexing::{local_graph::LocalGraph, rbs_indexer::RBSIndexer, ruby_indexer::RubyIndexer},
|
|
4
4
|
job_queue::{Job, JobQueue},
|
|
5
5
|
model::graph::Graph,
|
|
6
|
+
operation::ruby_builder::RubyOperationBuilder,
|
|
6
7
|
};
|
|
7
8
|
use crossbeam_channel::{Sender, unbounded};
|
|
8
9
|
use std::{ffi::OsStr, fs, path::PathBuf, sync::Arc};
|
|
@@ -12,6 +13,15 @@ pub mod local_graph;
|
|
|
12
13
|
pub mod rbs_indexer;
|
|
13
14
|
pub mod ruby_indexer;
|
|
14
15
|
|
|
16
|
+
/// Which backend to use for indexing Ruby files.
|
|
17
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
18
|
+
pub enum IndexerBackend {
|
|
19
|
+
/// The original tree-walking indexer.
|
|
20
|
+
RubyIndexer,
|
|
21
|
+
/// The two-phase operation builder + applier pipeline.
|
|
22
|
+
OperationBuilder,
|
|
23
|
+
}
|
|
24
|
+
|
|
15
25
|
/// The language of a source document, used to dispatch to the appropriate indexer
|
|
16
26
|
pub enum LanguageId {
|
|
17
27
|
Ruby,
|
|
@@ -42,15 +52,22 @@ impl LanguageId {
|
|
|
42
52
|
/// Job that indexes a single file
|
|
43
53
|
pub struct IndexingJob {
|
|
44
54
|
path: PathBuf,
|
|
55
|
+
backend: IndexerBackend,
|
|
45
56
|
local_graph_tx: Sender<LocalGraph>,
|
|
46
57
|
errors_tx: Sender<Errors>,
|
|
47
58
|
}
|
|
48
59
|
|
|
49
60
|
impl IndexingJob {
|
|
50
61
|
#[must_use]
|
|
51
|
-
pub fn new(
|
|
62
|
+
pub fn new(
|
|
63
|
+
path: PathBuf,
|
|
64
|
+
backend: IndexerBackend,
|
|
65
|
+
local_graph_tx: Sender<LocalGraph>,
|
|
66
|
+
errors_tx: Sender<Errors>,
|
|
67
|
+
) -> Self {
|
|
52
68
|
Self {
|
|
53
69
|
path,
|
|
70
|
+
backend,
|
|
54
71
|
local_graph_tx,
|
|
55
72
|
errors_tx,
|
|
56
73
|
}
|
|
@@ -84,7 +101,7 @@ impl Job for IndexingJob {
|
|
|
84
101
|
};
|
|
85
102
|
|
|
86
103
|
let language = self.path.extension().map_or(LanguageId::Ruby, LanguageId::from);
|
|
87
|
-
let local_graph = build_local_graph(url.to_string(), &source, &language);
|
|
104
|
+
let local_graph = build_local_graph(url.to_string(), &source, &language, self.backend);
|
|
88
105
|
|
|
89
106
|
self.local_graph_tx
|
|
90
107
|
.send(local_graph)
|
|
@@ -94,7 +111,7 @@ impl Job for IndexingJob {
|
|
|
94
111
|
|
|
95
112
|
/// Indexes a single source string in memory, dispatching to the appropriate indexer based on `language_id`.
|
|
96
113
|
pub fn index_source(graph: &mut Graph, uri: &str, source: &str, language_id: &LanguageId) {
|
|
97
|
-
let local_graph = build_local_graph(uri.to_string(), source, language_id);
|
|
114
|
+
let local_graph = build_local_graph(uri.to_string(), source, language_id, IndexerBackend::RubyIndexer);
|
|
98
115
|
graph.consume_document_changes(local_graph);
|
|
99
116
|
}
|
|
100
117
|
|
|
@@ -103,7 +120,7 @@ pub fn index_source(graph: &mut Graph, uri: &str, source: &str, language_id: &La
|
|
|
103
120
|
/// # Panics
|
|
104
121
|
///
|
|
105
122
|
/// Will panic if the graph cannot be wrapped in an Arc<Mutex<>>
|
|
106
|
-
pub fn index_files(graph: &mut Graph, paths: Vec<PathBuf
|
|
123
|
+
pub fn index_files(graph: &mut Graph, paths: Vec<PathBuf>, backend: IndexerBackend) -> Vec<Errors> {
|
|
107
124
|
let queue = Arc::new(JobQueue::new());
|
|
108
125
|
let (local_graphs_tx, local_graphs_rx) = unbounded();
|
|
109
126
|
let (errors_tx, errors_rx) = unbounded();
|
|
@@ -111,6 +128,7 @@ pub fn index_files(graph: &mut Graph, paths: Vec<PathBuf>) -> Vec<Errors> {
|
|
|
111
128
|
for path in paths {
|
|
112
129
|
queue.push(Box::new(IndexingJob::new(
|
|
113
130
|
path,
|
|
131
|
+
backend,
|
|
114
132
|
local_graphs_tx.clone(),
|
|
115
133
|
errors_tx.clone(),
|
|
116
134
|
)));
|
|
@@ -134,13 +152,21 @@ pub fn index_files(graph: &mut Graph, paths: Vec<PathBuf>) -> Vec<Errors> {
|
|
|
134
152
|
}
|
|
135
153
|
|
|
136
154
|
/// Indexes a source string using the appropriate indexer for the given language.
|
|
137
|
-
|
|
155
|
+
#[must_use]
|
|
156
|
+
pub fn build_local_graph(uri: String, source: &str, language: &LanguageId, backend: IndexerBackend) -> LocalGraph {
|
|
138
157
|
match language {
|
|
139
|
-
LanguageId::Ruby => {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
158
|
+
LanguageId::Ruby => match backend {
|
|
159
|
+
IndexerBackend::RubyIndexer => {
|
|
160
|
+
let mut indexer = RubyIndexer::new(uri, source);
|
|
161
|
+
indexer.index();
|
|
162
|
+
indexer.local_graph()
|
|
163
|
+
}
|
|
164
|
+
IndexerBackend::OperationBuilder => {
|
|
165
|
+
let builder = RubyOperationBuilder::new(uri, source);
|
|
166
|
+
let result = builder.build();
|
|
167
|
+
crate::operation::applier::apply_operations(result)
|
|
168
|
+
}
|
|
169
|
+
},
|
|
144
170
|
LanguageId::Rbs => {
|
|
145
171
|
let mut indexer = RBSIndexer::new(uri, source);
|
|
146
172
|
indexer.index();
|
|
@@ -175,7 +201,7 @@ mod tests {
|
|
|
175
201
|
let relative_to_pwd = &dots.join(absolute_path);
|
|
176
202
|
|
|
177
203
|
let mut graph = Graph::new();
|
|
178
|
-
let errors = index_files(&mut graph, vec![relative_to_pwd.clone()]);
|
|
204
|
+
let errors = index_files(&mut graph, vec![relative_to_pwd.clone()], IndexerBackend::RubyIndexer);
|
|
179
205
|
|
|
180
206
|
assert!(errors.is_empty());
|
|
181
207
|
assert_eq!(graph.documents().len(), 2);
|
|
@@ -196,7 +222,7 @@ mod tests {
|
|
|
196
222
|
let uri = Url::from_file_path(&path).unwrap().to_string();
|
|
197
223
|
|
|
198
224
|
let mut graph = Graph::new();
|
|
199
|
-
let errors = index_files(&mut graph, vec![path]);
|
|
225
|
+
let errors = index_files(&mut graph, vec![path], IndexerBackend::RubyIndexer);
|
|
200
226
|
|
|
201
227
|
assert!(errors.is_empty(), "Expected no errors, got: {errors:#?}");
|
|
202
228
|
assert_eq!(6, graph.definitions().len());
|
data/rust/rubydex/src/lib.rs
CHANGED
data/rust/rubydex/src/listing.rs
CHANGED
|
@@ -38,9 +38,14 @@ impl FileDiscoveryJob {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
fn is_indexable_file(path: &Path) -> bool {
|
|
42
|
+
path.extension()
|
|
43
|
+
.is_some_and(|ext| ext == "rb" || ext == "rake" || ext == "rbs" || ext == "ru")
|
|
44
|
+
}
|
|
45
|
+
|
|
41
46
|
impl FileDiscoveryJob {
|
|
42
47
|
fn handle_file(&self, path: &Path) {
|
|
43
|
-
if path
|
|
48
|
+
if is_indexable_file(path) {
|
|
44
49
|
self.paths_tx
|
|
45
50
|
.send(path.to_path_buf())
|
|
46
51
|
.expect("file receiver dropped before run completion");
|
|
@@ -266,22 +271,28 @@ mod tests {
|
|
|
266
271
|
}
|
|
267
272
|
|
|
268
273
|
#[test]
|
|
269
|
-
fn
|
|
274
|
+
fn collect_indexable_files() {
|
|
270
275
|
let context = Context::new();
|
|
271
276
|
let ruby_file = PathBuf::from("lib").join("foo.rb");
|
|
277
|
+
let rake_file = PathBuf::from("lib").join("task.rake");
|
|
272
278
|
let rbs_file = PathBuf::from("sig").join("foo.rbs");
|
|
279
|
+
let rack_file = PathBuf::from("config.ru");
|
|
273
280
|
let txt_file = PathBuf::from("lib").join("notes.txt");
|
|
274
281
|
context.touch(&ruby_file);
|
|
282
|
+
context.touch(&rake_file);
|
|
275
283
|
context.touch(&rbs_file);
|
|
284
|
+
context.touch(&rack_file);
|
|
276
285
|
context.touch(&txt_file);
|
|
277
286
|
|
|
278
|
-
let (files, errors) = collect_document_paths(&context, &["lib", "sig"]);
|
|
287
|
+
let (files, errors) = collect_document_paths(&context, &["lib", "sig", "config.ru"]);
|
|
279
288
|
|
|
280
289
|
assert!(errors.is_empty());
|
|
281
290
|
|
|
282
291
|
assert_eq!(
|
|
283
292
|
[
|
|
293
|
+
rack_file.to_str().unwrap().to_string(),
|
|
284
294
|
ruby_file.to_str().unwrap().to_string(),
|
|
295
|
+
rake_file.to_str().unwrap().to_string(),
|
|
285
296
|
rbs_file.to_str().unwrap().to_string(),
|
|
286
297
|
],
|
|
287
298
|
files.as_slice()
|
data/rust/rubydex/src/main.rs
CHANGED
|
@@ -2,7 +2,8 @@ use clap::{Parser, ValueEnum};
|
|
|
2
2
|
use std::{collections::HashSet, mem};
|
|
3
3
|
|
|
4
4
|
use rubydex::{
|
|
5
|
-
indexing,
|
|
5
|
+
indexing::{self, IndexerBackend},
|
|
6
|
+
integrity, listing,
|
|
6
7
|
model::graph::Graph,
|
|
7
8
|
resolution::Resolver,
|
|
8
9
|
stats::{
|
|
@@ -31,6 +32,14 @@ struct Args {
|
|
|
31
32
|
#[arg(long = "check-integrity", help = "Check the integrity of the graph after resolution")]
|
|
32
33
|
check_integrity: bool,
|
|
33
34
|
|
|
35
|
+
#[arg(
|
|
36
|
+
long = "indexer",
|
|
37
|
+
value_enum,
|
|
38
|
+
default_value = "ruby-indexer",
|
|
39
|
+
help = "Which indexer backend to use for Ruby files"
|
|
40
|
+
)]
|
|
41
|
+
indexer: Indexer,
|
|
42
|
+
|
|
34
43
|
#[arg(
|
|
35
44
|
long = "report-orphans",
|
|
36
45
|
value_name = "PATH",
|
|
@@ -49,6 +58,21 @@ enum StopAfter {
|
|
|
49
58
|
Resolution,
|
|
50
59
|
}
|
|
51
60
|
|
|
61
|
+
#[derive(Debug, Clone, ValueEnum)]
|
|
62
|
+
enum Indexer {
|
|
63
|
+
RubyIndexer,
|
|
64
|
+
OperationBuilder,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
impl From<&Indexer> for IndexerBackend {
|
|
68
|
+
fn from(indexer: &Indexer) -> Self {
|
|
69
|
+
match indexer {
|
|
70
|
+
Indexer::RubyIndexer => IndexerBackend::RubyIndexer,
|
|
71
|
+
Indexer::OperationBuilder => IndexerBackend::OperationBuilder,
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
52
76
|
fn exit(print_stats: bool) {
|
|
53
77
|
if print_stats {
|
|
54
78
|
Timer::print_breakdown();
|
|
@@ -80,7 +104,8 @@ fn main() {
|
|
|
80
104
|
// Indexing
|
|
81
105
|
|
|
82
106
|
let mut graph = Graph::new();
|
|
83
|
-
let
|
|
107
|
+
let backend = IndexerBackend::from(&args.indexer);
|
|
108
|
+
let errors = time_it!(indexing, { indexing::index_files(&mut graph, file_paths, backend) });
|
|
84
109
|
|
|
85
110
|
for error in errors {
|
|
86
111
|
eprintln!("{error}");
|
|
@@ -29,7 +29,7 @@ use crate::{
|
|
|
29
29
|
assert_mem_size,
|
|
30
30
|
model::{
|
|
31
31
|
comment::Comment,
|
|
32
|
-
ids::{ConstantReferenceId, DefinitionId, NameId, StringId, UriId},
|
|
32
|
+
ids::{self, ConstantReferenceId, DefinitionId, NameId, StringId, UriId},
|
|
33
33
|
visibility::Visibility,
|
|
34
34
|
},
|
|
35
35
|
offset::Offset,
|
|
@@ -289,7 +289,7 @@ impl ClassDefinition {
|
|
|
289
289
|
|
|
290
290
|
#[must_use]
|
|
291
291
|
pub fn id(&self) -> DefinitionId {
|
|
292
|
-
|
|
292
|
+
ids::namespace_definition_id(self.uri_id, &self.offset, self.name_id)
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
#[must_use]
|
|
@@ -411,7 +411,7 @@ impl SingletonClassDefinition {
|
|
|
411
411
|
|
|
412
412
|
#[must_use]
|
|
413
413
|
pub fn id(&self) -> DefinitionId {
|
|
414
|
-
|
|
414
|
+
ids::namespace_definition_id(self.uri_id, &self.offset, self.name_id)
|
|
415
415
|
}
|
|
416
416
|
|
|
417
417
|
#[must_use]
|
|
@@ -515,7 +515,7 @@ impl ModuleDefinition {
|
|
|
515
515
|
|
|
516
516
|
#[must_use]
|
|
517
517
|
pub fn id(&self) -> DefinitionId {
|
|
518
|
-
|
|
518
|
+
ids::namespace_definition_id(self.uri_id, &self.offset, self.name_id)
|
|
519
519
|
}
|
|
520
520
|
|
|
521
521
|
#[must_use]
|
|
@@ -611,7 +611,7 @@ impl ConstantDefinition {
|
|
|
611
611
|
|
|
612
612
|
#[must_use]
|
|
613
613
|
pub fn id(&self) -> DefinitionId {
|
|
614
|
-
|
|
614
|
+
ids::namespace_definition_id(self.uri_id, &self.offset, self.name_id)
|
|
615
615
|
}
|
|
616
616
|
|
|
617
617
|
#[must_use]
|
|
@@ -926,7 +926,7 @@ pub struct MethodDefinition {
|
|
|
926
926
|
assert_mem_size!(MethodDefinition, 96);
|
|
927
927
|
|
|
928
928
|
/// The receiver of a singleton method definition.
|
|
929
|
-
#[derive(Debug)]
|
|
929
|
+
#[derive(Debug, Clone)]
|
|
930
930
|
pub enum Receiver {
|
|
931
931
|
/// `def self.foo` - receiver is the enclosing definition (class, module, singleton class or DSL)
|
|
932
932
|
SelfReceiver(DefinitionId),
|
|
@@ -965,18 +965,7 @@ impl MethodDefinition {
|
|
|
965
965
|
|
|
966
966
|
#[must_use]
|
|
967
967
|
pub fn id(&self) -> DefinitionId {
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
if let Some(receiver) = &self.receiver {
|
|
971
|
-
match receiver {
|
|
972
|
-
Receiver::SelfReceiver(def_id) => formatted_id.push_str(&def_id.to_string()),
|
|
973
|
-
Receiver::ConstantReceiver(name_id) => {
|
|
974
|
-
formatted_id.push_str(&name_id.to_string());
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
DefinitionId::from(&formatted_id)
|
|
968
|
+
ids::method_definition_id(self.uri_id, &self.offset, self.str_id, self.receiver.as_ref())
|
|
980
969
|
}
|
|
981
970
|
|
|
982
971
|
#[must_use]
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
use crate::{
|
|
1
|
+
use crate::{
|
|
2
|
+
assert_mem_size,
|
|
3
|
+
model::{definitions::Receiver, id::Id},
|
|
4
|
+
offset::Offset,
|
|
5
|
+
};
|
|
2
6
|
|
|
3
7
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
|
|
4
8
|
pub struct DeclarationMarker;
|
|
@@ -12,6 +16,28 @@ pub struct DefinitionMarker;
|
|
|
12
16
|
pub type DefinitionId = Id<DefinitionMarker>;
|
|
13
17
|
assert_mem_size!(DefinitionId, 8);
|
|
14
18
|
|
|
19
|
+
#[must_use]
|
|
20
|
+
pub fn namespace_definition_id(uri_id: UriId, offset: &Offset, name_id: NameId) -> DefinitionId {
|
|
21
|
+
DefinitionId::from(&format!("{}{}{}", *uri_id, offset.start(), *name_id))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
#[must_use]
|
|
25
|
+
pub fn method_definition_id(
|
|
26
|
+
uri_id: UriId,
|
|
27
|
+
offset: &Offset,
|
|
28
|
+
str_id: StringId,
|
|
29
|
+
receiver: Option<&Receiver>,
|
|
30
|
+
) -> DefinitionId {
|
|
31
|
+
let mut formatted_id = format!("{}{}{}", *uri_id, offset.start(), *str_id);
|
|
32
|
+
if let Some(receiver) = receiver {
|
|
33
|
+
match receiver {
|
|
34
|
+
Receiver::SelfReceiver(def_id) => formatted_id.push_str(&def_id.to_string()),
|
|
35
|
+
Receiver::ConstantReceiver(name_id) => formatted_id.push_str(&name_id.to_string()),
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
DefinitionId::from(&formatted_id)
|
|
39
|
+
}
|
|
40
|
+
|
|
15
41
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
|
|
16
42
|
pub struct UriMarker;
|
|
17
43
|
// UriId represents the ID of a URI, which is the unique identifier for a document
|