Alan
3 years ago
commit
48661649d2
7 changed files with 2025 additions and 0 deletions
@ -0,0 +1,14 @@ |
|||||||
|
[package] |
||||||
|
name = "bib_manager" |
||||||
|
version = "0.1.0" |
||||||
|
authors = ["a"] |
||||||
|
edition = "2018" |
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
||||||
|
|
||||||
|
[dependencies] |
||||||
|
biblatex = "0.3.0" |
||||||
|
json = "*" |
||||||
|
jfs = "*" |
||||||
|
pubmed = "*" |
||||||
|
snafu = "*" |
@ -0,0 +1,49 @@ |
|||||||
|
use biblatex::Bibliography; |
||||||
|
// use json::*;
|
||||||
|
// use pubmed;
|
||||||
|
// use std::fs;
|
||||||
|
// use std::fs::File;
|
||||||
|
// use std::io::prelude::*;
|
||||||
|
use crate::bib_man::check_settings; |
||||||
|
// use crate::bib_man::find_doi;
|
||||||
|
use crate::bib_man::main_menu; |
||||||
|
use crate::bib_man::open_bib; |
||||||
|
use bib_manager::bib_man; |
||||||
|
use std::env; |
||||||
|
// use std::io::{self, Read};
|
||||||
|
use snafu::{ensure, Backtrace, ErrorCompat, ResultExt, Snafu}; |
||||||
|
|
||||||
|
use std::path::Path; |
||||||
|
|
||||||
|
fn main() { |
||||||
|
// check for settings, set path if needed, load bib from default path
|
||||||
|
// all happens automatically at startup, not sure how to make this better right now
|
||||||
|
// let empty_bib: biblatex::Bibliography;
|
||||||
|
let settings_json = check_settings().unwrap(); |
||||||
|
let path_string = Path::new(settings_json["default_path"].as_str().unwrap()); |
||||||
|
let bibliography = match open_bib(path_string) { |
||||||
|
Ok(bibliograph) => bibliograph, |
||||||
|
Err(e) => { |
||||||
|
eprintln!("uh oh, your bib file didn't load :S {}", e); |
||||||
|
// handle_err(&empty_bib);
|
||||||
|
if let Some(backtrace) = ErrorCompat::backtrace(&e) { |
||||||
|
println!("{}", backtrace); |
||||||
|
}; |
||||||
|
panic! |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
// starting of setting stuff up for custom settings struct, not totally sure if necessary?
|
||||||
|
// let settings: settings = settings::set_path(String::from(
|
||||||
|
// settings_json["default_path"].as_str().unwrap(),
|
||||||
|
// ));
|
||||||
|
|
||||||
|
// take command line args, only menu is implemented right now
|
||||||
|
let args: Vec<String> = env::args().collect(); |
||||||
|
println!("{:?}", args); |
||||||
|
if args.iter().any(|i| i == "menu") { |
||||||
|
main_menu(&bibliography); |
||||||
|
// } else if args.iter().any(|i| i == "find") {
|
||||||
|
// find_doi(&bibliography);
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,235 @@ |
|||||||
|
pub mod bib_man { |
||||||
|
|
||||||
|
use biblatex::Bibliography; |
||||||
|
use json::*; |
||||||
|
use pubmed; |
||||||
|
use std::fs::{self, File}; |
||||||
|
// use std::io::prelude::*;
|
||||||
|
// use std::env;
|
||||||
|
use std::fmt; |
||||||
|
use std::io::{self, Read}; |
||||||
|
use std::path::Path; |
||||||
|
use std::result; |
||||||
|
use std::option; |
||||||
|
use snafu::{ensure, Backtrace, ErrorCompat, ResultExt, Snafu}; |
||||||
|
// use bib_manager::bib_man;
|
||||||
|
|
||||||
|
pub struct Settings { |
||||||
|
default_path: String, |
||||||
|
} |
||||||
|
impl Settings { |
||||||
|
pub fn set_path(path: String) -> Settings { |
||||||
|
// basically new() function
|
||||||
|
Settings { default_path: path } |
||||||
|
} |
||||||
|
pub fn get_path(&self) -> &String { |
||||||
|
&self.default_path |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Debug, Snafu)] |
||||||
|
pub enum MyError { |
||||||
|
// error types and what they take go here
|
||||||
|
// functions will return Result<(thing), MyError>
|
||||||
|
// returns will need .map_err(|_| MyError::<error type>(format!("\"{}\" <error message here>", <variable to format into string for more error info>)))
|
||||||
|
// InvalidDigit(String),
|
||||||
|
#[snafu(display("BibError"))] |
||||||
|
#[non_exhaustive] |
||||||
|
BibError, |
||||||
|
#[snafu(display("IoError"))] |
||||||
|
#[non_exhaustive] |
||||||
|
IoError { |
||||||
|
source: std::io::Error, |
||||||
|
}, |
||||||
|
#[snafu(display("Other"))] |
||||||
|
#[non_exhaustive] |
||||||
|
Other, |
||||||
|
} |
||||||
|
|
||||||
|
// impl fmt::Display for MyError {
|
||||||
|
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
// match self {
|
||||||
|
// // MyError::InvalidDigit(description) => write!(f, "{}", description),
|
||||||
|
// MyError::BibError => Ok(handle_err()),
|
||||||
|
// MyError::IoError => Ok(handle_err()),
|
||||||
|
// MyError::Other => write!(f, "Unexpected error"),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl std::error::Error for MyError {}
|
||||||
|
|
||||||
|
// impl From<io::Error> for MyError {
|
||||||
|
// fn from(_: io::Error) -> Self {
|
||||||
|
// MyError::IoError
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// impl From<option::NoneError> for MyError {
|
||||||
|
// fn from(_: option::NoneError) -> Self {
|
||||||
|
// MyError::BibError
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
fn handle_err(bibliography: &Bibliography) { |
||||||
|
// gives a menu for errors I guess? haven't figured out a way to use it yet
|
||||||
|
println!("whoops, something went wrong:"); |
||||||
|
println!("1: return to main"); |
||||||
|
println!("2: quit"); |
||||||
|
let input = string_to_u32(get_input()); |
||||||
|
match &input { |
||||||
|
1 => main_menu(&bibliography), |
||||||
|
_ => panic!(), |
||||||
|
} |
||||||
|
} |
||||||
|
fn find_doi(bibliography: &Bibliography) -> result::Result<&biblatex::Entry, MyError> { |
||||||
|
let input = get_input(); |
||||||
|
let bib1 = bibliography.get(&input).ok_or(MyError::BibError)?; |
||||||
|
// bib1 = bibliography.get(&input).ok_or(MyError::BibError)?.clone();
|
||||||
|
// match bibliography.get(&input) {
|
||||||
|
// None => Err("nope"),
|
||||||
|
// Some(&bib) => Ok(&bib),
|
||||||
|
// Some(_) => Err("MyError"),
|
||||||
|
// };
|
||||||
|
Ok(&bib1) |
||||||
|
} |
||||||
|
|
||||||
|
fn pub_med() { |
||||||
|
let client = pubmed::Client::new(); |
||||||
|
let mut query = get_input(); |
||||||
|
query.pop(); |
||||||
|
let vector = client.article_ids_from_query(&query, 4).unwrap(); |
||||||
|
println!("{:#?}", client.articles(&vector).unwrap()); |
||||||
|
println!("enter the id:"); |
||||||
|
let id = string_to_u64(get_input()); |
||||||
|
println!("{:#?}", client.article(id).unwrap()); |
||||||
|
} |
||||||
|
fn cite_entry(parent_bib: &biblatex::Entry) -> io::Result<()> { |
||||||
|
// get existing bib entry, create child citation from entry using page numbers
|
||||||
|
let parent_key = &parent_bib.cite_key; |
||||||
|
println!("enter pages"); |
||||||
|
let pages = get_input(); |
||||||
|
let mut child_key = String::from("in_"); |
||||||
|
child_key.push_str(&parent_key); |
||||||
|
child_key.push_str("_"); |
||||||
|
child_key.push_str(&pages); |
||||||
|
let entry_type = biblatex::bibmechanics::EntryType::InBook; |
||||||
|
let mut child_bib = biblatex::Entry::new(&child_key, entry_type); |
||||||
|
// child_bib.set_pages
|
||||||
|
let test = core::ops::Range::<u32> { start: 3, end: 5 }; |
||||||
|
println!("{:#?}", test); |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
pub fn main_menu(bibliography: &Bibliography) { |
||||||
|
loop { |
||||||
|
println!("Select menu item:"); |
||||||
|
println!("1: pub med"); |
||||||
|
println!("2: get bib entry"); |
||||||
|
println!("3: cite entry"); |
||||||
|
println!("4: print first bib"); |
||||||
|
println!("5: find_doi"); |
||||||
|
let input = string_to_u32(get_input()); |
||||||
|
match &input { |
||||||
|
1 => pub_med(), |
||||||
|
2 => println!("{:#?}", get_bib(&bibliography)), |
||||||
|
3 => cite_entry(get_bib(&bibliography).unwrap()).unwrap(), |
||||||
|
4 => fn1(&bibliography).unwrap(), |
||||||
|
5 => match find_doi(&bibliography) { |
||||||
|
Ok(bib) => println!("{:#?}", &bib), |
||||||
|
Err(e) => { |
||||||
|
eprintln!("oh no: {}", e); |
||||||
|
handle_err(&bibliography); |
||||||
|
if let Some(backtrace) = ErrorCompat::backtrace(&e) { |
||||||
|
println!("{}", backtrace); |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
_ => break, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
pub fn check_settings() -> io::Result<JsonValue> { |
||||||
|
// checks for settings file, calls function to create one if there isn't one
|
||||||
|
let settings_json; |
||||||
|
if fs::metadata("settings.json").is_ok() { |
||||||
|
settings_json = read_settings().unwrap(); |
||||||
|
} else { |
||||||
|
set_default_path(); |
||||||
|
settings_json = read_settings().unwrap(); |
||||||
|
} |
||||||
|
Ok(settings_json) |
||||||
|
} |
||||||
|
fn read_settings() -> io::Result<JsonValue> { |
||||||
|
// reads settings.json file and passes result out as a JsonValue
|
||||||
|
let json_path = Path::new("settings.json"); |
||||||
|
let mut settings_string = String::new(); |
||||||
|
match File::open(&json_path) { |
||||||
|
Ok(mut file) => file.read_to_string(&mut settings_string).unwrap(), |
||||||
|
Err(why) => panic!("couldn't open: {}", why), |
||||||
|
}; |
||||||
|
let settings_json = json::parse(&settings_string[..]).unwrap(); |
||||||
|
Ok(settings_json) |
||||||
|
} |
||||||
|
fn set_default_path() -> io::Result<()> { |
||||||
|
// sets default path on first run when no settings.json is detected
|
||||||
|
println!("Please enter path:"); |
||||||
|
let new_path = get_input(); |
||||||
|
let mut file = File::create("settings.json")?; |
||||||
|
let settings = object! { |
||||||
|
"default_path" => &new_path[..] |
||||||
|
}; |
||||||
|
JsonValue::write_pretty(&settings, &mut file, 4)?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
fn fn1(bibliography: &Bibliography) -> io::Result<()> { |
||||||
|
for element in bibliography.iter() { |
||||||
|
println!("{:#?}", element); |
||||||
|
break; |
||||||
|
} |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
pub fn open_bib(path: &Path) -> io::Result<Bibliography> { |
||||||
|
// loads bibliography into memory
|
||||||
|
// need to update open_file to path
|
||||||
|
let mut contents = open_file(path)?; |
||||||
|
let bibliography = Bibliography::from_str(&mut contents, true); |
||||||
|
println!("😻bibliography loaded😻"); |
||||||
|
Ok(bibliography) |
||||||
|
} |
||||||
|
fn get_bib(bibliography: &Bibliography) -> io::Result<&biblatex::Entry> { |
||||||
|
// grab a single bib entry and return it
|
||||||
|
println!("enter id:"); |
||||||
|
let id: String = get_input(); |
||||||
|
let bib: &biblatex::Entry = bibliography.get(&id[..]).unwrap(); |
||||||
|
Ok(bib) |
||||||
|
} |
||||||
|
fn open_file(path: &Path) -> io::Result<String> { |
||||||
|
// this needs to get updated to path from string
|
||||||
|
// let path = String::from(path.to_str().unwrap());
|
||||||
|
let mut file = File::open(path)?; |
||||||
|
let mut contents = String::new(); |
||||||
|
file.read_to_string(&mut contents); |
||||||
|
Ok(contents) |
||||||
|
} |
||||||
|
fn get_input() -> String { |
||||||
|
// grabs user input from command line and throws it in a String
|
||||||
|
let mut input = String::new(); |
||||||
|
let mut _stdin = io::stdin().read_line(&mut input).expect("uh-oh"); |
||||||
|
input.pop(); |
||||||
|
input |
||||||
|
} |
||||||
|
fn string_to_u32(input: String) -> u32 { |
||||||
|
// takes string (such as user input) and spits out the same but in u32 form
|
||||||
|
let input: u32 = match input.trim().parse() { |
||||||
|
Ok(num) => num, |
||||||
|
Err(_) => panic!(), |
||||||
|
}; |
||||||
|
input |
||||||
|
} |
||||||
|
fn string_to_u64(input: String) -> u64 { |
||||||
|
// takes string (such as user input) and spits out the same but in u64 form
|
||||||
|
let input: u64 = match input.trim().parse() { |
||||||
|
Ok(num) => num, |
||||||
|
Err(_) => panic!(), |
||||||
|
}; |
||||||
|
input |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue