From ea948e9fbb519ab5f4a21e0cce0dc5f0f365a716 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 25 Oct 2019 12:04:17 +0300 Subject: refactor typing_handlers --- crates/ra_ide_api/src/lib.rs | 4 +++ crates/ra_ide_api/src/typing.rs | 72 +++++++++++++++++++++-------------------- 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index 6b8aa7a8e..d0188da44 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs @@ -323,6 +323,10 @@ impl Analysis { position: FilePosition, char_typed: char, ) -> Cancelable> { + // Fast path to not even parse the file. + if !typing::TRIGGER_CHARS.contains(char_typed) { + return Ok(None); + } self.with_db(|db| typing::on_char_typed(&db, position, char_typed)) } diff --git a/crates/ra_ide_api/src/typing.rs b/crates/ra_ide_api/src/typing.rs index c5ec6c1c1..17d0f08a5 100644 --- a/crates/ra_ide_api/src/typing.rs +++ b/crates/ra_ide_api/src/typing.rs @@ -81,22 +81,32 @@ fn node_indent(file: &SourceFile, token: &SyntaxToken) -> Option { Some(text[pos..].into()) } +pub(crate) const TRIGGER_CHARS: &str = ".="; + pub(crate) fn on_char_typed( db: &RootDatabase, position: FilePosition, char_typed: char, ) -> Option { + assert!(TRIGGER_CHARS.contains(char_typed)); let file = &db.parse(position.file_id).tree(); assert_eq!(file.syntax().text().char_at(position.offset), Some(char_typed)); - let single_file_change = match char_typed { - '=' => on_eq_typed(file, position.offset)?, - '.' => on_dot_typed(file, position.offset)?, - _ => return None, - }; - + let single_file_change = on_char_typed_inner(file, position.offset, char_typed)?; Some(single_file_change.into_source_change(position.file_id)) } +fn on_char_typed_inner( + file: &SourceFile, + offset: TextUnit, + char_typed: char, +) -> Option { + match char_typed { + '.' => on_dot_typed(file, offset), + '=' => on_eq_typed(file, offset), + _ => None, + } +} + /// Returns an edit which should be applied after `=` was typed. Primarily, /// this works when adding `let =`. // FIXME: use a snippet completion instead of this hack here. @@ -167,22 +177,29 @@ mod tests { use super::*; + fn type_char(char_typed: char, before: &str, after: &str) { + let (offset, before) = extract_offset(before); + let edit = TextEdit::insert(offset, char_typed.to_string()); + let before = edit.apply(&before); + let parse = SourceFile::parse(&before); + if let Some(result) = on_char_typed_inner(&parse.tree(), offset, char_typed) { + let actual = result.edit.apply(&before); + assert_eq_text!(after, &actual); + } else { + assert_eq_text!(&before, after) + }; + } + + fn type_eq(before: &str, after: &str) { + type_char('=', before, after); + } + + fn type_dot(before: &str, after: &str) { + type_char('.', before, after); + } + #[test] fn test_on_eq_typed() { - fn type_eq(before: &str, after: &str) { - let (offset, before) = extract_offset(before); - let mut edit = TextEditBuilder::default(); - edit.insert(offset, "=".to_string()); - let before = edit.finish().apply(&before); - let parse = SourceFile::parse(&before); - if let Some(result) = on_eq_typed(&parse.tree(), offset) { - let actual = result.edit.apply(&before); - assert_eq_text!(after, &actual); - } else { - assert_eq_text!(&before, after) - }; - } - // do_check(r" // fn foo() { // let foo =<|> @@ -217,21 +234,6 @@ fn foo() { // "); } - fn type_dot(before: &str, after: &str) { - let (offset, before) = extract_offset(before); - let mut edit = TextEditBuilder::default(); - edit.insert(offset, ".".to_string()); - let before = edit.finish().apply(&before); - let (analysis, file_id) = single_file(&before); - let file = analysis.parse(file_id).unwrap(); - if let Some(result) = on_dot_typed(&file, offset) { - let actual = result.edit.apply(&before); - assert_eq_text!(after, &actual); - } else { - assert_eq_text!(&before, after) - }; - } - #[test] fn indents_new_chain_call() { type_dot( -- cgit v1.2.3