use crate::form::{FormKey, PickerKey};
use crate::retype_modal::{Chosen, CombineField, CombineModal, RetypeModal};
use crate::{App, AppEvent, InputMode};
use crossterm::event::{KeyCode, KeyEvent};
use polars::prelude::DataType;
const EXAMPLES: usize = 20;
impl App {
pub(crate) fn menu_action(&mut self, action: crate::context_menu::MenuAction) {
let Some(column) = self
.data_table_state
.as_ref()
.and_then(|s| s.current_column().map(str::to_string))
else {
return;
};
match action {
crate::context_menu::MenuAction::ChangeType => self.open_retype(&column),
crate::context_menu::MenuAction::CombineDatetime => self.open_combine(&column),
}
}
pub(crate) fn open_retype(&mut self, column: &str) {
let Some(state) = self.data_table_state.as_ref() else {
return;
};
let Some(as_read) = state.type_as_read(column) else {
return;
};
let current = state.column_type_of(column).cloned();
let examples = state.values_on_screen(column, EXAMPLES);
self.retype = Some(RetypeModal::new(
column.to_string(),
as_read,
current.as_ref(),
examples,
));
self.retype_from_info = self.input_mode == InputMode::Info;
self.input_mode = InputMode::Retype;
}
pub(crate) fn open_combine(&mut self, date: &str) {
let Some(state) = self.data_table_state.as_ref() else {
return;
};
let schema = state.schema().clone();
let columns: Vec<String> = schema
.iter()
.filter(|(_, dtype)| {
matches!(dtype, DataType::String | DataType::Date | DataType::Time)
})
.map(|(name, _)| name.to_string())
.collect();
let taken: Vec<String> = schema.iter_names().map(|n| n.to_string()).collect();
self.combine = Some(CombineModal::new(date.to_string(), columns, &taken));
self.retype_from_info = self.input_mode == InputMode::Info;
self.input_mode = InputMode::Combine;
}
fn close_retype(&mut self) {
self.retype = None;
self.combine = None;
self.input_mode = if self.retype_from_info {
InputMode::Info
} else {
InputMode::Normal
};
}
pub(crate) fn retype_key(&mut self, event: &KeyEvent) -> Option<AppEvent> {
let modal = self.retype.as_mut()?;
match event.code {
KeyCode::Esc => {
if !modal.back() {
self.close_retype();
}
}
KeyCode::Enter => match modal.choose() {
Chosen::Nothing | Chosen::Format => {}
Chosen::AsRead => {
let column = modal.column.clone();
self.close_retype();
self.retype_column(&column, None);
}
Chosen::Type(ty) => {
let column = modal.column.clone();
self.close_retype();
self.retype_column(&column, Some(ty));
}
},
KeyCode::Up => modal.picker.move_up(),
KeyCode::Down => modal.picker.move_down(),
KeyCode::Backspace => modal.picker.backspace(),
KeyCode::Char(c) => modal.picker.filter_key(c, event.modifiers),
_ => {}
}
None
}
pub(crate) fn retype_column(
&mut self,
column: &str,
ty: Option<crate::column_types::ColumnType>,
) {
let Some(state) = self.data_table_state.as_mut() else {
return;
};
state.set_column_type(column, ty);
self.count_unfit();
}
pub(crate) fn combine_key(&mut self, event: &KeyEvent) -> Option<AppEvent> {
let modal = self.combine.as_mut()?;
if let Some((_, picker)) = modal.picker.as_mut() {
match crate::form::picker_key(picker, false, event) {
PickerKey::Close => modal.picker = None,
PickerKey::Choose | PickerKey::Toggle => modal.picker_choose(),
PickerKey::ChooseAndMove(forward) => {
modal.picker_choose();
crate::form::Form::move_focus(modal, if forward { 1 } else { -1 });
}
PickerKey::Handled | PickerKey::Other => {}
}
return None;
}
modal.problem = None;
match crate::form::key(modal, event) {
FormKey::Cancel => self.close_retype(),
FormKey::Submit => {
let derived = match modal.derived() {
Ok(derived) => derived,
Err(problem) => {
modal.problem = Some(problem);
return None;
}
};
let made = self
.data_table_state
.as_mut()
.map(|state| state.add_made_column(derived));
match made {
Some(Err(problem)) => {
if let Some(modal) = self.combine.as_mut() {
modal.problem = Some(problem);
}
}
_ => self.close_retype(),
}
}
FormKey::Step(CombineField::Kind, delta) => modal.step_kind(delta),
FormKey::Act(CombineField::Kind) => modal.step_kind(1),
FormKey::Act(_) | FormKey::Step(_, _) => {
if modal.focus != CombineField::Name {
modal.open_picker();
}
}
FormKey::Text(CombineField::Name) => match event.code {
KeyCode::Char(c) => modal.name.push(c),
KeyCode::Backspace => {
modal.name.pop();
}
_ => {}
},
_ => {}
}
None
}
}