i3status_rs/blocks/notmuch.rs
1//! Count of notmuch messages
2//!
3//! This block queries a notmuch database and displays the count of messages.
4//!
5//! The simplest configuration will return the total count of messages in the notmuch database stored at $HOME/.mail
6//!
7//! Note that you need to enable `notmuch` feature to use this block:
8//! ```sh
9//! cargo build --release --features notmuch
10//! ```
11//!
12//! # Configuration
13//!
14//! Key | Values | Default
15//! ----|--------|--------
16//! `format` | A string to customise the output of this block. See below for available placeholders. | `" $icon $count "`
17//! `maildir` | Path to the directory containing the notmuch database. Supports path expansions e.g. `~`. | `~/.mail`
18//! `query` | Query to run on the database. | `""`
19//! `threshold_critical` | Mail count that triggers `critical` state. | `99999`
20//! `threshold_warning` | Mail count that triggers `warning` state. | `99999`
21//! `threshold_good` | Mail count that triggers `good` state. | `99999`
22//! `threshold_info` | Mail count that triggers `info` state. | `99999`
23//! `interval` | Update interval in seconds. | `10`
24//!
25//! Placeholder | Value | Type | Unit
26//! ------------|--------------------------------------------|--------|-----
27//! `icon` | A static icon | Icon | -
28//! `count` | Number of messages for the query | Number | -
29//!
30//! # Example
31//!
32//! ```toml
33//! [[block]]
34//! block = "notmuch"
35//! query = "tag:alert and not tag:trash"
36//! threshold_warning = 1
37//! threshold_critical = 10
38//! [[block.click]]
39//! button = "left"
40//! update = true
41//! ```
42//!
43//! # Icons Used
44//! - `mail`
45
46use super::prelude::*;
47
48#[derive(Deserialize, Debug, SmartDefault)]
49#[serde(deny_unknown_fields, default)]
50pub struct Config {
51 pub format: FormatConfig,
52 #[default(10.into())]
53 pub interval: Seconds,
54 #[default("~/.mail".into())]
55 pub maildir: ShellString,
56 pub query: String,
57 #[default(u32::MAX)]
58 pub threshold_warning: u32,
59 #[default(u32::MAX)]
60 pub threshold_critical: u32,
61 #[default(u32::MAX)]
62 pub threshold_info: u32,
63 #[default(u32::MAX)]
64 pub threshold_good: u32,
65}
66
67pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
68 let format = config.format.with_default(" $icon $count ")?;
69
70 let db = config.maildir.expand()?;
71 let mut timer = config.interval.timer();
72
73 loop {
74 // TODO: spawn_blocking?
75 let count = run_query(&db, &config.query).error("Failed to get count")?;
76
77 let mut widget = Widget::new().with_format(format.clone());
78
79 widget.set_values(map! {
80 "icon" => Value::icon("mail"),
81 "count" => Value::number(count)
82 });
83
84 widget.state = if count >= config.threshold_critical {
85 State::Critical
86 } else if count >= config.threshold_warning {
87 State::Warning
88 } else if count >= config.threshold_good {
89 State::Good
90 } else if count >= config.threshold_info {
91 State::Info
92 } else {
93 State::Idle
94 };
95
96 api.set_widget(widget)?;
97
98 tokio::select! {
99 _ = timer.tick() => (),
100 _ = api.wait_for_update_request() => (),
101 }
102 }
103}
104
105fn run_query(db_path: &str, query_string: &str) -> std::result::Result<u32, notmuch::Error> {
106 let db = notmuch::Database::open_with_config(
107 Some(db_path),
108 notmuch::DatabaseMode::ReadOnly,
109 None::<&str>,
110 None,
111 )?;
112 let query = db.create_query(query_string)?;
113 query.count_messages()
114}