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}