diff --git a/Justfile b/Justfile new file mode 100644 index 0000000..67907d4 --- /dev/null +++ b/Justfile @@ -0,0 +1,2 @@ +doc: + cargo doc --document-private-items diff --git a/src/config.rs b/src/config.rs index 41164a6..964f44d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,7 @@ +//! Module for setting up config files and watchers. +//! +//! One of the primary goals of panorama is to be able to always hot-reload configuration files. + use std::fs::File; use std::sync::mpsc::{self, Receiver}; use std::time::Duration; @@ -9,14 +13,22 @@ use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher}; use tokio::sync::watch; use xdg::BaseDirectories; +/// Alias for a MailConfig receiver. pub type ConfigWatcher = watch::Receiver>; +/// Configuration #[derive(Default, Serialize, Deserialize, Clone, Debug)] pub struct MailConfig { + /// Host of the IMAP server (needs to be hostname for TLS) pub server: String, + + /// Port of the IMAP server pub port: u16, + /// Username for authenticating to IMAP pub username: String, + + /// Password for authenticating to IMAP pub password: String, } @@ -46,6 +58,10 @@ async fn read_config(path: impl AsRef) -> Result { Ok(config) } +/// The inner loop of the watcher, which is responsible for taking events received by the watcher +/// and trying to parse and return the config. +/// +/// This exists so all errors are able to be caught in one go. async fn watcher_loop( fs_events: Receiver, config_tx: watch::Sender>, @@ -67,6 +83,8 @@ async fn watcher_loop( Ok(()) } +/// Start the entire config watcher system, and return a [ConfigWatcher][self::ConfigWatcher], +/// which is a cloneable receiver of config update events. pub fn spawn_config_watcher() -> Result { let (_watcher, config_rx) = start_watcher()?; let (config_tx, config_update) = watch::channel(None); diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..84b6f59 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,20 @@ +//! Panorama +//! === + +#![deny(missing_docs)] + +#[macro_use] +extern crate anyhow; +#[macro_use] +extern crate crossterm; +#[macro_use] +extern crate log; +#[macro_use] +extern crate serde; + +pub mod config; +pub mod mail; +pub mod ui; + +/// A cloneable type that allows sending an exit-"signal" to stop the application. +pub type ExitSender = tokio::sync::oneshot::Sender<()>; diff --git a/src/mail.rs b/src/mail.rs index 502bb81..92b2d23 100644 --- a/src/mail.rs +++ b/src/mail.rs @@ -1,3 +1,5 @@ +//! Mail + use std::collections::HashMap; use std::fmt::Display; use std::sync::Arc; @@ -24,8 +26,12 @@ use tokio_util::codec::{Decoder, LinesCodec, LinesCodecError}; use crate::config::{MailConfig, ConfigWatcher}; +/// Command sent to the mail thread by something else (i.e. UI) pub enum MailCommand { + /// Refresh the list Refresh, + + /// Send a raw command Raw(Command), } diff --git a/src/main.rs b/src/main.rs index 0013768..e329e6e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,3 @@ -#[macro_use] -extern crate anyhow; -#[macro_use] -extern crate crossterm; -#[macro_use] -extern crate log; -#[macro_use] -extern crate serde; - -mod config; -mod mail; -mod ui; - use std::fs::File; use std::io::Read; use std::path::PathBuf; @@ -20,10 +7,7 @@ use futures::future::TryFutureExt; use structopt::StructOpt; use tokio::sync::{mpsc, oneshot}; use xdg::BaseDirectories; - -use crate::config::{spawn_config_watcher, MailConfig}; - -type ExitSender = oneshot::Sender<()>; +use panorama::config::{spawn_config_watcher, MailConfig}; #[derive(Debug, StructOpt)] #[structopt(author, about)] @@ -48,7 +32,6 @@ async fn main() -> Result<()> { let xdg = BaseDirectories::new()?; let config_update = spawn_config_watcher()?; - let config = MailConfig::default(); // let config: MailConfig = { // let config_path = opt // .config_path @@ -74,10 +57,6 @@ async fn main() -> Result<()> { Ok(()) } -fn report_err(err: anyhow::Error) { - error!("error: {:?}", err); -} - fn setup_logger(opt: &Opt) -> Result<()> { let mut fern = fern::Dispatch::new() .format(|out, message, record| { @@ -98,3 +77,7 @@ fn setup_logger(opt: &Opt) -> Result<()> { fern.apply()?; Ok(()) } + +fn report_err(err: anyhow::Error) { + log::error!("error: {:?}", err); +} diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 32e5cfa..ad13c42 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,3 +1,5 @@ +//! UI + mod table; use std::io::Write; @@ -23,6 +25,7 @@ const FRAME: Duration = Duration::from_millis(20); #[derive(Copy, Clone)] pub struct Rect(u16, u16, u16, u16); +/// UI entrypoint. pub async fn run_ui(mut w: impl Write, exit: ExitSender) -> Result<()> { execute!(w, cursor::Hide, terminal::EnterAlternateScreen)?; terminal::enable_raw_mode()?;