diff options
| author | adamelmore <[email protected]> | 2026-01-27 08:11:06 -0600 |
|---|---|---|
| committer | adamelmore <[email protected]> | 2026-01-27 08:43:36 -0600 |
| commit | 3297e5230e86b67c4013f8133aefd2c9d47cc464 (patch) | |
| tree | c0be37796c271bb7a0f4c6e65a2ad805bc56252d | |
| parent | c3d8d2b27fb4c10aec99295483d4c34e6eedc780 (diff) | |
| download | opencode-3297e5230e86b67c4013f8133aefd2c9d47cc464.tar.gz opencode-3297e5230e86b67c4013f8133aefd2c9d47cc464.zip | |
fix(app): open markdown links in external browser
| -rw-r--r-- | packages/desktop/src-tauri/src/markdown.rs | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/packages/desktop/src-tauri/src/markdown.rs b/packages/desktop/src-tauri/src/markdown.rs index a2a53b222..c3ca73857 100644 --- a/packages/desktop/src-tauri/src/markdown.rs +++ b/packages/desktop/src-tauri/src/markdown.rs @@ -1,4 +1,43 @@ -use comrak::{markdown_to_html, Options}; +use comrak::{create_formatter, parse_document, Arena, Options, html::ChildRendering, nodes::NodeValue}; +use std::fmt::Write; + +create_formatter!(ExternalLinkFormatter, { + NodeValue::Link(ref nl) => |context, node, entering| { + let skip = context.options.parse.relaxed_autolinks + && node.parent().is_some_and(|p| comrak::node_matches!(p, NodeValue::Link(..))); + if skip { + return Ok(ChildRendering::HTML); + } + + if entering { + context.write_str("<a")?; + comrak::html::render_sourcepos(context, node)?; + + context.write_str(" href=\"")?; + let url = &nl.url; + if context.options.render.r#unsafe || !comrak::html::dangerous_url(url) { + if let Some(rewriter) = &context.options.extension.link_url_rewriter { + context.escape_href(&rewriter.to_html(url))?; + } else { + context.escape_href(url)?; + } + } + context.write_str("\"")?; + + if !nl.title.is_empty() { + context.write_str(" title=\"")?; + context.escape(&nl.title)?; + context.write_str("\"")?; + } + + context.write_str( + " class=\"external-link\" target=\"_blank\" rel=\"noopener noreferrer\">", + )?; + } else { + context.write_str("</a>")?; + } + }, +}); pub fn parse_markdown(input: &str) -> String { let mut options = Options::default(); @@ -8,7 +47,11 @@ pub fn parse_markdown(input: &str) -> String { options.extension.autolink = true; options.render.r#unsafe = true; - markdown_to_html(input, &options) + let arena = Arena::new(); + let doc = parse_document(&arena, input, &options); + let mut html = String::new(); + ExternalLinkFormatter::format_document(doc, &options, &mut html).unwrap_or_default(); + html } #[tauri::command] |
