Browse Source

initial commit

master
Alan 3 years ago
commit
48661649d2
  1. 1
      .gitignore
  2. 1723
      Cargo.lock
  3. 14
      Cargo.toml
  4. 0
      README.md
  5. 3
      settings.json
  6. 49
      src/bin/main.rs
  7. 235
      src/lib.rs

1
.gitignore vendored

@ -0,0 +1 @@
/target

1723
Cargo.lock generated

File diff suppressed because it is too large Load Diff

14
Cargo.toml

@ -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 = "*"

3
settings.json

@ -0,0 +1,3 @@
{
"default_path": "<path>/<to>/<bib_file>.bib"
}

49
src/bin/main.rs

@ -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);
}
}

235
src/lib.rs

@ -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…
Cancel
Save