aboutsummaryrefslogtreecommitdiff
path: root/xtask/src/codegen.rs
diff options
context:
space:
mode:
Diffstat (limited to 'xtask/src/codegen.rs')
-rw-r--r--xtask/src/codegen.rs91
1 files changed, 72 insertions, 19 deletions
diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs
index 0e4dcb95a..5511c01d5 100644
--- a/xtask/src/codegen.rs
+++ b/xtask/src/codegen.rs
@@ -8,14 +8,18 @@
8mod gen_syntax; 8mod gen_syntax;
9mod gen_parser_tests; 9mod gen_parser_tests;
10mod gen_assists_docs; 10mod gen_assists_docs;
11mod gen_feature_docs;
11 12
12use std::{mem, path::Path}; 13use std::{
14 fmt, mem,
15 path::{Path, PathBuf},
16};
13 17
14use crate::{not_bash::fs2, Result}; 18use crate::{not_bash::fs2, project_root, Result};
15 19
16pub use self::{ 20pub use self::{
17 gen_assists_docs::generate_assists_docs, gen_parser_tests::generate_parser_tests, 21 gen_assists_docs::generate_assists_docs, gen_feature_docs::generate_feature_docs,
18 gen_syntax::generate_syntax, 22 gen_parser_tests::generate_parser_tests, gen_syntax::generate_syntax,
19}; 23};
20 24
21const GRAMMAR_DIR: &str = "crates/ra_parser/src/grammar"; 25const GRAMMAR_DIR: &str = "crates/ra_parser/src/grammar";
@@ -27,8 +31,7 @@ const AST_NODES: &str = "crates/ra_syntax/src/ast/generated/nodes.rs";
27const AST_TOKENS: &str = "crates/ra_syntax/src/ast/generated/tokens.rs"; 31const AST_TOKENS: &str = "crates/ra_syntax/src/ast/generated/tokens.rs";
28 32
29const ASSISTS_DIR: &str = "crates/ra_assists/src/handlers"; 33const ASSISTS_DIR: &str = "crates/ra_assists/src/handlers";
30const ASSISTS_TESTS: &str = "crates/ra_assists/src/doc_tests/generated.rs"; 34const ASSISTS_TESTS: &str = "crates/ra_assists/src/tests/generated.rs";
31const ASSISTS_DOCS: &str = "docs/user/assists.md";
32 35
33#[derive(Debug, PartialEq, Eq, Clone, Copy)] 36#[derive(Debug, PartialEq, Eq, Clone, Copy)]
34pub enum Mode { 37pub enum Mode {
@@ -40,7 +43,7 @@ pub enum Mode {
40/// With verify = false, 43/// With verify = false,
41fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { 44fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> {
42 match fs2::read_to_string(path) { 45 match fs2::read_to_string(path) {
43 Ok(ref old_contents) if normalize(old_contents) == normalize(contents) => { 46 Ok(old_contents) if normalize(&old_contents) == normalize(contents) => {
44 return Ok(()); 47 return Ok(());
45 } 48 }
46 _ => (), 49 _ => (),
@@ -58,35 +61,85 @@ fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> {
58} 61}
59 62
60fn extract_comment_blocks(text: &str) -> Vec<Vec<String>> { 63fn extract_comment_blocks(text: &str) -> Vec<Vec<String>> {
61 do_extract_comment_blocks(text, false) 64 do_extract_comment_blocks(text, false).into_iter().map(|(_line, block)| block).collect()
65}
66
67fn extract_comment_blocks_with_empty_lines(tag: &str, text: &str) -> Vec<CommentBlock> {
68 assert!(tag.starts_with(char::is_uppercase));
69 let tag = format!("{}:", tag);
70 let mut res = Vec::new();
71 for (line, mut block) in do_extract_comment_blocks(text, true) {
72 let first = block.remove(0);
73 if first.starts_with(&tag) {
74 let id = first[tag.len()..].trim().to_string();
75 let block = CommentBlock { id, line, contents: block };
76 res.push(block);
77 }
78 }
79 res
62} 80}
63 81
64fn extract_comment_blocks_with_empty_lines(text: &str) -> Vec<Vec<String>> { 82struct CommentBlock {
65 do_extract_comment_blocks(text, true) 83 id: String,
84 line: usize,
85 contents: Vec<String>,
66} 86}
67 87
68fn do_extract_comment_blocks(text: &str, allow_blocks_with_empty_lines: bool) -> Vec<Vec<String>> { 88fn do_extract_comment_blocks(
89 text: &str,
90 allow_blocks_with_empty_lines: bool,
91) -> Vec<(usize, Vec<String>)> {
69 let mut res = Vec::new(); 92 let mut res = Vec::new();
70 93
71 let prefix = "// "; 94 let prefix = "// ";
72 let lines = text.lines().map(str::trim_start); 95 let lines = text.lines().map(str::trim_start);
73 96
74 let mut block = vec![]; 97 let mut block = (0, vec![]);
75 for line in lines { 98 for (line_num, line) in lines.enumerate() {
76 if line == "//" && allow_blocks_with_empty_lines { 99 if line == "//" && allow_blocks_with_empty_lines {
77 block.push(String::new()); 100 block.1.push(String::new());
78 continue; 101 continue;
79 } 102 }
80 103
81 let is_comment = line.starts_with(prefix); 104 let is_comment = line.starts_with(prefix);
82 if is_comment { 105 if is_comment {
83 block.push(line[prefix.len()..].to_string()); 106 block.1.push(line[prefix.len()..].to_string());
84 } else if !block.is_empty() { 107 } else {
85 res.push(mem::replace(&mut block, Vec::new())); 108 if !block.1.is_empty() {
109 res.push(mem::take(&mut block));
110 }
111 block.0 = line_num + 2;
86 } 112 }
87 } 113 }
88 if !block.is_empty() { 114 if !block.1.is_empty() {
89 res.push(mem::replace(&mut block, Vec::new())) 115 res.push(block)
90 } 116 }
91 res 117 res
92} 118}
119
120#[derive(Debug)]
121struct Location {
122 file: PathBuf,
123 line: usize,
124}
125
126impl Location {
127 fn new(file: PathBuf, line: usize) -> Self {
128 Self { file, line }
129 }
130}
131
132impl fmt::Display for Location {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 let path = self.file.strip_prefix(&project_root()).unwrap().display().to_string();
135 let path = path.replace('\\', "/");
136 let name = self.file.file_name().unwrap();
137 write!(
138 f,
139 "https://github.com/rust-analyzer/rust-analyzer/blob/master/{}#L{}[{}]",
140 path,
141 self.line,
142 name.to_str().unwrap()
143 )
144 }
145}