aboutsummaryrefslogtreecommitdiff
path: root/xtask/src/codegen
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 /xtask/src/codegen
parent378dd90bab65fa6df078444c3932118105a460b8 (diff)
Create xtask module to generate diagnostics docs
Diffstat (limited to 'xtask/src/codegen')
-rw-r--r--xtask/src/codegen/gen_diagnostic_docs.rs73
1 files changed, 73 insertions, 0 deletions
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}