mod action;
mod config;
mod prompt;
#[cfg(test)]
#[cfg(feature = "crossterm")]
mod test;
pub use action::*;
use chrono::NaiveDate;
use crate::{
config::get_configuration,
date_utils::get_current_date,
error::{InquireError, InquireResult},
formatter::{self, DateFormatter},
prompts::prompt::Prompt,
terminal::get_default_terminal,
ui::{date::DateSelectBackend, Backend, RenderConfig},
validator::DateValidator,
};
use self::prompt::DateSelectPrompt;
#[derive(Clone)]
pub struct DateSelect<'a> {
pub message: &'a str,
pub week_start: chrono::Weekday,
pub starting_date: NaiveDate,
pub min_date: Option<NaiveDate>,
pub max_date: Option<NaiveDate>,
pub help_message: Option<&'a str>,
pub formatter: DateFormatter<'a>,
pub validators: Vec<Box<dyn DateValidator>>,
pub render_config: RenderConfig<'a>,
}
impl<'a> DateSelect<'a> {
pub const DEFAULT_FORMATTER: DateFormatter<'a> = formatter::DEFAULT_DATE_FORMATTER;
pub const DEFAULT_VIM_MODE: bool = true;
pub const DEFAULT_HELP_MESSAGE: Option<&'a str> =
Some("arrows to move, []{} move months and years, enter to select");
pub const DEFAULT_VALIDATORS: Vec<Box<dyn DateValidator>> = vec![];
pub const DEFAULT_WEEK_START: chrono::Weekday = chrono::Weekday::Sun;
pub const DEFAULT_MIN_DATE: Option<NaiveDate> = None;
pub const DEFAULT_MAX_DATE: Option<NaiveDate> = None;
pub fn new(message: &'a str) -> Self {
Self {
message,
starting_date: get_current_date(),
min_date: Self::DEFAULT_MIN_DATE,
max_date: Self::DEFAULT_MAX_DATE,
help_message: Self::DEFAULT_HELP_MESSAGE,
formatter: Self::DEFAULT_FORMATTER,
validators: Self::DEFAULT_VALIDATORS,
week_start: Self::DEFAULT_WEEK_START,
render_config: get_configuration(),
}
}
pub fn with_help_message(mut self, message: &'a str) -> Self {
self.help_message = Some(message);
self
}
pub fn without_help_message(mut self) -> Self {
self.help_message = None;
self
}
pub fn with_default(self, default: NaiveDate) -> Self {
self.with_starting_date(default)
}
pub fn with_week_start(mut self, week_start: chrono::Weekday) -> Self {
self.week_start = week_start;
self
}
pub fn with_min_date(mut self, min_date: NaiveDate) -> Self {
self.min_date = Some(min_date);
self
}
pub fn with_max_date(mut self, max_date: NaiveDate) -> Self {
self.max_date = Some(max_date);
self
}
pub fn with_starting_date(mut self, starting_date: NaiveDate) -> Self {
self.starting_date = starting_date;
self
}
pub fn with_validator<V>(mut self, validator: V) -> Self
where
V: DateValidator + 'static,
{
self.validators.push(Box::new(validator));
self
}
pub fn with_validators(mut self, validators: &[Box<dyn DateValidator>]) -> Self {
for validator in validators {
self.validators.push(validator.clone());
}
self
}
pub fn with_formatter(mut self, formatter: DateFormatter<'a>) -> Self {
self.formatter = formatter;
self
}
pub fn with_render_config(mut self, render_config: RenderConfig<'a>) -> Self {
self.render_config = render_config;
self
}
pub fn prompt_skippable(self) -> InquireResult<Option<NaiveDate>> {
match self.prompt() {
Ok(answer) => Ok(Some(answer)),
Err(InquireError::OperationCanceled) => Ok(None),
Err(err) => Err(err),
}
}
pub fn prompt(self) -> InquireResult<NaiveDate> {
let (input_reader, terminal) = get_default_terminal()?;
let mut backend = Backend::new(input_reader, terminal, self.render_config)?;
self.prompt_with_backend(&mut backend)
}
pub(crate) fn prompt_with_backend<B: DateSelectBackend>(
self,
backend: &mut B,
) -> InquireResult<NaiveDate> {
DateSelectPrompt::new(self)?.prompt(backend)
}
}