This commit is contained in:
69
src/interactive.rs
Normal file
69
src/interactive.rs
Normal file
@@ -0,0 +1,69 @@
|
||||
use dialoguer::{Confirm, MultiSelect, Input, Select};
|
||||
use crate::convention::CommitType;
|
||||
use crate::error::Result;
|
||||
|
||||
pub struct InteractivePrompter;
|
||||
|
||||
impl InteractivePrompter {
|
||||
pub fn new() -> Self { Self }
|
||||
|
||||
pub fn select_commit_type(&self, detected_type: &CommitType, all_types: &[CommitType]) -> Result<CommitType> {
|
||||
println!("Detected commit type: {}", detected_type);
|
||||
let type_names: Vec<String> = all_types.iter().map(|t| t.to_string()).collect();
|
||||
let items: Vec<&str> = type_names.iter().map(|s| s.as_str()).collect();
|
||||
println!("\nSelect commit type:");
|
||||
let selected = Select::new().with_prompt("Choose type").items(&items).default(0).interact()?;
|
||||
Ok(all_types[selected].clone())
|
||||
}
|
||||
|
||||
pub fn confirm_scope(&self, suggested_scope: &str, available_scopes: &[String]) -> Result<Option<String>> {
|
||||
println!("\nSuggested scope: {}", suggested_scope);
|
||||
let mut options = vec!["Use suggested scope", "Enter custom scope", "No scope"];
|
||||
options.extend(available_scopes.iter().map(|s| s.as_str()));
|
||||
let selected = Select::new().with_prompt("Choose scope").items(&options).default(0).interact()?;
|
||||
match selected {
|
||||
0 => Ok(Some(suggested_scope.to_string())),
|
||||
1 => {
|
||||
let input: String = Input::new().with_prompt("Enter custom scope").interact_text()?;
|
||||
Ok(if input.trim().is_empty() { None } else { Some(input) })
|
||||
}
|
||||
2 => Ok(None),
|
||||
_ => {
|
||||
let idx = selected - 3;
|
||||
Ok(if idx < available_scopes.len() { Some(available_scopes[idx].clone()) } else { None })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn confirm_description(&self, suggested: &str) -> Result<String> {
|
||||
let input: String = Input::new().with_prompt("Commit description").with_initial_text(suggested).interact_text()?;
|
||||
Ok(input)
|
||||
}
|
||||
|
||||
pub fn confirm_commit(&self, commit_message: &str) -> Result<bool> {
|
||||
println!("\nGenerated commit message:\n {}", commit_message);
|
||||
Confirm::new().with_prompt("Use this commit message?").default(true).interact()
|
||||
.map_err(|e| crate::error::Error::Other(e.to_string()))
|
||||
}
|
||||
|
||||
pub fn select_type_interactively(&self, suggestions: &[(CommitType, f64)]) -> Result<CommitType> {
|
||||
let items: Vec<String> = suggestions.iter().map(|(t, conf)| format!("{} ({:.0}%)", t, conf * 100.0)).collect();
|
||||
let selected = MultiSelect::new().with_prompt("Select commit types").items(&items.iter().map(|s| s.as_str()).collect::<Vec<&str>>()).interact()?;
|
||||
if selected.is_empty() { return Ok(CommitType::Chore); }
|
||||
Ok(suggestions[selected[0]].0.clone())
|
||||
}
|
||||
|
||||
pub fn show_alternatives(&self, alternatives: &[String]) -> Result<Option<usize>> {
|
||||
if alternatives.is_empty() { return Ok(None); }
|
||||
let selected = Select::new().with_prompt("Multiple possibilities detected. Choose one:").items(&alternatives.iter().map(|s| s.as_str()).collect::<Vec<&str>>()).default(0).interact()?;
|
||||
Ok(Some(selected))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)] mod tests {
|
||||
use super::*;
|
||||
#[test] fn test_interactive_prompter_new() {
|
||||
let prompter = InteractivePrompter::new();
|
||||
assert!(prompter.select_commit_type(&CommitType::Feat, &[CommitType::Feat, CommitType::Fix]).is_ok());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user