diff options
-rw-r--r-- | crates/libanalysis/tests/tests.rs | 30 | ||||
-rw-r--r-- | crates/libeditor/src/code_actions.rs | 1 | ||||
-rw-r--r-- | crates/libeditor/src/edit.rs | 12 | ||||
-rw-r--r-- | crates/libeditor/src/typing.rs | 69 |
4 files changed, 54 insertions, 58 deletions
diff --git a/crates/libanalysis/tests/tests.rs b/crates/libanalysis/tests/tests.rs index e05aa8895..5893efaf6 100644 --- a/crates/libanalysis/tests/tests.rs +++ b/crates/libanalysis/tests/tests.rs | |||
@@ -41,23 +41,21 @@ fn test_resolve_module() { | |||
41 | world.change_file(FileId(1), Some("mod foo;".to_string())); | 41 | world.change_file(FileId(1), Some("mod foo;".to_string())); |
42 | world.change_file(FileId(2), Some("".to_string())); | 42 | world.change_file(FileId(2), Some("".to_string())); |
43 | 43 | ||
44 | let snap = world.snapshot(FileMap(&[ | 44 | let snap = world.analysis(FileMap(&[ |
45 | (1, "/lib.rs"), | 45 | (1, "/lib.rs"), |
46 | (2, "/foo.rs"), | 46 | (2, "/foo.rs"), |
47 | ])); | 47 | ])); |
48 | let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into()) | 48 | let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into()); |
49 | .unwrap(); | ||
50 | assert_eq_dbg( | 49 | assert_eq_dbg( |
51 | r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, | 50 | r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, |
52 | &symbols, | 51 | &symbols, |
53 | ); | 52 | ); |
54 | 53 | ||
55 | let snap = world.snapshot(FileMap(&[ | 54 | let snap = world.analysis(FileMap(&[ |
56 | (1, "/lib.rs"), | 55 | (1, "/lib.rs"), |
57 | (2, "/foo/mod.rs") | 56 | (2, "/foo/mod.rs") |
58 | ])); | 57 | ])); |
59 | let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into()) | 58 | let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into()); |
60 | .unwrap(); | ||
61 | assert_eq_dbg( | 59 | assert_eq_dbg( |
62 | r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, | 60 | r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, |
63 | &symbols, | 61 | &symbols, |
@@ -69,11 +67,17 @@ fn test_unresolved_module_diagnostic() { | |||
69 | let mut world = WorldState::new(); | 67 | let mut world = WorldState::new(); |
70 | world.change_file(FileId(1), Some("mod foo;".to_string())); | 68 | world.change_file(FileId(1), Some("mod foo;".to_string())); |
71 | 69 | ||
72 | let snap = world.snapshot(FileMap(&[(1, "/lib.rs")])); | 70 | let snap = world.analysis(FileMap(&[(1, "/lib.rs")])); |
73 | let diagnostics = snap.diagnostics(FileId(1)).unwrap(); | 71 | let diagnostics = snap.diagnostics(FileId(1)); |
74 | assert_eq_dbg( | 72 | assert_eq_dbg( |
75 | r#"[(Diagnostic { range: [4; 7), msg: "unresolved module" }, | 73 | r#"[Diagnostic { |
76 | Some(QuickFix { fs_ops: [CreateFile { anchor: FileId(1), path: "../foo.rs" }] }))]"#, | 74 | message: "unresolved module", |
75 | range: [4; 7), | ||
76 | fix: Some(SourceChange { | ||
77 | label: "create module", | ||
78 | source_file_edits: [], | ||
79 | file_system_edits: [CreateFile { anchor: FileId(1), path: "../foo.rs" }], | ||
80 | cursor_position: None }) }]"#, | ||
77 | &diagnostics, | 81 | &diagnostics, |
78 | ); | 82 | ); |
79 | } | 83 | } |
@@ -83,8 +87,8 @@ fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { | |||
83 | let mut world = WorldState::new(); | 87 | let mut world = WorldState::new(); |
84 | world.change_file(FileId(1), Some("mod foo {}".to_string())); | 88 | world.change_file(FileId(1), Some("mod foo {}".to_string())); |
85 | 89 | ||
86 | let snap = world.snapshot(FileMap(&[(1, "/lib.rs")])); | 90 | let snap = world.analysis(FileMap(&[(1, "/lib.rs")])); |
87 | let diagnostics = snap.diagnostics(FileId(1)).unwrap(); | 91 | let diagnostics = snap.diagnostics(FileId(1)); |
88 | assert_eq_dbg( | 92 | assert_eq_dbg( |
89 | r#"[]"#, | 93 | r#"[]"#, |
90 | &diagnostics, | 94 | &diagnostics, |
@@ -97,7 +101,7 @@ fn test_resolve_parent_module() { | |||
97 | world.change_file(FileId(1), Some("mod foo;".to_string())); | 101 | world.change_file(FileId(1), Some("mod foo;".to_string())); |
98 | world.change_file(FileId(2), Some("".to_string())); | 102 | world.change_file(FileId(2), Some("".to_string())); |
99 | 103 | ||
100 | let snap = world.snapshot(FileMap(&[ | 104 | let snap = world.analysis(FileMap(&[ |
101 | (1, "/lib.rs"), | 105 | (1, "/lib.rs"), |
102 | (2, "/foo.rs"), | 106 | (2, "/foo.rs"), |
103 | ])); | 107 | ])); |
diff --git a/crates/libeditor/src/code_actions.rs b/crates/libeditor/src/code_actions.rs index dadbd63ab..522b605ed 100644 --- a/crates/libeditor/src/code_actions.rs +++ b/crates/libeditor/src/code_actions.rs | |||
@@ -13,7 +13,6 @@ use libsyntax2::{ | |||
13 | 13 | ||
14 | use {EditBuilder, Edit, find_node_at_offset}; | 14 | use {EditBuilder, Edit, find_node_at_offset}; |
15 | 15 | ||
16 | // TODO: rename to FileEdit | ||
17 | #[derive(Debug)] | 16 | #[derive(Debug)] |
18 | pub struct LocalEdit { | 17 | pub struct LocalEdit { |
19 | pub edit: Edit, | 18 | pub edit: Edit, |
diff --git a/crates/libeditor/src/edit.rs b/crates/libeditor/src/edit.rs index dcf1ee81e..09cf2bd00 100644 --- a/crates/libeditor/src/edit.rs +++ b/crates/libeditor/src/edit.rs | |||
@@ -1,5 +1,8 @@ | |||
1 | use {TextRange, TextUnit}; | 1 | use {TextRange, TextUnit}; |
2 | use libsyntax2::AtomEdit; | 2 | use libsyntax2::{ |
3 | AtomEdit, | ||
4 | text_utils::contains_offset_nonstrict, | ||
5 | }; | ||
3 | 6 | ||
4 | #[derive(Debug, Clone)] | 7 | #[derive(Debug, Clone)] |
5 | pub struct Edit { | 8 | pub struct Edit { |
@@ -15,19 +18,15 @@ impl EditBuilder { | |||
15 | pub fn new() -> EditBuilder { | 18 | pub fn new() -> EditBuilder { |
16 | EditBuilder { atoms: Vec::new() } | 19 | EditBuilder { atoms: Vec::new() } |
17 | } | 20 | } |
18 | |||
19 | pub fn replace(&mut self, range: TextRange, replace_with: String) { | 21 | pub fn replace(&mut self, range: TextRange, replace_with: String) { |
20 | self.atoms.push(AtomEdit::replace(range, replace_with)) | 22 | self.atoms.push(AtomEdit::replace(range, replace_with)) |
21 | } | 23 | } |
22 | |||
23 | pub fn delete(&mut self, range: TextRange) { | 24 | pub fn delete(&mut self, range: TextRange) { |
24 | self.atoms.push(AtomEdit::delete(range)) | 25 | self.atoms.push(AtomEdit::delete(range)) |
25 | } | 26 | } |
26 | |||
27 | pub fn insert(&mut self, offset: TextUnit, text: String) { | 27 | pub fn insert(&mut self, offset: TextUnit, text: String) { |
28 | self.atoms.push(AtomEdit::insert(offset, text)) | 28 | self.atoms.push(AtomEdit::insert(offset, text)) |
29 | } | 29 | } |
30 | |||
31 | pub fn finish(self) -> Edit { | 30 | pub fn finish(self) -> Edit { |
32 | let mut atoms = self.atoms; | 31 | let mut atoms = self.atoms; |
33 | atoms.sort_by_key(|a| a.delete.start()); | 32 | atoms.sort_by_key(|a| a.delete.start()); |
@@ -36,6 +35,9 @@ impl EditBuilder { | |||
36 | } | 35 | } |
37 | Edit { atoms } | 36 | Edit { atoms } |
38 | } | 37 | } |
38 | pub fn invalidates_offset(&self, offset: TextUnit) -> bool { | ||
39 | self.atoms.iter().any(|atom| contains_offset_nonstrict(atom.delete, offset)) | ||
40 | } | ||
39 | } | 41 | } |
40 | 42 | ||
41 | impl Edit { | 43 | impl Edit { |
diff --git a/crates/libeditor/src/typing.rs b/crates/libeditor/src/typing.rs index f888f3240..826b16181 100644 --- a/crates/libeditor/src/typing.rs +++ b/crates/libeditor/src/typing.rs | |||
@@ -45,10 +45,11 @@ pub fn join_lines(file: &File, range: TextRange) -> LocalEdit { | |||
45 | for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') { | 45 | for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') { |
46 | let pos: TextUnit = (pos as u32).into(); | 46 | let pos: TextUnit = (pos as u32).into(); |
47 | let off = node.range().start() + range.start() + pos; | 47 | let off = node.range().start() + range.start() + pos; |
48 | remove_newline(&mut edit, node, text.as_str(), off); | 48 | if !edit.invalidates_offset(off) { |
49 | remove_newline(&mut edit, node, text.as_str(), off); | ||
50 | } | ||
49 | } | 51 | } |
50 | } | 52 | } |
51 | eprintln!("{:?}", edit); | ||
52 | 53 | ||
53 | LocalEdit { | 54 | LocalEdit { |
54 | edit: edit.finish(), | 55 | edit: edit.finish(), |
@@ -239,17 +240,17 @@ fn foo() { | |||
239 | }"); | 240 | }"); |
240 | } | 241 | } |
241 | 242 | ||
242 | #[test] | 243 | fn check_join_lines_sel(before: &str, after: &str) { |
243 | fn test_join_lines_selection() { | 244 | let (sel, before) = extract_range(before); |
244 | fn do_check(before: &str, after: &str) { | 245 | let file = File::parse(&before); |
245 | let (sel, before) = extract_range(before); | 246 | let result = join_lines(&file, sel); |
246 | let file = File::parse(&before); | 247 | let actual = result.edit.apply(&before); |
247 | let result = join_lines(&file, sel); | 248 | assert_eq_text!(after, &actual); |
248 | let actual = result.edit.apply(&before); | 249 | } |
249 | assert_eq_text!(after, &actual); | ||
250 | } | ||
251 | 250 | ||
252 | do_check(r" | 251 | #[test] |
252 | fn test_join_lines_selection_fn_args() { | ||
253 | check_join_lines_sel(r" | ||
253 | fn foo() { | 254 | fn foo() { |
254 | <|>foo(1, | 255 | <|>foo(1, |
255 | 2, | 256 | 2, |
@@ -261,15 +262,22 @@ fn foo() { | |||
261 | foo(1, 2, 3) | 262 | foo(1, 2, 3) |
262 | } | 263 | } |
263 | "); | 264 | "); |
265 | } | ||
264 | 266 | ||
265 | do_check(r" | 267 | #[test] |
268 | fn test_join_lines_selection_struct() { | ||
269 | check_join_lines_sel(r" | ||
266 | struct Foo <|>{ | 270 | struct Foo <|>{ |
267 | f: u32, | 271 | f: u32, |
268 | }<|> | 272 | }<|> |
269 | ", r" | 273 | ", r" |
270 | struct Foo { f: u32 } | 274 | struct Foo { f: u32 } |
271 | "); | 275 | "); |
272 | do_check(r" | 276 | } |
277 | |||
278 | #[test] | ||
279 | fn test_join_lines_selection_dot_chain() { | ||
280 | check_join_lines_sel(r" | ||
273 | fn foo() { | 281 | fn foo() { |
274 | join(<|>type_params.type_params() | 282 | join(<|>type_params.type_params() |
275 | .filter_map(|it| it.name()) | 283 | .filter_map(|it| it.name()) |
@@ -278,39 +286,22 @@ fn foo() { | |||
278 | fn foo() { | 286 | fn foo() { |
279 | join(type_params.type_params().filter_map(|it| it.name()).map(|it| it.text())) | 287 | join(type_params.type_params().filter_map(|it| it.name()).map(|it| it.text())) |
280 | }"); | 288 | }"); |
289 | } | ||
281 | 290 | ||
282 | do_check(r" | 291 | #[test] |
283 | pub fn handle_find_matching_brace( | 292 | fn test_join_lines_selection_lambda_block_body() { |
284 | world: ServerWorld, | 293 | check_join_lines_sel(r" |
285 | params: req::FindMatchingBraceParams, | 294 | pub fn handle_find_matching_brace() { |
286 | ) -> Result<Vec<Position>> { | 295 | params.offsets |
287 | let file_id = params.text_document.try_conv_with(&world)?; | ||
288 | let file = world.analysis().file_syntax(file_id); | ||
289 | let line_index = world.analysis().file_line_index(file_id); | ||
290 | let res = params.offsets | ||
291 | .into_iter() | ||
292 | .map_conv_with(&line_index) | ||
293 | .map(|offset| <|>{ | 296 | .map(|offset| <|>{ |
294 | world.analysis().matching_brace(&file, offset).unwrap_or(offset) | 297 | world.analysis().matching_brace(&file, offset).unwrap_or(offset) |
295 | }<|>) | 298 | }<|>) |
296 | .map_conv_with(&line_index) | ||
297 | .collect(); | 299 | .collect(); |
298 | Ok(res) | ||
299 | }", r" | 300 | }", r" |
300 | pub fn handle_find_matching_brace( | 301 | pub fn handle_find_matching_brace() { |
301 | world: ServerWorld, | 302 | params.offsets |
302 | params: req::FindMatchingBraceParams, | ||
303 | ) -> Result<Vec<Position>> { | ||
304 | let file_id = params.text_document.try_conv_with(&world)?; | ||
305 | let file = world.analysis().file_syntax(file_id); | ||
306 | let line_index = world.analysis().file_line_index(file_id); | ||
307 | let res = params.offsets | ||
308 | .into_iter() | ||
309 | .map_conv_with(&line_index) | ||
310 | .map(|offset| world.analysis().matching_brace(&file, offset).unwrap_or(offset)) | 303 | .map(|offset| world.analysis().matching_brace(&file, offset).unwrap_or(offset)) |
311 | .map_conv_with(&line_index) | ||
312 | .collect(); | 304 | .collect(); |
313 | Ok(res) | ||
314 | }"); | 305 | }"); |
315 | } | 306 | } |
316 | 307 | ||