aboutsummaryrefslogtreecommitdiff
path: root/crates/syntax/src
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2021-03-17 13:38:11 +0000
committerLukas Wirth <[email protected]>2021-03-17 13:48:57 +0000
commitec824a92d05caa1908cb25cbd5b969c8e995aaa7 (patch)
tree4d64f1a745735200fbdbc3df564f1471d1b44be1 /crates/syntax/src
parent0fbfab3b45af7a02b1224bca4a53e9b8f6ec049e (diff)
Better handling of block doc comments
Diffstat (limited to 'crates/syntax/src')
-rw-r--r--crates/syntax/src/ast.rs29
-rw-r--r--crates/syntax/src/ast/token_ext.rs19
-rw-r--r--crates/syntax/src/ast/traits.rs16
3 files changed, 29 insertions, 35 deletions
diff --git a/crates/syntax/src/ast.rs b/crates/syntax/src/ast.rs
index 19261686c..38e0b04ef 100644
--- a/crates/syntax/src/ast.rs
+++ b/crates/syntax/src/ast.rs
@@ -118,7 +118,7 @@ fn test_doc_comment_none() {
118 .ok() 118 .ok()
119 .unwrap(); 119 .unwrap();
120 let module = file.syntax().descendants().find_map(Module::cast).unwrap(); 120 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
121 assert!(module.doc_comment_text().is_none()); 121 assert!(module.doc_comments().doc_comment_text().is_none());
122} 122}
123 123
124#[test] 124#[test]
@@ -133,7 +133,7 @@ fn test_outer_doc_comment_of_items() {
133 .ok() 133 .ok()
134 .unwrap(); 134 .unwrap();
135 let module = file.syntax().descendants().find_map(Module::cast).unwrap(); 135 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
136 assert_eq!("doc", module.doc_comment_text().unwrap()); 136 assert_eq!(" doc", module.doc_comments().doc_comment_text().unwrap());
137} 137}
138 138
139#[test] 139#[test]
@@ -148,7 +148,7 @@ fn test_inner_doc_comment_of_items() {
148 .ok() 148 .ok()
149 .unwrap(); 149 .unwrap();
150 let module = file.syntax().descendants().find_map(Module::cast).unwrap(); 150 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
151 assert!(module.doc_comment_text().is_none()); 151 assert!(module.doc_comments().doc_comment_text().is_none());
152} 152}
153 153
154#[test] 154#[test]
@@ -162,7 +162,7 @@ fn test_doc_comment_of_statics() {
162 .ok() 162 .ok()
163 .unwrap(); 163 .unwrap();
164 let st = file.syntax().descendants().find_map(Static::cast).unwrap(); 164 let st = file.syntax().descendants().find_map(Static::cast).unwrap();
165 assert_eq!("Number of levels", st.doc_comment_text().unwrap()); 165 assert_eq!(" Number of levels", st.doc_comments().doc_comment_text().unwrap());
166} 166}
167 167
168#[test] 168#[test]
@@ -181,7 +181,10 @@ fn test_doc_comment_preserves_indents() {
181 .ok() 181 .ok()
182 .unwrap(); 182 .unwrap();
183 let module = file.syntax().descendants().find_map(Module::cast).unwrap(); 183 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
184 assert_eq!("doc1\n```\nfn foo() {\n // ...\n}\n```", module.doc_comment_text().unwrap()); 184 assert_eq!(
185 " doc1\n ```\n fn foo() {\n // ...\n }\n ```",
186 module.doc_comments().doc_comment_text().unwrap()
187 );
185} 188}
186 189
187#[test] 190#[test]
@@ -198,7 +201,7 @@ fn test_doc_comment_preserves_newlines() {
198 .ok() 201 .ok()
199 .unwrap(); 202 .unwrap();
200 let module = file.syntax().descendants().find_map(Module::cast).unwrap(); 203 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
201 assert_eq!("this\nis\nmod\nfoo", module.doc_comment_text().unwrap()); 204 assert_eq!(" this\n is\n mod\n foo", module.doc_comments().doc_comment_text().unwrap());
202} 205}
203 206
204#[test] 207#[test]
@@ -212,7 +215,7 @@ fn test_doc_comment_single_line_block_strips_suffix() {
212 .ok() 215 .ok()
213 .unwrap(); 216 .unwrap();
214 let module = file.syntax().descendants().find_map(Module::cast).unwrap(); 217 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
215 assert_eq!("this is mod foo", module.doc_comment_text().unwrap()); 218 assert_eq!(" this is mod foo", module.doc_comments().doc_comment_text().unwrap());
216} 219}
217 220
218#[test] 221#[test]
@@ -226,7 +229,7 @@ fn test_doc_comment_single_line_block_strips_suffix_whitespace() {
226 .ok() 229 .ok()
227 .unwrap(); 230 .unwrap();
228 let module = file.syntax().descendants().find_map(Module::cast).unwrap(); 231 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
229 assert_eq!("this is mod foo ", module.doc_comment_text().unwrap()); 232 assert_eq!(" this is mod foo ", module.doc_comments().doc_comment_text().unwrap());
230} 233}
231 234
232#[test] 235#[test]
@@ -245,8 +248,8 @@ fn test_doc_comment_multi_line_block_strips_suffix() {
245 .unwrap(); 248 .unwrap();
246 let module = file.syntax().descendants().find_map(Module::cast).unwrap(); 249 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
247 assert_eq!( 250 assert_eq!(
248 " this\n is\n mod foo\n ", 251 "\n this\n is\n mod foo\n ",
249 module.doc_comment_text().unwrap() 252 module.doc_comments().doc_comment_text().unwrap()
250 ); 253 );
251} 254}
252 255
@@ -259,8 +262,8 @@ fn test_comments_preserve_trailing_whitespace() {
259 .unwrap(); 262 .unwrap();
260 let def = file.syntax().descendants().find_map(Struct::cast).unwrap(); 263 let def = file.syntax().descendants().find_map(Struct::cast).unwrap();
261 assert_eq!( 264 assert_eq!(
262 "Representation of a Realm. \nIn the specification these are called Realm Records.", 265 " Representation of a Realm. \n In the specification these are called Realm Records.",
263 def.doc_comment_text().unwrap() 266 def.doc_comments().doc_comment_text().unwrap()
264 ); 267 );
265} 268}
266 269
@@ -276,7 +279,7 @@ fn test_four_slash_line_comment() {
276 .ok() 279 .ok()
277 .unwrap(); 280 .unwrap();
278 let module = file.syntax().descendants().find_map(Module::cast).unwrap(); 281 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
279 assert_eq!("doc comment", module.doc_comment_text().unwrap()); 282 assert_eq!(" doc comment", module.doc_comments().doc_comment_text().unwrap());
280} 283}
281 284
282#[test] 285#[test]
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index 977eb8181..6c242d126 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -33,23 +33,20 @@ impl ast::Comment {
33 prefix 33 prefix
34 } 34 }
35 35
36 /// Returns the textual content of a doc comment block as a single string. 36 /// Returns the textual content of a doc comment node as a single string with prefix and suffix
37 /// That is, strips leading `///` (+ optional 1 character of whitespace), 37 /// removed.
38 /// trailing `*/`, trailing whitespace and then joins the lines.
39 pub fn doc_comment(&self) -> Option<&str> { 38 pub fn doc_comment(&self) -> Option<&str> {
40 let kind = self.kind(); 39 let kind = self.kind();
41 match kind { 40 match kind {
42 CommentKind { shape, doc: Some(_) } => { 41 CommentKind { shape, doc: Some(_) } => {
43 let prefix = kind.prefix(); 42 let prefix = kind.prefix();
44 let text = &self.text()[prefix.len()..]; 43 let text = &self.text()[prefix.len()..];
45 let ws = text.chars().next().filter(|c| c.is_whitespace()); 44 let text = if shape == CommentShape::Block {
46 let text = ws.map_or(text, |ws| &text[ws.len_utf8()..]); 45 text.strip_suffix("*/").unwrap_or(text)
47 match shape { 46 } else {
48 CommentShape::Block if text.ends_with("*/") => { 47 text
49 Some(&text[..text.len() - "*/".len()]) 48 };
50 } 49 Some(text)
51 _ => Some(text),
52 }
53 } 50 }
54 _ => None, 51 _ => None,
55 } 52 }
diff --git a/crates/syntax/src/ast/traits.rs b/crates/syntax/src/ast/traits.rs
index 96d4cc997..ddd213637 100644
--- a/crates/syntax/src/ast/traits.rs
+++ b/crates/syntax/src/ast/traits.rs
@@ -1,8 +1,6 @@
1//! Various traits that are implemented by ast nodes. 1//! Various traits that are implemented by ast nodes.
2//! 2//!
3//! The implementations are usually trivial, and live in generated.rs 3//! The implementations are usually trivial, and live in generated.rs
4use itertools::Itertools;
5
6use crate::{ 4use crate::{
7 ast::{self, support, AstChildren, AstNode, AstToken}, 5 ast::{self, support, AstChildren, AstNode, AstToken},
8 syntax_node::SyntaxElementChildren, 6 syntax_node::SyntaxElementChildren,
@@ -76,10 +74,6 @@ pub trait DocCommentsOwner: AttrsOwner {
76 fn doc_comments(&self) -> CommentIter { 74 fn doc_comments(&self) -> CommentIter {
77 CommentIter { iter: self.syntax().children_with_tokens() } 75 CommentIter { iter: self.syntax().children_with_tokens() }
78 } 76 }
79
80 fn doc_comment_text(&self) -> Option<String> {
81 self.doc_comments().doc_comment_text()
82 }
83} 77}
84 78
85impl CommentIter { 79impl CommentIter {
@@ -87,12 +81,12 @@ impl CommentIter {
87 CommentIter { iter: syntax_node.children_with_tokens() } 81 CommentIter { iter: syntax_node.children_with_tokens() }
88 } 82 }
89 83
90 /// Returns the textual content of a doc comment block as a single string. 84 #[cfg(test)]
91 /// That is, strips leading `///` (+ optional 1 character of whitespace),
92 /// trailing `*/`, trailing whitespace and then joins the lines.
93 pub fn doc_comment_text(self) -> Option<String> { 85 pub fn doc_comment_text(self) -> Option<String> {
94 let docs = 86 let docs = itertools::Itertools::join(
95 self.filter_map(|comment| comment.doc_comment().map(ToOwned::to_owned)).join("\n"); 87 &mut self.filter_map(|comment| comment.doc_comment().map(ToOwned::to_owned)),
88 "\n",
89 );
96 if docs.is_empty() { 90 if docs.is_empty() {
97 None 91 None
98 } else { 92 } else {