Skip to content

Commit

Permalink
make tables more customizable
Browse files Browse the repository at this point in the history
All tables can customize the color of their column, and the envelopes
table can customize its flag chars.
  • Loading branch information
soywod committed Aug 20, 2024
1 parent daf2c7c commit 8ccabf1
Show file tree
Hide file tree
Showing 14 changed files with 535 additions and 166 deletions.
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Added `account.list.table.preset` global config option, `accounts.<name>.folder.list.table.preset` and `accounts.<name>.envelope.list.table.preset` account config options.

These options customize the shape of tables, see examples at [`comfy_table::presets`](https://docs.rs/comfy-table/latest/comfy_table/presets/index.html). Defaults to `"|| |-||| "`, which corresponds to [`comfy_table::presets::ASCII_MARKDOWN`](https://docs.rs/comfy-table/latest/comfy_table/presets/constant.ASCII_MARKDOWN.html).

- Added `account.list.table.name-color` config option to customize the color used for the accounts' `NAME` column (defaults to `green`).
- Added `account.list.table.backends-color` config option to customize the color used for the folders' `BACKENDS` column (defaults to `blue`).
- Added `account.list.table.default-color` config option to customize the color used for the folders' `DEFAULT` column (defaults to `reset`).
- Added `accounts.<name>.folder.list.table.name-color` account config option to customize the color used for the folders' `NAME` column (defaults to `blue`).
- Added `accounts.<name>.folder.list.table.desc-color` account config option to customize the color used for the folders' `DESC` column (defaults to `green`).
- Added `accounts.<name>.envelope.list.table.id-color` account config option to customize the color used for the envelopes' `ID` column (defaults to `red`).
- Added `accounts.<name>.envelope.list.table.flags-color` account config option to customize the color used for the envelopes' `FLAGS` column (defaults to `reset`).
- Added `accounts.<name>.envelope.list.table.subject-color` account config option to customize the color used for the envelopes' `SUBJECT` column (defaults to `green`).
- Added `accounts.<name>.envelope.list.table.sender-color` account config option to customize the color used for the envelopes' `FROM` column (defaults to `blue`).
- Added `accounts.<name>.envelope.list.table.date-color` account config option to customize the color used for the envelopes' `DATE` column (defaults to `dark_yellow`).
- Added `accounts.<name>.envelope.list.table.unseen-char` account config option to customize the char used for unseen envelopes (defaults to `*`).
- Added `accounts.<name>.envelope.list.table.replied-char` account config option to customize the char used for replied envelopes (defaults to `R`).
- Added `accounts.<name>.envelope.list.table.flagged-char` account config option to customize the char used for flagged envelopes (defaults to `!`).
- Added `accounts.<name>.envelope.list.table.attachment-char` account config option to customize the char used for envelopes with at least one attachment (defaults to `@`).

## [1.0.0-beta.4] - 2024-04-16

### Added
Expand Down
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ clap_mangen = "0.2"
color-eyre = "0.6.3"
comfy-table = "7.1.1"
console = "0.15.2"
crossterm = "0.27"
crossterm = { version = "0.27", features = ["serde"] }
dirs = "4"
email-lib = { version = "=0.25.0", default-features = false, features = ["derive", "thread", "tracing"] }
email_address = "0.2.4"
Expand Down
7 changes: 6 additions & 1 deletion src/account/command/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ impl AccountListCommand {
info!("executing list accounts command");

let accounts = Accounts::from(config.accounts.iter());
let table = AccountsTable::from(accounts).with_some_width(self.table_max_width);
let table = AccountsTable::from(accounts)
.with_some_width(self.table_max_width)
.with_some_preset(config.account_list_table_preset())
.with_some_name_color(config.account_list_table_name_color())
.with_some_backends_color(config.account_list_table_backends_color())
.with_some_default_color(config.account_list_table_default_color());

printer.out(table)?;
Ok(())
Expand Down
135 changes: 134 additions & 1 deletion src/account/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
//! This module contains the raw deserialized representation of an
//! account in the accounts section of the user configuration file.
use comfy_table::presets;
use crossterm::style::Color;
#[cfg(feature = "pgp")]
use email::account::config::pgp::PgpConfig;
#[cfg(feature = "imap")]
Expand All @@ -21,7 +23,7 @@ use std::{collections::HashSet, path::PathBuf};

use crate::{
backend::BackendKind, envelope::config::EnvelopeConfig, flag::config::FlagConfig,
folder::config::FolderConfig, message::config::MessageConfig,
folder::config::FolderConfig, message::config::MessageConfig, ui::map_color,
};

/// Represents all existing kind of account config.
Expand Down Expand Up @@ -58,6 +60,110 @@ pub struct TomlAccountConfig {
}

impl TomlAccountConfig {
pub fn folder_list_table_preset(&self) -> Option<String> {
self.folder
.as_ref()
.and_then(|folder| folder.list.as_ref())
.and_then(|list| list.table.as_ref())
.and_then(|table| table.preset.clone())
}

pub fn folder_list_table_name_color(&self) -> Option<Color> {
self.folder
.as_ref()
.and_then(|folder| folder.list.as_ref())
.and_then(|list| list.table.as_ref())
.and_then(|table| table.name_color)
}

pub fn folder_list_table_desc_color(&self) -> Option<Color> {
self.folder
.as_ref()
.and_then(|folder| folder.list.as_ref())
.and_then(|list| list.table.as_ref())
.and_then(|table| table.desc_color)
}

pub fn envelope_list_table_preset(&self) -> Option<String> {
self.envelope
.as_ref()
.and_then(|env| env.list.as_ref())
.and_then(|list| list.table.as_ref())
.and_then(|table| table.preset.clone())
}

pub fn envelope_list_table_unseen_char(&self) -> Option<char> {
self.envelope
.as_ref()
.and_then(|env| env.list.as_ref())
.and_then(|list| list.table.as_ref())
.and_then(|table| table.unseen_char)
}

pub fn envelope_list_table_replied_char(&self) -> Option<char> {
self.envelope
.as_ref()
.and_then(|env| env.list.as_ref())
.and_then(|list| list.table.as_ref())
.and_then(|table| table.replied_char)
}

pub fn envelope_list_table_flagged_char(&self) -> Option<char> {
self.envelope
.as_ref()
.and_then(|env| env.list.as_ref())
.and_then(|list| list.table.as_ref())
.and_then(|table| table.flagged_char)
}

pub fn envelope_list_table_attachment_char(&self) -> Option<char> {
self.envelope
.as_ref()
.and_then(|env| env.list.as_ref())
.and_then(|list| list.table.as_ref())
.and_then(|table| table.attachment_char)
}

pub fn envelope_list_table_id_color(&self) -> Option<Color> {
self.envelope
.as_ref()
.and_then(|env| env.list.as_ref())
.and_then(|list| list.table.as_ref())
.and_then(|table| table.id_color)
}

pub fn envelope_list_table_flags_color(&self) -> Option<Color> {
self.envelope
.as_ref()
.and_then(|env| env.list.as_ref())
.and_then(|list| list.table.as_ref())
.and_then(|table| table.flags_color)
}

pub fn envelope_list_table_subject_color(&self) -> Option<Color> {
self.envelope
.as_ref()
.and_then(|env| env.list.as_ref())
.and_then(|list| list.table.as_ref())
.and_then(|table| table.subject_color)
}

pub fn envelope_list_table_sender_color(&self) -> Option<Color> {
self.envelope
.as_ref()
.and_then(|env| env.list.as_ref())
.and_then(|list| list.table.as_ref())
.and_then(|table| table.sender_color)
}

pub fn envelope_list_table_date_color(&self) -> Option<Color> {
self.envelope
.as_ref()
.and_then(|env| env.list.as_ref())
.and_then(|list| list.table.as_ref())
.and_then(|table| table.date_color)
}

pub fn add_folder_kind(&self) -> Option<&BackendKind> {
self.folder
.as_ref()
Expand Down Expand Up @@ -228,3 +334,30 @@ impl TomlAccountConfig {
used_backends
}
}

#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")]
pub struct ListAccountsTableConfig {
pub preset: Option<String>,
pub name_color: Option<Color>,
pub backends_color: Option<Color>,
pub default_color: Option<Color>,
}

impl ListAccountsTableConfig {
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::Green))
}

pub fn backends_color(&self) -> comfy_table::Color {
map_color(self.backends_color.unwrap_or(Color::Blue))
}

pub fn default_color(&self) -> comfy_table::Color {
map_color(self.default_color.unwrap_or(Color::Reset))
}
}
71 changes: 45 additions & 26 deletions src/account/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ pub mod config;
#[cfg(feature = "wizard")]
pub(crate) mod wizard;

use comfy_table::{presets, Attribute, Cell, Color, ContentArrangement, Row, Table};
use comfy_table::{Cell, ContentArrangement, Row, Table};
use crossterm::style::Color;
use serde::{Serialize, Serializer};
use std::{collections::hash_map::Iter, fmt, ops::Deref};

use self::config::TomlAccountConfig;
use self::config::{ListAccountsTableConfig, TomlAccountConfig};

/// Represents the printable account.
#[derive(Debug, Default, PartialEq, Eq, Serialize)]
Expand All @@ -30,12 +31,12 @@ impl Account {
}
}

pub fn to_row(&self) -> Row {
pub fn to_row(&self, config: &ListAccountsTableConfig) -> Row {
let mut row = Row::new();

row.add_cell(Cell::new(&self.name).fg(Color::Green));
row.add_cell(Cell::new(&self.backend).fg(Color::Blue));
row.add_cell(Cell::new(if self.default { "yes" } else { "" }).fg(Color::White));
row.add_cell(Cell::new(&self.name).fg(config.name_color()));
row.add_cell(Cell::new(&self.backend).fg(config.backends_color()));
row.add_cell(Cell::new(if self.default { "yes" } else { "" }).fg(config.default_color()));

row
}
Expand All @@ -51,24 +52,6 @@ impl fmt::Display for Account {
#[derive(Debug, Default, Serialize)]
pub struct Accounts(Vec<Account>);

impl Accounts {
pub fn to_table(&self) -> Table {
let mut table = Table::new();

table
.load_preset(presets::NOTHING)
.set_content_arrangement(ContentArrangement::DynamicFullWidth)
.set_header(Row::from([
Cell::new("NAME").add_attribute(Attribute::Reverse),
Cell::new("BACKENDS").add_attribute(Attribute::Reverse),
Cell::new("DEFAULT").add_attribute(Attribute::Reverse),
]))
.add_rows(self.iter().map(Account::to_row));

table
}
}

impl Deref for Accounts {
type Target = Vec<Account>;

Expand Down Expand Up @@ -98,7 +81,7 @@ impl From<Iter<'_, String, TomlAccountConfig>> for Accounts {
}

#[cfg(feature = "notmuch")]
if account.imap.is_some() {
if account.notmuch.is_some() {
if !backends.is_empty() {
backends.push_str(", ")
}
Expand Down Expand Up @@ -135,27 +118,63 @@ impl From<Iter<'_, String, TomlAccountConfig>> for Accounts {
pub struct AccountsTable {
accounts: Accounts,
width: Option<u16>,
config: ListAccountsTableConfig,
}

impl AccountsTable {
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_backends_color(mut self, color: Option<Color>) -> Self {
self.config.backends_color = color;
self
}

pub fn with_some_default_color(mut self, color: Option<Color>) -> Self {
self.config.default_color = color;
self
}
}

impl From<Accounts> for AccountsTable {
fn from(accounts: Accounts) -> Self {
Self {
accounts,
width: None,
config: Default::default(),
}
}
}

impl fmt::Display for AccountsTable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut table = self.accounts.to_table();
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("BACKENDS"),
Cell::new("DEFAULT"),
]))
.add_rows(
self.accounts
.iter()
.map(|account| account.to_row(&self.config)),
);

if let Some(width) = self.width {
table.set_width(width);
Expand Down
Loading

0 comments on commit 8ccabf1

Please sign in to comment.