Skip to main content

xls_rs/
config.rs

1//! Configuration file support for xls-rs
2//!
3//! Supports loading default options from ~/.xls-rs.toml or .xls-rs.toml
4//!
5//! For backward compatibility, legacy config locations from older releases are still supported.
6
7use anyhow::Result;
8use serde::{Deserialize, Serialize};
9use std::path::PathBuf;
10
11/// Configuration for xls-rs CLI
12#[derive(Debug, Clone, Serialize, Deserialize, Default)]
13pub struct Config {
14    /// Default output format (csv, json, markdown)
15    #[serde(default)]
16    pub default_format: Option<String>,
17
18    /// Default date format for parsing
19    #[serde(default)]
20    pub date_format: Option<String>,
21
22    /// Default output directory for batch operations
23    #[serde(default)]
24    pub output_dir: Option<String>,
25
26    /// Excel styling options
27    #[serde(default)]
28    pub excel: ExcelConfig,
29
30    /// CSV options
31    #[serde(default)]
32    pub csv: CsvConfig,
33
34    /// Google Sheets API options
35    #[serde(default)]
36    pub google_sheets: GoogleSheetsConfig,
37}
38
39/// Excel-specific configuration
40#[derive(Debug, Clone, Serialize, Deserialize, Default)]
41pub struct ExcelConfig {
42    /// Default header style
43    #[serde(default)]
44    pub header_bold: Option<bool>,
45
46    /// Header background color (hex like "4472C4")
47    #[serde(default)]
48    pub header_bg_color: Option<String>,
49
50    /// Header font color (hex)
51    #[serde(default)]
52    pub header_font_color: Option<String>,
53
54    /// Enable auto-filter on headers
55    #[serde(default)]
56    pub auto_filter: Option<bool>,
57
58    /// Freeze first row
59    #[serde(default)]
60    pub freeze_header: Option<bool>,
61
62    /// Auto-fit column widths
63    #[serde(default)]
64    pub auto_fit: Option<bool>,
65}
66
67/// CSV-specific configuration
68#[derive(Debug, Clone, Serialize, Deserialize, Default)]
69pub struct CsvConfig {
70    /// Delimiter character
71    #[serde(default)]
72    pub delimiter: Option<String>,
73
74    /// Quote character
75    #[serde(default)]
76    pub quote: Option<String>,
77
78    /// Has header row
79    #[serde(default)]
80    pub has_header: Option<bool>,
81}
82
83/// Google Sheets API configuration
84#[derive(Debug, Clone, Serialize, Deserialize, Default)]
85pub struct GoogleSheetsConfig {
86    /// Path to service account JSON file
87    #[serde(default)]
88    pub service_account_file: Option<String>,
89
90    /// Path to client secrets JSON file (for OAuth flow)
91    #[serde(default)]
92    pub client_secrets_file: Option<String>,
93
94    /// Path to token storage file
95    #[serde(default)]
96    pub token_file: Option<String>,
97
98    /// Default spreadsheet ID (can be overridden in commands)
99    #[serde(default)]
100    pub default_spreadsheet_id: Option<String>,
101
102    /// API key for simple access (read-only public sheets)
103    #[serde(default)]
104    pub api_key: Option<String>,
105
106    /// OAuth scopes
107    #[serde(default = "default_scopes")]
108    pub scopes: Vec<String>,
109}
110
111fn default_scopes() -> Vec<String> {
112    vec![
113        "https://www.googleapis.com/auth/spreadsheets".to_string(),
114        "https://www.googleapis.com/auth/drive.readonly".to_string(),
115    ]
116}
117
118impl Config {
119    /// Load configuration from default locations
120    pub fn load() -> Result<Self> {
121        // Try loading from multiple locations in order
122        let paths = vec![
123            // Current directory
124            PathBuf::from(".xls-rs.toml"),
125            // Home directory
126            dirs::home_dir()
127                .map(|p| p.join(".xls-rs.toml"))
128                .unwrap_or_default(),
129            // XDG config
130            dirs::config_dir()
131                .map(|p| p.join("xls-rs/config.toml"))
132                .unwrap_or_default(),
133        ];
134
135        for path in paths {
136            if path.exists() {
137                let content = std::fs::read_to_string(&path)?;
138                let config: Config = toml::from_str(&content)?;
139                return Ok(config);
140            }
141        }
142
143        // Return default config if no file found
144        Ok(Config::default())
145    }
146
147    /// Load configuration from a specific path
148    pub fn load_from(path: &str) -> Result<Self> {
149        let content = std::fs::read_to_string(path)?;
150        let config: Config = toml::from_str(&content)?;
151        Ok(config)
152    }
153
154    /// Save configuration to a file
155    pub fn save(&self, path: &str) -> Result<()> {
156        let content = toml::to_string_pretty(self)?;
157        std::fs::write(path, content)?;
158        Ok(())
159    }
160
161    /// Generate a default config file content
162    pub fn default_config_content() -> &'static str {
163        r#"# xls-rs configuration file
164# Place this file at ~/.xls-rs.toml or .xls-rs.toml in your project
165
166# Default output format: csv, json, markdown
167default_format = "csv"
168
169# Default date format for parsing
170date_format = "%Y-%m-%d"
171
172# Default output directory for batch operations
173# output_dir = "output"
174
175[excel]
176# Make header row bold
177header_bold = true
178
179# Header background color (hex without #)
180header_bg_color = "4472C4"
181
182# Header font color (hex without #)
183header_font_color = "FFFFFF"
184
185# Enable auto-filter on headers
186auto_filter = true
187
188# Freeze first row (header)
189freeze_header = true
190
191# Auto-fit column widths
192auto_fit = true
193
194[csv]
195# Delimiter character (default: comma)
196delimiter = ","
197
198# Quote character (default: double quote)
199quote = "\""
200
201# Has header row
202has_header = true
203
204[google_sheets]
205# Path to service account JSON file (for server-to-server auth)
206# service_account_file = "/path/to/service-account.json"
207
208# Path to client secrets JSON file (for OAuth flow)
209# client_secrets_file = "/path/to/client-secrets.json"
210
211# Path to token storage file (for OAuth flow)
212# token_file = "/path/to/token.json"
213
214# Default spreadsheet ID (can be overridden in commands)
215# default_spreadsheet_id = "your-spreadsheet-id"
216
217# API key for read-only access to public sheets
218# api_key = "your-api-key"
219"#
220    }
221}