Initial commit

This commit is contained in:
Lukas Stancik
2026-03-23 15:25:57 +00:00
commit 448b417db3
10 changed files with 927 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
use clap::{Parser, Subcommand};
/// Markdown to HTML converter
#[derive(Debug, Parser)]
#[command(name = "md-to-html")]
#[command(about = "Markdown to HTML converter", long_about = None)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
}
#[derive(Debug, Subcommand)]
pub enum Commands {
/// Convert markdown files to html
#[command(arg_required_else_help = true)]
Convert {
/// The remote to clone
#[clap(short, long)]
file: String,
/// Output file
#[clap(short, long)]
to: Option<String>,
},
}
+66
View File
@@ -0,0 +1,66 @@
use std::io::{Read, Write};
use std::path::Path;
#[derive(Debug, Clone)]
pub struct File {
title: String,
content: String,
}
impl Default for File {
fn default() -> Self {
Self::new()
}
}
impl File {
pub fn new() -> File {
File {
title: String::from("Unknown"),
content: String::new(),
}
}
pub fn read_from_file(&mut self, location: &Path) {
let mut file = std::fs::File::open(location).unwrap();
file.read_to_string(&mut self.content).unwrap();
}
pub fn get_title(&self) -> &String {
&self.title
}
pub fn get_content(&self) -> &String {
&self.content
}
pub fn set_title(&mut self, title: String) {
self.title = title;
}
pub fn exists(&self) -> bool {
std::path::Path::new(&self.title).exists()
}
pub fn write_content(&mut self, content: String) {
self.content = content;
}
pub fn erase_content(&mut self) {
self.content.clear();
}
pub fn append_content(&mut self, content: &str) {
self.content.push_str(content);
}
pub fn read_file(&mut self, location: &str) {
let mut file = std::fs::File::open(location).unwrap();
file.read_to_string(&mut self.content).unwrap();
}
pub fn write_file(&self) {
let mut file = std::fs::File::create(&self.title).unwrap();
file.write_all(self.content.as_bytes()).unwrap();
}
}
+41
View File
@@ -0,0 +1,41 @@
pub struct Html {}
impl Default for Html {
fn default() -> Html {
Html::new()
}
}
impl Html {
pub fn new() -> Html {
Html {}
}
pub fn render(&self, content: &str, minify_html: bool) -> String {
let rendered = format!(
r#"{}"#,
content
);
match minify_html {
true => self.minify(rendered, false),
false => rendered,
}
}
fn minify(&self, content: String, space: bool) -> String {
let mut compressed = String::new();
// Remove all newlines
for line in content.lines() {
compressed.push_str(line.trim());
}
if space {
// Remove all whitespace
compressed.retain(|c| !c.is_whitespace());
}
compressed
}
}
+3
View File
@@ -0,0 +1,3 @@
pub mod file;
pub mod html;
pub mod parser;
+54
View File
@@ -0,0 +1,54 @@
#![allow(clippy::single_match)]
mod args;
use args::{Cli, Commands};
use clap::Parser;
use md_to_html::{file, html, parser};
use std::path::Path;
use std::process::exit;
fn main() {
let args = Cli::parse();
let parser = parser::Parser::new(markdown::Options::gfm());
let html = html::Html::new();
match args.command {
Commands::Convert { file, to } => {
// File preprocessing
let location = Path::new(&file);
let mut input = file::File::new();
let mut output = file::File::new();
// if file exists, read it
if location.exists() {
input.read_from_file(location);
} else {
println!("File does not exist");
exit(1)
}
let parsed = parser.parse(input.get_content());
let render = html.render(parsed.as_str(), false);
// Convert all necessary characters
let render = render
.replace("&lt;", "<")
.replace("&gt;", ">")
.replace("&quot;", "\"");
output.write_content(render);
match to {
Some(out) => {
output.set_title(out);
output.write_file();
}
None => {
output.set_title("out.html".to_string());
output.write_file();
}
}
}
}
}
+18
View File
@@ -0,0 +1,18 @@
use markdown::Options;
pub struct Parser {
options: Option<Options>,
}
impl Parser {
pub fn new(opt: Options) -> Parser {
Parser { options: Some(opt) }
}
pub fn parse(&self, content: &str) -> String {
match &self.options {
Some(opt) => markdown::to_html_with_options(content, opt).unwrap(),
None => markdown::to_html(content),
}
}
}