fix: handle PathBuf correctly
This commit is contained in:
@ -1,3 +1,5 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use super::types::{CellValueArg, Command, CommandResult};
|
use super::types::{CellValueArg, Command, CommandResult};
|
||||||
use crate::formula::parse_formula;
|
use crate::formula::parse_formula;
|
||||||
use crate::import::analyzer::{analyze_records, extract_array_at_path, FieldKind};
|
use crate::import::analyzer::{analyze_records, extract_array_at_path, FieldKind};
|
||||||
@ -169,11 +171,11 @@ pub fn dispatch(model: &mut Model, cmd: &Command) -> CommandResult {
|
|||||||
|
|
||||||
fn import_headless(
|
fn import_headless(
|
||||||
model: &mut Model,
|
model: &mut Model,
|
||||||
path: &str,
|
path: &PathBuf,
|
||||||
model_name: Option<&str>,
|
model_name: Option<&str>,
|
||||||
array_path: Option<&str>,
|
array_path: Option<&str>,
|
||||||
) -> CommandResult {
|
) -> CommandResult {
|
||||||
let is_csv = path.ends_with(".csv");
|
let is_csv = path.extension().is_some_and(|ext| ext.eq_ignore_ascii_case("csv"));
|
||||||
|
|
||||||
let records = if is_csv {
|
let records = if is_csv {
|
||||||
// Parse CSV file
|
// Parse CSV file
|
||||||
@ -185,7 +187,7 @@ fn import_headless(
|
|||||||
// Parse JSON file
|
// Parse JSON file
|
||||||
let content = match std::fs::read_to_string(path) {
|
let content = match std::fs::read_to_string(path) {
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(e) => return CommandResult::err(format!("Cannot read '{path}': {e}")),
|
Err(e) => return CommandResult::err(format!("Cannot read '{}': {e}", path.display())),
|
||||||
};
|
};
|
||||||
let value: serde_json::Value = match serde_json::from_str(&content) {
|
let value: serde_json::Value = match serde_json::from_str(&content) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::view::Axis;
|
use crate::view::Axis;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -80,7 +82,7 @@ pub enum Command {
|
|||||||
|
|
||||||
/// Import a JSON file via the analyzer (non-interactive, uses auto-detected proposals).
|
/// Import a JSON file via the analyzer (non-interactive, uses auto-detected proposals).
|
||||||
ImportJson {
|
ImportJson {
|
||||||
path: String,
|
path: PathBuf,
|
||||||
model_name: Option<String>,
|
model_name: Option<String>,
|
||||||
/// Dot-path to the records array (empty = root)
|
/// Dot-path to the records array (empty = root)
|
||||||
array_path: Option<String>,
|
array_path: Option<String>,
|
||||||
|
|||||||
@ -1,15 +1,17 @@
|
|||||||
|
use std::path::Path;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use csv::ReaderBuilder;
|
use csv::ReaderBuilder;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
/// Parse a CSV file and return records as serde_json::Value array
|
/// Parse a CSV file and return records as serde_json::Value array
|
||||||
pub fn parse_csv(path: &str) -> Result<Vec<Value>> {
|
pub fn parse_csv(path: &Path) -> Result<Vec<Value>> {
|
||||||
let mut reader = ReaderBuilder::new()
|
let mut reader = ReaderBuilder::new()
|
||||||
.has_headers(true)
|
.has_headers(true)
|
||||||
.flexible(true)
|
.flexible(true)
|
||||||
.trim(csv::Trim::All)
|
.trim(csv::Trim::All)
|
||||||
.from_path(path)
|
.from_path(path)
|
||||||
.with_context(|| format!("Failed to open CSV file: {path}"))?;
|
.with_context(|| format!("Failed to open CSV file: {}", path.display()))?;
|
||||||
|
|
||||||
// Detect if first row looks like headers (strings) or data (mixed)
|
// Detect if first row looks like headers (strings) or data (mixed)
|
||||||
let has_headers = reader.headers().is_ok();
|
let has_headers = reader.headers().is_ok();
|
||||||
|
|||||||
67
src/main.rs
67
src/main.rs
@ -13,6 +13,7 @@ use anyhow::{Context, Result};
|
|||||||
|
|
||||||
use model::Model;
|
use model::Model;
|
||||||
use draw::run_tui;
|
use draw::run_tui;
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let args: Vec<String> = std::env::args().collect();
|
let args: Vec<String> = std::env::args().collect();
|
||||||
@ -35,42 +36,46 @@ impl Runnable for CmdLineArgs {
|
|||||||
let model = get_initial_model(&self.file_path)?;
|
let model = get_initial_model(&self.file_path)?;
|
||||||
|
|
||||||
// Pre-TUI import: parse JSON or CSV and open wizard
|
// Pre-TUI import: parse JSON or CSV and open wizard
|
||||||
let import_value = if let Some(ref path) = self.import_path {
|
let import_value = self.import_path.and_then(get_import_data);
|
||||||
match std::fs::read_to_string(path) {
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Cannot read '{}': {e}", path.display());
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
Ok(content) => {
|
|
||||||
if path.to_string_lossy().ends_with(".csv") {
|
|
||||||
// Parse CSV and wrap as JSON array
|
|
||||||
match crate::import::csv_parser::parse_csv(&path.to_string_lossy()) {
|
|
||||||
Ok(records) => Some(serde_json::Value::Array(records)),
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("CSV parse error: {e}");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Parse JSON
|
|
||||||
match serde_json::from_str::<serde_json::Value>(&content) {
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("JSON parse error: {e}");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
Ok(json) => Some(json),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
run_tui(model, self.file_path, import_value)
|
run_tui(model, self.file_path, import_value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn csv_path_p(path:&PathBuf) -> bool {
|
||||||
|
path.extension().is_some_and(|ext| ext.eq_ignore_ascii_case("csv"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_import_data(path: PathBuf) -> Option<Value> {
|
||||||
|
match std::fs::read_to_string(&path) {
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Cannot read '{}': {e}", path.display());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Ok(content) => {
|
||||||
|
if csv_path_p(&path) {
|
||||||
|
// Parse CSV and wrap as JSON array
|
||||||
|
match crate::import::csv_parser::parse_csv(&path) {
|
||||||
|
Ok(records) => Some(serde_json::Value::Array(records)),
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("CSV parse error: {e}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Parse JSON
|
||||||
|
match serde_json::from_str::<serde_json::Value>(&content) {
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("JSON parse error: {e}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Ok(json) => Some(json),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct HeadlessArgs {
|
struct HeadlessArgs {
|
||||||
file_path: Option<PathBuf>,
|
file_path: Option<PathBuf>,
|
||||||
commands: Vec<String>,
|
commands: Vec<String>,
|
||||||
|
|||||||
Reference in New Issue
Block a user