aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/change_visibility.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-02-03 18:26:35 +0000
committerAleksey Kladov <[email protected]>2019-02-06 14:00:00 +0000
commit0c5fd8f7cbf04eda763e55bc9a38dad5f7ec917d (patch)
tree4af15c8906b85de01a15c717bc1fac388952cd3d /crates/ra_assists/src/change_visibility.rs
parent736a55c97e69f95e6ff4a0c3dafb2018e8ea05f9 (diff)
move assists to a separate crate
Diffstat (limited to 'crates/ra_assists/src/change_visibility.rs')
-rw-r--r--crates/ra_assists/src/change_visibility.rs166
1 files changed, 166 insertions, 0 deletions
diff --git a/crates/ra_assists/src/change_visibility.rs b/crates/ra_assists/src/change_visibility.rs
new file mode 100644
index 000000000..4cd32985e
--- /dev/null
+++ b/crates/ra_assists/src/change_visibility.rs
@@ -0,0 +1,166 @@
1use hir::db::HirDatabase;
2use ra_syntax::{
3 AstNode, SyntaxNode, TextUnit,
4 ast::{self, VisibilityOwner, NameOwner},
5 SyntaxKind::{VISIBILITY, FN_KW, MOD_KW, STRUCT_KW, ENUM_KW, TRAIT_KW, FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF, IDENT, WHITESPACE, COMMENT, ATTR},
6};
7
8use crate::{AssistCtx, Assist};
9
10pub(crate) fn change_visibility(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
11 if let Some(vis) = ctx.node_at_offset::<ast::Visibility>() {
12 return change_vis(ctx, vis);
13 }
14 add_vis(ctx)
15}
16
17fn add_vis(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
18 let item_keyword = ctx.leaf_at_offset().find(|leaf| match leaf.kind() {
19 FN_KW | MOD_KW | STRUCT_KW | ENUM_KW | TRAIT_KW => true,
20 _ => false,
21 });
22
23 let offset = if let Some(keyword) = item_keyword {
24 let parent = keyword.parent()?;
25 let def_kws = vec![FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF];
26 // Parent is not a definition, can't add visibility
27 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
28 return None;
29 }
30 // Already have visibility, do nothing
31 if parent.children().any(|child| child.kind() == VISIBILITY) {
32 return None;
33 }
34 vis_offset(parent)
35 } else {
36 let ident = ctx.leaf_at_offset().find(|leaf| leaf.kind() == IDENT)?;
37 let field = ident.ancestors().find_map(ast::NamedFieldDef::cast)?;
38 if field.name()?.syntax().range() != ident.range() && field.visibility().is_some() {
39 return None;
40 }
41 vis_offset(field.syntax())
42 };
43
44 ctx.build("make pub(crate)", |edit| {
45 edit.insert(offset, "pub(crate) ");
46 edit.set_cursor(offset);
47 })
48}
49
50fn vis_offset(node: &SyntaxNode) -> TextUnit {
51 node.children()
52 .skip_while(|it| match it.kind() {
53 WHITESPACE | COMMENT | ATTR => true,
54 _ => false,
55 })
56 .next()
57 .map(|it| it.range().start())
58 .unwrap_or(node.range().start())
59}
60
61fn change_vis(ctx: AssistCtx<impl HirDatabase>, vis: &ast::Visibility) -> Option<Assist> {
62 if vis.syntax().text() == "pub" {
63 return ctx.build("chage to pub(crate)", |edit| {
64 edit.replace(vis.syntax().range(), "pub(crate)");
65 edit.set_cursor(vis.syntax().range().start());
66 });
67 }
68 if vis.syntax().text() == "pub(crate)" {
69 return ctx.build("chage to pub", |edit| {
70 edit.replace(vis.syntax().range(), "pub");
71 edit.set_cursor(vis.syntax().range().start());
72 });
73 }
74 None
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80 use crate::helpers::check_assist;
81
82 #[test]
83 fn change_visibility_adds_pub_crate_to_items() {
84 check_assist(
85 change_visibility,
86 "<|>fn foo() {}",
87 "<|>pub(crate) fn foo() {}",
88 );
89 check_assist(
90 change_visibility,
91 "f<|>n foo() {}",
92 "<|>pub(crate) fn foo() {}",
93 );
94 check_assist(
95 change_visibility,
96 "<|>struct Foo {}",
97 "<|>pub(crate) struct Foo {}",
98 );
99 check_assist(
100 change_visibility,
101 "<|>mod foo {}",
102 "<|>pub(crate) mod foo {}",
103 );
104 check_assist(
105 change_visibility,
106 "<|>trait Foo {}",
107 "<|>pub(crate) trait Foo {}",
108 );
109 check_assist(change_visibility, "m<|>od {}", "<|>pub(crate) mod {}");
110 check_assist(
111 change_visibility,
112 "unsafe f<|>n foo() {}",
113 "<|>pub(crate) unsafe fn foo() {}",
114 );
115 }
116
117 #[test]
118 fn change_visibility_works_with_struct_fields() {
119 check_assist(
120 change_visibility,
121 "struct S { <|>field: u32 }",
122 "struct S { <|>pub(crate) field: u32 }",
123 )
124 }
125
126 #[test]
127 fn change_visibility_pub_to_pub_crate() {
128 check_assist(
129 change_visibility,
130 "<|>pub fn foo() {}",
131 "<|>pub(crate) fn foo() {}",
132 )
133 }
134
135 #[test]
136 fn change_visibility_pub_crate_to_pub() {
137 check_assist(
138 change_visibility,
139 "<|>pub(crate) fn foo() {}",
140 "<|>pub fn foo() {}",
141 )
142 }
143
144 #[test]
145 fn change_visibility_handles_comment_attrs() {
146 check_assist(
147 change_visibility,
148 "
149 /// docs
150
151 // comments
152
153 #[derive(Debug)]
154 <|>struct Foo;
155 ",
156 "
157 /// docs
158
159 // comments
160
161 #[derive(Debug)]
162 <|>pub(crate) struct Foo;
163 ",
164 )
165 }
166}