662: Preserve indentation in doc comments r=matklad a=kjeremy

Fixes #502 

Co-authored-by: Jeremy Kolb <kjeremy@gmail.com>
This commit is contained in:
bors[bot] 2019-01-27 08:21:04 +00:00
commit ffcf618842
4 changed files with 65 additions and 27 deletions

View File

@ -27,10 +27,5 @@ pub trait Docs {
}
pub(crate) fn docs_from_ast(node: &impl ast::DocCommentsOwner) -> Option<Documentation> {
let comments = node.doc_comment_text();
if comments.is_empty() {
None
} else {
Some(Documentation::new(&comments))
}
node.doc_comment_text().map(|it| Documentation::new(&it))
}

View File

@ -126,8 +126,7 @@ impl CallInfo {
};
let mut doc = None;
let docs = node.doc_comment_text();
if !docs.is_empty() {
if let Some(docs) = node.doc_comment_text() {
// Massage markdown
let mut processed_lines = Vec::new();
let mut in_code_block = false;

View File

@ -100,12 +100,7 @@ impl NavigationTarget {
fn docs(&self, db: &RootDatabase) -> Option<String> {
let node = self.node(db)?;
fn doc_comments<N: ast::DocCommentsOwner>(node: &N) -> Option<String> {
let comments = node.doc_comment_text();
if comments.is_empty() {
None
} else {
Some(comments)
}
node.doc_comment_text()
}
visitor()

View File

@ -115,21 +115,38 @@ pub trait DocCommentsOwner: AstNode {
}
/// Returns the textual content of a doc comment block as a single string.
/// That is, strips leading `///` and joins lines
fn doc_comment_text(&self) -> std::string::String {
self.doc_comments()
/// That is, strips leading `///` (+ optional 1 character of whitespace)
/// and joins lines.
fn doc_comment_text(&self) -> Option<std::string::String> {
let docs = self
.doc_comments()
.filter(|comment| comment.is_doc_comment())
.map(|comment| {
let prefix = comment.prefix();
let trimmed = comment
.text()
.as_str()
.trim()
.trim_start_matches(prefix)
.trim_start();
trimmed.to_owned()
let prefix_len = comment.prefix().len();
let line = comment.text().as_str();
// Determine if the prefix or prefix + 1 char is stripped
let pos = if line
.chars()
.nth(prefix_len)
.map(|c| c.is_whitespace())
.unwrap_or(false)
{
prefix_len + 1
} else {
prefix_len
};
line[pos..].to_owned()
})
.join("\n")
.join("\n");
if docs.is_empty() {
None
} else {
Some(docs)
}
}
}
@ -703,6 +720,18 @@ impl BindPat {
}
}
#[test]
fn test_doc_comment_none() {
let file = SourceFile::parse(
r#"
// non-doc
mod foo {}
"#,
);
let module = file.syntax().descendants().find_map(Module::cast).unwrap();
assert!(module.doc_comment_text().is_none());
}
#[test]
fn test_doc_comment_of_items() {
let file = SourceFile::parse(
@ -713,5 +742,25 @@ fn test_doc_comment_of_items() {
"#,
);
let module = file.syntax().descendants().find_map(Module::cast).unwrap();
assert_eq!("doc", module.doc_comment_text());
assert_eq!("doc", module.doc_comment_text().unwrap());
}
#[test]
fn test_doc_comment_preserves_indents() {
let file = SourceFile::parse(
r#"
/// doc1
/// ```
/// fn foo() {
/// // ...
/// }
/// ```
mod foo {}
"#,
);
let module = file.syntax().descendants().find_map(Module::cast).unwrap();
assert_eq!(
"doc1\n```\nfn foo() {\n // ...\n}\n```",
module.doc_comment_text().unwrap()
);
}