@@ -13,10 +13,10 @@ use editor::{
use editor::{EditorElement, EditorStyle};
use gpui::{
actions, div, AnyElement, AnyView, AppContext, Context as _, Element, EntityId, EventEmitter,
- FocusHandle, FocusableView, FontStyle, FontWeight, InteractiveElement, IntoElement, KeyContext,
- Model, ModelContext, ParentElement, PromptLevel, Render, SharedString, Styled, Subscription,
- Task, TextStyle, View, ViewContext, VisualContext, WeakModel, WeakView, WhiteSpace,
- WindowContext,
+ FocusHandle, FocusableView, FontStyle, FontWeight, Hsla, InteractiveElement, IntoElement,
+ KeyContext, Model, ModelContext, ParentElement, PromptLevel, Render, SharedString, Styled,
+ Subscription, Task, TextStyle, View, ViewContext, VisualContext, WeakModel, WeakView,
+ WhiteSpace, WindowContext,
};
use menu::Confirm;
use project::{
@@ -1007,33 +1007,46 @@ impl ProjectSearchView {
}
fn build_search_query(&mut self, cx: &mut ViewContext<Self>) -> Option<SearchQuery> {
+ // Do not bail early in this function, as we want to fill out `self.panels_with_errors`.
let text = self.query_editor.read(cx).text(cx);
let included_files =
match Self::parse_path_matches(&self.included_files_editor.read(cx).text(cx)) {
Ok(included_files) => {
- self.panels_with_errors.remove(&InputPanel::Include);
+ let should_unmark_error = self.panels_with_errors.remove(&InputPanel::Include);
+ if should_unmark_error {
+ cx.notify();
+ }
included_files
}
Err(_e) => {
- self.panels_with_errors.insert(InputPanel::Include);
- cx.notify();
- return None;
+ let should_mark_error = self.panels_with_errors.insert(InputPanel::Include);
+ if should_mark_error {
+ cx.notify();
+ }
+ vec![]
}
};
let excluded_files =
match Self::parse_path_matches(&self.excluded_files_editor.read(cx).text(cx)) {
Ok(excluded_files) => {
- self.panels_with_errors.remove(&InputPanel::Exclude);
+ let should_unmark_error = self.panels_with_errors.remove(&InputPanel::Exclude);
+ if should_unmark_error {
+ cx.notify();
+ }
+
excluded_files
}
Err(_e) => {
- self.panels_with_errors.insert(InputPanel::Exclude);
- cx.notify();
- return None;
+ let should_mark_error = self.panels_with_errors.insert(InputPanel::Exclude);
+ if should_mark_error {
+ cx.notify();
+ }
+ vec![]
}
};
+
let current_mode = self.current_mode;
- match current_mode {
+ let query = match current_mode {
SearchMode::Regex => {
match SearchQuery::regex(
text,
@@ -1044,12 +1057,20 @@ impl ProjectSearchView {
excluded_files,
) {
Ok(query) => {
- self.panels_with_errors.remove(&InputPanel::Query);
+ let should_unmark_error =
+ self.panels_with_errors.remove(&InputPanel::Query);
+ if should_unmark_error {
+ cx.notify();
+ }
+
Some(query)
}
Err(_e) => {
- self.panels_with_errors.insert(InputPanel::Query);
- cx.notify();
+ let should_mark_error = self.panels_with_errors.insert(InputPanel::Query);
+ if should_mark_error {
+ cx.notify();
+ }
+
None
}
}
@@ -1063,16 +1084,27 @@ impl ProjectSearchView {
excluded_files,
) {
Ok(query) => {
- self.panels_with_errors.remove(&InputPanel::Query);
+ let should_unmark_error = self.panels_with_errors.remove(&InputPanel::Query);
+ if should_unmark_error {
+ cx.notify();
+ }
+
Some(query)
}
Err(_e) => {
- self.panels_with_errors.insert(InputPanel::Query);
- cx.notify();
+ let should_mark_error = self.panels_with_errors.insert(InputPanel::Query);
+ if should_mark_error {
+ cx.notify();
+ }
+
None
}
},
+ };
+ if !self.panels_with_errors.is_empty() {
+ return None;
}
+ query
}
fn parse_path_matches(text: &str) -> anyhow::Result<Vec<PathMatcher>> {
@@ -1185,6 +1217,13 @@ impl ProjectSearchView {
SearchMode::Semantic => "\nSimply explain the code you are looking to find. ex. 'prompt user for permissions to index their project'".into()
}
}
+ fn border_color_for(&self, panel: InputPanel, cx: &WindowContext) -> Hsla {
+ if self.panels_with_errors.contains(&panel) {
+ Color::Error.color(cx)
+ } else {
+ cx.theme().colors().border
+ }
+ }
}
impl Default for ProjectSearchBar {
@@ -1507,6 +1546,7 @@ impl Render for ProjectSearchBar {
}
let search = search.read(cx);
let semantic_is_available = SemanticIndex::enabled(cx);
+
let query_column = v_stack().child(
h_stack()
.min_w(rems(512. / 16.))
@@ -1515,7 +1555,7 @@ impl Render for ProjectSearchBar {
.gap_2()
.bg(cx.theme().colors().editor_background)
.border_1()
- .border_color(cx.theme().colors().border)
+ .border_color(search.border_color_for(InputPanel::Query, cx))
.rounded_lg()
.on_action(cx.listener(|this, action, cx| this.confirm(action, cx)))
.on_action(cx.listener(|this, action, cx| this.previous_history_query(action, cx)))
@@ -1789,7 +1829,7 @@ impl Render for ProjectSearchBar {
.px_2()
.py_1()
.border_1()
- .border_color(cx.theme().colors().border)
+ .border_color(search.border_color_for(InputPanel::Include, cx))
.rounded_lg()
.child(self.render_text_input(&search.included_files_editor, cx))
.when(search.current_mode != SearchMode::Semantic, |this| {
@@ -1815,7 +1855,7 @@ impl Render for ProjectSearchBar {
.px_2()
.py_1()
.border_1()
- .border_color(cx.theme().colors().border)
+ .border_color(search.border_color_for(InputPanel::Exclude, cx))
.rounded_lg()
.child(self.render_text_input(&search.excluded_files_editor, cx)),
),