Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rendering markdown files? #1355

Open
pdobsan opened this issue Mar 2, 2024 · 12 comments
Open

rendering markdown files? #1355

pdobsan opened this issue Mar 2, 2024 · 12 comments

Comments

@pdobsan
Copy link

pdobsan commented Mar 2, 2024

I use miniserve to browse /usr/share/doc and for this rendering the README.md file github style is great. Many times the whole documentation of a package is in markdown (.md) files.

Since the capability is there I was wondering if an option to allow automatic rendering of markdown files would be a possible/useful feature to add?

@Dialga
Copy link

Dialga commented Mar 5, 2024

It might be too much to ask for in miniserve, but there is the https://github.com/xyproto/algernon web server which can render markdown.

@pdobsan
Copy link
Author

pdobsan commented Mar 5, 2024 via email

@Dialga
Copy link

Dialga commented Apr 9, 2024

What would be the approximate difference in terms of source code complexity and runtime resource usage between rendering Readme.md and rendering an arbitrary markdown file named differently?

The code might be simple to write and integrate, but there is an added maintenance burden for every new feature, aka feature creep. Tomorrow the next person would want a word/powerpoint renderer.
I agree this is a nice to have feature for markdown, not a must have.

@svenstaro
Copy link
Owner

I actually think this would be fine for miniserve. A markdown renderer seems reasonable. We shouldn't add any other specific renderers, though.

@MrFaul
Copy link

MrFaul commented Apr 9, 2024

Since I had this actually opened in another tab...

/// Load a markdown file, render to HTML, and return the response.
async fn md_path_to_html(path: &Path) -> Result<Response<Body>> {
    // Render Markdown like GitHub
    let mut options = ComrakOptions::default();
    options.ext_autolink = true;
    options.ext_header_ids = None;
    options.ext_table = true;
    options.ext_strikethrough = true;
    options.ext_tagfilter = true;
    options.ext_tasklist = true;
    options.github_pre_lang = true;
    options.ext_header_ids = Some("user-content-".to_string());

    let buf = tokio::fs::read(path).await?;
    let s = String::from_utf8(buf).map_err(|_| Error::MarkdownUtf8)?;
    let html = comrak::markdown_to_html(&s, &options);
    let cfg = HtmlCfg {
        title: String::new(),
        body: html,
    };
    let html = super::render_html(cfg)?;

    Response::builder()
        .status(StatusCode::OK)
        .header(header::CONTENT_LENGTH, html.len() as u64)
        .header(header::CONTENT_TYPE, mime::TEXT_HTML.as_ref())
        .body(Body::from(html))
        .map_err(Error::from)
}

That's the implementation of the basic-http-server
Line 67 in ext.rs

@svenstaro
Copy link
Owner

miniserve already renders Markdown using Comrak so this should be rather easy if there are any takers. :)

@Atreyagaurav
Copy link
Contributor

About this. Just blindly converting any markdown file to rendered HTML would be easy with the mechanism we have for readme.md.

But I think there needs to be a way to get the raw file contents as well. So I don't think we can convert .md files into HTML when the url is pointing to that file directly. Right now, the --readme flag only adds the contents as HTML on the index page, but the file contents when you click on the file is raw. If we want to do that to every markdown file, then I think we need to add a mechanism to get the raw files somehow.

Considering someone would want to add links to other markdown files to make a website/wiki of markdown file, I think either the normal file paths have to be converted to HTML and have a separate way to get raw, or we'd have to modify the links to other .md paths in the rendered HTML. The first option would ruin the recursive download from wget and other scripts people might right. So the second option is more reasonable, but would need to post process the rendered HTML for Markdown links.

All that complication makes me think, miniserve might not be a good tool for that. Although having that feature would be nice, so if we agree on a simple flag (e.g. --markdown-mode) to just convert all markdown to HTML then we can do that.

@MrFaul
Copy link

MrFaul commented Jul 14, 2024

<URL>?render=true?
Any further rendered md URL could be automatically appended so it has the same net effect.
This way you have both worlds and on the file page you also could add a view/render button.

@Atreyagaurav
Copy link
Contributor

Modifying the URL like that seems simple. We can keep the directory listing pure, and modify the URLs in README.md so that can act as the index page to other .md files.

modified src/listing.rs

@@ -237,6 +237,7 @@ pub fn directory_listing(
     let mut entries: Vec<Entry> = Vec::new();
     let mut readme: Option<(String, String)> = None;
     let readme_rx: Regex = Regex::new("^readme([.](md|txt))?$").unwrap();
+    let md_link: Regex = Regex::new("href=\"(?<url>[.]/.*[.]md)\"").unwrap();
 
     for entry in dir.path.read_dir()? {
         if dir.is_visible(&entry) || conf.show_hidden {
@@ -292,10 +293,11 @@ pub fn directory_listing(
                         readme = Some((
                             file_name.to_string(),
                             if ext == "md" {
-                                markdown_to_html(
-                                    &std::fs::read_to_string(entry.path())?,
-                                    &ComrakOptions::default(),
-                                )
+				md_link.replace_all(
+                                    &markdown_to_html(
+					&std::fs::read_to_string(entry.path())?,
+					&ComrakOptions::default(),
+                                    ), "href=\"$url?render=true\"").to_string()
                             } else {
                                 format!("<pre>{}</pre>", &std::fs::read_to_string(entry.path())?)
                             },

But I can't figure out how to make it serve the modified contents for each .md path. As far as I can see, it somehow automatically serves the static files (through Files), so we might need to modify the path handler from actix through some traits, or custom functions that filter the .md?render=true urls and send html in those cases.

@MrFaul
Copy link

MrFaul commented Jul 15, 2024

Well, the best thing would probably to register ad-hoc middle ware, since the files hook won't work.
I tried that and failed.

I intended to start on that and forgot it 😅
Other stuff became more pressing so the entire project that used mini serve grinded to a halt.
I'm not a programmer by trade, so I easily lost track of it.

@MrFaul
Copy link

MrFaul commented Jul 24, 2024

Sooo...
I basically frankensteined that now into the pretty-urls flag, so it renders MD files when requested without file extension.
It works, but is super ugly.
@svenstaro up to you if you want to see that 😅

@svenstaro
Copy link
Owner

Why not, just put up a PR and I'll have a look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants