]> git.lizzy.rs Git - rust.git/commitdiff
Improve support for code block attributes
authorLeón Orell Valerian Liehr <liehr.exchange@gmx.net>
Wed, 26 Aug 2020 01:02:55 +0000 (03:02 +0200)
committerLeón Orell Valerian Liehr <liehr.exchange@gmx.net>
Wed, 26 Aug 2020 13:55:06 +0000 (15:55 +0200)
crates/ide/src/runnables.rs
crates/rust-analyzer/src/markdown.rs

index dd59d9e70e48ec6dcf0a359cc3758adee0880889..989a63c09c4d042d95b5db6f6a81b3df47617edf 100644 (file)
@@ -211,12 +211,29 @@ fn has_test_related_attribute(fn_def: &ast::Fn) -> bool {
         .any(|attribute_text| attribute_text.contains("test"))
 }
 
+const RUSTDOC_FENCE: &str = "```";
+const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
+    &["", "rust", "should_panic", "edition2015", "edition2018"];
+
 fn has_runnable_doc_test(fn_def: &ast::Fn) -> bool {
     fn_def.doc_comment_text().map_or(false, |comments_text| {
-        comments_text.contains("```")
-            && !comments_text.contains("```ignore")
-            && !comments_text.contains("```no_run")
-            && !comments_text.contains("```compile_fail")
+        let mut in_code_block = false;
+
+        for line in comments_text.lines() {
+            if let Some(header) = line.strip_prefix(RUSTDOC_FENCE) {
+                in_code_block = !in_code_block;
+
+                if in_code_block
+                    && header
+                        .split(',')
+                        .all(|sub| RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE.contains(&sub.trim()))
+                {
+                    return true;
+                }
+            }
+        }
+
+        false
     })
 }
 
@@ -421,7 +438,21 @@ fn main() {}
 /// ```
 /// let x = 5;
 /// ```
-fn foo() {}
+fn should_have_runnable() {}
+
+/// ```edition2018
+/// let x = 5;
+/// ```
+fn should_have_runnable_1() {}
+
+/// ```
+/// let z = 55;
+/// ```
+///
+/// ```ignore
+/// let z = 56;
+/// ```
+fn should_have_runnable_2() {}
 
 /// ```no_run
 /// let z = 55;
@@ -437,8 +468,27 @@ fn should_have_no_runnable_2() {}
 /// let z = 55;
 /// ```
 fn should_have_no_runnable_3() {}
+
+/// ```text
+/// arbitrary plain text
+/// ```
+fn should_have_no_runnable_4() {}
+
+/// ```text
+/// arbitrary plain text
+/// ```
+///
+/// ```sh
+/// $ shell code
+/// ```
+fn should_have_no_runnable_5() {}
+
+/// ```rust,no_run
+/// let z = 55;
+/// ```
+fn should_have_no_runnable_6() {}
 "#,
-            &[&BIN, &DOCTEST],
+            &[&BIN, &DOCTEST, &DOCTEST, &DOCTEST],
             expect![[r#"
                 [
                     Runnable {
@@ -464,9 +514,49 @@ fn should_have_no_runnable_3() {}
                             file_id: FileId(
                                 1,
                             ),
-                            full_range: 15..57,
+                            full_range: 15..74,
                             focus_range: None,
-                            name: "foo",
+                            name: "should_have_runnable",
+                            kind: FN,
+                            container_name: None,
+                            description: None,
+                            docs: None,
+                        },
+                        kind: DocTest {
+                            test_id: Path(
+                                "should_have_runnable",
+                            ),
+                        },
+                        cfg_exprs: [],
+                    },
+                    Runnable {
+                        nav: NavigationTarget {
+                            file_id: FileId(
+                                1,
+                            ),
+                            full_range: 76..148,
+                            focus_range: None,
+                            name: "should_have_runnable_1",
+                            kind: FN,
+                            container_name: None,
+                            description: None,
+                            docs: None,
+                        },
+                        kind: DocTest {
+                            test_id: Path(
+                                "should_have_runnable_1",
+                            ),
+                        },
+                        cfg_exprs: [],
+                    },
+                    Runnable {
+                        nav: NavigationTarget {
+                            file_id: FileId(
+                                1,
+                            ),
+                            full_range: 150..254,
+                            focus_range: None,
+                            name: "should_have_runnable_2",
                             kind: FN,
                             container_name: None,
                             description: None,
@@ -474,7 +564,7 @@ fn should_have_no_runnable_3() {}
                         },
                         kind: DocTest {
                             test_id: Path(
-                                "foo",
+                                "should_have_runnable_2",
                             ),
                         },
                         cfg_exprs: [],
index 76bef45ccc2041d716ccd311825e91ca6179a4f3..968ea55f0cc8ddd9385402c7e88bc58e25705723 100644 (file)
@@ -1,22 +1,32 @@
 //! Transforms markdown
 
+const RUSTDOC_FENCE: &str = "```";
+const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUST_SPECIFIC: &[&str] =
+    &["", "rust", "should_panic", "ignore", "no_run", "compile_fail", "edition2015", "edition2018"];
+
 pub(crate) fn format_docs(src: &str) -> String {
     let mut processed_lines = Vec::new();
     let mut in_code_block = false;
-    for line in src.lines() {
-        if in_code_block && code_line_ignored_by_rustdoc(line) {
+    let mut is_rust = false;
+
+    for mut line in src.lines() {
+        if in_code_block && is_rust && code_line_ignored_by_rustdoc(line) {
             continue;
         }
 
-        if line.starts_with("```") {
-            in_code_block ^= true
-        }
+        if let Some(header) = line.strip_prefix(RUSTDOC_FENCE) {
+            in_code_block ^= true;
 
-        let line = if in_code_block && line.starts_with("```") && !line.contains("rust") {
-            "```rust"
-        } else {
-            line
-        };
+            if in_code_block {
+                is_rust = header
+                    .split(',')
+                    .all(|sub| RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUST_SPECIFIC.contains(&sub.trim()));
+
+                if is_rust {
+                    line = "```rust";
+                }
+            }
+        }
 
         processed_lines.push(line);
     }
@@ -38,6 +48,30 @@ fn test_format_docs_adds_rust() {
         assert_eq!(format_docs(comment), "```rust\nfn some_rust() {}\n```");
     }
 
+    #[test]
+    fn test_format_docs_handles_plain_text() {
+        let comment = "```text\nthis is plain text\n```";
+        assert_eq!(format_docs(comment), "```text\nthis is plain text\n```");
+    }
+
+    #[test]
+    fn test_format_docs_handles_non_rust() {
+        let comment = "```sh\nsupposedly shell code\n```";
+        assert_eq!(format_docs(comment), "```sh\nsupposedly shell code\n```");
+    }
+
+    #[test]
+    fn test_format_docs_handles_rust_alias() {
+        let comment = "```ignore\nlet z = 55;\n```";
+        assert_eq!(format_docs(comment), "```rust\nlet z = 55;\n```");
+    }
+
+    #[test]
+    fn test_format_docs_handles_complex_code_block_attrs() {
+        let comment = "```rust,no_run\nlet z = 55;\n```";
+        assert_eq!(format_docs(comment), "```rust\nlet z = 55;\n```");
+    }
+
     #[test]
     fn test_format_docs_skips_comments_in_rust_block() {
         let comment =
@@ -45,6 +79,16 @@ fn test_format_docs_skips_comments_in_rust_block() {
         assert_eq!(format_docs(comment), "```rust\n#stay1\nstay2\n```");
     }
 
+    #[test]
+    fn test_format_docs_does_not_skip_lines_if_plain_text() {
+        let comment =
+            "```text\n # stay1\n# stay2\n#stay3\nstay4\n#\n #\n   #    \n #\tstay5\n\t#\t\n```";
+        assert_eq!(
+            format_docs(comment),
+            "```text\n # stay1\n# stay2\n#stay3\nstay4\n#\n #\n   #    \n #\tstay5\n\t#\t\n```",
+        );
+    }
+
     #[test]
     fn test_format_docs_keeps_comments_outside_of_rust_block() {
         let comment = " # stay1\n# stay2\n#stay3\nstay4\n#\n #\n   #    \n #\tstay5\n\t#\t";
@@ -72,4 +116,21 @@ fn main(){}
             "```rust\nfn main(){}\n```\nSome comment.\n```rust\nlet a = 1;\n```"
         );
     }
+
+    #[test]
+    fn test_code_blocks_in_comments_marked_as_text() {
+        let comment = r#"```text
+filler
+text
+```
+Some comment.
+```
+let a = 1;
+```"#;
+
+        assert_eq!(
+            format_docs(comment),
+            "```text\nfiller\ntext\n```\nSome comment.\n```rust\nlet a = 1;\n```"
+        );
+    }
 }