aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-01-05 10:57:39 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-01-05 10:57:39 +0000
commit9b5b13dfcfe32bccbf3593eee26bf88a5fd60413 (patch)
tree6e9822bea3fbda059fa02661f6e6137770885520
parent481713a0e17e1557288e88a6b1a173b111792998 (diff)
parentea3504057e73f541af64451a1b5d2c691d5c01bc (diff)
Merge #430
430: split import assist r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r--crates/ra_analysis/src/goto_defenition.rs73
-rw-r--r--crates/ra_editor/src/assists.rs3
-rw-r--r--crates/ra_editor/src/assists/split_import.rs44
-rw-r--r--crates/ra_syntax/src/ast.rs6
4 files changed, 126 insertions, 0 deletions
diff --git a/crates/ra_analysis/src/goto_defenition.rs b/crates/ra_analysis/src/goto_defenition.rs
new file mode 100644
index 000000000..607a25115
--- /dev/null
+++ b/crates/ra_analysis/src/goto_defenition.rs
@@ -0,0 +1,73 @@
1use ra_db::FileId;
2use ra_syntax::ast;
3
4use crate::db::RootDatabase;
5
6pub fn goto_defenition(db: &RootDatabase, position: FilePosition,
7) -> Cancelable<Option<Vec<NavigationTarget>>> {
8 let file = db.source_file(position.file_id);
9 let syntax = file.syntax();
10 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
11 return Ok(Some(reference_defenition(db, position.file_id, name_ref)));
12 }
13 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) {
14 return Ok(Some(name_defenition(db, position.file_idname)));
15 }
16 Ok(None)
17}
18
19fn reference_defenition(db: &RootDatabase, file_id: FileId, name_ref: ast::NameRef) -> Cancelable<Vec<Nav>> {
20 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
21 let mut rr = ReferenceResolution::new(name_ref.syntax().range());
22 if let Some(fn_descr) =
23 source_binder::function_from_child_node(self, position.file_id, name_ref.syntax())?
24 {
25 let scope = fn_descr.scopes(self);
26 // First try to resolve the symbol locally
27 if let Some(entry) = scope.resolve_local_name(name_ref) {
28 rr.resolves_to.push(NavigationTarget {
29 file_id: position.file_id,
30 name: entry.name().to_string().into(),
31 range: entry.ptr().range(),
32 kind: NAME,
33 ptr: None,
34 });
35 return Ok(Some(rr));
36 };
37 }
38 // If that fails try the index based approach.
39 rr.resolves_to.extend(
40 self.index_resolve(name_ref)?
41 .into_iter()
42 .map(NavigationTarget::from_symbol),
43 );
44 return Ok(Some(rr));
45 }
46 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) {
47 let mut rr = ReferenceResolution::new(name.syntax().range());
48 if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
49 if module.has_semi() {
50 if let Some(child_module) =
51 source_binder::module_from_declaration(self, position.file_id, module)?
52 {
53 let file_id = child_module.file_id();
54 let name = match child_module.name() {
55 Some(name) => name.to_string().into(),
56 None => "".into(),
57 };
58 let symbol = NavigationTarget {
59 file_id,
60 name,
61 range: TextRange::offset_len(0.into(), 0.into()),
62 kind: MODULE,
63 ptr: None,
64 };
65 rr.resolves_to.push(symbol);
66 return Ok(Some(rr));
67 }
68 }
69 }
70 }
71 Ok(None)
72
73}
diff --git a/crates/ra_editor/src/assists.rs b/crates/ra_editor/src/assists.rs
index cc40ee4c8..57b78342a 100644
--- a/crates/ra_editor/src/assists.rs
+++ b/crates/ra_editor/src/assists.rs
@@ -8,6 +8,7 @@ mod add_derive;
8mod add_impl; 8mod add_impl;
9mod introduce_variable; 9mod introduce_variable;
10mod change_visibility; 10mod change_visibility;
11mod split_import;
11 12
12use ra_text_edit::{TextEdit, TextEditBuilder}; 13use ra_text_edit::{TextEdit, TextEditBuilder};
13use ra_syntax::{ 14use ra_syntax::{
@@ -23,6 +24,7 @@ pub use self::{
23 add_impl::add_impl, 24 add_impl::add_impl,
24 introduce_variable::introduce_variable, 25 introduce_variable::introduce_variable,
25 change_visibility::change_visibility, 26 change_visibility::change_visibility,
27 split_import::split_import,
26}; 28};
27 29
28/// Return all the assists applicable at the given position. 30/// Return all the assists applicable at the given position.
@@ -34,6 +36,7 @@ pub fn assists(file: &SourceFileNode, range: TextRange) -> Vec<LocalEdit> {
34 add_impl, 36 add_impl,
35 introduce_variable, 37 introduce_variable,
36 change_visibility, 38 change_visibility,
39 split_import,
37 ] 40 ]
38 .iter() 41 .iter()
39 .filter_map(|&assist| ctx.clone().apply(assist)) 42 .filter_map(|&assist| ctx.clone().apply(assist))
diff --git a/crates/ra_editor/src/assists/split_import.rs b/crates/ra_editor/src/assists/split_import.rs
new file mode 100644
index 000000000..75f9e8dfb
--- /dev/null
+++ b/crates/ra_editor/src/assists/split_import.rs
@@ -0,0 +1,44 @@
1use ra_syntax::{
2 TextUnit, AstNode, SyntaxKind::COLONCOLON,
3 ast,
4 algo::generate,
5};
6
7use crate::assists::{AssistCtx, Assist};
8
9pub fn split_import(ctx: AssistCtx) -> Option<Assist> {
10 let colon_colon = ctx
11 .leaf_at_offset()
12 .find(|leaf| leaf.kind() == COLONCOLON)?;
13 let path = colon_colon.parent().and_then(ast::Path::cast)?;
14 let top_path = generate(Some(path), |it| it.parent_path()).last()?;
15
16 let use_tree = top_path.syntax().ancestors().find_map(ast::UseTree::cast);
17 if use_tree.is_none() {
18 return None;
19 }
20
21 let l_curly = colon_colon.range().end();
22 let r_curly = top_path.syntax().range().end();
23
24 ctx.build("split import", |edit| {
25 edit.insert(l_curly, "{");
26 edit.insert(r_curly, "}");
27 edit.set_cursor(l_curly + TextUnit::of_str("{"));
28 })
29}
30
31#[cfg(test)]
32mod tests {
33 use super::*;
34 use crate::assists::check_assist;
35
36 #[test]
37 fn test_split_import() {
38 check_assist(
39 split_import,
40 "use crate::<|>db::RootDatabase;",
41 "use crate::{<|>db::RootDatabase};",
42 )
43 }
44}
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index 2a3bd27e2..c10169d90 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -363,6 +363,12 @@ impl<'a> PathSegment<'a> {
363 } 363 }
364} 364}
365 365
366impl<'a> Path<'a> {
367 pub fn parent_path(self) -> Option<Path<'a>> {
368 self.syntax().parent().and_then(Path::cast)
369 }
370}
371
366impl<'a> UseTree<'a> { 372impl<'a> UseTree<'a> {
367 pub fn has_star(self) -> bool { 373 pub fn has_star(self) -> bool {
368 self.syntax().children().any(|it| it.kind() == STAR) 374 self.syntax().children().any(|it| it.kind() == STAR)