aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src
diff options
context:
space:
mode:
authorJeremy Kolb <[email protected]>2019-01-30 02:39:09 +0000
committerJeremy Kolb <[email protected]>2019-01-30 02:39:09 +0000
commitb88ba007cc2631799c2334753a7de807c548685e (patch)
tree0cbc02b9f764fdd8ff26e22135af281d3cbbd57f /crates/ra_ide_api/src
parent48d2acb297459fb06cbb49bdce2eccb4c2591714 (diff)
Pass Documentation up to LSP and add "rust" to our codeblocks there
Diffstat (limited to 'crates/ra_ide_api/src')
-rw-r--r--crates/ra_ide_api/src/call_info.rs66
-rw-r--r--crates/ra_ide_api/src/completion.rs19
-rw-r--r--crates/ra_ide_api/src/completion/completion_item.rs35
-rw-r--r--crates/ra_ide_api/src/lib.rs3
4 files changed, 49 insertions, 74 deletions
diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs
index ee1e13799..2eb388e0e 100644
--- a/crates/ra_ide_api/src/call_info.rs
+++ b/crates/ra_ide_api/src/call_info.rs
@@ -3,9 +3,10 @@ use ra_db::SourceDatabase;
3use ra_syntax::{ 3use ra_syntax::{
4 AstNode, SyntaxNode, TextUnit, TextRange, 4 AstNode, SyntaxNode, TextUnit, TextRange,
5 SyntaxKind::FN_DEF, 5 SyntaxKind::FN_DEF,
6 ast::{self, ArgListOwner, DocCommentsOwner}, 6 ast::{self, ArgListOwner},
7 algo::find_node_at_offset, 7 algo::find_node_at_offset,
8}; 8};
9use hir::Docs;
9 10
10use crate::{FilePosition, CallInfo, db::RootDatabase}; 11use crate::{FilePosition, CallInfo, db::RootDatabase};
11 12
@@ -26,7 +27,9 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
26 let fn_file = db.parse(symbol.file_id); 27 let fn_file = db.parse(symbol.file_id);
27 let fn_def = symbol.ptr.to_node(&fn_file); 28 let fn_def = symbol.ptr.to_node(&fn_file);
28 let fn_def = ast::FnDef::cast(fn_def).unwrap(); 29 let fn_def = ast::FnDef::cast(fn_def).unwrap();
29 let mut call_info = CallInfo::new(fn_def)?; 30 let function = hir::source_binder::function_from_source(db, symbol.file_id, fn_def)?;
31
32 let mut call_info = CallInfo::new(db, function, fn_def)?;
30 // If we have a calling expression let's find which argument we are on 33 // If we have a calling expression let's find which argument we are on
31 let num_params = call_info.parameters.len(); 34 let num_params = call_info.parameters.len();
32 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some(); 35 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some();
@@ -110,46 +113,13 @@ impl<'a> FnCallNode<'a> {
110} 113}
111 114
112impl CallInfo { 115impl CallInfo {
113 fn new(node: &ast::FnDef) -> Option<Self> { 116 fn new(db: &RootDatabase, function: hir::Function, node: &ast::FnDef) -> Option<Self> {
114 let label: String = if let Some(body) = node.body() { 117 let label = crate::completion::function_label(node)?;
115 let body_range = body.syntax().range(); 118 let doc = function.docs(db);
116 let label: String = node
117 .syntax()
118 .children()
119 .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body
120 .filter(|child| ast::Comment::cast(child).is_none()) // Filter out doc comments
121 .map(|node| node.text().to_string())
122 .collect();
123 label
124 } else {
125 node.syntax().text().to_string()
126 };
127
128 let mut doc = None;
129 if let Some(docs) = node.doc_comment_text() {
130 // Massage markdown
131 let mut processed_lines = Vec::new();
132 let mut in_code_block = false;
133 for line in docs.lines() {
134 if line.starts_with("```") {
135 in_code_block = !in_code_block;
136 }
137
138 let line = if in_code_block && line.starts_with("```") && !line.contains("rust") {
139 "```rust".into()
140 } else {
141 line.to_string()
142 };
143
144 processed_lines.push(line);
145 }
146
147 doc = Some(processed_lines.join("\n"));
148 }
149 119
150 Some(CallInfo { 120 Some(CallInfo {
151 parameters: param_list(node), 121 parameters: param_list(node),
152 label: label.trim().to_owned(), 122 label,
153 doc, 123 doc,
154 active_parameter: None, 124 active_parameter: None,
155 }) 125 })
@@ -284,7 +254,7 @@ fn bar() {
284 assert_eq!(info.parameters, vec!["j".to_string()]); 254 assert_eq!(info.parameters, vec!["j".to_string()]);
285 assert_eq!(info.active_parameter, Some(0)); 255 assert_eq!(info.active_parameter, Some(0));
286 assert_eq!(info.label, "fn foo(j: u32) -> u32".to_string()); 256 assert_eq!(info.label, "fn foo(j: u32) -> u32".to_string());
287 assert_eq!(info.doc, Some("test".into())); 257 assert_eq!(info.doc.map(|it| it.into()), Some("test".to_string()));
288 } 258 }
289 259
290 #[test] 260 #[test]
@@ -313,18 +283,18 @@ pub fn do() {
313 assert_eq!(info.active_parameter, Some(0)); 283 assert_eq!(info.active_parameter, Some(0));
314 assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string()); 284 assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string());
315 assert_eq!( 285 assert_eq!(
316 info.doc, 286 info.doc.map(|it| it.into()),
317 Some( 287 Some(
318 r#"Adds one to the number given. 288 r#"Adds one to the number given.
319 289
320# Examples 290# Examples
321 291
322```rust 292```
323let five = 5; 293let five = 5;
324 294
325assert_eq!(6, my_crate::add_one(5)); 295assert_eq!(6, my_crate::add_one(5));
326```"# 296```"#
327 .into() 297 .to_string()
328 ) 298 )
329 ); 299 );
330 } 300 }
@@ -359,18 +329,18 @@ pub fn do_it() {
359 assert_eq!(info.active_parameter, Some(0)); 329 assert_eq!(info.active_parameter, Some(0));
360 assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string()); 330 assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string());
361 assert_eq!( 331 assert_eq!(
362 info.doc, 332 info.doc.map(|it| it.into()),
363 Some( 333 Some(
364 r#"Adds one to the number given. 334 r#"Adds one to the number given.
365 335
366# Examples 336# Examples
367 337
368```rust 338```
369let five = 5; 339let five = 5;
370 340
371assert_eq!(6, my_crate::add_one(5)); 341assert_eq!(6, my_crate::add_one(5));
372```"# 342```"#
373 .into() 343 .to_string()
374 ) 344 )
375 ); 345 );
376 } 346 }
@@ -414,12 +384,12 @@ pub fn foo() {
414 ); 384 );
415 assert_eq!(info.active_parameter, Some(1)); 385 assert_eq!(info.active_parameter, Some(1));
416 assert_eq!( 386 assert_eq!(
417 info.doc, 387 info.doc.map(|it| it.into()),
418 Some( 388 Some(
419 r#"Method is called when writer finishes. 389 r#"Method is called when writer finishes.
420 390
421By default this method stops actor's `Context`."# 391By default this method stops actor's `Context`."#
422 .into() 392 .to_string()
423 ) 393 )
424 ); 394 );
425 } 395 }
diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs
index b1867de42..722d94f3a 100644
--- a/crates/ra_ide_api/src/completion.rs
+++ b/crates/ra_ide_api/src/completion.rs
@@ -10,6 +10,7 @@ mod complete_scope;
10mod complete_postfix; 10mod complete_postfix;
11 11
12use ra_db::SourceDatabase; 12use ra_db::SourceDatabase;
13use ra_syntax::ast::{self, AstNode};
13 14
14use crate::{ 15use crate::{
15 db, 16 db,
@@ -61,3 +62,21 @@ pub(crate) fn completions(db: &db::RootDatabase, position: FilePosition) -> Opti
61 complete_postfix::complete_postfix(&mut acc, &ctx); 62 complete_postfix::complete_postfix(&mut acc, &ctx);
62 Some(acc) 63 Some(acc)
63} 64}
65
66pub fn function_label(node: &ast::FnDef) -> Option<String> {
67 let label: String = if let Some(body) = node.body() {
68 let body_range = body.syntax().range();
69 let label: String = node
70 .syntax()
71 .children()
72 .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body
73 .filter(|child| ast::Comment::cast(child).is_none()) // Filter out comments
74 .map(|node| node.text().to_string())
75 .collect();
76 label
77 } else {
78 node.syntax().text().to_string()
79 };
80
81 Some(label.trim().to_owned())
82}
diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs
index 49bd636a5..d3bc14894 100644
--- a/crates/ra_ide_api/src/completion/completion_item.rs
+++ b/crates/ra_ide_api/src/completion/completion_item.rs
@@ -1,12 +1,12 @@
1use hir::{Docs, Documentation}; 1use hir::{Docs, Documentation};
2use ra_syntax::{ 2use ra_syntax::TextRange;
3 ast::{self, AstNode},
4 TextRange,
5};
6use ra_text_edit::TextEdit; 3use ra_text_edit::TextEdit;
7use test_utils::tested_by; 4use test_utils::tested_by;
8 5
9use crate::completion::completion_context::CompletionContext; 6use crate::completion::{
7 completion_context::CompletionContext,
8 function_label,
9};
10 10
11/// `CompletionItem` describes a single completion variant in the editor pop-up. 11/// `CompletionItem` describes a single completion variant in the editor pop-up.
12/// It is basically a POD with various properties. To construct a 12/// It is basically a POD with various properties. To construct a
@@ -97,8 +97,8 @@ impl CompletionItem {
97 self.detail.as_ref().map(|it| it.as_str()) 97 self.detail.as_ref().map(|it| it.as_str())
98 } 98 }
99 /// A doc-comment 99 /// A doc-comment
100 pub fn documentation(&self) -> Option<&str> { 100 pub fn documentation(&self) -> Option<Documentation> {
101 self.documentation.as_ref().map(|it| it.contents()) 101 self.documentation.clone()
102 } 102 }
103 /// What string is used for filtering. 103 /// What string is used for filtering.
104 pub fn lookup(&self) -> &str { 104 pub fn lookup(&self) -> &str {
@@ -252,7 +252,7 @@ impl Builder {
252 self.documentation = Some(docs); 252 self.documentation = Some(docs);
253 } 253 }
254 254
255 if let Some(label) = function_label(ctx, function) { 255 if let Some(label) = function_item_label(ctx, function) {
256 self.detail = Some(label); 256 self.detail = Some(label);
257 } 257 }
258 258
@@ -292,24 +292,9 @@ impl Into<Vec<CompletionItem>> for Completions {
292 } 292 }
293} 293}
294 294
295fn function_label(ctx: &CompletionContext, function: hir::Function) -> Option<String> { 295fn function_item_label(ctx: &CompletionContext, function: hir::Function) -> Option<String> {
296 let node = function.source(ctx.db).1; 296 let node = function.source(ctx.db).1;
297 297 function_label(&node)
298 let label: String = if let Some(body) = node.body() {
299 let body_range = body.syntax().range();
300 let label: String = node
301 .syntax()
302 .children()
303 .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body
304 .filter(|child| ast::Comment::cast(child).is_none()) // Filter out comments
305 .map(|node| node.text().to_string())
306 .collect();
307 label
308 } else {
309 node.syntax().text().to_string()
310 };
311
312 Some(label.trim().to_owned())
313} 298}
314 299
315#[cfg(test)] 300#[cfg(test)]
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index 51947e4cc..09cf0216d 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -58,6 +58,7 @@ pub use ra_ide_api_light::{
58pub use ra_db::{ 58pub use ra_db::{
59 Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId 59 Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId
60}; 60};
61pub use hir::Documentation;
61 62
62// We use jemalloc mainly to get heap usage statistics, actual performance 63// We use jemalloc mainly to get heap usage statistics, actual performance
63// differnece is not measures. 64// differnece is not measures.
@@ -266,7 +267,7 @@ impl<T> RangeInfo<T> {
266#[derive(Debug)] 267#[derive(Debug)]
267pub struct CallInfo { 268pub struct CallInfo {
268 pub label: String, 269 pub label: String,
269 pub doc: Option<String>, 270 pub doc: Option<Documentation>,
270 pub parameters: Vec<String>, 271 pub parameters: Vec<String>,
271 pub active_parameter: Option<usize>, 272 pub active_parameter: Option<usize>,
272} 273}