From 0e49abb7fbe9239b97f0b7168ec359014c63f8c0 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Tue, 12 Mar 2019 09:24:46 +0200 Subject: Refactor CallInfo function signatures to new FunctionSignature type This is used by CallInfo to create a pretty printed function signature that can be used with completions and other places as well. --- crates/ra_hir/src/docs.rs | 6 ++ crates/ra_ide_api/src/call_info.rs | 85 +++++++++++++--------- crates/ra_ide_api/src/completion.rs | 61 ++++++++++++---- crates/ra_ide_api/src/completion/complete_scope.rs | 2 +- crates/ra_ide_api/src/display.rs | 51 +++++++++++++ crates/ra_ide_api/src/lib.rs | 29 +++++++- crates/ra_lsp_server/src/conv.rs | 22 ++++++ crates/ra_lsp_server/src/main_loop/handlers.rs | 23 ++---- 8 files changed, 210 insertions(+), 69 deletions(-) create mode 100644 crates/ra_ide_api/src/display.rs (limited to 'crates') diff --git a/crates/ra_hir/src/docs.rs b/crates/ra_hir/src/docs.rs index 5db72c08a..e3a755b46 100644 --- a/crates/ra_hir/src/docs.rs +++ b/crates/ra_hir/src/docs.rs @@ -22,6 +22,12 @@ impl Into for Documentation { } } +impl<'a> Into for &'a Documentation { + fn into(self) -> String { + self.contents().into() + } +} + pub trait Docs { fn docs(&self, db: &impl HirDatabase) -> Option; } diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index 29fa7d30b..a65119315 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -30,7 +30,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option FnCallNode<'a> { impl CallInfo { fn new(db: &RootDatabase, function: hir::Function, node: &ast::FnDef) -> Option { - let label = crate::completion::function_label(node)?; + let sig = crate::completion::function_signature(node)?; let doc = function.docs(db); + let sig = sig.with_doc_opt(doc); - Some(CallInfo { parameters: param_list(node), label, doc, active_parameter: None }) + Some(CallInfo { signature: sig, active_parameter: None }) } -} -fn param_list(node: &ast::FnDef) -> Vec { - let mut res = vec![]; - if let Some(param_list) = node.param_list() { - if let Some(self_param) = param_list.self_param() { - res.push(self_param.syntax().text().to_string()) - } + fn parameters(&self) -> &[String] { + &self.signature.parameters + } - // Maybe use param.pat here? See if we can just extract the name? - //res.extend(param_list.params().map(|p| p.syntax().text().to_string())); - res.extend( - param_list.params().filter_map(|p| p.pat()).map(|pat| pat.syntax().text().to_string()), - ); + #[cfg(test)] + fn doc(&self) -> Option<&hir::Documentation> { + self.signature.doc.as_ref() + } + + #[cfg(test)] + fn label(&self) -> String { + self.signature.to_string() } - res } #[cfg(test)] @@ -151,7 +150,7 @@ mod tests { fn bar() { foo(<|>3, ); }"#, ); - assert_eq!(info.parameters, vec!("x".to_string(), "y".to_string())); + assert_eq!(info.parameters(), ["x: u32", "y: u32"]); assert_eq!(info.active_parameter, Some(0)); } @@ -162,7 +161,7 @@ fn bar() { foo(<|>3, ); }"#, fn bar() { foo(3, <|>); }"#, ); - assert_eq!(info.parameters, vec!("x".to_string(), "y".to_string())); + assert_eq!(info.parameters(), ["x: u32", "y: u32"]); assert_eq!(info.active_parameter, Some(1)); } @@ -173,7 +172,27 @@ fn bar() { foo(3, <|>); }"#, fn bar() { foo(<|>); }"#, ); - assert_eq!(info.parameters, vec!("x".to_string(), "y".to_string())); + assert_eq!(info.parameters(), ["x: u32", "y: u32"]); + assert_eq!(info.active_parameter, Some(0)); + } + + #[test] + fn test_fn_signature_two_args_first_generics() { + let info = call_info( + r#"fn foo(x: T, y: U) -> u32 where T: Copy + Display, U: Debug {x + y} +fn bar() { foo(<|>3, ); }"#, + ); + + assert_eq!(info.parameters(), ["x: T", "y: U"]); + assert_eq!( + info.label(), + r#" +fn foo(x: T, y: U) -> u32 +where T: Copy + Display, + U: Debug + "# + .trim() + ); assert_eq!(info.active_parameter, Some(0)); } @@ -184,7 +203,7 @@ fn bar() { foo(<|>); }"#, fn bar() {let _ : F = F::new(<|>);}"#, ); - assert_eq!(info.parameters, Vec::::new()); + assert!(info.parameters().is_empty()); assert_eq!(info.active_parameter, None); } @@ -206,7 +225,7 @@ fn bar() { }"#, ); - assert_eq!(info.parameters, vec!["&self".to_string()]); + assert_eq!(info.parameters(), ["&self"]); assert_eq!(info.active_parameter, None); } @@ -228,7 +247,7 @@ fn bar() { }"#, ); - assert_eq!(info.parameters, vec!["&self".to_string(), "x".to_string()]); + assert_eq!(info.parameters(), ["&self", "x: i32"]); assert_eq!(info.active_parameter, Some(1)); } @@ -248,10 +267,10 @@ fn bar() { "#, ); - assert_eq!(info.parameters, vec!["j".to_string()]); + assert_eq!(info.parameters(), ["j: u32"]); assert_eq!(info.active_parameter, Some(0)); - assert_eq!(info.label, "fn foo(j: u32) -> u32".to_string()); - assert_eq!(info.doc.map(|it| it.into()), Some("test".to_string())); + assert_eq!(info.label(), "fn foo(j: u32) -> u32"); + assert_eq!(info.doc().map(|it| it.into()), Some("test".to_string())); } #[test] @@ -276,11 +295,11 @@ pub fn do() { }"#, ); - assert_eq!(info.parameters, vec!["x".to_string()]); + assert_eq!(info.parameters(), ["x: i32"]); assert_eq!(info.active_parameter, Some(0)); - assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string()); + assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32"); assert_eq!( - info.doc.map(|it| it.into()), + info.doc().map(|it| it.into()), Some( r#"Adds one to the number given. @@ -322,11 +341,11 @@ pub fn do_it() { }"#, ); - assert_eq!(info.parameters, vec!["x".to_string()]); + assert_eq!(info.parameters(), ["x: i32"]); assert_eq!(info.active_parameter, Some(0)); - assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string()); + assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32"); assert_eq!( - info.doc.map(|it| it.into()), + info.doc().map(|it| it.into()), Some( r#"Adds one to the number given. @@ -375,10 +394,10 @@ pub fn foo() { "#, ); - assert_eq!(info.parameters, vec!["&mut self".to_string(), "ctx".to_string()]); + assert_eq!(info.parameters(), ["&mut self", "ctx: &mut Self::Context"]); assert_eq!(info.active_parameter, Some(1)); assert_eq!( - info.doc.map(|it| it.into()), + info.doc().map(|it| it.into()), Some( r#"Method is called when writer finishes. diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs index a846a7a3c..d8e4410b2 100644 --- a/crates/ra_ide_api/src/completion.rs +++ b/crates/ra_ide_api/src/completion.rs @@ -13,11 +13,12 @@ mod complete_scope; mod complete_postfix; use ra_db::SourceDatabase; -use ra_syntax::{ast::{self, AstNode}, SyntaxKind::{ATTR, COMMENT}}; +use ra_syntax::{ast::{self, AstNode, NameOwner, VisibilityOwner, TypeParamsOwner}, SyntaxKind::{ATTR, COMMENT}}; use crate::{ db, FilePosition, + FunctionSignature, completion::{ completion_item::{Completions, CompletionKind}, completion_context::CompletionContext, @@ -71,22 +72,52 @@ pub(crate) fn completions(db: &db::RootDatabase, position: FilePosition) -> Opti Some(acc) } -pub fn function_label(node: &ast::FnDef) -> Option { - let label: String = if let Some(body) = node.body() { - let body_range = body.syntax().range(); - let label: String = node - .syntax() - .children_with_tokens() - .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body - .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR)) // Filter out comments and attrs - .map(|node| node.to_string()) - .collect(); - label - } else { - node.syntax().text().to_string() +pub fn generic_parameters(node: &N) -> Vec { + let mut res = vec![]; + if let Some(type_params) = node.type_param_list() { + res.extend(type_params.lifetime_params().map(|p| p.syntax().text().to_string())); + res.extend(type_params.type_params().map(|p| p.syntax().text().to_string())); + } + res +} + +pub fn where_predicates(node: &N) -> Vec { + let mut res = vec![]; + if let Some(clause) = node.where_clause() { + res.extend(clause.predicates().map(|p| p.syntax().text().to_string())); + } + res +} + +pub fn function_signature(node: &ast::FnDef) -> Option { + fn param_list(node: &ast::FnDef) -> Vec { + let mut res = vec![]; + if let Some(param_list) = node.param_list() { + if let Some(self_param) = param_list.self_param() { + res.push(self_param.syntax().text().to_string()) + } + + res.extend(param_list.params().map(|param| param.syntax().text().to_string())); + } + res + } + + let sig = FunctionSignature { + visibility: node.visibility().map(|n| n.syntax().text().to_string()), + name: node.name().map(|n| n.text().to_string()), + ret_type: node.ret_type().and_then(|r| r.type_ref()).map(|n| n.syntax().text().to_string()), + parameters: param_list(node), + generic_parameters: generic_parameters(node), + where_predicates: where_predicates(node), + // docs are processed separately + doc: None, }; - Some(label.trim().to_owned()) + Some(sig) +} + +pub fn function_label(node: &ast::FnDef) -> Option { + function_signature(node).map(|n| n.to_string()) } pub fn const_label(node: &ast::ConstDef) -> String { diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs index 6146b7bb6..9d82f2270 100644 --- a/crates/ra_ide_api/src/completion/complete_scope.rs +++ b/crates/ra_ide_api/src/completion/complete_scope.rs @@ -145,7 +145,7 @@ mod tests { check_reference_completion( "dont_show_both_completions_for_shadowing", r" - fn foo() -> { + fn foo() { let bar = 92; { let bar = 62; diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs new file mode 100644 index 000000000..60fa72f1b --- /dev/null +++ b/crates/ra_ide_api/src/display.rs @@ -0,0 +1,51 @@ +use super::*; +use std::fmt::{self, Display}; + +impl Display for FunctionSignature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(t) = &self.visibility { + write!(f, "{} ", t)?; + } + + if let Some(name) = &self.name { + write!(f, "fn {}", name)?; + } + + if !self.generic_parameters.is_empty() { + write!(f, "<")?; + write_joined(f, &self.generic_parameters, ", ")?; + write!(f, ">")?; + } + + write!(f, "(")?; + write_joined(f, &self.parameters, ", ")?; + write!(f, ")")?; + + if let Some(t) = &self.ret_type { + write!(f, " -> {}", t)?; + } + + if !self.where_predicates.is_empty() { + write!(f, "\nwhere ")?; + write_joined(f, &self.where_predicates, ",\n ")?; + } + + Ok(()) + } +} + +fn write_joined( + f: &mut fmt::Formatter, + items: impl IntoIterator, + sep: &str, +) -> fmt::Result { + let mut first = true; + for e in items { + if !first { + write!(f, "{}", sep)?; + } + first = false; + write!(f, "{}", e)?; + } + Ok(()) +} diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index 9063f78a9..7f8f454bc 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs @@ -37,6 +37,7 @@ mod join_lines; mod structure; mod typing; mod matching_brace; +mod display; #[cfg(test)] mod marks; @@ -243,10 +244,34 @@ impl RangeInfo { #[derive(Debug)] pub struct CallInfo { - pub label: String, + pub signature: FunctionSignature, + pub active_parameter: Option, +} + +/// Contains information about a function signature +#[derive(Debug)] +pub struct FunctionSignature { + /// Optional visibility + pub visibility: Option, + /// Name of the function + pub name: Option, + /// Documentation for the function pub doc: Option, + /// Generic parameters + pub generic_parameters: Vec, + /// Parameters of the function pub parameters: Vec, - pub active_parameter: Option, + /// Optional return type + pub ret_type: Option, + /// Where predicates + pub where_predicates: Vec, +} + +impl FunctionSignature { + pub(crate) fn with_doc_opt(mut self, doc: Option) -> Self { + self.doc = doc; + self + } } /// `AnalysisHost` stores the current state of the world. diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index 74e91c236..4d6ede316 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs @@ -174,6 +174,28 @@ impl Conv for ra_ide_api::Documentation { } } +impl Conv for ra_ide_api::FunctionSignature { + type Output = lsp_types::SignatureInformation; + fn conv(self) -> Self::Output { + use lsp_types::{ParameterInformation, ParameterLabel, SignatureInformation}; + + let label = self.to_string(); + + let documentation = self.doc.map(|it| it.conv()); + + let parameters: Vec = self + .parameters + .into_iter() + .map(|param| ParameterInformation { + label: ParameterLabel::Simple(param), + documentation: None, + }) + .collect(); + + SignatureInformation { label, documentation, parameters: Some(parameters) } + } +} + impl ConvWith for TextEdit { type Ctx = LineIndex; type Output = Vec; diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 89e96a33a..b96deb061 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -3,8 +3,8 @@ use lsp_types::{ CodeActionResponse, CodeLens, Command, Diagnostic, DiagnosticSeverity, CodeAction, DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, - MarkupKind, ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, - RenameParams, SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit, + MarkupKind, Position, PrepareRenameResponse, Range, + RenameParams,SymbolInformation, TextDocumentIdentifier, TextEdit, WorkspaceEdit, }; use ra_ide_api::{ @@ -403,26 +403,13 @@ pub fn handle_signature_help( ) -> Result> { let position = params.try_conv_with(&world)?; if let Some(call_info) = world.analysis().call_info(position)? { - let parameters: Vec = call_info - .parameters - .into_iter() - .map(|param| ParameterInformation { - label: ParameterLabel::Simple(param.clone()), - documentation: None, - }) - .collect(); + let active_parameter = call_info.active_parameter.map(|it| it as i64); + let sig_info = call_info.signature.conv(); - let documentation = call_info.doc.map(|it| it.conv()); - - let sig_info = SignatureInformation { - label: call_info.label, - documentation, - parameters: Some(parameters), - }; Ok(Some(req::SignatureHelp { signatures: vec![sig_info], active_signature: Some(0), - active_parameter: call_info.active_parameter.map(|it| it as i64), + active_parameter, })) } else { Ok(None) -- cgit v1.2.3 From 751b4544426509b6b9a072c54604fa0ca4438e64 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Thu, 4 Apr 2019 17:54:26 +0300 Subject: Update test snapshots --- ...ion_item__dont_show_both_completions_for_shadowing.snap | 14 +++++++------- .../completion/snapshots/completion_item__return_type.snap | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__dont_show_both_completions_for_shadowing.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__dont_show_both_completions_for_shadowing.snap index 87691b304..34adcda6c 100644 --- a/crates/ra_ide_api/src/completion/snapshots/completion_item__dont_show_both_completions_for_shadowing.snap +++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__dont_show_both_completions_for_shadowing.snap @@ -1,23 +1,23 @@ --- -created: "2019-02-18T09:22:24.188564584Z" -creator: insta@0.6.2 +created: "2019-04-04T14:52:24.531844100Z" +creator: insta@0.7.4 source: crates/ra_ide_api/src/completion/completion_item.rs expression: kind_completions --- [ CompletionItem { label: "bar", - source_range: [129; 129), - delete: [129; 129), + source_range: [126; 126), + delete: [126; 126), insert: "bar", kind: Binding }, CompletionItem { label: "foo", - source_range: [129; 129), - delete: [129; 129), + source_range: [126; 126), + delete: [126; 126), insert: "foo()$0", kind: Function, - detail: "fn foo() ->" + detail: "fn foo()" } ] diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__return_type.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__return_type.snap index 0738cf466..ff36df707 100644 --- a/crates/ra_ide_api/src/completion/snapshots/completion_item__return_type.snap +++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__return_type.snap @@ -1,6 +1,6 @@ --- -created: "2019-02-18T09:22:24.182964414Z" -creator: insta@0.6.2 +created: "2019-04-04T14:52:24.525395600Z" +creator: insta@0.7.4 source: crates/ra_ide_api/src/completion/completion_item.rs expression: kind_completions --- @@ -18,6 +18,6 @@ expression: kind_completions delete: [47; 47), insert: "x()$0", kind: Function, - detail: "fn x() ->" + detail: "fn x()" } ] -- cgit v1.2.3 From 84fde47d00bb3ccba3876ad2b2e46c5c59cd07c4 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Thu, 4 Apr 2019 18:06:22 +0300 Subject: Move test specific things --- crates/ra_hir/src/docs.rs | 6 ------ crates/ra_ide_api/src/call_info.rs | 21 +++++++++++---------- 2 files changed, 11 insertions(+), 16 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/docs.rs b/crates/ra_hir/src/docs.rs index e3a755b46..5db72c08a 100644 --- a/crates/ra_hir/src/docs.rs +++ b/crates/ra_hir/src/docs.rs @@ -22,12 +22,6 @@ impl Into for Documentation { } } -impl<'a> Into for &'a Documentation { - fn into(self) -> String { - self.contents().into() - } -} - pub trait Docs { fn docs(&self, db: &impl HirDatabase) -> Option; } diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index a65119315..3c53bd11a 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -118,16 +118,6 @@ impl CallInfo { fn parameters(&self) -> &[String] { &self.signature.parameters } - - #[cfg(test)] - fn doc(&self) -> Option<&hir::Documentation> { - self.signature.doc.as_ref() - } - - #[cfg(test)] - fn label(&self) -> String { - self.signature.to_string() - } } #[cfg(test)] @@ -138,6 +128,17 @@ mod tests { use super::*; + // These are only used when testing + impl CallInfo { + fn doc(&self) -> Option { + self.signature.doc.clone() + } + + fn label(&self) -> String { + self.signature.to_string() + } + } + fn call_info(text: &str) -> CallInfo { let (analysis, position) = single_file_with_position(text); analysis.call_info(position).unwrap().unwrap() -- cgit v1.2.3 From 7ba22f1c19c8fbfe45630c35ebd963d4c5475bc9 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Thu, 4 Apr 2019 19:30:20 +0300 Subject: Move FunctionSignature to display, remove write_joined write_joined is replaced with `join_to_string::join` which provides the necessary functionality. --- crates/ra_ide_api/src/display.rs | 58 ++++++++++++++++++++++++---------------- crates/ra_ide_api/src/lib.rs | 27 +------------------ 2 files changed, 36 insertions(+), 49 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs index 60fa72f1b..9d9d2097f 100644 --- a/crates/ra_ide_api/src/display.rs +++ b/crates/ra_ide_api/src/display.rs @@ -1,5 +1,34 @@ +//! This module contains utilities for rendering turning things into something +//! that may be used to render in UI. use super::*; use std::fmt::{self, Display}; +use join_to_string::join; + +/// Contains information about a function signature +#[derive(Debug)] +pub struct FunctionSignature { + /// Optional visibility + pub visibility: Option, + /// Name of the function + pub name: Option, + /// Documentation for the function + pub doc: Option, + /// Generic parameters + pub generic_parameters: Vec, + /// Parameters of the function + pub parameters: Vec, + /// Optional return type + pub ret_type: Option, + /// Where predicates + pub where_predicates: Vec, +} + +impl FunctionSignature { + pub(crate) fn with_doc_opt(mut self, doc: Option) -> Self { + self.doc = doc; + self + } +} impl Display for FunctionSignature { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -12,14 +41,13 @@ impl Display for FunctionSignature { } if !self.generic_parameters.is_empty() { - write!(f, "<")?; - write_joined(f, &self.generic_parameters, ", ")?; - write!(f, ">")?; + join(self.generic_parameters.iter()) + .separator(", ") + .surround_with("<", ">") + .to_fmt(f)?; } - write!(f, "(")?; - write_joined(f, &self.parameters, ", ")?; - write!(f, ")")?; + join(self.parameters.iter()).separator(", ").surround_with("(", ")").to_fmt(f)?; if let Some(t) = &self.ret_type { write!(f, " -> {}", t)?; @@ -27,25 +55,9 @@ impl Display for FunctionSignature { if !self.where_predicates.is_empty() { write!(f, "\nwhere ")?; - write_joined(f, &self.where_predicates, ",\n ")?; + join(self.where_predicates.iter()).separator(",\n ").to_fmt(f)?; } Ok(()) } } - -fn write_joined( - f: &mut fmt::Formatter, - items: impl IntoIterator, - sep: &str, -) -> fmt::Result { - let mut first = true; - for e in items { - if !first { - write!(f, "{}", sep)?; - } - first = false; - write!(f, "{}", e)?; - } - Ok(()) -} diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index 7f8f454bc..816bab94f 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs @@ -73,6 +73,7 @@ pub use crate::{ syntax_highlighting::HighlightedRange, structure::{StructureNode, file_structure}, diagnostics::Severity, + display::FunctionSignature, }; pub use ra_db::{ @@ -248,32 +249,6 @@ pub struct CallInfo { pub active_parameter: Option, } -/// Contains information about a function signature -#[derive(Debug)] -pub struct FunctionSignature { - /// Optional visibility - pub visibility: Option, - /// Name of the function - pub name: Option, - /// Documentation for the function - pub doc: Option, - /// Generic parameters - pub generic_parameters: Vec, - /// Parameters of the function - pub parameters: Vec, - /// Optional return type - pub ret_type: Option, - /// Where predicates - pub where_predicates: Vec, -} - -impl FunctionSignature { - pub(crate) fn with_doc_opt(mut self, doc: Option) -> Self { - self.doc = doc; - self - } -} - /// `AnalysisHost` stores the current state of the world. #[derive(Debug, Default)] pub struct AnalysisHost { -- cgit v1.2.3 From ed65e2619a42aea7c375d0cbf81d337fffb11a46 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Thu, 4 Apr 2019 19:43:32 +0300 Subject: Add no parameter test to call_info --- crates/ra_ide_api/src/call_info.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'crates') diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index 3c53bd11a..1885d3da8 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -197,6 +197,25 @@ where T: Copy + Display, assert_eq!(info.active_parameter, Some(0)); } + #[test] + fn test_fn_signature_no_params() { + let info = call_info( + r#"fn foo() -> T where T: Copy + Display {} +fn bar() { foo(<|>); }"#, + ); + + assert!(info.parameters().is_empty()); + assert_eq!( + info.label(), + r#" +fn foo() -> T +where T: Copy + Display + "# + .trim() + ); + assert!(info.active_parameter.is_none()); + } + #[test] fn test_fn_signature_for_impl() { let info = call_info( -- cgit v1.2.3 From f4aa15c16b352d4ac9a90c1668311e4762c5e494 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Thu, 4 Apr 2019 20:05:01 +0300 Subject: Move FunctionSignature creation to display --- crates/ra_ide_api/src/call_info.rs | 7 +++--- crates/ra_ide_api/src/completion.rs | 48 ++---------------------------------- crates/ra_ide_api/src/display.rs | 49 +++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 50 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index 1885d3da8..66a769c73 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -8,7 +8,7 @@ use ra_syntax::{ }; use hir::Docs; -use crate::{FilePosition, CallInfo, db::RootDatabase}; +use crate::{FilePosition, CallInfo, FunctionSignature, db::RootDatabase}; /// Computes parameter information for the given call expression. pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option { @@ -108,11 +108,10 @@ impl<'a> FnCallNode<'a> { impl CallInfo { fn new(db: &RootDatabase, function: hir::Function, node: &ast::FnDef) -> Option { - let sig = crate::completion::function_signature(node)?; let doc = function.docs(db); - let sig = sig.with_doc_opt(doc); + let signature = FunctionSignature::from(node).with_doc_opt(doc); - Some(CallInfo { signature: sig, active_parameter: None }) + Some(CallInfo { signature, active_parameter: None }) } fn parameters(&self) -> &[String] { diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs index d8e4410b2..71a35c689 100644 --- a/crates/ra_ide_api/src/completion.rs +++ b/crates/ra_ide_api/src/completion.rs @@ -13,7 +13,7 @@ mod complete_scope; mod complete_postfix; use ra_db::SourceDatabase; -use ra_syntax::{ast::{self, AstNode, NameOwner, VisibilityOwner, TypeParamsOwner}, SyntaxKind::{ATTR, COMMENT}}; +use ra_syntax::{ast::{self, AstNode}, SyntaxKind::{ATTR, COMMENT}}; use crate::{ db, @@ -72,52 +72,8 @@ pub(crate) fn completions(db: &db::RootDatabase, position: FilePosition) -> Opti Some(acc) } -pub fn generic_parameters(node: &N) -> Vec { - let mut res = vec![]; - if let Some(type_params) = node.type_param_list() { - res.extend(type_params.lifetime_params().map(|p| p.syntax().text().to_string())); - res.extend(type_params.type_params().map(|p| p.syntax().text().to_string())); - } - res -} - -pub fn where_predicates(node: &N) -> Vec { - let mut res = vec![]; - if let Some(clause) = node.where_clause() { - res.extend(clause.predicates().map(|p| p.syntax().text().to_string())); - } - res -} - -pub fn function_signature(node: &ast::FnDef) -> Option { - fn param_list(node: &ast::FnDef) -> Vec { - let mut res = vec![]; - if let Some(param_list) = node.param_list() { - if let Some(self_param) = param_list.self_param() { - res.push(self_param.syntax().text().to_string()) - } - - res.extend(param_list.params().map(|param| param.syntax().text().to_string())); - } - res - } - - let sig = FunctionSignature { - visibility: node.visibility().map(|n| n.syntax().text().to_string()), - name: node.name().map(|n| n.text().to_string()), - ret_type: node.ret_type().and_then(|r| r.type_ref()).map(|n| n.syntax().text().to_string()), - parameters: param_list(node), - generic_parameters: generic_parameters(node), - where_predicates: where_predicates(node), - // docs are processed separately - doc: None, - }; - - Some(sig) -} - pub fn function_label(node: &ast::FnDef) -> Option { - function_signature(node).map(|n| n.to_string()) + Some(FunctionSignature::from(node).to_string()) } pub fn const_label(node: &ast::ConstDef) -> String { diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs index 9d9d2097f..e01635460 100644 --- a/crates/ra_ide_api/src/display.rs +++ b/crates/ra_ide_api/src/display.rs @@ -3,6 +3,8 @@ use super::*; use std::fmt::{self, Display}; use join_to_string::join; +use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner, TypeParamsOwner}; +use std::convert::From; /// Contains information about a function signature #[derive(Debug)] @@ -30,6 +32,36 @@ impl FunctionSignature { } } +impl From<&'_ ast::FnDef> for FunctionSignature { + fn from(node: &ast::FnDef) -> FunctionSignature { + fn param_list(node: &ast::FnDef) -> Vec { + let mut res = vec![]; + if let Some(param_list) = node.param_list() { + if let Some(self_param) = param_list.self_param() { + res.push(self_param.syntax().text().to_string()) + } + + res.extend(param_list.params().map(|param| param.syntax().text().to_string())); + } + res + } + + FunctionSignature { + visibility: node.visibility().map(|n| n.syntax().text().to_string()), + name: node.name().map(|n| n.text().to_string()), + ret_type: node + .ret_type() + .and_then(|r| r.type_ref()) + .map(|n| n.syntax().text().to_string()), + parameters: param_list(node), + generic_parameters: generic_parameters(node), + where_predicates: where_predicates(node), + // docs are processed separately + doc: None, + } + } +} + impl Display for FunctionSignature { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if let Some(t) = &self.visibility { @@ -61,3 +93,20 @@ impl Display for FunctionSignature { Ok(()) } } + +pub(crate) fn generic_parameters(node: &N) -> Vec { + let mut res = vec![]; + if let Some(type_params) = node.type_param_list() { + res.extend(type_params.lifetime_params().map(|p| p.syntax().text().to_string())); + res.extend(type_params.type_params().map(|p| p.syntax().text().to_string())); + } + res +} + +pub(crate) fn where_predicates(node: &N) -> Vec { + let mut res = vec![]; + if let Some(clause) = node.where_clause() { + res.extend(clause.predicates().map(|p| p.syntax().text().to_string())); + } + res +} -- cgit v1.2.3 From 2fe075f56eff65ee6d326f7ea8bc0efccc4df152 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Mon, 8 Apr 2019 10:25:35 +0300 Subject: Normalize line-endings in display.rs This changes from CRLF to LF --- crates/ra_ide_api/src/display.rs | 224 +++++++++++++++++++-------------------- 1 file changed, 112 insertions(+), 112 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs index e01635460..4ce362ebb 100644 --- a/crates/ra_ide_api/src/display.rs +++ b/crates/ra_ide_api/src/display.rs @@ -1,112 +1,112 @@ -//! This module contains utilities for rendering turning things into something -//! that may be used to render in UI. -use super::*; -use std::fmt::{self, Display}; -use join_to_string::join; -use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner, TypeParamsOwner}; -use std::convert::From; - -/// Contains information about a function signature -#[derive(Debug)] -pub struct FunctionSignature { - /// Optional visibility - pub visibility: Option, - /// Name of the function - pub name: Option, - /// Documentation for the function - pub doc: Option, - /// Generic parameters - pub generic_parameters: Vec, - /// Parameters of the function - pub parameters: Vec, - /// Optional return type - pub ret_type: Option, - /// Where predicates - pub where_predicates: Vec, -} - -impl FunctionSignature { - pub(crate) fn with_doc_opt(mut self, doc: Option) -> Self { - self.doc = doc; - self - } -} - -impl From<&'_ ast::FnDef> for FunctionSignature { - fn from(node: &ast::FnDef) -> FunctionSignature { - fn param_list(node: &ast::FnDef) -> Vec { - let mut res = vec![]; - if let Some(param_list) = node.param_list() { - if let Some(self_param) = param_list.self_param() { - res.push(self_param.syntax().text().to_string()) - } - - res.extend(param_list.params().map(|param| param.syntax().text().to_string())); - } - res - } - - FunctionSignature { - visibility: node.visibility().map(|n| n.syntax().text().to_string()), - name: node.name().map(|n| n.text().to_string()), - ret_type: node - .ret_type() - .and_then(|r| r.type_ref()) - .map(|n| n.syntax().text().to_string()), - parameters: param_list(node), - generic_parameters: generic_parameters(node), - where_predicates: where_predicates(node), - // docs are processed separately - doc: None, - } - } -} - -impl Display for FunctionSignature { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(t) = &self.visibility { - write!(f, "{} ", t)?; - } - - if let Some(name) = &self.name { - write!(f, "fn {}", name)?; - } - - if !self.generic_parameters.is_empty() { - join(self.generic_parameters.iter()) - .separator(", ") - .surround_with("<", ">") - .to_fmt(f)?; - } - - join(self.parameters.iter()).separator(", ").surround_with("(", ")").to_fmt(f)?; - - if let Some(t) = &self.ret_type { - write!(f, " -> {}", t)?; - } - - if !self.where_predicates.is_empty() { - write!(f, "\nwhere ")?; - join(self.where_predicates.iter()).separator(",\n ").to_fmt(f)?; - } - - Ok(()) - } -} - -pub(crate) fn generic_parameters(node: &N) -> Vec { - let mut res = vec![]; - if let Some(type_params) = node.type_param_list() { - res.extend(type_params.lifetime_params().map(|p| p.syntax().text().to_string())); - res.extend(type_params.type_params().map(|p| p.syntax().text().to_string())); - } - res -} - -pub(crate) fn where_predicates(node: &N) -> Vec { - let mut res = vec![]; - if let Some(clause) = node.where_clause() { - res.extend(clause.predicates().map(|p| p.syntax().text().to_string())); - } - res -} +//! This module contains utilities for rendering turning things into something +//! that may be used to render in UI. +use super::*; +use std::fmt::{self, Display}; +use join_to_string::join; +use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner, TypeParamsOwner}; +use std::convert::From; + +/// Contains information about a function signature +#[derive(Debug)] +pub struct FunctionSignature { + /// Optional visibility + pub visibility: Option, + /// Name of the function + pub name: Option, + /// Documentation for the function + pub doc: Option, + /// Generic parameters + pub generic_parameters: Vec, + /// Parameters of the function + pub parameters: Vec, + /// Optional return type + pub ret_type: Option, + /// Where predicates + pub where_predicates: Vec, +} + +impl FunctionSignature { + pub(crate) fn with_doc_opt(mut self, doc: Option) -> Self { + self.doc = doc; + self + } +} + +impl From<&'_ ast::FnDef> for FunctionSignature { + fn from(node: &ast::FnDef) -> FunctionSignature { + fn param_list(node: &ast::FnDef) -> Vec { + let mut res = vec![]; + if let Some(param_list) = node.param_list() { + if let Some(self_param) = param_list.self_param() { + res.push(self_param.syntax().text().to_string()) + } + + res.extend(param_list.params().map(|param| param.syntax().text().to_string())); + } + res + } + + FunctionSignature { + visibility: node.visibility().map(|n| n.syntax().text().to_string()), + name: node.name().map(|n| n.text().to_string()), + ret_type: node + .ret_type() + .and_then(|r| r.type_ref()) + .map(|n| n.syntax().text().to_string()), + parameters: param_list(node), + generic_parameters: generic_parameters(node), + where_predicates: where_predicates(node), + // docs are processed separately + doc: None, + } + } +} + +impl Display for FunctionSignature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(t) = &self.visibility { + write!(f, "{} ", t)?; + } + + if let Some(name) = &self.name { + write!(f, "fn {}", name)?; + } + + if !self.generic_parameters.is_empty() { + join(self.generic_parameters.iter()) + .separator(", ") + .surround_with("<", ">") + .to_fmt(f)?; + } + + join(self.parameters.iter()).separator(", ").surround_with("(", ")").to_fmt(f)?; + + if let Some(t) = &self.ret_type { + write!(f, " -> {}", t)?; + } + + if !self.where_predicates.is_empty() { + write!(f, "\nwhere ")?; + join(self.where_predicates.iter()).separator(",\n ").to_fmt(f)?; + } + + Ok(()) + } +} + +pub(crate) fn generic_parameters(node: &N) -> Vec { + let mut res = vec![]; + if let Some(type_params) = node.type_param_list() { + res.extend(type_params.lifetime_params().map(|p| p.syntax().text().to_string())); + res.extend(type_params.type_params().map(|p| p.syntax().text().to_string())); + } + res +} + +pub(crate) fn where_predicates(node: &N) -> Vec { + let mut res = vec![]; + if let Some(clause) = node.where_clause() { + res.extend(clause.predicates().map(|p| p.syntax().text().to_string())); + } + res +} -- cgit v1.2.3 From dfaebd76aba1cfd7ac13b940d7847eb44b953cac Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Mon, 8 Apr 2019 10:46:26 +0300 Subject: Add FunctionSignature::from_hir --- crates/ra_ide_api/src/call_info.rs | 10 ++++------ crates/ra_ide_api/src/display.rs | 7 +++++++ 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index 66a769c73..dbb3853d0 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -6,7 +6,6 @@ use ra_syntax::{ ast::{self, ArgListOwner}, algo::find_node_at_offset, }; -use hir::Docs; use crate::{FilePosition, CallInfo, FunctionSignature, db::RootDatabase}; @@ -27,7 +26,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option FnCallNode<'a> { } impl CallInfo { - fn new(db: &RootDatabase, function: hir::Function, node: &ast::FnDef) -> Option { - let doc = function.docs(db); - let signature = FunctionSignature::from(node).with_doc_opt(doc); + fn new(db: &RootDatabase, function: hir::Function) -> Self { + let signature = FunctionSignature::from_hir(db, function); - Some(CallInfo { signature, active_parameter: None }) + CallInfo { signature, active_parameter: None } } fn parameters(&self) -> &[String] { diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs index 4ce362ebb..c05d59689 100644 --- a/crates/ra_ide_api/src/display.rs +++ b/crates/ra_ide_api/src/display.rs @@ -5,6 +5,7 @@ use std::fmt::{self, Display}; use join_to_string::join; use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner, TypeParamsOwner}; use std::convert::From; +use hir::Docs; /// Contains information about a function signature #[derive(Debug)] @@ -30,6 +31,12 @@ impl FunctionSignature { self.doc = doc; self } + + pub(crate) fn from_hir(db: &db::RootDatabase, function: hir::Function) -> Self { + let doc = function.docs(db); + let (_, ast_node) = function.source(db); + FunctionSignature::from(&*ast_node).with_doc_opt(doc) + } } impl From<&'_ ast::FnDef> for FunctionSignature { -- cgit v1.2.3 From 946b5789d1ea6385a345fcb4aa0658392ec44a51 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Mon, 8 Apr 2019 11:44:23 +0300 Subject: Move completion label functions to display --- crates/ra_ide_api/src/completion.rs | 28 ------------------------ crates/ra_ide_api/src/completion/presentation.rs | 5 ++++- crates/ra_ide_api/src/display.rs | 28 +++++++++++++++++++++++- crates/ra_ide_api/src/hover.rs | 2 +- 4 files changed, 32 insertions(+), 31 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs index 71a35c689..deff59cd3 100644 --- a/crates/ra_ide_api/src/completion.rs +++ b/crates/ra_ide_api/src/completion.rs @@ -13,12 +13,10 @@ mod complete_scope; mod complete_postfix; use ra_db::SourceDatabase; -use ra_syntax::{ast::{self, AstNode}, SyntaxKind::{ATTR, COMMENT}}; use crate::{ db, FilePosition, - FunctionSignature, completion::{ completion_item::{Completions, CompletionKind}, completion_context::CompletionContext, @@ -71,29 +69,3 @@ 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 { - Some(FunctionSignature::from(node).to_string()) -} - -pub fn const_label(node: &ast::ConstDef) -> String { - let label: String = node - .syntax() - .children_with_tokens() - .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR)) - .map(|node| node.to_string()) - .collect(); - - label.trim().to_owned() -} - -pub fn type_label(node: &ast::TypeAliasDef) -> String { - let label: String = node - .syntax() - .children_with_tokens() - .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR)) - .map(|node| node.to_string()) - .collect(); - - label.trim().to_owned() -} diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs index 28c8f83ab..9aa346688 100644 --- a/crates/ra_ide_api/src/completion/presentation.rs +++ b/crates/ra_ide_api/src/completion/presentation.rs @@ -6,6 +6,9 @@ use ra_syntax::ast::NameOwner; use crate::completion::{ Completions, CompletionKind, CompletionItemKind, CompletionContext, CompletionItem, +}; + +use crate::display::{ function_label, const_label, type_label, }; @@ -101,7 +104,7 @@ impl Completions { CompletionItemKind::Function }) .set_documentation(func.docs(ctx.db)) - .set_detail(detail); + .detail(detail); // If not an import, add parenthesis automatically. if ctx.use_item_syntax.is_none() && !ctx.is_call { tested_by!(inserts_parens_for_function_calls); diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs index c05d59689..efadb9b10 100644 --- a/crates/ra_ide_api/src/display.rs +++ b/crates/ra_ide_api/src/display.rs @@ -3,10 +3,36 @@ use super::*; use std::fmt::{self, Display}; use join_to_string::join; -use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner, TypeParamsOwner}; +use ra_syntax::{ast::{self, AstNode, NameOwner, VisibilityOwner, TypeParamsOwner}, SyntaxKind::{ATTR, COMMENT}}; use std::convert::From; use hir::Docs; +pub(crate) fn function_label(node: &ast::FnDef) -> String { + FunctionSignature::from(node).to_string() +} + +pub(crate) fn const_label(node: &ast::ConstDef) -> String { + let label: String = node + .syntax() + .children_with_tokens() + .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR)) + .map(|node| node.to_string()) + .collect(); + + label.trim().to_owned() +} + +pub(crate) fn type_label(node: &ast::TypeAliasDef) -> String { + let label: String = node + .syntax() + .children_with_tokens() + .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR)) + .map(|node| node.to_string()) + .collect(); + + label.trim().to_owned() +} + /// Contains information about a function signature #[derive(Debug)] pub struct FunctionSignature { diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index bfa7cd67a..7d2c57f82 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -235,7 +235,7 @@ impl NavigationTarget { } visitor() - .visit(crate::completion::function_label) + .visit(|node: &ast::FnDef| Some(crate::display::function_label(node))) .visit(|node: &ast::StructDef| visit_node(node, "struct ")) .visit(|node: &ast::EnumDef| visit_node(node, "enum ")) .visit(|node: &ast::TraitDef| visit_node(node, "trait ")) -- cgit v1.2.3 From 027d4d229d7be91630de95d0d3ef004327828bd6 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Mon, 8 Apr 2019 12:20:28 +0300 Subject: Move navigation_target to display/navigation_target --- crates/ra_ide_api/src/display.rs | 4 + crates/ra_ide_api/src/display/navigation_target.rs | 251 +++++++++++++++++++++ crates/ra_ide_api/src/lib.rs | 4 +- crates/ra_ide_api/src/navigation_target.rs | 251 --------------------- crates/ra_ide_api/src/symbol_index.rs | 2 +- 5 files changed, 257 insertions(+), 255 deletions(-) create mode 100644 crates/ra_ide_api/src/display/navigation_target.rs delete mode 100644 crates/ra_ide_api/src/navigation_target.rs (limited to 'crates') diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs index efadb9b10..f0c818933 100644 --- a/crates/ra_ide_api/src/display.rs +++ b/crates/ra_ide_api/src/display.rs @@ -7,6 +7,10 @@ use ra_syntax::{ast::{self, AstNode, NameOwner, VisibilityOwner, TypeParamsOwner use std::convert::From; use hir::Docs; +pub mod navigation_target; + +pub use navigation_target::NavigationTarget; + pub(crate) fn function_label(node: &ast::FnDef) -> String { FunctionSignature::from(node).to_string() } diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs new file mode 100644 index 000000000..f6d7f3192 --- /dev/null +++ b/crates/ra_ide_api/src/display/navigation_target.rs @@ -0,0 +1,251 @@ +use ra_db::FileId; +use ra_syntax::{ + SyntaxNode, SyntaxNodePtr, AstNode, SmolStr, TextRange, ast, + SyntaxKind::{self, NAME}, +}; +use hir::{ModuleSource, FieldSource, Name, ImplItem}; + +use crate::{FileSymbol, db::RootDatabase}; + +/// `NavigationTarget` represents and element in the editor's UI which you can +/// click on to navigate to a particular piece of code. +/// +/// Typically, a `NavigationTarget` corresponds to some element in the source +/// code, like a function or a struct, but this is not strictly required. +#[derive(Debug, Clone)] +pub struct NavigationTarget { + file_id: FileId, + name: SmolStr, + kind: SyntaxKind, + full_range: TextRange, + focus_range: Option, + container_name: Option, +} + +impl NavigationTarget { + /// When `focus_range` is specified, returns it. otherwise + /// returns `full_range` + pub fn range(&self) -> TextRange { + self.focus_range.unwrap_or(self.full_range) + } + + pub fn name(&self) -> &SmolStr { + &self.name + } + + pub fn container_name(&self) -> Option<&SmolStr> { + self.container_name.as_ref() + } + + pub fn kind(&self) -> SyntaxKind { + self.kind + } + + pub fn file_id(&self) -> FileId { + self.file_id + } + + pub fn full_range(&self) -> TextRange { + self.full_range + } + + /// A "most interesting" range withing the `full_range`. + /// + /// Typically, `full_range` is the whole syntax node, + /// including doc comments, and `focus_range` is the range of the identifier. + pub fn focus_range(&self) -> Option { + self.focus_range + } + + pub(crate) fn from_bind_pat(file_id: FileId, pat: &ast::BindPat) -> NavigationTarget { + NavigationTarget::from_named(file_id, pat) + } + + pub(crate) fn from_symbol(symbol: FileSymbol) -> NavigationTarget { + NavigationTarget { + file_id: symbol.file_id, + name: symbol.name.clone(), + kind: symbol.ptr.kind(), + full_range: symbol.ptr.range(), + focus_range: symbol.name_range, + container_name: symbol.container_name.clone(), + } + } + + pub(crate) fn from_scope_entry( + file_id: FileId, + name: Name, + ptr: SyntaxNodePtr, + ) -> NavigationTarget { + NavigationTarget { + file_id, + name: name.to_string().into(), + full_range: ptr.range(), + focus_range: None, + kind: NAME, + container_name: None, + } + } + + pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget { + let (file_id, source) = module.definition_source(db); + let file_id = file_id.as_original_file(); + let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); + match source { + ModuleSource::SourceFile(node) => { + NavigationTarget::from_syntax(file_id, name, None, node.syntax()) + } + ModuleSource::Module(node) => { + NavigationTarget::from_syntax(file_id, name, None, node.syntax()) + } + } + } + + pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { + let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); + if let Some((file_id, source)) = module.declaration_source(db) { + let file_id = file_id.as_original_file(); + return NavigationTarget::from_syntax(file_id, name, None, source.syntax()); + } + NavigationTarget::from_module(db, module) + } + + pub(crate) fn from_function(db: &RootDatabase, func: hir::Function) -> NavigationTarget { + let (file_id, fn_def) = func.source(db); + NavigationTarget::from_named(file_id.original_file(db), &*fn_def) + } + + pub(crate) fn from_field(db: &RootDatabase, field: hir::StructField) -> NavigationTarget { + let (file_id, field) = field.source(db); + let file_id = file_id.original_file(db); + match field { + FieldSource::Named(it) => NavigationTarget::from_named(file_id, &*it), + FieldSource::Pos(it) => { + NavigationTarget::from_syntax(file_id, "".into(), None, it.syntax()) + } + } + } + + pub(crate) fn from_adt_def(db: &RootDatabase, adt_def: hir::AdtDef) -> NavigationTarget { + match adt_def { + hir::AdtDef::Struct(s) => { + let (file_id, node) = s.source(db); + NavigationTarget::from_named(file_id.original_file(db), &*node) + } + hir::AdtDef::Enum(s) => { + let (file_id, node) = s.source(db); + NavigationTarget::from_named(file_id.original_file(db), &*node) + } + } + } + + pub(crate) fn from_def(db: &RootDatabase, module_def: hir::ModuleDef) -> NavigationTarget { + match module_def { + hir::ModuleDef::Module(module) => NavigationTarget::from_module(db, module), + hir::ModuleDef::Function(func) => NavigationTarget::from_function(db, func), + hir::ModuleDef::Struct(s) => { + let (file_id, node) = s.source(db); + NavigationTarget::from_named(file_id.original_file(db), &*node) + } + hir::ModuleDef::Const(s) => { + let (file_id, node) = s.source(db); + NavigationTarget::from_named(file_id.original_file(db), &*node) + } + hir::ModuleDef::Static(s) => { + let (file_id, node) = s.source(db); + NavigationTarget::from_named(file_id.original_file(db), &*node) + } + hir::ModuleDef::Enum(e) => { + let (file_id, node) = e.source(db); + NavigationTarget::from_named(file_id.original_file(db), &*node) + } + hir::ModuleDef::EnumVariant(var) => { + let (file_id, node) = var.source(db); + NavigationTarget::from_named(file_id.original_file(db), &*node) + } + hir::ModuleDef::Trait(e) => { + let (file_id, node) = e.source(db); + NavigationTarget::from_named(file_id.original_file(db), &*node) + } + hir::ModuleDef::TypeAlias(e) => { + let (file_id, node) = e.source(db); + NavigationTarget::from_named(file_id.original_file(db), &*node) + } + } + } + + pub(crate) fn from_impl_block( + db: &RootDatabase, + impl_block: hir::ImplBlock, + ) -> NavigationTarget { + let (file_id, node) = impl_block.source(db); + NavigationTarget::from_syntax( + file_id.as_original_file(), + "impl".into(), + None, + node.syntax(), + ) + } + + pub(crate) fn from_impl_item(db: &RootDatabase, impl_item: hir::ImplItem) -> NavigationTarget { + match impl_item { + ImplItem::Method(f) => NavigationTarget::from_function(db, f), + ImplItem::Const(c) => { + let (file_id, node) = c.source(db); + NavigationTarget::from_named(file_id.original_file(db), &*node) + } + ImplItem::TypeAlias(a) => { + let (file_id, node) = a.source(db); + NavigationTarget::from_named(file_id.original_file(db), &*node) + } + } + } + + #[cfg(test)] + pub(crate) fn assert_match(&self, expected: &str) { + let actual = self.debug_render(); + test_utils::assert_eq_text!(expected.trim(), actual.trim(),); + } + + #[cfg(test)] + pub(crate) fn debug_render(&self) -> String { + let mut buf = format!( + "{} {:?} {:?} {:?}", + self.name(), + self.kind(), + self.file_id(), + self.full_range() + ); + if let Some(focus_range) = self.focus_range() { + buf.push_str(&format!(" {:?}", focus_range)) + } + if let Some(container_name) = self.container_name() { + buf.push_str(&format!(" {}", container_name)) + } + buf + } + + /// Allows `NavigationTarget` to be created from a `NameOwner` + pub(crate) fn from_named(file_id: FileId, node: &impl ast::NameOwner) -> NavigationTarget { + let name = node.name().map(|it| it.text().clone()).unwrap_or_default(); + let focus_range = node.name().map(|it| it.syntax().range()); + NavigationTarget::from_syntax(file_id, name, focus_range, node.syntax()) + } + + fn from_syntax( + file_id: FileId, + name: SmolStr, + focus_range: Option, + node: &SyntaxNode, + ) -> NavigationTarget { + NavigationTarget { + file_id, + name, + kind: node.kind(), + full_range: node.range(), + focus_range, + // ptr: Some(LocalSyntaxPtr::new(node)), + container_name: None, + } + } +} diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index 816bab94f..d76012a8c 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs @@ -13,7 +13,6 @@ mod db; pub mod mock_analysis; mod symbol_index; -mod navigation_target; mod change; mod status; @@ -63,7 +62,6 @@ pub use crate::{ change::{AnalysisChange, LibraryData}, completion::{CompletionItem, CompletionItemKind, InsertTextFormat}, runnables::{Runnable, RunnableKind}, - navigation_target::NavigationTarget, references::ReferenceSearchResult, assists::{Assist, AssistId}, hover::{HoverResult}, @@ -73,7 +71,7 @@ pub use crate::{ syntax_highlighting::HighlightedRange, structure::{StructureNode, file_structure}, diagnostics::Severity, - display::FunctionSignature, + display::{FunctionSignature, NavigationTarget}, }; pub use ra_db::{ diff --git a/crates/ra_ide_api/src/navigation_target.rs b/crates/ra_ide_api/src/navigation_target.rs deleted file mode 100644 index f6d7f3192..000000000 --- a/crates/ra_ide_api/src/navigation_target.rs +++ /dev/null @@ -1,251 +0,0 @@ -use ra_db::FileId; -use ra_syntax::{ - SyntaxNode, SyntaxNodePtr, AstNode, SmolStr, TextRange, ast, - SyntaxKind::{self, NAME}, -}; -use hir::{ModuleSource, FieldSource, Name, ImplItem}; - -use crate::{FileSymbol, db::RootDatabase}; - -/// `NavigationTarget` represents and element in the editor's UI which you can -/// click on to navigate to a particular piece of code. -/// -/// Typically, a `NavigationTarget` corresponds to some element in the source -/// code, like a function or a struct, but this is not strictly required. -#[derive(Debug, Clone)] -pub struct NavigationTarget { - file_id: FileId, - name: SmolStr, - kind: SyntaxKind, - full_range: TextRange, - focus_range: Option, - container_name: Option, -} - -impl NavigationTarget { - /// When `focus_range` is specified, returns it. otherwise - /// returns `full_range` - pub fn range(&self) -> TextRange { - self.focus_range.unwrap_or(self.full_range) - } - - pub fn name(&self) -> &SmolStr { - &self.name - } - - pub fn container_name(&self) -> Option<&SmolStr> { - self.container_name.as_ref() - } - - pub fn kind(&self) -> SyntaxKind { - self.kind - } - - pub fn file_id(&self) -> FileId { - self.file_id - } - - pub fn full_range(&self) -> TextRange { - self.full_range - } - - /// A "most interesting" range withing the `full_range`. - /// - /// Typically, `full_range` is the whole syntax node, - /// including doc comments, and `focus_range` is the range of the identifier. - pub fn focus_range(&self) -> Option { - self.focus_range - } - - pub(crate) fn from_bind_pat(file_id: FileId, pat: &ast::BindPat) -> NavigationTarget { - NavigationTarget::from_named(file_id, pat) - } - - pub(crate) fn from_symbol(symbol: FileSymbol) -> NavigationTarget { - NavigationTarget { - file_id: symbol.file_id, - name: symbol.name.clone(), - kind: symbol.ptr.kind(), - full_range: symbol.ptr.range(), - focus_range: symbol.name_range, - container_name: symbol.container_name.clone(), - } - } - - pub(crate) fn from_scope_entry( - file_id: FileId, - name: Name, - ptr: SyntaxNodePtr, - ) -> NavigationTarget { - NavigationTarget { - file_id, - name: name.to_string().into(), - full_range: ptr.range(), - focus_range: None, - kind: NAME, - container_name: None, - } - } - - pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget { - let (file_id, source) = module.definition_source(db); - let file_id = file_id.as_original_file(); - let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); - match source { - ModuleSource::SourceFile(node) => { - NavigationTarget::from_syntax(file_id, name, None, node.syntax()) - } - ModuleSource::Module(node) => { - NavigationTarget::from_syntax(file_id, name, None, node.syntax()) - } - } - } - - pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { - let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); - if let Some((file_id, source)) = module.declaration_source(db) { - let file_id = file_id.as_original_file(); - return NavigationTarget::from_syntax(file_id, name, None, source.syntax()); - } - NavigationTarget::from_module(db, module) - } - - pub(crate) fn from_function(db: &RootDatabase, func: hir::Function) -> NavigationTarget { - let (file_id, fn_def) = func.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*fn_def) - } - - pub(crate) fn from_field(db: &RootDatabase, field: hir::StructField) -> NavigationTarget { - let (file_id, field) = field.source(db); - let file_id = file_id.original_file(db); - match field { - FieldSource::Named(it) => NavigationTarget::from_named(file_id, &*it), - FieldSource::Pos(it) => { - NavigationTarget::from_syntax(file_id, "".into(), None, it.syntax()) - } - } - } - - pub(crate) fn from_adt_def(db: &RootDatabase, adt_def: hir::AdtDef) -> NavigationTarget { - match adt_def { - hir::AdtDef::Struct(s) => { - let (file_id, node) = s.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) - } - hir::AdtDef::Enum(s) => { - let (file_id, node) = s.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) - } - } - } - - pub(crate) fn from_def(db: &RootDatabase, module_def: hir::ModuleDef) -> NavigationTarget { - match module_def { - hir::ModuleDef::Module(module) => NavigationTarget::from_module(db, module), - hir::ModuleDef::Function(func) => NavigationTarget::from_function(db, func), - hir::ModuleDef::Struct(s) => { - let (file_id, node) = s.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) - } - hir::ModuleDef::Const(s) => { - let (file_id, node) = s.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) - } - hir::ModuleDef::Static(s) => { - let (file_id, node) = s.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) - } - hir::ModuleDef::Enum(e) => { - let (file_id, node) = e.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) - } - hir::ModuleDef::EnumVariant(var) => { - let (file_id, node) = var.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) - } - hir::ModuleDef::Trait(e) => { - let (file_id, node) = e.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) - } - hir::ModuleDef::TypeAlias(e) => { - let (file_id, node) = e.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) - } - } - } - - pub(crate) fn from_impl_block( - db: &RootDatabase, - impl_block: hir::ImplBlock, - ) -> NavigationTarget { - let (file_id, node) = impl_block.source(db); - NavigationTarget::from_syntax( - file_id.as_original_file(), - "impl".into(), - None, - node.syntax(), - ) - } - - pub(crate) fn from_impl_item(db: &RootDatabase, impl_item: hir::ImplItem) -> NavigationTarget { - match impl_item { - ImplItem::Method(f) => NavigationTarget::from_function(db, f), - ImplItem::Const(c) => { - let (file_id, node) = c.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) - } - ImplItem::TypeAlias(a) => { - let (file_id, node) = a.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) - } - } - } - - #[cfg(test)] - pub(crate) fn assert_match(&self, expected: &str) { - let actual = self.debug_render(); - test_utils::assert_eq_text!(expected.trim(), actual.trim(),); - } - - #[cfg(test)] - pub(crate) fn debug_render(&self) -> String { - let mut buf = format!( - "{} {:?} {:?} {:?}", - self.name(), - self.kind(), - self.file_id(), - self.full_range() - ); - if let Some(focus_range) = self.focus_range() { - buf.push_str(&format!(" {:?}", focus_range)) - } - if let Some(container_name) = self.container_name() { - buf.push_str(&format!(" {}", container_name)) - } - buf - } - - /// Allows `NavigationTarget` to be created from a `NameOwner` - pub(crate) fn from_named(file_id: FileId, node: &impl ast::NameOwner) -> NavigationTarget { - let name = node.name().map(|it| it.text().clone()).unwrap_or_default(); - let focus_range = node.name().map(|it| it.syntax().range()); - NavigationTarget::from_syntax(file_id, name, focus_range, node.syntax()) - } - - fn from_syntax( - file_id: FileId, - name: SmolStr, - focus_range: Option, - node: &SyntaxNode, - ) -> NavigationTarget { - NavigationTarget { - file_id, - name, - kind: node.kind(), - full_range: node.range(), - focus_range, - // ptr: Some(LocalSyntaxPtr::new(node)), - container_name: None, - } - } -} diff --git a/crates/ra_ide_api/src/symbol_index.rs b/crates/ra_ide_api/src/symbol_index.rs index 0eadc4e71..914d3fc71 100644 --- a/crates/ra_ide_api/src/symbol_index.rs +++ b/crates/ra_ide_api/src/symbol_index.rs @@ -275,7 +275,7 @@ fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option { mod tests { use ra_syntax::SmolStr; use crate::{ - navigation_target::NavigationTarget, + display::NavigationTarget, mock_analysis::single_file, Query, }; -- cgit v1.2.3 From 7821c56be7fc1699f6fb748e45f4765162b75ba9 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Mon, 8 Apr 2019 16:04:58 +0300 Subject: Move structure to display/structure --- crates/ra_ide_api/src/display.rs | 6 +- .../display/snapshots/tests__file_structure.snap | 182 ++++++++++++++++++++ crates/ra_ide_api/src/display/structure.rs | 190 +++++++++++++++++++++ crates/ra_ide_api/src/lib.rs | 6 +- .../src/snapshots/tests__file_structure.snap | 182 -------------------- crates/ra_ide_api/src/structure.rs | 190 --------------------- 6 files changed, 378 insertions(+), 378 deletions(-) create mode 100644 crates/ra_ide_api/src/display/snapshots/tests__file_structure.snap create mode 100644 crates/ra_ide_api/src/display/structure.rs delete mode 100644 crates/ra_ide_api/src/snapshots/tests__file_structure.snap delete mode 100644 crates/ra_ide_api/src/structure.rs (limited to 'crates') diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs index f0c818933..7a1f40fcf 100644 --- a/crates/ra_ide_api/src/display.rs +++ b/crates/ra_ide_api/src/display.rs @@ -1,5 +1,5 @@ -//! This module contains utilities for rendering turning things into something -//! that may be used to render in UI. +//! This module contains utilities for turning SyntaxNodes and HIR types +//! into things that may be used to render in a UI. use super::*; use std::fmt::{self, Display}; use join_to_string::join; @@ -8,8 +8,10 @@ use std::convert::From; use hir::Docs; pub mod navigation_target; +pub mod structure; pub use navigation_target::NavigationTarget; +pub use structure::StructureNode; pub(crate) fn function_label(node: &ast::FnDef) -> String { FunctionSignature::from(node).to_string() diff --git a/crates/ra_ide_api/src/display/snapshots/tests__file_structure.snap b/crates/ra_ide_api/src/display/snapshots/tests__file_structure.snap new file mode 100644 index 000000000..32dd99484 --- /dev/null +++ b/crates/ra_ide_api/src/display/snapshots/tests__file_structure.snap @@ -0,0 +1,182 @@ +--- +created: "2019-04-08T09:44:50.196004400Z" +creator: insta@0.7.4 +source: crates/ra_ide_api/src/display/structure.rs +expression: structure +--- +[ + StructureNode { + parent: None, + label: "Foo", + navigation_range: [8; 11), + node_range: [1; 26), + kind: STRUCT_DEF, + detail: None, + deprecated: false + }, + StructureNode { + parent: Some( + 0 + ), + label: "x", + navigation_range: [18; 19), + node_range: [18; 24), + kind: NAMED_FIELD_DEF, + detail: Some( + "i32" + ), + deprecated: false + }, + StructureNode { + parent: None, + label: "m", + navigation_range: [32; 33), + node_range: [28; 158), + kind: MODULE, + detail: None, + deprecated: false + }, + StructureNode { + parent: Some( + 2 + ), + label: "bar1", + navigation_range: [43; 47), + node_range: [40; 52), + kind: FN_DEF, + detail: Some( + "fn()" + ), + deprecated: false + }, + StructureNode { + parent: Some( + 2 + ), + label: "bar2", + navigation_range: [60; 64), + node_range: [57; 81), + kind: FN_DEF, + detail: Some( + "fn(t: T) -> T" + ), + deprecated: false + }, + StructureNode { + parent: Some( + 2 + ), + label: "bar3", + navigation_range: [89; 93), + node_range: [86; 156), + kind: FN_DEF, + detail: Some( + "fn(a: A, b: B) -> Vec< u32 >" + ), + deprecated: false + }, + StructureNode { + parent: None, + label: "E", + navigation_range: [165; 166), + node_range: [160; 180), + kind: ENUM_DEF, + detail: None, + deprecated: false + }, + StructureNode { + parent: Some( + 6 + ), + label: "X", + navigation_range: [169; 170), + node_range: [169; 170), + kind: ENUM_VARIANT, + detail: None, + deprecated: false + }, + StructureNode { + parent: Some( + 6 + ), + label: "Y", + navigation_range: [172; 173), + node_range: [172; 178), + kind: ENUM_VARIANT, + detail: None, + deprecated: false + }, + StructureNode { + parent: None, + label: "T", + navigation_range: [186; 187), + node_range: [181; 193), + kind: TYPE_ALIAS_DEF, + detail: Some( + "()" + ), + deprecated: false + }, + StructureNode { + parent: None, + label: "S", + navigation_range: [201; 202), + node_range: [194; 213), + kind: STATIC_DEF, + detail: Some( + "i32" + ), + deprecated: false + }, + StructureNode { + parent: None, + label: "C", + navigation_range: [220; 221), + node_range: [214; 232), + kind: CONST_DEF, + detail: Some( + "i32" + ), + deprecated: false + }, + StructureNode { + parent: None, + label: "impl E", + navigation_range: [239; 240), + node_range: [234; 243), + kind: IMPL_BLOCK, + detail: None, + deprecated: false + }, + StructureNode { + parent: None, + label: "impl fmt::Debug for E", + navigation_range: [265; 266), + node_range: [245; 269), + kind: IMPL_BLOCK, + detail: None, + deprecated: false + }, + StructureNode { + parent: None, + label: "obsolete", + navigation_range: [288; 296), + node_range: [271; 301), + kind: FN_DEF, + detail: Some( + "fn()" + ), + deprecated: true + }, + StructureNode { + parent: None, + label: "very_obsolete", + navigation_range: [341; 354), + node_range: [303; 359), + kind: FN_DEF, + detail: Some( + "fn()" + ), + deprecated: true + } +] diff --git a/crates/ra_ide_api/src/display/structure.rs b/crates/ra_ide_api/src/display/structure.rs new file mode 100644 index 000000000..ec2c9bbc6 --- /dev/null +++ b/crates/ra_ide_api/src/display/structure.rs @@ -0,0 +1,190 @@ +use crate::TextRange; + +use ra_syntax::{ + algo::visit::{visitor, Visitor}, + ast::{self, AttrsOwner, NameOwner, TypeParamsOwner, TypeAscriptionOwner}, + AstNode, SourceFile, SyntaxKind, SyntaxNode, WalkEvent, +}; + +#[derive(Debug, Clone)] +pub struct StructureNode { + pub parent: Option, + pub label: String, + pub navigation_range: TextRange, + pub node_range: TextRange, + pub kind: SyntaxKind, + pub detail: Option, + pub deprecated: bool, +} + +pub fn file_structure(file: &SourceFile) -> Vec { + let mut res = Vec::new(); + let mut stack = Vec::new(); + + for event in file.syntax().preorder() { + match event { + WalkEvent::Enter(node) => { + if let Some(mut symbol) = structure_node(node) { + symbol.parent = stack.last().map(|&n| n); + stack.push(res.len()); + res.push(symbol); + } + } + WalkEvent::Leave(node) => { + if structure_node(node).is_some() { + stack.pop().unwrap(); + } + } + } + } + res +} + +fn structure_node(node: &SyntaxNode) -> Option { + fn decl(node: &N) -> Option { + decl_with_detail(node, None) + } + + fn decl_with_ascription( + node: &N, + ) -> Option { + decl_with_type_ref(node, node.ascribed_type()) + } + + fn decl_with_type_ref( + node: &N, + type_ref: Option<&ast::TypeRef>, + ) -> Option { + let detail = type_ref.map(|type_ref| { + let mut detail = String::new(); + collapse_ws(type_ref.syntax(), &mut detail); + detail + }); + decl_with_detail(node, detail) + } + + fn decl_with_detail( + node: &N, + detail: Option, + ) -> Option { + let name = node.name()?; + + Some(StructureNode { + parent: None, + label: name.text().to_string(), + navigation_range: name.syntax().range(), + node_range: node.syntax().range(), + kind: node.syntax().kind(), + detail, + deprecated: node.attrs().filter_map(|x| x.as_named()).any(|x| x == "deprecated"), + }) + } + + fn collapse_ws(node: &SyntaxNode, output: &mut String) { + let mut can_insert_ws = false; + for line in node.text().chunks().flat_map(|chunk| chunk.lines()) { + let line = line.trim(); + if line.is_empty() { + if can_insert_ws { + output.push_str(" "); + can_insert_ws = false; + } + } else { + output.push_str(line); + can_insert_ws = true; + } + } + } + + visitor() + .visit(|fn_def: &ast::FnDef| { + let mut detail = String::from("fn"); + if let Some(type_param_list) = fn_def.type_param_list() { + collapse_ws(type_param_list.syntax(), &mut detail); + } + if let Some(param_list) = fn_def.param_list() { + collapse_ws(param_list.syntax(), &mut detail); + } + if let Some(ret_type) = fn_def.ret_type() { + detail.push_str(" "); + collapse_ws(ret_type.syntax(), &mut detail); + } + + decl_with_detail(fn_def, Some(detail)) + }) + .visit(decl::) + .visit(decl::) + .visit(decl::) + .visit(decl::) + .visit(decl::) + .visit(|td: &ast::TypeAliasDef| decl_with_type_ref(td, td.type_ref())) + .visit(decl_with_ascription::) + .visit(decl_with_ascription::) + .visit(decl_with_ascription::) + .visit(|im: &ast::ImplBlock| { + let target_type = im.target_type()?; + let target_trait = im.target_trait(); + let label = match target_trait { + None => format!("impl {}", target_type.syntax().text()), + Some(t) => { + format!("impl {} for {}", t.syntax().text(), target_type.syntax().text(),) + } + }; + + let node = StructureNode { + parent: None, + label, + navigation_range: target_type.syntax().range(), + node_range: im.syntax().range(), + kind: im.syntax().kind(), + detail: None, + deprecated: false, + }; + Some(node) + }) + .accept(node)? +} + +#[cfg(test)] +mod tests { + use super::*; + use insta::assert_debug_snapshot_matches; + + #[test] + fn test_file_structure() { + let file = SourceFile::parse( + r#" +struct Foo { + x: i32 +} + +mod m { + fn bar1() {} + fn bar2(t: T) -> T {} + fn bar3(a: A, + b: B) -> Vec< + u32 + > {} +} + +enum E { X, Y(i32) } +type T = (); +static S: i32 = 92; +const C: i32 = 92; + +impl E {} + +impl fmt::Debug for E {} + +#[deprecated] +fn obsolete() {} + +#[deprecated(note = "for awhile")] +fn very_obsolete() {} +"#, + ); + let structure = file_structure(&file); + assert_debug_snapshot_matches!("file_structure", structure); + } +} diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index d76012a8c..974820a69 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs @@ -33,7 +33,6 @@ mod folding_ranges; mod line_index; mod line_index_utils; mod join_lines; -mod structure; mod typing; mod matching_brace; mod display; @@ -69,9 +68,8 @@ pub use crate::{ line_index_utils::translate_offset_with_edit, folding_ranges::{Fold, FoldKind}, syntax_highlighting::HighlightedRange, - structure::{StructureNode, file_structure}, diagnostics::Severity, - display::{FunctionSignature, NavigationTarget}, + display::{FunctionSignature, NavigationTarget, structure::{StructureNode, file_structure}}, }; pub use ra_db::{ @@ -385,7 +383,7 @@ impl Analysis { /// file outline. pub fn file_structure(&self, file_id: FileId) -> Vec { let file = self.db.parse(file_id); - structure::file_structure(&file) + file_structure(&file) } /// Returns the set of folding ranges. diff --git a/crates/ra_ide_api/src/snapshots/tests__file_structure.snap b/crates/ra_ide_api/src/snapshots/tests__file_structure.snap deleted file mode 100644 index 2efa8e22c..000000000 --- a/crates/ra_ide_api/src/snapshots/tests__file_structure.snap +++ /dev/null @@ -1,182 +0,0 @@ ---- -created: "2019-02-05T22:03:50.763530100Z" -creator: insta@0.6.1 -source: crates/ra_ide_api/src/structure.rs -expression: structure ---- -[ - StructureNode { - parent: None, - label: "Foo", - navigation_range: [8; 11), - node_range: [1; 26), - kind: STRUCT_DEF, - detail: None, - deprecated: false - }, - StructureNode { - parent: Some( - 0 - ), - label: "x", - navigation_range: [18; 19), - node_range: [18; 24), - kind: NAMED_FIELD_DEF, - detail: Some( - "i32" - ), - deprecated: false - }, - StructureNode { - parent: None, - label: "m", - navigation_range: [32; 33), - node_range: [28; 158), - kind: MODULE, - detail: None, - deprecated: false - }, - StructureNode { - parent: Some( - 2 - ), - label: "bar1", - navigation_range: [43; 47), - node_range: [40; 52), - kind: FN_DEF, - detail: Some( - "fn()" - ), - deprecated: false - }, - StructureNode { - parent: Some( - 2 - ), - label: "bar2", - navigation_range: [60; 64), - node_range: [57; 81), - kind: FN_DEF, - detail: Some( - "fn(t: T) -> T" - ), - deprecated: false - }, - StructureNode { - parent: Some( - 2 - ), - label: "bar3", - navigation_range: [89; 93), - node_range: [86; 156), - kind: FN_DEF, - detail: Some( - "fn(a: A, b: B) -> Vec< u32 >" - ), - deprecated: false - }, - StructureNode { - parent: None, - label: "E", - navigation_range: [165; 166), - node_range: [160; 180), - kind: ENUM_DEF, - detail: None, - deprecated: false - }, - StructureNode { - parent: Some( - 6 - ), - label: "X", - navigation_range: [169; 170), - node_range: [169; 170), - kind: ENUM_VARIANT, - detail: None, - deprecated: false - }, - StructureNode { - parent: Some( - 6 - ), - label: "Y", - navigation_range: [172; 173), - node_range: [172; 178), - kind: ENUM_VARIANT, - detail: None, - deprecated: false - }, - StructureNode { - parent: None, - label: "T", - navigation_range: [186; 187), - node_range: [181; 193), - kind: TYPE_ALIAS_DEF, - detail: Some( - "()" - ), - deprecated: false - }, - StructureNode { - parent: None, - label: "S", - navigation_range: [201; 202), - node_range: [194; 213), - kind: STATIC_DEF, - detail: Some( - "i32" - ), - deprecated: false - }, - StructureNode { - parent: None, - label: "C", - navigation_range: [220; 221), - node_range: [214; 232), - kind: CONST_DEF, - detail: Some( - "i32" - ), - deprecated: false - }, - StructureNode { - parent: None, - label: "impl E", - navigation_range: [239; 240), - node_range: [234; 243), - kind: IMPL_BLOCK, - detail: None, - deprecated: false - }, - StructureNode { - parent: None, - label: "impl fmt::Debug for E", - navigation_range: [265; 266), - node_range: [245; 269), - kind: IMPL_BLOCK, - detail: None, - deprecated: false - }, - StructureNode { - parent: None, - label: "obsolete", - navigation_range: [288; 296), - node_range: [271; 301), - kind: FN_DEF, - detail: Some( - "fn()" - ), - deprecated: true - }, - StructureNode { - parent: None, - label: "very_obsolete", - navigation_range: [341; 354), - node_range: [303; 359), - kind: FN_DEF, - detail: Some( - "fn()" - ), - deprecated: true - } -] diff --git a/crates/ra_ide_api/src/structure.rs b/crates/ra_ide_api/src/structure.rs deleted file mode 100644 index ec2c9bbc6..000000000 --- a/crates/ra_ide_api/src/structure.rs +++ /dev/null @@ -1,190 +0,0 @@ -use crate::TextRange; - -use ra_syntax::{ - algo::visit::{visitor, Visitor}, - ast::{self, AttrsOwner, NameOwner, TypeParamsOwner, TypeAscriptionOwner}, - AstNode, SourceFile, SyntaxKind, SyntaxNode, WalkEvent, -}; - -#[derive(Debug, Clone)] -pub struct StructureNode { - pub parent: Option, - pub label: String, - pub navigation_range: TextRange, - pub node_range: TextRange, - pub kind: SyntaxKind, - pub detail: Option, - pub deprecated: bool, -} - -pub fn file_structure(file: &SourceFile) -> Vec { - let mut res = Vec::new(); - let mut stack = Vec::new(); - - for event in file.syntax().preorder() { - match event { - WalkEvent::Enter(node) => { - if let Some(mut symbol) = structure_node(node) { - symbol.parent = stack.last().map(|&n| n); - stack.push(res.len()); - res.push(symbol); - } - } - WalkEvent::Leave(node) => { - if structure_node(node).is_some() { - stack.pop().unwrap(); - } - } - } - } - res -} - -fn structure_node(node: &SyntaxNode) -> Option { - fn decl(node: &N) -> Option { - decl_with_detail(node, None) - } - - fn decl_with_ascription( - node: &N, - ) -> Option { - decl_with_type_ref(node, node.ascribed_type()) - } - - fn decl_with_type_ref( - node: &N, - type_ref: Option<&ast::TypeRef>, - ) -> Option { - let detail = type_ref.map(|type_ref| { - let mut detail = String::new(); - collapse_ws(type_ref.syntax(), &mut detail); - detail - }); - decl_with_detail(node, detail) - } - - fn decl_with_detail( - node: &N, - detail: Option, - ) -> Option { - let name = node.name()?; - - Some(StructureNode { - parent: None, - label: name.text().to_string(), - navigation_range: name.syntax().range(), - node_range: node.syntax().range(), - kind: node.syntax().kind(), - detail, - deprecated: node.attrs().filter_map(|x| x.as_named()).any(|x| x == "deprecated"), - }) - } - - fn collapse_ws(node: &SyntaxNode, output: &mut String) { - let mut can_insert_ws = false; - for line in node.text().chunks().flat_map(|chunk| chunk.lines()) { - let line = line.trim(); - if line.is_empty() { - if can_insert_ws { - output.push_str(" "); - can_insert_ws = false; - } - } else { - output.push_str(line); - can_insert_ws = true; - } - } - } - - visitor() - .visit(|fn_def: &ast::FnDef| { - let mut detail = String::from("fn"); - if let Some(type_param_list) = fn_def.type_param_list() { - collapse_ws(type_param_list.syntax(), &mut detail); - } - if let Some(param_list) = fn_def.param_list() { - collapse_ws(param_list.syntax(), &mut detail); - } - if let Some(ret_type) = fn_def.ret_type() { - detail.push_str(" "); - collapse_ws(ret_type.syntax(), &mut detail); - } - - decl_with_detail(fn_def, Some(detail)) - }) - .visit(decl::) - .visit(decl::) - .visit(decl::) - .visit(decl::) - .visit(decl::) - .visit(|td: &ast::TypeAliasDef| decl_with_type_ref(td, td.type_ref())) - .visit(decl_with_ascription::) - .visit(decl_with_ascription::) - .visit(decl_with_ascription::) - .visit(|im: &ast::ImplBlock| { - let target_type = im.target_type()?; - let target_trait = im.target_trait(); - let label = match target_trait { - None => format!("impl {}", target_type.syntax().text()), - Some(t) => { - format!("impl {} for {}", t.syntax().text(), target_type.syntax().text(),) - } - }; - - let node = StructureNode { - parent: None, - label, - navigation_range: target_type.syntax().range(), - node_range: im.syntax().range(), - kind: im.syntax().kind(), - detail: None, - deprecated: false, - }; - Some(node) - }) - .accept(node)? -} - -#[cfg(test)] -mod tests { - use super::*; - use insta::assert_debug_snapshot_matches; - - #[test] - fn test_file_structure() { - let file = SourceFile::parse( - r#" -struct Foo { - x: i32 -} - -mod m { - fn bar1() {} - fn bar2(t: T) -> T {} - fn bar3(a: A, - b: B) -> Vec< - u32 - > {} -} - -enum E { X, Y(i32) } -type T = (); -static S: i32 = 92; -const C: i32 = 92; - -impl E {} - -impl fmt::Debug for E {} - -#[deprecated] -fn obsolete() {} - -#[deprecated(note = "for awhile")] -fn very_obsolete() {} -"#, - ); - let structure = file_structure(&file); - assert_debug_snapshot_matches!("file_structure", structure); - } -} -- cgit v1.2.3 From bd6ddfcddebf532e5fa0fe89c00a53e59a5d0704 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Mon, 8 Apr 2019 16:07:50 +0300 Subject: Make display modules private --- crates/ra_ide_api/src/display.rs | 9 +++++---- crates/ra_ide_api/src/lib.rs | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs index 7a1f40fcf..e29ae3371 100644 --- a/crates/ra_ide_api/src/display.rs +++ b/crates/ra_ide_api/src/display.rs @@ -1,5 +1,9 @@ //! This module contains utilities for turning SyntaxNodes and HIR types //! into things that may be used to render in a UI. + +mod navigation_target; +mod structure; + use super::*; use std::fmt::{self, Display}; use join_to_string::join; @@ -7,11 +11,8 @@ use ra_syntax::{ast::{self, AstNode, NameOwner, VisibilityOwner, TypeParamsOwner use std::convert::From; use hir::Docs; -pub mod navigation_target; -pub mod structure; - pub use navigation_target::NavigationTarget; -pub use structure::StructureNode; +pub use structure::{StructureNode, file_structure}; pub(crate) fn function_label(node: &ast::FnDef) -> String { FunctionSignature::from(node).to_string() diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index 974820a69..d25795adc 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs @@ -69,7 +69,7 @@ pub use crate::{ folding_ranges::{Fold, FoldKind}, syntax_highlighting::HighlightedRange, diagnostics::Severity, - display::{FunctionSignature, NavigationTarget, structure::{StructureNode, file_structure}}, + display::{FunctionSignature, NavigationTarget, StructureNode, file_structure}, }; pub use ra_db::{ -- cgit v1.2.3 From fead60aa27e54d3ce48819c30d1db59c52d856c9 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Mon, 8 Apr 2019 16:34:59 +0300 Subject: Move FunctionSignature to display/function_signature --- crates/ra_ide_api/src/display.rs | 103 +-------------------- .../ra_ide_api/src/display/function_signature.rs | 101 ++++++++++++++++++++ 2 files changed, 104 insertions(+), 100 deletions(-) create mode 100644 crates/ra_ide_api/src/display/function_signature.rs (limited to 'crates') diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs index e29ae3371..f1717b008 100644 --- a/crates/ra_ide_api/src/display.rs +++ b/crates/ra_ide_api/src/display.rs @@ -1,18 +1,15 @@ //! This module contains utilities for turning SyntaxNodes and HIR types //! into things that may be used to render in a UI. +mod function_signature; mod navigation_target; mod structure; -use super::*; -use std::fmt::{self, Display}; -use join_to_string::join; -use ra_syntax::{ast::{self, AstNode, NameOwner, VisibilityOwner, TypeParamsOwner}, SyntaxKind::{ATTR, COMMENT}}; -use std::convert::From; -use hir::Docs; +use ra_syntax::{ast::{self, AstNode, TypeParamsOwner}, SyntaxKind::{ATTR, COMMENT}}; pub use navigation_target::NavigationTarget; pub use structure::{StructureNode, file_structure}; +pub use function_signature::FunctionSignature; pub(crate) fn function_label(node: &ast::FnDef) -> String { FunctionSignature::from(node).to_string() @@ -40,100 +37,6 @@ pub(crate) fn type_label(node: &ast::TypeAliasDef) -> String { label.trim().to_owned() } -/// Contains information about a function signature -#[derive(Debug)] -pub struct FunctionSignature { - /// Optional visibility - pub visibility: Option, - /// Name of the function - pub name: Option, - /// Documentation for the function - pub doc: Option, - /// Generic parameters - pub generic_parameters: Vec, - /// Parameters of the function - pub parameters: Vec, - /// Optional return type - pub ret_type: Option, - /// Where predicates - pub where_predicates: Vec, -} - -impl FunctionSignature { - pub(crate) fn with_doc_opt(mut self, doc: Option) -> Self { - self.doc = doc; - self - } - - pub(crate) fn from_hir(db: &db::RootDatabase, function: hir::Function) -> Self { - let doc = function.docs(db); - let (_, ast_node) = function.source(db); - FunctionSignature::from(&*ast_node).with_doc_opt(doc) - } -} - -impl From<&'_ ast::FnDef> for FunctionSignature { - fn from(node: &ast::FnDef) -> FunctionSignature { - fn param_list(node: &ast::FnDef) -> Vec { - let mut res = vec![]; - if let Some(param_list) = node.param_list() { - if let Some(self_param) = param_list.self_param() { - res.push(self_param.syntax().text().to_string()) - } - - res.extend(param_list.params().map(|param| param.syntax().text().to_string())); - } - res - } - - FunctionSignature { - visibility: node.visibility().map(|n| n.syntax().text().to_string()), - name: node.name().map(|n| n.text().to_string()), - ret_type: node - .ret_type() - .and_then(|r| r.type_ref()) - .map(|n| n.syntax().text().to_string()), - parameters: param_list(node), - generic_parameters: generic_parameters(node), - where_predicates: where_predicates(node), - // docs are processed separately - doc: None, - } - } -} - -impl Display for FunctionSignature { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(t) = &self.visibility { - write!(f, "{} ", t)?; - } - - if let Some(name) = &self.name { - write!(f, "fn {}", name)?; - } - - if !self.generic_parameters.is_empty() { - join(self.generic_parameters.iter()) - .separator(", ") - .surround_with("<", ">") - .to_fmt(f)?; - } - - join(self.parameters.iter()).separator(", ").surround_with("(", ")").to_fmt(f)?; - - if let Some(t) = &self.ret_type { - write!(f, " -> {}", t)?; - } - - if !self.where_predicates.is_empty() { - write!(f, "\nwhere ")?; - join(self.where_predicates.iter()).separator(",\n ").to_fmt(f)?; - } - - Ok(()) - } -} - pub(crate) fn generic_parameters(node: &N) -> Vec { let mut res = vec![]; if let Some(type_params) = node.type_param_list() { diff --git a/crates/ra_ide_api/src/display/function_signature.rs b/crates/ra_ide_api/src/display/function_signature.rs new file mode 100644 index 000000000..d09950bce --- /dev/null +++ b/crates/ra_ide_api/src/display/function_signature.rs @@ -0,0 +1,101 @@ +use super::{where_predicates, generic_parameters}; +use crate::db; +use std::fmt::{self, Display}; +use join_to_string::join; +use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; +use std::convert::From; +use hir::{Docs, Documentation}; + +/// Contains information about a function signature +#[derive(Debug)] +pub struct FunctionSignature { + /// Optional visibility + pub visibility: Option, + /// Name of the function + pub name: Option, + /// Documentation for the function + pub doc: Option, + /// Generic parameters + pub generic_parameters: Vec, + /// Parameters of the function + pub parameters: Vec, + /// Optional return type + pub ret_type: Option, + /// Where predicates + pub where_predicates: Vec, +} + +impl FunctionSignature { + pub(crate) fn with_doc_opt(mut self, doc: Option) -> Self { + self.doc = doc; + self + } + + pub(crate) fn from_hir(db: &db::RootDatabase, function: hir::Function) -> Self { + let doc = function.docs(db); + let (_, ast_node) = function.source(db); + FunctionSignature::from(&*ast_node).with_doc_opt(doc) + } +} + +impl From<&'_ ast::FnDef> for FunctionSignature { + fn from(node: &ast::FnDef) -> FunctionSignature { + fn param_list(node: &ast::FnDef) -> Vec { + let mut res = vec![]; + if let Some(param_list) = node.param_list() { + if let Some(self_param) = param_list.self_param() { + res.push(self_param.syntax().text().to_string()) + } + + res.extend(param_list.params().map(|param| param.syntax().text().to_string())); + } + res + } + + FunctionSignature { + visibility: node.visibility().map(|n| n.syntax().text().to_string()), + name: node.name().map(|n| n.text().to_string()), + ret_type: node + .ret_type() + .and_then(|r| r.type_ref()) + .map(|n| n.syntax().text().to_string()), + parameters: param_list(node), + generic_parameters: generic_parameters(node), + where_predicates: where_predicates(node), + // docs are processed separately + doc: None, + } + } +} + +impl Display for FunctionSignature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(t) = &self.visibility { + write!(f, "{} ", t)?; + } + + if let Some(name) = &self.name { + write!(f, "fn {}", name)?; + } + + if !self.generic_parameters.is_empty() { + join(self.generic_parameters.iter()) + .separator(", ") + .surround_with("<", ">") + .to_fmt(f)?; + } + + join(self.parameters.iter()).separator(", ").surround_with("(", ")").to_fmt(f)?; + + if let Some(t) = &self.ret_type { + write!(f, " -> {}", t)?; + } + + if !self.where_predicates.is_empty() { + write!(f, "\nwhere ")?; + join(self.where_predicates.iter()).separator(",\n ").to_fmt(f)?; + } + + Ok(()) + } +} -- cgit v1.2.3 From 07f0069f342afa17536aa4b9db4250f4d6c83954 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Tue, 9 Apr 2019 14:43:11 +0300 Subject: Move display related things from hover to display --- crates/ra_ide_api/src/display.rs | 27 +++++ crates/ra_ide_api/src/display/navigation_target.rs | 82 ++++++++++++++- crates/ra_ide_api/src/hover.rs | 110 +-------------------- 3 files changed, 110 insertions(+), 109 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs index f1717b008..b68b3a719 100644 --- a/crates/ra_ide_api/src/display.rs +++ b/crates/ra_ide_api/src/display.rs @@ -5,6 +5,7 @@ mod function_signature; mod navigation_target; mod structure; +use crate::db::RootDatabase; use ra_syntax::{ast::{self, AstNode, TypeParamsOwner}, SyntaxKind::{ATTR, COMMENT}}; pub use navigation_target::NavigationTarget; @@ -53,3 +54,29 @@ pub(crate) fn where_predicates(node: &N) -> Vec { } res } + +pub(crate) fn rust_code_markup>(val: CODE) -> String { + rust_code_markup_with_doc::<_, &str>(val, None) +} + +pub(crate) fn rust_code_markup_with_doc(val: CODE, doc: Option) -> String +where + CODE: AsRef, + DOC: AsRef, +{ + if let Some(doc) = doc { + format!("```rust\n{}\n```\n\n{}", val.as_ref(), doc.as_ref()) + } else { + format!("```rust\n{}\n```", val.as_ref()) + } +} + +// FIXME: this should not really use navigation target. Rather, approximately +// resolved symbol should return a `DefId`. +pub(crate) fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option { + match (nav.description(db), nav.docs(db)) { + (Some(desc), docs) => Some(rust_code_markup_with_doc(desc, docs)), + (None, Some(docs)) => Some(docs), + _ => None, + } +} diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs index f6d7f3192..3c518faf5 100644 --- a/crates/ra_ide_api/src/display/navigation_target.rs +++ b/crates/ra_ide_api/src/display/navigation_target.rs @@ -1,7 +1,9 @@ -use ra_db::FileId; +use ra_db::{FileId, SourceDatabase}; use ra_syntax::{ - SyntaxNode, SyntaxNodePtr, AstNode, SmolStr, TextRange, ast, + SyntaxNode, SyntaxNodePtr, AstNode, SmolStr, TextRange, TreeArc, SyntaxKind::{self, NAME}, + ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner}, + algo::visit::{visitor, Visitor}, }; use hir::{ModuleSource, FieldSource, Name, ImplItem}; @@ -248,4 +250,80 @@ impl NavigationTarget { container_name: None, } } + + pub(crate) fn node(&self, db: &RootDatabase) -> Option> { + let source_file = db.parse(self.file_id()); + let source_file = source_file.syntax(); + let node = source_file + .descendants() + .find(|node| node.kind() == self.kind() && node.range() == self.full_range())? + .to_owned(); + Some(node) + } + + pub(crate) fn docs(&self, db: &RootDatabase) -> Option { + let node = self.node(db)?; + fn doc_comments(node: &N) -> Option { + node.doc_comment_text() + } + + visitor() + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .accept(&node)? + } + + /// Get a description of this node. + /// + /// e.g. `struct Name`, `enum Name`, `fn Name` + pub(crate) fn description(&self, db: &RootDatabase) -> Option { + // FIXME: After type inference is done, add type information to improve the output + let node = self.node(db)?; + + fn visit_ascribed_node(node: &T, prefix: &str) -> Option + where + T: NameOwner + VisibilityOwner + TypeAscriptionOwner, + { + let mut string = visit_node(node, prefix)?; + + if let Some(type_ref) = node.ascribed_type() { + string.push_str(": "); + type_ref.syntax().text().push_to(&mut string); + } + + Some(string) + } + + fn visit_node(node: &T, label: &str) -> Option + where + T: NameOwner + VisibilityOwner, + { + let mut string = + node.visibility().map(|v| format!("{} ", v.syntax().text())).unwrap_or_default(); + string.push_str(label); + string.push_str(node.name()?.text().as_str()); + Some(string) + } + + visitor() + .visit(|node: &ast::FnDef| Some(crate::display::function_label(node))) + .visit(|node: &ast::StructDef| visit_node(node, "struct ")) + .visit(|node: &ast::EnumDef| visit_node(node, "enum ")) + .visit(|node: &ast::TraitDef| visit_node(node, "trait ")) + .visit(|node: &ast::Module| visit_node(node, "mod ")) + .visit(|node: &ast::TypeAliasDef| visit_node(node, "type ")) + .visit(|node: &ast::ConstDef| visit_ascribed_node(node, "const ")) + .visit(|node: &ast::StaticDef| visit_ascribed_node(node, "static ")) + .visit(|node: &ast::NamedFieldDef| visit_ascribed_node(node, "")) + .visit(|node: &ast::EnumVariant| Some(node.name()?.text().to_string())) + .accept(&node)? + } } diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 7d2c57f82..3a8c93b99 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -1,11 +1,11 @@ use ra_db::SourceDatabase; use ra_syntax::{ - AstNode, SyntaxNode, TreeArc, ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner}, - algo::{find_covering_element, find_node_at_offset, find_token_at_offset, visit::{visitor, Visitor}}, + AstNode, ast, + algo::{find_covering_element, find_node_at_offset, find_token_at_offset}, }; use hir::HirDisplay; -use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, NavigationTarget}; +use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, display::{rust_code_markup, doc_text_for}}; /// Contains the results when hovering over an item #[derive(Debug, Clone)] @@ -145,110 +145,6 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option { } } -fn rust_code_markup>(val: CODE) -> String { - rust_code_markup_with_doc::<_, &str>(val, None) -} - -fn rust_code_markup_with_doc(val: CODE, doc: Option) -> String -where - CODE: AsRef, - DOC: AsRef, -{ - if let Some(doc) = doc { - format!("```rust\n{}\n```\n\n{}", val.as_ref(), doc.as_ref()) - } else { - format!("```rust\n{}\n```", val.as_ref()) - } -} - -// FIXME: this should not really use navigation target. Rather, approximately -// resolved symbol should return a `DefId`. -fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option { - match (nav.description(db), nav.docs(db)) { - (Some(desc), docs) => Some(rust_code_markup_with_doc(desc, docs)), - (None, Some(docs)) => Some(docs), - _ => None, - } -} - -impl NavigationTarget { - fn node(&self, db: &RootDatabase) -> Option> { - let source_file = db.parse(self.file_id()); - let source_file = source_file.syntax(); - let node = source_file - .descendants() - .find(|node| node.kind() == self.kind() && node.range() == self.full_range())? - .to_owned(); - Some(node) - } - - fn docs(&self, db: &RootDatabase) -> Option { - let node = self.node(db)?; - fn doc_comments(node: &N) -> Option { - node.doc_comment_text() - } - - visitor() - .visit(doc_comments::) - .visit(doc_comments::) - .visit(doc_comments::) - .visit(doc_comments::) - .visit(doc_comments::) - .visit(doc_comments::) - .visit(doc_comments::) - .visit(doc_comments::) - .visit(doc_comments::) - .visit(doc_comments::) - .accept(&node)? - } - - /// Get a description of this node. - /// - /// e.g. `struct Name`, `enum Name`, `fn Name` - fn description(&self, db: &RootDatabase) -> Option { - // FIXME: After type inference is done, add type information to improve the output - let node = self.node(db)?; - - fn visit_ascribed_node(node: &T, prefix: &str) -> Option - where - T: NameOwner + VisibilityOwner + TypeAscriptionOwner, - { - let mut string = visit_node(node, prefix)?; - - if let Some(type_ref) = node.ascribed_type() { - string.push_str(": "); - type_ref.syntax().text().push_to(&mut string); - } - - Some(string) - } - - fn visit_node(node: &T, label: &str) -> Option - where - T: NameOwner + VisibilityOwner, - { - let mut string = - node.visibility().map(|v| format!("{} ", v.syntax().text())).unwrap_or_default(); - string.push_str(label); - string.push_str(node.name()?.text().as_str()); - Some(string) - } - - visitor() - .visit(|node: &ast::FnDef| Some(crate::display::function_label(node))) - .visit(|node: &ast::StructDef| visit_node(node, "struct ")) - .visit(|node: &ast::EnumDef| visit_node(node, "enum ")) - .visit(|node: &ast::TraitDef| visit_node(node, "trait ")) - .visit(|node: &ast::Module| visit_node(node, "mod ")) - .visit(|node: &ast::TypeAliasDef| visit_node(node, "type ")) - .visit(|node: &ast::ConstDef| visit_ascribed_node(node, "const ")) - .visit(|node: &ast::StaticDef| visit_ascribed_node(node, "static ")) - .visit(|node: &ast::NamedFieldDef| visit_ascribed_node(node, "")) - .visit(|node: &ast::EnumVariant| Some(node.name()?.text().to_string())) - .accept(&node)? - } -} - #[cfg(test)] mod tests { use ra_syntax::TextRange; -- cgit v1.2.3 From 45a2b9252401cc580dfa2e0e761313cc8334d47c Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Tue, 9 Apr 2019 16:08:24 +0300 Subject: Fix doc comment --- crates/ra_ide_api/src/display.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs index b68b3a719..1b06abf94 100644 --- a/crates/ra_ide_api/src/display.rs +++ b/crates/ra_ide_api/src/display.rs @@ -1,5 +1,5 @@ //! This module contains utilities for turning SyntaxNodes and HIR types -//! into things that may be used to render in a UI. +//! into types that may be used to render in a UI. mod function_signature; mod navigation_target; -- cgit v1.2.3