injm 0.6.0

A CLI tool that injects content into marked regions in source files.
use crate::cli::ListArgs;
use crate::output::print;
use crate::parser::parse_patterns;
use crate::types::BlockRole;
use anyhow::Result;
use core::fmt;
use serde::Serialize;
use tabled::Tabled;

#[derive(Serialize, Tabled)]
pub struct MarkerInfo {
    #[tabled(rename = "File")]
    pub file: String,

    #[tabled(rename = "ID")]
    pub id: String,

    #[tabled(rename = "Type")]
    pub marker_type: MarkerType,

    #[tabled(rename = "Lines")]
    pub lines: String,
}

#[derive(Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum MarkerType {
    Input,
    Output,
}

impl fmt::Display for MarkerType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            MarkerType::Input => write!(f, "input"),
            MarkerType::Output => write!(f, "output"),
        }
    }
}

pub fn run(args: ListArgs) -> Result<()> {
    // If the input is empty, then fallback to current directory (`.`)
    let input: Vec<String> = if args.input.is_empty() {
        vec![".".to_string()]
    } else {
        args.input
    };

    // Get all input and output blocks.
    let mut rows = Vec::new();

    let files = parse_patterns(&input)?;
    for file in &files {
        for block in &file.blocks {
            match &block.role {
                BlockRole::Input { ids, .. } => {
                    for id in ids {
                        rows.push(MarkerInfo {
                            file: file.path.display().to_string(),
                            marker_type: MarkerType::Input,
                            id: id.clone(),
                            lines: block.span.display_lines(),
                        });
                    }
                }
                BlockRole::Output { id } => {
                    if let Some(id) = id {
                        rows.push(MarkerInfo {
                            file: file.path.display().to_string(),
                            marker_type: MarkerType::Output,
                            id: id.clone(),
                            lines: block.span.display_lines(),
                        });
                    }
                }
            }
        }
    }

    // Display input and output blocks, including
    // Path, ID, input/output.
    print(&rows, args.format)?;

    Ok(())
}