From ea948e9fbb519ab5f4a21e0cce0dc5f0f365a716 Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
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(-)

(limited to 'crates/ra_ide_api')

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<Option<SourceChange>> {
+        // 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<SmolStr> {
     Some(text[pos..].into())
 }
 
+pub(crate) const TRIGGER_CHARS: &str = ".=";
+
 pub(crate) fn on_char_typed(
     db: &RootDatabase,
     position: FilePosition,
     char_typed: char,
 ) -> Option<SourceChange> {
+    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<SingleFileChange> {
+    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