mirror of
https://github.com/pimalaya/himalaya.git
synced 2026-06-16 12:47:55 +08:00
228 lines
7.0 KiB
Rust
228 lines
7.0 KiB
Rust
use std::{fmt, ops::Deref};
|
|
|
|
use anyhow::{bail, Result};
|
|
use clap::Parser;
|
|
use comfy_table::{presets, Cell, ContentArrangement, Row, Table};
|
|
use crossterm::style::Color;
|
|
use io_imap::coroutines::list::*;
|
|
use io_stream::runtimes::std::handle;
|
|
use pimalaya_toolbox::terminal::printer::Printer;
|
|
use serde::{Serialize, Serializer};
|
|
|
|
use crate::{config::ImapConfig, imap::stream};
|
|
|
|
/// List all mailboxes.
|
|
///
|
|
/// This command allows you to list all exsting mailboxes from your
|
|
/// IMAP account.
|
|
#[derive(Debug, Parser)]
|
|
pub struct ListMailboxesCommand {
|
|
// /// The maximum width the table should not exceed.
|
|
// ///
|
|
// /// This argument will force the table not to exceed the given
|
|
// /// width, in pixels. Columns may shrink with ellipsis in order to
|
|
// /// fit the width.
|
|
// #[arg(long = "max-width", short = 'w')]
|
|
// #[arg(name = "table_max_width", value_name = "PIXELS")]
|
|
// pub table_max_width: Option<u16>,
|
|
}
|
|
|
|
impl ListMailboxesCommand {
|
|
pub fn execute(self, printer: &mut impl Printer, config: ImapConfig) -> Result<()> {
|
|
let (context, mut stream) = stream::connect(config)?;
|
|
|
|
let mut arg = None;
|
|
let mut coroutine = ImapList::new(context, "".try_into().unwrap(), "*".try_into().unwrap());
|
|
|
|
let mailboxes = loop {
|
|
match coroutine.resume(arg.take()) {
|
|
ImapListResult::Io(io) => arg = Some(handle(&mut stream, io)?),
|
|
ImapListResult::Ok { mailboxes, .. } => break mailboxes,
|
|
ImapListResult::Err { err, .. } => bail!(err),
|
|
}
|
|
};
|
|
|
|
let table = MailboxesTable::from(mailboxes);
|
|
|
|
printer.out(table)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
|
|
#[serde(rename_all = "kebab-case")]
|
|
pub struct ListMailboxesTableConfig {
|
|
pub preset: Option<String>,
|
|
pub name_color: Option<Color>,
|
|
pub desc_color: Option<Color>,
|
|
}
|
|
|
|
impl ListMailboxesTableConfig {
|
|
pub fn preset(&self) -> &str {
|
|
self.preset.as_deref().unwrap_or(presets::ASCII_MARKDOWN)
|
|
}
|
|
|
|
pub fn name_color(&self) -> comfy_table::Color {
|
|
map_color(self.name_color.unwrap_or(Color::Blue))
|
|
}
|
|
|
|
pub fn desc_color(&self) -> comfy_table::Color {
|
|
map_color(self.desc_color.unwrap_or(Color::Green))
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize)]
|
|
pub struct Mailbox {
|
|
pub name: String,
|
|
pub delimiter: String,
|
|
pub attributes: Vec<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Default, Serialize)]
|
|
pub struct Mailboxes(Vec<Mailbox>);
|
|
|
|
impl<T: IntoIterator<Item = Mailbox>> From<T> for Mailboxes {
|
|
fn from(mboxes: T) -> Self {
|
|
Self(mboxes.into_iter().collect())
|
|
}
|
|
}
|
|
|
|
impl Deref for Mailboxes {
|
|
type Target = Vec<Mailbox>;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
pub struct MailboxesTable {
|
|
mailboxes: Mailboxes,
|
|
width: Option<u16>,
|
|
config: ListMailboxesTableConfig,
|
|
}
|
|
|
|
impl MailboxesTable {
|
|
pub fn with_some_width(mut self, width: Option<u16>) -> Self {
|
|
self.width = width;
|
|
self
|
|
}
|
|
|
|
pub fn with_some_preset(mut self, preset: Option<String>) -> Self {
|
|
self.config.preset = preset;
|
|
self
|
|
}
|
|
|
|
pub fn with_some_name_color(mut self, color: Option<Color>) -> Self {
|
|
self.config.name_color = color;
|
|
self
|
|
}
|
|
|
|
pub fn with_some_desc_color(mut self, color: Option<Color>) -> Self {
|
|
self.config.desc_color = color;
|
|
self
|
|
}
|
|
}
|
|
|
|
impl
|
|
From<
|
|
Vec<(
|
|
io_imap::types::mailbox::Mailbox<'static>,
|
|
Option<io_imap::types::core::QuotedChar>,
|
|
Vec<io_imap::types::flag::FlagNameAttribute<'static>>,
|
|
)>,
|
|
> for MailboxesTable
|
|
{
|
|
fn from(
|
|
mailboxes: Vec<(
|
|
io_imap::types::mailbox::Mailbox<'static>,
|
|
Option<io_imap::types::core::QuotedChar>,
|
|
Vec<io_imap::types::flag::FlagNameAttribute<'static>>,
|
|
)>,
|
|
) -> Self {
|
|
Self {
|
|
mailboxes: mailboxes
|
|
.into_iter()
|
|
.map(|(mbox, delim, attrs)| Mailbox {
|
|
name: match mbox {
|
|
io_imap::types::mailbox::Mailbox::Inbox => "Inbox".into(),
|
|
io_imap::types::mailbox::Mailbox::Other(mbox) => {
|
|
String::from_utf8_lossy(mbox.inner().as_ref()).to_string()
|
|
}
|
|
},
|
|
delimiter: match delim {
|
|
Some(delim) => delim.inner().to_string(),
|
|
None => String::new(),
|
|
},
|
|
attributes: attrs.into_iter().map(|attr| attr.to_string()).collect(),
|
|
})
|
|
.into(),
|
|
width: None,
|
|
config: Default::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for MailboxesTable {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
let mut table = Table::new();
|
|
|
|
table
|
|
.load_preset(self.config.preset())
|
|
.set_content_arrangement(ContentArrangement::DynamicFullWidth)
|
|
.set_header(Row::from([
|
|
Cell::new("NAME"),
|
|
Cell::new("DELIMITER"),
|
|
Cell::new("ATTRIBUTES"),
|
|
]))
|
|
.add_rows(self.mailboxes.iter().map(|mbox| {
|
|
let mut row = Row::new();
|
|
row.max_height(1);
|
|
|
|
row.add_cell(Cell::new(&mbox.name).fg(self.config.name_color()));
|
|
row.add_cell(Cell::new(&mbox.delimiter).fg(self.config.desc_color()));
|
|
row.add_cell(Cell::new(&mbox.attributes.join(", ")).fg(self.config.desc_color()));
|
|
|
|
row
|
|
}));
|
|
|
|
if let Some(width) = self.width {
|
|
table.set_width(width);
|
|
}
|
|
|
|
writeln!(f)?;
|
|
write!(f, "{table}")?;
|
|
writeln!(f)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl Serialize for MailboxesTable {
|
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
|
self.mailboxes.serialize(serializer)
|
|
}
|
|
}
|
|
|
|
fn map_color(color: Color) -> comfy_table::Color {
|
|
match color {
|
|
Color::Reset => comfy_table::Color::Reset,
|
|
Color::Black => comfy_table::Color::Black,
|
|
Color::DarkGrey => comfy_table::Color::DarkGrey,
|
|
Color::Red => comfy_table::Color::Red,
|
|
Color::DarkRed => comfy_table::Color::DarkRed,
|
|
Color::Green => comfy_table::Color::Green,
|
|
Color::DarkGreen => comfy_table::Color::DarkGreen,
|
|
Color::Yellow => comfy_table::Color::Yellow,
|
|
Color::DarkYellow => comfy_table::Color::DarkYellow,
|
|
Color::Blue => comfy_table::Color::Blue,
|
|
Color::DarkBlue => comfy_table::Color::DarkBlue,
|
|
Color::Magenta => comfy_table::Color::Magenta,
|
|
Color::DarkMagenta => comfy_table::Color::DarkMagenta,
|
|
Color::Cyan => comfy_table::Color::Cyan,
|
|
Color::DarkCyan => comfy_table::Color::DarkCyan,
|
|
Color::White => comfy_table::Color::White,
|
|
Color::Grey => comfy_table::Color::Grey,
|
|
Color::Rgb { r, g, b } => comfy_table::Color::Rgb { r, g, b },
|
|
Color::AnsiValue(n) => comfy_table::Color::AnsiValue(n),
|
|
}
|
|
}
|