Highlight include/exclude inputs when errors happen there

This commit is contained in:
Kirill Bulatov 2023-05-10 00:06:44 +03:00 committed by Kirill Bulatov
parent dfdf7e4866
commit eec60556ab
3 changed files with 67 additions and 23 deletions

View File

@ -22,6 +22,7 @@ use smallvec::SmallVec;
use std::{ use std::{
any::{Any, TypeId}, any::{Any, TypeId},
borrow::Cow, borrow::Cow,
collections::HashSet,
mem, mem,
ops::Range, ops::Range,
path::PathBuf, path::PathBuf,
@ -76,6 +77,13 @@ struct ProjectSearch {
search_id: usize, search_id: usize,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum InputPanel {
Query,
Exclude,
Include,
}
pub struct ProjectSearchView { pub struct ProjectSearchView {
model: ModelHandle<ProjectSearch>, model: ModelHandle<ProjectSearch>,
query_editor: ViewHandle<Editor>, query_editor: ViewHandle<Editor>,
@ -83,7 +91,7 @@ pub struct ProjectSearchView {
case_sensitive: bool, case_sensitive: bool,
whole_word: bool, whole_word: bool,
regex: bool, regex: bool,
query_contains_error: bool, panels_with_errors: HashSet<InputPanel>,
active_match_index: Option<usize>, active_match_index: Option<usize>,
search_id: usize, search_id: usize,
query_editor_was_focused: bool, query_editor_was_focused: bool,
@ -493,7 +501,7 @@ impl ProjectSearchView {
case_sensitive, case_sensitive,
whole_word, whole_word,
regex, regex,
query_contains_error: false, panels_with_errors: HashSet::new(),
active_match_index: None, active_match_index: None,
query_editor_was_focused: false, query_editor_was_focused: false,
included_files_editor, included_files_editor,
@ -564,7 +572,7 @@ impl ProjectSearchView {
fn build_search_query(&mut self, cx: &mut ViewContext<Self>) -> Option<SearchQuery> { fn build_search_query(&mut self, cx: &mut ViewContext<Self>) -> Option<SearchQuery> {
let text = self.query_editor.read(cx).text(cx); let text = self.query_editor.read(cx).text(cx);
let Ok(included_files) = self let included_files = match self
.included_files_editor .included_files_editor
.read(cx) .read(cx)
.text(cx) .text(cx)
@ -572,12 +580,19 @@ impl ProjectSearchView {
.map(str::trim) .map(str::trim)
.filter(|glob_str| !glob_str.is_empty()) .filter(|glob_str| !glob_str.is_empty())
.map(|glob_str| glob::Pattern::new(glob_str)) .map(|glob_str| glob::Pattern::new(glob_str))
.collect::<Result<_, _>>() else { .collect::<Result<_, _>>()
self.query_contains_error = true; {
Ok(included_files) => {
self.panels_with_errors.remove(&InputPanel::Include);
included_files
}
Err(_e) => {
self.panels_with_errors.insert(InputPanel::Include);
cx.notify(); cx.notify();
return None return None;
}; }
let Ok(excluded_files) = self };
let excluded_files = match self
.excluded_files_editor .excluded_files_editor
.read(cx) .read(cx)
.text(cx) .text(cx)
@ -585,11 +600,18 @@ impl ProjectSearchView {
.map(str::trim) .map(str::trim)
.filter(|glob_str| !glob_str.is_empty()) .filter(|glob_str| !glob_str.is_empty())
.map(|glob_str| glob::Pattern::new(glob_str)) .map(|glob_str| glob::Pattern::new(glob_str))
.collect::<Result<_, _>>() else { .collect::<Result<_, _>>()
self.query_contains_error = true; {
Ok(excluded_files) => {
self.panels_with_errors.remove(&InputPanel::Exclude);
excluded_files
}
Err(_e) => {
self.panels_with_errors.insert(InputPanel::Exclude);
cx.notify(); cx.notify();
return None return None;
}; }
};
if self.regex { if self.regex {
match SearchQuery::regex( match SearchQuery::regex(
text, text,
@ -598,9 +620,12 @@ impl ProjectSearchView {
included_files, included_files,
excluded_files, excluded_files,
) { ) {
Ok(query) => Some(query), Ok(query) => {
Err(_) => { self.panels_with_errors.remove(&InputPanel::Query);
self.query_contains_error = true; Some(query)
}
Err(_e) => {
self.panels_with_errors.insert(InputPanel::Query);
cx.notify(); cx.notify();
None None
} }
@ -968,11 +993,23 @@ impl View for ProjectSearchBar {
if let Some(search) = self.active_project_search.as_ref() { if let Some(search) = self.active_project_search.as_ref() {
let search = search.read(cx); let search = search.read(cx);
let theme = cx.global::<Settings>().theme.clone(); let theme = cx.global::<Settings>().theme.clone();
let editor_container = if search.query_contains_error { let query_container_style = if search.panels_with_errors.contains(&InputPanel::Query) {
theme.search.invalid_editor theme.search.invalid_editor
} else { } else {
theme.search.editor.input.container theme.search.editor.input.container
}; };
let include_container_style =
if search.panels_with_errors.contains(&InputPanel::Include) {
theme.search.invalid_include_exclude_editor
} else {
theme.search.include_exclude_editor.input.container
};
let exclude_container_style =
if search.panels_with_errors.contains(&InputPanel::Exclude) {
theme.search.invalid_include_exclude_editor
} else {
theme.search.include_exclude_editor.input.container
};
let included_files_view = ChildView::new(&search.included_files_editor, cx) let included_files_view = ChildView::new(&search.included_files_editor, cx)
.aligned() .aligned()
@ -1010,7 +1047,7 @@ impl View for ProjectSearchBar {
.aligned() .aligned()
})) }))
.contained() .contained()
.with_style(editor_container) .with_style(query_container_style)
.aligned() .aligned()
.constrained() .constrained()
.with_min_width(theme.search.editor.min_width) .with_min_width(theme.search.editor.min_width)
@ -1053,7 +1090,7 @@ impl View for ProjectSearchBar {
Flex::row() Flex::row()
.with_child(included_files_view) .with_child(included_files_view)
.contained() .contained()
.with_style(theme.search.include_exclude_editor.input.container) .with_style(include_container_style)
.aligned() .aligned()
.constrained() .constrained()
.with_min_width(theme.search.include_exclude_editor.min_width) .with_min_width(theme.search.include_exclude_editor.min_width)
@ -1064,7 +1101,7 @@ impl View for ProjectSearchBar {
Flex::row() Flex::row()
.with_child(excluded_files_view) .with_child(excluded_files_view)
.contained() .contained()
.with_style(theme.search.include_exclude_editor.input.container) .with_style(exclude_container_style)
.aligned() .aligned()
.constrained() .constrained()
.with_min_width(theme.search.include_exclude_editor.min_width) .with_min_width(theme.search.include_exclude_editor.min_width)

View File

@ -320,6 +320,7 @@ pub struct Search {
pub invalid_editor: ContainerStyle, pub invalid_editor: ContainerStyle,
pub option_button_group: ContainerStyle, pub option_button_group: ContainerStyle,
pub include_exclude_editor: FindEditor, pub include_exclude_editor: FindEditor,
pub invalid_include_exclude_editor: ContainerStyle,
pub include_exclude_inputs: ContainedText, pub include_exclude_inputs: ContainedText,
pub option_button: Interactive<ContainedText>, pub option_button: Interactive<ContainedText>,
pub match_background: Color, pub match_background: Color,

View File

@ -26,6 +26,12 @@ export default function search(colorScheme: ColorScheme) {
}, },
} }
const includeExcludeEditor = {
...editor,
minWidth: 100,
maxWidth: 250,
};
return { return {
// TODO: Add an activeMatchBackground on the rust side to differenciate between active and inactive // TODO: Add an activeMatchBackground on the rust side to differenciate between active and inactive
matchBackground: withOpacity(foreground(layer, "accent"), 0.4), matchBackground: withOpacity(foreground(layer, "accent"), 0.4),
@ -64,10 +70,10 @@ export default function search(colorScheme: ColorScheme) {
...editor, ...editor,
border: border(layer, "negative"), border: border(layer, "negative"),
}, },
includeExcludeEditor: { includeExcludeEditor,
...editor, invalidIncludeExcludeEditor: {
minWidth: 100, ...includeExcludeEditor,
maxWidth: 250, border: border(layer, "negative"),
}, },
matchIndex: { matchIndex: {
...text(layer, "mono", "variant"), ...text(layer, "mono", "variant"),