diff options
author | Aleksey Kladov <[email protected]> | 2020-03-11 11:46:36 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-03-11 11:58:16 +0000 |
commit | 52da9e90a6002eb712175f7c8d76a472cf966d8e (patch) | |
tree | f2a08835519d35693e1c8661581ce1593c3c2a91 /crates/ra_ide/src/typing.rs | |
parent | c48dcf74118b6e0df747f036a9b66701037f3fc7 (diff) |
Move on enter to a separate module
Diffstat (limited to 'crates/ra_ide/src/typing.rs')
-rw-r--r-- | crates/ra_ide/src/typing.rs | 160 |
1 files changed, 6 insertions, 154 deletions
diff --git a/crates/ra_ide/src/typing.rs b/crates/ra_ide/src/typing.rs index 7f1b9150f..53c65f8bc 100644 --- a/crates/ra_ide/src/typing.rs +++ b/crates/ra_ide/src/typing.rs | |||
@@ -13,77 +13,21 @@ | |||
13 | //! Language server executes such typing assists synchronously. That is, they | 13 | //! Language server executes such typing assists synchronously. That is, they |
14 | //! block user's typing and should be pretty fast for this reason! | 14 | //! block user's typing and should be pretty fast for this reason! |
15 | 15 | ||
16 | mod on_enter; | ||
17 | |||
16 | use ra_db::{FilePosition, SourceDatabase}; | 18 | use ra_db::{FilePosition, SourceDatabase}; |
17 | use ra_fmt::leading_indent; | 19 | use ra_fmt::leading_indent; |
18 | use ra_ide_db::RootDatabase; | 20 | use ra_ide_db::RootDatabase; |
19 | use ra_syntax::{ | 21 | use ra_syntax::{ |
20 | algo::find_node_at_offset, | 22 | algo::find_node_at_offset, |
21 | ast::{self, AstToken}, | 23 | ast::{self, AstToken}, |
22 | AstNode, SmolStr, SourceFile, | 24 | AstNode, SourceFile, TextRange, TextUnit, |
23 | SyntaxKind::*, | ||
24 | SyntaxToken, TextRange, TextUnit, TokenAtOffset, | ||
25 | }; | 25 | }; |
26 | use ra_text_edit::TextEdit; | 26 | use ra_text_edit::TextEdit; |
27 | 27 | ||
28 | use crate::{source_change::SingleFileChange, SourceChange, SourceFileEdit}; | 28 | use crate::{source_change::SingleFileChange, SourceChange}; |
29 | |||
30 | pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<SourceChange> { | ||
31 | let parse = db.parse(position.file_id); | ||
32 | let file = parse.tree(); | ||
33 | let comment = file | ||
34 | .syntax() | ||
35 | .token_at_offset(position.offset) | ||
36 | .left_biased() | ||
37 | .and_then(ast::Comment::cast)?; | ||
38 | |||
39 | if comment.kind().shape.is_block() { | ||
40 | return None; | ||
41 | } | ||
42 | |||
43 | let prefix = comment.prefix(); | ||
44 | let comment_range = comment.syntax().text_range(); | ||
45 | if position.offset < comment_range.start() + TextUnit::of_str(prefix) { | ||
46 | return None; | ||
47 | } | ||
48 | |||
49 | // Continuing non-doc line comments (like this one :) ) is annoying | ||
50 | if prefix == "//" && comment_range.end() == position.offset { | ||
51 | return None; | ||
52 | } | ||
53 | |||
54 | let indent = node_indent(&file, comment.syntax())?; | ||
55 | let inserted = format!("\n{}{} ", indent, prefix); | ||
56 | let cursor_position = position.offset + TextUnit::of_str(&inserted); | ||
57 | let edit = TextEdit::insert(position.offset, inserted); | ||
58 | 29 | ||
59 | Some( | 30 | pub(crate) use on_enter::on_enter; |
60 | SourceChange::source_file_edit( | ||
61 | "on enter", | ||
62 | SourceFileEdit { edit, file_id: position.file_id }, | ||
63 | ) | ||
64 | .with_cursor(FilePosition { offset: cursor_position, file_id: position.file_id }), | ||
65 | ) | ||
66 | } | ||
67 | |||
68 | fn node_indent(file: &SourceFile, token: &SyntaxToken) -> Option<SmolStr> { | ||
69 | let ws = match file.syntax().token_at_offset(token.text_range().start()) { | ||
70 | TokenAtOffset::Between(l, r) => { | ||
71 | assert!(r == *token); | ||
72 | l | ||
73 | } | ||
74 | TokenAtOffset::Single(n) => { | ||
75 | assert!(n == *token); | ||
76 | return Some("".into()); | ||
77 | } | ||
78 | TokenAtOffset::None => unreachable!(), | ||
79 | }; | ||
80 | if ws.kind() != WHITESPACE { | ||
81 | return None; | ||
82 | } | ||
83 | let text = ws.text(); | ||
84 | let pos = text.rfind('\n').map(|it| it + 1).unwrap_or(0); | ||
85 | Some(text[pos..].into()) | ||
86 | } | ||
87 | 31 | ||
88 | pub(crate) const TRIGGER_CHARS: &str = ".=>"; | 32 | pub(crate) const TRIGGER_CHARS: &str = ".=>"; |
89 | 33 | ||
@@ -196,102 +140,10 @@ fn on_arrow_typed(file: &SourceFile, offset: TextUnit) -> Option<SingleFileChang | |||
196 | 140 | ||
197 | #[cfg(test)] | 141 | #[cfg(test)] |
198 | mod tests { | 142 | mod tests { |
199 | use test_utils::{add_cursor, assert_eq_text, extract_offset}; | 143 | use test_utils::{assert_eq_text, extract_offset}; |
200 | |||
201 | use crate::mock_analysis::single_file; | ||
202 | 144 | ||
203 | use super::*; | 145 | use super::*; |
204 | 146 | ||
205 | #[test] | ||
206 | fn test_on_enter() { | ||
207 | fn apply_on_enter(before: &str) -> Option<String> { | ||
208 | let (offset, before) = extract_offset(before); | ||
209 | let (analysis, file_id) = single_file(&before); | ||
210 | let result = analysis.on_enter(FilePosition { offset, file_id }).unwrap()?; | ||
211 | |||
212 | assert_eq!(result.source_file_edits.len(), 1); | ||
213 | let actual = result.source_file_edits[0].edit.apply(&before); | ||
214 | let actual = add_cursor(&actual, result.cursor_position.unwrap().offset); | ||
215 | Some(actual) | ||
216 | } | ||
217 | |||
218 | fn do_check(before: &str, after: &str) { | ||
219 | let actual = apply_on_enter(before).unwrap(); | ||
220 | assert_eq_text!(after, &actual); | ||
221 | } | ||
222 | |||
223 | fn do_check_noop(text: &str) { | ||
224 | assert!(apply_on_enter(text).is_none()) | ||
225 | } | ||
226 | |||
227 | do_check( | ||
228 | r" | ||
229 | /// Some docs<|> | ||
230 | fn foo() { | ||
231 | } | ||
232 | ", | ||
233 | r" | ||
234 | /// Some docs | ||
235 | /// <|> | ||
236 | fn foo() { | ||
237 | } | ||
238 | ", | ||
239 | ); | ||
240 | do_check( | ||
241 | r" | ||
242 | impl S { | ||
243 | /// Some<|> docs. | ||
244 | fn foo() {} | ||
245 | } | ||
246 | ", | ||
247 | r" | ||
248 | impl S { | ||
249 | /// Some | ||
250 | /// <|> docs. | ||
251 | fn foo() {} | ||
252 | } | ||
253 | ", | ||
254 | ); | ||
255 | do_check( | ||
256 | r" | ||
257 | fn main() { | ||
258 | // Fix<|> me | ||
259 | let x = 1 + 1; | ||
260 | } | ||
261 | ", | ||
262 | r" | ||
263 | fn main() { | ||
264 | // Fix | ||
265 | // <|> me | ||
266 | let x = 1 + 1; | ||
267 | } | ||
268 | ", | ||
269 | ); | ||
270 | do_check( | ||
271 | r" | ||
272 | ///<|> Some docs | ||
273 | fn foo() { | ||
274 | } | ||
275 | ", | ||
276 | r" | ||
277 | /// | ||
278 | /// <|> Some docs | ||
279 | fn foo() { | ||
280 | } | ||
281 | ", | ||
282 | ); | ||
283 | do_check_noop( | ||
284 | r" | ||
285 | fn main() { | ||
286 | // Fix me<|> | ||
287 | let x = 1 + 1; | ||
288 | } | ||
289 | ", | ||
290 | ); | ||
291 | |||
292 | do_check_noop(r"<|>//! docz"); | ||
293 | } | ||
294 | |||
295 | fn do_type_char(char_typed: char, before: &str) -> Option<(String, SingleFileChange)> { | 147 | fn do_type_char(char_typed: char, before: &str) -> Option<(String, SingleFileChange)> { |
296 | let (offset, before) = extract_offset(before); | 148 | let (offset, before) = extract_offset(before); |
297 | let edit = TextEdit::insert(offset, char_typed.to_string()); | 149 | let edit = TextEdit::insert(offset, char_typed.to_string()); |