jiq 3.22.1

Interactive JSON query tool with real-time output
Documentation
// Configuration module for jiq
// This module handles loading and parsing configuration from ~/.config/jiq/config.toml

pub mod ai_types;
mod types;

// AI types are used internally via Config struct
pub use types::{ClipboardBackend, Config};

#[allow(unused_imports)]
pub use types::AutocompleteConfig;

// Re-export for integration tests
#[allow(unused_imports)]
pub use ai_types::{AiConfig, AiProviderType, AnthropicConfig};
#[allow(unused_imports)]
pub use types::TooltipConfig;

use std::fs;
use std::path::PathBuf;

/// Result of loading configuration
pub struct ConfigResult {
    pub config: Config,
    pub warning: Option<String>,
}

/// Loads configuration from ~/.config/jiq/config.toml
/// Returns default configuration if file doesn't exist or on parse errors
pub fn load_config() -> ConfigResult {
    let config_path = get_config_path();
    log::debug!("Config path: {:?}", config_path);

    // If file doesn't exist, return defaults silently
    if !config_path.exists() {
        log::debug!("No config file found, using defaults");
        return ConfigResult {
            config: Config::default(),
            warning: None,
        };
    }

    // Try to read the file
    let contents = match fs::read_to_string(&config_path) {
        Ok(contents) => contents,
        Err(e) => {
            log::error!("Failed to read config file {:?}: {}", config_path, e);
            return ConfigResult {
                config: Config::default(),
                warning: Some(format!("Failed to read config: {}", e)),
            };
        }
    };

    // Try to parse TOML
    match toml::from_str::<Config>(&contents) {
        Ok(mut config) => {
            config.autocomplete.array_sample_size =
                config.autocomplete.array_sample_size.clamp(1, 1000);
            log::debug!(
                "Config: clipboard={:?}, ai.enabled={}, ai.provider={:?}, array_sample_size={}",
                config.clipboard.backend,
                config.ai.enabled,
                config.ai.provider,
                config.autocomplete.array_sample_size
            );
            ConfigResult {
                config,
                warning: None,
            }
        }
        Err(e) => {
            log::error!("Failed to parse config file {:?}: {}", config_path, e);
            ConfigResult {
                config: Config::default(),
                warning: Some(format!("Invalid config: {}", e)),
            }
        }
    }
}

/// Returns the path to the configuration file
///
/// Always uses ~/.config/jiq/config.toml on all platforms for consistency.
fn get_config_path() -> PathBuf {
    dirs::home_dir()
        .unwrap_or_else(|| PathBuf::from("."))
        .join(".config")
        .join("jiq")
        .join("config.toml")
}

#[cfg(test)]
#[path = "config_tests.rs"]
mod config_tests;