tabiew 0.13.1

A lightweight TUI application to view and query tabular data files, such as CSV, TSV, and parquet.
use std::{
    fs,
    ops::Deref,
    sync::{
        OnceLock, RwLock,
        atomic::{AtomicBool, Ordering},
    },
};

use serde::{Deserialize, Serialize};

use crate::{AppResult, misc::paths::config_path, tui::themes::theme::LoadedTheme};

use super::type_ext::UnwrapOrGracefulShutdown;

#[derive(Debug, Serialize, Deserialize)]
#[serde(default)]
pub struct Config {
    theme: RwLock<LoadedTheme>,
    show_table_borders: AtomicBool,
    show_table_row_numbers: AtomicBool,
}

impl Config {
    pub fn reload(&self) -> AppResult<()> {
        let path = config_path()?;
        let contents = fs::read_to_string(path)?;
        let Config {
            theme,
            show_table_borders: table_borders,
            show_table_row_numbers: table_row_numbers,
        } = toml::from_str(&contents)?;
        self.set_theme(theme.into_inner()?);
        self.show_table_borders
            .swap(table_borders.into_inner(), Ordering::Relaxed);
        self.show_table_row_numbers
            .swap(table_row_numbers.into_inner(), Ordering::Relaxed);
        Ok(())
    }

    pub fn store(&self) -> AppResult<()> {
        let config_path = config_path()?;
        if let Some(parent) = config_path.parent() {
            fs::create_dir_all(parent)?;
        }
        let contents = toml::to_string_pretty(self)?;
        Ok(fs::write(config_path, contents)?)
    }

    pub fn theme(&self) -> impl Deref<Target = LoadedTheme> {
        self.theme.read().unwrap_or_graceful_shutdown()
    }

    pub fn set_theme(&self, theme: impl Into<LoadedTheme>) {
        *self.theme.write().unwrap_or_graceful_shutdown() = theme.into();
    }

    pub fn show_table_borders(&self) -> bool {
        self.show_table_borders.load(Ordering::Relaxed)
    }

    pub fn toggle_show_table_borders(&self) {
        self.show_table_borders.fetch_xor(true, Ordering::Relaxed);
    }

    pub fn show_table_row_numbers(&self) -> bool {
        self.show_table_row_numbers.load(Ordering::Relaxed)
    }

    pub fn toggle_show_table_row_numbers(&self) {
        self.show_table_row_numbers
            .fetch_xor(true, Ordering::Relaxed);
    }
}

impl Default for Config {
    fn default() -> Self {
        Self {
            theme: RwLock::new(LoadedTheme::default()),
            show_table_borders: AtomicBool::new(true),
            show_table_row_numbers: AtomicBool::new(true),
        }
    }
}

pub fn config() -> &'static Config {
    static CONFIG: OnceLock<Config> = OnceLock::new();
    CONFIG.get_or_init(Config::default)
}

pub fn theme() -> impl Deref<Target = LoadedTheme> {
    config().theme()
}