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 strum::IntoEnumIterator;
use strum_macros::{EnumIter, IntoStaticStr};

use crate::tui::{
    pickers::search_picker::SearchPicker,
    popups::{
        importers::{arrow, avro, csv, excel, fwf, json, jsonl, logfmt, parquet, sqlite, tsv},
        multi_step_overlay::{MultiStepOverlay, OverlayStep},
    },
};

pub type Importer = MultiStepOverlay<State>;

#[derive(Debug)]
pub enum State {
    PickFormat { picker: SearchPicker<Format> },
    Arrow { arrow: arrow::State },
    Avro { avro: avro::State },
    Csv { csv: csv::State },
    Excel { excel: excel::State },
    Fwf { fwf: fwf::State },
    Json { json: json::State },
    JsonL { jsonl: jsonl::State },
    Parquet { parquet: parquet::State },
    Sqlite { sqlite: sqlite::State },
    Tsv { tsv: tsv::State },
    Logfmt { logfmt: logfmt::State },
}

impl OverlayStep for State {
    fn next(self) -> Self {
        match self {
            State::PickFormat { picker } => match picker.selected_item() {
                Some(Format::Arrow) => State::Arrow {
                    arrow: Default::default(),
                },
                Some(Format::Avro) => State::Avro {
                    avro: Default::default(),
                },
                Some(Format::Csv) => Self::Csv {
                    csv: Default::default(),
                },
                Some(Format::Excel) => Self::Excel {
                    excel: Default::default(),
                },
                Some(Format::Fwf) => Self::Fwf {
                    fwf: Default::default(),
                },
                Some(Format::Json) => Self::Json {
                    json: Default::default(),
                },
                Some(Format::Jsonl) => Self::JsonL {
                    jsonl: Default::default(),
                },
                Some(Format::Parquet) => Self::Parquet {
                    parquet: Default::default(),
                },
                Some(Format::Sqlite) => Self::Sqlite {
                    sqlite: Default::default(),
                },
                Some(Format::Tsv) => Self::Tsv {
                    tsv: Default::default(),
                },
                Some(Format::Logfmt) => Self::Logfmt {
                    logfmt: Default::default(),
                },
                None => State::PickFormat { picker },
            },
            State::Arrow { arrow } => State::Arrow {
                arrow: arrow.next(),
            },
            State::Avro { avro } => State::Avro { avro: avro.next() },
            State::Csv { csv } => State::Csv { csv: csv.next() },
            State::Excel { excel } => State::Excel {
                excel: excel.next(),
            },
            State::Fwf { fwf } => State::Fwf { fwf: fwf.next() },
            State::Json { json } => State::Json { json: json.next() },
            State::JsonL { jsonl } => State::JsonL {
                jsonl: jsonl.next(),
            },
            State::Parquet { parquet } => State::Parquet {
                parquet: parquet.next(),
            },
            State::Sqlite { sqlite } => State::Sqlite {
                sqlite: sqlite.next(),
            },
            State::Tsv { tsv } => State::Tsv { tsv: tsv.next() },
            State::Logfmt { logfmt } => State::Logfmt {
                logfmt: logfmt.next(),
            },
        }
    }

    fn responder(&mut self) -> &mut dyn crate::tui::component::Component {
        match self {
            State::PickFormat { picker } => picker,
            State::Arrow { arrow } => arrow.responder(),
            State::Avro { avro } => avro.responder(),
            State::Csv { csv } => csv.responder(),
            State::Excel { excel } => excel.responder(),
            State::Fwf { fwf } => fwf.responder(),
            State::Json { json } => json.responder(),
            State::JsonL { jsonl } => jsonl.responder(),
            State::Parquet { parquet } => parquet.responder(),
            State::Sqlite { sqlite } => sqlite.responder(),
            State::Tsv { tsv } => tsv.responder(),
            State::Logfmt { logfmt } => logfmt.responder(),
        }
    }
}

impl Default for State {
    fn default() -> Self {
        Self::PickFormat {
            picker: SearchPicker::new(Format::iter().collect()),
        }
    }
}

#[derive(Debug, Clone, Copy, IntoStaticStr, EnumIter)]
pub enum Format {
    Csv,
    Tsv,
    Parquet,
    Jsonl,
    Json,
    Arrow,
    Avro,
    Fwf,
    Sqlite,
    Excel,
    Logfmt,
}

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