1mod buffer;
14mod commands;
15mod core;
16mod infrastructure;
17
18#[cfg(feature = "analyzer")]
19pub mod analyzer;
20
21#[cfg(feature = "lsp")]
22pub mod lsp;
23
24use commands::{handle_in_memory, process_mode_and_handle, process_mode_and_handle_with_options};
25use console::style;
26use core::{compiled_css::CompiledCssInMemory, config::ConfigInMemory};
27use indicatif::{ProgressBar, ProgressStyle};
28use infrastructure::{GrimoireCssDiagnostic, LightningCssOptimizer};
29use miette::GraphicalReportHandler;
30use std::path::Path;
31use std::time::{Duration, Instant};
32
33pub use core::{GrimoireCssError, color, component, config, spell::Spell};
34
35static GRIMM_CALM: &str = " |(• ε •)|";
36static GRIMM_HAPPY: &str = " ヽ(• ε •)ノ";
37static GRIMM_CURSED: &str = " |(x ~ x)|";
38static GRIMM_CASTING: [&str; 8] = [
39 GRIMM_CALM,
40 " (|¬ヘ¬)|",
41 " \\(°o°)/",
42 " (∩¬ロ¬)⊃━▪ ~",
43 " (∩¬ロ¬)⊃━▪ ~·",
44 " (∩¬ロ¬)⊃━▪ ~·•",
45 " (∩¬ロ¬)⊃━▪ ~·•●",
46 GRIMM_HAPPY,
47];
48
49pub fn start(mode: &str) -> Result<(), GrimoireCssError> {
79 let current_dir = std::env::current_dir()?;
80 let css_optimizer = LightningCssOptimizer::new(¤t_dir)?;
81
82 process_mode_and_handle(mode, ¤t_dir, &css_optimizer)
83}
84
85pub fn start_in_memory(
86 config: &ConfigInMemory,
87) -> Result<Vec<CompiledCssInMemory>, GrimoireCssError> {
88 let css_optimizer = LightningCssOptimizer::new_from(
89 config.browserslist_content.as_deref().unwrap_or_default(),
90 )?;
91
92 handle_in_memory(config, &css_optimizer)
93}
94
95#[cfg(feature = "analyzer")]
99pub fn start_in_memory_pretty(
100 config: &ConfigInMemory,
101) -> Result<Vec<CompiledCssInMemory>, GrimoireCssError> {
102 let css_optimizer = LightningCssOptimizer::new_from_with_printer_minify(
103 config.browserslist_content.as_deref().unwrap_or_default(),
104 false,
105 )?;
106
107 handle_in_memory(config, &css_optimizer)
108}
109
110pub fn get_logged_messages() -> Vec<String> {
114 buffer::read_messages()
115}
116
117pub fn start_as_cli(args: Vec<String>) -> Result<(), GrimoireCssError> {
153 let bin_name = args
154 .first()
155 .and_then(|s| Path::new(s).file_name())
156 .and_then(|n| n.to_str())
157 .unwrap_or("grimoire_css");
158
159 if args.get(1).is_some_and(|m| m == "fi") {
161 return commands::fi::run_fi_cli(args);
162 }
163
164 println!();
165
166 println!(
167 "{} Ritual initiated",
168 style(" Grimoire CSS ").white().on_color256(55).bright(),
169 );
170
171 if args.len() < 2 {
173 let message = format!(
174 "{} {} ",
175 style(" Cursed! ").white().on_red().bright(),
176 format_args!("Follow: {bin_name} <mode> ('build', 'init', 'shorten', 'fi')")
177 );
178
179 println!();
180 println!("{GRIMM_CURSED}");
181 println!();
182 println!("{message}");
183
184 return Err(GrimoireCssError::InvalidInput(message));
185 }
186
187 println!();
188
189 let pb = ProgressBar::new_spinner();
190 pb.set_style(ProgressStyle::default_spinner().tick_strings(&GRIMM_CASTING));
191 pb.enable_steady_tick(Duration::from_millis(220));
192 pb.set_draw_target(indicatif::ProgressDrawTarget::stdout_with_hz(10));
193
194 let start_time = Instant::now();
195
196 let mode = args[1].as_str();
197
198 let cli_options = commands::CliOptions {
199 force_version_update: mode == "build" && args.iter().any(|a| a == "--force-version-update"),
200 };
201
202 let current_dir = std::env::current_dir()?;
204 let css_optimizer = LightningCssOptimizer::new(¤t_dir)?;
205
206 match process_mode_and_handle_with_options(mode, ¤t_dir, &css_optimizer, cli_options) {
207 Ok(_) => {
208 pb.finish_and_clear();
209
210 print!("\r\x1b[2K{GRIMM_HAPPY} Spells cast successfully.\n");
211
212 let duration = start_time.elapsed();
213
214 output_saved_messages();
215
216 println!();
217
218 println!(
219 "{}",
220 style(format!(
221 "{}",
222 style(format!(" Enchanted in {duration:.2?}! "))
223 .white()
224 .on_color256(55)
225 .bright(),
226 ))
227 );
228
229 println!();
230
231 Ok(())
232 }
233 Err(e) => {
234 pb.finish_and_clear();
235 print!("\r\x1b[2K{GRIMM_CURSED}\n");
236
237 println!();
238 println!("{}", style(" Cursed! ").white().on_red().bright());
239 println!();
240
241 let diagnostic: GrimoireCssDiagnostic = (&e).into();
242 let mut out = String::new();
243 GraphicalReportHandler::new()
244 .render_report(&mut out, &diagnostic)
245 .unwrap();
246 println!("{out}");
247
248 Err(e)
249 }
250 }
251}
252
253fn output_saved_messages() {
254 let messages = get_logged_messages();
255
256 if !messages.is_empty() {
257 println!();
258 for msg in &messages {
259 println!(" • {msg}");
260 }
261 }
262}