aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Aleksanov <[email protected]>2020-10-17 15:06:42 +0100
committerIgor Aleksanov <[email protected]>2020-10-19 18:55:16 +0100
commit52b19c39e8bdbc0a0ed650aa03358768c6803818 (patch)
tree295e9b17874cfc6117dbb852c41ab61bec73e242
parent378dd90bab65fa6df078444c3932118105a460b8 (diff)
Create xtask module to generate diagnostics docs
-rw-r--r--.gitignore1
-rw-r--r--xtask/src/codegen.rs3
-rw-r--r--xtask/src/codegen/gen_diagnostic_docs.rs73
3 files changed, 77 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 472fe1a13..b205bf3fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ crates/*/target
9.vscode/settings.json 9.vscode/settings.json
10generated_assists.adoc 10generated_assists.adoc
11generated_features.adoc 11generated_features.adoc
12generated_diagnostic.adoc
diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs
index 3ee4c1adf..afa703471 100644
--- a/xtask/src/codegen.rs
+++ b/xtask/src/codegen.rs
@@ -10,6 +10,7 @@ mod gen_parser_tests;
10mod gen_assists_docs; 10mod gen_assists_docs;
11mod gen_feature_docs; 11mod gen_feature_docs;
12mod gen_features; 12mod gen_features;
13mod gen_diagnostic_docs;
13 14
14use std::{ 15use std::{
15 fmt, mem, 16 fmt, mem,
@@ -21,6 +22,7 @@ use crate::{ensure_rustfmt, project_root, Result};
21 22
22pub use self::{ 23pub use self::{
23 gen_assists_docs::{generate_assists_docs, generate_assists_tests}, 24 gen_assists_docs::{generate_assists_docs, generate_assists_tests},
25 gen_diagnostic_docs::generate_diagnostic_docs,
24 gen_feature_docs::generate_feature_docs, 26 gen_feature_docs::generate_feature_docs,
25 gen_features::generate_features, 27 gen_features::generate_features,
26 gen_parser_tests::generate_parser_tests, 28 gen_parser_tests::generate_parser_tests,
@@ -47,6 +49,7 @@ impl CodegenCmd {
47 generate_assists_tests(Mode::Overwrite)?; 49 generate_assists_tests(Mode::Overwrite)?;
48 generate_assists_docs(Mode::Overwrite)?; 50 generate_assists_docs(Mode::Overwrite)?;
49 generate_feature_docs(Mode::Overwrite)?; 51 generate_feature_docs(Mode::Overwrite)?;
52 generate_diagnostic_docs(Mode::Overwrite)?;
50 Ok(()) 53 Ok(())
51 } 54 }
52} 55}
diff --git a/xtask/src/codegen/gen_diagnostic_docs.rs b/xtask/src/codegen/gen_diagnostic_docs.rs
new file mode 100644
index 000000000..4d630ce8c
--- /dev/null
+++ b/xtask/src/codegen/gen_diagnostic_docs.rs
@@ -0,0 +1,73 @@
1//! Generates `assists.md` documentation.
2
3use std::{fmt, fs, path::PathBuf};
4
5use crate::{
6 codegen::{self, extract_comment_blocks_with_empty_lines, Location, Mode, PREAMBLE},
7 project_root, rust_files, Result,
8};
9
10pub fn generate_diagnostic_docs(mode: Mode) -> Result<()> {
11 let features = Diagnostic::collect()?;
12 let contents = features.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n");
13 let contents = format!("//{}\n{}\n", PREAMBLE, contents.trim());
14 let dst = project_root().join("docs/user/generated_diagnostic.adoc");
15 codegen::update(&dst, &contents, mode)?;
16 Ok(())
17}
18
19#[derive(Debug)]
20struct Diagnostic {
21 id: String,
22 location: Location,
23 doc: String,
24}
25
26impl Diagnostic {
27 fn collect() -> Result<Vec<Diagnostic>> {
28 let mut res = Vec::new();
29 for path in rust_files(&project_root()) {
30 collect_file(&mut res, path)?;
31 }
32 res.sort_by(|lhs, rhs| lhs.id.cmp(&rhs.id));
33 return Ok(res);
34
35 fn collect_file(acc: &mut Vec<Diagnostic>, path: PathBuf) -> Result<()> {
36 let text = fs::read_to_string(&path)?;
37 let comment_blocks = extract_comment_blocks_with_empty_lines("Diagnostic", &text);
38
39 for block in comment_blocks {
40 let id = block.id;
41 if let Err(msg) = is_valid_diagnostic_name(&id) {
42 panic!("invalid diagnostic name: {:?}:\n {}", id, msg)
43 }
44 let doc = block.contents.join("\n");
45 let location = Location::new(path.clone(), block.line);
46 acc.push(Diagnostic { id, location, doc })
47 }
48
49 Ok(())
50 }
51 }
52}
53
54fn is_valid_diagnostic_name(diagnostic: &str) -> Result<(), String> {
55 let diagnostic = diagnostic.trim();
56 if diagnostic.find(char::is_whitespace).is_some() {
57 return Err("Diagnostic names can't contain whitespace symbols".into());
58 }
59 if diagnostic.chars().any(|c| c.is_ascii_uppercase()) {
60 return Err("Diagnostic names can't contain uppercase symbols".into());
61 }
62 if diagnostic.chars().any(|c| !c.is_ascii()) {
63 return Err("Diagnostic can't contain non-ASCII symbols".into());
64 }
65
66 Ok(())
67}
68
69impl fmt::Display for Diagnostic {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 writeln!(f, "=== {}\n**Source:** {}\n{}", self.id, self.location, self.doc)
72 }
73}