use crate::domain::{CommitMessage, CommitType};
use crate::input::interactive::InteractiveError;
use crate::ports::ui::Ui;
pub fn collect_type<U: Ui>(ui: &U) -> Result<CommitType, InteractiveError> {
ui.println("1. Commit type:");
ui.println(" feat — new feature");
ui.println(" fix — bug fix");
ui.println(" docs — documentation only");
ui.println(" style — formatting, whitespace");
ui.println(" refactor — code restructuring");
ui.println(" perf — performance improvement");
ui.println(" test — adding or fixing tests");
ui.println(" build — build system / dependencies");
ui.println(" ci — CI configuration");
ui.println(" chore — maintenance");
ui.println(" revert — revert a previous commit");
ui.println("");
loop {
let input = ui.prompt("Type: ").map_err(InteractiveError::Ui)?;
match CommitType::from_str(&input) {
Ok(ct) => {
ui.println("");
return Ok(ct);
}
Err(_) => {
ui.println(&format!(
" ✗ '{}' is not valid. Choose from the list above.",
input
));
}
}
}
}
pub fn collect_scope<U: Ui>(ui: &U) -> Result<Option<String>, InteractiveError> {
ui.println("2. Scope (optional — press Enter to skip):");
ui.println(" e.g. api, parser, auth-service");
ui.println("");
loop {
let input = ui.prompt("Scope: ").map_err(InteractiveError::Ui)?;
if input.is_empty() {
ui.println("");
return Ok(None);
}
match CommitMessage::validate_scope(&input) {
Ok(()) => {
ui.println("");
return Ok(Some(input));
}
Err(_) => {
ui.println(" ✗ Scope must be alphanumeric with hyphens/underscores only.");
}
}
}
}
pub fn collect_description<U: Ui>(ui: &U) -> Result<String, InteractiveError> {
ui.println("3. Description (max 72 characters):");
ui.println("");
loop {
let input = ui.prompt("Description: ").map_err(InteractiveError::Ui)?;
if input.is_empty() {
ui.println(" ✗ Description cannot be empty.");
continue;
}
if input.len() > 72 {
ui.println(&format!(
" ✗ {}/72 characters — too long. Please shorten.",
input.len()
));
continue;
}
ui.println("");
return Ok(input);
}
}