structure of project, arguments, patches
This commit is contained in:
parent
cff0563bf7
commit
90948a1c83
59
src/rnote/app.rs
Normal file
59
src/rnote/app.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
pub use clap::{App, AppSettings, Arg, SubCommand};
|
||||||
|
|
||||||
|
pub fn make_app() -> App<'static, 'static> {
|
||||||
|
App::new("rnote")
|
||||||
|
.version("0.0.0")
|
||||||
|
.author("Volodymyr Patuta <vpatuta AT protonmail DOT com>")
|
||||||
|
.about("Minimal note talking cli tool.")
|
||||||
|
.setting(AppSettings::ArgRequiredElseHelp)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("new")
|
||||||
|
.alias("n")
|
||||||
|
.about("Create new note")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("category")
|
||||||
|
.help("Create note in category.")
|
||||||
|
.short("c")
|
||||||
|
.long("category"),
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("header").help("Give name to the file.")),
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("remove")
|
||||||
|
.alias("r")
|
||||||
|
.about("Remove a note.")
|
||||||
|
.arg(Arg::with_name("header").help("Name of the note.")),
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("edit")
|
||||||
|
.alias("e")
|
||||||
|
.about("Edit a note.")
|
||||||
|
.arg(Arg::with_name("header").help("Name of the note.")),
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("list")
|
||||||
|
.alias("l")
|
||||||
|
.alias("ls")
|
||||||
|
.alias("show")
|
||||||
|
.about("Show all notes or one note")
|
||||||
|
.arg(Arg::with_name("header").help("Name of the note."))
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("category")
|
||||||
|
.help("List all notes from a category.")
|
||||||
|
.short("c")
|
||||||
|
.long("category"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("search")
|
||||||
|
.alias("s")
|
||||||
|
.about("Search a note.")
|
||||||
|
.arg(Arg::with_name("header").help("Name of the note."))
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("word")
|
||||||
|
.help("Search by word.")
|
||||||
|
.short("w")
|
||||||
|
.long("word"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
3
src/rnote/mod.rs
Normal file
3
src/rnote/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod app;
|
||||||
|
mod notes;
|
||||||
|
pub mod process;
|
127
src/rnote/notes.rs
Normal file
127
src/rnote/notes.rs
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use chrono::Utc;
|
||||||
|
use std::{env, fs, process::Command};
|
||||||
|
use text_io::read;
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
/// Get the path to the root directory of all notes.
|
||||||
|
fn get_base_path() -> Result<String> {
|
||||||
|
let home = env::var("HOME")?;
|
||||||
|
Ok(format!("{}/.rnote/", home))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get path to a category/date directory.
|
||||||
|
fn get_path(category: &str) -> Result<String> {
|
||||||
|
let base = get_base_path()?;
|
||||||
|
let date = Utc::now().format("%Y-%m-%d");
|
||||||
|
match category.is_empty() {
|
||||||
|
true => Ok(format!("{}{}/", base, date)),
|
||||||
|
false => Ok(format!("{}{}/", base, category)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create directory for a note.
|
||||||
|
pub fn create_dir(category: &str) -> Result<()> {
|
||||||
|
let path = get_base_path()?;
|
||||||
|
let date = Utc::now().format("%Y-%m-%d");
|
||||||
|
match category.is_empty() {
|
||||||
|
true => fs::create_dir_all(format!("{}{}", path, date))?,
|
||||||
|
false => fs::create_dir_all(format!("{}{}", path, category))?,
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new note.
|
||||||
|
pub fn create(header: &str, category: &str) -> Result<()> {
|
||||||
|
let editor = env::var("EDITOR").unwrap_or("/bin/vi".to_owned());
|
||||||
|
let file = format!("{}{}.md", get_path(category)?, header);
|
||||||
|
create_dir(category)?;
|
||||||
|
is_duplicate(header, category)?;
|
||||||
|
Command::new(editor).arg(&file).status()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if potentially new note name already exists.
|
||||||
|
fn is_duplicate(header: &str, category: &str) -> Result<()> {
|
||||||
|
let file = format!("{}{}.md", get_path(category)?, header);
|
||||||
|
let path = format!("{}", get_path(category)?);
|
||||||
|
for entry in WalkDir::new(path) {
|
||||||
|
let entry = entry?;
|
||||||
|
let p: &str = match entry.path().to_str() {
|
||||||
|
Some(s) => s,
|
||||||
|
None => "",
|
||||||
|
};
|
||||||
|
if p == file {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"Duplicate in the same category/date. Choose another name."
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finds a path to desired note.
|
||||||
|
fn find_path(header: &str) -> Result<String> {
|
||||||
|
let mut paths: Vec<String> = Vec::new();
|
||||||
|
let base = get_base_path()?;
|
||||||
|
let header = format!("{}.md", header);
|
||||||
|
for entry in WalkDir::new(base) {
|
||||||
|
let entry = entry?;
|
||||||
|
let p: &str = match entry.path().to_str() {
|
||||||
|
Some(s) => s,
|
||||||
|
None => "",
|
||||||
|
};
|
||||||
|
let name: &str = match entry.file_name().to_str() {
|
||||||
|
Some(s) => s,
|
||||||
|
None => "",
|
||||||
|
};
|
||||||
|
if name == header {
|
||||||
|
paths.push(String::from(p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if paths.is_empty() {
|
||||||
|
Err(anyhow!("Note not found."))
|
||||||
|
} else {
|
||||||
|
if paths.len() == 1 {
|
||||||
|
Ok(format!("{}.md", paths[0]))
|
||||||
|
} else {
|
||||||
|
let mut n: usize;
|
||||||
|
loop {
|
||||||
|
let mut i = 1;
|
||||||
|
println!("Choose one: \n");
|
||||||
|
for path in &paths {
|
||||||
|
println!("{}\t {}", i, path);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
n = read!();
|
||||||
|
if n >= 1 && n <= paths.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(format!("{}.md", paths[n]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes a note.
|
||||||
|
pub fn remove(header: &str) -> Result<()> {
|
||||||
|
let path = find_path(header)?;
|
||||||
|
println!("Are you sure you want to delete {} [Y/n]", header);
|
||||||
|
let response: String = read!();
|
||||||
|
if response == "y" || response == "Y" || response == "yes" || response == "Yes" {
|
||||||
|
println!("Deleting...");
|
||||||
|
fs::remove_file(path)?;
|
||||||
|
println!("Successfully deleted.");
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(anyhow!("Abort."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Modify a note.
|
||||||
|
pub fn modify(header: &str) -> Result<()> {
|
||||||
|
let editor = env::var("EDITOR").unwrap_or("/bin/vi".to_owned());
|
||||||
|
let file = find_path(header)?;
|
||||||
|
Command::new(editor).arg(&file).status()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
50
src/rnote/process.rs
Normal file
50
src/rnote/process.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
use crate::rnote::notes;
|
||||||
|
use anyhow::Result;
|
||||||
|
use clap::ArgMatches;
|
||||||
|
use notes::modify;
|
||||||
|
use text_io::read;
|
||||||
|
|
||||||
|
pub fn new(matches: &ArgMatches) -> Result<()> {
|
||||||
|
let header = match matches.value_of("header") {
|
||||||
|
Some(s) => s.to_owned(),
|
||||||
|
None => {
|
||||||
|
print!("Enter the name of your note: ");
|
||||||
|
read!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let category = matches.value_of("category").unwrap_or("");
|
||||||
|
|
||||||
|
notes::create(&header, category)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn remove(matches: &ArgMatches) -> Result<()> {
|
||||||
|
let header = match matches.value_of("header") {
|
||||||
|
Some(s) => s.to_owned(),
|
||||||
|
None => {
|
||||||
|
print!("Enter the name of your note: ");
|
||||||
|
read!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
notes::remove(&header)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn edit(matches: &ArgMatches) -> Result<()> {
|
||||||
|
let header = match matches.value_of("header") {
|
||||||
|
Some(s) => s.to_owned(),
|
||||||
|
None => {
|
||||||
|
print!("Enter the name of your note: ");
|
||||||
|
read!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
notes::modify(&header)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn list(matches: &ArgMatches) -> Result<()> {
|
||||||
|
unimplemented!("list all notes, one note or category");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn search(matches: &ArgMatches) -> Result<()> {
|
||||||
|
unimplemented!("Search a note by header or by word.");
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user