Remove another unwrap on regex compilation (#29984)

Conrad Irwin created

Follow up to #29979

Release Notes:

- Fixed a (hypothetical) panic in terminal search

Change summary

Cargo.lock                                |  1 
crates/terminal_view/Cargo.toml           |  1 
crates/terminal_view/src/terminal_view.rs | 61 ++++--------------------
3 files changed, 12 insertions(+), 51 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -14746,6 +14746,7 @@ dependencies = [
  "log",
  "project",
  "rand 0.8.5",
+ "regex",
  "schemars",
  "search",
  "serde",

crates/terminal_view/Cargo.toml 🔗

@@ -29,6 +29,7 @@ itertools.workspace = true
 language.workspace = true
 log.workspace = true
 project.workspace = true
+regex.workspace = true
 task.workspace = true
 schemars.workspace = true
 search.workspace = true

crates/terminal_view/src/terminal_view.rs 🔗

@@ -57,10 +57,6 @@ use std::{
     time::Duration,
 };
 
-const REGEX_SPECIAL_CHARS: &[char] = &[
-    '\\', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '^', '$',
-];
-
 const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
 
 const GIT_DIFF_PATH_PREFIXES: &[&str] = &["a", "b"];
@@ -1258,26 +1254,16 @@ fn possible_open_target(
     })
 }
 
-fn regex_to_literal(regex: &str) -> String {
-    regex
-        .chars()
-        .flat_map(|c| {
-            if REGEX_SPECIAL_CHARS.contains(&c) {
-                vec!['\\', c]
-            } else {
-                vec![c]
-            }
-        })
-        .collect()
-}
-
-pub fn regex_search_for_query(query: &project::search::SearchQuery) -> Option<RegexSearch> {
-    let query = query.as_str();
-    if query == "." {
-        return None;
+fn regex_search_for_query(query: &project::search::SearchQuery) -> Option<RegexSearch> {
+    let str = query.as_str();
+    if query.is_regex() {
+        if str == "." {
+            return None;
+        }
+        RegexSearch::new(str).ok()
+    } else {
+        RegexSearch::new(&regex::escape(str)).ok()
     }
-    let searcher = RegexSearch::new(query);
-    searcher.ok()
 }
 
 impl TerminalView {
@@ -1740,24 +1726,7 @@ impl SearchableItem for TerminalView {
         _: &mut Window,
         cx: &mut Context<Self>,
     ) -> Task<Vec<Self::Match>> {
-        let searcher = match &*query {
-            SearchQuery::Text { .. } => regex_search_for_query(
-                &(SearchQuery::text(
-                    regex_to_literal(query.as_str()),
-                    query.whole_word(),
-                    query.case_sensitive(),
-                    query.include_ignored(),
-                    query.files_to_include().clone(),
-                    query.files_to_exclude().clone(),
-                    false,
-                    None,
-                )
-                .unwrap()),
-            ),
-            SearchQuery::Regex { .. } => regex_search_for_query(&query),
-        };
-
-        if let Some(s) = searcher {
+        if let Some(s) = regex_search_for_query(&query) {
             self.terminal()
                 .update(cx, |term, cx| term.find_matches(s, cx))
         } else {
@@ -2052,14 +2021,4 @@ mod tests {
             project.update(cx, |project, cx| project.set_active_path(Some(p), cx));
         });
     }
-
-    #[test]
-    fn escapes_only_special_characters() {
-        assert_eq!(regex_to_literal(r"test(\w)"), r"test\(\\w\)".to_string());
-    }
-
-    #[test]
-    fn empty_string_stays_empty() {
-        assert_eq!(regex_to_literal(""), "".to_string());
-    }
 }