Add sort/subsort functions, not working yet as intended

embed
Manos Pitsidianakis 2018-08-07 11:47:26 +03:00
parent 8a7dfcd4ee
commit 43ad31d2ab
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
6 changed files with 136 additions and 20 deletions

View File

@ -46,7 +46,7 @@ pub struct Mailbox {
pub folder: Folder,
pub collection: Vec<Envelope>,
pub threaded_collection: Vec<usize>,
threads: Vec<Container>,
pub threads: Vec<Container>,
}
impl Mailbox {

View File

@ -53,6 +53,9 @@ pub struct Container {
}
impl Container {
pub fn date(&self) -> UnixTimestamp {
self.date
}
pub fn message(&self) -> Option<usize> {
self.message
}

View File

@ -10,7 +10,8 @@ pub struct MailListing {
cursor_pos: (usize, usize, usize),
new_cursor_pos: (usize, usize, usize),
length: usize,
// TODO: sorting
sort: (SortField, SortOrder),
subsort: (SortField, SortOrder),
/// Cache current view.
content: CellBuffer,
/// If we must redraw on next redraw event
@ -38,6 +39,8 @@ impl MailListing {
cursor_pos: (0, 1, 0),
new_cursor_pos: (0, 0, 0),
length: 0,
sort: (SortField::Date, SortOrder::Desc),
subsort: (SortField::Date, SortOrder::Asc),
content: content,
dirty: true,
unfocused: false,
@ -99,7 +102,33 @@ impl MailListing {
let mut indentations: Vec<bool> = Vec::with_capacity(6);
let mut thread_idx = 0; // needed for alternate thread colors
/* Draw threaded view. */
let mut iter = mailbox.threaded_collection.iter().enumerate().peekable();
let mut local_collection: Vec<usize> = mailbox.threaded_collection.clone();
let mut threads: Vec<&Container> = mailbox.threads.iter().map(|v| v).collect();
local_collection.sort_by(|a, b| {
match self.sort {
(SortField::Date, SortOrder::Desc) => {
mailbox.thread(*b).date().cmp(&mailbox.thread(*a).date())
},
(SortField::Date, SortOrder::Asc) => {
mailbox.thread(*a).date().cmp(&mailbox.thread(*b).date())
},
(SortField::Subject, SortOrder::Desc) => {
let a = mailbox.thread(*a);
let b = mailbox.thread(*b);
let ma = &mailbox.collection[*a.message().as_ref().unwrap()];
let mb = &mailbox.collection[*b.message().as_ref().unwrap()];
ma.subject().cmp(&mb.subject())
},
(SortField::Subject, SortOrder::Asc) => {
let a = mailbox.thread(*a);
let b = mailbox.thread(*b);
let ma = &mailbox.collection[*a.message().as_ref().unwrap()];
let mb = &mailbox.collection[*b.message().as_ref().unwrap()];
mb.subject().cmp(&ma.subject())
},
}
});
let mut iter = local_collection.iter().enumerate().peekable();
let len = mailbox
.threaded_collection
.len()
@ -108,16 +137,16 @@ impl MailListing {
.count();
/* This is just a desugared for loop so that we can use .peek() */
while let Some((idx, i)) = iter.next() {
let container = mailbox.thread(*i);
let container = threads[*i];
let indentation = container.indentation();
if indentation == 0 {
thread_idx += 1;
}
assert_eq!(container.has_message(), true);
assert!(container.has_message() == true);
match iter.peek() {
Some(&(_, x)) if mailbox.thread(*x).indentation() == indentation => {
Some(&(_, x)) if threads[*x].indentation() == indentation => {
indentations.pop();
indentations.push(true);
}
@ -164,11 +193,11 @@ impl MailListing {
}
match iter.peek() {
Some(&(_, x)) if mailbox.thread(*x).indentation() > indentation => {
Some(&(_, x)) if threads[*x].indentation() > indentation => {
indentations.push(false);
}
Some(&(_, x)) if mailbox.thread(*x).indentation() < indentation => {
for _ in 0..(indentation - mailbox.thread(*x).indentation()) {
Some(&(_, x)) if threads[*x].indentation() < indentation => {
for _ in 0..(indentation - threads[*x].indentation()) {
indentations.pop();
}
}
@ -661,7 +690,13 @@ impl Component for MailListing {
self.refresh_mailbox(context);
return;
},
//_ => {},
Action::Sort(field, order) => {
self.sort = (field.clone(), order.clone());
self.dirty = true;
self.refresh_mailbox(context);
return;
},
_ => {},
},
_ => {}
}

View File

@ -2,13 +2,65 @@
* User actions that need to be handled by the UI
*/
#[derive(Debug)]
use std::str::FromStr;
#[derive(Debug, Clone)]
pub enum MailListingAction {
ToggleThreaded,
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum SortOrder {
Asc,
Desc,
}
#[derive(Debug, Clone)]
pub enum SortField {
Subject,
Date,
}
impl FromStr for SortField {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
eprintln!("sortfield from_str {}", s);
match s.trim() {
"subject" | "s" | "sub" | "sbj" | "subj" => {
eprintln!("parsed: subject");
}
"date" | "d" => {
eprintln!("parsed date");
}
_ => {
eprintln!("error in parse");
}
}
match s.trim() {
"subject" | "s" | "sub" | "sbj" | "subj" => Ok(SortField::Subject),
"date" | "d" => Ok(SortField::Date),
_ => Err(())
}
}
}
impl FromStr for SortOrder {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
eprintln!("sortoder from_str {}", s);
match s.trim() {
"asc" => Ok(SortOrder::Asc),
"desc" => Ok(SortOrder::Desc),
_ => Err(())
}
}
}
#[derive(Debug, Clone)]
pub enum Action {
MailListing(MailListingAction),
ViewMailbox(usize),
Sort(SortField, SortOrder),
SubSort(SortField, SortOrder),
}

View File

@ -1,6 +1,6 @@
/*! A parser module for user commands passed through the Ex mode.
*/
use nom::{digit, };
use nom::{digit, not_line_ending};
use std;
pub mod actions;
pub use actions::*;
@ -14,15 +14,40 @@ named!(
)
);
named!(sortfield<SortField>,
map_res!(
map_res!(take_until_s!(" "), std::str::from_utf8),
std::str::FromStr::from_str));
named!(sortorder<SortOrder>,
map_res!(
map_res!(call!(not_line_ending), std::str::from_utf8),
std::str::FromStr::from_str));
named!(goto<Action>,
preceded!(tag!("b "),
map!(call!(usize_c), |v| Action::ViewMailbox(v))
));
//named!(sort<&str>,
// preceded!(tag!("sort "),
// map_res!(call!(alpha), std::str::from_utf8))
// );
named!(subsort<Action>, do_parse!(
tag!("subsort ") >>
p: pair!(sortfield,sortorder) >>
(
Action::SubSort(p.0, p.1)
)
));
named!(sort<Action>, do_parse!(
tag!("sort ") >>
p: separated_pair!(sortfield,tag!(" "), sortorder) >>
(
Action::Sort(p.0, p.1)
)
));
named!(threaded<Action>,
map!(ws!(tag!("threaded")), |_| Action::MailListing(MailListingAction::ToggleThreaded)));
@ -30,6 +55,6 @@ named!(toggle<Action>,
preceded!(tag!("toggle "),
alt_complete!( threaded )));
named!(pub parse_command<Action>,
alt_complete!( goto | toggle)
named!(pub parse_command<Action>,
alt_complete!( goto | toggle | sort | subsort)
);

View File

@ -313,7 +313,9 @@ impl<W: Write> State<W> {
}
/// Convert user commands to actions/method calls.
fn parse_command(&mut self, cmd: String) {
eprintln!("cmd is {}", cmd);
let result = parse_command(&cmd.as_bytes()).to_full_result();
eprintln!("rseult is {:?}", result);
if let Ok(v) = result {
self.rcv_event(UIEvent { id: 0, event_type: UIEventType::Action(v) });
@ -399,7 +401,6 @@ impl<W: Write> State<W> {
}
}
pub fn try_wait_on_child(&mut self) -> Option<bool> {
if {
match self.child {