refactor: code cleanup with clippy

This commit is contained in:
xeruf 2024-08-25 14:46:07 +03:00
parent 38fd00b150
commit dedda147c0
4 changed files with 50 additions and 68 deletions

View File

@ -57,7 +57,7 @@ where
EventBuilder::new( EventBuilder::new(
Kind::from(TRACKING_KIND), Kind::from(TRACKING_KIND),
"", "",
id.into_iter().map(|id| Tag::event(id)), id.into_iter().map(Tag::event),
) )
} }
@ -65,7 +65,7 @@ where
pub(crate) fn build_task(name: &str, tags: Vec<Tag>, kind: Option<(&str, Kind)>) -> EventBuilder { pub(crate) fn build_task(name: &str, tags: Vec<Tag>, kind: Option<(&str, Kind)>) -> EventBuilder {
info!("Created {}task \"{name}\" with tags [{}]", info!("Created {}task \"{name}\" with tags [{}]",
kind.map(|k| k.0).unwrap_or_default(), kind.map(|k| k.0).unwrap_or_default(),
tags.iter().map(|tag| format_tag(tag)).join(", ")); tags.iter().map(format_tag).join(", "));
EventBuilder::new(kind.map(|k| k.1).unwrap_or(Kind::from(TASK_KIND)), name, tags) EventBuilder::new(kind.map(|k| k.1).unwrap_or(Kind::from(TASK_KIND)), name, tags)
} }
@ -107,7 +107,7 @@ fn format_tag(tag: &Tag) -> String {
public_key, public_key,
alias, alias,
.. ..
}) => format!("Key{}: {:.8}", public_key.to_string(), alias.as_ref().map(|s| format!(" {s}")).unwrap_or_default()), }) => format!("Key{}: {:.8}", public_key, alias.as_ref().map(|s| format!(" {s}")).unwrap_or_default()),
Some(TagStandard::Hashtag(content)) => Some(TagStandard::Hashtag(content)) =>
format!("#{content}"), format!("#{content}"),
_ => tag.content().map_or_else( _ => tag.content().map_or_else(

View File

@ -18,7 +18,7 @@ use log::{debug, error, info, LevelFilter, trace, warn};
use nostr_sdk::prelude::*; use nostr_sdk::prelude::*;
use nostr_sdk::TagStandard::Hashtag; use nostr_sdk::TagStandard::Hashtag;
use regex::Regex; use regex::Regex;
use rustyline::{DefaultEditor, Editor}; use rustyline::DefaultEditor;
use rustyline::error::ReadlineError; use rustyline::error::ReadlineError;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tokio::sync::mpsc::Sender; use tokio::sync::mpsc::Sender;
@ -239,12 +239,12 @@ async fn main() -> Result<()> {
client.connect().await; client.connect().await;
let sub1 = client.subscribe(vec![ let sub1 = client.subscribe(vec![
Filter::new().kinds(KINDS.into_iter().map(|k| Kind::from(k))) Filter::new().kinds(KINDS.into_iter().map(Kind::from))
], None).await; ], None).await;
info!("Subscribed to tasks with {:?}", sub1); info!("Subscribed to tasks with {:?}", sub1);
let sub2 = client.subscribe(vec![ let sub2 = client.subscribe(vec![
Filter::new().kinds(PROP_KINDS.into_iter().map(|k| Kind::from(k))) Filter::new().kinds(PROP_KINDS.into_iter().map(Kind::from))
], None).await; ], None).await;
info!("Subscribed to updates with {:?}", sub2); info!("Subscribed to updates with {:?}", sub2);
@ -418,19 +418,19 @@ async fn main() -> Result<()> {
Some(arg) => { Some(arg) => {
if arg.len() < CHARACTER_THRESHOLD { if arg.len() < CHARACTER_THRESHOLD {
warn!("Note needs at least {CHARACTER_THRESHOLD} characters!"); warn!("Note needs at least {CHARACTER_THRESHOLD} characters!");
continue continue;
} }
tasks.make_note(arg) tasks.make_note(arg)
}, }
} }
Some('>') => { Some('>') => {
tasks.update_state(&arg_default, State::Done); tasks.update_state(arg_default, State::Done);
tasks.move_up(); tasks.move_up();
} }
Some('<') => { Some('<') => {
tasks.update_state(&arg_default, State::Closed); tasks.update_state(arg_default, State::Closed);
tasks.move_up(); tasks.move_up();
} }
@ -441,7 +441,7 @@ async fn main() -> Result<()> {
Some('@') => { Some('@') => {
match arg { match arg {
None => { None => {
let today = Timestamp::from(Timestamp::now() - 80_000); let today = Timestamp::now() - 80_000;
info!("Filtering for tasks created in the last 22 hours"); info!("Filtering for tasks created in the last 22 hours");
tasks.set_filter( tasks.set_filter(
tasks.filtered_tasks(tasks.get_position_ref()) tasks.filtered_tasks(tasks.get_position_ref())
@ -503,7 +503,7 @@ async fn main() -> Result<()> {
} }
}, },
Some(arg) => 'arm: { Some(arg) => 'arm: {
if arg.chars().next() != Some('|') { if !arg.starts_with('|') {
if let Some(pos) = tasks.get_position() { if let Some(pos) = tasks.get_position() {
tasks.move_up(); tasks.move_up();
tasks.make_task_with( tasks.make_task_with(
@ -562,7 +562,7 @@ async fn main() -> Result<()> {
let (label, times) = tasks.times_tracked(); let (label, times) = tasks.times_tracked();
println!("{}\n{}", label.italic(), times.rev().take(15).join("\n")); println!("{}\n{}", label.italic(), times.rev().take(15).join("\n"));
} }
// TODO show history from author / pubkey // TODO show history of author / pubkey
} else { } else {
let (label, mut times) = tasks.times_tracked(); let (label, mut times) = tasks.times_tracked();
println!("{}\n{}", label.italic(), times.join("\n")); println!("{}\n{}", label.italic(), times.join("\n"));
@ -629,7 +629,7 @@ async fn main() -> Result<()> {
tasks.set_depth(depth); tasks.set_depth(depth);
} else { } else {
let mut transform: Box<dyn Fn(&str) -> String> = Box::new(|s: &str| s.to_string()); let mut transform: Box<dyn Fn(&str) -> String> = Box::new(|s: &str| s.to_string());
if slice.chars().find(|c| c.is_ascii_uppercase()).is_none() { if !slice.chars().any(|c| c.is_ascii_uppercase()) {
// Smart-case - case-sensitive if any uppercase char is entered // Smart-case - case-sensitive if any uppercase char is entered
transform = Box::new(|s| s.to_ascii_lowercase()); transform = Box::new(|s| s.to_ascii_lowercase());
} }
@ -643,7 +643,7 @@ async fn main() -> Result<()> {
.map(|t| t.event.id) .map(|t| t.event.id)
.collect_vec(); .collect_vec();
if filtered.len() == 1 { if filtered.len() == 1 {
tasks.move_to(filtered.into_iter().nth(0)); tasks.move_to(filtered.into_iter().next());
} else { } else {
tasks.move_to(pos.cloned()); tasks.move_to(pos.cloned());
tasks.set_filter(filtered); tasks.set_filter(filtered);
@ -652,10 +652,10 @@ async fn main() -> Result<()> {
} }
_ => _ =>
if Regex::new("^wss?://").unwrap().is_match(&input.trim()) { if Regex::new("^wss?://").unwrap().is_match(input.trim()) {
tasks.move_to(None); tasks.move_to(None);
if let Some((url, tasks)) = relays.iter().find(|(key, _)| key.as_ref().is_some_and(|url| url.as_str().starts_with(&input))) { if let Some((url, tasks)) = relays.iter().find(|(key, _)| key.as_ref().is_some_and(|url| url.as_str().starts_with(&input))) {
selected_relay = url.clone(); selected_relay.clone_from(url);
or_warn!(tasks.print_tasks()); or_warn!(tasks.print_tasks());
continue; continue;
} }

View File

@ -46,7 +46,8 @@ impl Ord for Task {
impl Task { impl Task {
pub(crate) fn new(event: Event) -> Task { pub(crate) fn new(event: Event) -> Task {
let (refs, tags) = event.tags.iter().partition_map(|tag| match tag.as_standardized() { let (refs, tags) = event.tags.iter().partition_map(|tag| match tag.as_standardized() {
Some(TagStandard::Event { event_id, marker, .. }) => Left((marker.as_ref().map_or(MARKER_PARENT.to_string(), |m| m.to_string()), event_id.clone())), Some(TagStandard::Event { event_id, marker, .. }) =>
Left((marker.as_ref().map_or(MARKER_PARENT.to_string(), |m| m.to_string()), *event_id)),
_ => Right(tag.clone()), _ => Right(tag.clone()),
}); });
// Separate refs for dependencies // Separate refs for dependencies
@ -82,13 +83,7 @@ impl Task {
} }
pub(crate) fn description_events(&self) -> impl Iterator<Item=&Event> + '_ { pub(crate) fn description_events(&self) -> impl Iterator<Item=&Event> + '_ {
self.props.iter().filter_map(|event| { self.props.iter().filter(|event| event.kind == Kind::TextNote)
if event.kind == Kind::TextNote {
Some(event)
} else {
None
}
})
} }
pub(crate) fn descriptions(&self) -> impl Iterator<Item=&String> + '_ { pub(crate) fn descriptions(&self) -> impl Iterator<Item=&String> + '_ {
@ -105,7 +100,7 @@ impl Task {
event.kind.try_into().ok().map(|s| TaskState { event.kind.try_into().ok().map(|s| TaskState {
name: some_non_empty(&event.content), name: some_non_empty(&event.content),
state: s, state: s,
time: event.created_at.clone(), time: event.created_at,
}) })
}) })
} }
@ -142,9 +137,9 @@ impl Task {
P: FnMut(&&Tag) -> bool, P: FnMut(&&Tag) -> bool,
{ {
self.tags.as_ref().map(|tags| { self.tags.as_ref().map(|tags| {
tags.into_iter() tags.iter()
.filter(predicate) .filter(predicate)
.map(|t| format!("{}", t.content().unwrap())) .map(|t| t.content().unwrap().to_string())
.join(" ") .join(" ")
}) })
} }
@ -261,10 +256,7 @@ impl TryFrom<Kind> for State {
} }
impl State { impl State {
pub(crate) fn is_open(&self) -> bool { pub(crate) fn is_open(&self) -> bool {
match self { matches!(self, State::Open | State::Pending | State::Procedure)
State::Open | State::Pending | State::Procedure => true,
_ => false,
}
} }
pub(crate) fn kind(self) -> u16 { pub(crate) fn kind(self) -> u16 {

View File

@ -49,8 +49,9 @@ pub(crate) struct Tasks {
sender: EventSender, sender: EventSender,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, Default)]
pub(crate) enum StateFilter { pub(crate) enum StateFilter {
#[default]
Default, Default,
All, All,
State(String), State(String),
@ -68,7 +69,7 @@ impl StateFilter {
match self { match self {
StateFilter::Default => { StateFilter::Default => {
let state = task.pure_state(); let state = task.pure_state();
state.is_open() || (state == State::Done && task.parent_id() != None) state.is_open() || (state == State::Done && task.parent_id().is_some())
} }
StateFilter::All => true, StateFilter::All => true,
StateFilter::State(filter) => task.state().is_some_and(|t| t.matches_label(filter)), StateFilter::State(filter) => task.state().is_some_and(|t| t.matches_label(filter)),
@ -83,11 +84,6 @@ impl StateFilter {
} }
} }
} }
impl Default for StateFilter {
fn default() -> Self {
StateFilter::Default
}
}
impl Display for StateFilter { impl Display for StateFilter {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!( write!(
@ -104,12 +100,7 @@ impl Display for StateFilter {
impl Tasks { impl Tasks {
pub(crate) fn from(url: Option<Url>, tx: &tokio::sync::mpsc::Sender<MostrMessage>, keys: &Keys, metadata: Option<Metadata>) -> Self { pub(crate) fn from(url: Option<Url>, tx: &tokio::sync::mpsc::Sender<MostrMessage>, keys: &Keys, metadata: Option<Metadata>) -> Self {
let mut new = Self::with_sender(EventSender { let mut new = Self::with_sender(EventSender::from(url, tx, keys));
url,
tx: tx.clone(),
keys: keys.clone(),
queue: Default::default(),
});
metadata.map(|m| new.users.insert(keys.public_key(), m)); metadata.map(|m| new.users.insert(keys.public_key(), m));
new new
} }
@ -156,7 +147,7 @@ impl Tasks {
} }
fn now() -> Timestamp { fn now() -> Timestamp {
Timestamp::from(Timestamp::now() + Self::MAX_OFFSET) Timestamp::now() + Self::MAX_OFFSET
} }
pub(crate) fn get_position_ref(&self) -> Option<&EventId> { pub(crate) fn get_position_ref(&self) -> Option<&EventId> {
@ -166,7 +157,7 @@ impl Tasks {
} }
/// Ids of all subtasks recursively found for id, including itself /// Ids of all subtasks recursively found for id, including itself
pub(crate) fn get_task_tree<'a>(&'a self, id: &'a EventId) -> ChildIterator { fn get_task_tree<'a>(&'a self, id: &'a EventId) -> ChildIterator {
ChildIterator::from(self, id) ChildIterator::from(self, id)
} }
@ -220,7 +211,7 @@ impl Tasks {
vec.push(format!("{} started by {}", format_timestamp_local(stamp), self.get_author(key)))); vec.push(format!("{} started by {}", format_timestamp_local(stamp), self.get_author(key))));
vec vec
}).sorted_unstable(); // TODO sorting depends on timestamp format - needed to interleave different people }).sorted_unstable(); // TODO sorting depends on timestamp format - needed to interleave different people
(format!("Times Tracked on {:?}", self.get_task_title(&id)), Box::from(history)) (format!("Times Tracked on {:?}", self.get_task_title(id)), Box::from(history))
} }
} }
} }
@ -314,7 +305,7 @@ impl Tasks {
iter: impl Iterator<Item=&'a EventId>, iter: impl Iterator<Item=&'a EventId>,
depth: i8, depth: i8,
) -> Box<impl Iterator<Item=&'a Task>> { ) -> Box<impl Iterator<Item=&'a Task>> {
iter.filter_map(|id| self.get_by_id(&id)) iter.filter_map(|id| self.get_by_id(id))
.flat_map(move |task| { .flat_map(move |task| {
let new_depth = depth - 1; let new_depth = depth - 1;
if new_depth == 0 { if new_depth == 0 {
@ -372,7 +363,7 @@ impl Tasks {
// TODO apply filters in transit // TODO apply filters in transit
self.state.matches(t) && self.state.matches(t) &&
t.tags.as_ref().map_or(true, |tags| { t.tags.as_ref().map_or(true, |tags| {
tags.iter().find(|tag| self.tags_excluded.contains(tag)).is_none() !tags.iter().any(|tag| self.tags_excluded.contains(tag))
}) && }) &&
(self.tags.is_empty() || (self.tags.is_empty() ||
t.tags.as_ref().map_or(false, |tags| { t.tags.as_ref().map_or(false, |tags| {
@ -386,7 +377,7 @@ impl Tasks {
if self.depth == 0 { if self.depth == 0 {
return vec![]; return vec![];
} }
if self.view.len() > 0 { if !self.view.is_empty() {
return self.resolve_tasks(self.view.iter()).collect(); return self.resolve_tasks(self.view.iter()).collect();
} }
self.filtered_tasks(self.get_position_ref()).collect() self.filtered_tasks(self.get_position_ref()).collect()
@ -399,12 +390,12 @@ impl Tasks {
let now = &Self::now(); let now = &Self::now();
let mut tracking_stamp: Option<Timestamp> = None; let mut tracking_stamp: Option<Timestamp> = None;
for elem in for elem in
timestamps(self.history.get(&self.sender.pubkey()).into_iter().flatten(), &vec![t.get_id()]) timestamps(self.history.get(&self.sender.pubkey()).into_iter().flatten(), &[t.get_id()])
.map(|(e, _)| e) { .map(|(e, _)| e) {
if tracking_stamp.is_some() && elem > now { if tracking_stamp.is_some() && elem > now {
break; break;
} }
tracking_stamp = Some(elem.clone()) tracking_stamp = Some(*elem)
} }
writeln!( writeln!(
lock, lock,
@ -458,9 +449,8 @@ impl Tasks {
fn get_property(&self, task: &Task, str: &str) -> String { fn get_property(&self, task: &Task, str: &str) -> String {
let progress = let progress =
self self.total_progress(task.get_id())
.total_progress(task.get_id()) .filter(|_| !task.children.is_empty());
.filter(|_| task.children.len() > 0);
let prog_string = progress.map_or(String::new(), |p| format!("{:2.0}%", p * 100.0)); let prog_string = progress.map_or(String::new(), |p| format!("{:2.0}%", p * 100.0));
match str { match str {
"subtasks" => { "subtasks" => {
@ -496,7 +486,7 @@ impl Tasks {
// TODO format strings configurable // TODO format strings configurable
"time" => display_time("MMMm", self.time_tracked(*task.get_id())), "time" => display_time("MMMm", self.time_tracked(*task.get_id())),
"rtime" => display_time("HH:MM", self.total_time_tracked(*task.get_id())), "rtime" => display_time("HH:MM", self.total_time_tracked(*task.get_id())),
prop => task.get(prop).unwrap_or(String::new()), prop => task.get(prop).unwrap_or_default(),
} }
} }
@ -596,7 +586,7 @@ impl Tasks {
if filtered.is_empty() { if filtered.is_empty() {
return filtered_more; return filtered_more;
} }
return filtered; filtered
} }
/// Finds out what to do with the given string. /// Finds out what to do with the given string.
@ -609,7 +599,7 @@ impl Tasks {
self.view.clear(); self.view.clear();
if arg.len() < CHARACTER_THRESHOLD { if arg.len() < CHARACTER_THRESHOLD {
warn!("New task name needs at least {CHARACTER_THRESHOLD} characters"); warn!("New task name needs at least {CHARACTER_THRESHOLD} characters");
return None return None;
} }
Some(self.make_task_with(arg, self.position_tags_for(position), true)) Some(self.make_task_with(arg, self.position_tags_for(position), true))
} }
@ -727,7 +717,7 @@ impl Tasks {
let id = self.submit( let id = self.submit(
build_task(input, input_tags, None) build_task(input, input_tags, None)
.add_tags(self.tags.iter().cloned()) .add_tags(self.tags.iter().cloned())
.add_tags(tags.into_iter()) .add_tags(tags)
); );
if set_state { if set_state {
self.state.as_option().inspect(|s| self.set_state_for_with(id, s)); self.state.as_option().inspect(|s| self.set_state_for_with(id, s));
@ -845,13 +835,13 @@ impl Tasks {
pub(crate) fn update_state(&mut self, comment: &str, state: State) -> Option<EventId> { pub(crate) fn update_state(&mut self, comment: &str, state: State) -> Option<EventId> {
let id = self.get_position_ref()?; let id = self.get_position_ref()?;
Some(self.set_state_for(id.clone(), comment, state)) Some(self.set_state_for(*id, comment, state))
} }
pub(crate) fn make_note(&mut self, note: &str) { pub(crate) fn make_note(&mut self, note: &str) {
if let Some(id) = self.get_position_ref() { if let Some(id) = self.get_position_ref() {
if self.get_by_id(id).is_some_and(|t| t.is_task()) { if self.get_by_id(id).is_some_and(|t| t.is_task()) {
let prop = build_prop(Kind::TextNote, note.trim(), id.clone()); let prop = build_prop(Kind::TextNote, note.trim(), *id);
self.submit(prop); self.submit(prop);
return; return;
} }
@ -968,7 +958,7 @@ fn referenced_events(event: &Event) -> Option<&EventId> {
}) })
} }
fn matching_tag_id<'a>(event: &'a Event, ids: &'a Vec<&'a EventId>) -> Option<&'a EventId> { fn matching_tag_id<'a>(event: &'a Event, ids: &'a [&'a EventId]) -> Option<&'a EventId> {
event.tags.iter().find_map(|tag| match tag.as_standardized() { event.tags.iter().find_map(|tag| match tag.as_standardized() {
Some(TagStandard::Event { event_id, .. }) if ids.contains(&event_id) => Some(event_id), Some(TagStandard::Event { event_id, .. }) if ids.contains(&event_id) => Some(event_id),
_ => None _ => None
@ -976,10 +966,10 @@ fn matching_tag_id<'a>(event: &'a Event, ids: &'a Vec<&'a EventId>) -> Option<&'
} }
/// Filters out event timestamps to those that start or stop one of the given events /// Filters out event timestamps to those that start or stop one of the given events
fn timestamps<'a>(events: impl Iterator<Item=&'a Event>, ids: &'a Vec<&'a EventId>) -> impl Iterator<Item=(&Timestamp, Option<&EventId>)> { fn timestamps<'a>(events: impl Iterator<Item=&'a Event>, ids: &'a [&'a EventId]) -> impl Iterator<Item=(&Timestamp, Option<&EventId>)> {
events.map(|event| (&event.created_at, matching_tag_id(event, ids))) events.map(|event| (&event.created_at, matching_tag_id(event, ids)))
.dedup_by(|(_, e1), (_, e2)| e1 == e2) .dedup_by(|(_, e1), (_, e2)| e1 == e2)
.skip_while(|element| element.1 == None) .skip_while(|element| element.1.is_none())
} }
/// Iterates Events to accumulate times tracked /// Iterates Events to accumulate times tracked
@ -1016,7 +1006,7 @@ impl Iterator for Durations<'_> {
} }
} }
let now = self.threshold.unwrap_or(Timestamp::now()).as_u64(); let now = self.threshold.unwrap_or(Timestamp::now()).as_u64();
return start.filter(|t| t < &now).map(|stamp| Duration::from_secs(now.saturating_sub(stamp))); start.filter(|t| t < &now).map(|stamp| Duration::from_secs(now.saturating_sub(stamp)))
} }
} }
@ -1065,7 +1055,7 @@ impl<'a> Iterator for ChildIterator<'a> {
return None; return None;
} }
let id = self.queue[self.index]; let id = self.queue[self.index];
if let Some(task) = self.tasks.get(&id) { if let Some(task) = self.tasks.get(id) {
self.queue.reserve(task.children.len()); self.queue.reserve(task.children.len());
self.queue.extend(task.children.iter()); self.queue.extend(task.children.iter());
} else { } else {
@ -1097,7 +1087,7 @@ impl<'a> Iterator for ParentIterator<'a> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.current.and_then(|id| self.tasks.get(&id)).map(|t| { self.current.and_then(|id| self.tasks.get(&id)).map(|t| {
self.prev.map(|id| assert!(t.children.contains(&id))); self.prev.inspect(|id| assert!(t.children.contains(id)));
self.prev = self.current; self.prev = self.current;
self.current = t.parent_id().cloned(); self.current = t.parent_id().cloned();
t t