git-mit 5.12.207

Set author and Co-authored trailer.
use std::fmt::Display;

use miette::{Diagnostic, LabeledSpan, SourceCode};
use thiserror::Error;

#[derive(Error, Diagnostic, Debug)]
#[error("no repository")]
#[diagnostic(help("To add an author run `git mit` from a git repository"))]
pub struct NoRepository {}

#[derive(Error, Debug)]
#[error("could not find initial")]
pub struct UnknownAuthor {
    pub command: String,
    pub missing_initials: Vec<String>,
}

impl Diagnostic for UnknownAuthor {
    fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
        let mut tips = vec![
            "To see a summary of your configured authors run",
            "`git mit-config mit generate`",
            "To add a new author run",
            "`git mit-config mit set eg \"Egg Sample\" egg.sample@example.com`",
        ];

        if self.missing_initials.contains(&"config".to_string()) {
            tips.push("Did you mean `git mit-config`");
        }

        if self.missing_initials.contains(&"relates-to".to_string()) {
            tips.push("Did you mean `git mit-relates-to`");
        }

        if self.missing_initials.contains(&"install".to_string()) {
            tips.push("Did you mean `git mit-install`");
        }

        let help: String = tips.join(" ");

        Some(Box::new(help))
    }

    fn source_code(&self) -> Option<&dyn SourceCode> {
        Some(&self.command)
    }

    fn labels(&self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + '_>> {
        Some(Box::new(
            self.missing_initials
                .clone()
                .into_iter()
                .flat_map(|initial| {
                    let mut matches = self
                        .command
                        .match_indices(&format!(" {initial} "))
                        .map(|x| (x, initial.clone()))
                        .map(|(x, y)| ("Not found".to_string(), x.0 + 1, y.len()))
                        .map(|(label, pos, offset)| LabeledSpan::new(Some(label), pos, offset))
                        .collect::<Vec<_>>();

                    if self.command.ends_with(&initial) {
                        matches.push(LabeledSpan::new(
                            Some("Not found".to_string()),
                            self.command.len() - initial.len(),
                            initial.len(),
                        ));
                    }

                    matches
                })
                .collect::<Vec<LabeledSpan>>()
                .into_iter(),
        ))
    }
}