From 201b344f2b0c9e84606115d135cd658d0a955d2c Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sat, 20 Jul 2019 00:20:09 +0300 Subject: Refactor server api --- crates/ra_ide_api/src/display/structure.rs | 27 ----- crates/ra_ide_api/src/inlay_hints.rs | 110 +++++++++++++++++++++ crates/ra_ide_api/src/lib.rs | 7 ++ .../src/snapshots/tests__inlay_hints.snap | 63 ++++++++++++ 4 files changed, 180 insertions(+), 27 deletions(-) create mode 100644 crates/ra_ide_api/src/inlay_hints.rs create mode 100644 crates/ra_ide_api/src/snapshots/tests__inlay_hints.snap (limited to 'crates/ra_ide_api/src') diff --git a/crates/ra_ide_api/src/display/structure.rs b/crates/ra_ide_api/src/display/structure.rs index bd2e908da..2ba10b2ef 100644 --- a/crates/ra_ide_api/src/display/structure.rs +++ b/crates/ra_ide_api/src/display/structure.rs @@ -1,6 +1,5 @@ use crate::TextRange; -use ra_syntax::ast::PatKind; use ra_syntax::{ algo::visit::{visitor, Visitor}, ast::{self, AttrsOwner, NameOwner, TypeAscriptionOwner, TypeParamsOwner}, @@ -156,32 +155,6 @@ fn structure_node(node: &SyntaxNode) -> Option { } decl(mc) }) - .visit(|let_statement: ast::LetStmt| { - let let_syntax = let_statement.syntax(); - - let mut label = String::new(); - collapse_ws(let_syntax, &mut label); - - if let_statement.ascribed_type().is_some() { - return None; - } - - let pat_range = match let_statement.pat()?.kind() { - PatKind::BindPat(bind_pat) => bind_pat.syntax().range(), - PatKind::TuplePat(tuple_pat) => tuple_pat.syntax().range(), - _ => return None, - }; - - Some(StructureNode { - parent: None, - label, - navigation_range: pat_range, - node_range: let_syntax.range(), - kind: let_syntax.kind(), - detail: None, - deprecated: false, - }) - }) .accept(&node)? } diff --git a/crates/ra_ide_api/src/inlay_hints.rs b/crates/ra_ide_api/src/inlay_hints.rs new file mode 100644 index 000000000..4d1df65d0 --- /dev/null +++ b/crates/ra_ide_api/src/inlay_hints.rs @@ -0,0 +1,110 @@ +use ra_syntax::{ + algo::visit::{visitor, Visitor}, + ast::{self, PatKind, TypeAscriptionOwner}, + AstNode, SmolStr, SourceFile, SyntaxNode, TextRange, +}; + +#[derive(Debug, PartialEq, Eq)] +pub enum InlayKind { + LetBinding, + ClosureParameter, +} + +#[derive(Debug)] +pub struct InlayHint { + pub range: TextRange, + pub text: SmolStr, + pub inlay_kind: InlayKind, +} + +pub(crate) fn inlay_hints(file: &SourceFile) -> Vec { + file.syntax().descendants().map(|node| get_inlay_hints(&node)).flatten().collect() +} + +fn get_inlay_hints(node: &SyntaxNode) -> Vec { + visitor() + .visit(|let_statement: ast::LetStmt| { + let let_syntax = let_statement.syntax(); + + if let_statement.ascribed_type().is_some() { + return Vec::new(); + } + + let pat_range = match let_statement.pat().map(|pat| pat.kind()) { + Some(PatKind::BindPat(bind_pat)) => bind_pat.syntax().text_range(), + Some(PatKind::TuplePat(tuple_pat)) => tuple_pat.syntax().text_range(), + _ => return Vec::new(), + }; + + vec![InlayHint { + range: pat_range, + text: let_syntax.text().to_smol_string(), + inlay_kind: InlayKind::LetBinding, + }] + }) + .visit(|closure_parameter: ast::LambdaExpr| { + if let Some(param_list) = closure_parameter.param_list() { + param_list + .params() + .filter(|closure_param| closure_param.ascribed_type().is_none()) + .map(|closure_param| { + let closure_param_syntax = closure_param.syntax(); + InlayHint { + range: closure_param_syntax.text_range(), + text: closure_param_syntax.text().to_smol_string(), + inlay_kind: InlayKind::ClosureParameter, + } + }) + .collect() + } else { + Vec::new() + } + }) + .accept(&node) + .unwrap_or_else(Vec::new) +} + +#[cfg(test)] +mod tests { + use super::*; + use insta::assert_debug_snapshot_matches; + + #[test] + fn test_inlay_hints() { + let file = SourceFile::parse( + r#" +struct OuterStruct {} + +fn main() { + struct InnerStruct {} + + let test = 54; + let test = InnerStruct {}; + let test = OuterStruct {}; + let test = vec![222]; + let mut test = Vec::new(); + test.push(333); + let test = test.into_iter().map(|i| i * i).collect::>(); + let mut test = 33; + let _ = 22; + let test: Vec<_> = (0..3).collect(); + + let _ = (0..23).map(|i: u32| { + let i_squared = i * i; + i_squared + }); + + let test: i32 = 33; + + let (x, c) = (42, 'a'); + let test = (42, 'a'); +} + +"#, + ) + .ok() + .unwrap(); + let hints = inlay_hints(&file); + assert_debug_snapshot_matches!("inlay_hints", hints); + } +} diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index c54d574bc..af163088a 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs @@ -38,6 +38,7 @@ mod join_lines; mod typing; mod matching_brace; mod display; +mod inlay_hints; #[cfg(test)] mod marks; @@ -64,6 +65,7 @@ pub use crate::{ display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, folding_ranges::{Fold, FoldKind}, hover::HoverResult, + inlay_hints::{InlayHint, InlayKind}, line_index::{LineCol, LineIndex}, line_index_utils::translate_offset_with_edit, references::ReferenceSearchResult, @@ -396,6 +398,11 @@ impl Analysis { file_structure(&parse.tree()) } + /// Returns a list of the places in the file where type hints can be displayed. + pub fn inlay_hints(&self, file_id: FileId) -> Vec { + inlay_hints::inlay_hints(&self.db.parse(file_id).tree()) + } + /// Returns the set of folding ranges. pub fn folding_ranges(&self, file_id: FileId) -> Vec { let parse = self.db.parse(file_id); diff --git a/crates/ra_ide_api/src/snapshots/tests__inlay_hints.snap b/crates/ra_ide_api/src/snapshots/tests__inlay_hints.snap new file mode 100644 index 000000000..f4d562314 --- /dev/null +++ b/crates/ra_ide_api/src/snapshots/tests__inlay_hints.snap @@ -0,0 +1,63 @@ +--- +created: "2019-07-20T20:13:53.385368Z" +creator: insta@0.8.1 +source: crates/ra_ide_api/src/inlay_hints.rs +expression: hints +--- +[ + InlayHint { + range: [71; 75), + text: "let test = 54;", + inlay_kind: LetBinding, + }, + InlayHint { + range: [90; 94), + text: "let test = InnerStruct {};", + inlay_kind: LetBinding, + }, + InlayHint { + range: [121; 125), + text: "let test = OuterStruct {};", + inlay_kind: LetBinding, + }, + InlayHint { + range: [152; 156), + text: "let test = vec![222];", + inlay_kind: LetBinding, + }, + InlayHint { + range: [178; 186), + text: "let mut test = Vec::new();", + inlay_kind: LetBinding, + }, + InlayHint { + range: [229; 233), + text: "let test = test.into_iter().map(|i| i * i).collect::>();", + inlay_kind: LetBinding, + }, + InlayHint { + range: [258; 259), + text: "i", + inlay_kind: ClosureParameter, + }, + InlayHint { + range: [297; 305), + text: "let mut test = 33;", + inlay_kind: LetBinding, + }, + InlayHint { + range: [417; 426), + text: "let i_squared = i * i;", + inlay_kind: LetBinding, + }, + InlayHint { + range: [500; 506), + text: "let (x, c) = (42, \'a\');", + inlay_kind: LetBinding, + }, + InlayHint { + range: [528; 532), + text: "let test = (42, \'a\');", + inlay_kind: LetBinding, + }, +] -- cgit v1.2.3