Pass a new query parameter into the search

Kirill Bulatov created

Change summary

crates/collab/src/tests/integration_tests.rs                   |  2 
crates/collab/src/tests/random_project_collaboration_tests.rs  |  3 
crates/collab2/src/tests/integration_tests.rs                  |  2 
crates/collab2/src/tests/random_project_collaboration_tests.rs |  3 
crates/collab_ui/src/chat_panel/message_editor.rs              | 10 -
crates/project/src/project.rs                                  | 20 ++
crates/project/src/project_tests.rs                            | 16 ++
crates/project/src/search.rs                                   | 20 +++
crates/project2/src/project2.rs                                | 20 ++
crates/project2/src/project_tests.rs                           | 16 ++
crates/project2/src/search.rs                                  | 20 +++
crates/rpc/proto/zed.proto                                     |  1 
crates/rpc2/proto/zed.proto                                    |  1 
crates/search/src/buffer_search.rs                             |  2 
crates/search/src/project_search.rs                            | 15 ++
crates/search/src/search.rs                                    | 24 ++-
16 files changed, 143 insertions(+), 32 deletions(-)

Detailed changes

crates/collab/src/tests/integration_tests.rs 🔗

@@ -5052,7 +5052,7 @@ async fn test_project_search(
     let mut results = HashMap::default();
     let mut search_rx = project_b.update(cx_b, |project, cx| {
         project.search(
-            SearchQuery::text("world", false, false, Vec::new(), Vec::new()).unwrap(),
+            SearchQuery::text("world", false, false, false, Vec::new(), Vec::new()).unwrap(),
             cx,
         )
     });

crates/collab/src/tests/random_project_collaboration_tests.rs 🔗

@@ -869,7 +869,8 @@ impl RandomizedTest for ProjectCollaborationTest {
 
                 let mut search = project.update(cx, |project, cx| {
                     project.search(
-                        SearchQuery::text(query, false, false, Vec::new(), Vec::new()).unwrap(),
+                        SearchQuery::text(query, false, false, false, Vec::new(), Vec::new())
+                            .unwrap(),
                         cx,
                     )
                 });

crates/collab2/src/tests/integration_tests.rs 🔗

@@ -4599,7 +4599,7 @@ async fn test_project_search(
     let mut results = HashMap::default();
     let mut search_rx = project_b.update(cx_b, |project, cx| {
         project.search(
-            SearchQuery::text("world", false, false, Vec::new(), Vec::new()).unwrap(),
+            SearchQuery::text("world", false, false, false, Vec::new(), Vec::new()).unwrap(),
             cx,
         )
     });

crates/collab2/src/tests/random_project_collaboration_tests.rs 🔗

@@ -870,7 +870,8 @@ impl RandomizedTest for ProjectCollaborationTest {
 
                 let mut search = project.update(cx, |project, cx| {
                     project.search(
-                        SearchQuery::text(query, false, false, Vec::new(), Vec::new()).unwrap(),
+                        SearchQuery::text(query, false, false, false, Vec::new(), Vec::new())
+                            .unwrap(),
                         cx,
                     )
                 });

crates/collab_ui/src/chat_panel/message_editor.rs 🔗

@@ -14,14 +14,8 @@ use std::{sync::Arc, time::Duration};
 const MENTIONS_DEBOUNCE_INTERVAL: Duration = Duration::from_millis(50);
 
 lazy_static! {
-    static ref MENTIONS_SEARCH: SearchQuery = SearchQuery::regex(
-        "@[-_\\w]+",
-        false,
-        false,
-        Default::default(),
-        Default::default()
-    )
-    .unwrap();
+    static ref MENTIONS_SEARCH: SearchQuery =
+        SearchQuery::regex("@[-_\\w]+", false, false, false, Vec::new(), Vec::new()).unwrap();
 }
 
 pub struct MessageEditor {

crates/project/src/project.rs 🔗

@@ -5548,7 +5548,16 @@ impl Project {
             .collect::<Vec<_>>();
 
         let background = cx.background().clone();
-        let path_count: usize = snapshots.iter().map(|s| s.visible_file_count()).sum();
+        let path_count: usize = snapshots
+            .iter()
+            .map(|s| {
+                if query.include_ignored() {
+                    s.file_count()
+                } else {
+                    s.visible_file_count()
+                }
+            })
+            .sum();
         if path_count == 0 {
             let (_, rx) = smol::channel::bounded(1024);
             return rx;
@@ -5735,7 +5744,12 @@ impl Project {
                         let mut snapshot_start_ix = 0;
                         let mut abs_path = PathBuf::new();
                         for snapshot in snapshots {
-                            let snapshot_end_ix = snapshot_start_ix + snapshot.visible_file_count();
+                            let snapshot_end_ix = snapshot_start_ix
+                                + if query.include_ignored() {
+                                    snapshot.file_count()
+                                } else {
+                                    snapshot.visible_file_count()
+                                };
                             if worker_end_ix <= snapshot_start_ix {
                                 break;
                             } else if worker_start_ix > snapshot_end_ix {
@@ -5748,7 +5762,7 @@ impl Project {
                                     cmp::min(worker_end_ix, snapshot_end_ix) - snapshot_start_ix;
 
                                 for entry in snapshot
-                                    .files(false, start_in_snapshot)
+                                    .files(query.include_ignored(), start_in_snapshot)
                                     .take(end_in_snapshot - start_in_snapshot)
                                 {
                                     if matching_paths_tx.is_closed() {

crates/project/src/project_tests.rs 🔗

@@ -3598,7 +3598,7 @@ async fn test_search(cx: &mut gpui::TestAppContext) {
     assert_eq!(
         search(
             &project,
-            SearchQuery::text("TWO", false, true, Vec::new(), Vec::new()).unwrap(),
+            SearchQuery::text("TWO", false, true, false, Vec::new(), Vec::new()).unwrap(),
             cx
         )
         .await
@@ -3623,7 +3623,7 @@ async fn test_search(cx: &mut gpui::TestAppContext) {
     assert_eq!(
         search(
             &project,
-            SearchQuery::text("TWO", false, true, Vec::new(), Vec::new()).unwrap(),
+            SearchQuery::text("TWO", false, true, false, Vec::new(), Vec::new()).unwrap(),
             cx
         )
         .await
@@ -3662,6 +3662,7 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
                 search_query,
                 false,
                 true,
+                false,
                 vec![PathMatcher::new("*.odd").unwrap()],
                 Vec::new()
             )
@@ -3681,6 +3682,7 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
                 search_query,
                 false,
                 true,
+                false,
                 vec![PathMatcher::new("*.rs").unwrap()],
                 Vec::new()
             )
@@ -3703,6 +3705,7 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
                 search_query,
                 false,
                 true,
+                false,
                 vec![
                     PathMatcher::new("*.ts").unwrap(),
                     PathMatcher::new("*.odd").unwrap(),
@@ -3727,6 +3730,7 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
                 search_query,
                 false,
                 true,
+                false,
                 vec![
                     PathMatcher::new("*.rs").unwrap(),
                     PathMatcher::new("*.ts").unwrap(),
@@ -3774,6 +3778,7 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
                 search_query,
                 false,
                 true,
+                false,
                 Vec::new(),
                 vec![PathMatcher::new("*.odd").unwrap()],
             )
@@ -3798,6 +3803,7 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
                 search_query,
                 false,
                 true,
+                false,
                 Vec::new(),
                 vec![PathMatcher::new("*.rs").unwrap()],
             )
@@ -3820,6 +3826,7 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
                 search_query,
                 false,
                 true,
+                false,
                 Vec::new(),
                 vec![
                     PathMatcher::new("*.ts").unwrap(),
@@ -3844,6 +3851,7 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
                 search_query,
                 false,
                 true,
+                false,
                 Vec::new(),
                 vec![
                     PathMatcher::new("*.rs").unwrap(),
@@ -3885,6 +3893,7 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex
                 search_query,
                 false,
                 true,
+                false,
                 vec![PathMatcher::new("*.odd").unwrap()],
                 vec![PathMatcher::new("*.odd").unwrap()],
             )
@@ -3904,6 +3913,7 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex
                 search_query,
                 false,
                 true,
+                false,
                 vec![PathMatcher::new("*.ts").unwrap()],
                 vec![PathMatcher::new("*.ts").unwrap()],
             ).unwrap(),
@@ -3922,6 +3932,7 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex
                 search_query,
                 false,
                 true,
+                false,
                 vec![
                     PathMatcher::new("*.ts").unwrap(),
                     PathMatcher::new("*.odd").unwrap()
@@ -3947,6 +3958,7 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex
                 search_query,
                 false,
                 true,
+                false,
                 vec![
                     PathMatcher::new("*.ts").unwrap(),
                     PathMatcher::new("*.odd").unwrap()

crates/project/src/search.rs 🔗

@@ -39,6 +39,7 @@ pub enum SearchQuery {
         replacement: Option<String>,
         whole_word: bool,
         case_sensitive: bool,
+        include_ignored: bool,
         inner: SearchInputs,
     },
 
@@ -48,6 +49,7 @@ pub enum SearchQuery {
         multiline: bool,
         whole_word: bool,
         case_sensitive: bool,
+        include_ignored: bool,
         inner: SearchInputs,
     },
 }
@@ -57,6 +59,7 @@ impl SearchQuery {
         query: impl ToString,
         whole_word: bool,
         case_sensitive: bool,
+        include_ignored: bool,
         files_to_include: Vec<PathMatcher>,
         files_to_exclude: Vec<PathMatcher>,
     ) -> Result<Self> {
@@ -74,6 +77,7 @@ impl SearchQuery {
             replacement: None,
             whole_word,
             case_sensitive,
+            include_ignored,
             inner,
         })
     }
@@ -82,6 +86,7 @@ impl SearchQuery {
         query: impl ToString,
         whole_word: bool,
         case_sensitive: bool,
+        include_ignored: bool,
         files_to_include: Vec<PathMatcher>,
         files_to_exclude: Vec<PathMatcher>,
     ) -> Result<Self> {
@@ -111,6 +116,7 @@ impl SearchQuery {
             multiline,
             whole_word,
             case_sensitive,
+            include_ignored,
             inner,
         })
     }
@@ -121,6 +127,7 @@ impl SearchQuery {
                 message.query,
                 message.whole_word,
                 message.case_sensitive,
+                message.include_ignored,
                 deserialize_path_matches(&message.files_to_include)?,
                 deserialize_path_matches(&message.files_to_exclude)?,
             )
@@ -129,6 +136,7 @@ impl SearchQuery {
                 message.query,
                 message.whole_word,
                 message.case_sensitive,
+                message.include_ignored,
                 deserialize_path_matches(&message.files_to_include)?,
                 deserialize_path_matches(&message.files_to_exclude)?,
             )
@@ -156,6 +164,7 @@ impl SearchQuery {
             regex: self.is_regex(),
             whole_word: self.whole_word(),
             case_sensitive: self.case_sensitive(),
+            include_ignored: self.include_ignored(),
             files_to_include: self
                 .files_to_include()
                 .iter()
@@ -336,6 +345,17 @@ impl SearchQuery {
         }
     }
 
+    pub fn include_ignored(&self) -> bool {
+        match self {
+            Self::Text {
+                include_ignored, ..
+            } => *include_ignored,
+            Self::Regex {
+                include_ignored, ..
+            } => *include_ignored,
+        }
+    }
+
     pub fn is_regex(&self) -> bool {
         matches!(self, Self::Regex { .. })
     }

crates/project2/src/project2.rs 🔗

@@ -5618,7 +5618,16 @@ impl Project {
             .collect::<Vec<_>>();
 
         let background = cx.background_executor().clone();
-        let path_count: usize = snapshots.iter().map(|s| s.visible_file_count()).sum();
+        let path_count: usize = snapshots
+            .iter()
+            .map(|s| {
+                if query.include_ignored() {
+                    s.file_count()
+                } else {
+                    s.visible_file_count()
+                }
+            })
+            .sum();
         if path_count == 0 {
             let (_, rx) = smol::channel::bounded(1024);
             return rx;
@@ -5806,7 +5815,12 @@ impl Project {
                         let mut snapshot_start_ix = 0;
                         let mut abs_path = PathBuf::new();
                         for snapshot in snapshots {
-                            let snapshot_end_ix = snapshot_start_ix + snapshot.visible_file_count();
+                            let snapshot_end_ix = snapshot_start_ix
+                                + if query.include_ignored() {
+                                    snapshot.file_count()
+                                } else {
+                                    snapshot.visible_file_count()
+                                };
                             if worker_end_ix <= snapshot_start_ix {
                                 break;
                             } else if worker_start_ix > snapshot_end_ix {
@@ -5819,7 +5833,7 @@ impl Project {
                                     cmp::min(worker_end_ix, snapshot_end_ix) - snapshot_start_ix;
 
                                 for entry in snapshot
-                                    .files(false, start_in_snapshot)
+                                    .files(query.include_ignored(), start_in_snapshot)
                                     .take(end_in_snapshot - start_in_snapshot)
                                 {
                                     if matching_paths_tx.is_closed() {

crates/project2/src/project_tests.rs 🔗

@@ -3730,7 +3730,7 @@ async fn test_search(cx: &mut gpui::TestAppContext) {
     assert_eq!(
         search(
             &project,
-            SearchQuery::text("TWO", false, true, Vec::new(), Vec::new()).unwrap(),
+            SearchQuery::text("TWO", false, true, false, Vec::new(), Vec::new()).unwrap(),
             cx
         )
         .await
@@ -3755,7 +3755,7 @@ async fn test_search(cx: &mut gpui::TestAppContext) {
     assert_eq!(
         search(
             &project,
-            SearchQuery::text("TWO", false, true, Vec::new(), Vec::new()).unwrap(),
+            SearchQuery::text("TWO", false, true, false, Vec::new(), Vec::new()).unwrap(),
             cx
         )
         .await
@@ -3794,6 +3794,7 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
                 search_query,
                 false,
                 true,
+                false,
                 vec![PathMatcher::new("*.odd").unwrap()],
                 Vec::new()
             )
@@ -3813,6 +3814,7 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
                 search_query,
                 false,
                 true,
+                false,
                 vec![PathMatcher::new("*.rs").unwrap()],
                 Vec::new()
             )
@@ -3835,6 +3837,7 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
                 search_query,
                 false,
                 true,
+                false,
                 vec![
                     PathMatcher::new("*.ts").unwrap(),
                     PathMatcher::new("*.odd").unwrap(),
@@ -3859,6 +3862,7 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
                 search_query,
                 false,
                 true,
+                false,
                 vec![
                     PathMatcher::new("*.rs").unwrap(),
                     PathMatcher::new("*.ts").unwrap(),
@@ -3906,6 +3910,7 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
                 search_query,
                 false,
                 true,
+                false,
                 Vec::new(),
                 vec![PathMatcher::new("*.odd").unwrap()],
             )
@@ -3930,6 +3935,7 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
                 search_query,
                 false,
                 true,
+                false,
                 Vec::new(),
                 vec![PathMatcher::new("*.rs").unwrap()],
             )
@@ -3952,6 +3958,7 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
                 search_query,
                 false,
                 true,
+                false,
                 Vec::new(),
                 vec![
                     PathMatcher::new("*.ts").unwrap(),
@@ -3976,6 +3983,7 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
                 search_query,
                 false,
                 true,
+                false,
                 Vec::new(),
                 vec![
                     PathMatcher::new("*.rs").unwrap(),
@@ -4017,6 +4025,7 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex
                 search_query,
                 false,
                 true,
+                false,
                 vec![PathMatcher::new("*.odd").unwrap()],
                 vec![PathMatcher::new("*.odd").unwrap()],
             )
@@ -4036,6 +4045,7 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex
                 search_query,
                 false,
                 true,
+                false,
                 vec![PathMatcher::new("*.ts").unwrap()],
                 vec![PathMatcher::new("*.ts").unwrap()],
             ).unwrap(),
@@ -4054,6 +4064,7 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex
                 search_query,
                 false,
                 true,
+                false,
                 vec![
                     PathMatcher::new("*.ts").unwrap(),
                     PathMatcher::new("*.odd").unwrap()
@@ -4079,6 +4090,7 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex
                 search_query,
                 false,
                 true,
+                false,
                 vec![
                     PathMatcher::new("*.ts").unwrap(),
                     PathMatcher::new("*.odd").unwrap()

crates/project2/src/search.rs 🔗

@@ -39,6 +39,7 @@ pub enum SearchQuery {
         replacement: Option<String>,
         whole_word: bool,
         case_sensitive: bool,
+        include_ignored: bool,
         inner: SearchInputs,
     },
 
@@ -48,6 +49,7 @@ pub enum SearchQuery {
         multiline: bool,
         whole_word: bool,
         case_sensitive: bool,
+        include_ignored: bool,
         inner: SearchInputs,
     },
 }
@@ -57,6 +59,7 @@ impl SearchQuery {
         query: impl ToString,
         whole_word: bool,
         case_sensitive: bool,
+        include_ignored: bool,
         files_to_include: Vec<PathMatcher>,
         files_to_exclude: Vec<PathMatcher>,
     ) -> Result<Self> {
@@ -74,6 +77,7 @@ impl SearchQuery {
             replacement: None,
             whole_word,
             case_sensitive,
+            include_ignored,
             inner,
         })
     }
@@ -82,6 +86,7 @@ impl SearchQuery {
         query: impl ToString,
         whole_word: bool,
         case_sensitive: bool,
+        include_ignored: bool,
         files_to_include: Vec<PathMatcher>,
         files_to_exclude: Vec<PathMatcher>,
     ) -> Result<Self> {
@@ -111,6 +116,7 @@ impl SearchQuery {
             multiline,
             whole_word,
             case_sensitive,
+            include_ignored,
             inner,
         })
     }
@@ -121,6 +127,7 @@ impl SearchQuery {
                 message.query,
                 message.whole_word,
                 message.case_sensitive,
+                message.include_ignored,
                 deserialize_path_matches(&message.files_to_include)?,
                 deserialize_path_matches(&message.files_to_exclude)?,
             )
@@ -129,6 +136,7 @@ impl SearchQuery {
                 message.query,
                 message.whole_word,
                 message.case_sensitive,
+                message.include_ignored,
                 deserialize_path_matches(&message.files_to_include)?,
                 deserialize_path_matches(&message.files_to_exclude)?,
             )
@@ -156,6 +164,7 @@ impl SearchQuery {
             regex: self.is_regex(),
             whole_word: self.whole_word(),
             case_sensitive: self.case_sensitive(),
+            include_ignored: self.include_ignored(),
             files_to_include: self
                 .files_to_include()
                 .iter()
@@ -336,6 +345,17 @@ impl SearchQuery {
         }
     }
 
+    pub fn include_ignored(&self) -> bool {
+        match self {
+            Self::Text {
+                include_ignored, ..
+            } => *include_ignored,
+            Self::Regex {
+                include_ignored, ..
+            } => *include_ignored,
+        }
+    }
+
     pub fn is_regex(&self) -> bool {
         matches!(self, Self::Regex { .. })
     }

crates/rpc/proto/zed.proto 🔗

@@ -884,6 +884,7 @@ message SearchProject {
     bool case_sensitive = 5;
     string files_to_include = 6;
     string files_to_exclude = 7;
+    bool include_ignored = 8;
 }
 
 message SearchProjectResponse {

crates/rpc2/proto/zed.proto 🔗

@@ -884,6 +884,7 @@ message SearchProject {
     bool case_sensitive = 5;
     string files_to_include = 6;
     string files_to_exclude = 7;
+    bool include_ignored = 8;
 }
 
 message SearchProjectResponse {

crates/search/src/buffer_search.rs 🔗

@@ -805,6 +805,7 @@ impl BufferSearchBar {
                         query,
                         self.search_options.contains(SearchOptions::WHOLE_WORD),
                         self.search_options.contains(SearchOptions::CASE_SENSITIVE),
+                        false,
                         Vec::new(),
                         Vec::new(),
                     ) {
@@ -820,6 +821,7 @@ impl BufferSearchBar {
                         query,
                         self.search_options.contains(SearchOptions::WHOLE_WORD),
                         self.search_options.contains(SearchOptions::CASE_SENSITIVE),
+                        false,
                         Vec::new(),
                         Vec::new(),
                     ) {

crates/search/src/project_search.rs 🔗

@@ -4,7 +4,7 @@ use crate::{
     search_bar::{render_nav_button, render_option_button_icon, render_search_mode_button},
     ActivateRegexMode, ActivateSemanticMode, ActivateTextMode, CycleMode, NextHistoryQuery,
     PreviousHistoryQuery, ReplaceAll, ReplaceNext, SearchOptions, SelectNextMatch, SelectPrevMatch,
-    ToggleCaseSensitive, ToggleReplace, ToggleWholeWord,
+    ToggleCaseSensitive, ToggleIncludeIgnored, ToggleReplace, ToggleWholeWord,
 };
 use anyhow::{Context, Result};
 use collections::HashMap;
@@ -85,6 +85,7 @@ pub fn init(cx: &mut AppContext) {
     cx.capture_action(ProjectSearchView::replace_next);
     add_toggle_option_action::<ToggleCaseSensitive>(SearchOptions::CASE_SENSITIVE, cx);
     add_toggle_option_action::<ToggleWholeWord>(SearchOptions::WHOLE_WORD, cx);
+    add_toggle_option_action::<ToggleIncludeIgnored>(SearchOptions::INCLUDE_IGNORED, cx);
     add_toggle_filters_action::<ToggleFilters>(cx);
 }
 
@@ -1192,6 +1193,7 @@ impl ProjectSearchView {
                     text,
                     self.search_options.contains(SearchOptions::WHOLE_WORD),
                     self.search_options.contains(SearchOptions::CASE_SENSITIVE),
+                    self.search_options.contains(SearchOptions::INCLUDE_IGNORED),
                     included_files,
                     excluded_files,
                 ) {
@@ -1210,6 +1212,7 @@ impl ProjectSearchView {
                 text,
                 self.search_options.contains(SearchOptions::WHOLE_WORD),
                 self.search_options.contains(SearchOptions::CASE_SENSITIVE),
+                self.search_options.contains(SearchOptions::INCLUDE_IGNORED),
                 included_files,
                 excluded_files,
             ) {
@@ -1764,6 +1767,15 @@ impl View for ProjectSearchBar {
                 render_option_button_icon("icons/word_search.svg", SearchOptions::WHOLE_WORD, cx)
             });
 
+            let include_ignored = is_semantic_disabled.then(|| {
+                render_option_button_icon(
+                    // TODO kb icon
+                    "icons/case_insensitive.svg",
+                    SearchOptions::INCLUDE_IGNORED,
+                    cx,
+                )
+            });
+
             let search_button_for_mode = |mode, side, cx: &mut ViewContext<ProjectSearchBar>| {
                 let is_active = if let Some(search) = self.active_project_search.as_ref() {
                     let search = search.read(cx);
@@ -1863,6 +1875,7 @@ impl View for ProjectSearchBar {
                                 .with_child(filter_button)
                                 .with_children(case_sensitive)
                                 .with_children(whole_word)
+                                .with_children(include_ignored)
                                 .flex(1., false)
                                 .constrained()
                                 .contained(),

crates/search/src/search.rs 🔗

@@ -29,6 +29,7 @@ actions!(
         CycleMode,
         ToggleWholeWord,
         ToggleCaseSensitive,
+        ToggleIncludeIgnored,
         ToggleReplace,
         SelectNextMatch,
         SelectPrevMatch,
@@ -49,31 +50,35 @@ bitflags! {
         const NONE = 0b000;
         const WHOLE_WORD = 0b001;
         const CASE_SENSITIVE = 0b010;
+        const INCLUDE_IGNORED = 0b100;
     }
 }
 
 impl SearchOptions {
     pub fn label(&self) -> &'static str {
         match *self {
-            SearchOptions::WHOLE_WORD => "Match Whole Word",
-            SearchOptions::CASE_SENSITIVE => "Match Case",
-            _ => panic!("{:?} is not a named SearchOption", self),
+            Self::WHOLE_WORD => "Match Whole Word",
+            Self::CASE_SENSITIVE => "Match Case",
+            Self::INCLUDE_IGNORED => "Include Ignored",
+            _ => panic!("{self:?} is not a named SearchOption"),
         }
     }
 
     pub fn icon(&self) -> &'static str {
         match *self {
-            SearchOptions::WHOLE_WORD => "icons/word_search.svg",
-            SearchOptions::CASE_SENSITIVE => "icons/case_insensitive.svg",
-            _ => panic!("{:?} is not a named SearchOption", self),
+            Self::WHOLE_WORD => "icons/word_search.svg",
+            Self::CASE_SENSITIVE => "icons/case_insensitive.svg",
+            Self::INCLUDE_IGNORED => "icons/case_insensitive.svg",
+            _ => panic!("{self:?} is not a named SearchOption"),
         }
     }
 
     pub fn to_toggle_action(&self) -> Box<dyn Action> {
         match *self {
-            SearchOptions::WHOLE_WORD => Box::new(ToggleWholeWord),
-            SearchOptions::CASE_SENSITIVE => Box::new(ToggleCaseSensitive),
-            _ => panic!("{:?} is not a named SearchOption", self),
+            Self::WHOLE_WORD => Box::new(ToggleWholeWord),
+            Self::CASE_SENSITIVE => Box::new(ToggleCaseSensitive),
+            Self::INCLUDE_IGNORED => Box::new(ToggleIncludeIgnored),
+            _ => panic!("{self:?} is not a named SearchOption"),
         }
     }
 
@@ -85,6 +90,7 @@ impl SearchOptions {
         let mut options = SearchOptions::NONE;
         options.set(SearchOptions::WHOLE_WORD, query.whole_word());
         options.set(SearchOptions::CASE_SENSITIVE, query.case_sensitive());
+        options.set(SearchOptions::INCLUDE_IGNORED, query.include_ignored());
         options
     }