v0.1.3
This commit is contained in:
parent
9209299af6
commit
03466aad80
297
7
297
7
@ -1,297 +0,0 @@
|
|||||||
use std::io;
|
|
||||||
use std::fs;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::env;
|
|
||||||
use walkdir::WalkDir;
|
|
||||||
use std::process::Command;
|
|
||||||
use std::ffi::OsStr;
|
|
||||||
use colorize::AnsiColor;
|
|
||||||
use dirs;
|
|
||||||
use pandoc::PandocError;
|
|
||||||
use dokugile::template;
|
|
||||||
use rust_i18n::t;
|
|
||||||
use include_dir::{include_dir, Dir};
|
|
||||||
|
|
||||||
rust_i18n::i18n!("locales");
|
|
||||||
|
|
||||||
struct Project {
|
|
||||||
wiki_path: String,
|
|
||||||
doc_path: String,
|
|
||||||
doc_title: String,
|
|
||||||
output_dir: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Project {
|
|
||||||
fn new(wiki_path: String, doc_path: String, doc_title:String, output_dir: String) -> Project {
|
|
||||||
Project {
|
|
||||||
wiki_path,
|
|
||||||
doc_path,
|
|
||||||
doc_title,
|
|
||||||
output_dir,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
const NAME: &str = env!("CARGO_PKG_NAME");
|
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
||||||
const REPO: &str = env!("CARGO_PKG_REPOSITORY");
|
|
||||||
println!("{} {}\n{}\n",NAME.b_magenta(), VERSION.b_magenta(), REPO.b_blue());
|
|
||||||
|
|
||||||
static ASSETS_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/assets");
|
|
||||||
let _ = set_lang();
|
|
||||||
let mut wiki_path = String::new();
|
|
||||||
let mut doc_path = String::new();
|
|
||||||
let mut doc_title = String::new();
|
|
||||||
let mut output_dir = String::new();
|
|
||||||
let mut attempts: i8 = 0;
|
|
||||||
|
|
||||||
while !Path::new(&doc_path).exists() || doc_title.trim().is_empty(){
|
|
||||||
doc_path = String::new();
|
|
||||||
let mut input = String::new();
|
|
||||||
println!("{}:", t!("Project name"));
|
|
||||||
io::stdin().read_line(&mut input).expect(&t!("Failed to read line"));
|
|
||||||
let root = env::var("HOME").unwrap().to_string()+"/";
|
|
||||||
let user_documents_path = dirs::document_dir().unwrap().display().to_string();
|
|
||||||
let user_doc_dir = user_documents_path.split("/").collect::<Vec<_>>().last().unwrap().to_string();
|
|
||||||
|
|
||||||
while !Path::new(&wiki_path).exists() {
|
|
||||||
let mut project_dir = String::new();
|
|
||||||
println!("{}:[{}/Wiki] ", t!("Project location"), &user_doc_dir);
|
|
||||||
io::stdin().read_line(&mut project_dir).expect(&t!("Failed to read line"));
|
|
||||||
if project_dir.trim().is_empty() { project_dir = String::from(user_doc_dir.clone()+"/Wiki") };
|
|
||||||
wiki_path = root.clone()+project_dir.trim();
|
|
||||||
|
|
||||||
if !Path::new(&wiki_path).exists(){
|
|
||||||
let mut ans = String::new();
|
|
||||||
println!("{}", t!("Do you want to create a new location called %{s} for the documents?(y/n)[Y]", s = &project_dir.trim().to_owned().green().bold()));
|
|
||||||
io::stdin().read_line(&mut ans).expect("Failed to read line");
|
|
||||||
if ans.trim().is_empty() { ans = String::from("Y") };
|
|
||||||
match ans.trim() {
|
|
||||||
"y" | "yes" | "Y" | "B" | "Bai" => { //let _ = fs::create_dir(&wiki_path);
|
|
||||||
let _ = mkdir(&wiki_path);
|
|
||||||
println!("{}.", t!("Location %{s} has been created", s = &project_dir.trim().to_owned().green().bold()));
|
|
||||||
},
|
|
||||||
_ => continue,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if input.trim().is_empty(){
|
|
||||||
attempts += 1;
|
|
||||||
}
|
|
||||||
if attempts == 3 {
|
|
||||||
//break
|
|
||||||
let cwd = env::current_dir().unwrap().display().to_string();
|
|
||||||
let dir_name: Vec<&str> = cwd.split('/').collect();
|
|
||||||
if input.trim().is_empty() { input = String::from(dir_name.clone()) };
|
|
||||||
};
|
|
||||||
|
|
||||||
doc_title = input.to_string();
|
|
||||||
output_dir = input.trim_end().to_owned()+"_html";
|
|
||||||
doc_path.push_str(&wiki_path);
|
|
||||||
doc_path.push_str("/");
|
|
||||||
doc_path.push_str(&doc_title.trim_end());
|
|
||||||
//doc_path.push_str(&capitalize_first_letter(&doc_title.trim_end()));
|
|
||||||
let res_path = wiki_path.clone()+"/res";
|
|
||||||
if !Path::new(&doc_path).exists() || !Path::new(&res_path).exists(){
|
|
||||||
// extract assets to temporary directory
|
|
||||||
let _ = ASSETS_DIR.extract("/tmp/assets");
|
|
||||||
let mut ans = String::new();
|
|
||||||
if !Path::new(&doc_path).exists() {
|
|
||||||
println!("{}", t!("The project %{s} has not been found. Do you want to create it?(y/n)[Y]", s = &input.trim().to_owned().green().bold()));
|
|
||||||
io::stdin().read_line(&mut ans).expect(&t!("Failed to read line"));
|
|
||||||
}
|
|
||||||
if ans.trim().is_empty() { ans = String::from("Y") };
|
|
||||||
match ans.trim() {
|
|
||||||
"y" | "yes" | "Y" | "B" | "Bai" => {
|
|
||||||
let _ = mkdir(&doc_path);
|
|
||||||
// create resources
|
|
||||||
for entry in WalkDir::new("/tmp/assets").into_iter().filter_map(|e| e.ok()) {
|
|
||||||
let input_entry = String::from(entry.path().strip_prefix("/tmp/assets").expect(&t!("Path not found")).display().to_string());
|
|
||||||
let subdirs = wiki_path.to_string()+"/"+&input_entry;
|
|
||||||
let images = wiki_path.to_string()+"/"+&doc_title.trim()+"/"+&input_entry;
|
|
||||||
|
|
||||||
if entry.path().is_dir(){
|
|
||||||
match Path::new(&input_entry).to_str() {
|
|
||||||
Some("images") => { //create images directory
|
|
||||||
let _ = mkdir(&images);
|
|
||||||
},
|
|
||||||
Some(..) => { //create resources and its subdirectories
|
|
||||||
let _ = mkdir(&subdirs);
|
|
||||||
},
|
|
||||||
_ => continue
|
|
||||||
};
|
|
||||||
}else if entry.path().is_file(){
|
|
||||||
let source = String::from(entry.path().display().to_string());
|
|
||||||
match Path::new(&input_entry).to_str() {
|
|
||||||
Some(d) if d.contains("images/")=>{ //copy sample-image to images folder
|
|
||||||
let _ = copy(&source, &images);
|
|
||||||
},
|
|
||||||
Some(..) => { //copy files from all other directories
|
|
||||||
let _ = copy(&source, &subdirs);
|
|
||||||
},
|
|
||||||
_ => continue
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!("{}.", t!("Project %{s} has been created. Now you can edit index.md file and create content", s = &input.trim().to_owned().green().bold()));
|
|
||||||
//remove temporary created assets directory
|
|
||||||
let _ = fs::remove_dir_all(Path::new("/tmp/assets"));
|
|
||||||
},
|
|
||||||
_ => continue,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let index = doc_path.to_string()+"/index.md";
|
|
||||||
if !Path::new(&index).exists(){
|
|
||||||
let _ = touch(&index, &template());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let res = processing(Project::new(wiki_path.clone(), doc_path.clone(), doc_title, output_dir));
|
|
||||||
match res {
|
|
||||||
Err(e) => println!("{}", t!("The operation failed with error %{s}", s = e)),
|
|
||||||
Ok(e) => println!("{}", e)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mkdir(dir: &String) -> std::io::Result<()>{
|
|
||||||
let _ = fs::create_dir(dir)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn touch(file: &String, content: &String) -> std::io::Result<()>{
|
|
||||||
fs::write(file, content)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn copy(source: &String, dest: &String) -> std::io::Result<()> {
|
|
||||||
fs::copy(source, dest)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
fn capitalize_first_letter(s: &str) -> String {
|
|
||||||
s[0..1].to_uppercase() + &s[1..]
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
fn processing(project: Project) -> Result<String, String>{
|
|
||||||
let mut md_count :i32 = 0;
|
|
||||||
let mut error = String::new();
|
|
||||||
for entry in WalkDir::new(&project.doc_path).into_iter().filter_map(|e| e.ok()) {
|
|
||||||
if entry.path().is_dir(){
|
|
||||||
let input_entry = String::from(entry.path().display().to_string());
|
|
||||||
let doc_title: String = "/".to_string()+&project.doc_title.trim_end();
|
|
||||||
let output_dir: String = "/".to_string()+ &project.output_dir.trim_end();
|
|
||||||
//replace project-directory to project-directory_html(e.g. "Test" to "Test_html")
|
|
||||||
let new_entry = input_entry.replace(&doc_title, &output_dir);
|
|
||||||
//create output _html directory and subdirectories except images dir
|
|
||||||
match &entry.path().file_name() {
|
|
||||||
Some(p) if *p != "images"=> {
|
|
||||||
let _ = mkdir(&new_entry);
|
|
||||||
},
|
|
||||||
_ => continue,
|
|
||||||
};
|
|
||||||
}else if entry.path().is_file(){
|
|
||||||
if let Some(extension) = entry.path().extension().and_then(OsStr::to_str) {
|
|
||||||
//filter md files
|
|
||||||
match extension {
|
|
||||||
"md" => {
|
|
||||||
//md_count += 1;
|
|
||||||
println!("{}", t!("found... %{s}", s = entry.path().display()));
|
|
||||||
let conv = md_to_html(entry.path(), &project.doc_title, &project.output_dir, &project.wiki_path);
|
|
||||||
match conv {
|
|
||||||
Ok(()) => md_count += 1,
|
|
||||||
Err(e) => { //println!("{}", e);
|
|
||||||
error = e.to_string();
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
_ => (),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
if error.is_empty() {
|
|
||||||
if md_count == 0 {
|
|
||||||
println!("{}", t!("No markdown files found!"));
|
|
||||||
println!("{}", t!("Pleade edit first your documents in markdown format and come back to convert them to html. Bye!"));
|
|
||||||
}else{
|
|
||||||
println!("{}", t!("Processed markdown files.. %{s}", s = md_count));
|
|
||||||
}
|
|
||||||
let mut index = project.wiki_path.to_owned()+"/"+&project.output_dir.trim_end();
|
|
||||||
index.push_str("/index.html");
|
|
||||||
sanitize(Path::new(&index));
|
|
||||||
//Ok("Success")
|
|
||||||
let link = String::from("file://".to_owned()+&index).b_blue();
|
|
||||||
let message:String = String::from(t!("Congrats! Check your documentation at.. %{s}", s = &link));
|
|
||||||
Ok(message)
|
|
||||||
}else{
|
|
||||||
//Err(std::stringify!(error))
|
|
||||||
Err(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn md_to_html(input_file: &Path, doc_title: &String, output_dir: &String, wiki_path: &String) -> Result<(), PandocError>{
|
|
||||||
let page_title: String = "pagetitle=".to_string()+*&doc_title.trim_end();
|
|
||||||
let doc_title: String = "/".to_string()+*&doc_title.trim_end();
|
|
||||||
let output_dir: String = "/".to_string()+ *&output_dir.trim_end();
|
|
||||||
let output_file = input_file.display().to_string().replace(&doc_title, &output_dir).replace(".md", ".html");
|
|
||||||
let base_path = wiki_path.to_owned()+&doc_title;
|
|
||||||
let res_path = wiki_path.to_owned()+&"/res:".to_string();
|
|
||||||
let mut pandoc = pandoc::new();
|
|
||||||
pandoc.add_input(&input_file);
|
|
||||||
pandoc.arg("resource-path", &res_path); //for css and javascript resources
|
|
||||||
pandoc.arg("resource-path", &base_path); //for image search
|
|
||||||
pandoc.arg("include-after-body", "buttons.html");
|
|
||||||
pandoc.arg("css", "css/theme.css");
|
|
||||||
pandoc.arg("css", "css/sidebar.css");
|
|
||||||
pandoc.arg("css", "css/buttons.css");
|
|
||||||
pandoc.arg("embed-resources", "true");
|
|
||||||
pandoc.arg("standalone", "true");
|
|
||||||
pandoc.arg("shift-heading-level-by", "-1");
|
|
||||||
pandoc.set_number_sections();
|
|
||||||
pandoc.set_toc();
|
|
||||||
pandoc.arg("toc-depth", "4");
|
|
||||||
pandoc.arg("metadata", &page_title);
|
|
||||||
pandoc.set_output(pandoc::OutputKind::File(output_file.into()));
|
|
||||||
//pandoc.execute().unwrap();
|
|
||||||
|
|
||||||
match pandoc.execute() {
|
|
||||||
Ok(..) => Ok(()),
|
|
||||||
Err(PandocError::PandocNotFound) => Err(PandocError::PandocNotFound),
|
|
||||||
Err(PandocError::IoErr(e)) => Err(PandocError::IoErr(e)),
|
|
||||||
Err(PandocError::Err(e)) => Err(PandocError::Err(e)),
|
|
||||||
Err(PandocError::NoInputSpecified) => Err(PandocError::NoInputSpecified),
|
|
||||||
Err(PandocError::BadUtf8Conversion(e)) => Err(PandocError::BadUtf8Conversion(e)),
|
|
||||||
Err(PandocError::NoOutputSpecified) => Err(PandocError::NoOutputSpecified)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sanitize(index: &Path){
|
|
||||||
if index.exists(){
|
|
||||||
//convert page links from ".md" to ".html" in the index.html file
|
|
||||||
Command::new("sed")
|
|
||||||
.args(["-i", r"-e s/\.md/\.html/g", &index.display().to_string()])
|
|
||||||
.status()
|
|
||||||
.expect(&t!("sed command failed start"));
|
|
||||||
}else{
|
|
||||||
println!("{}", t!("Please consider renaming your main page to index.md and restart the document conversion again. See you later!"));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_lang(){
|
|
||||||
let default = String::from("en_US"); // default locale
|
|
||||||
let locales = rust_i18n::available_locales!(); // available locales
|
|
||||||
let lang:String = match env::var("LANG") { // find out user's lang
|
|
||||||
Ok(val) => match val {
|
|
||||||
v if !v.is_empty() && locales.iter().any(|e| v.contains(e)) => v[..5].to_string(),
|
|
||||||
_ => default
|
|
||||||
} ,
|
|
||||||
Err(..) => default,
|
|
||||||
};
|
|
||||||
rust_i18n::set_locale(&lang); // set user lang
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user