#![warn(missing_docs, clippy::missing_docs_in_private_items)]
use std::{path::PathBuf, str::FromStr};
use clap::{builder::ArgAction, Parser, Subcommand};
use console::style;
use error::LearnerdError;
use learner::{database::Database, error::LearnerError, paper::Paper, prelude::*, Config, Learner};
use tracing::trace;
use tracing_subscriber::EnvFilter;
pub mod commands;
pub mod daemon;
pub mod error;
pub mod interaction;
#[cfg(feature = "tui")] pub mod tui;
use crate::{commands::*, daemon::*, error::*};
static INFO_PREFIX: &str = "ℹ ";
static SUCCESS_PREFIX: &str = "✓ ";
static WARNING_PREFIX: &str = "⚠️ ";
static ERROR_PREFIX: &str = "✗ ";
static PROMPT_PREFIX: &str = "❯ ";
static CONTINUE_PREFIX: &str = "│ ";
static TREE_VERT: &str = "│";
static TREE_BRANCH: &str = "├";
static TREE_LEAF: &str = "└";
#[derive(Parser)]
#[command(author, version, about = "Daemon and CLI for the learner paper management system")]
pub struct Cli {
#[arg(
short,
long,
action = ArgAction::Count,
global = true,
help = "Increase logging verbosity"
)]
verbose: u8,
#[arg(long, short, global = true)]
path: Option<PathBuf>,
#[command(subcommand)]
command: Option<Commands>,
#[arg(long, hide = true, global = true)]
accept_defaults: bool,
}
fn setup_logging(verbosity: u8) {
let filter = match verbosity {
0 => "error",
1 => "warn",
2 => "info",
3 => "debug",
_ => "trace",
};
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(filter));
tracing_subscriber::fmt()
.with_env_filter(filter)
.with_file(true)
.with_line_number(true)
.with_thread_ids(true)
.with_target(true)
.init();
}
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();
let command = cli.command.clone().unwrap_or_else(|| {
#[cfg(feature = "tui")]
return Commands::Tui;
#[cfg(not(feature = "tui"))]
{
println!("Please specify a command. Use --help for usage information.");
std::process::exit(1);
}
});
if let Commands::Daemon { .. } = command {
} else {
setup_logging(cli.verbose);
}
if let Ok(learner) = Learner::from_path(Config::default_path()?).await {
match command {
Commands::Init => init(cli).await,
Commands::Add { identifier, pdf, no_pdf } =>
add(&cli, learner, &identifier, pdf, no_pdf).await,
Commands::Remove { query, filter, dry_run, force, remove_pdf, keep_pdf } =>
remove(&cli, learner, &query, &filter, dry_run, force, remove_pdf, keep_pdf).await,
Commands::Search { query, filter, detailed } =>
search(&cli, learner, &query, &filter, detailed).await,
Commands::Daemon { cmd } => daemon(cmd).await,
#[cfg(feature = "tui")]
Commands::Tui => tui::run().await,
}
} else {
eprintln!(
"{} Failed to open Learner config! Please run `learner init` to set up a config!",
style(ERROR_PREFIX).red(),
);
Err(LearnerdError::from(LearnerError::Config(
"Configuration not initialized. Run 'learner init' first.".to_string(),
)))
}
}