mod buffer;
mod commands;
mod core;
mod infrastructure;
#[cfg(feature = "analyzer")]
pub mod analyzer;
#[cfg(feature = "lsp")]
pub mod lsp;
use commands::{handle_in_memory, process_mode_and_handle, process_mode_and_handle_with_options};
use console::style;
use core::{compiled_css::CompiledCssInMemory, config::ConfigInMemory};
use indicatif::{ProgressBar, ProgressStyle};
use infrastructure::{GrimoireCssDiagnostic, LightningCssOptimizer};
use miette::GraphicalReportHandler;
use std::path::Path;
use std::time::{Duration, Instant};
pub use core::{GrimoireCssError, color, component, config, spell::Spell};
static GRIMM_CALM: &str = " |(• ε •)|";
static GRIMM_HAPPY: &str = " ヽ(• ε •)ノ";
static GRIMM_CURSED: &str = " |(x ~ x)|";
static GRIMM_CASTING: [&str; 8] = [
GRIMM_CALM,
" (|¬ヘ¬)|",
" \\(°o°)/",
" (∩¬ロ¬)⊃━▪ ~",
" (∩¬ロ¬)⊃━▪ ~·",
" (∩¬ロ¬)⊃━▪ ~·•",
" (∩¬ロ¬)⊃━▪ ~·•●",
GRIMM_HAPPY,
];
pub fn start(mode: &str) -> Result<(), GrimoireCssError> {
let current_dir = std::env::current_dir()?;
let css_optimizer = LightningCssOptimizer::new(¤t_dir)?;
process_mode_and_handle(mode, ¤t_dir, &css_optimizer)
}
pub fn start_in_memory(
config: &ConfigInMemory,
) -> Result<Vec<CompiledCssInMemory>, GrimoireCssError> {
let css_optimizer = LightningCssOptimizer::new_from(
config.browserslist_content.as_deref().unwrap_or_default(),
)?;
handle_in_memory(config, &css_optimizer)
}
#[cfg(feature = "analyzer")]
pub fn start_in_memory_pretty(
config: &ConfigInMemory,
) -> Result<Vec<CompiledCssInMemory>, GrimoireCssError> {
let css_optimizer = LightningCssOptimizer::new_from_with_printer_minify(
config.browserslist_content.as_deref().unwrap_or_default(),
false,
)?;
handle_in_memory(config, &css_optimizer)
}
pub fn get_logged_messages() -> Vec<String> {
buffer::read_messages()
}
pub fn start_as_cli(args: Vec<String>) -> Result<(), GrimoireCssError> {
let bin_name = args
.first()
.and_then(|s| Path::new(s).file_name())
.and_then(|n| n.to_str())
.unwrap_or("grimoire_css");
let help_text = || {
let usage = ["grimoire_css", "grim"]
.into_iter()
.map(|n| format!(" {n} <mode> [mode args]"))
.collect::<Vec<_>>()
.join("\n");
format!(
"Usage:\n{usage}\n\nModes:\n build\n init\n shorten\n fi\n\nUtilities:\n -h, --help Print help\n -V, --version Print version\n"
)
};
if args.get(1).is_some_and(|a| a == "--version" || a == "-V") {
println!("{bin_name} {}", env!("CARGO_PKG_VERSION"));
return Ok(());
}
if args
.get(1)
.is_some_and(|a| a == "--help" || a == "-h" || a == "help")
{
println!("{}", help_text());
return Ok(());
}
if args.get(1).is_some_and(|m| m == "fi") {
return commands::fi::run_fi_cli(args);
}
println!();
println!(
"{} Ritual initiated",
style(" Grimoire CSS ").white().on_color256(55).bright(),
);
if args.len() < 2 {
let message = format!(
"{} {} ",
style(" Cursed! ").white().on_red().bright(),
format_args!("No mode provided")
);
println!();
println!("{GRIMM_CURSED}");
println!();
println!("{message}");
println!();
println!("{}", help_text());
return Err(GrimoireCssError::InvalidInput(message));
}
println!();
let pb = ProgressBar::new_spinner();
pb.set_style(ProgressStyle::default_spinner().tick_strings(&GRIMM_CASTING));
pb.enable_steady_tick(Duration::from_millis(220));
pb.set_draw_target(indicatif::ProgressDrawTarget::stdout_with_hz(10));
let start_time = Instant::now();
let mode = args[1].as_str();
let cli_options = commands::CliOptions {
force_version_update: mode == "build" && args.iter().any(|a| a == "--force-version-update"),
};
let current_dir = std::env::current_dir()?;
let css_optimizer = LightningCssOptimizer::new(¤t_dir)?;
match process_mode_and_handle_with_options(mode, ¤t_dir, &css_optimizer, cli_options) {
Ok(_) => {
pb.finish_and_clear();
print!("\r\x1b[2K{GRIMM_HAPPY} Spells cast successfully.\n");
let duration = start_time.elapsed();
output_saved_messages();
println!();
println!(
"{}",
style(format!(
"{}",
style(format!(" Enchanted in {duration:.2?}! "))
.white()
.on_color256(55)
.bright(),
))
);
println!();
Ok(())
}
Err(e) => {
pb.finish_and_clear();
print!("\r\x1b[2K{GRIMM_CURSED}\n");
println!();
println!("{}", style(" Cursed! ").white().on_red().bright());
println!();
let diagnostic: GrimoireCssDiagnostic = (&e).into();
let mut out = String::new();
GraphicalReportHandler::new()
.render_report(&mut out, &diagnostic)
.unwrap();
println!("{out}");
Err(e)
}
}
}
fn output_saved_messages() {
let messages = get_logged_messages();
if !messages.is_empty() {
println!();
for msg in &messages {
println!(" • {msg}");
}
}
}