Skip to content

Commit

Permalink
refactor(term): use ApplicationBuilder to construct Application
Browse files Browse the repository at this point in the history
  • Loading branch information
ymgyt committed Jun 2, 2024
1 parent 42edc9b commit 985edfd
Show file tree
Hide file tree
Showing 4 changed files with 220 additions and 54 deletions.
149 changes: 149 additions & 0 deletions crates/synd_term/src/application/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
use crate::{
application::{Application, Authenticator, Cache, Config},
client::Client,
config::Categories,
terminal::Terminal,
ui::theme::Theme,
};

pub struct ApplicationBuilder<
Terminal = (),
Client = (),
Categories = (),
Cache = (),
Config = (),
Theme = (),
> {
pub(super) terminal: Terminal,
pub(super) client: Client,
pub(super) categories: Categories,
pub(super) cache: Cache,
pub(super) config: Config,
pub(super) theme: Theme,

pub(super) authenticator: Option<Authenticator>,
}

impl Default for ApplicationBuilder {
fn default() -> Self {
Self {
terminal: (),
client: (),
categories: (),
cache: (),
config: (),
theme: (),
authenticator: None,
}
}
}

impl<T1, T2, T3, T4, T5> ApplicationBuilder<(), T1, T2, T3, T4, T5> {
#[must_use]
pub fn terminal(self, terminal: Terminal) -> ApplicationBuilder<Terminal, T1, T2, T3, T4, T5> {
ApplicationBuilder {
terminal,
client: self.client,
categories: self.categories,
cache: self.cache,
config: self.config,
theme: self.theme,
authenticator: self.authenticator,
}
}
}

impl<T1, T2, T3, T4, T5> ApplicationBuilder<T1, (), T2, T3, T4, T5> {
#[must_use]
pub fn client(self, client: Client) -> ApplicationBuilder<T1, Client, T2, T3, T4, T5> {
ApplicationBuilder {
terminal: self.terminal,
client,
categories: self.categories,
cache: self.cache,
config: self.config,
theme: self.theme,
authenticator: self.authenticator,
}
}
}

impl<T1, T2, T3, T4, T5> ApplicationBuilder<T1, T2, (), T3, T4, T5> {
#[must_use]
pub fn categories(
self,
categories: Categories,
) -> ApplicationBuilder<T1, T2, Categories, T3, T4, T5> {
ApplicationBuilder {
terminal: self.terminal,
client: self.client,
categories,
cache: self.cache,
config: self.config,
theme: self.theme,
authenticator: self.authenticator,
}
}
}

impl<T1, T2, T3, T4, T5> ApplicationBuilder<T1, T2, T3, (), T4, T5> {
#[must_use]
pub fn cache(self, cache: Cache) -> ApplicationBuilder<T1, T2, T3, Cache, T4, T5> {
ApplicationBuilder {
terminal: self.terminal,
client: self.client,
categories: self.categories,
cache,
config: self.config,
theme: self.theme,
authenticator: self.authenticator,
}
}
}

impl<T1, T2, T3, T4, T5> ApplicationBuilder<T1, T2, T3, T4, (), T5> {
#[must_use]
pub fn config(self, config: Config) -> ApplicationBuilder<T1, T2, T3, T4, Config, T5> {
ApplicationBuilder {
terminal: self.terminal,
client: self.client,
categories: self.categories,
cache: self.cache,
config,
theme: self.theme,
authenticator: self.authenticator,
}
}
}

impl<T1, T2, T3, T4, T5> ApplicationBuilder<T1, T2, T3, T4, T5, ()> {
#[must_use]
pub fn theme(self, theme: Theme) -> ApplicationBuilder<T1, T2, T3, T4, T5, Theme> {
ApplicationBuilder {
terminal: self.terminal,
client: self.client,
categories: self.categories,
cache: self.cache,
config: self.config,
theme,
authenticator: self.authenticator,
}
}
}

impl<T1, T2, T3, T4, T5, T6> ApplicationBuilder<T1, T2, T3, T4, T5, T6> {
#[must_use]
pub fn authenticator(self, authenticator: Authenticator) -> Self {
Self {
authenticator: Some(authenticator),
..self
}
}
}

impl ApplicationBuilder<Terminal, Client, Categories, Cache, Config, Theme> {
#[must_use]
pub fn build(self) -> Application {
Application::new(self)
}
}
58 changes: 30 additions & 28 deletions crates/synd_term/src/application/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ use flags::Should;
mod cache;
pub use cache::Cache;

mod builder;
pub use builder::ApplicationBuilder;

pub(crate) mod event;

enum Screen {
Expand Down Expand Up @@ -107,23 +110,35 @@ pub struct Application {
}

impl Application {
pub fn new(terminal: Terminal, client: Client, categories: Categories, cache: Cache) -> Self {
Application::with(terminal, client, categories, Config::default(), cache)
/// Construct `ApplicationBuilder`
pub fn builder() -> ApplicationBuilder {
ApplicationBuilder::default()
}

pub fn with(
terminal: Terminal,
client: Client,
categories: Categories,
config: Config,
cache: Cache,
/// Construct `Application` from builder.
/// Configure keymaps for terminal use
fn new(
builder: ApplicationBuilder<Terminal, Client, Categories, Cache, Config, Theme>,
) -> Self {
let mut keymaps = Keymaps::default();
keymaps.enable(KeymapId::Global);
keymaps.enable(KeymapId::Login);
let ApplicationBuilder {
terminal,
client,
categories,
cache,
config,
theme,
authenticator,
} = builder;

let key_handlers = {
let mut keymaps = Keymaps::default();
keymaps.enable(KeymapId::Global);
keymaps.enable(KeymapId::Login);

let mut key_handlers = event::KeyHandlers::new();
key_handlers.push(event::KeyHandler::Keymaps(keymaps));
let mut key_handlers = event::KeyHandlers::new();
key_handlers.push(event::KeyHandler::Keymaps(keymaps));
key_handlers
};

Self {
clock: Box::new(SystemClock),
Expand All @@ -132,10 +147,10 @@ impl Application {
jobs: Jobs::new(),
components: Components::new(),
interactor: Interactor::new(),
authenticator: Authenticator::new(),
authenticator: authenticator.unwrap_or_else(Authenticator::new),
in_flight: InFlight::new().with_throbber_timer_interval(config.throbber_timer_interval),
cache,
theme: Theme::default(),
theme,
idle_timer: Box::pin(tokio::time::sleep(config.idle_timer_interval)),
screen: Screen::Login,
config,
Expand All @@ -146,19 +161,6 @@ impl Application {
}
}

#[must_use]
pub fn with_theme(self, theme: Theme) -> Self {
Self { theme, ..self }
}

#[must_use]
pub fn with_authenticator(self, authenticator: Authenticator) -> Self {
Self {
authenticator,
..self
}
}

fn now(&self) -> DateTime<Utc> {
self.clock.now()
}
Expand Down
54 changes: 31 additions & 23 deletions crates/synd_term/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{path::PathBuf, time::Duration};
use std::{future, path::PathBuf, time::Duration};

use anyhow::Context as _;
use crossterm::event::EventStream;
Expand Down Expand Up @@ -59,9 +59,7 @@ fn init_tracing(log_path: Option<PathBuf>) -> anyhow::Result<Option<WorkerGuard>
Ok(guard)
}

// Construct and configure application
#[allow(clippy::unused_async)]
async fn init_app(
fn build_app(
endpoint: Url,
timeout: Duration,
palette: Palette,
Expand All @@ -71,19 +69,22 @@ async fn init_app(
}: FeedOptions,
cache_dir: PathBuf,
) -> anyhow::Result<Application> {
let terminal = Terminal::new().context("Failed to construct terminal")?;
let client = Client::new(endpoint, timeout).context("Failed to construct client")?;
let categories = categories
.map(Categories::load)
.transpose()?
.unwrap_or_else(Categories::default_toml);
let config = Config {
entries_limit,
..Default::default()
};
let cache = Cache::new(cache_dir);
let app = Application::with(terminal, client, categories, config, cache)
.with_theme(Theme::with_palette(&palette.into()));
let app = Application::builder()
.terminal(Terminal::new().context("Failed to construct terminal")?)
.client(Client::new(endpoint, timeout).context("Failed to construct client")?)
.categories(
categories
.map(Categories::load)
.transpose()?
.unwrap_or_else(Categories::default_toml),
)
.config(Config {
entries_limit,
..Default::default()
})
.cache(Cache::new(cache_dir))
.theme(Theme::with_palette(&palette.into()))
.build();

Ok(app)
}
Expand All @@ -102,6 +103,7 @@ async fn main() {
palette,
} = cli::parse();

// Subcommand logs to the terminal, tui writes logs to a file.
let log = if command.is_some() { None } else { Some(log) };
let _guard = init_tracing(log).unwrap();

Expand All @@ -117,12 +119,18 @@ async fn main() {

let mut event_stream = EventStream::new();

if let Err(err) = init_app(endpoint, client_timeout, palette, feed, cache_dir)
.and_then(|app| {
tracing::info!("Running...");
app.run(&mut event_stream)
})
.await
if let Err(err) = future::ready(build_app(
endpoint,
client_timeout,
palette,
feed,
cache_dir,
))
.and_then(|app| {
tracing::info!("Running...");
app.run(&mut event_stream)
})
.await
{
error!("{err:?}");
std::process::exit(1);
Expand Down
13 changes: 10 additions & 3 deletions crates/synd_term/tests/test/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,16 @@ impl TestCase {
};
// to isolate the state for each test
let cache = Cache::new(cache_dir);
Application::with(terminal, client, Categories::default_toml(), config, cache)
.with_theme(Theme::default())
.with_authenticator(authenticator)

Application::builder()
.terminal(terminal)
.client(client)
.categories(Categories::default_toml())
.config(config)
.cache(cache)
.theme(Theme::default())
.authenticator(authenticator)
.build()
};

Ok(application)
Expand Down

0 comments on commit 985edfd

Please sign in to comment.