use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use anyhow::anyhow;
use anyhow::Result;
use once_cell::sync::Lazy;
use rand::distributions::Alphanumeric;
use rand::distributions::DistString;
use regex::Regex;
use tracing::info;
static EXTRACT_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r"(?s)```rust.*?\n(?<code>.*?)```").unwrap());
pub fn extract_code_from_all_markdown_files_in<P1, P2>(
markdown_src_dir_path: P1,
code_dest_dir_path: P2,
) -> Result<()>
where
P1: AsRef<Path>,
P2: AsRef<Path>,
{
let markdown_file_paths = crate::fs::find_markdown_files_in(markdown_src_dir_path.as_ref())?;
crate::fs::create_dir(code_dest_dir_path.as_ref())?;
for p in markdown_file_paths {
info!("{p:?}");
let buf = fs::read_to_string(p.as_path())?;
let random_string = Alphanumeric.sample_string(&mut rand::thread_rng(), 5);
for (number, (_, [code])) in EXTRACT_REGEX
.captures_iter(&buf)
.map(|c| c.extract())
.enumerate()
{
let code = Regex::new(r"(?m)^(?:#\s)(?<rest>.*)$")?.replace_all(code, "$rest");
let code_filename = format!(
"{}{}{}",
p.file_stem()
.unwrap_or(random_string.as_ref())
.to_string_lossy(),
if number == 0 {
String::new()
} else {
number.to_string()
},
".rs"
);
let code_path = code_dest_dir_path.as_ref().join(code_filename);
info!(" {number}: {code_path:?}\n");
File::create(code_path)?.write_all(code.as_bytes())?;
}
}
Ok(())
}
pub fn remove_code_from_all_markdown_files_in<P1, P2>(
markdown_src_dir_path: P1,
code_dir_path: P2,
) -> Result<()>
where
P1: AsRef<Path>,
P2: AsRef<Path>,
{
let markdown_file_paths = crate::fs::find_markdown_files_in(markdown_src_dir_path)?;
for p in markdown_file_paths {
info!("{p:?}");
let buf = fs::read_to_string(p.as_path())?;
let re = Regex::new(r"(?s)(?<first>```rust.*?\n)(?<code>.+?)(?<last>```)")?;
if re.is_match(&buf) {
let replacement = format!(
"$first{{#include {}.rs}}\n$last",
PathBuf::from(code_dir_path.as_ref())
.join(p.file_stem().ok_or(anyhow!(
"[remove_code_from_all_markdown_files_in] There is no file name."
))?)
.display()
);
let new_txt = re.replace_all(&buf, replacement);
File::create(p)?.write_all(new_txt.as_bytes())?;
}
}
Ok(())
}