aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide/src/syntax_highlighting/inject.rs10
-rw-r--r--crates/mbe/src/syntax_bridge.rs2
-rw-r--r--crates/mbe/src/tests/expand.rs24
-rw-r--r--crates/rust-analyzer/src/markdown.rs18
4 files changed, 46 insertions, 8 deletions
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index 04fafd244..855c7fba8 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -90,6 +90,13 @@ const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[
90 "edition2021", 90 "edition2021",
91]; 91];
92 92
93fn is_rustdoc_fence_token(token: &str) -> bool {
94 if RUSTDOC_FENCE_TOKENS.contains(&token) {
95 return true;
96 }
97 token.starts_with('E') && token.len() == 5 && token[1..].parse::<u32>().is_ok()
98}
99
93/// Injection of syntax highlighting of doctests. 100/// Injection of syntax highlighting of doctests.
94pub(super) fn doc_comment( 101pub(super) fn doc_comment(
95 hl: &mut Highlights, 102 hl: &mut Highlights,
@@ -174,8 +181,7 @@ pub(super) fn doc_comment(
174 is_codeblock = !is_codeblock; 181 is_codeblock = !is_codeblock;
175 // Check whether code is rust by inspecting fence guards 182 // Check whether code is rust by inspecting fence guards
176 let guards = &line[idx + RUSTDOC_FENCE.len()..]; 183 let guards = &line[idx + RUSTDOC_FENCE.len()..];
177 let is_rust = 184 let is_rust = guards.split(',').all(|sub| is_rustdoc_fence_token(sub.trim()));
178 guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim()));
179 is_doctest = is_codeblock && is_rust; 185 is_doctest = is_codeblock && is_rust;
180 continue; 186 continue;
181 } 187 }
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index 9ba98f7fb..a7c8c13c6 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -213,7 +213,7 @@ fn doc_comment_text(comment: &ast::Comment) -> SmolStr {
213 213
214 // Quote the string 214 // Quote the string
215 // Note that `tt::Literal` expect an escaped string 215 // Note that `tt::Literal` expect an escaped string
216 let text = format!("{:?}", text.escape_debug().to_string()); 216 let text = format!("\"{}\"", text.escape_debug());
217 text.into() 217 text.into()
218} 218}
219 219
diff --git a/crates/mbe/src/tests/expand.rs b/crates/mbe/src/tests/expand.rs
index 146b236e2..3a1d840ea 100644
--- a/crates/mbe/src/tests/expand.rs
+++ b/crates/mbe/src/tests/expand.rs
@@ -936,7 +936,7 @@ fn test_meta_doc_comments() {
936 MultiLines Doc 936 MultiLines Doc
937 */ 937 */
938 }"#, 938 }"#,
939 "# [doc = \" Single Line Doc 1\"] # [doc = \"\\\\n MultiLines Doc\\\\n \"] fn bar () {}", 939 "# [doc = \" Single Line Doc 1\"] # [doc = \"\\n MultiLines Doc\\n \"] fn bar () {}",
940 ); 940 );
941} 941}
942 942
@@ -977,7 +977,27 @@ fn test_meta_doc_comments_non_latin() {
977 莊生曉夢迷蝴蝶,望帝春心託杜鵑。 977 莊生曉夢迷蝴蝶,望帝春心託杜鵑。
978 */ 978 */
979 }"#, 979 }"#,
980 "# [doc = \" 錦瑟無端五十弦,一弦一柱思華年。\"] # [doc = \"\\\\n 莊生曉夢迷蝴蝶,望帝春心託杜鵑。\\\\n \"] fn bar () {}", 980 "# [doc = \" 錦瑟無端五十弦,一弦一柱思華年。\"] # [doc = \"\\n 莊生曉夢迷蝴蝶,望帝春心託杜鵑。\\n \"] fn bar () {}",
981 );
982}
983
984#[test]
985fn test_meta_doc_comments_escaped_characters() {
986 parse_macro(
987 r#"
988 macro_rules! foo {
989 ($(#[$ i:meta])+) => (
990 $(#[$ i])+
991 fn bar() {}
992 )
993 }
994"#,
995 )
996 .assert_expand_items(
997 r#"foo! {
998 /// \ " '
999 }"#,
1000 r#"# [doc = " \\ \" \'"] fn bar () {}"#,
981 ); 1001 );
982} 1002}
983 1003
diff --git a/crates/rust-analyzer/src/markdown.rs b/crates/rust-analyzer/src/markdown.rs
index 865eaae9b..a51ff89e4 100644
--- a/crates/rust-analyzer/src/markdown.rs
+++ b/crates/rust-analyzer/src/markdown.rs
@@ -27,9 +27,8 @@ pub(crate) fn format_docs(src: &str) -> String {
27 in_code_block ^= true; 27 in_code_block ^= true;
28 28
29 if in_code_block { 29 if in_code_block {
30 is_rust = header 30 is_rust =
31 .split(',') 31 header.split(',').all(|sub| is_rust_specific_code_block_attribute(sub.trim()));
32 .all(|sub| RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUST_SPECIFIC.contains(&sub.trim()));
33 32
34 if is_rust { 33 if is_rust {
35 line = "```rust"; 34 line = "```rust";
@@ -42,6 +41,13 @@ pub(crate) fn format_docs(src: &str) -> String {
42 processed_lines.join("\n") 41 processed_lines.join("\n")
43} 42}
44 43
44fn is_rust_specific_code_block_attribute(attr: &str) -> bool {
45 if RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUST_SPECIFIC.contains(&attr) {
46 return true;
47 }
48 attr.starts_with('E') && attr.len() == 5 && attr[1..].parse::<u32>().is_ok()
49}
50
45fn code_line_ignored_by_rustdoc(line: &str) -> bool { 51fn code_line_ignored_by_rustdoc(line: &str) -> bool {
46 let trimmed = line.trim(); 52 let trimmed = line.trim();
47 trimmed == "#" || trimmed.starts_with("# ") || trimmed.starts_with("#\t") 53 trimmed == "#" || trimmed.starts_with("# ") || trimmed.starts_with("#\t")
@@ -82,6 +88,12 @@ mod tests {
82 } 88 }
83 89
84 #[test] 90 #[test]
91 fn test_format_docs_handles_error_codes() {
92 let comment = "```compile_fail,E0641\nlet b = 0 as *const _;\n```";
93 assert_eq!(format_docs(comment), "```rust\nlet b = 0 as *const _;\n```");
94 }
95
96 #[test]
85 fn test_format_docs_skips_comments_in_rust_block() { 97 fn test_format_docs_skips_comments_in_rust_block() {
86 let comment = 98 let comment =
87 "```rust\n # skip1\n# skip2\n#stay1\nstay2\n#\n #\n # \n #\tskip3\n\t#\t\n```"; 99 "```rust\n # skip1\n# skip2\n#stay1\nstay2\n#\n #\n # \n #\tskip3\n\t#\t\n```";