From bde87af3877d4a0b071e331c93a07e0acf51bf7a Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Sun, 28 Aug 2022 17:29:30 +0300 Subject: [PATCH] Refactor filter() method in Listing trait --- src/components/mail/listing.rs | 2 +- src/components/mail/listing/compact.rs | 104 ++++++++----------- src/components/mail/listing/conversations.rs | 93 ++++++++--------- src/components/mail/listing/plain.rs | 81 ++++++--------- src/components/mail/listing/thread.rs | 65 ++++++++++++ 5 files changed, 178 insertions(+), 167 deletions(-) diff --git a/src/components/mail/listing.rs b/src/components/mail/listing.rs index c9f894d19..3bdf9113e 100644 --- a/src/components/mail/listing.rs +++ b/src/components/mail/listing.rs @@ -505,7 +505,7 @@ pub trait ListingTrait: Component { fn filter( &mut self, _filter_term: String, - _results: Result>, + _results: SmallVec<[EnvelopeHash; 512]>, _context: &Context, ) { } diff --git a/src/components/mail/listing/compact.rs b/src/components/mail/listing/compact.rs index ab55248f2..b29807271 100644 --- a/src/components/mail/listing/compact.rs +++ b/src/components/mail/listing/compact.rs @@ -768,7 +768,7 @@ impl ListingTrait for CompactListing { fn filter( &mut self, filter_term: String, - results: Result>, + results: SmallVec<[EnvelopeHash; 512]>, context: &Context, ) { self.order.clear(); @@ -780,70 +780,41 @@ impl ListingTrait for CompactListing { self.row_updates.clear(); let account = &context.accounts[&self.cursor_pos.0]; - match results { - Ok(results) => { - let threads = account.collection.get_threads(self.cursor_pos.1); - for env_hash in results { - if !account.collection.contains_key(&env_hash) { - continue; - } - let env_thread_node_hash = account.collection.get_env(env_hash).thread(); - if !threads.thread_nodes.contains_key(&env_thread_node_hash) { - continue; - } - let thread = - threads.find_group(threads.thread_nodes[&env_thread_node_hash].group); - if self.filtered_order.contains_key(&thread) { - continue; - } - if self.all_threads.contains(&thread) { - self.filtered_selection.push(thread); - self.filtered_order - .insert(thread, self.filtered_selection.len() - 1); - } - } - if !self.filtered_selection.is_empty() { - threads.group_inner_sort_by( - &mut self.filtered_selection, - self.sort, - &context.accounts[&self.cursor_pos.0].collection.envelopes, - ); - self.new_cursor_pos.2 = - std::cmp::min(self.filtered_selection.len() - 1, self.cursor_pos.2); - } else { - self.data_columns.columns[0] = - CellBuffer::new_with_context(0, 0, None, context); - } - self.redraw_threads_list( - context, - Box::new(self.filtered_selection.clone().into_iter()) - as Box>, - ); + let threads = account.collection.get_threads(self.cursor_pos.1); + for env_hash in results { + if !account.collection.contains_key(&env_hash) { + continue; } - Err(e) => { - self.cursor_pos.2 = 0; - self.new_cursor_pos.2 = 0; - let message = format!( - "Encountered an error while searching for `{}`: {}.", - &self.filter_term, e - ); - log( - format!("Failed to search for term {}: {}", &self.filter_term, e), - ERROR, - ); - self.data_columns.columns[0] = - CellBuffer::new_with_context(message.len(), 1, None, context); - write_string_to_grid( - &message, - &mut self.data_columns.columns[0], - self.color_cache.theme_default.fg, - self.color_cache.theme_default.bg, - self.color_cache.theme_default.attrs, - ((0, 0), (message.len() - 1, 0)), - None, - ); + let env_thread_node_hash = account.collection.get_env(env_hash).thread(); + if !threads.thread_nodes.contains_key(&env_thread_node_hash) { + continue; + } + let thread = threads.find_group(threads.thread_nodes[&env_thread_node_hash].group); + if self.filtered_order.contains_key(&thread) { + continue; + } + if self.all_threads.contains(&thread) { + self.filtered_selection.push(thread); + self.filtered_order + .insert(thread, self.filtered_selection.len() - 1); } } + if !self.filtered_selection.is_empty() { + threads.group_inner_sort_by( + &mut self.filtered_selection, + self.sort, + &context.accounts[&self.cursor_pos.0].collection.envelopes, + ); + self.new_cursor_pos.2 = + std::cmp::min(self.filtered_selection.len() - 1, self.cursor_pos.2); + } else { + self.data_columns.columns[0] = CellBuffer::new_with_context(0, 0, None, context); + } + self.redraw_threads_list( + context, + Box::new(self.filtered_selection.clone().into_iter()) + as Box>, + ); } fn unfocused(&self) -> bool { @@ -2020,7 +1991,14 @@ impl Component for CompactListing { match handle.chan.try_recv() { Err(_) => { /* search was canceled */ } Ok(None) => { /* something happened, perhaps a worker thread panicked */ } - Ok(Some(results)) => self.filter(filter_term, results, context), + Ok(Some(Ok(results))) => self.filter(filter_term, results, context), + Ok(Some(Err(err))) => { + context.replies.push_back(UIEvent::Notification( + Some("Could not perform search".to_string()), + err.to_string(), + Some(crate::types::NotificationType::Error(err.kind)), + )); + } } self.set_dirty(true); } diff --git a/src/components/mail/listing/conversations.rs b/src/components/mail/listing/conversations.rs index b29b43246..51ce76e84 100644 --- a/src/components/mail/listing/conversations.rs +++ b/src/components/mail/listing/conversations.rs @@ -480,7 +480,7 @@ impl ListingTrait for ConversationsListing { fn filter( &mut self, filter_term: String, - results: Result>, + results: SmallVec<[EnvelopeHash; 512]>, context: &Context, ) { if filter_term.is_empty() { @@ -499,59 +499,41 @@ impl ListingTrait for ConversationsListing { } let account = &context.accounts[&self.cursor_pos.0]; - match results { - Ok(results) => { - let threads = account.collection.get_threads(self.cursor_pos.1); - for env_hash in results { - if !account.collection.contains_key(&env_hash) { - continue; - } - let env_thread_node_hash = account.collection.get_env(env_hash).thread(); - if !threads.thread_nodes.contains_key(&env_thread_node_hash) { - continue; - } - let thread = - threads.find_group(threads.thread_nodes[&env_thread_node_hash].group); - if self.filtered_order.contains_key(&thread) { - continue; - } - if self.all_threads.contains(&thread) { - self.filtered_selection.push(thread); - self.filtered_order - .insert(thread, self.filtered_selection.len().saturating_sub(1)); - } - } - if !self.filtered_selection.is_empty() { - threads.group_inner_sort_by( - &mut self.filtered_selection, - self.sort, - &context.accounts[&self.cursor_pos.0].collection.envelopes, - ); - self.new_cursor_pos.2 = std::cmp::min( - self.filtered_selection.len().saturating_sub(1), - self.cursor_pos.2, - ); - } - self.redraw_threads_list( - context, - Box::new(self.filtered_selection.clone().into_iter()) - as Box>, - ); + let threads = account.collection.get_threads(self.cursor_pos.1); + for env_hash in results { + if !account.collection.contains_key(&env_hash) { + continue; } - Err(e) => { - self.cursor_pos.2 = 0; - self.new_cursor_pos.2 = 0; - let message = format!( - "Encountered an error while searching for `{}`: {}.", - self.filter_term, e - ); - log( - format!("Failed to search for term {}: {}", self.filter_term, e), - ERROR, - ); - self.rows = Err(message); + let env_thread_node_hash = account.collection.get_env(env_hash).thread(); + if !threads.thread_nodes.contains_key(&env_thread_node_hash) { + continue; + } + let thread = threads.find_group(threads.thread_nodes[&env_thread_node_hash].group); + if self.filtered_order.contains_key(&thread) { + continue; + } + if self.all_threads.contains(&thread) { + self.filtered_selection.push(thread); + self.filtered_order + .insert(thread, self.filtered_selection.len().saturating_sub(1)); } } + if !self.filtered_selection.is_empty() { + threads.group_inner_sort_by( + &mut self.filtered_selection, + self.sort, + &context.accounts[&self.cursor_pos.0].collection.envelopes, + ); + self.new_cursor_pos.2 = std::cmp::min( + self.filtered_selection.len().saturating_sub(1), + self.cursor_pos.2, + ); + } + self.redraw_threads_list( + context, + Box::new(self.filtered_selection.clone().into_iter()) + as Box>, + ); } fn unfocused(&self) -> bool { @@ -1438,7 +1420,14 @@ impl Component for ConversationsListing { match handle.chan.try_recv() { Err(_) => { /* search was canceled */ } Ok(None) => { /* something happened, perhaps a worker thread panicked */ } - Ok(Some(results)) => self.filter(filter_term, results, context), + Ok(Some(Ok(results))) => self.filter(filter_term, results, context), + Ok(Some(Err(err))) => { + context.replies.push_back(UIEvent::Notification( + Some("Could not perform search".to_string()), + err.to_string(), + Some(crate::types::NotificationType::Error(err.kind)), + )); + } } self.set_dirty(true); } diff --git a/src/components/mail/listing/plain.rs b/src/components/mail/listing/plain.rs index 8b5f38a59..84a41f381 100644 --- a/src/components/mail/listing/plain.rs +++ b/src/components/mail/listing/plain.rs @@ -595,7 +595,7 @@ impl ListingTrait for PlainListing { fn filter( &mut self, filter_term: String, - results: Result>, + results: SmallVec<[EnvelopeHash; 512]>, context: &Context, ) { if filter_term.is_empty() { @@ -614,58 +614,30 @@ impl ListingTrait for PlainListing { } let account = &context.accounts[&self.cursor_pos.0]; - match results { - Ok(results) => { - for env_hash in results { - if !account.collection.contains_key(&env_hash) { - continue; - } - if self.filtered_order.contains_key(&env_hash) { - continue; - } - if self.all_envelopes.contains(&env_hash) { - self.filtered_selection.push(env_hash); - self.filtered_order - .insert(env_hash, self.filtered_selection.len() - 1); - } - } - if !self.filtered_selection.is_empty() { - self.new_cursor_pos.2 = - std::cmp::min(self.filtered_selection.len() - 1, self.cursor_pos.2); - } else { - self.data_columns.columns[0] = - CellBuffer::new_with_context(0, 0, None, context); - } - self.redraw_list( - context, - Box::new(self.filtered_selection.clone().into_iter()) - as Box>, - ); + for env_hash in results { + if !account.collection.contains_key(&env_hash) { + continue; } - Err(e) => { - self.cursor_pos.2 = 0; - self.new_cursor_pos.2 = 0; - let message = format!( - "Encountered an error while searching for `{}`: {}.", - &self.filter_term, e - ); - log( - format!("Failed to search for term {}: {}", &self.filter_term, e), - ERROR, - ); - self.data_columns.columns[0] = - CellBuffer::new_with_context(message.len(), 1, None, context); - write_string_to_grid( - &message, - &mut self.data_columns.columns[0], - self.color_cache.theme_default.fg, - self.color_cache.theme_default.bg, - self.color_cache.theme_default.attrs, - ((0, 0), (message.len() - 1, 0)), - None, - ); + if self.filtered_order.contains_key(&env_hash) { + continue; + } + if self.all_envelopes.contains(&env_hash) { + self.filtered_selection.push(env_hash); + self.filtered_order + .insert(env_hash, self.filtered_selection.len() - 1); } } + if !self.filtered_selection.is_empty() { + self.new_cursor_pos.2 = + std::cmp::min(self.filtered_selection.len() - 1, self.cursor_pos.2); + } else { + self.data_columns.columns[0] = CellBuffer::new_with_context(0, 0, None, context); + } + self.redraw_list( + context, + Box::new(self.filtered_selection.clone().into_iter()) + as Box>, + ); } fn unfocused(&self) -> bool { @@ -1402,7 +1374,14 @@ impl Component for PlainListing { match handle.chan.try_recv() { Err(_) => { /* search was canceled */ } Ok(None) => { /* something happened, perhaps a worker thread panicked */ } - Ok(Some(results)) => self.filter(filter_term, results, context), + Ok(Some(Ok(results))) => self.filter(filter_term, results, context), + Ok(Some(Err(err))) => { + context.replies.push_back(UIEvent::Notification( + Some("Could not perform search".to_string()), + err.to_string(), + Some(crate::types::NotificationType::Error(err.kind)), + )); + } } self.set_dirty(true); } diff --git a/src/components/mail/listing/thread.rs b/src/components/mail/listing/thread.rs index 44fe2b638..029a0408c 100644 --- a/src/components/mail/listing/thread.rs +++ b/src/components/mail/listing/thread.rs @@ -113,6 +113,12 @@ pub struct ThreadListing { /// Cache current view. color_cache: ColorCache, + #[allow(clippy::type_complexity)] + search_job: Option<( + String, + crate::jobs::JoinHandle>>, + )>, + data_columns: DataColumns, rows_drawn: SegmentTree, rows: Vec<((usize, bool, bool, EnvelopeHash), EntryStrings)>, @@ -721,6 +727,19 @@ impl ListingTrait for ThreadListing { } } + fn filter( + &mut self, + filter_term: String, + _results: SmallVec<[EnvelopeHash; 512]>, + context: &Context, + ) { + if filter_term.is_empty() { + return; + } + + let _account = &context.accounts[&self.cursor_pos.0]; + } + fn unfocused(&self) -> bool { self.unfocused } @@ -758,6 +777,7 @@ impl ThreadListing { initialised: false, movement: None, id: ComponentId::new_v4(), + search_job: None, }) } @@ -1308,8 +1328,53 @@ impl Component for ThreadListing { self.refresh_mailbox(context, false); return true; } + Action::Listing(Search(ref filter_term)) if !self.unfocused => { + match context.accounts[&self.cursor_pos.0].search( + filter_term, + self.sort, + self.cursor_pos.1, + ) { + Ok(job) => { + let handle = context.accounts[&self.cursor_pos.0] + .job_executor + .spawn_specialized(job); + self.search_job = Some((filter_term.to_string(), handle)); + } + Err(err) => { + context.replies.push_back(UIEvent::Notification( + Some("Could not perform search".to_string()), + err.to_string(), + Some(crate::types::NotificationType::Error(err.kind)), + )); + } + }; + self.set_dirty(true); + return true; + } _ => {} }, + UIEvent::StatusEvent(StatusEvent::JobFinished(ref job_id)) + if self + .search_job + .as_ref() + .map(|(_, j)| j == job_id) + .unwrap_or(false) => + { + let (filter_term, mut handle) = self.search_job.take().unwrap(); + match handle.chan.try_recv() { + Err(_) => { /* search was canceled */ } + Ok(None) => { /* something happened, perhaps a worker thread panicked */ } + Ok(Some(Ok(results))) => self.filter(filter_term, results, context), + Ok(Some(Err(err))) => { + context.replies.push_back(UIEvent::Notification( + Some("Could not perform search".to_string()), + err.to_string(), + Some(crate::types::NotificationType::Error(err.kind)), + )); + } + } + self.set_dirty(true); + } _ => {} } false