use super::funejson::Value; use super::todo_item::{todos_from_value, Todo}; const HEADER: [&str; 13] = [ "id", "title", "notes", "done", "priority", "due", "tags", "recurrenceFrequency", "recurrenceInterval", "recurrenceAnchor", "createdAt", "completedAt", "order", ]; /// Quote a field only when RFC 4180 needs it: a comma, a double quote, CR or LF. fn field(text: &str) -> String { if !text.contains(|c: char| c == ',' || c == '"' || c == '\r' || c == '\n') { return text.to_string(); } format!("\"{}\"", text.replace('"', "\"\"")) } /// Todos as CSV under a fixed 13-column header, one CRLF-ended row each, in /// the order given. Nothing is escaped for spreadsheets (see README). pub fn export_csv(todos: &[Todo]) -> String { let mut out = HEADER.join(","); out.push_str("\r\n"); for todo in todos { let rule = todo.recurrence.as_ref(); let cells: [String; 13] = [ todo.id.clone(), todo.title.clone(), todo.notes.clone().unwrap_or_default(), (if todo.done { "true" } else { "false" }).to_string(), todo.priority.clone(), todo.due.clone().unwrap_or_default(), todo.tags.join(" "), rule.map(|r| r.frequency.clone()).unwrap_or_default(), rule.map(|r| r.interval.to_string()).unwrap_or_default(), rule.map(|r| r.anchor.clone()).unwrap_or_default(), todo.created_at.clone(), todo.completed_at.clone().unwrap_or_default(), todo.order.to_string(), ]; let row: Vec = cells.iter().map(|c| field(c)).collect(); out.push_str(&row.join(",")); out.push_str("\r\n"); } out } pub fn fune_vector(args: &[Value]) -> Value { Value::str(&export_csv(&todos_from_value(&args[0]))) }