tabiew 0.13.1

A lightweight TUI application to view and query tabular data files, such as CSV, TSV, and parquet.
use std::fmt::Display;

use polars::frame::DataFrame;
use strum::IntoEnumIterator;
use strum_macros::{EnumIter, IntoStaticStr};

use crate::tui::{
    component::Component,
    pickers::search_picker::SearchPicker,
    popups::{
        exporters::{arrow, avro, csv, json, jsonl, parquet, tsv},
        multi_step_overlay::{MultiStepOverlay, OverlayStep},
    },
};

pub type Exporter = MultiStepOverlay<State>;

#[derive(Debug)]
pub enum State {
    PickFormat {
        df: DataFrame,
        picker: SearchPicker<Format>,
    },
    Arrow {
        state: arrow::State,
    },
    Avro {
        state: avro::State,
    },
    Csv {
        state: csv::State,
    },
    Json {
        state: json::State,
    },
    JsonL {
        state: jsonl::State,
    },
    Parquet {
        state: parquet::State,
    },
    Tsv {
        state: tsv::State,
    },
}

impl From<DataFrame> for State {
    fn from(value: DataFrame) -> Self {
        State::PickFormat {
            df: value,
            picker: SearchPicker::new(Format::iter().collect()).with_title("Format"),
        }
    }
}

impl OverlayStep for State {
    fn next(self) -> Self {
        match self {
            State::PickFormat { df, picker } => match picker.selected_item() {
                Some(Format::Arrow) => State::Arrow { state: df.into() },
                Some(Format::Avro) => State::Avro { state: df.into() },
                Some(Format::Csv) => State::Csv { state: df.into() },
                Some(Format::Json) => State::Json { state: df.into() },
                Some(Format::JsonL) => State::JsonL { state: df.into() },
                Some(Format::Parquet) => State::Parquet { state: df.into() },
                Some(Format::Tsv) => State::Tsv { state: df.into() },
                None => State::PickFormat { df, picker },
            },
            State::Arrow { state } => State::Arrow {
                state: state.next(),
            },
            State::Avro { state } => State::Avro {
                state: state.next(),
            },
            State::Csv { state } => State::Csv {
                state: state.next(),
            },
            State::Json { state } => State::Json {
                state: state.next(),
            },
            State::JsonL { state } => State::JsonL {
                state: state.next(),
            },
            State::Parquet { state } => State::Parquet {
                state: state.next(),
            },
            State::Tsv { state } => State::Tsv {
                state: state.next(),
            },
        }
    }

    fn responder(&mut self) -> &mut dyn Component {
        match self {
            State::PickFormat { df: _, picker } => picker,
            State::Arrow { state } => state.responder(),
            State::Avro { state } => state.responder(),
            State::Csv { state } => state.responder(),
            State::Json { state } => state.responder(),
            State::JsonL { state } => state.responder(),
            State::Parquet { state } => state.responder(),
            State::Tsv { state } => state.responder(),
        }
    }
}

#[derive(Debug, IntoStaticStr, EnumIter, PartialEq)]
pub enum Format {
    Csv,
    Tsv,
    Parquet,
    Json,
    JsonL,
    Arrow,
    Avro,
}

impl Display for Format {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", Into::<&str>::into(self))
    }
}