path handling and unwraps
This commit is contained in:
parent
1c51c53eef
commit
e0c81885c8
|
|
@ -13,3 +13,4 @@ figment = { version = "0.10.10", features = ["env", "serde_json", "json"] }
|
||||||
regex = "1.8.4"
|
regex = "1.8.4"
|
||||||
serde = { version = "1.0.164", features = ["serde_derive"] }
|
serde = { version = "1.0.164", features = ["serde_derive"] }
|
||||||
serde_json = "1.0.97"
|
serde_json = "1.0.97"
|
||||||
|
resolve-path = "0.1.0"
|
||||||
|
|
|
||||||
|
|
@ -11,17 +11,17 @@ use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub editor: Option<String>,
|
pub editor: String,
|
||||||
pub sections: Option<Vec<String>>,
|
pub sections: Vec<String>,
|
||||||
pub notes_dir: Option<String>,
|
pub notes_dir: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Config {
|
Config {
|
||||||
editor: Some("nano".into()),
|
editor: "nano".into(),
|
||||||
sections: Some(vec!["Daily".into(), "Weekly".into(), "Monthly".into()]),
|
sections: vec!["Daily".into(), "Weekly".into(), "Monthly".into()],
|
||||||
notes_dir: Some("Notes".into()),
|
notes_dir: "./Notes".into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -44,17 +44,17 @@ impl Config {
|
||||||
|
|
||||||
pub fn write_default(cfg_file: &str) -> Result<(), ConfigError> {
|
pub fn write_default(cfg_file: &str) -> Result<(), ConfigError> {
|
||||||
let buf = serde_json::to_string_pretty(&Self::default()).or_else(|_| {
|
let buf = serde_json::to_string_pretty(&Self::default()).or_else(|_| {
|
||||||
return Err(ConfigError::ParseError(
|
Err(ConfigError::ParseError(
|
||||||
"could not serialize default config",
|
"could not serialize default config",
|
||||||
));
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mut f = File::create(cfg_file)
|
let mut f = File::create(cfg_file)
|
||||||
.or_else(|_| Err(ConfigError::IOError("Could not open config file")))?;
|
.or_else(|_| Err(ConfigError::IOError("Could not open config file")))?;
|
||||||
f.write_all(&buf.as_bytes()).or_else(|_| {
|
f.write_all(&buf.as_bytes()).or_else(|_| {
|
||||||
return Err(ConfigError::IOError(
|
Err(ConfigError::IOError(
|
||||||
"could not write default config to file",
|
"could not write default config to file",
|
||||||
));
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
91
src/main.rs
91
src/main.rs
|
|
@ -5,7 +5,7 @@ mod todo;
|
||||||
use crate::cli::Args;
|
use crate::cli::Args;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
use crate::config::{Config, ConfigError};
|
use crate::config::Config;
|
||||||
use crate::todo::File as TodoFile;
|
use crate::todo::File as TodoFile;
|
||||||
use crate::todo::{Status as TaskStatus, TaskGroup};
|
use crate::todo::{Status as TaskStatus, TaskGroup};
|
||||||
use chrono::naive::NaiveDate;
|
use chrono::naive::NaiveDate;
|
||||||
|
|
@ -13,32 +13,22 @@ use chrono::{Datelike, Local};
|
||||||
use comrak::nodes::{AstNode, NodeValue};
|
use comrak::nodes::{AstNode, NodeValue};
|
||||||
use comrak::{parse_document, Arena};
|
use comrak::{parse_document, Arena};
|
||||||
use comrak::{ComrakExtensionOptions, ComrakOptions, ComrakParseOptions};
|
use comrak::{ComrakExtensionOptions, ComrakOptions, ComrakParseOptions};
|
||||||
|
use resolve_path::PathResolveExt;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::{create_dir_all, metadata, read, read_dir, File};
|
use std::fs::{create_dir_all, metadata, read, read_dir, File};
|
||||||
use std::io::{self, Write};
|
use std::io::Write;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::{env, str};
|
use std::str;
|
||||||
|
|
||||||
//TODO handle unwraps and errors more uniformly
|
|
||||||
//TODO refactor creating new file
|
//TODO refactor creating new file
|
||||||
//TODO clean up verbose printing
|
|
||||||
//TODO create custom errors for better error handling
|
|
||||||
//TODO Default path for note_dir should start with curent path not home
|
|
||||||
|
|
||||||
// Nested errors look bad, code smell?
|
fn main() {
|
||||||
#[derive(Debug)]
|
|
||||||
enum ExitError {
|
|
||||||
ConfigError(ConfigError),
|
|
||||||
IOError(String, io::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<(), ExitError> {
|
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
let expected_cfg_files = match Config::expected_locations() {
|
let expected_cfg_files = match Config::expected_locations() {
|
||||||
Err(e) => return Err(ExitError::ConfigError(e)),
|
|
||||||
Ok(cfg_files) => cfg_files,
|
Ok(cfg_files) => cfg_files,
|
||||||
|
Err(e) => panic!("{:?}", e),
|
||||||
};
|
};
|
||||||
|
|
||||||
let cfg_files: Vec<&Path> = expected_cfg_files
|
let cfg_files: Vec<&Path> = expected_cfg_files
|
||||||
|
|
@ -48,9 +38,11 @@ fn main() -> Result<(), ExitError> {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if cfg_files.len() <= 0 {
|
if cfg_files.len() <= 0 {
|
||||||
match Config::write_default(expected_cfg_files[0].to_str()?) {
|
if let Err(e) = Config::write_default(match expected_cfg_files[0].to_str() {
|
||||||
Err(e) => return Err(ExitError::ConfigError(e)),
|
Some(s) => s,
|
||||||
_ => (),
|
None => panic!("Could not resolve expected cfg file paths"),
|
||||||
|
}) {
|
||||||
|
panic!("Could not write config: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,45 +56,29 @@ fn main() -> Result<(), ExitError> {
|
||||||
|
|
||||||
if args.current_config {
|
if args.current_config {
|
||||||
println!("{}", &cfg_file);
|
println!("{}", &cfg_file);
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cfg = Config::load(&cfg_file).unwrap();
|
let cfg = match Config::load(&cfg_file) {
|
||||||
|
Ok(cfg) => cfg,
|
||||||
println!("{:#?}", cfg);
|
Err(_e) => panic!("could not load config: {}", cfg_file),
|
||||||
let data_dir = match &cfg.notes_dir {
|
|
||||||
Some(dir) => get_data_dir(dir),
|
|
||||||
_ => {
|
|
||||||
return Err(ExitError::ConfigError(ConfigError::IOError(
|
|
||||||
"Could not get notes dir from config",
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let data_dir = cfg.notes_dir.resolve().to_path_buf();
|
||||||
|
|
||||||
if !metadata(&data_dir).is_ok() {
|
if !metadata(&data_dir).is_ok() {
|
||||||
match create_dir_all(&data_dir) {
|
match create_dir_all(&data_dir) {
|
||||||
Err(e) => {
|
Err(_e) => panic!("Could not create defult directory: {:?}", &data_dir),
|
||||||
return Err(ExitError::IOError(
|
|
||||||
format!(
|
|
||||||
"Could not create defult directory: {}",
|
|
||||||
&data_dir.to_str().unwrap(),
|
|
||||||
),
|
|
||||||
e,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
println!("dir = {}", data_dir.to_str().unwrap());
|
|
||||||
|
|
||||||
let latest_file = get_latest_file(&data_dir);
|
let latest_file = get_latest_file(&data_dir);
|
||||||
println!("Latest file: {:?}", latest_file);
|
|
||||||
|
|
||||||
let now = Local::now();
|
let now = Local::now();
|
||||||
let today = NaiveDate::from_ymd_opt(now.year(), now.month(), now.day()).unwrap();
|
let today = NaiveDate::from_ymd_opt(now.year(), now.month(), now.day()).unwrap();
|
||||||
let current_file = match latest_file {
|
let current_file = match latest_file {
|
||||||
Ok(todo_file) if todo_file.date < today => {
|
Ok(todo_file) if todo_file.date < today => {
|
||||||
println!("Today's file does not exist, creating");
|
|
||||||
let arena = Arena::new();
|
let arena = Arena::new();
|
||||||
let root = {
|
let root = {
|
||||||
let contents = load_file(&todo_file);
|
let contents = load_file(&todo_file);
|
||||||
|
|
@ -110,12 +86,9 @@ fn main() -> Result<(), ExitError> {
|
||||||
root
|
root
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("{:#?}", root);
|
let sections = &cfg.sections;
|
||||||
println!("=======================================================");
|
|
||||||
|
|
||||||
let sections = &cfg.sections.unwrap();
|
|
||||||
let groups = extract_secitons(root, sections);
|
let groups = extract_secitons(root, sections);
|
||||||
println!("{:#?}", groups);
|
|
||||||
|
|
||||||
let level = groups.values().map(|group| group.level).min().unwrap_or(2);
|
let level = groups.values().map(|group| group.level).min().unwrap_or(2);
|
||||||
|
|
||||||
|
|
@ -133,8 +106,7 @@ fn main() -> Result<(), ExitError> {
|
||||||
file_path
|
file_path
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
println!("No files in dir: {:}", cfg.notes_dir.unwrap());
|
let sections = &cfg.sections;
|
||||||
let sections = &cfg.sections.unwrap();
|
|
||||||
let data = sections
|
let data = sections
|
||||||
.iter()
|
.iter()
|
||||||
.map(|sec| TaskGroup::empty(sec.clone(), 2))
|
.map(|sec| TaskGroup::empty(sec.clone(), 2))
|
||||||
|
|
@ -144,18 +116,13 @@ fn main() -> Result<(), ExitError> {
|
||||||
write_file(&file_path, &content);
|
write_file(&file_path, &content);
|
||||||
file_path
|
file_path
|
||||||
}
|
}
|
||||||
Ok(todo_file) => {
|
Ok(todo_file) => todo_file.file.path(),
|
||||||
println!("Today's file was created");
|
|
||||||
todo_file.file.path()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Command::new(cfg.editor.expect("Could not resolve editor from config"))
|
Command::new(cfg.editor)
|
||||||
.args([current_file])
|
.args([current_file])
|
||||||
.status()
|
.status()
|
||||||
.expect(format!("failed to launch editor {}", "vim").as_str());
|
.expect(format!("failed to launch editor {}", "vim").as_str());
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_filepath(data_dir: &PathBuf, date: &NaiveDate) -> PathBuf {
|
fn get_filepath(data_dir: &PathBuf, date: &NaiveDate) -> PathBuf {
|
||||||
|
|
@ -239,7 +206,6 @@ fn extract_secitons<'a>(
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("Attempting to parse {}", title);
|
|
||||||
if sections.iter().any(|section| section.eq(title)) {
|
if sections.iter().any(|section| section.eq(title)) {
|
||||||
if let Ok(mut group) = TaskGroup::try_from(node) {
|
if let Ok(mut group) = TaskGroup::try_from(node) {
|
||||||
group.tasks = group
|
group.tasks = group
|
||||||
|
|
@ -255,19 +221,6 @@ fn extract_secitons<'a>(
|
||||||
groups
|
groups
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_data_dir(dir_name: &str) -> PathBuf {
|
|
||||||
let mut dir = match env::var("HOME") {
|
|
||||||
Ok(home) => {
|
|
||||||
let mut x = PathBuf::new();
|
|
||||||
x.push(home);
|
|
||||||
x
|
|
||||||
}
|
|
||||||
_ => env::current_dir().expect("PWD environment variable not set"),
|
|
||||||
};
|
|
||||||
dir = dir.join(dir_name);
|
|
||||||
dir
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_latest_file(dir: &Path) -> Result<TodoFile, String> {
|
fn get_latest_file(dir: &Path) -> Result<TodoFile, String> {
|
||||||
let dir = read_dir(dir).expect(format!("Could not find notes folder: {:?}", dir).as_str());
|
let dir = read_dir(dir).expect(format!("Could not find notes folder: {:?}", dir).as_str());
|
||||||
dir.filter_map(|f| f.ok())
|
dir.filter_map(|f| f.ok())
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue