Skip to main content

quillmark_core/quill/
query.rs

1//! QuillSource file/query convenience methods.
2use std::path::{Path, PathBuf};
3
4use super::{FileTreeNode, QuillSource};
5
6impl QuillSource {
7    /// Get file contents by path (relative to quill root)
8    pub fn get_file<P: AsRef<Path>>(&self, path: P) -> Option<&[u8]> {
9        self.files.get_file(path)
10    }
11
12    /// Check if a file exists in memory
13    pub fn file_exists<P: AsRef<Path>>(&self, path: P) -> bool {
14        self.files.file_exists(path)
15    }
16
17    /// Check if a directory exists in memory
18    pub fn dir_exists<P: AsRef<Path>>(&self, path: P) -> bool {
19        self.files.dir_exists(path)
20    }
21
22    /// List files in a directory (non-recursive, returns file names only)
23    pub fn list_files<P: AsRef<Path>>(&self, path: P) -> Vec<String> {
24        self.files.list_files(path)
25    }
26
27    /// List subdirectories in a directory (non-recursive, returns directory names only)
28    pub fn list_subdirectories<P: AsRef<Path>>(&self, path: P) -> Vec<String> {
29        self.files.list_subdirectories(path)
30    }
31
32    /// List all files in a directory (returns paths relative to quill root)
33    pub fn list_directory<P: AsRef<Path>>(&self, dir_path: P) -> Vec<PathBuf> {
34        let dir_path = dir_path.as_ref();
35        let filenames = self.files.list_files(dir_path);
36
37        // Convert filenames to full paths
38        filenames
39            .iter()
40            .map(|name| {
41                if dir_path == Path::new("") {
42                    PathBuf::from(name)
43                } else {
44                    dir_path.join(name)
45                }
46            })
47            .collect()
48    }
49
50    /// List all directories in a directory (returns paths relative to quill root)
51    pub fn list_directories<P: AsRef<Path>>(&self, dir_path: P) -> Vec<PathBuf> {
52        let dir_path = dir_path.as_ref();
53        let subdirs = self.files.list_subdirectories(dir_path);
54
55        // Convert subdirectory names to full paths
56        subdirs
57            .iter()
58            .map(|name| {
59                if dir_path == Path::new("") {
60                    PathBuf::from(name)
61                } else {
62                    dir_path.join(name)
63                }
64            })
65            .collect()
66    }
67
68    /// Get all files matching a pattern (supports glob-style wildcards)
69    pub fn find_files<P: AsRef<Path>>(&self, pattern: P) -> Vec<PathBuf> {
70        let pattern_str = pattern.as_ref().to_string_lossy();
71        let mut matches = Vec::new();
72
73        // Compile the glob pattern
74        let glob_pattern = match glob::Pattern::new(&pattern_str) {
75            Ok(pat) => pat,
76            Err(_) => return matches, // Invalid pattern returns empty results
77        };
78
79        // Recursively search the tree for matching files
80        Self::find_files_recursive(&self.files, Path::new(""), &glob_pattern, &mut matches);
81
82        matches.sort();
83        matches
84    }
85
86    /// Helper method to recursively search for files matching a pattern
87    fn find_files_recursive(
88        node: &FileTreeNode,
89        current_path: &Path,
90        pattern: &glob::Pattern,
91        matches: &mut Vec<PathBuf>,
92    ) {
93        match node {
94            FileTreeNode::File { .. } => {
95                let path_str = current_path.to_string_lossy();
96                if pattern.matches(&path_str) {
97                    matches.push(current_path.to_path_buf());
98                }
99            }
100            FileTreeNode::Directory { files } => {
101                for (name, child_node) in files {
102                    let child_path = if current_path == Path::new("") {
103                        PathBuf::from(name)
104                    } else {
105                        current_path.join(name)
106                    };
107                    Self::find_files_recursive(child_node, &child_path, pattern, matches);
108                }
109            }
110        }
111    }
112}