rubydex 0.1.0.beta11 → 0.1.0.beta13

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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +23 -23
  3. data/README.md +125 -125
  4. data/THIRD_PARTY_LICENSES.html +2018 -945
  5. data/exe/rdx +47 -47
  6. data/ext/rubydex/declaration.c +453 -388
  7. data/ext/rubydex/declaration.h +23 -23
  8. data/ext/rubydex/definition.c +284 -197
  9. data/ext/rubydex/definition.h +28 -28
  10. data/ext/rubydex/diagnostic.c +6 -6
  11. data/ext/rubydex/diagnostic.h +11 -11
  12. data/ext/rubydex/document.c +97 -98
  13. data/ext/rubydex/document.h +10 -10
  14. data/ext/rubydex/extconf.rb +146 -127
  15. data/ext/rubydex/graph.c +701 -512
  16. data/ext/rubydex/graph.h +10 -10
  17. data/ext/rubydex/handle.h +44 -44
  18. data/ext/rubydex/location.c +22 -22
  19. data/ext/rubydex/location.h +15 -15
  20. data/ext/rubydex/reference.c +123 -104
  21. data/ext/rubydex/reference.h +15 -16
  22. data/ext/rubydex/rubydex.c +22 -22
  23. data/ext/rubydex/utils.c +108 -86
  24. data/ext/rubydex/utils.h +34 -28
  25. data/lib/rubydex/comment.rb +17 -17
  26. data/lib/rubydex/declaration.rb +11 -0
  27. data/lib/rubydex/diagnostic.rb +21 -21
  28. data/lib/rubydex/failures.rb +15 -15
  29. data/lib/rubydex/graph.rb +98 -92
  30. data/lib/rubydex/keyword.rb +17 -0
  31. data/lib/rubydex/keyword_parameter.rb +13 -0
  32. data/lib/rubydex/location.rb +90 -90
  33. data/lib/rubydex/mixin.rb +22 -0
  34. data/lib/rubydex/version.rb +5 -5
  35. data/lib/rubydex.rb +24 -20
  36. data/rbi/rubydex.rbi +425 -310
  37. data/rust/Cargo.lock +1851 -1851
  38. data/rust/Cargo.toml +29 -29
  39. data/rust/about.toml +10 -10
  40. data/rust/{about.hbs → about_templates/about.hbs} +81 -78
  41. data/rust/about_templates/mingw_licenses.hbs +1071 -0
  42. data/rust/rubydex/Cargo.toml +42 -42
  43. data/rust/rubydex/src/compile_assertions.rs +13 -13
  44. data/rust/rubydex/src/diagnostic.rs +110 -109
  45. data/rust/rubydex/src/errors.rs +28 -28
  46. data/rust/rubydex/src/indexing/local_graph.rs +224 -224
  47. data/rust/rubydex/src/indexing/rbs_indexer.rs +1551 -1554
  48. data/rust/rubydex/src/indexing/ruby_indexer.rs +2329 -6753
  49. data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +4962 -0
  50. data/rust/rubydex/src/indexing.rs +210 -210
  51. data/rust/rubydex/src/integrity.rs +279 -278
  52. data/rust/rubydex/src/job_queue.rs +199 -205
  53. data/rust/rubydex/src/lib.rs +17 -17
  54. data/rust/rubydex/src/listing.rs +371 -272
  55. data/rust/rubydex/src/main.rs +160 -160
  56. data/rust/rubydex/src/model/built_in.rs +83 -0
  57. data/rust/rubydex/src/model/comment.rs +24 -24
  58. data/rust/rubydex/src/model/declaration.rs +679 -588
  59. data/rust/rubydex/src/model/definitions.rs +1682 -1602
  60. data/rust/rubydex/src/model/document.rs +222 -252
  61. data/rust/rubydex/src/model/encoding.rs +22 -22
  62. data/rust/rubydex/src/model/graph.rs +3782 -3556
  63. data/rust/rubydex/src/model/id.rs +110 -110
  64. data/rust/rubydex/src/model/identity_maps.rs +58 -58
  65. data/rust/rubydex/src/model/ids.rs +60 -38
  66. data/rust/rubydex/src/model/keywords.rs +256 -256
  67. data/rust/rubydex/src/model/name.rs +298 -298
  68. data/rust/rubydex/src/model/references.rs +111 -111
  69. data/rust/rubydex/src/model/string_ref.rs +50 -50
  70. data/rust/rubydex/src/model/visibility.rs +41 -41
  71. data/rust/rubydex/src/model.rs +15 -14
  72. data/rust/rubydex/src/offset.rs +147 -147
  73. data/rust/rubydex/src/position.rs +6 -6
  74. data/rust/rubydex/src/query.rs +1841 -1700
  75. data/rust/rubydex/src/resolution.rs +1852 -5895
  76. data/rust/rubydex/src/resolution_tests.rs +4701 -0
  77. data/rust/rubydex/src/stats/memory.rs +71 -71
  78. data/rust/rubydex/src/stats/orphan_report.rs +264 -263
  79. data/rust/rubydex/src/stats/timer.rs +127 -127
  80. data/rust/rubydex/src/stats.rs +11 -11
  81. data/rust/rubydex/src/test_utils/context.rs +226 -226
  82. data/rust/rubydex/src/test_utils/graph_test.rs +730 -679
  83. data/rust/rubydex/src/test_utils/local_graph_test.rs +602 -602
  84. data/rust/rubydex/src/test_utils.rs +52 -52
  85. data/rust/rubydex/src/visualization/dot.rs +192 -176
  86. data/rust/rubydex/src/visualization.rs +6 -6
  87. data/rust/rubydex/tests/cli.rs +185 -167
  88. data/rust/rubydex-mcp/Cargo.toml +28 -28
  89. data/rust/rubydex-mcp/src/main.rs +48 -48
  90. data/rust/rubydex-mcp/src/server.rs +1145 -1145
  91. data/rust/rubydex-mcp/src/tools.rs +49 -49
  92. data/rust/rubydex-mcp/tests/mcp.rs +302 -302
  93. data/rust/rubydex-sys/Cargo.toml +20 -20
  94. data/rust/rubydex-sys/build.rs +14 -14
  95. data/rust/rubydex-sys/cbindgen.toml +12 -12
  96. data/rust/rubydex-sys/src/declaration_api.rs +485 -469
  97. data/rust/rubydex-sys/src/definition_api.rs +443 -352
  98. data/rust/rubydex-sys/src/diagnostic_api.rs +99 -99
  99. data/rust/rubydex-sys/src/document_api.rs +85 -54
  100. data/rust/rubydex-sys/src/graph_api.rs +1017 -700
  101. data/rust/rubydex-sys/src/lib.rs +79 -9
  102. data/rust/rubydex-sys/src/location_api.rs +79 -79
  103. data/rust/rubydex-sys/src/name_api.rs +187 -135
  104. data/rust/rubydex-sys/src/reference_api.rs +267 -195
  105. data/rust/rubydex-sys/src/utils.rs +70 -70
  106. data/rust/rustfmt.toml +2 -2
  107. metadata +16 -9
  108. data/lib/rubydex/librubydex_sys.so +0 -0
@@ -1,210 +1,210 @@
1
- use crate::{
2
- errors::Errors,
3
- indexing::{local_graph::LocalGraph, rbs_indexer::RBSIndexer, ruby_indexer::RubyIndexer},
4
- job_queue::{Job, JobQueue},
5
- model::graph::Graph,
6
- };
7
- use crossbeam_channel::{Sender, unbounded};
8
- use std::{ffi::OsStr, fs, path::PathBuf, sync::Arc};
9
- use url::Url;
10
-
11
- pub mod local_graph;
12
- pub mod rbs_indexer;
13
- pub mod ruby_indexer;
14
-
15
- /// The language of a source document, used to dispatch to the appropriate indexer
16
- pub enum LanguageId {
17
- Ruby,
18
- Rbs,
19
- }
20
-
21
- impl From<&OsStr> for LanguageId {
22
- fn from(ext: &OsStr) -> Self {
23
- if ext == "rbs" { Self::Rbs } else { Self::Ruby }
24
- }
25
- }
26
-
27
- impl LanguageId {
28
- /// Determines the language from an LSP language ID string.
29
- ///
30
- /// # Errors
31
- ///
32
- /// Returns an error if the language ID is not recognized.
33
- pub fn from_language_id(language_id: &str) -> Result<Self, Errors> {
34
- match language_id {
35
- "ruby" => Ok(Self::Ruby),
36
- "rbs" => Ok(Self::Rbs),
37
- _ => Err(Errors::FileError(format!("Unsupported language_id `{language_id}`"))),
38
- }
39
- }
40
- }
41
-
42
- /// Job that indexes a single file
43
- pub struct IndexingJob {
44
- path: PathBuf,
45
- local_graph_tx: Sender<LocalGraph>,
46
- errors_tx: Sender<Errors>,
47
- }
48
-
49
- impl IndexingJob {
50
- #[must_use]
51
- pub fn new(path: PathBuf, local_graph_tx: Sender<LocalGraph>, errors_tx: Sender<Errors>) -> Self {
52
- Self {
53
- path,
54
- local_graph_tx,
55
- errors_tx,
56
- }
57
- }
58
-
59
- fn send_error(&self, error: Errors) {
60
- self.errors_tx
61
- .send(error)
62
- .expect("errors receiver dropped before run completion");
63
- }
64
- }
65
-
66
- impl Job for IndexingJob {
67
- fn run(&self) {
68
- let Ok(source) = fs::read_to_string(&self.path) else {
69
- self.send_error(Errors::FileError(format!(
70
- "Failed to read file `{}`",
71
- self.path.display()
72
- )));
73
-
74
- return;
75
- };
76
-
77
- let Ok(url) = Url::from_file_path(&self.path) else {
78
- self.send_error(Errors::FileError(format!(
79
- "Couldn't build URI from path `{}`",
80
- self.path.display()
81
- )));
82
-
83
- return;
84
- };
85
-
86
- let language = self.path.extension().map_or(LanguageId::Ruby, LanguageId::from);
87
- let local_graph = build_local_graph(url.to_string(), &source, &language);
88
-
89
- self.local_graph_tx
90
- .send(local_graph)
91
- .expect("graph receiver dropped before merge");
92
- }
93
- }
94
-
95
- /// Indexes a single source string in memory, dispatching to the appropriate indexer based on `language_id`.
96
- 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);
98
- graph.consume_document_changes(local_graph);
99
- }
100
-
101
- /// Indexes the given paths, reading the content from disk and populating the given `Graph` instance.
102
- ///
103
- /// # Panics
104
- ///
105
- /// Will panic if the graph cannot be wrapped in an Arc<Mutex<>>
106
- pub fn index_files(graph: &mut Graph, paths: Vec<PathBuf>) -> Vec<Errors> {
107
- let queue = Arc::new(JobQueue::new());
108
- let (local_graphs_tx, local_graphs_rx) = unbounded();
109
- let (errors_tx, errors_rx) = unbounded();
110
-
111
- for path in paths {
112
- queue.push(Box::new(IndexingJob::new(
113
- path,
114
- local_graphs_tx.clone(),
115
- errors_tx.clone(),
116
- )));
117
- }
118
-
119
- drop(local_graphs_tx);
120
- drop(errors_tx);
121
-
122
- let handles = JobQueue::run_without_waiting(&queue);
123
-
124
- // Merge graphs as they arrive, overlapping with indexing work on other threads.
125
- while let Ok(local_graph) = local_graphs_rx.recv() {
126
- graph.consume_document_changes(local_graph);
127
- }
128
-
129
- for handle in handles {
130
- handle.join().expect("Worker thread panicked");
131
- }
132
-
133
- errors_rx.iter().collect()
134
- }
135
-
136
- /// Indexes a source string using the appropriate indexer for the given language.
137
- fn build_local_graph(uri: String, source: &str, language: &LanguageId) -> LocalGraph {
138
- match language {
139
- LanguageId::Ruby => {
140
- let mut indexer = RubyIndexer::new(uri, source);
141
- indexer.index();
142
- indexer.local_graph()
143
- }
144
- LanguageId::Rbs => {
145
- let mut indexer = RBSIndexer::new(uri, source);
146
- indexer.index();
147
- indexer.local_graph()
148
- }
149
- }
150
- }
151
-
152
- #[cfg(test)]
153
- mod tests {
154
- use std::path::PathBuf;
155
-
156
- use super::*;
157
- use crate::test_utils::Context;
158
- use std::path::Path;
159
-
160
- #[test]
161
- fn index_relative_paths() {
162
- let relative_path = Path::new("foo").join("bar.rb");
163
- let context = Context::new();
164
- context.touch(&relative_path);
165
-
166
- let working_directory = std::env::current_dir().unwrap();
167
- let absolute_path = context.absolute_path_to("foo/bar.rb");
168
-
169
- let mut dots = PathBuf::from("..");
170
-
171
- for _ in 0..working_directory.components().count() - 1 {
172
- dots = dots.join("..");
173
- }
174
-
175
- let relative_to_pwd = &dots.join(absolute_path);
176
-
177
- let mut graph = Graph::new();
178
- let errors = index_files(&mut graph, vec![relative_to_pwd.clone()]);
179
-
180
- assert!(errors.is_empty());
181
- assert_eq!(graph.documents().len(), 1);
182
- }
183
-
184
- #[test]
185
- fn from_language_id_unknown() {
186
- let result = LanguageId::from_language_id("python");
187
- assert!(result.is_err());
188
- }
189
-
190
- #[test]
191
- fn updating_document_from_in_memory_source() {
192
- let context = Context::new();
193
- let path = context.absolute_path_to("foo/bar.rb");
194
- context.write(&path, "class Foo; end");
195
-
196
- let uri = Url::from_file_path(&path).unwrap().to_string();
197
-
198
- let mut graph = Graph::new();
199
- let errors = index_files(&mut graph, vec![path]);
200
-
201
- assert!(errors.is_empty(), "Expected no errors, got: {errors:#?}");
202
- assert_eq!(1, graph.definitions().len());
203
- assert_eq!(1, graph.documents().len());
204
-
205
- index_source(&mut graph, &uri, "", &LanguageId::Ruby);
206
-
207
- assert_eq!(0, graph.definitions().len());
208
- assert_eq!(1, graph.documents().len());
209
- }
210
- }
1
+ use crate::{
2
+ errors::Errors,
3
+ indexing::{local_graph::LocalGraph, rbs_indexer::RBSIndexer, ruby_indexer::RubyIndexer},
4
+ job_queue::{Job, JobQueue},
5
+ model::graph::Graph,
6
+ };
7
+ use crossbeam_channel::{Sender, unbounded};
8
+ use std::{ffi::OsStr, fs, path::PathBuf, sync::Arc};
9
+ use url::Url;
10
+
11
+ pub mod local_graph;
12
+ pub mod rbs_indexer;
13
+ pub mod ruby_indexer;
14
+
15
+ /// The language of a source document, used to dispatch to the appropriate indexer
16
+ pub enum LanguageId {
17
+ Ruby,
18
+ Rbs,
19
+ }
20
+
21
+ impl From<&OsStr> for LanguageId {
22
+ fn from(ext: &OsStr) -> Self {
23
+ if ext == "rbs" { Self::Rbs } else { Self::Ruby }
24
+ }
25
+ }
26
+
27
+ impl LanguageId {
28
+ /// Determines the language from an LSP language ID string.
29
+ ///
30
+ /// # Errors
31
+ ///
32
+ /// Returns an error if the language ID is not recognized.
33
+ pub fn from_language_id(language_id: &str) -> Result<Self, Errors> {
34
+ match language_id {
35
+ "ruby" => Ok(Self::Ruby),
36
+ "rbs" => Ok(Self::Rbs),
37
+ _ => Err(Errors::FileError(format!("Unsupported language_id `{language_id}`"))),
38
+ }
39
+ }
40
+ }
41
+
42
+ /// Job that indexes a single file
43
+ pub struct IndexingJob {
44
+ path: PathBuf,
45
+ local_graph_tx: Sender<LocalGraph>,
46
+ errors_tx: Sender<Errors>,
47
+ }
48
+
49
+ impl IndexingJob {
50
+ #[must_use]
51
+ pub fn new(path: PathBuf, local_graph_tx: Sender<LocalGraph>, errors_tx: Sender<Errors>) -> Self {
52
+ Self {
53
+ path,
54
+ local_graph_tx,
55
+ errors_tx,
56
+ }
57
+ }
58
+
59
+ fn send_error(&self, error: Errors) {
60
+ self.errors_tx
61
+ .send(error)
62
+ .expect("errors receiver dropped before run completion");
63
+ }
64
+ }
65
+
66
+ impl Job for IndexingJob {
67
+ fn run(&self) {
68
+ let Ok(source) = fs::read_to_string(&self.path) else {
69
+ self.send_error(Errors::FileError(format!(
70
+ "Failed to read file `{}`",
71
+ self.path.display()
72
+ )));
73
+
74
+ return;
75
+ };
76
+
77
+ let Ok(url) = Url::from_file_path(&self.path) else {
78
+ self.send_error(Errors::FileError(format!(
79
+ "Couldn't build URI from path `{}`",
80
+ self.path.display()
81
+ )));
82
+
83
+ return;
84
+ };
85
+
86
+ let language = self.path.extension().map_or(LanguageId::Ruby, LanguageId::from);
87
+ let local_graph = build_local_graph(url.to_string(), &source, &language);
88
+
89
+ self.local_graph_tx
90
+ .send(local_graph)
91
+ .expect("graph receiver dropped before merge");
92
+ }
93
+ }
94
+
95
+ /// Indexes a single source string in memory, dispatching to the appropriate indexer based on `language_id`.
96
+ 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);
98
+ graph.consume_document_changes(local_graph);
99
+ }
100
+
101
+ /// Indexes the given paths, reading the content from disk and populating the given `Graph` instance.
102
+ ///
103
+ /// # Panics
104
+ ///
105
+ /// Will panic if the graph cannot be wrapped in an Arc<Mutex<>>
106
+ pub fn index_files(graph: &mut Graph, paths: Vec<PathBuf>) -> Vec<Errors> {
107
+ let queue = Arc::new(JobQueue::new());
108
+ let (local_graphs_tx, local_graphs_rx) = unbounded();
109
+ let (errors_tx, errors_rx) = unbounded();
110
+
111
+ for path in paths {
112
+ queue.push(Box::new(IndexingJob::new(
113
+ path,
114
+ local_graphs_tx.clone(),
115
+ errors_tx.clone(),
116
+ )));
117
+ }
118
+
119
+ drop(local_graphs_tx);
120
+ drop(errors_tx);
121
+
122
+ let handles = JobQueue::run_without_waiting(&queue);
123
+
124
+ // Merge graphs as they arrive, overlapping with indexing work on other threads.
125
+ while let Ok(local_graph) = local_graphs_rx.recv() {
126
+ graph.consume_document_changes(local_graph);
127
+ }
128
+
129
+ for handle in handles {
130
+ handle.join().expect("Worker thread panicked");
131
+ }
132
+
133
+ errors_rx.iter().collect()
134
+ }
135
+
136
+ /// Indexes a source string using the appropriate indexer for the given language.
137
+ fn build_local_graph(uri: String, source: &str, language: &LanguageId) -> LocalGraph {
138
+ match language {
139
+ LanguageId::Ruby => {
140
+ let mut indexer = RubyIndexer::new(uri, source);
141
+ indexer.index();
142
+ indexer.local_graph()
143
+ }
144
+ LanguageId::Rbs => {
145
+ let mut indexer = RBSIndexer::new(uri, source);
146
+ indexer.index();
147
+ indexer.local_graph()
148
+ }
149
+ }
150
+ }
151
+
152
+ #[cfg(test)]
153
+ mod tests {
154
+ use std::path::PathBuf;
155
+
156
+ use super::*;
157
+ use crate::test_utils::Context;
158
+ use std::path::Path;
159
+
160
+ #[test]
161
+ fn index_relative_paths() {
162
+ let relative_path = Path::new("foo").join("bar.rb");
163
+ let context = Context::new();
164
+ context.touch(&relative_path);
165
+
166
+ let working_directory = std::env::current_dir().unwrap();
167
+ let absolute_path = context.absolute_path_to("foo/bar.rb");
168
+
169
+ let mut dots = PathBuf::from("..");
170
+
171
+ for _ in 0..working_directory.components().count() - 1 {
172
+ dots = dots.join("..");
173
+ }
174
+
175
+ let relative_to_pwd = &dots.join(absolute_path);
176
+
177
+ let mut graph = Graph::new();
178
+ let errors = index_files(&mut graph, vec![relative_to_pwd.clone()]);
179
+
180
+ assert!(errors.is_empty());
181
+ assert_eq!(graph.documents().len(), 2);
182
+ }
183
+
184
+ #[test]
185
+ fn from_language_id_unknown() {
186
+ let result = LanguageId::from_language_id("python");
187
+ assert!(result.is_err());
188
+ }
189
+
190
+ #[test]
191
+ fn updating_document_from_in_memory_source() {
192
+ let context = Context::new();
193
+ let path = context.absolute_path_to("foo/bar.rb");
194
+ context.write(&path, "class Foo; end");
195
+
196
+ let uri = Url::from_file_path(&path).unwrap().to_string();
197
+
198
+ let mut graph = Graph::new();
199
+ let errors = index_files(&mut graph, vec![path]);
200
+
201
+ assert!(errors.is_empty(), "Expected no errors, got: {errors:#?}");
202
+ assert_eq!(6, graph.definitions().len());
203
+ assert_eq!(2, graph.documents().len());
204
+
205
+ index_source(&mut graph, &uri, "", &LanguageId::Ruby);
206
+
207
+ assert_eq!(5, graph.definitions().len());
208
+ assert_eq!(2, graph.documents().len());
209
+ }
210
+ }