Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
# i3status-rust 0.35.0 [unreleased]

### Bug Fixes and Improvements

- The `notmuch` block can now automatically locate the notmuch database (the same way the `notmuch` command does) without being explicitly configured. Furthermore, the block has gained a `profile` option that can be used to specify a notmuch profile other than "default".

### Breaking Changes

- The `interval` option has been removed from the `notmuch` block in favor of watching the notmuch database for changes.
- The `maildir` option in the `notmuch` block has been renamed to `database` to better reflect its purpose, and has been made optional.

# i3status-rust 0.34.0

### New Blocks and Features
Expand Down
1 change: 1 addition & 0 deletions cspell.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ignoreRegExpList:
# Ignore unicode characters
- /(\\u[0-9a-fA-F]{4}|\\U[0-9a-fA-F]{8})/g
words:
- xapian
- aarch
- alacritty
- alphanum
Expand Down
69 changes: 58 additions & 11 deletions src/blocks/notmuch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,23 @@
//! # Icons Used
//! - `mail`

use inotify::{Inotify, WatchMask};

use super::prelude::*;

#[derive(Deserialize, Debug, SmartDefault)]
#[serde(deny_unknown_fields, default)]
pub struct Config {
pub format: FormatConfig,
#[default(10.into())]
pub interval: Seconds,
#[default("~/.mail".into())]
pub maildir: ShellString,
/// Path to the notmuch database.
///
/// Defaults to the database used by the notmuch CLI tool.
pub database: Option<ShellString>,
/// Database profile. Cannot be specified at the same time as `database`.
///
/// Defaults to the profile used by the notmuch CLI tool.
pub profile: Option<String>,
/// The notmuch query to count.
pub query: String,
#[default(u32::MAX)]
pub threshold_warning: u32,
Expand All @@ -67,12 +74,36 @@ pub struct Config {
pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
let format = config.format.with_default(" $icon $count ")?;

let db = config.maildir.expand()?;
let mut timer = config.interval.timer();
if config.database.is_some() && config.profile.is_some() {
return Err(Error::new(
"cannot specify both a notmuch database and a notmuch profile",
));
}

let profile = config.profile.as_deref();

let db_path = config.database.as_ref().map(|p| p.expand()).transpose()?;
let db_path: Option<&str> = db_path.as_deref();
let notify = Inotify::init().error("Failed to start inotify")?;

{
let lock_path = open_database(db_path, profile)
.error("failed to open the notmuch database")?
.path()
.join("xapian/flintlock");
notify
.watches()
.add(lock_path, WatchMask::CLOSE_WRITE)
.error("failed to watch the notmuch database lock")?;
}

let mut updates = notify
.into_event_stream([0; 1024])
.error("Failed to create event stream")?;

loop {
// TODO: spawn_blocking?
let count = run_query(&db, &config.query).error("Failed to get count")?;
let count = run_query(db_path, profile, &config.query).error("Failed to get count")?;

let mut widget = Widget::new().with_format(format.clone());

Expand All @@ -96,18 +127,34 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
api.set_widget(widget)?;

tokio::select! {
_ = timer.tick() => (),
_ = updates.next_debounced() => (),
_ = api.wait_for_update_request() => (),
}
}
}

fn run_query(db_path: &str, query_string: &str) -> std::result::Result<u32, notmuch::Error> {
fn open_database(
db_path: Option<&str>,
profile: Option<&str>,
) -> std::result::Result<notmuch::Database, notmuch::Error> {
notmuch::Database::open_with_config(
db_path,
notmuch::DatabaseMode::ReadOnly,
None::<&str>,
profile,
)
}

fn run_query(
db_path: Option<&str>,
profile: Option<&str>,
query_string: &str,
) -> std::result::Result<u32, notmuch::Error> {
let db = notmuch::Database::open_with_config(
Some(db_path),
db_path,
notmuch::DatabaseMode::ReadOnly,
None::<&str>,
None,
profile,
)?;
let query = db.create_query(query_string)?;
query.count_messages()
Expand Down