markdown.rs 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. use comrak::{
  2. Arena, Options, create_formatter, html::ChildRendering, nodes::NodeValue, parse_document,
  3. };
  4. use std::fmt::Write;
  5. create_formatter!(ExternalLinkFormatter, {
  6. NodeValue::Link(ref nl) => |context, node, entering| {
  7. let skip = context.options.parse.relaxed_autolinks
  8. && node.parent().is_some_and(|p| comrak::node_matches!(p, NodeValue::Link(..)));
  9. if skip {
  10. return Ok(ChildRendering::HTML);
  11. }
  12. if entering {
  13. context.write_str("<a")?;
  14. comrak::html::render_sourcepos(context, node)?;
  15. context.write_str(" href=\"")?;
  16. let url = &nl.url;
  17. if context.options.render.r#unsafe || !comrak::html::dangerous_url(url) {
  18. if let Some(rewriter) = &context.options.extension.link_url_rewriter {
  19. context.escape_href(&rewriter.to_html(url))?;
  20. } else {
  21. context.escape_href(url)?;
  22. }
  23. }
  24. context.write_str("\"")?;
  25. if !nl.title.is_empty() {
  26. context.write_str(" title=\"")?;
  27. context.escape(&nl.title)?;
  28. context.write_str("\"")?;
  29. }
  30. context.write_str(
  31. " class=\"external-link\" target=\"_blank\" rel=\"noopener noreferrer\">",
  32. )?;
  33. } else {
  34. context.write_str("</a>")?;
  35. }
  36. },
  37. });
  38. pub fn parse_markdown(input: &str) -> String {
  39. let mut options = Options::default();
  40. options.extension.strikethrough = true;
  41. options.extension.table = true;
  42. options.extension.tasklist = true;
  43. options.extension.autolink = true;
  44. options.render.r#unsafe = true;
  45. let arena = Arena::new();
  46. let doc = parse_document(&arena, input, &options);
  47. let mut html = String::new();
  48. ExternalLinkFormatter::format_document(doc, &options, &mut html).unwrap_or_default();
  49. html
  50. }
  51. #[tauri::command]
  52. #[specta::specta]
  53. pub async fn parse_markdown_command(markdown: String) -> Result<String, String> {
  54. Ok(parse_markdown(&markdown))
  55. }