From 3b46e66015097ffe7cc5a7737df578f1e8eaab2a Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Wed, 18 Sep 2024 18:29:07 -0700 Subject: [PATCH 1/2] feat(forge): Add `escape_square_brackets` into `comment_formats` markdown configuration --- CHANGELOG.md | 6 + crates/weaver_forge/README.md | 1 + crates/weaver_forge/src/formats/markdown.rs | 115 +++++++++++++++++++- docs/weaver-config.md | 1 + 4 files changed, 119 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3170746..cd366950 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. +## [Next] - YYYY-MM-DD + +What's changed + +* Add `escape_square_brackets` into `comment_formats` markdown configuration. ([#XXX](...) by lquerel). + ## [0.9.2] - 2024-09-09 What's Changed diff --git a/crates/weaver_forge/README.md b/crates/weaver_forge/README.md index 888e3f96..cf668458 100644 --- a/crates/weaver_forge/README.md +++ b/crates/weaver_forge/README.md @@ -579,6 +579,7 @@ comment_formats: # optional # Fields specific to 'markdown' format escape_backslashes: # Whether to escape backslashes in markdown (default: false). + escape_square_brackets: # Whether to escape square brackets in markdown (default: false). shortcut_reference_links: # Convert inlined links into shortcut reference links (default: false). indent_first_level_list_items: # Indent the first level of list items in markdown (default: false). default_block_code_language: # Default language for block code snippets (default: ""). diff --git a/crates/weaver_forge/src/formats/markdown.rs b/crates/weaver_forge/src/formats/markdown.rs index bb327386..aa9c0151 100644 --- a/crates/weaver_forge/src/formats/markdown.rs +++ b/crates/weaver_forge/src/formats/markdown.rs @@ -12,10 +12,14 @@ use std::collections::HashMap; #[derive(Deserialize, Serialize, Debug, Clone, Default)] #[serde(rename_all = "snake_case")] pub struct MarkdownRenderOptions { - /// Whether to escape backslashes in the markdown. + /// Whether to escape backslashes in the Markdown. /// Default is false. #[serde(default)] pub(crate) escape_backslashes: bool, + /// Whether to escape square brackets in the Markdown text. Valid links are not affected. + /// Default is false. + #[serde(default)] + pub(crate) escape_square_brackets: bool, /// Whether to indent the first level of list items in the markdown. /// Default is false. #[serde(default)] @@ -196,11 +200,36 @@ impl MarkdownRenderer { } } Node::Text(text) => { + fn escape_unescaped_chars(s: &str, chars_to_escape: &[char]) -> String { + let mut result = String::with_capacity(s.len()); + let mut backslash_count = 0; + + for c in s.chars() { + if c == '\\' { + backslash_count += 1; + result.push(c); + } else { + if chars_to_escape.contains(&c) && backslash_count % 2 == 0 { + // Even number of backslashes means the character is unescaped + result.push('\\'); + } + result.push(c); + // Reset the backslash count after a non-backslash character + backslash_count = 0; + } + } + + result + } + + let mut text = text.value.clone(); if options.escape_backslashes { - ctx.add_text(&text.value.replace('\\', "\\\\")); - } else { - ctx.add_text(&text.value); + text = text.replace('\\', "\\\\"); + } + if options.escape_square_brackets { + text = escape_unescaped_chars(&text, &['[', ']']); } + ctx.add_text(&text); } Node::Paragraph(p) => { ctx.add_cond_blank_line(); @@ -374,6 +403,7 @@ mod tests { footer: None, format: RenderFormat::Markdown(MarkdownRenderOptions { escape_backslashes: false, + escape_square_brackets: false, indent_first_level_list_items: true, shortcut_reference_link: true, default_block_code_language: None, @@ -465,6 +495,83 @@ it's RECOMMENDED to: - Use a domain-specific attribute - Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not."## ); + + let config = WeaverConfig { + comment_formats: Some( + vec![( + "go".to_owned(), + CommentFormat { + header: None, + prefix: Some("// ".to_owned()), + footer: None, + format: RenderFormat::Markdown(MarkdownRenderOptions { + escape_backslashes: false, + escape_square_brackets: false, + indent_first_level_list_items: true, + shortcut_reference_link: true, + default_block_code_language: None, + }), + trim: true, + remove_trailing_dots: true, + }, + )] + .into_iter() + .collect(), + ), + default_comment_format: Some("go".to_owned()), + ..WeaverConfig::default() + }; + + let renderer = MarkdownRenderer::try_new(&config)?; + let markdown = r##"In some cases a [URL] may refer to an [IP](http://ip.com) and/or port directly, + The file \\[extension\\] extracted \\[from] the `url.full`, excluding the leading dot."##; + let html = renderer.render(markdown, "go")?; + assert_eq!( + html, + r##"In some cases a [URL] may refer to an [IP] and/or port directly, +The file \[extension\] extracted \[from] the `url.full`, excluding the leading dot. + +[IP]: http://ip.com"## + ); + + let config = WeaverConfig { + comment_formats: Some( + vec![( + "go".to_owned(), + CommentFormat { + header: None, + prefix: Some("// ".to_owned()), + footer: None, + format: RenderFormat::Markdown(MarkdownRenderOptions { + escape_backslashes: false, + escape_square_brackets: true, + indent_first_level_list_items: true, + shortcut_reference_link: true, + default_block_code_language: None, + }), + trim: true, + remove_trailing_dots: true, + }, + )] + .into_iter() + .collect(), + ), + default_comment_format: Some("go".to_owned()), + ..WeaverConfig::default() + }; + + let renderer = MarkdownRenderer::try_new(&config)?; + let markdown = r##"In some cases a [URL] may refer to an [IP](http://ip.com) and/or port directly, + The file \[extension\] extracted \[from] the `url.full`, excluding the leading dot."##; + let html = renderer.render(markdown, "go")?; + assert_eq!( + html, + r##"In some cases a \[URL\] may refer to an [IP] and/or port directly, +The file \[extension\] extracted \[from\] the `url.full`, excluding the leading dot. + +[IP]: http://ip.com"## + ); + Ok(()) } } diff --git a/docs/weaver-config.md b/docs/weaver-config.md index 3a7b4c4a..baf66628 100644 --- a/docs/weaver-config.md +++ b/docs/weaver-config.md @@ -52,6 +52,7 @@ comment_formats: # optional # The following fields are enabled only when format is set to 'markdown' escape_backslashes: # Whether to escape backslashes in the markdown (default: false). + escape_square_brackets: # Whether to escape square brackets in markdown (default: false). shortcut_reference_links: # Use this to convert inlined links into shortcut reference links, similar to those in Go documentation (default: false). indent_first_level_list_items: # Whether to indent the first level of list items in the markdown (default: false). default_block_code_language: # The default language for block code snippets (default: ""). From ed492f980bb7e8a6957edc42138e6bfcbb234cac Mon Sep 17 00:00:00 2001 From: Laurent Querel Date: Thu, 19 Sep 2024 08:59:49 -0700 Subject: [PATCH 2/2] feat(forge): Change default value for `escape_square_brackets` --- .../expected_output/comment_format/example.rs | 2 +- crates/weaver_forge/src/formats/markdown.rs | 14 ++++++++++++-- .../templates/comment_format/weaver.yaml | 2 ++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/crates/weaver_forge/expected_output/comment_format/example.rs b/crates/weaver_forge/expected_output/comment_format/example.rs index a2b38245..82304fbb 100644 --- a/crates/weaver_forge/expected_output/comment_format/example.rs +++ b/crates/weaver_forge/expected_output/comment_format/example.rs @@ -96,7 +96,7 @@ /// > Lorem ipsum dolor sit amet, consectetur adipiscing /// > elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. /// - /// > [!NOTE] Something very important here + /// > \[!NOTE\] Something very important here const ATTR: &str = ""; diff --git a/crates/weaver_forge/src/formats/markdown.rs b/crates/weaver_forge/src/formats/markdown.rs index cf027d29..6e3fce88 100644 --- a/crates/weaver_forge/src/formats/markdown.rs +++ b/crates/weaver_forge/src/formats/markdown.rs @@ -17,8 +17,8 @@ pub struct MarkdownRenderOptions { #[serde(default)] pub(crate) escape_backslashes: bool, /// Whether to escape square brackets in the Markdown text. Valid links are not affected. - /// Default is false. - #[serde(default)] + /// Default is true. + #[serde(default = "default_bool::")] pub(crate) escape_square_brackets: bool, /// Whether to indent the first level of list items in the markdown. /// Default is false. @@ -34,6 +34,12 @@ pub struct MarkdownRenderOptions { pub(crate) default_block_code_language: Option, } +/// Used to set a default value for a boolean field in a struct. +#[must_use] +pub const fn default_bool() -> bool { + V +} + pub(crate) struct ShortcutReferenceLink { pub(crate) label: String, pub(crate) url: String, @@ -515,6 +521,8 @@ it's RECOMMENDED to: }), trim: true, remove_trailing_dots: true, + indent_type: Default::default(), + enforce_trailing_dots: false, }, )] .into_iter() @@ -553,6 +561,8 @@ The file \[extension\] extracted \[from] the `url.full`, excluding the leading d }), trim: true, remove_trailing_dots: true, + indent_type: Default::default(), + enforce_trailing_dots: false, }, )] .into_iter() diff --git a/crates/weaver_forge/templates/comment_format/weaver.yaml b/crates/weaver_forge/templates/comment_format/weaver.yaml index 375ea7e6..ce265626 100644 --- a/crates/weaver_forge/templates/comment_format/weaver.yaml +++ b/crates/weaver_forge/templates/comment_format/weaver.yaml @@ -37,6 +37,7 @@ comment_formats: shortcut_reference_link: true trim: true remove_trailing_dots: true + escape_square_brackets: false python: format: markdown header: '"""' @@ -44,6 +45,7 @@ comment_formats: escape_backslashes: true trim: true remove_trailing_dots: true + escape_square_brackets: false templates: - template: "example.java.j2"