rmatrix 0.2.0

Matrix like animation running in terminal
Documentation
use std::{
    fs::{self, File},
    io,
    path::PathBuf,
};

use anyhow::{Context, Result};
use clap::Parser;
use directories::ProjectDirs;
use rmatrix::{Cli, app::App, term::CrosstermTerminal};
use time::OffsetDateTime;
use tracing::error;
use tracing_subscriber::EnvFilter;

fn main() -> Result<()> {
    let cli = Cli::parse();

    enable_logging(cli.log_file.as_ref()).context("Failed to enable logging")?;

    if let Err(err) = run(cli) {
        eprintln!("{:?}", err);
        error!("{}", err);
    }

    Ok(())
}

fn run(cli: Cli) -> Result<()> {
    App::builder()
        .rng(rand::rng())
        .terminal(
            CrosstermTerminal::builder()
                .stdout(io::stdout().lock())
                .maybe_head_color(cli.head_color)
                .maybe_tail_color(cli.tail_color)
                .build()
                .context("Failed to setup the terminal")?,
        )
        .sequence_height_bounds(10..=32)
        .maybe_speed(cli.speed)
        .build()
        .context("Failed to create the app")?
        .run()
        .context("Failed to run the app")
}

fn enable_logging(log_file_path: Option<impl Into<PathBuf>>) -> Result<()> {
    let log_path = if let Some(path) = log_file_path {
        path.into()
    } else {
        default_log_file_path().context("Failed to get default log file path")?
    };

    if let Some(parent) = log_path.parent() {
        fs::create_dir_all(parent).context("Failed to create logs directory")?;
    }

    let log_file = File::options()
        .append(true)
        .create(true)
        .open(log_path)
        .context("Failed to open log file")?;

    tracing_subscriber::fmt()
        .with_env_filter(EnvFilter::from_default_env())
        .json()
        .with_writer(log_file)
        .init();

    Ok(())
}

fn default_log_file_path() -> Result<PathBuf> {
    let now = OffsetDateTime::now_local().context("Failed to get local time")?;
    let path = ProjectDirs::from("app.augustyniak", "magmast", "rmatrix")
        .context("Failed to get project directories")?
        .data_local_dir()
        .join("logs")
        .join(format!("{}.log", now));
    Ok(path)
}