refactor!: links command and cli logic
This commit is contained in:
27
src/links.rs
27
src/links.rs
@@ -1,9 +1,12 @@
|
||||
use std::borrow::{Borrow, BorrowMut};
|
||||
use std::{cell::RefCell, collections::HashMap};
|
||||
use std::{fs, io, path::PathBuf};
|
||||
|
||||
use comrak::nodes::{Ast, NodeLink, NodeValue};
|
||||
use comrak::{arena_tree::Node, Arena};
|
||||
|
||||
use crate::utils;
|
||||
|
||||
pub struct ParseOptions {
|
||||
pub alias_prop: Option<String>,
|
||||
pub path_root: PathBuf,
|
||||
@@ -23,6 +26,30 @@ impl Default for ParseOptions {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iterate_links<'a, F>(ast: &'a Node<'a, RefCell<Ast>>, iterator: F)
|
||||
where
|
||||
F: Fn(&mut NodeLink),
|
||||
{
|
||||
let _ = utils::iter_nodes(ast, &|node| {
|
||||
if let NodeValue::Link(ref mut l) = &mut node.data.borrow_mut().value {
|
||||
iterator(l);
|
||||
};
|
||||
Ok::<(), ()>(())
|
||||
});
|
||||
}
|
||||
|
||||
pub fn get_links<'a>(ast: &'a Node<'a, RefCell<Ast>>) -> Vec<String> {
|
||||
let links: RefCell<Vec<String>> = RefCell::new(vec![]);
|
||||
let _ = utils::iter_nodes(ast, &|node| {
|
||||
if let NodeValue::Link(l) = &node.data.borrow().value {
|
||||
links.borrow_mut().push(l.url.clone());
|
||||
}
|
||||
Ok::<(), ()>(())
|
||||
});
|
||||
let r = links.borrow().to_vec();
|
||||
r
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ParsingError {
|
||||
AliasNotFound { file: String },
|
||||
|
||||
307
src/main.rs
307
src/main.rs
@@ -2,14 +2,11 @@ use core::panic;
|
||||
use std::io::Write;
|
||||
|
||||
use clap::{ArgAction, Parser, Subcommand};
|
||||
use clio::*;
|
||||
use comrak::nodes::NodeValue;
|
||||
use clio::{Input, Output};
|
||||
|
||||
use mdparser::{
|
||||
convert,
|
||||
frontmatter::{self, Frontmatter},
|
||||
links, utils,
|
||||
};
|
||||
use mdparser::convert;
|
||||
use mdparser::links;
|
||||
use mdparser::utils;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version = "0.1", about = "", long_about = None, propagate_version = true)]
|
||||
@@ -17,10 +14,13 @@ struct Cli {
|
||||
#[command(subcommand)]
|
||||
command: Commands,
|
||||
|
||||
#[arg(short, long, default_value = "-")]
|
||||
#[arg(long, global = true, default_value = "lines")]
|
||||
list_format: cli::ListFormat,
|
||||
|
||||
#[arg(short, long, global = true, default_value = "-")]
|
||||
input: Input,
|
||||
|
||||
#[arg(short, long, default_value = "-")]
|
||||
#[arg(short, long, global = true, default_value = "-")]
|
||||
output: Output,
|
||||
|
||||
#[arg(long)]
|
||||
@@ -30,20 +30,14 @@ struct Cli {
|
||||
#[derive(Debug, Subcommand)]
|
||||
enum Commands {
|
||||
Links {
|
||||
#[arg(short, long)]
|
||||
path_root: clio::ClioPath,
|
||||
#[arg(short, long, action = ArgAction::SetTrue)]
|
||||
list: bool,
|
||||
|
||||
#[arg(short, long, default_value = "x_alias_url")]
|
||||
alias_prop: String,
|
||||
#[arg(short, long, num_args = 2, value_names = ["FROM", "TO"])]
|
||||
replace_url: Vec<String>,
|
||||
|
||||
#[arg(long)]
|
||||
to_absolute_paths: bool,
|
||||
|
||||
#[arg(long)]
|
||||
not_remove_unalised: bool,
|
||||
|
||||
#[arg(long)]
|
||||
not_remove_unfound: bool,
|
||||
#[arg(long, default_value = ".")]
|
||||
root: clio::ClioPath,
|
||||
},
|
||||
Frontmatter {
|
||||
#[command(subcommand)]
|
||||
@@ -86,95 +80,196 @@ fn main() {
|
||||
let arena = comrak::Arena::new();
|
||||
let ast = comrak::parse_document(&arena, &file, &mdparser::utils::default_options());
|
||||
|
||||
// println!("{ast:#?}");
|
||||
|
||||
if let Commands::Convert { format } = &cli.command {
|
||||
let r = match format {
|
||||
convert::Formats::TumblrNPF => convert::to_tumblr_npf(&ast),
|
||||
};
|
||||
// println!("{}", serde_json::to_string_pretty(&r.unwrap()).unwrap());
|
||||
let _ = &cli.output.write(
|
||||
serde_json::to_string_pretty(&r.unwrap())
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.as_bytes(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let _: Result<()> = match &cli.command {
|
||||
let result = match cli.command {
|
||||
Commands::Links {
|
||||
path_root,
|
||||
alias_prop,
|
||||
to_absolute_paths,
|
||||
not_remove_unalised,
|
||||
not_remove_unfound,
|
||||
} => utils::iter_nodes(&ast, &|node| {
|
||||
if let NodeValue::Link(ref mut link) = &mut node.data.borrow_mut().value {
|
||||
match links::parse(
|
||||
node,
|
||||
link,
|
||||
&links::ParseOptions {
|
||||
path_root: path_root.to_path_buf(),
|
||||
alias_prop: Some(String::from(alias_prop)),
|
||||
to_complete_paths: *to_absolute_paths,
|
||||
remove_unalised: !*not_remove_unalised,
|
||||
remove_unfound: !*not_remove_unfound,
|
||||
},
|
||||
) {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
if !&cli.surpress_errors {
|
||||
panic!("{err:#?}\n");
|
||||
} else {
|
||||
eprint!("{err:#?}\n");
|
||||
}
|
||||
list,
|
||||
root,
|
||||
replace_url,
|
||||
} => {
|
||||
println!("{list:#?} {root:#?} {replace_url:#?}");
|
||||
|
||||
let list = if replace_url.len() == 0 && !list {
|
||||
true
|
||||
} else {
|
||||
list
|
||||
};
|
||||
|
||||
replace_url.chunks(2).for_each(|p| {
|
||||
links::iterate_links(ast, |l| {
|
||||
if l.url == p[0] {
|
||||
l.url = (*p[1]).to_string()
|
||||
}
|
||||
};
|
||||
})
|
||||
});
|
||||
|
||||
if list {
|
||||
let links = links::get_links(ast);
|
||||
cli::ResultType::List(links)
|
||||
} else {
|
||||
let mut str = vec![];
|
||||
match comrak::format_commonmark(ast, &utils::default_options(), &mut str) {
|
||||
Ok(_) => cli::ResultType::String(String::from_utf8(str).unwrap()),
|
||||
Err(e) => cli::ResultType::Err(cli::Error {
|
||||
code: cli::ErrorCode::EPRSG,
|
||||
description: format!("Error formatting ast back to markdown\n{e:#?}"),
|
||||
fix: None,
|
||||
url: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
_ => cli::ResultType::Err(cli::Error {
|
||||
description: "".to_string(),
|
||||
code: cli::ErrorCode::EPRSG,
|
||||
url: None,
|
||||
fix: None,
|
||||
}),
|
||||
Commands::Frontmatter { command } => utils::iter_nodes(&ast, &|node| {
|
||||
if let NodeValue::FrontMatter(ref mut f) = &mut node.data.borrow_mut().value {
|
||||
let mut frontmatter: Frontmatter<serde_yaml::Value> = match Frontmatter::new(f) {
|
||||
Ok(f) => f,
|
||||
Err(e) => panic!("{e:#?}"),
|
||||
};
|
||||
match command {
|
||||
FrontmatterCommands::Set {
|
||||
property,
|
||||
value,
|
||||
json,
|
||||
} => {
|
||||
frontmatter.set(
|
||||
&property,
|
||||
frontmatter::to_yaml_value(value.to_vec(), !*json),
|
||||
);
|
||||
}
|
||||
FrontmatterCommands::Get {
|
||||
property,
|
||||
error_on_unfound,
|
||||
stderr_on_unfound,
|
||||
} => {
|
||||
let v = frontmatter.get(property);
|
||||
if let Some(v) = v {
|
||||
print!("{v:#?}")
|
||||
} else if *error_on_unfound {
|
||||
panic!()
|
||||
} else if *stderr_on_unfound {
|
||||
eprint!("Not Found")
|
||||
}
|
||||
}
|
||||
};
|
||||
*f = match frontmatter.to_string() {
|
||||
Ok(s) => s,
|
||||
Err(e) => panic!("{e:#?}"),
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}),
|
||||
_ => Ok(()),
|
||||
};
|
||||
|
||||
let _ = comrak::format_commonmark(&ast, &mdparser::utils::default_options(), &mut cli.output);
|
||||
if let cli::ListFormat::JSON = &cli.list_format {
|
||||
if cli.output.is_tty() {
|
||||
cli.list_format = cli::ListFormat::PrettyJSON
|
||||
}
|
||||
}
|
||||
|
||||
let str = match cli::result_to_str(result, &cli.list_format) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
cli::print_error(e);
|
||||
panic!();
|
||||
}
|
||||
};
|
||||
|
||||
match cli.output.write(str.as_bytes()) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
panic!("{e:#?}");
|
||||
}
|
||||
}
|
||||
|
||||
// println!("{ast:#?}");
|
||||
}
|
||||
|
||||
mod cli {
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, clap::ValueEnum)]
|
||||
pub enum ListFormat {
|
||||
Lines,
|
||||
Comma,
|
||||
JSON,
|
||||
UglyJSON,
|
||||
PrettyJSON,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ErrorCode {
|
||||
EPRSG,
|
||||
}
|
||||
impl fmt::Display for ErrorCode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let s = format!("{:?}", self);
|
||||
write!(f, "{}", s)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Error {
|
||||
pub description: String,
|
||||
pub code: ErrorCode,
|
||||
pub fix: Option<String>,
|
||||
pub url: Option<String>,
|
||||
}
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let title = match self.code {
|
||||
ErrorCode::EPRSG => "Parsing error",
|
||||
};
|
||||
|
||||
let fix = if let Some(fix) = &self.fix {
|
||||
format!("\nFix: {}", fix)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
let url = if let Some(url) = &self.url {
|
||||
format!("\nMore info: {}", url)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
write!(
|
||||
f,
|
||||
"Error {:?} - {:?} \n{}{}{}",
|
||||
self.code, title, self.description, fix, url
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ResultType<T>
|
||||
where
|
||||
T: fmt::Display + fmt::Debug + serde::Serialize,
|
||||
{
|
||||
List(Vec<T>),
|
||||
String(String),
|
||||
Err(Error),
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
struct YAMLList<T: fmt::Display + fmt::Debug + serde::Serialize> {
|
||||
list: Vec<T>,
|
||||
}
|
||||
|
||||
pub fn result_to_str<T: fmt::Display + fmt::Debug + serde::Serialize>(
|
||||
result: ResultType<T>,
|
||||
list_format: &ListFormat,
|
||||
) -> Result<String, Error> {
|
||||
match result {
|
||||
ResultType::List(list) => match list_format {
|
||||
ListFormat::Lines => Ok(list
|
||||
.iter()
|
||||
.map(|i| i.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n")
|
||||
.to_string()),
|
||||
ListFormat::Comma => Ok(list
|
||||
.iter()
|
||||
.map(|i| i.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(",")
|
||||
.to_string()),
|
||||
ListFormat::UglyJSON | ListFormat::JSON => {
|
||||
serde_json::to_string(&list).map_err(|e| Error {
|
||||
description: format!(
|
||||
"Failed to parse list vector into a JSON output \
|
||||
on line {}, column {}. Used vector: \n{:#?}",
|
||||
e.line(),
|
||||
e.column(),
|
||||
list
|
||||
),
|
||||
code: ErrorCode::EPRSG,
|
||||
url: None,
|
||||
fix: None,
|
||||
})
|
||||
}
|
||||
ListFormat::PrettyJSON => serde_json::to_string_pretty(&list).map_err(|e| Error {
|
||||
description: format!(
|
||||
"Failed to parse list vector into a JSON output \
|
||||
on line {}, column {}. Used vector: \n{:#?}",
|
||||
e.line(),
|
||||
e.column(),
|
||||
list
|
||||
),
|
||||
code: ErrorCode::EPRSG,
|
||||
url: None,
|
||||
fix: None,
|
||||
}),
|
||||
},
|
||||
ResultType::String(s) => Ok(s),
|
||||
_ => Ok(String::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_error(err: Error) {
|
||||
eprintln!("{}", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user