Alan
3 years ago
commit
48661649d2
7 changed files with 2025 additions and 0 deletions
@ -0,0 +1,14 @@
@@ -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,3 @@
@@ -0,0 +1,3 @@
|
||||
{ |
||||
"default_path": "<path>/<to>/<bib_file>.bib" |
||||
} |
@ -0,0 +1,49 @@
@@ -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 @@
@@ -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