zarz 0.3.4-alpha → 0.3.5-alpha

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.
package/src/fs_ops.rs DELETED
@@ -1,117 +0,0 @@
1
- use anyhow::{Context, Result};
2
- use std::path::{Path, PathBuf};
3
- use tokio::fs;
4
- use walkdir::WalkDir;
5
-
6
- pub struct FileSystemOps;
7
-
8
- impl FileSystemOps {
9
- pub async fn create_file(path: &Path, content: &str) -> Result<()> {
10
- if let Some(parent) = path.parent() {
11
- fs::create_dir_all(parent)
12
- .await
13
- .with_context(|| format!("Failed to create parent directories for {}", path.display()))?;
14
- }
15
-
16
- fs::write(path, content)
17
- .await
18
- .with_context(|| format!("Failed to write file {}", path.display()))?;
19
-
20
- Ok(())
21
- }
22
-
23
- #[allow(dead_code)]
24
- pub async fn delete_file(path: &Path) -> Result<()> {
25
- fs::remove_file(path)
26
- .await
27
- .with_context(|| format!("Failed to delete file {}", path.display()))?;
28
-
29
- Ok(())
30
- }
31
-
32
- #[allow(dead_code)]
33
- pub async fn rename_file(from: &Path, to: &Path) -> Result<()> {
34
- if let Some(parent) = to.parent() {
35
- fs::create_dir_all(parent)
36
- .await
37
- .with_context(|| format!("Failed to create parent directories for {}", to.display()))?;
38
- }
39
-
40
- fs::rename(from, to)
41
- .await
42
- .with_context(|| format!("Failed to rename {} to {}", from.display(), to.display()))?;
43
-
44
- Ok(())
45
- }
46
-
47
- #[allow(dead_code)]
48
- pub async fn create_directory(path: &Path) -> Result<()> {
49
- fs::create_dir_all(path)
50
- .await
51
- .with_context(|| format!("Failed to create directory {}", path.display()))?;
52
-
53
- Ok(())
54
- }
55
-
56
- pub async fn read_file(path: &Path) -> Result<String> {
57
- fs::read_to_string(path)
58
- .await
59
- .with_context(|| format!("Failed to read file {}", path.display()))
60
- }
61
-
62
- pub async fn file_exists(path: &Path) -> bool {
63
- fs::metadata(path).await.is_ok()
64
- }
65
-
66
- #[allow(dead_code)]
67
- pub fn list_files(root: &Path, pattern: Option<&str>) -> Result<Vec<PathBuf>> {
68
- let mut files = Vec::new();
69
-
70
- for entry in WalkDir::new(root)
71
- .follow_links(false)
72
- .into_iter()
73
- .filter_map(|e| e.ok())
74
- {
75
- if entry.file_type().is_file() {
76
- let path = entry.path();
77
-
78
- if let Some(pattern) = pattern {
79
- if let Some(file_name) = path.file_name() {
80
- if file_name.to_string_lossy().contains(pattern) {
81
- files.push(path.to_path_buf());
82
- }
83
- }
84
- } else {
85
- files.push(path.to_path_buf());
86
- }
87
- }
88
- }
89
-
90
- Ok(files)
91
- }
92
-
93
- #[allow(dead_code)]
94
- pub fn get_directory_structure(root: &Path, max_depth: Option<usize>) -> Result<String> {
95
- let mut output = String::new();
96
- let max_depth = max_depth.unwrap_or(3);
97
-
98
- for entry in WalkDir::new(root)
99
- .max_depth(max_depth)
100
- .follow_links(false)
101
- .into_iter()
102
- .filter_map(|e| e.ok())
103
- {
104
- let depth = entry.depth();
105
- let indent = " ".repeat(depth);
106
- let name = entry.file_name().to_string_lossy();
107
-
108
- if entry.file_type().is_dir() {
109
- output.push_str(&format!("{}{}/\n", indent, name));
110
- } else {
111
- output.push_str(&format!("{}{}\n", indent, name));
112
- }
113
- }
114
-
115
- Ok(output)
116
- }
117
- }
@@ -1,143 +0,0 @@
1
- use anyhow::Result;
2
- use regex::Regex;
3
- use std::collections::HashSet;
4
- use std::path::{Path, PathBuf};
5
- use walkdir::WalkDir;
6
-
7
- pub struct ContextBuilder;
8
-
9
- impl ContextBuilder {
10
- pub fn build_context(root: &Path, query: &str) -> Result<Vec<PathBuf>> {
11
- let keywords = Self::extract_keywords(query);
12
- let mut relevant_files = Vec::new();
13
- let mut scores: Vec<(PathBuf, usize)> = Vec::new();
14
-
15
- for entry in WalkDir::new(root)
16
- .max_depth(10)
17
- .follow_links(false)
18
- .into_iter()
19
- .filter_map(|e| e.ok())
20
- {
21
- if entry.file_type().is_file() {
22
- let path = entry.path();
23
-
24
- if Self::should_skip(path) {
25
- continue;
26
- }
27
-
28
- if let Ok(content) = std::fs::read_to_string(path) {
29
- let score = Self::calculate_relevance(&content, &keywords);
30
-
31
- if score > 0 {
32
- scores.push((path.to_path_buf(), score));
33
- }
34
- }
35
- }
36
- }
37
-
38
- scores.sort_by(|a, b| b.1.cmp(&a.1));
39
-
40
- for (path, _) in scores.iter().take(5) {
41
- relevant_files.push(path.clone());
42
- }
43
-
44
- Ok(relevant_files)
45
- }
46
-
47
- fn extract_keywords(query: &str) -> HashSet<String> {
48
- let re = Regex::new(r"\b[a-zA-Z_][a-zA-Z0-9_]{2,}\b").unwrap();
49
- let mut keywords = HashSet::new();
50
-
51
- for cap in re.find_iter(query) {
52
- let word = cap.as_str().to_lowercase();
53
- if !Self::is_common_word(&word) {
54
- keywords.insert(word);
55
- }
56
- }
57
-
58
- keywords
59
- }
60
-
61
- fn calculate_relevance(content: &str, keywords: &HashSet<String>) -> usize {
62
- let content_lower = content.to_lowercase();
63
- let mut score = 0;
64
-
65
- for keyword in keywords {
66
- let count = content_lower.matches(keyword.as_str()).count();
67
- score += count * 10;
68
- }
69
-
70
- score
71
- }
72
-
73
- fn should_skip(path: &Path) -> bool {
74
- let path_str = path.to_string_lossy();
75
-
76
- if path_str.contains("target/")
77
- || path_str.contains(".git/")
78
- || path_str.contains("node_modules/")
79
- || path_str.contains(".vscode/")
80
- {
81
- return true;
82
- }
83
-
84
- if let Some(ext) = path.extension() {
85
- let ext_str = ext.to_string_lossy();
86
- if ext_str == "lock"
87
- || ext_str == "json"
88
- || ext_str == "md"
89
- || ext_str == "txt"
90
- || ext_str == "yml"
91
- || ext_str == "yaml"
92
- {
93
- return true;
94
- }
95
- }
96
-
97
- false
98
- }
99
-
100
- fn is_common_word(word: &str) -> bool {
101
- matches!(
102
- word,
103
- "the" | "and"
104
- | "for"
105
- | "are"
106
- | "but"
107
- | "not"
108
- | "you"
109
- | "all"
110
- | "can"
111
- | "her"
112
- | "was"
113
- | "one"
114
- | "our"
115
- | "out"
116
- | "day"
117
- | "get"
118
- | "has"
119
- | "him"
120
- | "his"
121
- | "how"
122
- | "let"
123
- | "may"
124
- | "new"
125
- | "now"
126
- | "old"
127
- | "see"
128
- | "try"
129
- | "use"
130
- | "way"
131
- | "who"
132
- | "boy"
133
- | "did"
134
- | "its"
135
- | "say"
136
- | "she"
137
- | "too"
138
- | "any"
139
- | "add"
140
- | "set"
141
- )
142
- }
143
- }
@@ -1,60 +0,0 @@
1
- mod rust_parser;
2
- mod symbol_search;
3
- mod context;
4
-
5
- pub use rust_parser::RustParser;
6
- pub use symbol_search::SymbolSearcher;
7
- pub use context::ContextBuilder;
8
-
9
- use anyhow::Result;
10
- use std::path::{Path, PathBuf};
11
-
12
- #[derive(Debug, Clone)]
13
- pub struct Symbol {
14
- pub name: String,
15
- pub kind: SymbolKind,
16
- pub file: PathBuf,
17
- #[allow(dead_code)]
18
- pub line: usize,
19
- }
20
-
21
- #[derive(Debug, Clone, PartialEq)]
22
- pub enum SymbolKind {
23
- Function,
24
- Struct,
25
- Enum,
26
- Trait,
27
- Impl,
28
- Module,
29
- Constant,
30
- Static,
31
- }
32
-
33
- #[derive(Debug)]
34
- pub struct ProjectIntelligence {
35
- root: PathBuf,
36
- }
37
-
38
- impl ProjectIntelligence {
39
- pub fn new(root: PathBuf) -> Self {
40
- Self { root }
41
- }
42
-
43
- pub fn find_symbol(&self, name: &str) -> Result<Vec<Symbol>> {
44
- SymbolSearcher::search(&self.root, name)
45
- }
46
-
47
- #[allow(dead_code)]
48
- pub fn get_file_symbols(&self, file: &Path) -> Result<Vec<Symbol>> {
49
- RustParser::parse_file(file)
50
- }
51
-
52
- pub fn get_relevant_context(&self, query: &str) -> Result<Vec<PathBuf>> {
53
- ContextBuilder::build_context(&self.root, query)
54
- }
55
-
56
- #[allow(dead_code)]
57
- pub fn analyze_dependencies(&self) -> Result<Vec<String>> {
58
- RustParser::extract_dependencies(&self.root)
59
- }
60
- }
@@ -1,141 +0,0 @@
1
- use super::{Symbol, SymbolKind};
2
- use anyhow::{Context, Result};
3
- use std::path::{Path, PathBuf};
4
- use syn::{visit::Visit, Item};
5
-
6
- pub struct RustParser;
7
-
8
- impl RustParser {
9
- pub fn parse_file(path: &Path) -> Result<Vec<Symbol>> {
10
- let content = std::fs::read_to_string(path)
11
- .with_context(|| format!("Failed to read file {}", path.display()))?;
12
-
13
- let syntax = syn::parse_file(&content)
14
- .with_context(|| format!("Failed to parse Rust file {}", path.display()))?;
15
-
16
- let mut visitor = SymbolVisitor {
17
- symbols: Vec::new(),
18
- file: path.to_path_buf(),
19
- };
20
-
21
- visitor.visit_file(&syntax);
22
-
23
- Ok(visitor.symbols)
24
- }
25
-
26
- #[allow(dead_code)]
27
- pub fn extract_dependencies(root: &Path) -> Result<Vec<String>> {
28
- let cargo_path = root.join("Cargo.toml");
29
-
30
- if !cargo_path.exists() {
31
- return Ok(Vec::new());
32
- }
33
-
34
- let content = std::fs::read_to_string(&cargo_path)
35
- .context("Failed to read Cargo.toml")?;
36
-
37
- let toml: toml::Value = toml::from_str(&content)
38
- .context("Failed to parse Cargo.toml")?;
39
-
40
- let mut deps = Vec::new();
41
-
42
- if let Some(dependencies) = toml.get("dependencies") {
43
- if let Some(table) = dependencies.as_table() {
44
- for (name, _) in table {
45
- deps.push(name.clone());
46
- }
47
- }
48
- }
49
-
50
- Ok(deps)
51
- }
52
- }
53
-
54
- struct SymbolVisitor {
55
- symbols: Vec<Symbol>,
56
- file: PathBuf,
57
- }
58
-
59
- impl<'ast> Visit<'ast> for SymbolVisitor {
60
- fn visit_item(&mut self, item: &'ast Item) {
61
- match item {
62
- Item::Fn(func) => {
63
- let name = func.sig.ident.to_string();
64
- self.symbols.push(Symbol {
65
- name,
66
- kind: SymbolKind::Function,
67
- file: self.file.clone(),
68
- line: 0,
69
- });
70
- }
71
- Item::Struct(s) => {
72
- let name = s.ident.to_string();
73
- self.symbols.push(Symbol {
74
- name,
75
- kind: SymbolKind::Struct,
76
- file: self.file.clone(),
77
- line: 0,
78
- });
79
- }
80
- Item::Enum(e) => {
81
- let name = e.ident.to_string();
82
- self.symbols.push(Symbol {
83
- name,
84
- kind: SymbolKind::Enum,
85
- file: self.file.clone(),
86
- line: 0,
87
- });
88
- }
89
- Item::Trait(t) => {
90
- let name = t.ident.to_string();
91
- self.symbols.push(Symbol {
92
- name,
93
- kind: SymbolKind::Trait,
94
- file: self.file.clone(),
95
- line: 0,
96
- });
97
- }
98
- Item::Impl(impl_item) => {
99
- if let Some((_, path, _)) = &impl_item.trait_ {
100
- let name = quote::quote!(#path).to_string();
101
- self.symbols.push(Symbol {
102
- name,
103
- kind: SymbolKind::Impl,
104
- file: self.file.clone(),
105
- line: 0,
106
- });
107
- }
108
- }
109
- Item::Mod(m) => {
110
- let name = m.ident.to_string();
111
- self.symbols.push(Symbol {
112
- name,
113
- kind: SymbolKind::Module,
114
- file: self.file.clone(),
115
- line: 0,
116
- });
117
- }
118
- Item::Const(c) => {
119
- let name = c.ident.to_string();
120
- self.symbols.push(Symbol {
121
- name,
122
- kind: SymbolKind::Constant,
123
- file: self.file.clone(),
124
- line: 0,
125
- });
126
- }
127
- Item::Static(s) => {
128
- let name = s.ident.to_string();
129
- self.symbols.push(Symbol {
130
- name,
131
- kind: SymbolKind::Static,
132
- file: self.file.clone(),
133
- line: 0,
134
- });
135
- }
136
- _ => {}
137
- }
138
-
139
- syn::visit::visit_item(self, item);
140
- }
141
- }
@@ -1,97 +0,0 @@
1
- use super::{RustParser, Symbol};
2
- use anyhow::Result;
3
- use std::path::Path;
4
- use walkdir::WalkDir;
5
-
6
- pub struct SymbolSearcher;
7
-
8
- impl SymbolSearcher {
9
- pub fn search(root: &Path, name: &str) -> Result<Vec<Symbol>> {
10
- let mut results = Vec::new();
11
-
12
- for entry in WalkDir::new(root)
13
- .follow_links(false)
14
- .into_iter()
15
- .filter_map(|e| e.ok())
16
- {
17
- if entry.file_type().is_file() {
18
- let path = entry.path();
19
-
20
- if let Some(ext) = path.extension() {
21
- if ext == "rs" {
22
- if let Ok(symbols) = RustParser::parse_file(path) {
23
- for symbol in symbols {
24
- if symbol.name.contains(name) {
25
- results.push(symbol);
26
- }
27
- }
28
- }
29
- }
30
- }
31
- }
32
- }
33
-
34
- Ok(results)
35
- }
36
-
37
- #[allow(dead_code)]
38
- pub fn search_exact(root: &Path, name: &str) -> Result<Vec<Symbol>> {
39
- let mut results = Vec::new();
40
-
41
- for entry in WalkDir::new(root)
42
- .follow_links(false)
43
- .into_iter()
44
- .filter_map(|e| e.ok())
45
- {
46
- if entry.file_type().is_file() {
47
- let path = entry.path();
48
-
49
- if let Some(ext) = path.extension() {
50
- if ext == "rs" {
51
- if let Ok(symbols) = RustParser::parse_file(path) {
52
- for symbol in symbols {
53
- if symbol.name == name {
54
- results.push(symbol);
55
- }
56
- }
57
- }
58
- }
59
- }
60
- }
61
- }
62
-
63
- Ok(results)
64
- }
65
-
66
- #[allow(dead_code)]
67
- pub fn find_references(root: &Path, symbol_name: &str) -> Result<Vec<(String, usize)>> {
68
- let mut references = Vec::new();
69
-
70
- for entry in WalkDir::new(root)
71
- .follow_links(false)
72
- .into_iter()
73
- .filter_map(|e| e.ok())
74
- {
75
- if entry.file_type().is_file() {
76
- let path = entry.path();
77
-
78
- if let Some(ext) = path.extension() {
79
- if ext == "rs" {
80
- if let Ok(content) = std::fs::read_to_string(path) {
81
- for (line_num, line) in content.lines().enumerate() {
82
- if line.contains(symbol_name) {
83
- references.push((
84
- format!("{}:{}", path.display(), line_num + 1),
85
- line_num + 1,
86
- ));
87
- }
88
- }
89
- }
90
- }
91
- }
92
- }
93
- }
94
-
95
- Ok(references)
96
- }
97
- }