aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2018-10-31 19:41:24 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2018-10-31 19:41:24 +0000
commit55ebe6380aef233fff86b7e6cead361787bf1f65 (patch)
tree9ed060e4738a0504ddfd146649b9cf8a2f2fac40 /crates/ra_analysis/src
parentdfba29e4fb66457d101db295e3c356a932ac005e (diff)
parent74320945b664916005d263552194201cbe9a52bc (diff)
Merge #167
167: Attempt to extract useful comments from function signatures r=matklad a=kjeremy I'm trying to extract useful function comments for signature info. This will also be useful for hover. This is a WIP (and actually works pretty well!) but I don't think it's the right approach long term so some guidance would be appreciated so that we could also get comments for say types and variable instances etc. Currently `test_fn_signature_with_simple_doc` fails due to a bug in `extend` but we probably shouldn't use this approach anyway. Maybe comments should be attached to nodes somehow? I'm also thinking that maybe the markdown bits should live in the language server. Thoughts? Co-authored-by: Jeremy A. Kolb <[email protected]>
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() {