leadr 2.8.6

Shell aliases on steroids
Documentation
use std::io::Write;

use crossterm::style::Stylize;

use crate::{InsertType, Mapping, Symbols, Theme, mappings::MatchType};

pub struct Entry {
    pub styled_parts: Vec<crossterm::style::StyledContent<String>>,
}

impl Entry {
    pub fn new(
        key: &str,
        match_type: MatchType,
        width: u16,
        symbols: &Symbols,
        theme: &Theme,
    ) -> Self {
        let (mut label, flags, is_prefix) = match match_type {
            MatchType::Exact(mapping) => {
                let label = mapping
                    .description
                    .as_deref()
                    .unwrap_or(&mapping.command)
                    .to_string();
                let flags = format_flags(mapping, symbols);
                (label, flags, false)
            }
            MatchType::Prefix(count) => (format!("+{count} mappings"), " ".repeat(5), true),
            MatchType::None => ("(invalid)".into(), "".into(), true),
        };

        let raw_entry = format!("{key}{label} {flags}");
        let raw_entry_width = raw_entry.chars().count() as u16;

        let mut spacing = " ".to_string();
        if raw_entry_width > width {
            let entry_overflow = raw_entry_width - width;
            label = label
                .chars()
                .take(label.chars().count() - entry_overflow as usize - 2)
                .collect::<String>()
                + "";
        } else {
            let entry_underflow = width - raw_entry_width;
            spacing = " ".repeat(entry_underflow as usize);
        };
        let styled_label = if is_prefix {
            label
                .with(theme.text_primary.into())
                .on(theme.background.into())
        } else {
            label
                .with(theme.text_highlight_secondary.into())
                .on(theme.background.into())
        };

        let styled_parts = vec![
            key.to_string()
                .with(theme.text_primary.into())
                .on(theme.background.into()),
            format!(" {} ", symbols.arrow)
                .to_string()
                .with(theme.text_secondary.into())
                .on(theme.background.into()),
            styled_label,
            spacing.on(theme.background.into()),
            flags
                .with(theme.text_highlight_primary.into())
                .on(theme.background.into()),
        ];
        Self { styled_parts }
    }

    pub fn to_tty(&self, tty: &mut std::fs::File) -> std::io::Result<()> {
        for part in &self.styled_parts {
            write!(tty, "{part}")?;
        }
        Ok(())
    }
}

fn format_flags(mapping: &Mapping, symbols: &Symbols) -> String {
    let mut flags: Vec<&str> = vec![];

    match mapping.insert_type {
        InsertType::Replace => flags.push(&symbols.replace),
        InsertType::Insert => flags.push(&symbols.insert),
        InsertType::Append => flags.push(&symbols.append),
        InsertType::Prepend => flags.push(&symbols.prepend),
        InsertType::Surround => flags.push(&symbols.surround),
    }

    if mapping.evaluate {
        flags.push(&symbols.evaluate);
    } else {
        flags.push(" ");
    }

    if mapping.execute {
        flags.push(&symbols.execute);
    } else {
        flags.push(" ");
    }

    flags.join(" ")
}