瀏覽代碼

Improved completion performance
Removed non-matching candidates from consideration earlier, obviating need to filter them out
Removed clones of candidates that didn't match (before: clone then check; after: check then clone)

Robert Bennett 1 年之前
父節點
當前提交
aa564a3c4e
共有 2 個文件被更改,包括 42 次插入42 次删除
  1. 1 1
      numbat-cli/src/completer.rs
  2. 41 41
      numbat/src/lib.rs

+ 1 - 1
numbat-cli/src/completer.rs

@@ -131,7 +131,7 @@ impl Completer for NumbatCompleter {
             candidates
                 .map(|w| Pair {
                     display: w.to_string(),
-                    replacement: w.to_string(),
+                    replacement: w,
                 })
                 .collect(),
         ))

+ 41 - 41
numbat/src/lib.rs

@@ -47,6 +47,8 @@ mod unit_registry;
 pub mod value;
 mod vm;
 
+use std::borrow::Cow;
+
 use bytecode_interpreter::BytecodeInterpreter;
 use column_formatter::ColumnFormatter;
 use currency::ExchangeRatesCache;
@@ -200,15 +202,6 @@ impl Context {
     }
 
     pub fn print_environment(&self) -> Markup {
-        let mut functions: Vec<_> = self.function_names().collect();
-        functions.sort();
-        let mut dimensions = Vec::from(self.dimension_names());
-        dimensions.sort();
-        let mut units = Vec::from(self.unit_names());
-        units.sort();
-        let mut variables: Vec<_> = self.variable_names().collect();
-        variables.sort();
-
         let mut output = m::empty();
 
         output += m::emphasized("List of functions:") + m::nl();
@@ -253,11 +246,11 @@ impl Context {
     /// Gets completions for the given word_part
     ///
     /// If `add_paren` is true, then an opening paren will be added to the end of function names
-    pub fn get_completions_for<'a>(
+    pub fn get_completions_for(
         &self,
-        word_part: &'a str,
+        word_part: &str,
         add_paren: bool,
-    ) -> impl Iterator<Item = String> + 'a {
+    ) -> impl Iterator<Item = String> {
         const COMMON_METRIC_PREFIXES: &[&str] = &[
             "pico", "nano", "micro", "milli", "centi", "kilo", "mega", "giga", "tera",
         ];
@@ -270,53 +263,60 @@ impl Context {
             })
             .collect();
 
-        let mut words: Vec<_> = KEYWORDS.iter().map(|k| k.to_string()).collect();
+        let mut words = Vec::new();
+
+        let mut add_if_valid = |word: Cow<'_, str>| {
+            if word.starts_with(word_part) {
+                words.push(word.into_owned());
+            }
+        };
+
+        for kw in KEYWORDS {
+            add_if_valid((*kw).into());
+        }
 
         for (patterns, _) in UNICODE_INPUT {
             for pattern in *patterns {
-                words.push(pattern.to_string());
+                add_if_valid((*pattern).into());
             }
         }
 
-        {
-            for variable in self.variable_names() {
-                words.push(variable.clone());
-            }
+        for variable in self.variable_names() {
+            add_if_valid(variable.into());
+        }
 
-            for function in self.function_names() {
-                if add_paren {
-                    words.push(format!("{function}("));
-                } else {
-                    words.push(function.to_string());
-                }
+        for mut function in self.function_names() {
+            if add_paren {
+                function.push('(');
             }
+            add_if_valid(function.into());
+        }
 
-            for dimension in self.dimension_names() {
-                words.push(dimension.clone());
-            }
+        for dimension in self.dimension_names() {
+            add_if_valid(dimension.into());
+        }
 
-            for (_, (_, meta)) in self.unit_representations() {
-                for (unit, accepts_prefix) in meta.aliases {
-                    words.push(unit.clone());
-
-                    // Add some of the common long prefixes for units that accept them.
-                    // We do not add all possible prefixes here in order to keep the
-                    // number of completions to a reasonable size. Also, we do not add
-                    // short prefixes for units that accept them, as that leads to lots
-                    // and lots of 2-3 character words.
-                    if accepts_prefix.long && meta.metric_prefixes {
-                        for prefix in &metric_prefixes {
-                            words.push(format!("{prefix}{unit}"));
-                        }
+        for (_, (_, meta)) in self.unit_representations() {
+            for (unit, accepts_prefix) in meta.aliases {
+                // Add some of the common long prefixes for units that accept them.
+                // We do not add all possible prefixes here in order to keep the
+                // number of completions to a reasonable size. Also, we do not add
+                // short prefixes for units that accept them, as that leads to lots
+                // and lots of 2-3 character words.
+                if accepts_prefix.long && meta.metric_prefixes {
+                    for prefix in &metric_prefixes {
+                        add_if_valid(format!("{prefix}{unit}").into());
                     }
                 }
+
+                add_if_valid(unit.into());
             }
         }
 
         words.sort();
         words.dedup();
 
-        words.into_iter().filter(move |w| w.starts_with(word_part))
+        words.into_iter()
     }
 
     pub fn print_info_for_keyword(&mut self, keyword: &str) -> Markup {