diff options
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r-- | crates/ra_ide_api/src/lib.rs | 29 | ||||
-rw-r--r-- | crates/ra_ide_api/src/typing.rs | 81 |
2 files changed, 55 insertions, 55 deletions
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index c2ef61ae2..0e7b47e3c 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs | |||
@@ -72,7 +72,7 @@ pub use crate::{ | |||
72 | folding_ranges::{Fold, FoldKind}, | 72 | folding_ranges::{Fold, FoldKind}, |
73 | }; | 73 | }; |
74 | pub use ra_ide_api_light::{ | 74 | pub use ra_ide_api_light::{ |
75 | HighlightedRange, Severity, StructureNode, LocalEdit, | 75 | HighlightedRange, Severity, StructureNode, |
76 | }; | 76 | }; |
77 | pub use ra_db::{ | 77 | pub use ra_db::{ |
78 | Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId, | 78 | Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId, |
@@ -295,9 +295,7 @@ impl Analysis { | |||
295 | /// Returns an edit which should be applied when opening a new line, fixing | 295 | /// Returns an edit which should be applied when opening a new line, fixing |
296 | /// up minor stuff like continuing the comment. | 296 | /// up minor stuff like continuing the comment. |
297 | pub fn on_enter(&self, position: FilePosition) -> Option<SourceChange> { | 297 | pub fn on_enter(&self, position: FilePosition) -> Option<SourceChange> { |
298 | let file = self.db.parse(position.file_id); | 298 | typing::on_enter(&self.db, position) |
299 | let edit = typing::on_enter(&file, position.offset)?; | ||
300 | Some(SourceChange::from_local_edit(position.file_id, edit)) | ||
301 | } | 299 | } |
302 | 300 | ||
303 | /// Returns an edit which should be applied after `=` was typed. Primarily, | 301 | /// Returns an edit which should be applied after `=` was typed. Primarily, |
@@ -306,14 +304,17 @@ impl Analysis { | |||
306 | pub fn on_eq_typed(&self, position: FilePosition) -> Option<SourceChange> { | 304 | pub fn on_eq_typed(&self, position: FilePosition) -> Option<SourceChange> { |
307 | let file = self.db.parse(position.file_id); | 305 | let file = self.db.parse(position.file_id); |
308 | let edit = typing::on_eq_typed(&file, position.offset)?; | 306 | let edit = typing::on_eq_typed(&file, position.offset)?; |
309 | Some(SourceChange::from_local_edit(position.file_id, edit)) | 307 | Some(SourceChange { |
308 | label: "add semicolon".to_string(), | ||
309 | source_file_edits: vec![SourceFileEdit { edit, file_id: position.file_id }], | ||
310 | file_system_edits: vec![], | ||
311 | cursor_position: None, | ||
312 | }) | ||
310 | } | 313 | } |
311 | 314 | ||
312 | /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. | 315 | /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. |
313 | pub fn on_dot_typed(&self, position: FilePosition) -> Option<SourceChange> { | 316 | pub fn on_dot_typed(&self, position: FilePosition) -> Option<SourceChange> { |
314 | let file = self.db.parse(position.file_id); | 317 | typing::on_dot_typed(&self.db, position) |
315 | let edit = typing::on_dot_typed(&file, position.offset)?; | ||
316 | Some(SourceChange::from_local_edit(position.file_id, edit)) | ||
317 | } | 318 | } |
318 | 319 | ||
319 | /// Returns a tree representation of symbols in the file. Useful to draw a | 320 | /// Returns a tree representation of symbols in the file. Useful to draw a |
@@ -435,18 +436,6 @@ impl Analysis { | |||
435 | } | 436 | } |
436 | } | 437 | } |
437 | 438 | ||
438 | impl SourceChange { | ||
439 | pub(crate) fn from_local_edit(file_id: FileId, edit: LocalEdit) -> SourceChange { | ||
440 | let file_edit = SourceFileEdit { file_id, edit: edit.edit }; | ||
441 | SourceChange { | ||
442 | label: edit.label, | ||
443 | source_file_edits: vec![file_edit], | ||
444 | file_system_edits: vec![], | ||
445 | cursor_position: edit.cursor_position.map(|offset| FilePosition { offset, file_id }), | ||
446 | } | ||
447 | } | ||
448 | } | ||
449 | |||
450 | #[test] | 439 | #[test] |
451 | fn analysis_is_send() { | 440 | fn analysis_is_send() { |
452 | fn is_send<T: Send>() {} | 441 | fn is_send<T: Send>() {} |
diff --git a/crates/ra_ide_api/src/typing.rs b/crates/ra_ide_api/src/typing.rs index b7e023d60..94b228466 100644 --- a/crates/ra_ide_api/src/typing.rs +++ b/crates/ra_ide_api/src/typing.rs | |||
@@ -5,31 +5,37 @@ use ra_syntax::{ | |||
5 | ast::{self, AstToken}, | 5 | ast::{self, AstToken}, |
6 | }; | 6 | }; |
7 | use ra_fmt::leading_indent; | 7 | use ra_fmt::leading_indent; |
8 | use crate::LocalEdit; | 8 | use ra_text_edit::{TextEdit, TextEditBuilder}; |
9 | use ra_text_edit::TextEditBuilder; | 9 | use ra_db::{FilePosition, SourceDatabase}; |
10 | use crate::{db::RootDatabase, SourceChange, SourceFileEdit}; | ||
10 | 11 | ||
11 | pub fn on_enter(file: &SourceFile, offset: TextUnit) -> Option<LocalEdit> { | 12 | pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<SourceChange> { |
12 | let comment = | 13 | let file = db.parse(position.file_id); |
13 | find_leaf_at_offset(file.syntax(), offset).left_biased().and_then(ast::Comment::cast)?; | 14 | let comment = find_leaf_at_offset(file.syntax(), position.offset) |
15 | .left_biased() | ||
16 | .and_then(ast::Comment::cast)?; | ||
14 | 17 | ||
15 | if let ast::CommentFlavor::Multiline = comment.flavor() { | 18 | if let ast::CommentFlavor::Multiline = comment.flavor() { |
16 | return None; | 19 | return None; |
17 | } | 20 | } |
18 | 21 | ||
19 | let prefix = comment.prefix(); | 22 | let prefix = comment.prefix(); |
20 | if offset < comment.syntax().range().start() + TextUnit::of_str(prefix) + TextUnit::from(1) { | 23 | if position.offset |
24 | < comment.syntax().range().start() + TextUnit::of_str(prefix) + TextUnit::from(1) | ||
25 | { | ||
21 | return None; | 26 | return None; |
22 | } | 27 | } |
23 | 28 | ||
24 | let indent = node_indent(file, comment.syntax())?; | 29 | let indent = node_indent(&file, comment.syntax())?; |
25 | let inserted = format!("\n{}{} ", indent, prefix); | 30 | let inserted = format!("\n{}{} ", indent, prefix); |
26 | let cursor_position = offset + TextUnit::of_str(&inserted); | 31 | let cursor_position = position.offset + TextUnit::of_str(&inserted); |
27 | let mut edit = TextEditBuilder::default(); | 32 | let mut edit = TextEditBuilder::default(); |
28 | edit.insert(offset, inserted); | 33 | edit.insert(position.offset, inserted); |
29 | Some(LocalEdit { | 34 | Some(SourceChange { |
30 | label: "on enter".to_string(), | 35 | label: "on enter".to_string(), |
31 | edit: edit.finish(), | 36 | source_file_edits: vec![SourceFileEdit { edit: edit.finish(), file_id: position.file_id }], |
32 | cursor_position: Some(cursor_position), | 37 | file_system_edits: vec![], |
38 | cursor_position: Some(FilePosition { offset: cursor_position, file_id: position.file_id }), | ||
33 | }) | 39 | }) |
34 | } | 40 | } |
35 | 41 | ||
@@ -53,7 +59,7 @@ fn node_indent<'a>(file: &'a SourceFile, node: &SyntaxNode) -> Option<&'a str> { | |||
53 | Some(&text[pos..]) | 59 | Some(&text[pos..]) |
54 | } | 60 | } |
55 | 61 | ||
56 | pub fn on_eq_typed(file: &SourceFile, eq_offset: TextUnit) -> Option<LocalEdit> { | 62 | pub fn on_eq_typed(file: &SourceFile, eq_offset: TextUnit) -> Option<TextEdit> { |
57 | assert_eq!(file.syntax().text().char_at(eq_offset), Some('=')); | 63 | assert_eq!(file.syntax().text().char_at(eq_offset), Some('=')); |
58 | let let_stmt: &ast::LetStmt = find_node_at_offset(file.syntax(), eq_offset)?; | 64 | let let_stmt: &ast::LetStmt = find_node_at_offset(file.syntax(), eq_offset)?; |
59 | if let_stmt.has_semi() { | 65 | if let_stmt.has_semi() { |
@@ -73,17 +79,14 @@ pub fn on_eq_typed(file: &SourceFile, eq_offset: TextUnit) -> Option<LocalEdit> | |||
73 | let offset = let_stmt.syntax().range().end(); | 79 | let offset = let_stmt.syntax().range().end(); |
74 | let mut edit = TextEditBuilder::default(); | 80 | let mut edit = TextEditBuilder::default(); |
75 | edit.insert(offset, ";".to_string()); | 81 | edit.insert(offset, ";".to_string()); |
76 | Some(LocalEdit { | 82 | Some(edit.finish()) |
77 | label: "add semicolon".to_string(), | ||
78 | edit: edit.finish(), | ||
79 | cursor_position: None, | ||
80 | }) | ||
81 | } | 83 | } |
82 | 84 | ||
83 | pub fn on_dot_typed(file: &SourceFile, dot_offset: TextUnit) -> Option<LocalEdit> { | 85 | pub(crate) fn on_dot_typed(db: &RootDatabase, position: FilePosition) -> Option<SourceChange> { |
84 | assert_eq!(file.syntax().text().char_at(dot_offset), Some('.')); | 86 | let file = db.parse(position.file_id); |
87 | assert_eq!(file.syntax().text().char_at(position.offset), Some('.')); | ||
85 | 88 | ||
86 | let whitespace = find_leaf_at_offset(file.syntax(), dot_offset) | 89 | let whitespace = find_leaf_at_offset(file.syntax(), position.offset) |
87 | .left_biased() | 90 | .left_biased() |
88 | .and_then(ast::Whitespace::cast)?; | 91 | .and_then(ast::Whitespace::cast)?; |
89 | 92 | ||
@@ -104,15 +107,18 @@ pub fn on_dot_typed(file: &SourceFile, dot_offset: TextUnit) -> Option<LocalEdit | |||
104 | } | 107 | } |
105 | let mut edit = TextEditBuilder::default(); | 108 | let mut edit = TextEditBuilder::default(); |
106 | edit.replace( | 109 | edit.replace( |
107 | TextRange::from_to(dot_offset - current_indent_len, dot_offset), | 110 | TextRange::from_to(position.offset - current_indent_len, position.offset), |
108 | target_indent.into(), | 111 | target_indent.into(), |
109 | ); | 112 | ); |
110 | let res = LocalEdit { | 113 | let res = SourceChange { |
111 | label: "reindent dot".to_string(), | 114 | label: "reindent dot".to_string(), |
112 | edit: edit.finish(), | 115 | source_file_edits: vec![SourceFileEdit { edit: edit.finish(), file_id: position.file_id }], |
113 | cursor_position: Some( | 116 | file_system_edits: vec![], |
114 | dot_offset + target_indent_len - current_indent_len + TextUnit::of_char('.'), | 117 | cursor_position: Some(FilePosition { |
115 | ), | 118 | offset: position.offset + target_indent_len - current_indent_len |
119 | + TextUnit::of_char('.'), | ||
120 | file_id: position.file_id, | ||
121 | }), | ||
116 | }; | 122 | }; |
117 | Some(res) | 123 | Some(res) |
118 | } | 124 | } |
@@ -121,6 +127,8 @@ pub fn on_dot_typed(file: &SourceFile, dot_offset: TextUnit) -> Option<LocalEdit | |||
121 | mod tests { | 127 | mod tests { |
122 | use test_utils::{add_cursor, assert_eq_text, extract_offset}; | 128 | use test_utils::{add_cursor, assert_eq_text, extract_offset}; |
123 | 129 | ||
130 | use crate::mock_analysis::single_file; | ||
131 | |||
124 | use super::*; | 132 | use super::*; |
125 | 133 | ||
126 | #[test] | 134 | #[test] |
@@ -132,7 +140,7 @@ mod tests { | |||
132 | let before = edit.finish().apply(&before); | 140 | let before = edit.finish().apply(&before); |
133 | let file = SourceFile::parse(&before); | 141 | let file = SourceFile::parse(&before); |
134 | if let Some(result) = on_eq_typed(&file, offset) { | 142 | if let Some(result) = on_eq_typed(&file, offset) { |
135 | let actual = result.edit.apply(&before); | 143 | let actual = result.apply(&before); |
136 | assert_eq_text!(after, &actual); | 144 | assert_eq_text!(after, &actual); |
137 | } else { | 145 | } else { |
138 | assert_eq_text!(&before, after) | 146 | assert_eq_text!(&before, after) |
@@ -178,9 +186,10 @@ fn foo() { | |||
178 | let mut edit = TextEditBuilder::default(); | 186 | let mut edit = TextEditBuilder::default(); |
179 | edit.insert(offset, ".".to_string()); | 187 | edit.insert(offset, ".".to_string()); |
180 | let before = edit.finish().apply(&before); | 188 | let before = edit.finish().apply(&before); |
181 | let file = SourceFile::parse(&before); | 189 | let (analysis, file_id) = single_file(&before); |
182 | if let Some(result) = on_dot_typed(&file, offset) { | 190 | if let Some(result) = analysis.on_dot_typed(FilePosition { offset, file_id }) { |
183 | let actual = result.edit.apply(&before); | 191 | assert_eq!(result.source_file_edits.len(), 1); |
192 | let actual = result.source_file_edits[0].edit.apply(&before); | ||
184 | assert_eq_text!(after, &actual); | 193 | assert_eq_text!(after, &actual); |
185 | } else { | 194 | } else { |
186 | assert_eq_text!(&before, after) | 195 | assert_eq_text!(&before, after) |
@@ -359,10 +368,12 @@ fn foo() { | |||
359 | fn test_on_enter() { | 368 | fn test_on_enter() { |
360 | fn apply_on_enter(before: &str) -> Option<String> { | 369 | fn apply_on_enter(before: &str) -> Option<String> { |
361 | let (offset, before) = extract_offset(before); | 370 | let (offset, before) = extract_offset(before); |
362 | let file = SourceFile::parse(&before); | 371 | let (analysis, file_id) = single_file(&before); |
363 | let result = on_enter(&file, offset)?; | 372 | let result = analysis.on_enter(FilePosition { offset, file_id })?; |
364 | let actual = result.edit.apply(&before); | 373 | |
365 | let actual = add_cursor(&actual, result.cursor_position.unwrap()); | 374 | assert_eq!(result.source_file_edits.len(), 1); |
375 | let actual = result.source_file_edits[0].edit.apply(&before); | ||
376 | let actual = add_cursor(&actual, result.cursor_position.unwrap().offset); | ||
366 | Some(actual) | 377 | Some(actual) |
367 | } | 378 | } |
368 | 379 | ||