diff --git a/src/main.rs b/src/main.rs index 8cf9c71..44937ef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,20 @@ -mod tasks; - -use crate::tasks::Tasks; -use crate::State::*; -use nostr_sdk::async_utility::futures_util::TryFutureExt; -use nostr_sdk::prelude::*; -use once_cell::sync::Lazy; use std::borrow::Borrow; use std::env::args; -use std::fmt; -use std::fmt::{Display, Formatter}; use std::io::{stdin, stdout, Write}; use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use std::ops::Deref; use std::time::Duration; +use nostr_sdk::async_utility::futures_util::TryFutureExt; +use nostr_sdk::prelude::*; +use once_cell::sync::Lazy; + +use crate::task::State; +use crate::tasks::Tasks; + +mod task; +mod tasks; + /* 1: Task Description Issue Tracking: https://github.com/nostr-protocol/nips/blob/master/34.md @@ -143,7 +144,11 @@ async fn repl() { Some('>') | Some('<') => { tasks.update_state(&input[1..], |_| { - Some(if op.unwrap() == '<' { Closed } else { Done }) + Some(if op.unwrap() == '<' { + State::Closed + } else { + State::Done + }) }); tasks.move_up() } @@ -198,144 +203,3 @@ async fn repl() { ) .await; } - -struct Task { - event: Event, - children: Vec, - props: Vec, -} -impl Task { - fn new(event: Event) -> Task { - Task { - event, - children: Vec::new(), - props: Vec::new(), - } - } - - fn parent_id(&self) -> Option { - for tag in self.event.tags.iter() { - match tag { - Tag::Event { event_id, .. } => return Some(*event_id), - _ => {} - } - } - None - } - - fn descriptions(&self) -> impl Iterator + '_ { - self.props.iter().filter_map(|event| { - if event.kind == Kind::TextNote { - Some(event.content.clone()) - } else { - None - } - }) - } - - fn states(&self) -> impl Iterator + '_ { - self.props.iter().filter_map(|event| { - match event.kind.as_u32() { - 1630 => Some(Open), - 1631 => Some(Done), - 1632 => Some(Closed), - 1633 => Some(Active), - _ => None, - } - .map(|s| TaskState { - name: if event.content.is_empty() { - None - } else { - Some(event.content.clone()) - }, - state: s, - time: event.created_at.clone(), - }) - }) - } - - fn state(&self) -> Option { - self.states().max_by_key(|t| t.time) - } - - fn pure_state(&self) -> State { - self.state().map_or(Open, |s| s.state) - } - - fn default_state(&self) -> TaskState { - TaskState { - name: None, - state: Open, - time: self.event.created_at, - } - } - - fn update_state(&mut self, state: State, comment: &str) { - self.props.push(make_event( - state.kind(), - comment, - &[Tag::event(self.event.id)], - )) - } - - fn get(&self, property: &str) -> Option { - match property { - "id" => Some(self.event.id.to_string()), - "parentid" => self.parent_id().map(|i| i.to_string()), - "state" => self.state().map(|s| s.to_string()), - "name" => Some(self.event.content.clone()), - "desc" | "description" => self.descriptions().fold(None, |total, s| { - Some(match total { - None => s, - Some(i) => i + " " + &s, - }) - }), - _ => { - eprintln!("Unknown column {}", property); - None - } - } - } -} - -struct TaskState { - name: Option, - state: State, - time: Timestamp, -} -impl Display for TaskState { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!( - f, - "{}{}", - self.state, - self.name - .as_ref() - .map_or(String::new(), |s| format!(": {}", s)) - ) - } -} - -#[derive(Debug, Copy, Clone, PartialEq)] -enum State { - Closed, - Open, - Active, - Done, -} -impl State { - fn kind(&self) -> Kind { - match self { - Open => Kind::from(1630), - Done => Kind::from(1631), - Closed => Kind::from(1632), - Active => Kind::from(1633), - } - } -} -static STATES: [State; 4] = [Closed, Open, Active, Done]; -impl fmt::Display for State { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self, f) - } -} diff --git a/src/task.rs b/src/task.rs new file mode 100644 index 0000000..9b961d5 --- /dev/null +++ b/src/task.rs @@ -0,0 +1,143 @@ +use std::fmt; +use nostr_sdk::{Event, EventId, Kind, Tag, Timestamp}; +use crate::make_event; + +pub(crate) struct Task { + pub(crate) event: Event, + pub(crate) children: Vec, + pub(crate) props: Vec, +} +impl Task { + pub(crate) fn new(event: Event) -> Task { + Task { + event, + children: Vec::new(), + props: Vec::new(), + } + } + + pub(crate) fn parent_id(&self) -> Option { + for tag in self.event.tags.iter() { + match tag { + Tag::Event { event_id, .. } => return Some(*event_id), + _ => {} + } + } + None + } + + fn descriptions(&self) -> impl Iterator + '_ { + self.props.iter().filter_map(|event| { + if event.kind == Kind::TextNote { + Some(event.content.clone()) + } else { + None + } + }) + } + + fn states(&self) -> impl Iterator + '_ { + self.props.iter().filter_map(|event| { + match event.kind.as_u32() { + 1630 => Some(State::Open), + 1631 => Some(State::Done), + 1632 => Some(State::Closed), + 1633 => Some(State::Active), + _ => None, + } + .map(|s| TaskState { + name: if event.content.is_empty() { + None + } else { + Some(event.content.clone()) + }, + state: s, + time: event.created_at.clone(), + }) + }) + } + + fn state(&self) -> Option { + self.states().max_by_key(|t| t.time) + } + + pub(crate) fn pure_state(&self) -> State { + self.state().map_or(State::Open, |s| s.state) + } + + fn default_state(&self) -> TaskState { + TaskState { + name: None, + state: State::Open, + time: self.event.created_at, + } + } + + pub(crate) fn update_state(&mut self, state: State, comment: &str) { + self.props.push(make_event( + state.kind(), + comment, + &[Tag::event(self.event.id)], + )) + } + + pub(crate) fn get(&self, property: &str) -> Option { + match property { + "id" => Some(self.event.id.to_string()), + "parentid" => self.parent_id().map(|i| i.to_string()), + "state" => self.state().map(|s| s.to_string()), + "name" => Some(self.event.content.clone()), + "desc" | "description" => self.descriptions().fold(None, |total, s| { + Some(match total { + None => s, + Some(i) => i + " " + &s, + }) + }), + _ => { + eprintln!("Unknown column {}", property); + None + } + } + } +} + +struct TaskState { + name: Option, + state: State, + time: Timestamp, +} +impl fmt::Display for TaskState { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}{}", + self.state, + self.name + .as_ref() + .map_or(String::new(), |s| format!(": {}", s)) + ) + } +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub(crate) enum State { + Closed, + Open, + Active, + Done, +} +impl State { + fn kind(&self) -> Kind { + match self { + State::Open => Kind::from(1630), + State::Done => Kind::from(1631), + State::Closed => Kind::from(1632), + State::Active => Kind::from(1633), + } + } +} +impl fmt::Display for State { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} diff --git a/src/tasks.rs b/src/tasks.rs index fcaf640..650738c 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -1,4 +1,5 @@ -use crate::{make_event, make_task, State, Task}; +use crate::{make_event, make_task}; +use crate::task::{Task, State}; use nostr_sdk::{Event, EventId, Tag}; use std::collections::HashMap; @@ -135,8 +136,7 @@ impl Tasks { { self.tasks.get_mut(id).map(|t| { f(t).map(|s| { - t.props - .push(make_event(s.kind(), comment, &[Tag::event(id.clone())])) + t.update_state(s, comment); }) }); }