aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis/src')
-rw-r--r--crates/ra_analysis/src/descriptors/function/mod.rs60
1 files changed, 57 insertions, 3 deletions
diff --git a/crates/ra_analysis/src/descriptors/function/mod.rs b/crates/ra_analysis/src/descriptors/function/mod.rs
index bb68b0ce7..ae40f3e8f 100644
--- a/crates/ra_analysis/src/descriptors/function/mod.rs
+++ b/crates/ra_analysis/src/descriptors/function/mod.rs
@@ -1,8 +1,11 @@
1pub(super) mod imp; 1pub(super) mod imp;
2mod scope; 2mod scope;
3 3
4use std::cmp::{min, max};
5
4use ra_syntax::{ 6use ra_syntax::{
5 ast::{self, AstNode, NameOwner} 7 ast::{self, AstNode, DocCommentsOwner, NameOwner},
8 TextRange, TextUnit
6}; 9};
7 10
8use crate::{ 11use crate::{
@@ -30,14 +33,17 @@ pub struct FnDescriptor {
30 pub label: String, 33 pub label: String,
31 pub ret_type: Option<String>, 34 pub ret_type: Option<String>,
32 pub params: Vec<String>, 35 pub params: Vec<String>,
36 pub doc: Option<String>
33} 37}
34 38
35impl FnDescriptor { 39impl FnDescriptor {
36 pub fn new(node: ast::FnDef) -> Option<Self> { 40 pub fn new(node: ast::FnDef) -> Option<Self> {
37 let name = node.name()?.text().to_string(); 41 let name = node.name()?.text().to_string();
38 42
43 let mut doc = None;
44
39 // Strip the body out for the label. 45 // Strip the body out for the label.
40 let label: String = if let Some(body) = node.body() { 46 let mut label: String = if let Some(body) = node.body() {
41 let body_range = body.syntax().range(); 47 let body_range = body.syntax().range();
42 let label: String = node 48 let label: String = node
43 .syntax() 49 .syntax()
@@ -50,6 +56,36 @@ impl FnDescriptor {
50 node.syntax().text().to_string() 56 node.syntax().text().to_string()
51 }; 57 };
52 58
59 if let Some((comment_range, docs)) = FnDescriptor::extract_doc_comments(node) {
60 let comment_range = comment_range.checked_sub(node.syntax().range().start()).unwrap();
61 let start = comment_range.start().to_usize();
62 let end = comment_range.end().to_usize();
63
64 // Remove the comment from the label
65 label.replace_range(start..end, "");
66
67 // Massage markdown
68 let mut processed_lines = Vec::new();
69 let mut in_code_block = false;
70 for line in docs.lines() {
71 if line.starts_with("```") {
72 in_code_block = !in_code_block;
73 }
74
75 let line = if in_code_block && line.starts_with("```") && !line.contains("rust") {
76 "```rust".into()
77 } else {
78 line.to_string()
79 };
80
81 processed_lines.push(line);
82 }
83
84 if !processed_lines.is_empty() {
85 doc = Some(processed_lines.join("\n"));
86 }
87 }
88
53 let params = FnDescriptor::param_list(node); 89 let params = FnDescriptor::param_list(node);
54 let ret_type = node.ret_type().map(|r| r.syntax().text().to_string()); 90 let ret_type = node.ret_type().map(|r| r.syntax().text().to_string());
55 91
@@ -57,10 +93,28 @@ impl FnDescriptor {
57 name, 93 name,
58 ret_type, 94 ret_type,
59 params, 95 params,
60 label, 96 label: label.trim().to_owned(),
97 doc
61 }) 98 })
62 } 99 }
63 100
101 fn extract_doc_comments(node: ast::FnDef) -> Option<(TextRange, String)> {
102 if node.doc_comments().count() == 0 {
103 return None;
104 }
105
106 let comment_text = node.doc_comment_text();
107
108 let (begin, end) = node.doc_comments()
109 .map(|comment| comment.syntax().range())
110 .map(|range| (range.start().to_usize(), range.end().to_usize()))
111 .fold((std::usize::MAX, std::usize::MIN), |acc, range| (min(acc.0, range.0), max(acc.1, range.1)));
112
113 let range = TextRange::from_to(TextUnit::from_usize(begin), TextUnit::from_usize(end));
114
115 Some((range, comment_text))
116 }
117
64 fn param_list(node: ast::FnDef) -> Vec<String> { 118 fn param_list(node: ast::FnDef) -> Vec<String> {
65 let mut res = vec![]; 119 let mut res = vec![];
66 if let Some(param_list) = node.param_list() { 120 if let Some(param_list) = node.param_list() {