aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-29 16:35:28 +0100
committerAleksey Kladov <[email protected]>2018-08-29 16:35:28 +0100
commit7d95d38ecb9b197721e2533ba98afbc2f91610d0 (patch)
tree51cf2370f95dedc1d7434be1b708e4afa0c7bf7f
parent09ea0ca7e5fb5d3e123dc38927b158c798b689ad (diff)
fix join lines selection
-rw-r--r--crates/libanalysis/tests/tests.rs30
-rw-r--r--crates/libeditor/src/code_actions.rs1
-rw-r--r--crates/libeditor/src/edit.rs12
-rw-r--r--crates/libeditor/src/typing.rs69
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
14use {EditBuilder, Edit, find_node_at_offset}; 14use {EditBuilder, Edit, find_node_at_offset};
15 15
16// TODO: rename to FileEdit
17#[derive(Debug)] 16#[derive(Debug)]
18pub struct LocalEdit { 17pub 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 @@
1use {TextRange, TextUnit}; 1use {TextRange, TextUnit};
2use libsyntax2::AtomEdit; 2use libsyntax2::{
3 AtomEdit,
4 text_utils::contains_offset_nonstrict,
5};
3 6
4#[derive(Debug, Clone)] 7#[derive(Debug, Clone)]
5pub struct Edit { 8pub 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
41impl Edit { 43impl 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"
253fn foo() { 254fn 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"
266struct Foo <|>{ 270struct Foo <|>{
267 f: u32, 271 f: u32,
268}<|> 272}<|>
269 ", r" 273 ", r"
270struct Foo { f: u32 } 274struct 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"
273fn foo() { 281fn 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() {
278fn foo() { 286fn 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]
283pub 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, 294pub 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"
300pub fn handle_find_matching_brace( 301pub 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