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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use crate::notebook::Notebook;

use entry::Entry;
use serde::{Deserialize, Serialize};
use std::{env, fmt, fs, io, io::prelude::*, process::Command};

pub mod argparse;
pub mod config;
pub mod entry;
pub mod notebook;

#[derive(Clone, Debug)]
pub enum Args {
    New(Entry),
    List(usize, u8),
    Read(usize),
    Edit(usize),
    Delete(usize, bool),
    Search(String),
    DateFilter(String),
    DateSearch(String),
    Unimplemented(),
}

#[derive(Clone, Debug)]
struct Sentiment {
    compound: f64,
    icon: String,
}

impl Sentiment {
    fn new(compound: f64) -> Sentiment {
        let icon = match compound {
            c if c <= -0.7 => "😿",
            c if c <= -0.2 => "😾",
            c if c <= 0.2 => "🐱",
            c if c <= 0.7 => "😺",
            c if c <= 1.0 => "😸",
            _ => "Problemo",
        };

        Sentiment {
            compound,
            icon: icon.to_owned(),
        }
    }
}

impl fmt::Display for Sentiment {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:.3} ≅ {}", self.compound, self.icon)
    }
}

#[derive(Clone, Debug, Serialize, Deserialize)]
struct EncryptionScheme {
    cipher: bool,
    hash: bool,
    salt: bool,
}

fn get_user_confirm<R>(mut reader: R, prompt: String) -> bool
where
    R: io::BufRead,
{
    print!("{prompt} (Y/n) ");
    let _ = io::stdout().flush();
    let mut buffer = String::new();

    reader.read_line(&mut buffer).expect("Error reading input.");

    buffer.starts_with('Y')
}

pub fn create_temp_file(filename: Option<&str>) -> String {
    let mut file_path = env::temp_dir();
    file_path.push(filename.unwrap_or("notebook_rs"));
    fs::File::create(&file_path).expect("Could not create file.");
    file_path.into_os_string().into_string().unwrap()
}

pub fn text_from_editor(path: Option<String>) -> Option<String> {
    let editor = env::var("EDITOR").expect("EDITOR environment variable is missing.");
    let file_path = path.unwrap_or_else(|| create_temp_file(None));

    Command::new(editor)
        .arg(&file_path)
        .status()
        .expect("Something went wrong with the editor.");

    let mut text = String::new();
    fs::File::open(&file_path)
        .expect("Couldn't open temp file.")
        .read_to_string(&mut text)
        .expect("Couldn't load file to string.");

    fs::remove_file(file_path).expect("Couldn't remove temp file.");

    if text.is_empty() {
        None
    } else {
        Some(text)
    }
}

#[cfg(test)]
mod test_util {
    use super::*;

    #[test]
    fn test_missing_editor_variable() {
        env::remove_var("EDITOR");
        let result = std::panic::catch_unwind(|| text_from_editor(None));
        assert!(result.is_err());
    }

    #[test]
    fn test_user_confirm_pos() {
        let pos = b"Y";
        assert!(get_user_confirm(&pos[..], "Prompt".to_string()))
    }

    #[test]
    fn test_user_confirm_neg() {
        let pos = b"n";
        assert_eq!(get_user_confirm(&pos[..], "Prompt".to_string()), false)
    }
}