Skip to main content

fastpaper/commands/
mod.rs

1//! One module per command. Each owns its argument validation, source calls and
2//! rendering; `main.rs` only dispatches and maps errors to exit codes.
3
4pub mod cite;
5pub mod download;
6pub mod get;
7pub mod read;
8pub mod search;
9pub mod sources;
10
11use std::path::Path;
12
13use crate::cli::OutputFormat;
14use crate::output;
15use crate::sources::Paper;
16
17/// What went wrong, and how the process should exit.
18#[derive(Debug)]
19pub enum CommandError {
20    /// Exit 1: bad arguments, network failure, parse failure.
21    Failed(String),
22    /// Exit 4: the request was well-formed but matched nothing.
23    NotFound(String),
24    /// Exit 0: the file was already there, which is not a failure.
25    AlreadyExists(String),
26}
27
28impl CommandError {
29    pub fn exit_code(&self) -> i32 {
30        match self {
31            CommandError::Failed(_) => 1,
32            CommandError::NotFound(_) => 4,
33            CommandError::AlreadyExists(_) => 0,
34        }
35    }
36
37    pub fn message(&self) -> &str {
38        match self {
39            CommandError::Failed(m)
40            | CommandError::NotFound(m)
41            | CommandError::AlreadyExists(m) => m,
42        }
43    }
44}
45
46pub type CommandResult = Result<(), CommandError>;
47
48pub fn failed(message: impl Into<String>) -> CommandError {
49    CommandError::Failed(message.into())
50}
51
52/// Render papers in the requested format.
53pub fn render(papers: &[Paper], format: OutputFormat) -> String {
54    match format {
55        OutputFormat::Json => output::to_json(papers),
56        OutputFormat::Jsonl => output::to_jsonl(papers),
57        OutputFormat::Csv => output::to_csv(papers),
58        OutputFormat::Bibtex => output::to_bibtex(papers),
59        OutputFormat::Table => output::to_table(papers),
60    }
61}
62
63/// Write to a file when `-o` was given, otherwise to stdout.
64pub fn emit(text: &str, output_path: Option<&Path>) -> CommandResult {
65    match output_path {
66        Some(path) => std::fs::write(path, text)
67            .map_err(|e| failed(format!("Failed to write {}: {}", path.display(), e))),
68        None => {
69            print!("{}", text);
70            Ok(())
71        }
72    }
73}