summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2020-07-23 15:33:26 +0200
committerMatthias Beyer <mail@beyermatthias.de>2020-07-23 15:33:26 +0200
commit8242b5ffb29f3c20ee33221fd3a07e96a087cb27 (patch)
tree61532484ce7a9fb951ea435eb8cfe6de5f810415
parent7c77ae52c546596ac2be057efeefd5939e0c0d26 (diff)
parentcc1a2e381cce09e7ed7039cc14c7e9823cbd0529 (diff)
Merge branch 'notmuch'
This switches to an implementation that only relies on notmuch as a mail backend. Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r--Cargo.toml5
-rw-r--r--config.toml2
-rw-r--r--shell.nix1
-rw-r--r--src/configuration.rs19
-rw-r--r--src/database_connection.rs22
-rw-r--r--src/loader.rs19
-rw-r--r--src/maillist_view.rs152
-rw-r--r--src/mailstore.rs120
-rw-r--r--src/main.rs43
-rw-r--r--src/main_view.rs206
-rw-r--r--src/sidebar.rs3
11 files changed, 279 insertions, 313 deletions
diff --git a/Cargo.toml b/Cargo.toml
index c26cb54..44c923d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,11 +10,14 @@ walkdir = "2"
anyhow = "1"
log = "0.4"
env_logger = "0.7"
-maildir.git = "https://git.sr.ht/~matthiasbeyer/maildir"
mailparse.git = "https://git.sr.ht/~matthiasbeyer/mailparse"
cursive-tabs = "0.5"
cursive_table_view.git = "https://git.sr.ht/~matthiasbeyer/cursive_table_view"
cursive-async-view = "0.4"
+notmuch = "0.6"
+config = "0.10"
+serde = { version = "1.0", features = ["derive"] }
+chrono = "0.4"
cursive = "0.15"
diff --git a/config.toml b/config.toml
new file mode 100644
index 0000000..99d004c
--- /dev/null
+++ b/config.toml
@@ -0,0 +1,2 @@
+notmuch_database_path = "/tmp/mails"
+notmuch_default_query = "tag:inbox and tag:new"
diff --git a/shell.nix b/shell.nix
index df41ddf..26c81fc 100644
--- a/shell.nix
+++ b/shell.nix
@@ -21,6 +21,7 @@ pkgs.mkShell {
openssl
pkgconfig
ncurses
+ notmuch
];
LIBCLANG_PATH = "${pkgs.llvmPackages.libclang}/lib";
}
diff --git a/src/configuration.rs b/src/configuration.rs
new file mode 100644
index 0000000..165b503
--- /dev/null
+++ b/src/configuration.rs
@@ -0,0 +1,19 @@
+use std::path::PathBuf;
+use serde::Deserialize;
+
+#[derive(Debug, Deserialize)]
+pub struct Configuration {
+ notmuch_database_path: PathBuf,
+ notmuch_default_query: String,
+}
+
+impl Configuration {
+ pub fn notmuch_database_path(&self) -> &PathBuf {
+ &self.notmuch_database_path
+ }
+
+ pub fn notmuch_default_query(&self) -> &String {
+ &self.notmuch_default_query
+ }
+}
+
diff --git a/src/database_connection.rs b/src/database_connection.rs
new file mode 100644
index 0000000..21124cc
--- /dev/null
+++ b/src/database_connection.rs
@@ -0,0 +1,22 @@
+#[derive(Debug)]
+pub struct DatabaseConnection(notmuch::Database);
+
+impl DatabaseConnection {
+
+ pub fn readonly(p: &PathBuf) -> Result<DatabaseConnection> {
+ .map(DatabaseConnection)
+ }
+
+ pub fn for_thread<'d, 'q, F, T>(&self, thread_id: &str, f: F) -> Result<T>
+ where F: FnOnce<Threads<'d, 'q>> -> Result<T>,
+ T: Sized
+ {
+ let query = format!("thread:{}", thread_id);
+
+ self.0
+ .create_query(query)?
+ .search_threads()
+ .and_then(func)
+ }
+
+}
diff --git a/src/loader.rs b/src/loader.rs
deleted file mode 100644
index 9aae9c8..0000000
--- a/src/loader.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-/// Helper trait to load something and then postprocess it
-///
-/// the load() function might fail, but the PostProcessor::postprocess() function should never fail.
-pub trait Loader {
- type Output: Sized;
- type Error: Sized;
- type PostProcessedOutput: Sized;
- type PostProcessor: PostProcessor<Self::Output, Output = Self::PostProcessedOutput>;
-
- fn load(self) -> Result<Self::Output, Self::Error>;
- fn postprocessor(&self, load_name: String) -> Self::PostProcessor;
-}
-
-pub trait PostProcessor<Object: Sized> {
- type Output: Sized;
-
- fn postprocess(&self, o: Object) -> Self::Output;
-}
-
diff --git a/src/maillist_view.rs b/src/maillist_view.rs
new file mode 100644
index 0000000..97afff7
--- /dev/null
+++ b/src/maillist_view.rs
@@ -0,0 +1,152 @@
+use std::path::PathBuf;
+
+use anyhow::Result;
+use cursive::Cursive;
+use cursive::Printer;
+use cursive::Rect;
+use cursive::View;
+use cursive::XY;
+use cursive::direction::Direction;
+use cursive::view::Selector;
+use cursive::event::Event;
+use cursive::event::EventResult;
+use cursive::views::ResizedView;
+use cursive_table_view::TableView;
+use cursive_table_view::TableViewItem;
+
+pub struct MaillistView(TableView<MailListingData, MailListingColumn>);
+
+impl MaillistView {
+ pub fn create_for(database_path: &PathBuf, query: &str, name: String) -> Result<Self> {
+ debug!("Getting '{}' from '{}'", query, database_path.display());
+
+ let items = notmuch::Database::open(database_path, notmuch::DatabaseMode::ReadOnly)?
+ .create_query(query)?
+ .search_messages()?
+ .map(|msg| {
+ Ok(MailListingData {
+ mail_id: msg.id().to_string(),
+ tags: msg.tags().collect(),
+ date: chrono::naive::NaiveDateTime::from_timestamp_opt(msg.date(), 0)
+ .ok_or_else(|| anyhow!("Failed to parse timestamp: {}", msg.date()))?
+ .to_string(),
+
+ from: msg.header("From")?.ok_or_else(|| anyhow!("Failed to get From for {}", msg.id()))?.to_string(),
+ to: msg.header("To")?.map(|c| c.to_string()).unwrap_or_else(|| String::from("")),
+ subject: msg.header("Subject")?.ok_or_else(|| anyhow!("Failed to get Subject for {}", msg.id()))?.to_string(),
+ })
+ })
+ .collect::<Result<Vec<_>>>()?;
+
+ debug!("Found {} entries", items.len());
+ let tab = TableView::<MailListingData, MailListingColumn>::new()
+ .column(MailListingColumn::Date, "Date", |c| c.width(20))
+ .column(MailListingColumn::Tags, "Tags", |c| c.width(20))
+ .column(MailListingColumn::From, "From", |c| c)
+ .column(MailListingColumn::To, "To", |c| c)
+ .column(MailListingColumn::Subject, "Subject", |c| c)
+ .default_column(MailListingColumn::Date)
+ .items(items)
+ .selected_item(0)
+ .on_submit(move |siv: &mut Cursive, row: usize, _: usize| {
+ let mail_id = siv.call_on_name(&name, move |table: &mut ResizedView<TableView<MailListingData, MailListingColumn>>| {
+ table.get_inner_mut()
+ .borrow_item(row)
+ .map(|data| data.mail_id.clone())
+ });
+
+ // use the mail ID to get the whole thread and open it as a table item
+ });
+
+ Ok(MaillistView(tab))
+ }
+}
+
+impl View for MaillistView {
+ fn draw(&self, printer: &Printer) {
+ self.0.draw(printer)
+ }
+
+ fn layout(&mut self, xy: XY<usize>) {
+ self.0.layout(xy)
+ }
+
+ fn needs_relayout(&self) -> bool {
+ self.0.needs_relayout()
+ }
+
+ fn required_size(&mut self, constraint: XY<usize>) -> XY<usize> {
+ self.0.required_size(constraint)
+ }
+
+ fn on_event(&mut self, e: Event) -> EventResult {
+ self.0.on_event(e)
+ }
+
+ fn call_on_any<'a>(&mut self, s: &Selector, tpl: &'a mut (dyn FnMut(&mut (dyn View + 'static)) + 'a)) {
+ self.0.call_on_any(s, tpl);
+ }
+
+ fn focus_view(&mut self, s: &Selector) -> Result<(), ()> {
+ self.0.focus_view(s)
+ }
+
+ fn take_focus(&mut self, source: Direction) -> bool {
+ self.0.take_focus(source)
+ }
+
+ fn important_area(&self, view_size: XY<usize>) -> Rect {
+ self.0.important_area(view_size)
+ }
+
+ fn type_name(&self) -> &'static str {
+ self.0.type_name()
+ }
+
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub enum MailListingColumn {
+ Date,
+ Tags,
+ From,
+ To,
+ Subject,
+}
+
+#[derive(Clone, Debug)]
+pub struct MailListingData {
+ mail_id: String,
+ tags: Vec<String>,
+ date: String,
+ from: String,
+ to: String,
+ subject: String,
+}
+
+impl TableViewItem<MailListingColumn> for MailListingData {
+
+ fn to_column(&self, column: MailListingColumn) -> String {
+ match column {
+ MailListingColumn::Date => self.date.clone(),
+ MailListingColumn::Tags => self.tags.join(", "),
+ MailListingColumn::From => self.from.clone(),
+ MailListingColumn::To => self.to.clone(),
+ MailListingColumn::Subject => self.subject.clone(),
+ }
+ }
+
+ fn cmp(&self, other: &Self, column: MailListingColumn) -> std::cmp::Ordering
+ where Self: Sized
+ {
+ match column {
+ MailListingColumn::Date => self.date.cmp(&other.date),
+ MailListingColumn::Tags => self.tags.cmp(&other.tags),
+ MailListingColumn::From => self.from.cmp(&other.from),
+ MailListingColumn::To => self.to.cmp(&other.to),
+ MailListingColumn::Subject => self.subject.cmp(&other.subject),
+ }
+ }
+
+}
+
diff --git a/src/mailstore.rs b/src/mailstore.rs
deleted file mode 100644
index 49f911f..0000000
--- a/src/mailstore.rs
+++ /dev/null
@@ -1,120 +0,0 @@
-use std::ops::Deref;
-use std::path::PathBuf;
-use std::iter::FromIterator;
-use anyhow::Result;
-use maildir::Maildir;
-use maildir::MailEntry;
-use mailparse::ParsedMail;
-
-pub struct MailStore {
- new: Vec<Mail>,
- cur: Vec<Mail>,
-}
-
-impl MailStore {
- pub fn build_from_path(path: PathBuf) -> MailStoreBuilder {
- let md = Maildir::from(path);
- MailStoreBuilder {
- cur: Box::new(md.list_cur().map(|m| Mail::cur_from(m?))),
- new: Box::new(md.list_new().map(|m| Mail::new_from(m?))),
- }
- }
-
- pub fn new_mail(&self) -> &Vec<Mail> {
- &self.new
- }
-
- pub fn cur_mail(&self) -> &Vec<Mail> {
- &self.cur
- }
-}
-
-
-impl FromIterator<Mail> for MailStore {
- fn from_iter<T>(iter: T) -> Self
- where T: IntoIterator<Item = Mail>
- {
- let mut new = vec![];
- let mut cur = vec![];
- for mail in iter {
- if mail.is_new() {
- new.push(mail)
- } else if mail.is_cur() {
- cur.push(mail)
- } else {
- unreachable!("Not implemented yet, should not be reachable in current implementation")
- }
- }
-
- MailStore { new, cur }
- }
-}
-
-pub struct MailStoreBuilder {
- cur: Box<dyn Iterator<Item = Result<Mail>>>,
- new: Box<dyn Iterator<Item = Result<Mail>>>,
-}
-
-impl Iterator for MailStoreBuilder {
- type Item = Result<Mail>;
-
- fn next(&mut self) -> Option<Self::Item> {
- if let Some(next) = self.cur.next() {
- return Some(next)
- }
-
- self.new.next()
- }
-}
-
-#[derive(Clone, Debug)]
-pub struct Mail {
- entry: MailEntry,
- parsed: ParsedMail,
- mailtype: MailType,
-}
-
-#[derive(Debug, Clone, Eq, PartialEq)]
-enum MailType {
- Cur,
- New,
-}
-
-impl Mail {
- fn cur_from(mut entry: MailEntry) -> Result<Self> {
- Ok(Mail {
- parsed: entry.parsed()?,
- entry,
- mailtype: MailType::Cur,
- })
- }
-
- fn new_from(mut entry: MailEntry) -> Result<Self> {
- Ok(Mail {
- parsed: entry.parsed()?,
- entry,
- mailtype: MailType::New,
- })
- }
-
- pub fn parsed(&self) -> &ParsedMail {
- &self.parsed
- }
-
- pub fn is_new(&self) -> bool {
- self.mailtype == MailType::New
- }
-
- pub fn is_cur(&self) -> bool {
- self.mailtype == MailType::Cur
- }
-}
-
-impl Deref for Mail {
- type Target = MailEntry;
-
- fn deref(&self) -> &Self::Target {
- &self.entry
- }
-}
-
diff --git a/src/main.rs b/src/main.rs
index 2eb311f..6f7000e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,45 +1,32 @@
#[macro_use] extern crate anyhow;
#[macro_use] extern crate log;
-use std::path::PathBuf;
use anyhow::Result;
use cursive::CursiveExt;
+use cursive::event::{Event, EventTrigger};
-mod mailstore;
-mod sidebar;
mod main_view;
-mod loader;
+mod maillist_view;
+mod configuration;
+
+use configuration::Configuration;
fn main() -> Result<()> {
cursive::logger::init();
- let maildir_path = std::env::args()
- .skip(1)
- .next()
- .map(PathBuf::from)
- .ok_or_else(|| anyhow!("No path to maildir passed"))?;
-
- let pathes = walkdir::WalkDir::new(maildir_path.clone())
- .max_depth(1)
- .follow_links(false)
- .same_file_system(true)
- .into_iter()
- .filter_map(Result::ok)
- .filter(|de| de.file_type().is_dir())
- .map(|de| de.path().to_path_buf())
- .collect();
-
- let sidebar = sidebar::Sidebar::new(pathes);
+ let mut config = config::Config::default();
+ config
+ .merge(config::File::with_name("config"))?
+ .merge(config::Environment::with_prefix("MUAR"))?;
+ let config = config.try_into::<Configuration>()?;
- let mainview = main_view::MainView::new();
+ let mut siv = cursive::Cursive::default();
- let mut layout = cursive::views::LinearLayout::horizontal();
- layout.add_child(sidebar);
- layout.add_child(mainview);
+ let event = Event::Char('q');
+ let trigger: EventTrigger = event.clone().into();
+ siv.set_on_post_event(trigger, |s| s.quit());
- let mut siv = cursive::Cursive::default();
- siv.add_layer(layout);
- siv.add_global_callback('q', |s| s.quit());
+ siv.add_fullscreen_layer(main_view::MainView::new(config)?);
siv.add_global_callback('~', cursive::Cursive::toggle_debug_console);
debug!("Starting cursive");
diff --git a/src/main_view.rs b/src/main_view.rs
index 35d5979..748c1ea 100644
--- a/src/main_view.rs
+++ b/src/main_view.rs
@@ -1,4 +1,3 @@
-use std::path::PathBuf;
use anyhow::Result;
use cursive::Cursive;
use cursive::Printer;
@@ -6,28 +5,24 @@ use cursive::Rect;
use cursive::View;
use cursive::XY;
use cursive::direction::Direction;
+use cursive::event::Callback;
use cursive::event::Event;
use cursive::event::EventResult;
use cursive::view::Nameable;
use cursive::view::Selector;
-use cursive::views::ListView;
-use cursive::views::LinearLayout;
+use cursive::views::Dialog;
+use cursive::views::EditView;
use cursive::views::NamedView;
use cursive::views::ResizedView;
-use cursive::views::TextView;
-use mailparse::MailHeaderMap;
-use cursive_table_view::TableView;
-use cursive_table_view::TableViewItem;
-use cursive_table_view::TableColumn;
-use crate::mailstore::MailStore;
-use crate::mailstore::Mail;
-use crate::loader::Loader;
-use crate::loader::PostProcessor;
+use crate::configuration::Configuration;
+use crate::maillist_view::MaillistView;
pub const MAIN_VIEW_NAME: &'static str = "main_view";
+pub const MAIN_MAIL_LIST_NAME: &'static str = "main_mail_list";
pub struct MainView {
+ config: Configuration,
tabs: cursive_tabs::TabPanel<String>,
}
@@ -49,7 +44,30 @@ impl View for MainView {
}
fn on_event(&mut self, e: Event) -> EventResult {
- self.tabs.on_event(e)
+ match e {
+ Event::Char('q') => {
+ if self.tabs.tab_order().len() == 1 {
+ EventResult::Ignored
+ } else {
+ if let Some(key) = self.tabs.active_tab().cloned() {
+ if let Err(e) = self.tabs.remove_tab(&key) {
+ error!("{:?}", e); // TODO do more than just logging
+ }
+ debug!("Remove tab");
+ EventResult::Consumed(None)
+ } else {
+ debug!("No tab to remove found.");
+ EventResult::Ignored
+ }
+ }
+ },
+
+ Event::Char('o') => {
+ EventResult::Consumed(Some(Callback::from_fn(MainView::add_notmuch_query_layer)))
+ },
+
+ other => self.tabs.on_event(other),
+ }
}
fn call_on_any<'a>(&mut self, s: &Selector, tpl: &'a mut (dyn FnMut(&mut (dyn View + 'static)) + 'a)) {
@@ -75,159 +93,59 @@ impl View for MainView {
}
impl MainView {
- pub fn new() -> NamedView<Self> {
+ pub fn new(config: Configuration) -> Result<NamedView<Self>> {
let tabs = cursive_tabs::TabPanel::default()
.with_bar_alignment(cursive_tabs::Align::Start)
.with_bar_placement(cursive_tabs::Placement::HorizontalTop)
- .with_tab(String::from("nobox"), {
+ .with_tab(config.notmuch_default_query().clone(), {
ResizedView::new(cursive::view::SizeConstraint::Full,
cursive::view::SizeConstraint::Full,
- TextView::new("No mailbox loaded"))
+ MaillistView::create_for(config.notmuch_database_path(), config.notmuch_default_query(), MAIN_MAIL_LIST_NAME.to_string())?
+ .with_name(MAIN_MAIL_LIST_NAME))
});
- MainView { tabs }.with_name(MAIN_VIEW_NAME)
- }
-
- pub fn maildir_loader(&mut self, pb: PathBuf) -> MaildirLoader {
- debug!("Creating Loader for: {}", pb.display());
- MaildirLoader(pb)
+ Ok(MainView { config, tabs }.with_name(MAIN_VIEW_NAME))
}
pub fn add_tab<T: View>(&mut self, id: String, view: T) {
self.tabs.add_tab(id, view)
}
-}
-
-pub struct MaildirLoader(PathBuf);
-
-impl Loader for MaildirLoader {
- type Output = Vec<MailListingData>;
- type Error = String;
- type PostProcessedOutput = LinearLayout;
- type PostProcessor = MaildirLoaderPostProcessor;
-
- fn load(self) -> Result<Self::Output, Self::Error> {
- debug!("Loading: {}", self.0.display());
- MailStore::build_from_path(self.0).collect::<Result<MailStore>>()
- .map(|store| {
- store.cur_mail()
- .iter()
- .chain(store.new_mail().iter())
- .map(|mail| {
- debug!("Loaded: {:?}", mail.parsed());
- let date = mail.parsed().headers.get_first_value("Date").unwrap_or_else(|| String::from("No date"));
- let from = mail.parsed().headers.get_first_value("From").unwrap_or_else(|| String::from("No From"));
- let to = mail.parsed().headers.get_first_value("To").unwrap_or_else(|| String::from("No To"));
- let subject = mail.parsed().headers.get_first_value("Subject").unwrap_or_else(|| String::from("No Subject"));
-
- // FIXME: do not clone Mail object
- MailListingData { mail: mail.clone(), date, from, to, subject }
- })
- .collect()
- })
- .map_err(|e| e.to_string())
- }
-
- fn postprocessor(&self, load_name: String) -> Self::PostProcessor {
- MaildirLoaderPostProcessor { name: load_name }
+ pub fn config(&self) -> &Configuration {
+ &self.config
}
-}
-pub struct MaildirLoaderPostProcessor {
- name: String
-}
-
-impl PostProcessor<Vec<MailListingData>> for MaildirLoaderPostProcessor {
- type Output = LinearLayout;
-
- fn postprocess(&self, list: Vec<MailListingData>) -> Self::Output {
- use cursive::view::SizeConstraint;
-
- let name = self.name.clone();
-
- let tab = TableView::<MailListingData, MailListingColumn>::new()
- .column(MailListingColumn::Date, "Date", |c| c.width(20))
- .column(MailListingColumn::From, "From", |c| c)
- .column(MailListingColumn::To, "To", |c| c)
- .column(MailListingColumn::Subject, "Subject", |c| c)
- .default_column(MailListingColumn::Date)
- .items(list)
- .selected_item(0)
- .on_submit(move |siv: &mut Cursive, row: usize, index: usize| {
- let mail_body = siv.call_on_name(&format!("{}-mail-list", name), move |table: &mut ResizedView<TableView<MailListingData, MailListingColumn>>| {
- table.get_inner_mut() // TODO: Bug in cursive_table_view::TableView::borrow_item() implementation
- .borrow_item(row)
- .map(|mail_listing| {
- mail_listing.mail.parsed().get_body()
- })
- });
-
- siv.call_on_name(&format!("{}-mail-view", name), move |mail_view: &mut ResizedView<TextView>| {
- let body = match mail_body.flatten() {
- Some(Ok(body)) => body,
- Some(Err(e)) => format!("Failed to parse mail body: {:?}", e),
- None => format!("No mail body found"),
- };
-
- mail_view.get_inner_mut().set_content(body);
- });
+ fn add_notmuch_query_layer(siv: &mut Cursive) {
+ let edit_view = EditView::new()
+ .on_submit(move |siv: &mut Cursive, query: &str| {
+ let database_path = siv.call_on_name(MAIN_VIEW_NAME, move |main_view: &mut MainView| {
+ main_view.config().notmuch_database_path().clone()
});
- LinearLayout::vertical()
- .child({
- ResizedView::new(SizeConstraint::Full,
- SizeConstraint::Full,
- tab)
- .with_name(format!("{}-mail-list", self.name))
- })
- .child({
- ResizedView::new(SizeConstraint::Full,
- SizeConstraint::AtMost(50),
- TextView::new("Not a loaded mail yet"))
- .with_name(format!("{}-mail-view", self.name))
- })
- }
-}
+ let database_path = database_path.unwrap(); // TODO: Fixme
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
-pub enum MailListingColumn {
- Date,
- From,
- To,
- Subject,
-}
+ let tab_name = format!("{}-view", query);
+ let tab = MaillistView::create_for(&database_path, query, query.to_string())
+ .unwrap() // TODO: FIXME
+ .with_name(tab_name);
-#[derive(Clone, Debug)]
-pub struct MailListingData {
- mail: Mail,
- date: String,
- from: String,
- to: String,
- subject: String,
-}
+ let tab = ResizedView::new(cursive::view::SizeConstraint::Full,
+ cursive::view::SizeConstraint::Full,
+ tab);
-impl TableViewItem<MailListingColumn> for MailListingData {
+ siv.call_on_name(MAIN_VIEW_NAME, move |main_view: &mut MainView| {
+ main_view.add_tab(query.to_string(), tab);
+ });
- fn to_column(&self, column: MailListingColumn) -> String {
- match column {
- MailListingColumn::Date => self.date.clone(),
- MailListingColumn::From => self.from.clone(),
- MailListingColumn::To => self.to.clone(),
- MailListingColumn::Subject => self.subject.clone(),
- }
- }
+ siv.pop_layer();
+ })
+ .with_name("query");
- fn cmp(&self, other: &Self, column: MailListingColumn) -> std::cmp::Ordering
- where Self: Sized
- {
- match column {
- MailListingColumn::Date => self.date.cmp(&other.date),
- MailListingColumn::From => self.from.cmp(&other.from),
- MailListingColumn::To => self.to.cmp(&other.to),
- MailListingColumn::Subject => self.subject.cmp(&other.subject),
- }
+ siv.add_layer({
+ ResizedView::new(cursive::view::SizeConstraint::AtLeast(80),
+ cursive::view::SizeConstraint::Free,
+ Dialog::around(edit_view).title("Query"))
+ })
}
}
-
diff --git a/src/sidebar.rs b/src/sidebar.rs
index 9da58ff..4573eb6 100644
--- a/src/sidebar.rs
+++ b/src/sidebar.rs
@@ -31,7 +31,8 @@ pub struct Sidebar {
}
impl Sidebar {
- pub fn new(pathes: Vec<PathBuf>) -> Self {
+ pub fn new(config: Configuration) -> Self {
+
let mut tv = cursive_tree_view::TreeView::default();
pathes