flk 0.6.3

A CLI tool for managing flake.nix devShell environments
Documentation
//! # Visual Output Utilities
//!
//! Terminal formatting, progress indicators, and display helpers.
//!
//! This module provides consistent styling for CLI output including
//! colored text, spinners, and formatted lists/tables.

use crate::flake::interfaces::profiles::Package;
use crate::utils::flk_spinner::{Spinner, Style};
use anyhow::Result;
use colored::Colorize;

/// Execute a function with Flik thinking on screen.
///
/// Shows the Flik mascot pondering (with an assembling snowflake) while the
/// function runs. The spinner is cleared after completion, regardless of
/// whether the closure returned Ok or Err — call sites stay responsible for
/// their own success/failure messaging.
///
/// # Example
///
/// ```rust,ignore
/// let result = with_spinner("Searching packages...", || {
///     search_nixpkgs("ripgrep")
/// })?;
/// ```
pub fn with_spinner<F, T>(message: &str, f: F) -> Result<T>
where
    F: FnOnce() -> Result<T>,
{
    let spinner = Spinner::start(message, Style::Thinking);
    let result = f();
    spinner.stop();
    result
}

/// Display a numbered list of packages.
///
/// Each package is shown with an index number and optional version.
pub fn display_list(packages: &[Package]) -> String {
    if packages.is_empty() {
        return String::new();
    }

    let mut output = String::new();

    for (i, pkg) in packages.iter().enumerate() {
        output.push_str(&format!(
            "{} {}\n",
            format!("[{}]", i + 1).cyan().bold(),
            pkg.name.green()
        ));

        if let Some(version) = &pkg.version {
            output.push_str(&format!("  {} {}\n", "Version:".bold(), version.yellow()));
        }

        output.push('\n');
    }

    output
}

/// Display packages in a table format with columns.
///
/// Shows package names and versions in aligned columns.
pub fn display_table(packages: &[Package]) -> String {
    if packages.is_empty() {
        return String::new();
    }

    let max_name_len = packages
        .iter()
        .map(|p| p.name.len())
        .max()
        .unwrap_or(0)
        .max(4);

    let mut output = format!("{:<width$}  Version\n", "Name", width = max_name_len);

    for pkg in packages {
        if let Some(version) = &pkg.version {
            output.push_str(&format!(
                "{:<width$}  {}\n",
                pkg.name.cyan().bold(),
                version.bright_black(),
                width = max_name_len
            ));
        } else {
            output.push_str(&format!("{}\n", pkg.name.cyan().bold()));
        }
    }

    output
}