about summary refs log tree commit diff
path: root/xtask/src/codegen
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-05-31 10:50:11 +0000
committerGitHub <noreply@github.com>2020-05-31 10:50:11 +0000
commit09df51dab89340bcf4b8ede95c02c32b0c8eb2bc (patch)
tree0240c629fe96243e1a1c91ccd679947bfb1ecb03 /xtask/src/codegen
parent5f7225446e75509ae0d971a6f3e2b9d3e37d6f2a (diff)
parent13a996f3b68c175f6e6ad8d89081e45850dc5583 (diff)
downloadrust-09df51dab89340bcf4b8ede95c02c32b0c8eb2bc.tar.gz
rust-09df51dab89340bcf4b8ede95c02c32b0c8eb2bc.zip
Merge #4664
4664: Generate feature documentation from code r=matklad a=matklad



Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
Diffstat (limited to 'xtask/src/codegen')
-rw-r--r--xtask/src/codegen/gen_assists_docs.rs10
-rw-r--r--xtask/src/codegen/gen_feature_docs.rs88
2 files changed, 91 insertions, 7 deletions
diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs
index 20dcde82068..6ebeb8aea4e 100644
--- a/xtask/src/codegen/gen_assists_docs.rs
+++ b/xtask/src/codegen/gen_assists_docs.rs
@@ -33,22 +33,18 @@ impl Assist {
 
         fn collect_file(acc: &mut Vec<Assist>, path: &Path) -> Result<()> {
             let text = fs::read_to_string(path)?;
-            let comment_blocks = extract_comment_blocks_with_empty_lines(&text);
+            let comment_blocks = extract_comment_blocks_with_empty_lines("Assist", &text);
 
             for block in comment_blocks {
                 // FIXME: doesn't support blank lines yet, need to tweak
                 // `extract_comment_blocks` for that.
-                let mut lines = block.iter();
-                let first_line = lines.next().unwrap();
-                if !first_line.starts_with("Assist: ") {
-                    continue;
-                }
-                let id = first_line["Assist: ".len()..].to_string();
+                let id = block.id;
                 assert!(
                     id.chars().all(|it| it.is_ascii_lowercase() || it == '_'),
                     "invalid assist id: {:?}",
                     id
                 );
+                let mut lines = block.contents.iter();
 
                 let doc = take_until(lines.by_ref(), "```").trim().to_string();
                 assert!(
diff --git a/xtask/src/codegen/gen_feature_docs.rs b/xtask/src/codegen/gen_feature_docs.rs
new file mode 100644
index 00000000000..dbe583e8e4f
--- /dev/null
+++ b/xtask/src/codegen/gen_feature_docs.rs
@@ -0,0 +1,88 @@
+//! Generates `assists.md` documentation.
+
+use std::{fmt, fs, path::PathBuf};
+
+use crate::{
+    codegen::{self, extract_comment_blocks_with_empty_lines, Mode},
+    project_root, rust_files, Result,
+};
+
+pub fn generate_feature_docs(mode: Mode) -> Result<()> {
+    let features = Feature::collect()?;
+    let contents = features.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n");
+    let contents = contents.trim().to_string() + "\n";
+    let dst = project_root().join("docs/user/generated_features.adoc");
+    codegen::update(&dst, &contents, mode)?;
+    Ok(())
+}
+
+#[derive(Debug)]
+struct Feature {
+    id: String,
+    path: PathBuf,
+    doc: String,
+}
+
+impl Feature {
+    fn collect() -> Result<Vec<Feature>> {
+        let mut res = Vec::new();
+        for path in rust_files(&project_root()) {
+            collect_file(&mut res, path)?;
+        }
+        res.sort_by(|lhs, rhs| lhs.id.cmp(&rhs.id));
+        return Ok(res);
+
+        fn collect_file(acc: &mut Vec<Feature>, path: PathBuf) -> Result<()> {
+            let text = fs::read_to_string(&path)?;
+            let comment_blocks = extract_comment_blocks_with_empty_lines("Feature", &text);
+
+            for block in comment_blocks {
+                let id = block.id;
+                assert!(is_valid_feature_name(&id), "invalid feature name: {:?}", id);
+                let doc = block.contents.join("\n");
+                acc.push(Feature { id, path: path.clone(), doc })
+            }
+
+            Ok(())
+        }
+    }
+}
+
+fn is_valid_feature_name(feature: &str) -> bool {
+    'word: for word in feature.split_whitespace() {
+        for &short in ["to", "and"].iter() {
+            if word == short {
+                continue 'word;
+            }
+        }
+        for &short in ["To", "And"].iter() {
+            if word == short {
+                return false;
+            }
+        }
+        if !word.starts_with(char::is_uppercase) {
+            return false;
+        }
+    }
+    true
+}
+
+impl fmt::Display for Feature {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        writeln!(f, "=== {}", self.id)?;
+        let path = self.path.strip_prefix(&project_root()).unwrap().display().to_string();
+        let path = path.replace('\\', "/");
+        let name = self.path.file_name().unwrap();
+
+        //FIXME: generate line number as well
+        writeln!(
+            f,
+            "**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/{}[{}]",
+            path,
+            name.to_str().unwrap(),
+        )?;
+
+        writeln!(f, "{}", self.doc)?;
+        Ok(())
+    }
+}