diff options
Diffstat (limited to 'xtask')
-rw-r--r-- | xtask/src/ast_src.rs | 2 | ||||
-rw-r--r-- | xtask/src/codegen.rs | 66 | ||||
-rw-r--r-- | xtask/src/codegen/gen_assists_docs.rs | 73 | ||||
-rw-r--r-- | xtask/src/codegen/gen_feature_docs.rs | 23 | ||||
-rw-r--r-- | xtask/src/lib.rs | 6 |
5 files changed, 100 insertions, 70 deletions
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs index d4621930e..f60f0fb16 100644 --- a/xtask/src/ast_src.rs +++ b/xtask/src/ast_src.rs | |||
@@ -1058,7 +1058,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc { | |||
1058 | /// [Reference](https://doc.rust-lang.org/reference/expressions/block-expr.html) | 1058 | /// [Reference](https://doc.rust-lang.org/reference/expressions/block-expr.html) |
1059 | /// [Labels for blocks RFC](https://github.com/rust-lang/rfcs/blob/master/text/2046-label-break-value.md) | 1059 | /// [Labels for blocks RFC](https://github.com/rust-lang/rfcs/blob/master/text/2046-label-break-value.md) |
1060 | struct BlockExpr: AttrsOwner, ModuleItemOwner { | 1060 | struct BlockExpr: AttrsOwner, ModuleItemOwner { |
1061 | T!['{'], statements: [Stmt], Expr, T!['}'], | 1061 | Label, T!['{'], statements: [Stmt], Expr, T!['}'], |
1062 | } | 1062 | } |
1063 | 1063 | ||
1064 | /// Return expression. | 1064 | /// Return expression. |
diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs index f47d54125..5511c01d5 100644 --- a/xtask/src/codegen.rs +++ b/xtask/src/codegen.rs | |||
@@ -10,9 +10,12 @@ mod gen_parser_tests; | |||
10 | mod gen_assists_docs; | 10 | mod gen_assists_docs; |
11 | mod gen_feature_docs; | 11 | mod gen_feature_docs; |
12 | 12 | ||
13 | use std::{mem, path::Path}; | 13 | use std::{ |
14 | fmt, mem, | ||
15 | path::{Path, PathBuf}, | ||
16 | }; | ||
14 | 17 | ||
15 | use crate::{not_bash::fs2, Result}; | 18 | use crate::{not_bash::fs2, project_root, Result}; |
16 | 19 | ||
17 | pub use self::{ | 20 | pub use self::{ |
18 | gen_assists_docs::generate_assists_docs, gen_feature_docs::generate_feature_docs, | 21 | gen_assists_docs::generate_assists_docs, gen_feature_docs::generate_feature_docs, |
@@ -29,7 +32,6 @@ const AST_TOKENS: &str = "crates/ra_syntax/src/ast/generated/tokens.rs"; | |||
29 | 32 | ||
30 | const ASSISTS_DIR: &str = "crates/ra_assists/src/handlers"; | 33 | const ASSISTS_DIR: &str = "crates/ra_assists/src/handlers"; |
31 | const ASSISTS_TESTS: &str = "crates/ra_assists/src/tests/generated.rs"; | 34 | const ASSISTS_TESTS: &str = "crates/ra_assists/src/tests/generated.rs"; |
32 | const ASSISTS_DOCS: &str = "docs/user/assists.md"; | ||
33 | 35 | ||
34 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 36 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
35 | pub enum Mode { | 37 | pub enum Mode { |
@@ -59,18 +61,18 @@ fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { | |||
59 | } | 61 | } |
60 | 62 | ||
61 | fn extract_comment_blocks(text: &str) -> Vec<Vec<String>> { | 63 | fn extract_comment_blocks(text: &str) -> Vec<Vec<String>> { |
62 | do_extract_comment_blocks(text, false) | 64 | do_extract_comment_blocks(text, false).into_iter().map(|(_line, block)| block).collect() |
63 | } | 65 | } |
64 | 66 | ||
65 | fn extract_comment_blocks_with_empty_lines(tag: &str, text: &str) -> Vec<CommentBlock> { | 67 | fn extract_comment_blocks_with_empty_lines(tag: &str, text: &str) -> Vec<CommentBlock> { |
66 | assert!(tag.starts_with(char::is_uppercase)); | 68 | assert!(tag.starts_with(char::is_uppercase)); |
67 | let tag = format!("{}:", tag); | 69 | let tag = format!("{}:", tag); |
68 | let mut res = Vec::new(); | 70 | let mut res = Vec::new(); |
69 | for mut block in do_extract_comment_blocks(text, true) { | 71 | for (line, mut block) in do_extract_comment_blocks(text, true) { |
70 | let first = block.remove(0); | 72 | let first = block.remove(0); |
71 | if first.starts_with(&tag) { | 73 | if first.starts_with(&tag) { |
72 | let id = first[tag.len()..].trim().to_string(); | 74 | let id = first[tag.len()..].trim().to_string(); |
73 | let block = CommentBlock { id, contents: block }; | 75 | let block = CommentBlock { id, line, contents: block }; |
74 | res.push(block); | 76 | res.push(block); |
75 | } | 77 | } |
76 | } | 78 | } |
@@ -79,31 +81,65 @@ fn extract_comment_blocks_with_empty_lines(tag: &str, text: &str) -> Vec<Comment | |||
79 | 81 | ||
80 | struct CommentBlock { | 82 | struct CommentBlock { |
81 | id: String, | 83 | id: String, |
84 | line: usize, | ||
82 | contents: Vec<String>, | 85 | contents: Vec<String>, |
83 | } | 86 | } |
84 | 87 | ||
85 | fn do_extract_comment_blocks(text: &str, allow_blocks_with_empty_lines: bool) -> Vec<Vec<String>> { | 88 | fn do_extract_comment_blocks( |
89 | text: &str, | ||
90 | allow_blocks_with_empty_lines: bool, | ||
91 | ) -> Vec<(usize, Vec<String>)> { | ||
86 | let mut res = Vec::new(); | 92 | let mut res = Vec::new(); |
87 | 93 | ||
88 | let prefix = "// "; | 94 | let prefix = "// "; |
89 | let lines = text.lines().map(str::trim_start); | 95 | let lines = text.lines().map(str::trim_start); |
90 | 96 | ||
91 | let mut block = vec![]; | 97 | let mut block = (0, vec![]); |
92 | for line in lines { | 98 | for (line_num, line) in lines.enumerate() { |
93 | if line == "//" && allow_blocks_with_empty_lines { | 99 | if line == "//" && allow_blocks_with_empty_lines { |
94 | block.push(String::new()); | 100 | block.1.push(String::new()); |
95 | continue; | 101 | continue; |
96 | } | 102 | } |
97 | 103 | ||
98 | let is_comment = line.starts_with(prefix); | 104 | let is_comment = line.starts_with(prefix); |
99 | if is_comment { | 105 | if is_comment { |
100 | block.push(line[prefix.len()..].to_string()); | 106 | block.1.push(line[prefix.len()..].to_string()); |
101 | } else if !block.is_empty() { | 107 | } else { |
102 | 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; | ||
103 | } | 112 | } |
104 | } | 113 | } |
105 | if !block.is_empty() { | 114 | if !block.1.is_empty() { |
106 | res.push(mem::replace(&mut block, Vec::new())) | 115 | res.push(block) |
107 | } | 116 | } |
108 | res | 117 | res |
109 | } | 118 | } |
119 | |||
120 | #[derive(Debug)] | ||
121 | struct Location { | ||
122 | file: PathBuf, | ||
123 | line: usize, | ||
124 | } | ||
125 | |||
126 | impl Location { | ||
127 | fn new(file: PathBuf, line: usize) -> Self { | ||
128 | Self { file, line } | ||
129 | } | ||
130 | } | ||
131 | |||
132 | impl 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 | } | ||
diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs index 6ebeb8aea..6c1be5350 100644 --- a/xtask/src/codegen/gen_assists_docs.rs +++ b/xtask/src/codegen/gen_assists_docs.rs | |||
@@ -1,22 +1,28 @@ | |||
1 | //! Generates `assists.md` documentation. | 1 | //! Generates `assists.md` documentation. |
2 | 2 | ||
3 | use std::{fs, path::Path}; | 3 | use std::{fmt, fs, path::Path}; |
4 | 4 | ||
5 | use crate::{ | 5 | use crate::{ |
6 | codegen::{self, extract_comment_blocks_with_empty_lines, Mode}, | 6 | codegen::{self, extract_comment_blocks_with_empty_lines, Location, Mode}, |
7 | project_root, rust_files, Result, | 7 | project_root, rust_files, Result, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | pub fn generate_assists_docs(mode: Mode) -> Result<()> { | 10 | pub fn generate_assists_docs(mode: Mode) -> Result<()> { |
11 | let assists = Assist::collect()?; | 11 | let assists = Assist::collect()?; |
12 | generate_tests(&assists, mode)?; | 12 | generate_tests(&assists, mode)?; |
13 | generate_docs(&assists, mode)?; | 13 | |
14 | let contents = assists.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n"); | ||
15 | let contents = contents.trim().to_string() + "\n"; | ||
16 | let dst = project_root().join("docs/user/generated_assists.adoc"); | ||
17 | codegen::update(&dst, &contents, mode)?; | ||
18 | |||
14 | Ok(()) | 19 | Ok(()) |
15 | } | 20 | } |
16 | 21 | ||
17 | #[derive(Debug)] | 22 | #[derive(Debug)] |
18 | struct Assist { | 23 | struct Assist { |
19 | id: String, | 24 | id: String, |
25 | location: Location, | ||
20 | doc: String, | 26 | doc: String, |
21 | before: String, | 27 | before: String, |
22 | after: String, | 28 | after: String, |
@@ -58,7 +64,8 @@ impl Assist { | |||
58 | assert_eq!(lines.next().unwrap().as_str(), "->"); | 64 | assert_eq!(lines.next().unwrap().as_str(), "->"); |
59 | assert_eq!(lines.next().unwrap().as_str(), "```"); | 65 | assert_eq!(lines.next().unwrap().as_str(), "```"); |
60 | let after = take_until(lines.by_ref(), "```"); | 66 | let after = take_until(lines.by_ref(), "```"); |
61 | acc.push(Assist { id, doc, before, after }) | 67 | let location = Location::new(path.to_path_buf(), block.line); |
68 | acc.push(Assist { id, location, doc, before, after }) | ||
62 | } | 69 | } |
63 | 70 | ||
64 | fn take_until<'a>(lines: impl Iterator<Item = &'a String>, marker: &str) -> String { | 71 | fn take_until<'a>(lines: impl Iterator<Item = &'a String>, marker: &str) -> String { |
@@ -76,6 +83,33 @@ impl Assist { | |||
76 | } | 83 | } |
77 | } | 84 | } |
78 | 85 | ||
86 | impl fmt::Display for Assist { | ||
87 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
88 | let before = self.before.replace("<|>", "┃"); // Unicode pseudo-graphics bar | ||
89 | let after = self.after.replace("<|>", "┃"); | ||
90 | writeln!( | ||
91 | f, | ||
92 | "[discrete]\n=== `{}` | ||
93 | **Source:** {} | ||
94 | |||
95 | {} | ||
96 | |||
97 | .Before | ||
98 | ```rust | ||
99 | {}``` | ||
100 | |||
101 | .After | ||
102 | ```rust | ||
103 | {}```", | ||
104 | self.id, | ||
105 | self.location, | ||
106 | self.doc, | ||
107 | hide_hash_comments(&before), | ||
108 | hide_hash_comments(&after) | ||
109 | ) | ||
110 | } | ||
111 | } | ||
112 | |||
79 | fn generate_tests(assists: &[Assist], mode: Mode) -> Result<()> { | 113 | fn generate_tests(assists: &[Assist], mode: Mode) -> Result<()> { |
80 | let mut buf = String::from("use super::check_doc_test;\n"); | 114 | let mut buf = String::from("use super::check_doc_test;\n"); |
81 | 115 | ||
@@ -103,37 +137,6 @@ r#####" | |||
103 | codegen::update(&project_root().join(codegen::ASSISTS_TESTS), &buf, mode) | 137 | codegen::update(&project_root().join(codegen::ASSISTS_TESTS), &buf, mode) |
104 | } | 138 | } |
105 | 139 | ||
106 | fn generate_docs(assists: &[Assist], mode: Mode) -> Result<()> { | ||
107 | let mut buf = String::from( | ||
108 | "# Assists\n\nCursor position or selection is signified by `┃` character.\n\n", | ||
109 | ); | ||
110 | |||
111 | for assist in assists { | ||
112 | let before = assist.before.replace("<|>", "┃"); // Unicode pseudo-graphics bar | ||
113 | let after = assist.after.replace("<|>", "┃"); | ||
114 | let docs = format!( | ||
115 | " | ||
116 | ## `{}` | ||
117 | |||
118 | {} | ||
119 | |||
120 | ```rust | ||
121 | // BEFORE | ||
122 | {} | ||
123 | // AFTER | ||
124 | {}``` | ||
125 | ", | ||
126 | assist.id, | ||
127 | assist.doc, | ||
128 | hide_hash_comments(&before), | ||
129 | hide_hash_comments(&after) | ||
130 | ); | ||
131 | buf.push_str(&docs); | ||
132 | } | ||
133 | |||
134 | codegen::update(&project_root().join(codegen::ASSISTS_DOCS), &buf, mode) | ||
135 | } | ||
136 | |||
137 | fn hide_hash_comments(text: &str) -> String { | 140 | fn hide_hash_comments(text: &str) -> String { |
138 | text.split('\n') // want final newline | 141 | text.split('\n') // want final newline |
139 | .filter(|&it| !(it.starts_with("# ") || it == "#")) | 142 | .filter(|&it| !(it.starts_with("# ") || it == "#")) |
diff --git a/xtask/src/codegen/gen_feature_docs.rs b/xtask/src/codegen/gen_feature_docs.rs index dbe583e8e..31bc3839d 100644 --- a/xtask/src/codegen/gen_feature_docs.rs +++ b/xtask/src/codegen/gen_feature_docs.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use std::{fmt, fs, path::PathBuf}; | 3 | use std::{fmt, fs, path::PathBuf}; |
4 | 4 | ||
5 | use crate::{ | 5 | use crate::{ |
6 | codegen::{self, extract_comment_blocks_with_empty_lines, Mode}, | 6 | codegen::{self, extract_comment_blocks_with_empty_lines, Location, Mode}, |
7 | project_root, rust_files, Result, | 7 | project_root, rust_files, Result, |
8 | }; | 8 | }; |
9 | 9 | ||
@@ -19,7 +19,7 @@ pub fn generate_feature_docs(mode: Mode) -> Result<()> { | |||
19 | #[derive(Debug)] | 19 | #[derive(Debug)] |
20 | struct Feature { | 20 | struct Feature { |
21 | id: String, | 21 | id: String, |
22 | path: PathBuf, | 22 | location: Location, |
23 | doc: String, | 23 | doc: String, |
24 | } | 24 | } |
25 | 25 | ||
@@ -40,7 +40,8 @@ impl Feature { | |||
40 | let id = block.id; | 40 | let id = block.id; |
41 | assert!(is_valid_feature_name(&id), "invalid feature name: {:?}", id); | 41 | assert!(is_valid_feature_name(&id), "invalid feature name: {:?}", id); |
42 | let doc = block.contents.join("\n"); | 42 | let doc = block.contents.join("\n"); |
43 | acc.push(Feature { id, path: path.clone(), doc }) | 43 | let location = Location::new(path.clone(), block.line); |
44 | acc.push(Feature { id, location, doc }) | ||
44 | } | 45 | } |
45 | 46 | ||
46 | Ok(()) | 47 | Ok(()) |
@@ -69,20 +70,6 @@ fn is_valid_feature_name(feature: &str) -> bool { | |||
69 | 70 | ||
70 | impl fmt::Display for Feature { | 71 | impl fmt::Display for Feature { |
71 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 72 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
72 | writeln!(f, "=== {}", self.id)?; | 73 | writeln!(f, "=== {}\n**Source:** {}\n{}", self.id, self.location, self.doc) |
73 | let path = self.path.strip_prefix(&project_root()).unwrap().display().to_string(); | ||
74 | let path = path.replace('\\', "/"); | ||
75 | let name = self.path.file_name().unwrap(); | ||
76 | |||
77 | //FIXME: generate line number as well | ||
78 | writeln!( | ||
79 | f, | ||
80 | "**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/{}[{}]", | ||
81 | path, | ||
82 | name.to_str().unwrap(), | ||
83 | )?; | ||
84 | |||
85 | writeln!(f, "{}", self.doc)?; | ||
86 | Ok(()) | ||
87 | } | 74 | } |
88 | } | 75 | } |
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index 2b7a461e5..874957885 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs | |||
@@ -191,7 +191,11 @@ Release: release:{}[] | |||
191 | let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n)); | 191 | let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n)); |
192 | fs2::write(&path, &contents)?; | 192 | fs2::write(&path, &contents)?; |
193 | 193 | ||
194 | fs2::copy(project_root().join("./docs/user/readme.adoc"), website_root.join("manual.adoc"))?; | 194 | for &adoc in ["manual.adoc", "generated_features.adoc", "generated_assists.adoc"].iter() { |
195 | let src = project_root().join("./docs/user/").join(adoc); | ||
196 | let dst = website_root.join(adoc); | ||
197 | fs2::copy(src, dst)?; | ||
198 | } | ||
195 | 199 | ||
196 | let tags = run!("git tag --list"; echo = false)?; | 200 | let tags = run!("git tag --list"; echo = false)?; |
197 | let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap(); | 201 | let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap(); |