#[cfg(test)]
#[macro_use]
extern crate matches;
extern crate clap;
use clap::Parser;
use commands::Cli;
use errors::Error;
use std::{
io::{self, Write},
process::ExitCode,
};
use tasks::SortOrder;
use tokio::sync::mpsc::{UnboundedSender, unbounded_channel};
mod cargo;
mod commands;
mod comments;
mod config;
mod debug;
mod errors;
mod filters;
mod format;
mod input;
mod labels;
mod legacy;
mod lists;
mod oauth;
mod projects;
mod regexes;
mod reminders;
mod sections;
mod shell;
mod tasks;
mod test;
mod test_time;
mod time;
mod todoist;
mod update;
mod users;
const LOWERCASE_NAME: &str = "tod";
const VERSION: &str = env!("CARGO_PKG_VERSION");
struct CommandResult {
result: Result<String, Error>,
bell_success: bool,
bell_failure: bool,
}
#[tokio::main]
async fn main() -> ExitCode {
let cli = Cli::parse();
let (tx, mut rx) = unbounded_channel::<Error>();
let result = run_command(cli, tx).await;
let mut exit_code = output_result(result);
while let Ok(error) = rx.try_recv() {
if error.source.as_str() == "shell command" {
exit_code = 1;
}
eprintln!("Error from async process: {error}");
}
ExitCode::from(exit_code)
}
fn output_result(result: CommandResult) -> u8 {
match result.result {
Ok(text) => {
println!("{text}");
if result.bell_success {
terminal_bell()
}
0
}
Err(e) => {
eprintln!("\n\n{e}");
if result.bell_failure {
terminal_bell()
}
1
}
}
}
async fn run_command(cli: Cli, tx: UnboundedSender<Error>) -> CommandResult {
commands::select_command(cli, tx)
.await
.unwrap_or_else(|e| CommandResult {
result: Err(e),
bell_success: true,
bell_failure: true,
})
}
fn terminal_bell() {
print!("\x07");
io::stdout().flush().expect("failed to flush stdout");
}
#[test]
fn verify_cmd() {
use clap::CommandFactory;
Cli::try_parse().err();
Cli::command().debug_assert();
}