Re-enable compact listing style

Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
pull/312/head
Manos Pitsidianakis 2023-11-25 22:41:17 +02:00
parent d018f07aa5
commit 458258e1aa
Signed by: Manos Pitsidianakis
GPG Key ID: 7729C7707F7E09D0
4 changed files with 369 additions and 268 deletions

View File

@ -233,8 +233,8 @@ impl<T> RowsState<T> {
//mod conversations;
//pub use self::conversations::*;
//mod compact;
//pub use self::compact::*;
mod compact;
pub use self::compact::*;
//mod thread;
//pub use self::thread::*;
@ -922,7 +922,7 @@ pub trait ListingTrait: Component {
#[derive(Debug)]
pub enum ListingComponent {
//Compact(Box<CompactListing>),
Compact(Box<CompactListing>),
//Conversations(Box<ConversationsListing>),
Offline(Box<OfflineListing>),
Plain(Box<PlainListing>),
@ -935,7 +935,7 @@ impl std::ops::Deref for ListingComponent {
fn deref(&self) -> &Self::Target {
match &self {
//Compact(ref l) => l.as_ref(),
Compact(ref l) => l.as_ref(),
//Conversations(ref l) => l.as_ref(),
Offline(ref l) => l.as_ref(),
Plain(ref l) => l.as_ref(),
@ -947,7 +947,7 @@ impl std::ops::Deref for ListingComponent {
impl std::ops::DerefMut for ListingComponent {
fn deref_mut(&mut self) -> &mut (dyn MailListingTrait + 'static) {
match self {
//Compact(l) => l.as_mut(),
Compact(l) => l.as_mut(),
//Conversations(l) => l.as_mut(),
Offline(l) => l.as_mut(),
Plain(l) => l.as_mut(),
@ -959,7 +959,7 @@ impl std::ops::DerefMut for ListingComponent {
impl ListingComponent {
fn id(&self) -> ComponentId {
match self {
//Compact(l) => l.as_component().id(),
Compact(l) => l.as_component().id(),
//Conversations(l) => l.as_component().id(),
Offline(l) => l.as_component().id(),
Plain(l) => l.as_component().id(),
@ -1036,7 +1036,7 @@ pub struct Listing {
impl std::fmt::Display for Listing {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self.component {
//Compact(ref l) => write!(f, "{}", l),
Compact(ref l) => write!(f, "{}", l),
//Conversations(ref l) => write!(f, "{}", l),
Offline(ref l) => write!(f, "{}", l),
Plain(ref l) => write!(f, "{}", l),
@ -2439,7 +2439,7 @@ impl Component for Listing {
ret.insert(
self.component.id(),
match &self.component {
//Compact(l) => l.as_component(),
Compact(l) => l.as_component(),
//Conversations(l) => l.as_component(),
Offline(l) => l.as_component(),
Plain(l) => l.as_component(),
@ -2455,7 +2455,7 @@ impl Component for Listing {
ret.insert(
self.component.id(),
match &mut self.component {
//Compact(l) => l.as_component_mut(),
Compact(l) => l.as_component_mut(),
//Conversations(l) => l.as_component_mut(),
Offline(l) => l.as_component_mut(),
Plain(l) => l.as_component_mut(),
@ -3091,61 +3091,54 @@ impl Listing {
!matches!(self.component.focus(), Focus::EntryFullscreen) && self.menu_visibility
}
fn set_style(&mut self, _new_style: IndexStyle, context: &mut Context) {
if matches!(self.component, Plain(_)) {
return;
}
let coordinates = self.component.coordinates();
self.component = Plain(PlainListing::new(self.id, coordinates));
fn set_style(&mut self, new_style: IndexStyle, context: &mut Context) {
let old = match new_style {
IndexStyle::Conversations | IndexStyle::Threaded | IndexStyle::Plain => {
if matches!(self.component, Plain(_)) {
return;
}
let coordinates = self.component.coordinates();
std::mem::replace(
&mut self.component,
Plain(PlainListing::new(self.id, coordinates)),
)
}
//IndexStyle::Threaded => {
// return;
// //if matches!(self.component, Threaded(_)) {
// // return;
// //}
// //let coordinates = self.component.coordinates();
// //std::mem::replace(
// // &mut self.component,
// // Threaded(ThreadListing::new(self.id, coordinates,
// // context)), //)
//}
IndexStyle::Compact => {
if matches!(self.component, Compact(_)) {
return;
}
let coordinates = self.component.coordinates();
std::mem::replace(
&mut self.component,
Compact(CompactListing::new(self.id, coordinates)),
)
} //IndexStyle::Conversations => {
// return;
// //if matches!(self.component, Conversations(_)) {
// // return;
// //}
// //let coordinates = self.component.coordinates();
// //std::mem::replace(
// // &mut self.component,
// // Conversations(ConversationsListing::new(self.id,
// // coordinates)),
//}
};
self.component
.process_event(&mut UIEvent::VisibilityChange(true), context);
//let old = match new_style {
// IndexStyle::Plain => {
// if matches!(self.component, Plain(_)) {
// return;
// }
// let coordinates = self.component.coordinates();
// std::mem::replace(
// &mut self.component,
// Plain(PlainListing::new(self.id, coordinates)),
// )
// }
// IndexStyle::Threaded => {
// return;
// //if matches!(self.component, Threaded(_)) {
// // return;
// //}
// //let coordinates = self.component.coordinates();
// //std::mem::replace(
// // &mut self.component,
// // Threaded(ThreadListing::new(self.id, coordinates,
// context)), //)
// }
// IndexStyle::Compact => {
// return;
// //if matches!(self.component, Compact(_)) {
// // return;
// //}
// //let coordinates = self.component.coordinates();
// //std::mem::replace(
// // &mut self.component,
// // Compact(CompactListing::new(self.id, coordinates)),
// //)
// }
// IndexStyle::Conversations => {
// return;
// //if matches!(self.component, Conversations(_)) {
// // return;
// //}
// //let coordinates = self.component.coordinates();
// //std::mem::replace(
// // &mut self.component,
// // Conversations(ConversationsListing::new(self.id,
// coordinates)), //)
// }
//};
//old.unrealize(context);
//self.component.realize(self.id.into(), context);
old.unrealize(context);
self.component.realize(self.id.into(), context);
}
}

View File

@ -19,13 +19,13 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
use std::{cmp, collections::BTreeMap, convert::TryInto, iter::FromIterator};
use std::{collections::BTreeMap, convert::TryInto, iter::FromIterator};
use indexmap::IndexSet;
use melib::{SortField, SortOrder, TagHash, Threads};
use melib::{Address, SortField, SortOrder, TagHash, Threads};
use super::*;
use crate::{components::PageMovement, jobs::JoinHandle};
use crate::{components::PageMovement, jobs::JoinHandle, segment_tree::SegmentTree};
macro_rules! row_attr {
($color_cache:expr, $even: expr, $unseen:expr, $highlighted:expr, $selected:expr $(,)*) => {{
@ -230,11 +230,10 @@ impl MailListingTrait for CompactListing {
match context.accounts[&self.cursor_pos.0].load(self.cursor_pos.1) {
Ok(()) => {}
Err(_) => {
self.length = 0;
let message: String =
context.accounts[&self.cursor_pos.0][&self.cursor_pos.1].status();
self.data_columns.columns[0].resize_with_context(message.len(), 1, context);
self.length = 0;
{
if self.data_columns.columns[0].resize_with_context(message.len(), 1, context) {
let area = self.data_columns.columns[0].area();
self.data_columns.columns[0].grid_mut().write_string(
message.as_str(),
@ -243,8 +242,8 @@ impl MailListingTrait for CompactListing {
self.color_cache.theme_default.attrs,
area,
None,
)
};
);
}
return;
}
}
@ -265,13 +264,15 @@ impl MailListingTrait for CompactListing {
Box::new(roots.into_iter()) as Box<dyn Iterator<Item = ThreadHash>>,
);
if !force && old_cursor_pos == self.new_cursor_pos {
self.kick_parent(self.parent, ListingMessage::UpdateView, context);
} else if self.unfocused() {
if let Some((thread_hash, env_hash)) = self
.get_thread_under_cursor(self.cursor_pos.2)
.and_then(|thread| self.rows.thread_to_env.get(&thread).map(|e| (thread, e[0])))
{
if let Some((thread_hash, env_hash)) = self
.get_thread_under_cursor(self.cursor_pos.2)
.and_then(|thread| self.rows.thread_to_env.get(&thread).map(|e| (thread, e[0])))
{
if !force && old_cursor_pos == self.new_cursor_pos {
self.kick_parent(self.parent, ListingMessage::UpdateView, context);
} else if self.unfocused() {
self.force_draw = true;
self.dirty = true;
self.kick_parent(
self.parent,
ListingMessage::OpenEntryUnderCursor {
@ -293,9 +294,10 @@ impl MailListingTrait for CompactListing {
items: Box<dyn Iterator<Item = ThreadHash>>,
) {
let account = &context.accounts[&self.cursor_pos.0];
let threads = account.collection.get_threads(self.cursor_pos.1);
self.rows.clear();
self.length = 0;
// Use account settings only if no sortcmd has been used
if !self.sortcmd {
self.sort = context.accounts[&self.cursor_pos.0].settings.account.order
@ -350,7 +352,7 @@ impl MailListingTrait for CompactListing {
);
log::debug!("{:#?}", context.accounts);
panic!();
continue;
}
let root_envelope: EnvelopeRef = context.accounts[&self.cursor_pos.0]
.collection
@ -447,24 +449,19 @@ impl MailListingTrait for CompactListing {
/* subject */
row_widths.3.push(
(entry_strings.flag.grapheme_width()
+ 1
+ entry_strings.subject.grapheme_width()
+ 1
+ entry_strings.tags.grapheme_width()
+ 16)
.try_into()
.unwrap_or(255),
+ entry_strings.tags.grapheme_width())
.try_into()
.unwrap_or(255),
);
min_width.1 = cmp::max(min_width.1, entry_strings.date.grapheme_width()); /* date */
min_width.2 = cmp::max(min_width.2, entry_strings.from.grapheme_width()); /* from */
min_width.3 = cmp::max(
min_width.3,
min_width.1 = min_width.1.max(entry_strings.date.grapheme_width()); /* date */
min_width.2 = min_width.2.max(entry_strings.from.grapheme_width()); /* from */
min_width.3 = min_width.3.max(
entry_strings.flag.grapheme_width()
+ 1
+ entry_strings.subject.grapheme_width()
+ 1
+ entry_strings.tags.grapheme_width()
+ 16,
+ entry_strings.tags.grapheme_width(),
); /* subject */
self.rows.insert_thread(
thread,
@ -484,7 +481,7 @@ impl MailListingTrait for CompactListing {
self.data_columns.elasticities[0].set_rigid();
self.data_columns.elasticities[1].set_rigid();
self.data_columns.elasticities[2].set_grow(5, Some(35));
self.data_columns.elasticities[2].set_grow(15, Some(35));
self.data_columns.elasticities[3].set_rigid();
self.data_columns
.cursor_config
@ -498,17 +495,16 @@ impl MailListingTrait for CompactListing {
.set_even_odd_theme(self.color_cache.even, self.color_cache.odd);
/* index column */
self.data_columns.columns[0].resize_with_context(min_width.0, self.rows.len(), context);
self.data_columns.segment_tree[0] = row_widths.0.into();
_ = self.data_columns.columns[0].resize_with_context(min_width.0, self.rows.len(), context);
/* date column */
self.data_columns.columns[1].resize_with_context(min_width.1, self.rows.len(), context);
self.data_columns.segment_tree[1] = row_widths.1.into();
_ = self.data_columns.columns[1].resize_with_context(min_width.1, self.rows.len(), context);
/* from column */
self.data_columns.columns[2].resize_with_context(min_width.2, self.rows.len(), context);
self.data_columns.segment_tree[2] = row_widths.2.into();
_ = self.data_columns.columns[2].resize_with_context(min_width.2, self.rows.len(), context);
/* subject column */
self.data_columns.columns[3].resize_with_context(min_width.3, self.rows.len(), context);
_ = self.data_columns.columns[3].resize_with_context(min_width.3, self.rows.len(), context);
self.data_columns.segment_tree[0] = row_widths.0.into();
self.data_columns.segment_tree[1] = row_widths.1.into();
self.data_columns.segment_tree[2] = row_widths.2.into();
self.data_columns.segment_tree[3] = row_widths.3.into();
self.rows_drawn = SegmentTree::from(
@ -516,16 +512,11 @@ impl MailListingTrait for CompactListing {
.take(self.rows.len())
.collect::<SmallVec<_>>(),
);
debug_assert!(self.rows_drawn.array.len() == self.rows.len());
self.draw_rows(
context,
0,
std::cmp::min(80, self.rows.len().saturating_sub(1)),
);
debug_assert_eq!(self.rows_drawn.array.len(), self.rows.len());
self.draw_rows(context, 0, 80.min(self.rows.len().saturating_sub(1)));
if self.length == 0 && self.filter_term.is_empty() {
let message: String = account[&self.cursor_pos.1].status();
self.data_columns.columns[0].resize_with_context(message.len(), 1, context);
{
if self.data_columns.columns[0].resize_with_context(message.len(), 1, context) {
let area = self.data_columns.columns[0].area();
self.data_columns.columns[0].grid_mut().write_string(
&message,
@ -534,8 +525,8 @@ impl MailListingTrait for CompactListing {
self.color_cache.theme_default.attrs,
area,
None,
)
};
);
}
}
}
}
@ -637,8 +628,6 @@ impl ListingTrait for CompactListing {
{
self.refresh_mailbox(context, false);
}
let upper_left = area.upper_left();
let bottom_right = area.bottom_right();
if self.length == 0 {
grid.clear_area(area, self.color_cache.theme_default);
@ -679,7 +668,20 @@ impl ListingTrait for CompactListing {
self.new_cursor_pos.2 = (self.length.saturating_sub(1) / rows) * rows;
}
}
PageMovement::Right(_) | PageMovement::Left(_) => {}
PageMovement::Right(amount) => {
self.data_columns.x_offset += amount;
self.data_columns.x_offset = self.data_columns.x_offset.min(
self.data_columns
.widths
.iter()
.map(|w| w + 2)
.sum::<usize>()
.saturating_sub(2),
);
}
PageMovement::Left(amount) => {
self.data_columns.x_offset = self.data_columns.x_offset.saturating_sub(amount);
}
PageMovement::Home => {
self.new_cursor_pos.2 = 0;
}
@ -689,11 +691,15 @@ impl ListingTrait for CompactListing {
}
}
if self.force_draw {
grid.clear_area(area, self.color_cache.theme_default);
}
let prev_page_no = (self.cursor_pos.2).wrapping_div(rows);
let page_no = (self.new_cursor_pos.2).wrapping_div(rows);
let top_idx = page_no * rows;
let end_idx = cmp::min(self.length.saturating_sub(1), top_idx + rows - 1);
let end_idx = self.length.saturating_sub(1).min(top_idx + rows - 1);
self.draw_rows(context, top_idx, end_idx);
/* If cursor position has changed, remove the highlight from the previous
@ -727,11 +733,11 @@ impl ListingTrait for CompactListing {
self.cursor_pos.2 = self.new_cursor_pos.2;
}
if !self.force_draw {
grid.clear_area(area, self.color_cache.theme_default);
}
/* Page_no has changed, so draw new page */
_ = self
.data_columns
.recalc_widths((area.width(), area.height()), top_idx);
grid.clear_area(area, self.color_cache.theme_default);
_ = self.data_columns.recalc_widths(area.size(), top_idx);
/* copy table columns */
self.data_columns
.draw(grid, top_idx, self.cursor_pos.2, grid.bounds_iter(area));
@ -754,11 +760,13 @@ impl ListingTrait for CompactListing {
/* clear gap if available height is more than count of entries */
if top_idx + rows > self.length {
grid.clear_area(
area.skip_rows(top_idx + rows - self.length),
grid.change_theme(
area.skip_rows(self.length - top_idx),
self.color_cache.theme_default,
);
}
self.force_draw = false;
context.dirty_areas.push_back(area);
}
@ -799,10 +807,9 @@ impl ListingTrait for CompactListing {
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);
self.new_cursor_pos.2 = self.cursor_pos.2.min(self.filtered_selection.len() - 1);
} else {
self.data_columns.columns[0].resize_with_context(0, 0, context);
_ = self.data_columns.columns[0].resize_with_context(0, 0, context);
}
self.redraw_threads_list(
context,
@ -891,10 +898,9 @@ impl std::fmt::Display for CompactListing {
}
impl CompactListing {
pub const DESCRIPTION: &'static str = "compact listing";
pub fn new(parent: ComponentId, coordinates: (AccountHash, MailboxHash)) -> Box<Self> {
Box::new(CompactListing {
cursor_pos: (coordinates.0, MailboxHash::default(), 0),
cursor_pos: (AccountHash::default(), MailboxHash::default(), 0),
new_cursor_pos: (coordinates.0, coordinates.1, 0),
length: 0,
sort: (Default::default(), Default::default()),
@ -1332,6 +1338,7 @@ impl CompactListing {
self.data_columns.columns[3].area().width(),
);
let columns = &mut self.data_columns.columns;
for (idx, ((_thread_hash, root_env_hash), strings)) in self
.rows
.entries
@ -1349,12 +1356,12 @@ impl CompactListing {
//);
//debug!("{:#?}", context.accounts);
panic!();
continue;
}
let row_attr = self.rows.row_attr_cache[&idx];
let (x, _) = {
let area = self.data_columns.columns[0].area().nth_row(idx);
self.data_columns.columns[0].grid_mut().write_string(
let area = columns[0].area().nth_row(idx);
columns[0].grid_mut().write_string(
&idx.to_string(),
row_attr.fg,
row_attr.bg,
@ -1363,14 +1370,17 @@ impl CompactListing {
None,
)
};
for x in x..min_width.0 {
self.data_columns.columns[0].grid_mut()[(x, idx)]
for c in {
let area = columns[0].area();
columns[0].grid_mut().row_iter(area, x..min_width.0, idx)
} {
columns[0].grid_mut()[c]
.set_bg(row_attr.bg)
.set_attrs(row_attr.attrs);
}
let (x, _) = {
let area = self.data_columns.columns[1].area().nth_row(idx);
self.data_columns.columns[1].grid_mut().write_string(
let area = columns[1].area().nth_row(idx);
columns[1].grid_mut().write_string(
&strings.date,
row_attr.fg,
row_attr.bg,
@ -1379,14 +1389,17 @@ impl CompactListing {
None,
)
};
for x in x..min_width.1 {
self.data_columns.columns[1].grid_mut()[(x, idx)]
for c in {
let area = columns[1].area();
columns[1].grid_mut().row_iter(area, x..min_width.1, idx)
} {
columns[1].grid_mut()[c]
.set_bg(row_attr.bg)
.set_attrs(row_attr.attrs);
}
let (x, _) = {
let area = self.data_columns.columns[2].area().nth_row(idx);
self.data_columns.columns[2].grid_mut().write_string(
let area = columns[2].area().nth_row(idx);
columns[2].grid_mut().write_string(
&strings.from,
row_attr.fg,
row_attr.bg,
@ -1395,29 +1408,27 @@ impl CompactListing {
None,
)
};
for c in {
let area = columns[2].area();
columns[2].grid_mut().row_iter(area, x..min_width.2, idx)
} {
columns[2].grid_mut()[c]
.set_bg(row_attr.bg)
.set_attrs(row_attr.attrs)
.set_ch(' ');
}
#[cfg(feature = "regexp")]
{
for text_formatter in crate::conf::text_format_regexps(context, "listing.from") {
let t = self.data_columns.columns[2]
.grid_mut()
.insert_tag(text_formatter.tag);
let t = columns[2].grid_mut().insert_tag(text_formatter.tag);
for (start, end) in text_formatter.regexp.find_iter(strings.from.as_str()) {
self.data_columns.columns[2].grid_mut().set_tag(
t,
(start, idx),
(end, idx),
);
columns[2].grid_mut().set_tag(t, (start, idx), (end, idx));
}
}
}
for x in x..min_width.2 {
self.data_columns.columns[2].grid_mut()[(x, idx)]
.set_bg(row_attr.bg)
.set_attrs(row_attr.attrs);
}
let (x, _) = {
let area = self.data_columns.columns[3].area().nth_row(idx);
self.data_columns.columns[3].grid_mut().write_string(
let area = columns[3].area().nth_row(idx);
columns[3].grid_mut().write_string(
&strings.flag,
row_attr.fg,
row_attr.bg,
@ -1426,69 +1437,92 @@ impl CompactListing {
None,
)
};
let (x, _) = self.data_columns.columns[3].grid_mut().write_string(
&strings.subject,
row_attr.fg,
row_attr.bg,
row_attr.attrs,
self.data_columns.columns[3]
.area()
.nth_row(idx)
.skip_cols(x),
None,
);
let x = {
let area = columns[3].area().nth_row(idx).skip_cols(x);
columns[3]
.grid_mut()
.write_string(
&strings.subject,
row_attr.fg,
row_attr.bg,
row_attr.attrs,
area,
None,
)
.0
+ x
};
#[cfg(feature = "regexp")]
{
for text_formatter in crate::conf::text_format_regexps(context, "listing.subject") {
let t = self.data_columns.columns[3]
.grid_mut()
.insert_tag(text_formatter.tag);
let t = columns[3].grid_mut().insert_tag(text_formatter.tag);
for (start, end) in text_formatter.regexp.find_iter(strings.subject.as_str()) {
self.data_columns.columns[3].grid_mut().set_tag(
t,
(start, idx),
(end, idx),
);
columns[3].grid_mut().set_tag(t, (start, idx), (end, idx));
}
}
}
let x = {
let mut x = x + 1;
for (t, &color) in strings.tags.split_whitespace().zip(strings.tags.1.iter()) {
let color = color.unwrap_or(self.color_cache.tag_default.bg);
let (_x, _) = self.data_columns.columns[3].grid_mut().write_string(
t,
self.color_cache.tag_default.fg,
color,
self.color_cache.tag_default.attrs,
self.data_columns.columns[3]
.area()
.nth_row(idx)
.skip_cols(x + 1),
None,
);
self.data_columns.columns[3].grid_mut()[(x, idx)].set_bg(color);
if _x < min_width.3 {
self.data_columns.columns[3].grid_mut()[(_x, idx)]
.set_bg(color)
.set_keep_bg(true);
}
for x in (x + 1).._x {
self.data_columns.columns[3].grid_mut()[(x, idx)]
.set_keep_fg(true)
.set_keep_bg(true)
.set_keep_attrs(true);
}
self.data_columns.columns[3].grid_mut()[(x, idx)].set_keep_bg(true);
x = _x + 1;
let mut x = x + 1;
for (t, &color) in strings.tags.split_whitespace().zip(strings.tags.1.iter()) {
let color = color.unwrap_or(self.color_cache.tag_default.bg);
let _x = {
let area = columns[3].area().nth_row(idx).skip_cols(x + 1);
columns[3]
.grid_mut()
.write_string(
t,
self.color_cache.tag_default.fg,
color,
self.color_cache.tag_default.attrs,
area,
None,
)
.0
+ x
+ 1
};
for c in {
let area = columns[3].area();
columns[3].grid_mut().row_iter(area, x..(x + 1), idx)
} {
columns[3].grid_mut()[c].set_bg(color);
}
x
};
for x in x..min_width.3 {
self.data_columns.columns[3].grid_mut()[(x, idx)]
.set_ch(' ')
.set_bg(row_attr.bg)
.set_attrs(row_attr.attrs);
for c in {
let area = columns[3].area();
columns[3].grid_mut().row_iter(area, _x..(_x + 1), idx)
} {
columns[3].grid_mut()[c].set_bg(color).set_keep_bg(true);
}
for c in {
let area = columns[3].area();
columns[3].grid_mut().row_iter(area, (x + 1)..(_x + 1), idx)
} {
columns[3].grid_mut()[c]
.set_keep_fg(true)
.set_keep_bg(true)
.set_keep_attrs(true);
}
for c in {
let area = columns[3].area();
columns[3].grid_mut().row_iter(area, x..(x + 1), idx)
} {
columns[3].grid_mut()[c].set_keep_bg(true);
}
x = _x + 2;
}
}
if self.length == 0 && self.filter_term.is_empty() {
let account = &context.accounts[&self.cursor_pos.0];
let message: String = account[&self.cursor_pos.1].status();
if self.data_columns.columns[0].resize_with_context(message.len(), 1, context) {
let area = self.data_columns.columns[0].area();
self.data_columns.columns[0].grid_mut().write_string(
message.as_str(),
self.color_cache.theme_default.fg,
self.color_cache.theme_default.bg,
self.color_cache.theme_default.attrs,
area,
None,
);
}
}
}
@ -1550,7 +1584,7 @@ impl Component for CompactListing {
return;
}
if !self.unfocused() {
if matches!(self.focus, Focus::None) {
let mut area = area;
if !self.filter_term.is_empty() {
let (x, y) = grid.write_string(
@ -1563,24 +1597,15 @@ impl Component for CompactListing {
self.color_cache.theme_default.bg,
self.color_cache.theme_default.attrs,
area,
None,
Some(0),
);
let default_cell = {
let mut ret = Cell::with_char(' ');
ret.set_fg(self.color_cache.theme_default.fg)
.set_bg(self.color_cache.theme_default.bg)
.set_attrs(self.color_cache.theme_default.attrs);
ret
};
for row in grid.bounds_iter(area.nth_row(y).skip_cols(x)) {
for c in row {
grid[c] = default_cell;
}
}
grid.clear_area(area.skip(x, y).nth_row(y), self.color_cache.theme_default);
context.dirty_areas.push_back(area);
area = area.skip_rows(y + 1);
}
let rows = area.height();
if let Some(modifier) = self.modifier_command.take() {
@ -1633,8 +1658,8 @@ impl Component for CompactListing {
}
}
PageMovement::Down(amount) => {
for c in self.cursor_pos.2
..std::cmp::min(self.length, self.cursor_pos.2 + amount + 1)
for c in
self.cursor_pos.2..self.length.min(self.cursor_pos.2 + amount + 1)
{
if let Some(thread) = self.get_thread_under_cursor(c) {
self.rows.update_selection_with_thread(
@ -1652,8 +1677,7 @@ impl Component for CompactListing {
}
if modifier == Modifier::Intersection {
for c in (0..self.cursor_pos.2).chain(
(std::cmp::min(self.length, self.cursor_pos.2 + amount) + 1)
..self.length,
self.length.min(self.cursor_pos.2 + amount) + 1..self.length,
) {
if let Some(thread) = self.get_thread_under_cursor(c) {
self.rows
@ -1664,10 +1688,7 @@ impl Component for CompactListing {
}
PageMovement::PageDown(multiplier) => {
for c in self.cursor_pos.2
..std::cmp::min(
self.cursor_pos.2 + rows * multiplier + 1,
self.length,
)
..self.length.min(self.cursor_pos.2 + rows * multiplier + 1)
{
if let Some(thread) = self.get_thread_under_cursor(c) {
self.rows.update_selection_with_thread(
@ -1685,10 +1706,8 @@ impl Component for CompactListing {
}
if modifier == Modifier::Intersection {
for c in (0..self.cursor_pos.2).chain(
(std::cmp::min(
self.cursor_pos.2 + rows * multiplier,
self.length,
) + 1)..self.length,
self.length.min(self.cursor_pos.2 + rows * multiplier) + 1
..self.length,
) {
if let Some(thread) = self.get_thread_under_cursor(c) {
self.rows
@ -1772,13 +1791,11 @@ impl Component for CompactListing {
self.draw_list(grid, area, context);
}
} else {
self.view_area = area.into();
if self.length == 0 && self.dirty {
grid.clear_area(area, self.color_cache.theme_default);
context.dirty_areas.push_back(area);
return;
}
self.view_area = area.into();
}
self.dirty = false;
}
@ -1787,6 +1804,11 @@ impl Component for CompactListing {
let shortcuts = self.shortcuts(context);
match (&event, self.focus) {
(UIEvent::VisibilityChange(true), _) => {
self.force_draw = true;
self.set_dirty(true);
return true;
}
(UIEvent::Input(ref k), Focus::Entry)
if shortcut!(k == shortcuts[Shortcuts::LISTING]["focus_right"]) =>
{
@ -2019,6 +2041,7 @@ impl Component for CompactListing {
}
};
self.set_dirty(true);
return true;
}
UIEvent::Action(Action::Listing(Select(ref search_term))) if !self.unfocused() => {
match context.accounts[&self.cursor_pos.0].search(
@ -2046,6 +2069,7 @@ impl Component for CompactListing {
}
};
self.set_dirty(true);
return true;
}
UIEvent::StatusEvent(StatusEvent::JobFinished(ref job_id))
if self
@ -2090,11 +2114,11 @@ impl Component for CompactListing {
}
fn is_dirty(&self) -> bool {
match self.focus {
Focus::None => self.dirty,
Focus::Entry => self.dirty,
Focus::EntryFullscreen => false,
}
self.force_draw
|| match self.focus {
Focus::None | Focus::Entry => self.dirty,
Focus::EntryFullscreen => false,
}
}
fn set_dirty(&mut self, value: bool) {

View File

@ -19,7 +19,7 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
use std::{cmp, iter::FromIterator};
use std::iter::FromIterator;
use melib::{Address, SortField, SortOrder, ThreadNode};
@ -141,6 +141,8 @@ pub struct PlainListing {
#[allow(clippy::type_complexity)]
search_job: Option<(String, JoinHandle<Result<SmallVec<[EnvelopeHash; 512]>>>)>,
#[allow(clippy::type_complexity)]
select_job: Option<(String, JoinHandle<Result<SmallVec<[EnvelopeHash; 512]>>>)>,
filter_term: String,
filtered_selection: Vec<EnvelopeHash>,
filtered_order: HashMap<EnvelopeHash, usize>,
@ -286,6 +288,7 @@ impl MailListingTrait for PlainListing {
},
context,
);
self.set_focus(Focus::Entry, context);
}
}
}
@ -359,9 +362,7 @@ impl ListingTrait for PlainListing {
}
fn highlight_line(&mut self, grid: &mut CellBuffer, area: Area, idx: usize, context: &Context) {
let i = if let Some(i) = self.get_env_under_cursor(idx) {
i
} else {
let Some(i) = self.get_env_under_cursor(idx) else {
// self.length == 0
return;
};
@ -579,8 +580,7 @@ impl ListingTrait for PlainListing {
}
}
if !self.filtered_selection.is_empty() {
self.new_cursor_pos.2 =
std::cmp::min(self.filtered_selection.len() - 1, self.cursor_pos.2);
self.new_cursor_pos.2 = self.cursor_pos.2.min(self.filtered_selection.len() - 1);
} else {
_ = self.data_columns.columns[0].resize_with_context(0, 0, context);
}
@ -683,6 +683,7 @@ impl PlainListing {
local_collection: Vec::new(),
filter_term: String::new(),
search_job: None,
select_job: None,
filtered_selection: Vec::new(),
filtered_order: HashMap::default(),
data_columns: DataColumns::default(),
@ -824,7 +825,7 @@ impl PlainListing {
);
log::debug!("{:#?}", context.accounts);
panic!();
continue;
}
let envelope: EnvelopeRef = context.accounts[&self.cursor_pos.0].collection.get_env(i);
use melib::search::QueryTrait;
@ -849,6 +850,9 @@ impl PlainListing {
self.rows.row_attr_cache.insert(self.length, row_attr);
let entry_strings = self.make_entry_string(&envelope, context);
row_widths
.0
.push(digits_of_num!(self.length).try_into().unwrap_or(255));
row_widths.1.push(
entry_strings
.date
@ -871,10 +875,9 @@ impl PlainListing {
.try_into()
.unwrap_or(255),
);
min_width.1 = cmp::max(min_width.1, entry_strings.date.grapheme_width()); /* date */
min_width.2 = cmp::max(min_width.2, entry_strings.from.grapheme_width()); /* from */
min_width.3 = cmp::max(
min_width.3,
min_width.1 = min_width.1.max(entry_strings.date.grapheme_width()); /* date */
min_width.2 = min_width.2.max(entry_strings.from.grapheme_width()); /* from */
min_width.3 = min_width.3.max(
entry_strings.flag.grapheme_width()
+ entry_strings.subject.grapheme_width()
+ 1
@ -889,9 +892,6 @@ impl PlainListing {
self.length += 1;
}
row_widths
.0
.push(digits_of_num!(self.length).try_into().unwrap_or(255));
min_width.0 = self.length.saturating_sub(1).to_string().len();
@ -1276,6 +1276,51 @@ impl PlainListing {
}
*self.rows.entries.get_mut(idx).unwrap() = ((thread_hash, env_hash), strings);
}
fn select(
&mut self,
search_term: &str,
results: Result<SmallVec<[EnvelopeHash; 512]>>,
context: &mut Context,
) {
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.rows.all_threads.contains(&thread) {
self.rows
.selection
.entry(env_hash)
.and_modify(|entry| *entry = true);
}
}
}
Err(err) => {
self.cursor_pos.2 = 0;
self.new_cursor_pos.2 = 0;
let message = format!(
"Encountered an error while searching for `{}`: {}.",
search_term, &err
);
log::error!("{}", message);
context.replies.push_back(UIEvent::Notification(
Some("Could not perform search".to_string()),
message,
Some(crate::types::NotificationType::Error(err.kind)),
));
}
}
}
}
impl Component for PlainListing {
@ -1363,8 +1408,8 @@ impl Component for PlainListing {
}
}
PageMovement::Down(amount) => {
for c in self.cursor_pos.2
..std::cmp::min(self.length, self.cursor_pos.2 + amount + 1)
for c in
self.cursor_pos.2..self.length.min(self.cursor_pos.2 + amount + 1)
{
if let Some(env_hash) = self.get_env_under_cursor(c) {
self.rows.update_selection_with_env(
@ -1382,8 +1427,7 @@ impl Component for PlainListing {
}
if modifier == Modifier::Intersection {
for c in (0..self.cursor_pos.2).chain(
(std::cmp::min(self.length, self.cursor_pos.2 + amount) + 1)
..self.length,
self.length.min(self.cursor_pos.2 + amount) + 1..self.length,
) {
if let Some(env_hash) = self.get_env_under_cursor(c) {
self.rows
@ -1394,7 +1438,7 @@ impl Component for PlainListing {
}
PageMovement::PageDown(multiplier) => {
for c in self.cursor_pos.2
..std::cmp::min(self.cursor_pos.2 + rows * multiplier, self.length)
..self.length.min(self.cursor_pos.2 + rows * multiplier)
{
if let Some(env_hash) = self.get_env_under_cursor(c) {
self.rows.update_selection_with_env(
@ -1412,10 +1456,8 @@ impl Component for PlainListing {
}
if modifier == Modifier::Intersection {
for c in (0..self.cursor_pos.2).chain(
(std::cmp::min(
self.cursor_pos.2 + rows * multiplier,
self.length,
) + 1)..self.length,
self.length.min(self.cursor_pos.2 + rows * multiplier) + 1
..self.length,
) {
if let Some(env_hash) = self.get_env_under_cursor(c) {
self.rows
@ -1514,8 +1556,6 @@ impl Component for PlainListing {
if self.length == 0 && self.dirty {
grid.clear_area(area, self.color_cache.theme_default);
context.dirty_areas.push_back(area);
self.dirty = false;
return;
}
}
self.dirty = false;
@ -1724,6 +1764,35 @@ impl Component for PlainListing {
}
};
self.set_dirty(true);
return true;
}
UIEvent::Action(Action::Listing(Select(ref search_term))) if !self.unfocused() => {
match context.accounts[&self.cursor_pos.0].search(
search_term,
self.sort,
self.cursor_pos.1,
) {
Ok(job) => {
let mut handle = context.accounts[&self.cursor_pos.0]
.main_loop_handler
.job_executor
.spawn_specialized("select_by_search".into(), job);
if let Ok(Some(search_result)) = try_recv_timeout!(&mut handle.chan) {
self.select(search_term, search_result, context);
} else {
self.select_job = Some((search_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
@ -1747,6 +1816,21 @@ impl Component for PlainListing {
}
self.set_dirty(true);
}
UIEvent::StatusEvent(StatusEvent::JobFinished(ref job_id))
if self
.select_job
.as_ref()
.map(|(_, j)| j == job_id)
.unwrap_or(false) =>
{
let (search_term, mut handle) = self.select_job.take().unwrap();
match handle.chan.try_recv() {
Err(_) => { /* search was canceled */ }
Ok(None) => { /* something happened, perhaps a worker thread panicked */ }
Ok(Some(results)) => self.select(&search_term, results, context),
}
self.set_dirty(true);
}
_ => {}
}
false
@ -1755,8 +1839,8 @@ impl Component for PlainListing {
fn is_dirty(&self) -> bool {
self.force_draw
|| match self.focus {
Focus::None => self.dirty,
Focus::Entry | Focus::EntryFullscreen => false,
Focus::None | Focus::Entry => self.dirty,
Focus::EntryFullscreen => false,
}
}

View File

@ -95,7 +95,7 @@ impl std::fmt::Debug for CellBuffer {
}
impl CellBuffer {
pub const MAX_SIZE: usize = 1_000_000;
pub const MAX_SIZE: usize = 100_000_000;
pub fn nil(area: Area) -> Self {
Self {