css_variable_lsp/
workspace.rs1use globset::{Glob, GlobSetBuilder};
2use std::fs;
3use std::path::PathBuf;
4use tower_lsp::lsp_types::Url;
5use walkdir::WalkDir;
6
7use crate::manager::CssVariableManager;
8use crate::parsers::{parse_css_document, parse_html_document};
9
10pub async fn scan_workspace(
12 folders: Vec<Url>,
13 manager: &CssVariableManager,
14 mut on_progress: impl FnMut(usize, usize),
15) -> Result<(), String> {
16 let config = manager.get_config().await;
17
18 let mut lookup_builder = GlobSetBuilder::new();
20 for pattern in &config.lookup_files {
21 if let Ok(glob) = Glob::new(pattern) {
22 lookup_builder.add(glob);
23 }
24 }
25 let lookup_set = lookup_builder
26 .build()
27 .map_err(|e| format!("Failed to build lookup glob set: {}", e))?;
28
29 let mut ignore_builder = GlobSetBuilder::new();
31 for pattern in &config.ignore_globs {
32 if let Ok(glob) = Glob::new(pattern) {
33 ignore_builder.add(glob);
34 }
35 }
36 let ignore_set = ignore_builder
37 .build()
38 .map_err(|e| format!("Failed to build ignore glob set: {}", e))?;
39
40 let mut all_files = Vec::new();
42
43 for folder_uri in folders {
44 let folder_path = PathBuf::from(folder_uri.path());
45
46 for entry in WalkDir::new(&folder_path)
47 .follow_links(false)
48 .into_iter()
49 .filter_map(|e| e.ok())
50 {
51 let path = entry.path();
52
53 if !path.is_file() {
55 continue;
56 }
57
58 let relative = match path.strip_prefix(&folder_path) {
60 Ok(rel) => rel,
61 Err(_) => continue,
62 };
63
64 let path_str = relative.to_string_lossy();
66
67 if ignore_set.is_match(&*path_str) {
69 continue;
70 }
71
72 if lookup_set.is_match(&*path_str) {
74 all_files.push(path.to_path_buf());
75 }
76 }
77 }
78
79 let total = all_files.len();
80
81 for (i, file_path) in all_files.iter().enumerate() {
83 on_progress(i + 1, total);
85
86 let content = match fs::read_to_string(file_path) {
88 Ok(c) => c,
89 Err(_) => continue,
90 };
91
92 let file_uri = match Url::from_file_path(file_path) {
94 Ok(u) => u,
95 Err(_) => continue,
96 };
97
98 let path_str = file_path.to_string_lossy();
100 let result = if path_str.ends_with(".html")
101 || path_str.ends_with(".vue")
102 || path_str.ends_with(".svelte")
103 || path_str.ends_with(".astro")
104 || path_str.ends_with(".ripple")
105 {
106 parse_html_document(&content, &file_uri, manager).await
107 } else if path_str.ends_with(".css")
108 || path_str.ends_with(".scss")
109 || path_str.ends_with(".sass")
110 || path_str.ends_with(".less")
111 {
112 parse_css_document(&content, &file_uri, manager).await
113 } else {
114 continue;
115 };
116
117 if let Err(_e) = result {
119 }
121 }
122
123 Ok(())
124}