mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-22 11:00:19 +00:00
implement flowed format POC (#206)
This commit is contained in:
parent
6e5362e76e
commit
613e592f72
10 changed files with 109 additions and 35 deletions
|
@ -29,6 +29,9 @@ pub struct AccountConfig {
|
|||
pub notify_query: String,
|
||||
/// Represents the watch commands.
|
||||
pub watch_cmds: Vec<String>,
|
||||
/// Represents the text/plain format as defined in the
|
||||
/// [RFC2646](https://www.ietf.org/rfc/rfc2646.txt)
|
||||
pub format: Format,
|
||||
|
||||
/// Represents mailbox aliases.
|
||||
pub mailboxes: HashMap<String, String>,
|
||||
|
@ -148,6 +151,7 @@ impl<'a> AccountConfig {
|
|||
.or_else(|| config.watch_cmds.as_ref())
|
||||
.unwrap_or(&vec![])
|
||||
.to_owned(),
|
||||
format: base_account.format.unwrap_or_default(),
|
||||
mailboxes: base_account.mailboxes.clone(),
|
||||
default: base_account.default.unwrap_or_default(),
|
||||
email: base_account.email.to_owned(),
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use serde::Deserialize;
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use crate::config::Format;
|
||||
|
||||
pub trait ToDeserializedBaseAccountConfig {
|
||||
fn to_base(&self) -> DeserializedBaseAccountConfig;
|
||||
}
|
||||
|
@ -47,6 +49,9 @@ macro_rules! make_account_config {
|
|||
pub notify_query: Option<String>,
|
||||
/// Overrides the watch commands for this account.
|
||||
pub watch_cmds: Option<Vec<String>>,
|
||||
/// Represents the text/plain format as defined in the
|
||||
/// [RFC2646](https://www.ietf.org/rfc/rfc2646.txt)
|
||||
pub format: Option<Format>,
|
||||
|
||||
/// Makes this account the default one.
|
||||
pub default: Option<bool>,
|
||||
|
@ -89,6 +94,7 @@ macro_rules! make_account_config {
|
|||
notify_cmd: self.notify_cmd.clone(),
|
||||
notify_query: self.notify_query.clone(),
|
||||
watch_cmds: self.watch_cmds.clone(),
|
||||
format: self.format.clone(),
|
||||
|
||||
default: self.default.clone(),
|
||||
email: self.email.clone(),
|
||||
|
|
23
src/config/format.rs
Normal file
23
src/config/format.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
/// Represents the text/plain format as defined in the [RFC2646]. The
|
||||
/// format is then used by the table system to adjust the way it is
|
||||
/// rendered.
|
||||
///
|
||||
/// [RFC2646]: https://www.ietf.org/rfc/rfc2646.txt
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Deserialize)]
|
||||
#[serde(tag = "type", content = "width", rename_all = "lowercase")]
|
||||
pub enum Format {
|
||||
// Forces the content width with a fixed amount of pixels.
|
||||
Fixed(usize),
|
||||
// Makes the content fit the terminal.
|
||||
Auto,
|
||||
// Does not restrict the content.
|
||||
Flowed,
|
||||
}
|
||||
|
||||
impl Default for Format {
|
||||
fn default() -> Self {
|
||||
Self::Auto
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
//! This barrel module provides everything related to the user configuration.
|
||||
|
||||
pub mod config_args;
|
||||
pub mod deserialized_config;
|
||||
pub use deserialized_config::*;
|
||||
|
||||
pub mod account_args;
|
||||
pub mod account_config;
|
||||
pub use account_config::*;
|
||||
pub mod deserialized_account_config;
|
||||
pub use deserialized_account_config::*;
|
34
src/lib.rs
34
src/lib.rs
|
@ -34,37 +34,36 @@ pub mod msg {
|
|||
}
|
||||
|
||||
pub mod backends {
|
||||
pub use backend::*;
|
||||
pub mod backend;
|
||||
pub use backend::*;
|
||||
|
||||
pub use id_mapper::*;
|
||||
pub mod id_mapper;
|
||||
pub use id_mapper::*;
|
||||
|
||||
pub use self::imap::*;
|
||||
pub mod imap {
|
||||
pub mod imap_arg;
|
||||
|
||||
pub use imap_backend::*;
|
||||
pub mod imap_backend;
|
||||
pub use imap_backend::*;
|
||||
|
||||
pub mod imap_handler;
|
||||
|
||||
pub use imap_mbox::*;
|
||||
pub mod imap_mbox;
|
||||
pub use imap_mbox::*;
|
||||
|
||||
pub use imap_mbox_attr::*;
|
||||
pub mod imap_mbox_attr;
|
||||
pub use imap_mbox_attr::*;
|
||||
|
||||
pub use imap_envelope::*;
|
||||
pub mod imap_envelope;
|
||||
pub use imap_envelope::*;
|
||||
|
||||
pub use imap_flag::*;
|
||||
pub mod imap_flag;
|
||||
pub use imap_flag::*;
|
||||
|
||||
pub mod msg_sort_criterion;
|
||||
}
|
||||
pub use self::imap::*;
|
||||
|
||||
pub use self::maildir::*;
|
||||
pub mod maildir {
|
||||
pub mod maildir_backend;
|
||||
pub use maildir_backend::*;
|
||||
|
@ -78,6 +77,7 @@ pub mod backends {
|
|||
pub mod maildir_flag;
|
||||
pub use maildir_flag::*;
|
||||
}
|
||||
pub use self::maildir::*;
|
||||
|
||||
#[cfg(feature = "notmuch")]
|
||||
pub use self::notmuch::*;
|
||||
|
@ -99,7 +99,21 @@ pub mod smtp {
|
|||
pub use smtp_service::*;
|
||||
}
|
||||
|
||||
pub mod config {
|
||||
pub mod config_args;
|
||||
pub mod deserialized_config;
|
||||
pub use deserialized_config::*;
|
||||
|
||||
pub mod account_args;
|
||||
pub mod account_config;
|
||||
pub use account_config::*;
|
||||
pub mod deserialized_account_config;
|
||||
pub use deserialized_account_config::*;
|
||||
|
||||
pub mod format;
|
||||
pub use format::*;
|
||||
}
|
||||
|
||||
pub mod compl;
|
||||
pub mod config;
|
||||
pub mod output;
|
||||
pub mod ui;
|
||||
|
|
|
@ -144,7 +144,7 @@ fn main() -> Result<()> {
|
|||
// Check mailbox commands.
|
||||
match mbox_arg::matches(&m)? {
|
||||
Some(mbox_arg::Cmd::List(max_width)) => {
|
||||
return mbox_handler::list(max_width, &mut printer, backend);
|
||||
return mbox_handler::list(max_width, &account_config, &mut printer, backend);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
|
|
@ -7,19 +7,27 @@ use log::{info, trace};
|
|||
|
||||
use crate::{
|
||||
backends::Backend,
|
||||
config::AccountConfig,
|
||||
output::{PrintTableOpts, PrinterService},
|
||||
};
|
||||
|
||||
/// Lists all mailboxes.
|
||||
pub fn list<'a, P: PrinterService, B: Backend<'a> + ?Sized>(
|
||||
max_width: Option<usize>,
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: Box<&'a mut B>,
|
||||
) -> Result<()> {
|
||||
info!("entering list mailbox handler");
|
||||
let mboxes = backend.get_mboxes()?;
|
||||
trace!("mailboxes: {:?}", mboxes);
|
||||
printer.print_table(mboxes, PrintTableOpts { max_width })
|
||||
printer.print_table(
|
||||
mboxes,
|
||||
PrintTableOpts {
|
||||
format: &config.format,
|
||||
max_width,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -159,11 +167,12 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
let config = AccountConfig::default();
|
||||
let mut printer = PrinterServiceTest::default();
|
||||
let mut backend = TestBackend {};
|
||||
let backend = Box::new(&mut backend);
|
||||
|
||||
assert!(list(None, &mut printer, backend).is_ok());
|
||||
assert!(list(None, &config, &mut printer, backend).is_ok());
|
||||
assert_eq!(
|
||||
concat![
|
||||
"\n",
|
||||
|
|
|
@ -110,7 +110,13 @@ pub fn list<'a, P: PrinterService, B: Backend<'a> + ?Sized>(
|
|||
debug!("page size: {}", page_size);
|
||||
let msgs = imap.get_envelopes(mbox, page_size, page)?;
|
||||
trace!("envelopes: {:?}", msgs);
|
||||
printer.print_table(msgs, PrintTableOpts { max_width })
|
||||
printer.print_table(
|
||||
msgs,
|
||||
PrintTableOpts {
|
||||
format: &config.format,
|
||||
max_width,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Parses and edits a message from a [mailto] URL string.
|
||||
|
@ -275,7 +281,13 @@ pub fn search<'a, P: PrinterService, B: Backend<'a> + ?Sized>(
|
|||
debug!("page size: {}", page_size);
|
||||
let msgs = backend.search_envelopes(mbox, &query, "", page_size, page)?;
|
||||
trace!("messages: {:#?}", msgs);
|
||||
printer.print_table(msgs, PrintTableOpts { max_width })
|
||||
printer.print_table(
|
||||
msgs,
|
||||
PrintTableOpts {
|
||||
format: &config.format,
|
||||
max_width,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Paginates messages from the selected mailbox matching the specified query, sorted by the given criteria.
|
||||
|
@ -294,7 +306,13 @@ pub fn sort<'a, P: PrinterService, B: Backend<'a> + ?Sized>(
|
|||
debug!("page size: {}", page_size);
|
||||
let msgs = backend.search_envelopes(mbox, &query, &sort, page_size, page)?;
|
||||
trace!("envelopes: {:#?}", msgs);
|
||||
printer.print_table(msgs, PrintTableOpts { max_width })
|
||||
printer.print_table(
|
||||
msgs,
|
||||
PrintTableOpts {
|
||||
format: &config.format,
|
||||
max_width,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Send a raw message.
|
||||
|
|
|
@ -2,6 +2,8 @@ use anyhow::Result;
|
|||
use std::io;
|
||||
use termcolor::{self, StandardStream};
|
||||
|
||||
use crate::config::Format;
|
||||
|
||||
pub trait WriteColor: io::Write + termcolor::WriteColor {}
|
||||
|
||||
impl WriteColor for StandardStream {}
|
||||
|
@ -10,6 +12,7 @@ pub trait PrintTable {
|
|||
fn print_table(&self, writter: &mut dyn WriteColor, opts: PrintTableOpts) -> Result<()>;
|
||||
}
|
||||
|
||||
pub struct PrintTableOpts {
|
||||
pub struct PrintTableOpts<'a> {
|
||||
pub format: &'a Format,
|
||||
pub max_width: Option<usize>,
|
||||
}
|
||||
|
|
|
@ -10,7 +10,10 @@ use termcolor::{Color, ColorSpec};
|
|||
use terminal_size;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use crate::output::{Print, PrintTableOpts, WriteColor};
|
||||
use crate::{
|
||||
config::Format,
|
||||
output::{Print, PrintTableOpts, WriteColor},
|
||||
};
|
||||
|
||||
/// Defines the default terminal size.
|
||||
/// This is used when the size cannot be determined by the `terminal_size` crate.
|
||||
|
@ -164,10 +167,15 @@ where
|
|||
|
||||
/// Writes the table to the writter.
|
||||
fn print(writter: &mut dyn WriteColor, items: &[Self], opts: PrintTableOpts) -> Result<()> {
|
||||
let max_width = opts
|
||||
.max_width
|
||||
.or_else(|| terminal_size::terminal_size().map(|(w, _)| w.0 as usize))
|
||||
.unwrap_or(DEFAULT_TERM_WIDTH);
|
||||
let is_format_flowed = matches!(opts.format, Format::Flowed);
|
||||
let max_width = match opts.format {
|
||||
Format::Fixed(width) => opts.max_width.unwrap_or(*width),
|
||||
Format::Flowed => 0,
|
||||
Format::Auto => opts
|
||||
.max_width
|
||||
.or_else(|| terminal_size::terminal_size().map(|(w, _)| w.0 as usize))
|
||||
.unwrap_or(DEFAULT_TERM_WIDTH),
|
||||
};
|
||||
let mut table = vec![Self::head()];
|
||||
let mut cell_widths: Vec<usize> =
|
||||
table[0].0.iter().map(|cell| cell.unicode_width()).collect();
|
||||
|
@ -195,7 +203,7 @@ where
|
|||
glue.print(writter)?;
|
||||
|
||||
let table_is_overflowing = table_width > max_width;
|
||||
if table_is_overflowing && cell.is_shrinkable() {
|
||||
if table_is_overflowing && !is_format_flowed && cell.is_shrinkable() {
|
||||
trace!("table is overflowing and cell is shrinkable");
|
||||
|
||||
let shrink_width = table_width - max_width;
|
||||
|
@ -329,7 +337,7 @@ mod tests {
|
|||
|
||||
macro_rules! write_items {
|
||||
($writter:expr, $($item:expr),*) => {
|
||||
Table::print($writter, &[$($item,)*], PrintTableOpts { max_width: Some(20) }).unwrap();
|
||||
Table::print($writter, &[$($item,)*], PrintTableOpts { format: &Format::Auto, max_width: Some(20) }).unwrap();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue