11 Commits

Author SHA1 Message Date
Bel LaPointe
d45ddb3b6d ffrom panics 2026-02-01 11:48:58 -07:00
Bel LaPointe
d6167c84bf from panic 2026-02-01 11:48:39 -07:00
Bel LaPointe
05dfbcc270 delta mod 2026-02-01 11:48:02 -07:00
Bel LaPointe
cd26b1a82a parse add 2026-02-01 11:41:14 -07:00
Bel LaPointe
cb8a173456 stub into add, reconcile, edit, dump 2026-02-01 11:37:00 -07:00
Bel LaPointe
7da42521e9 stub add, edit, dump 2026-02-01 11:35:49 -07:00
Bel LaPointe
999e37bd65 stub add 2026-02-01 11:35:09 -07:00
Bel LaPointe
df9b2823b6 stub edit 2026-02-01 11:32:39 -07:00
Bel LaPointe
2f708ef41c stub edit 2026-02-01 11:32:02 -07:00
Bel LaPointe
dcdbb8a5a1 v2 start 2026-02-01 11:28:58 -07:00
Bel LaPointe
07dc5ca5ee comment out v1 2026-02-01 10:33:47 -07:00

View File

@@ -3,6 +3,167 @@ use serde::{Deserialize, Serialize};
use serde_yaml; use serde_yaml;
use std::io::{BufRead, Read, Write}; use std::io::{BufRead, Read, Write};
pub fn main() {
let flags = Flags::new().expect("failed to flags");
if let Some(added) = flags.add.clone() {
add(
flags.files().expect("couldnt find files from flags"),
added,
flags.add_schedule.clone(),
)
.expect("failed to add");
}
if flags.add.is_some() || flags.edit {
reconcile(flags.files().expect("couldnt find files from flags"))
.expect("failed to reconcile");
}
if flags.edit {
edit(flags.files().expect("couldnt find files from flags")).expect("failed to edit");
}
dump(flags.files().expect("couldnt find files from flags")).expect("failed to dump");
}
#[derive(Debug, Parser)]
struct Flags {
#[arg(short = 'f', long = "path", default_value = "$PTTODO_FILE")]
path: String,
#[arg(short = 'a', long = "add")]
add: Option<String>,
#[arg(short = 'e', long = "edit", default_value = "false")]
edit: bool,
#[arg(short = 'd', long = "dry-run", default_value = "false")]
dry_run: bool,
#[arg(short = 's', long = "add-schedule")]
add_schedule: Option<String>,
}
impl Flags {
pub fn new() -> Result<Flags, String> {
let mut result = Flags::parse();
if result.path.get(..1) == Some("$") {
result.path = match std::env::var(result.path.get(1..).unwrap()) {
Ok(v) => Ok(v),
Err(msg) => Err(format!("'{}' unset: {}", result.path, msg)),
}?;
}
let _ = result.files()?;
Ok(result)
}
fn files(&self) -> Result<Vec<String>, String> {
Self::files_with(&self.path)
}
fn files_with(p: &String) -> Result<Vec<String>, String> {
let metadata = match std::fs::metadata(p.clone()) {
Ok(v) => Ok(v),
Err(msg) => Err(format!("failed to load {}: {}", p.clone(), msg)),
}?;
let files = match metadata.is_dir() {
false => Ok(vec![p.clone()]),
true => match std::fs::read_dir(p.clone()) {
Ok(paths) => Ok(paths
.filter(|x| x.is_ok())
.map(|x| x.unwrap())
.filter(|x| x.metadata().unwrap().is_file())
.map(|x| x.path().display().to_string())
.filter(|x| !x.contains("/."))
.collect()),
Err(msg) => Err(format!("failed to read {}: {}", p.clone(), msg)),
},
}?;
assert!(files.len() > 0, "no files");
Ok(files)
}
}
#[cfg(test)]
mod test_flags {
use super::*;
#[test]
fn test_flags_files_unhidden_only() {
tests::with_dir(|d| {
std::fs::File::create(d.path().join("plain")).unwrap();
std::fs::File::create(d.path().join(".hidden")).unwrap();
let flags = Flags {
path: d.path().to_str().unwrap().to_string(),
add: None,
edit: false,
dry_run: true,
add_schedule: None,
};
let files = flags.files().expect("failed to files from dir");
assert_eq!(1, files.len());
});
}
}
fn add(files: Vec<String>, added: String, add_schedule: Option<String>) -> Result<(), String> {
let task = Delta::new(added, add_schedule);
Err(format!("append {:?} to {:?}", &task, &files))
}
fn reconcile(files: Vec<String>) -> Result<(), String> {
Err("not impl".to_string())
}
fn edit(files: Vec<String>) -> Result<(), String> {
Err("not impl".to_string())
}
fn dump(files: Vec<String>) -> Result<(), String> {
Err("not impl".to_string())
}
mod Delta {
pub fn new(added: String, add_schedule: Option<String>) -> serde_yaml::Value {
match add_schedule.clone() {
None => new_add(added),
Some(add_schedule) => new_add_with_schedule(added, add_schedule),
}
}
fn new_add(added: String) -> serde_yaml::Value {
serde_yaml::Value::String(added)
}
fn new_add_with_schedule(added: String, schedule: String) -> serde_yaml::Value {
let mut m = serde_yaml::Mapping::new();
m.insert("schedule".into(), schedule.into());
m.insert("do".into(), added.into());
serde_yaml::Value::Mapping(m)
}
}
mod tests {
use super::*;
pub fn with_dir(mut foo: impl FnMut(tempdir::TempDir)) {
foo(tempdir::TempDir::new("").unwrap());
}
}
/*
mod v1 {
use clap::Parser;
use serde::{Deserialize, Serialize};
use serde_yaml;
use std::io::{BufRead, Read, Write};
fn main() { fn main() {
let flags = Flags::new().expect("failed to flags"); let flags = Flags::new().expect("failed to flags");
let files = flags.files().expect("failed to files"); let files = flags.files().expect("failed to files");
@@ -474,17 +635,17 @@ mod test_file {
#[test] #[test]
fn test_schedule_cron_resolve_reschedules() { fn test_schedule_cron_resolve_reschedules() {
panic!("not impl"); //!("not impl");
} }
#[test] #[test]
fn test_schedule_duration_resolve_reschedules() { fn test_schedule_duration_resolve_reschedules() {
panic!("not impl"); //!("not impl");
} }
#[test] #[test]
fn test_schedule_date_resolve_does_not_reschedule() { fn test_schedule_date_resolve_does_not_reschedule() {
panic!("not impl"); //!("not impl");
} }
#[test] #[test]
@@ -668,7 +829,7 @@ impl Task {
_ => {} _ => {}
}; };
} }
Err(msg) => panic!("{}", msg), Err(msg) => //!("{}", msg),
}; };
} }
@@ -802,7 +963,9 @@ impl Events {
if line.len() > 0 { if line.len() > 0 {
let delta = match serde_json::from_str(&line) { let delta = match serde_json::from_str(&line) {
Ok(v) => Ok(v), Ok(v) => Ok(v),
Err(msg) => Err(format!("failed to parse line {}: {}", &line, msg)), Err(msg) => {
Err(format!("failed to parse line {}: {}", &line, msg))
}
}?; }?;
result.push(delta); result.push(delta);
} }
@@ -1134,3 +1297,5 @@ mod edit {
} }
} }
} }
}
*/