]> git.lizzy.rs Git - rust.git/commitdiff
Pass Documentation up to LSP and add "rust" to our codeblocks there
authorJeremy Kolb <kjeremy@gmail.com>
Wed, 30 Jan 2019 02:39:09 +0000 (21:39 -0500)
committerJeremy Kolb <kjeremy@gmail.com>
Wed, 30 Jan 2019 02:39:09 +0000 (21:39 -0500)
crates/ra_ide_api/src/call_info.rs
crates/ra_ide_api/src/completion.rs
crates/ra_ide_api/src/completion/completion_item.rs
crates/ra_ide_api/src/lib.rs
crates/ra_lsp_server/src/conv.rs
crates/ra_lsp_server/src/lib.rs
crates/ra_lsp_server/src/main_loop/handlers.rs
crates/ra_lsp_server/src/markdown.rs [new file with mode: 0644]

index ee1e137993673c3bd631b447b49bd8ea06ad2538..2eb388e0e763dec1ac33342ce9858245881c3aab 100644 (file)
@@ -3,9 +3,10 @@
 use ra_syntax::{
     AstNode, SyntaxNode, TextUnit, TextRange,
     SyntaxKind::FN_DEF,
-    ast::{self, ArgListOwner, DocCommentsOwner},
+    ast::{self, ArgListOwner},
     algo::find_node_at_offset,
 };
+use hir::Docs;
 
 use crate::{FilePosition, CallInfo, db::RootDatabase};
 
@@ -26,7 +27,9 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
     let fn_file = db.parse(symbol.file_id);
     let fn_def = symbol.ptr.to_node(&fn_file);
     let fn_def = ast::FnDef::cast(fn_def).unwrap();
-    let mut call_info = CallInfo::new(fn_def)?;
+    let function = hir::source_binder::function_from_source(db, symbol.file_id, fn_def)?;
+
+    let mut call_info = CallInfo::new(db, function, fn_def)?;
     // If we have a calling expression let's find which argument we are on
     let num_params = call_info.parameters.len();
     let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some();
@@ -110,46 +113,13 @@ pub fn arg_list(&self) -> Option<&'a ast::ArgList> {
 }
 
 impl CallInfo {
-    fn new(node: &ast::FnDef) -> Option<Self> {
-        let label: String = if let Some(body) = node.body() {
-            let body_range = body.syntax().range();
-            let label: String = node
-                .syntax()
-                .children()
-                .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body
-                .filter(|child| ast::Comment::cast(child).is_none()) // Filter out doc comments
-                .map(|node| node.text().to_string())
-                .collect();
-            label
-        } else {
-            node.syntax().text().to_string()
-        };
-
-        let mut doc = None;
-        if let Some(docs) = node.doc_comment_text() {
-            // Massage markdown
-            let mut processed_lines = Vec::new();
-            let mut in_code_block = false;
-            for line in docs.lines() {
-                if line.starts_with("```") {
-                    in_code_block = !in_code_block;
-                }
-
-                let line = if in_code_block && line.starts_with("```") && !line.contains("rust") {
-                    "```rust".into()
-                } else {
-                    line.to_string()
-                };
-
-                processed_lines.push(line);
-            }
-
-            doc = Some(processed_lines.join("\n"));
-        }
+    fn new(db: &RootDatabase, function: hir::Function, node: &ast::FnDef) -> Option<Self> {
+        let label = crate::completion::function_label(node)?;
+        let doc = function.docs(db);
 
         Some(CallInfo {
             parameters: param_list(node),
-            label: label.trim().to_owned(),
+            label,
             doc,
             active_parameter: None,
         })
@@ -284,7 +254,7 @@ fn bar() {
         assert_eq!(info.parameters, vec!["j".to_string()]);
         assert_eq!(info.active_parameter, Some(0));
         assert_eq!(info.label, "fn foo(j: u32) -> u32".to_string());
-        assert_eq!(info.doc, Some("test".into()));
+        assert_eq!(info.doc.map(|it| it.into()), Some("test".to_string()));
     }
 
     #[test]
@@ -313,18 +283,18 @@ pub fn do() {
         assert_eq!(info.active_parameter, Some(0));
         assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string());
         assert_eq!(
-            info.doc,
+            info.doc.map(|it| it.into()),
             Some(
                 r#"Adds one to the number given.
 
 # Examples
 
-```rust
+```
 let five = 5;
 
 assert_eq!(6, my_crate::add_one(5));
 ```"#
-                    .into()
+                    .to_string()
             )
         );
     }
@@ -359,18 +329,18 @@ pub fn do_it() {
         assert_eq!(info.active_parameter, Some(0));
         assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string());
         assert_eq!(
-            info.doc,
+            info.doc.map(|it| it.into()),
             Some(
                 r#"Adds one to the number given.
 
 # Examples
 
-```rust
+```
 let five = 5;
 
 assert_eq!(6, my_crate::add_one(5));
 ```"#
-                    .into()
+                    .to_string()
             )
         );
     }
@@ -414,12 +384,12 @@ pub fn foo() {
         );
         assert_eq!(info.active_parameter, Some(1));
         assert_eq!(
-            info.doc,
+            info.doc.map(|it| it.into()),
             Some(
                 r#"Method is called when writer finishes.
 
 By default this method stops actor's `Context`."#
-                    .into()
+                    .to_string()
             )
         );
     }
index b1867de4270284f48d88ac004173c716ea4871fb..722d94f3a2c4b89a8ab62efb59e2521b33cf57f2 100644 (file)
@@ -10,6 +10,7 @@
 mod complete_postfix;
 
 use ra_db::SourceDatabase;
+use ra_syntax::ast::{self, AstNode};
 
 use crate::{
     db,
@@ -61,3 +62,21 @@ pub(crate) fn completions(db: &db::RootDatabase, position: FilePosition) -> Opti
     complete_postfix::complete_postfix(&mut acc, &ctx);
     Some(acc)
 }
+
+pub fn function_label(node: &ast::FnDef) -> Option<String> {
+    let label: String = if let Some(body) = node.body() {
+        let body_range = body.syntax().range();
+        let label: String = node
+            .syntax()
+            .children()
+            .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body
+            .filter(|child| ast::Comment::cast(child).is_none()) // Filter out comments
+            .map(|node| node.text().to_string())
+            .collect();
+        label
+    } else {
+        node.syntax().text().to_string()
+    };
+
+    Some(label.trim().to_owned())
+}
index 49bd636a5dc20c5b23972738e22123fcf8aa7c05..d3bc148944e1be9a1d6107d2c95f82df49bc6b41 100644 (file)
@@ -1,12 +1,12 @@
 use hir::{Docs, Documentation};
-use ra_syntax::{
-    ast::{self, AstNode},
-    TextRange,
-};
+use ra_syntax::TextRange;
 use ra_text_edit::TextEdit;
 use test_utils::tested_by;
 
-use crate::completion::completion_context::CompletionContext;
+use crate::completion::{
+    completion_context::CompletionContext,
+    function_label,
+};
 
 /// `CompletionItem` describes a single completion variant in the editor pop-up.
 /// It is basically a POD with various properties. To construct a
@@ -97,8 +97,8 @@ pub fn detail(&self) -> Option<&str> {
         self.detail.as_ref().map(|it| it.as_str())
     }
     /// A doc-comment
-    pub fn documentation(&self) -> Option<&str> {
-        self.documentation.as_ref().map(|it| it.contents())
+    pub fn documentation(&self) -> Option<Documentation> {
+        self.documentation.clone()
     }
     /// What string is used for filtering.
     pub fn lookup(&self) -> &str {
@@ -252,7 +252,7 @@ pub(super) fn from_function(
             self.documentation = Some(docs);
         }
 
-        if let Some(label) = function_label(ctx, function) {
+        if let Some(label) = function_item_label(ctx, function) {
             self.detail = Some(label);
         }
 
@@ -292,24 +292,9 @@ fn into(self) -> Vec<CompletionItem> {
     }
 }
 
-fn function_label(ctx: &CompletionContext, function: hir::Function) -> Option<String> {
+fn function_item_label(ctx: &CompletionContext, function: hir::Function) -> Option<String> {
     let node = function.source(ctx.db).1;
-
-    let label: String = if let Some(body) = node.body() {
-        let body_range = body.syntax().range();
-        let label: String = node
-            .syntax()
-            .children()
-            .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body
-            .filter(|child| ast::Comment::cast(child).is_none()) // Filter out comments
-            .map(|node| node.text().to_string())
-            .collect();
-        label
-    } else {
-        node.syntax().text().to_string()
-    };
-
-    Some(label.trim().to_owned())
+    function_label(&node)
 }
 
 #[cfg(test)]
index 51947e4ccd2faeac21455ec72f1af7c396012ef1..09cf0216d0724fa68733aa8407d4c9c8c3e6394d 100644 (file)
@@ -58,6 +58,7 @@
 pub use ra_db::{
     Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId
 };
+pub use hir::Documentation;
 
 // We use jemalloc mainly to get heap usage statistics, actual performance
 // differnece is not measures.
@@ -266,7 +267,7 @@ pub fn new(range: TextRange, info: T) -> RangeInfo<T> {
 #[derive(Debug)]
 pub struct CallInfo {
     pub label: String,
-    pub doc: Option<String>,
+    pub doc: Option<Documentation>,
     pub parameters: Vec<String>,
     pub active_parameter: Option<usize>,
 }
index 8c87f5195173ae6e4a4468e32dfff85d547dcf89..c033ecdeaa10a1c570b9b4e4bec72b7dee60dca4 100644 (file)
@@ -87,13 +87,6 @@ fn conv_with(mut self, ctx: &LineIndex) -> ::lsp_types::CompletionItem {
             None
         };
 
-        let documentation = self.documentation().map(|value| {
-            Documentation::MarkupContent(MarkupContent {
-                kind: MarkupKind::Markdown,
-                value: value.to_string(),
-            })
-        });
-
         let mut res = lsp_types::CompletionItem {
             label: self.label().to_string(),
             detail: self.detail().map(|it| it.to_string()),
@@ -101,7 +94,7 @@ fn conv_with(mut self, ctx: &LineIndex) -> ::lsp_types::CompletionItem {
             kind: self.kind().map(|it| it.conv()),
             text_edit: Some(text_edit),
             additional_text_edits,
-            documentation: documentation,
+            documentation: self.documentation().map(|it| it.conv()),
             ..Default::default()
         };
         res.insert_text_format = Some(match self.insert_text_format() {
@@ -160,6 +153,16 @@ fn conv_with(self, line_index: &LineIndex) -> TextRange {
     }
 }
 
+impl Conv for ra_ide_api::Documentation {
+    type Output = lsp_types::Documentation;
+    fn conv(self) -> Documentation {
+        Documentation::MarkupContent(MarkupContent {
+            kind: MarkupKind::Markdown,
+            value: crate::markdown::sanitize_markdown(self).into(),
+        })
+    }
+}
+
 impl ConvWith for TextEdit {
     type Ctx = LineIndex;
     type Output = Vec<lsp_types::TextEdit>;
index f93d4b37d9dd7f007f990672453f73cc52a3be29..5b5f3b948fddda5e85a686d812ee0dae055d299b 100644 (file)
@@ -2,6 +2,7 @@
 mod cargo_target_spec;
 mod conv;
 mod main_loop;
+mod markdown;
 mod project_model;
 pub mod req;
 mod server_world;
index 9478ebfb89cfdf56147829f8dcdc4ad693dceac4..4f75f9a22930d00dfe4888452d3cf6e2794ee559 100644 (file)
@@ -1,7 +1,7 @@
 use gen_lsp_server::ErrorCode;
 use lsp_types::{
     CodeActionResponse, CodeLens, Command, Diagnostic, DiagnosticSeverity,
-    DocumentFormattingParams, DocumentHighlight, DocumentSymbol, Documentation, FoldingRange,
+    DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange,
     FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent,
     MarkupKind, ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range,
     RenameParams, SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit,
@@ -401,12 +401,9 @@ pub fn handle_signature_help(
                 documentation: None,
             })
             .collect();
-        let documentation = call_info.doc.map(|value| {
-            Documentation::MarkupContent(MarkupContent {
-                kind: MarkupKind::Markdown,
-                value,
-            })
-        });
+
+        let documentation = call_info.doc.map(|it| it.conv());
+
         let sig_info = SignatureInformation {
             label: call_info.label,
             documentation,
diff --git a/crates/ra_lsp_server/src/markdown.rs b/crates/ra_lsp_server/src/markdown.rs
new file mode 100644 (file)
index 0000000..f505755
--- /dev/null
@@ -0,0 +1,38 @@
+use ra_ide_api::Documentation;
+
+pub(crate) fn sanitize_markdown(docs: Documentation) -> Documentation {
+    let docs: String = docs.into();
+
+    // Massage markdown
+    let mut processed_lines = Vec::new();
+    let mut in_code_block = false;
+    for line in docs.lines() {
+        if line.starts_with("```") {
+            in_code_block = !in_code_block;
+        }
+
+        let line = if in_code_block && line.starts_with("```") && !line.contains("rust") {
+            "```rust".into()
+        } else {
+            line.to_string()
+        };
+
+        processed_lines.push(line);
+    }
+
+    Documentation::new(&processed_lines.join("\n"))
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_codeblock_adds_rust() {
+        let comment = "```\nfn some_rust() {}\n```";
+        assert_eq!(
+            sanitize_markdown(Documentation::new(comment)).contents(),
+            "```rust\nfn some_rust() {}\n```"
+        );
+    }
+}