tabiew 0.13.1

A lightweight TUI application to view and query tabular data files, such as CSV, TSV, and parquet.
use crate::{
    io::{DataSource, reader::FwfToDataFrame},
    tui::{
        pickers::text_picker::TextPicker,
        popups::{
            importers::{
                dismiss_overlay_and_load_data_frame,
                import_source_picker::{ImportSource, ImportSourcePicker},
            },
            multi_step_overlay::OverlayStep,
            path_picker::PathPicker,
            url_picker::UrlPicker,
            yes_no_picker::YesNoPicker,
        },
        widgets::input::InputType,
    },
};

#[derive(Debug)]
pub enum State {
    PickSource {
        picker: ImportSourcePicker,
    },
    PickPath {
        picker: PathPicker,
    },
    PickUrl {
        picker: UrlPicker,
    },
    PickWidths {
        source: DataSource,
        picker: TextPicker,
    },
    PickHeader {
        widths: Vec<usize>,
        source: DataSource,
        picker: YesNoPicker,
    },
    PickSeparatorLength {
        has_header: bool,
        widths: Vec<usize>,
        source: DataSource,
        picker: TextPicker,
    },
    PickFlexibleWidth {
        separator_length: usize,
        has_header: bool,
        widths: Vec<usize>,
        source: DataSource,
        picker: YesNoPicker,
    },
}

impl OverlayStep for State {
    fn next(self) -> Self {
        match self {
            State::PickSource { picker } => match picker.value() {
                Some(ImportSource::File) => State::PickPath {
                    picker: PathPicker::default(),
                },
                Some(ImportSource::Stdin) => State::PickWidths {
                    source: DataSource::Stdin,
                    picker: TextPicker::default()
                        .with_input_type(InputType::MultiNumeric)
                        .with_title("Widths")
                        .with_hint("4 8 12 or leave empty to auto detect"),
                },
                Some(ImportSource::Url) => State::PickUrl {
                    picker: UrlPicker::default(),
                },
                None => State::PickSource { picker },
            },
            State::PickPath { picker } => State::PickWidths {
                source: DataSource::File(picker.path()),
                picker: TextPicker::default()
                    .with_input_type(InputType::MultiNumeric)
                    .with_title("Widths")
                    .with_hint("4 8 12 or leave empty to auto detect"),
            },
            State::PickUrl { picker } => State::PickWidths {
                source: DataSource::Url(picker.url()),
                picker: TextPicker::default()
                    .with_input_type(InputType::MultiNumeric)
                    .with_title("Widths")
                    .with_hint("4 8 12 or leave empty to auto detect"),
            },
            State::PickWidths { source, picker } => {
                let widths = picker
                    .value()
                    .split(' ')
                    .map(|s| s.parse())
                    .collect::<Result<_, _>>()
                    .unwrap_or_default();
                State::PickHeader {
                    widths,
                    source,
                    picker: YesNoPicker::default().with_title("Has Header"),
                }
            }
            State::PickHeader {
                widths,
                source,
                picker,
            } => match picker.value() {
                Some(has_header) => State::PickSeparatorLength {
                    has_header,
                    widths,
                    source,
                    picker: TextPicker::default()
                        .with_input_type(InputType::Numeric)
                        .with_title("Separator Legnth"),
                },
                None => State::PickHeader {
                    widths,
                    source,
                    picker,
                },
            },
            State::PickSeparatorLength {
                has_header,
                widths,
                source,
                picker,
            } => {
                let separator_length = picker.value().parse().unwrap_or(0);
                State::PickFlexibleWidth {
                    separator_length,
                    has_header,
                    widths,
                    source,
                    picker: YesNoPicker::default().with_title("Flexible Width"),
                }
            }
            State::PickFlexibleWidth {
                separator_length,
                has_header,
                widths,
                source,
                picker,
            } => {
                let flexible_width = picker.value().unwrap_or(true);
                let rtdf = FwfToDataFrame::default()
                    .with_flexible_width(flexible_width)
                    .with_has_header(has_header)
                    .with_separator_length(separator_length)
                    .with_widths(widths);
                dismiss_overlay_and_load_data_frame(source, rtdf);
                Default::default()
            }
        }
    }

    fn responder(&mut self) -> &mut dyn crate::tui::component::Component {
        match self {
            State::PickSource { picker } => picker,
            State::PickPath { picker } => picker,
            State::PickWidths { source: _, picker } => picker,
            State::PickHeader {
                widths: _,
                source: _,
                picker,
            } => picker,
            State::PickSeparatorLength {
                has_header: _,
                widths: _,
                source: _,
                picker,
            } => picker,
            State::PickFlexibleWidth {
                separator_length: _,
                has_header: _,
                widths: _,
                source: _,
                picker,
            } => picker,
            State::PickUrl { picker } => picker,
        }
    }
}

impl Default for State {
    fn default() -> Self {
        Self::PickSource {
            picker: Default::default(),
        }
    }
}