#![warn(unused_extern_crates)] use std::{ fs::ReadDir, io::{BufWriter, Write, stdout}, ops::Deref, path::{self, Path, PathBuf}, str::FromStr, }; use ansi_align::{AlignOptions, ansi_align, ansi_align_with_options}; use borderrs::BorderFormatter; use boxen::boxen; use lipgloss::{Border, Position}; use mq_markdown::{ColorTheme, ListStyle, Markdown, Node, RenderOptions, UrlSurroundStyle}; use mq_view::{RenderConfig, render_markdown, render_markdown_with_config}; use serde::de::value; use warp::{Filter, filters::path::FullPath}; fn renderer(path: FullPath, user_agent: String) -> Box { let time = chrono::Local::now().to_rfc2822(); println!("{:?} requested by {}", path, user_agent); let path_as_buf = PathBuf::from_str(path.as_str()) .unwrap_or_default() .strip_prefix("/") .unwrap() .to_owned(); let target_path = std::env::current_dir() .expect("could not determine current directory") .join(path_as_buf); if target_path.exists() { let page_contents: Vec = match target_path.is_dir() { true => std::fs::read_dir(target_path) .unwrap() .filter(|x| { x.as_ref() .unwrap() .path() .extension() .unwrap_or_default() .eq("md") }) .map(|x| x.unwrap().path()) .collect(), false => vec![target_path], }; if user_agent.starts_with("curl/") { println!("displaying curl formatting"); let page_markdowns: Vec = page_contents .iter() .map(|x| { let source = std::fs::read_to_string(x).unwrap(); let mut mq: mq_markdown::Markdown = source.parse().unwrap(); let render_opts = RenderOptions { list_style: ListStyle::Dash, link_url_style: UrlSurroundStyle::None, link_title_style: mq_markdown::TitleSurroundStyle::Single, }; mq.set_options(render_opts); let theme = ColorTheme::parse_colors("heading=34:code=31"); mq.to_colored_string_with_theme(&theme); let render_conf = RenderConfig { header_full_width_highlight: false, }; let styled_mq = mq_view::render_markdown_to_string(&mq).unwrap(); let mut writer: Vec = Vec::new(); render_markdown_with_config(&mq, &mut writer, &render_conf).unwrap(); let render_string = String::from_utf8(writer).unwrap(); println!("{}", render_string); let md = mdriver::StreamingParser::new().feed( termimad::text(std::fs::read_to_string(x).unwrap_or_default().as_str()) .to_string() .as_str(), ); let border_style = lipgloss::Style::new() .border(Border::new( "─", "─", "│", "│", "╭", "╮", "╰", "╯", "", "", "", "", "", )) .width(80) .padding(0, 2, 0, 2) .align_horizontal(lipgloss::position::CENTER); border_style.render(render_string.as_str()) }) .collect(); for c in &page_markdowns { println!("{}\n", c); } let page_md_collected = format!("{}\n", page_markdowns.join("\n")); Box::new(warp::reply::with_status( page_md_collected, warp::http::StatusCode::OK, )) } else { println!("displaying html formatting"); let page_md_packed: Vec = page_contents .iter() .map(|x| { format!( "
{}
", x.file_stem() .unwrap_or_default() .to_str() .unwrap_or_default(), markdown::to_html_with_options( std::fs::read_to_string(x).unwrap_or_default().as_str(), &markdown::Options::gfm() ) .unwrap_or_default() ) }) .collect(); let page_md_collected = page_md_packed.join("\n"); let template_html = std::fs::read_to_string("./assets/template.html").unwrap_or_default(); let template = text_template::Template::from(template_html.as_str()); let mut values = std::collections::HashMap::new(); values.insert("time", time.as_str()); values.insert("body", page_md_collected.as_str()); let html = template.fill_in(&values); Box::new(warp::reply::html(html.to_string())) } } else { println!("could not find path!"); Box::new(warp::reply::with_status( "uh oh", warp::http::StatusCode::NOT_FOUND, )) } } #[tokio::main] async fn main() { println!("Hello, world!"); let readme = warp::any() //path::end() .and(warp::path::full()) .and(warp::header("user-agent")) .map(|path: FullPath, agent: String| renderer(path, agent)); warp::serve(readme).run(([127, 0, 0, 1], 3030)).await; }