1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use std::convert::TryFrom;
use std::sync::{Arc, RwLock};

#[macro_use]
extern crate lazy_static;
use rayon::iter::{ParallelBridge, ParallelIterator};
use skim::{
    prelude::{unbounded, SkimOptionsBuilder},
    Skim, SkimItemReceiver, SkimItemSender,
};

/// `Action` and its implementations
mod action;
/// `clap` configuration
mod cli;
/// `Config` struct and its implementations
mod config;
/// `FileIter` enum and its implementations
mod file_iter;
/// `PDFContent` and its implementations
mod pdf;

use action::Action;
use file_iter::FileIter;
use pdf::PDFContent;

lazy_static! {
    /// Global configuration for the application
    pub static ref CONFIG: RwLock<config::Config> = RwLock::new(config::Config::new());
}

fn main() {
    let matches = cli::get_app().get_matches();
    CONFIG.write().unwrap().modify_with_argmatches(&matches);
    let (tx_item, rx_item): (SkimItemSender, SkimItemReceiver) = unbounded();

    let path = matches.value_of("PATH").unwrap();
    let with_hidden_files = matches.is_present("hidden");

    FileIter::new(path, with_hidden_files)
        .par_bridge()
        .filter_map(|possible_entry| {
            let possible_pdf = possible_entry.ok()?.into_path();
            if possible_pdf.extension()?.to_str()? == "pdf" {
                Some(possible_pdf.into_os_string())
            } else {
                None
            }
        })
        .filter_map(|pdf_path| match PDFContent::try_from(pdf_path) {
            Ok(pdf_content) => Some(pdf_content),
            Err((error, file_path)) => {
                if !CONFIG.read().unwrap().quiet {
                    println!("{:?}: {:?}", file_path, error);
                }
                None
            }
        })
        .for_each_with(tx_item, |tx_item, pdf_content| {
            let _ = tx_item.send(Arc::new(pdf_content));
        });

    let skim_options = SkimOptionsBuilder::default()
        .reverse(true)
        .exact(true)
        .preview_window(Some("down:80%"))
        .preview(Some(""))
        .build()
        .unwrap();

    match Skim::run_with(&skim_options, Some(rx_item)) {
        Some(sk_output) => {
            if sk_output.is_abort {
                std::process::exit(130)
            }

            Action::from_matches(&matches).execute(sk_output);
        }
        None => std::process::exit(1),
    }
}