override configuration with per-folder configs

embed
Manos Pitsidianakis 2019-09-09 21:38:37 +03:00
parent 81a55abc7c
commit fd38dbed48
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
3 changed files with 132 additions and 48 deletions

View File

@ -96,6 +96,40 @@ impl ListingTrait for ListingComponent {
}
}
impl ListingComponent {
fn set_style(&mut self, new_style: IndexStyle) {
match new_style {
IndexStyle::Plain => {
if let Plain(_) = self {
return;
}
let mut new_l = PlainListing::default();
let coors = self.coordinates();
new_l.set_coordinates((coors.0, coors.1, None));
*self = Plain(new_l);
}
IndexStyle::Threaded => {
if let Threaded(_) = self {
return;
}
let mut new_l = ThreadListing::default();
let coors = self.coordinates();
new_l.set_coordinates((coors.0, coors.1, None));
*self = Threaded(new_l);
}
IndexStyle::Compact => {
if let Compact(_) = self {
return;
}
let mut new_l = CompactListing::default();
let coors = self.coordinates();
new_l.set_coordinates((coors.0, coors.1, None));
*self = Compact(new_l);
}
}
}
}
#[derive(Debug)]
pub struct Listing {
component: ListingComponent,
@ -226,6 +260,14 @@ impl Component for Listing {
}
let folder_hash =
context.accounts[self.cursor_pos.0].folders_order[self.cursor_pos.1];
/* Check if per-folder configuration overrides general configuration */
if let Some(index_style) = context
.accounts
.get(self.cursor_pos.0)
.and_then(|account| account.folder_confs(folder_hash).conf_override.index)
{
self.component.set_style(index_style);
};
// Inform State that we changed the current folder view.
context
.replies
@ -258,6 +300,14 @@ impl Component for Listing {
}
let folder_hash =
context.accounts[self.cursor_pos.0].folders_order[self.cursor_pos.1];
/* Check if per-folder configuration overrides general configuration */
if let Some(index_style) = context
.accounts
.get(self.cursor_pos.0)
.and_then(|account| account.folder_confs(folder_hash).conf_override.index)
{
self.component.set_style(index_style);
};
// Inform State that we changed the current folder view.
context
.replies
@ -266,30 +316,15 @@ impl Component for Listing {
}
UIEvent::Action(ref action) => match action {
Action::Listing(ListingAction::SetPlain) => {
if let Plain(_) = self.component {
return true;
}
let mut new_l = PlainListing::default();
new_l.set_coordinates((self.cursor_pos.0, self.cursor_pos.1, None));
self.component = Plain(new_l);
self.component.set_style(IndexStyle::Plain);
return true;
}
Action::Listing(ListingAction::SetThreaded) => {
if let Threaded(_) = self.component {
return true;
}
let mut new_l = ThreadListing::default();
new_l.set_coordinates((self.cursor_pos.0, self.cursor_pos.1, None));
self.component = Threaded(new_l);
self.component.set_style(IndexStyle::Threaded);
return true;
}
Action::Listing(ListingAction::SetCompact) => {
if let Compact(_) = self.component {
return true;
}
let mut new_l = CompactListing::default();
new_l.set_coordinates((self.cursor_pos.0, self.cursor_pos.1, None));
self.component = Compact(new_l);
self.component.set_style(IndexStyle::Compact);
return true;
}
_ => {}
@ -437,7 +472,7 @@ impl From<IndexStyle> for ListingComponent {
impl Listing {
const DESCRIPTION: &'static str = "listing";
pub fn new(accounts: &[Account]) -> Self {
let accounts = accounts
let account_entries = accounts
.iter()
.enumerate()
.map(|(i, a)| AccountMenuEntry {
@ -445,9 +480,20 @@ impl Listing {
index: i,
})
.collect();
/* Check if per-folder configuration overrides general configuration */
let component = if let Some(index_style) = accounts.get(0).and_then(|account| {
account
.folders_order
.get(0)
.and_then(|folder_hash| account.folder_confs(*folder_hash).conf_override.index)
}) {
ListingComponent::from(index_style)
} else {
Compact(Default::default())
};
Listing {
component: Compact(Default::default()),
accounts,
component,
accounts: account_entries,
visible: true,
dirty: true,
cursor_pos: (0, 0),

View File

@ -89,17 +89,29 @@ impl ToggleFlag {
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct MailUIConf {
pub pager: Option<PagerSettings>,
pub notifications: Option<NotificationsSettings>,
pub shortcuts: Option<Shortcuts>,
pub mailer: Option<MailerSettings>,
pub identity: Option<String>,
pub index: Option<IndexStyle>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FolderConf {
rename: Option<String>,
pub rename: Option<String>,
#[serde(default = "true_val")]
autoload: bool,
pub autoload: bool,
#[serde(deserialize_with = "toggleflag_de", default)]
subscribe: ToggleFlag,
pub subscribe: ToggleFlag,
#[serde(deserialize_with = "toggleflag_de", default)]
ignore: ToggleFlag,
pub ignore: ToggleFlag,
#[serde(default = "none")]
usage: Option<SpecialUseMailbox>,
pub usage: Option<SpecialUseMailbox>,
#[serde(flatten)]
pub conf_override: MailUIConf,
}
impl Default for FolderConf {
@ -108,8 +120,9 @@ impl Default for FolderConf {
rename: None,
autoload: true,
subscribe: ToggleFlag::Unset,
ignore: ToggleFlag::False,
ignore: ToggleFlag::Unset,
usage: None,
conf_override: MailUIConf::default(),
}
}
}
@ -132,7 +145,6 @@ pub struct FileAccount {
#[serde(default = "none")]
display_name: Option<String>,
#[serde(deserialize_with = "index_from_str")]
index: IndexStyle,
/// A command to pipe html output before displaying it in a pager
@ -197,7 +209,10 @@ impl From<FileAccount> for AccountConf {
}
if folder_confs[s].usage.is_none() {
let name = s.split('/').last().unwrap_or("");
let name = s
.split(if s.contains('/') { '/' } else { '.' })
.last()
.unwrap_or("");
folder_confs.get_mut(s).unwrap().usage = if name.eq_ignore_ascii_case("inbox") {
Some(SpecialUseMailbox::Inbox)
} else if name.eq_ignore_ascii_case("archive") {
@ -265,9 +280,9 @@ struct FileSettings {
#[derive(Debug, Clone, Default)]
pub struct AccountConf {
account: AccountSettings,
conf: FileAccount,
folder_confs: HashMap<String, FolderConf>,
pub(crate) account: AccountSettings,
pub(crate) conf: FileAccount,
pub(crate) folder_confs: HashMap<String, FolderConf>,
}
impl AccountConf {
@ -380,7 +395,7 @@ impl Settings {
}
}
#[derive(Copy, Debug, Clone, Serialize, Deserialize)]
#[derive(Copy, Debug, Clone, Hash, PartialEq)]
pub enum IndexStyle {
Plain,
Threaded,
@ -393,19 +408,6 @@ impl Default for IndexStyle {
}
}
fn index_from_str<'de, D>(deserializer: D) -> std::result::Result<IndexStyle, D::Error>
where
D: Deserializer<'de>,
{
let s = <String>::deserialize(deserializer)?;
match s.as_str() {
"Plain" | "plain" => Ok(IndexStyle::Plain),
"Threaded" | "threaded" => Ok(IndexStyle::Threaded),
"Compact" | "compact" => Ok(IndexStyle::Compact),
_ => Err(de::Error::custom("invalid `index` value")),
}
}
fn non_empty_string<'de, D>(deserializer: D) -> std::result::Result<Option<String>, D::Error>
where
D: Deserializer<'de>,
@ -468,3 +470,31 @@ mod default_vals {
None
}
}
impl<'de> Deserialize<'de> for IndexStyle {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = <String>::deserialize(deserializer)?;
match s.as_str() {
"Plain" | "plain" => Ok(IndexStyle::Plain),
"Threaded" | "threaded" => Ok(IndexStyle::Threaded),
"Compact" | "compact" => Ok(IndexStyle::Compact),
_ => Err(de::Error::custom("invalid `index` value")),
}
}
}
impl Serialize for IndexStyle {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
IndexStyle::Plain => serializer.serialize_str("plain"),
IndexStyle::Threaded => serializer.serialize_str("threaded"),
IndexStyle::Compact => serializer.serialize_str("compact"),
}
}
}

View File

@ -23,7 +23,7 @@
* Account management from user configuration.
*/
use super::AccountConf;
use super::{AccountConf, FolderConf};
use fnv::FnvHashMap;
use melib::async_workers::{Async, AsyncBuilder, AsyncStatus};
use melib::backends::{
@ -116,8 +116,9 @@ impl MailboxEntry {
pub struct Account {
name: String,
pub(crate) folders: FnvHashMap<FolderHash, MailboxEntry>,
pub(crate) folder_confs: FnvHashMap<FolderHash, FolderConf>,
pub(crate) folders_order: Vec<FolderHash>,
folder_names: FnvHashMap<FolderHash, String>,
pub(crate) folder_names: FnvHashMap<FolderHash, String>,
tree: Vec<FolderNode>,
sent_folder: Option<FolderHash>,
pub(crate) collection: Collection,
@ -205,6 +206,7 @@ impl Account {
let mut workers: FnvHashMap<FolderHash, Worker> = FnvHashMap::default();
let notify_fn = Arc::new(notify_fn);
let mut folder_names = FnvHashMap::default();
let mut folder_confs = FnvHashMap::default();
let mut sent_folder = None;
for f in ref_folders.values_mut() {
@ -221,6 +223,7 @@ impl Account {
}
_ => {}
}
folder_confs.insert(f.hash(), settings.folder_confs[f.path()].clone());
folder_names.insert(f.hash(), f.path().to_string());
}
@ -300,6 +303,7 @@ impl Account {
Account {
name,
folders,
folder_confs,
folders_order,
folder_names,
tree,
@ -669,6 +673,10 @@ impl Account {
pub fn folder_operation(&mut self, path: &str, op: FolderOperation) -> Result<()> {
self.backend.folder_operation(path, op)
}
pub fn folder_confs(&self, folder_hash: FolderHash) -> &FolderConf {
&self.folder_confs[&folder_hash]
}
}
impl Index<FolderHash> for Account {