Render query text red in project search if no results are found
This commit is contained in:
parent
e354159f77
commit
bce501c696
3 changed files with 147 additions and 172 deletions
|
@ -4,20 +4,20 @@ use crate::{
|
||||||
FocusSearch, NextHistoryQuery, PreviousHistoryQuery, ReplaceAll, ReplaceNext, SearchOptions,
|
FocusSearch, NextHistoryQuery, PreviousHistoryQuery, ReplaceAll, ReplaceNext, SearchOptions,
|
||||||
SelectAllMatches, SelectNextMatch, SelectPreviousMatch, ToggleCaseSensitive, ToggleRegex,
|
SelectAllMatches, SelectNextMatch, SelectPreviousMatch, ToggleCaseSensitive, ToggleRegex,
|
||||||
ToggleReplace, ToggleSelection, ToggleWholeWord,
|
ToggleReplace, ToggleSelection, ToggleWholeWord,
|
||||||
search_bar::{input_base_styles, render_nav_button, toggle_replace_button},
|
search_bar::{input_base_styles, render_nav_button, render_text_input, toggle_replace_button},
|
||||||
};
|
};
|
||||||
use any_vec::AnyVec;
|
use any_vec::AnyVec;
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use editor::{
|
use editor::{
|
||||||
DisplayPoint, Editor, EditorElement, EditorSettings, EditorStyle,
|
DisplayPoint, Editor, EditorSettings,
|
||||||
actions::{Backtab, Tab},
|
actions::{Backtab, Tab},
|
||||||
};
|
};
|
||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
Action, App, ClickEvent, Context, Entity, EventEmitter, FocusHandle, Focusable,
|
Action, App, ClickEvent, Context, Entity, EventEmitter, FocusHandle, Focusable,
|
||||||
InteractiveElement as _, IntoElement, KeyContext, ParentElement as _, Render, ScrollHandle,
|
InteractiveElement as _, IntoElement, KeyContext, ParentElement as _, Render, ScrollHandle,
|
||||||
Styled, Subscription, Task, TextStyle, Window, actions, div,
|
Styled, Subscription, Task, Window, actions, div,
|
||||||
};
|
};
|
||||||
use language::{Language, LanguageRegistry};
|
use language::{Language, LanguageRegistry};
|
||||||
use project::{
|
use project::{
|
||||||
|
@ -28,7 +28,6 @@ use schemars::JsonSchema;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use theme::ThemeSettings;
|
|
||||||
use zed_actions::outline::ToggleOutline;
|
use zed_actions::outline::ToggleOutline;
|
||||||
|
|
||||||
use ui::{
|
use ui::{
|
||||||
|
@ -126,46 +125,6 @@ pub struct BufferSearchBar {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BufferSearchBar {
|
impl BufferSearchBar {
|
||||||
fn render_text_input(
|
|
||||||
&self,
|
|
||||||
editor: &Entity<Editor>,
|
|
||||||
color_override: Option<Color>,
|
|
||||||
cx: &mut Context<Self>,
|
|
||||||
) -> impl IntoElement {
|
|
||||||
let (color, use_syntax) = if editor.read(cx).read_only(cx) {
|
|
||||||
(cx.theme().colors().text_disabled, false)
|
|
||||||
} else {
|
|
||||||
match color_override {
|
|
||||||
Some(color_override) => (color_override.color(cx), false),
|
|
||||||
None => (cx.theme().colors().text, true),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let settings = ThemeSettings::get_global(cx);
|
|
||||||
let text_style = TextStyle {
|
|
||||||
color,
|
|
||||||
font_family: settings.buffer_font.family.clone(),
|
|
||||||
font_features: settings.buffer_font.features.clone(),
|
|
||||||
font_fallbacks: settings.buffer_font.fallbacks.clone(),
|
|
||||||
font_size: rems(0.875).into(),
|
|
||||||
font_weight: settings.buffer_font.weight,
|
|
||||||
line_height: relative(1.3),
|
|
||||||
..TextStyle::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut editor_style = EditorStyle {
|
|
||||||
background: cx.theme().colors().toolbar_background,
|
|
||||||
local_player: cx.theme().players().local(),
|
|
||||||
text: text_style,
|
|
||||||
..EditorStyle::default()
|
|
||||||
};
|
|
||||||
if use_syntax {
|
|
||||||
editor_style.syntax = cx.theme().syntax().clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorElement::new(editor, editor_style)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn query_editor_focused(&self) -> bool {
|
pub fn query_editor_focused(&self) -> bool {
|
||||||
self.query_editor_focused
|
self.query_editor_focused
|
||||||
}
|
}
|
||||||
|
@ -251,13 +210,13 @@ impl Render for BufferSearchBar {
|
||||||
input_base_styles(query_border)
|
input_base_styles(query_border)
|
||||||
.id("editor-scroll")
|
.id("editor-scroll")
|
||||||
.track_scroll(&self.editor_scroll_handle)
|
.track_scroll(&self.editor_scroll_handle)
|
||||||
.child(self.render_text_input(&self.query_editor, color_override, cx))
|
.child(render_text_input(&self.query_editor, color_override, cx))
|
||||||
.when(!hide_inline_icons, |div| {
|
.when(!hide_inline_icons, |div| {
|
||||||
div.child(
|
div.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.gap_1()
|
.gap_1()
|
||||||
.children(supported_options.case.then(|| {
|
.when(supported_options.case, |div| {
|
||||||
self.render_search_option_button(
|
div.child(self.render_search_option_button(
|
||||||
SearchOptions::CASE_SENSITIVE,
|
SearchOptions::CASE_SENSITIVE,
|
||||||
focus_handle.clone(),
|
focus_handle.clone(),
|
||||||
cx.listener(|this, _, window, cx| {
|
cx.listener(|this, _, window, cx| {
|
||||||
|
@ -267,26 +226,26 @@ impl Render for BufferSearchBar {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
)
|
))
|
||||||
}))
|
})
|
||||||
.children(supported_options.word.then(|| {
|
.when(supported_options.word, |div| {
|
||||||
self.render_search_option_button(
|
div.child(self.render_search_option_button(
|
||||||
SearchOptions::WHOLE_WORD,
|
SearchOptions::WHOLE_WORD,
|
||||||
focus_handle.clone(),
|
focus_handle.clone(),
|
||||||
cx.listener(|this, _, window, cx| {
|
cx.listener(|this, _, window, cx| {
|
||||||
this.toggle_whole_word(&ToggleWholeWord, window, cx)
|
this.toggle_whole_word(&ToggleWholeWord, window, cx)
|
||||||
}),
|
}),
|
||||||
)
|
))
|
||||||
}))
|
})
|
||||||
.children(supported_options.regex.then(|| {
|
.when(supported_options.regex, |div| {
|
||||||
self.render_search_option_button(
|
div.child(self.render_search_option_button(
|
||||||
SearchOptions::REGEX,
|
SearchOptions::REGEX,
|
||||||
focus_handle.clone(),
|
focus_handle.clone(),
|
||||||
cx.listener(|this, _, window, cx| {
|
cx.listener(|this, _, window, cx| {
|
||||||
this.toggle_regex(&ToggleRegex, window, cx)
|
this.toggle_regex(&ToggleRegex, window, cx)
|
||||||
}),
|
}),
|
||||||
)
|
))
|
||||||
})),
|
}),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
@ -404,7 +363,7 @@ impl Render for BufferSearchBar {
|
||||||
h_flex()
|
h_flex()
|
||||||
.gap_2()
|
.gap_2()
|
||||||
.child(
|
.child(
|
||||||
input_base_styles(replacement_border).child(self.render_text_input(
|
input_base_styles(replacement_border).child(render_text_input(
|
||||||
&self.replacement_editor,
|
&self.replacement_editor,
|
||||||
None,
|
None,
|
||||||
cx,
|
cx,
|
||||||
|
|
|
@ -3,20 +3,20 @@ use crate::{
|
||||||
SearchOptions, SelectNextMatch, SelectPreviousMatch, ToggleCaseSensitive, ToggleIncludeIgnored,
|
SearchOptions, SelectNextMatch, SelectPreviousMatch, ToggleCaseSensitive, ToggleIncludeIgnored,
|
||||||
ToggleRegex, ToggleReplace, ToggleWholeWord,
|
ToggleRegex, ToggleReplace, ToggleWholeWord,
|
||||||
buffer_search::Deploy,
|
buffer_search::Deploy,
|
||||||
search_bar::{input_base_styles, toggle_replace_button},
|
search_bar::{input_base_styles, render_text_input, toggle_replace_button},
|
||||||
};
|
};
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
use editor::{
|
use editor::{
|
||||||
Anchor, Editor, EditorElement, EditorEvent, EditorSettings, EditorStyle, MAX_TAB_TITLE_LEN,
|
Anchor, Editor, EditorEvent, EditorSettings, MAX_TAB_TITLE_LEN, MultiBuffer, SelectionEffects,
|
||||||
MultiBuffer, SelectionEffects, actions::SelectAll, items::active_match_index,
|
actions::SelectAll, items::active_match_index,
|
||||||
};
|
};
|
||||||
use futures::{StreamExt, stream::FuturesOrdered};
|
use futures::{StreamExt, stream::FuturesOrdered};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
Action, AnyElement, AnyView, App, Axis, Context, Entity, EntityId, EventEmitter, FocusHandle,
|
Action, AnyElement, AnyView, App, Axis, Context, Entity, EntityId, EventEmitter, FocusHandle,
|
||||||
Focusable, Global, Hsla, InteractiveElement, IntoElement, KeyContext, ParentElement, Point,
|
Focusable, Global, Hsla, InteractiveElement, IntoElement, KeyContext, ParentElement, Point,
|
||||||
Render, SharedString, Styled, Subscription, Task, TextStyle, UpdateGlobal, WeakEntity, Window,
|
Render, SharedString, Styled, Subscription, Task, UpdateGlobal, WeakEntity, Window, actions,
|
||||||
actions, div,
|
div,
|
||||||
};
|
};
|
||||||
use language::{Buffer, Language};
|
use language::{Buffer, Language};
|
||||||
use menu::Confirm;
|
use menu::Confirm;
|
||||||
|
@ -34,7 +34,6 @@ use std::{
|
||||||
pin::pin,
|
pin::pin,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use theme::ThemeSettings;
|
|
||||||
use ui::{
|
use ui::{
|
||||||
Icon, IconButton, IconButtonShape, IconName, KeyBinding, Label, LabelCommon, LabelSize,
|
Icon, IconButton, IconButtonShape, IconName, KeyBinding, Label, LabelCommon, LabelSize,
|
||||||
Toggleable, Tooltip, h_flex, prelude::*, utils::SearchInputWidth, v_flex,
|
Toggleable, Tooltip, h_flex, prelude::*, utils::SearchInputWidth, v_flex,
|
||||||
|
@ -1917,37 +1916,6 @@ impl ProjectSearchBar {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_text_input(&self, editor: &Entity<Editor>, cx: &Context<Self>) -> impl IntoElement {
|
|
||||||
let (color, use_syntax) = if editor.read(cx).read_only(cx) {
|
|
||||||
(cx.theme().colors().text_disabled, false)
|
|
||||||
} else {
|
|
||||||
(cx.theme().colors().text, true)
|
|
||||||
};
|
|
||||||
let settings = ThemeSettings::get_global(cx);
|
|
||||||
let text_style = TextStyle {
|
|
||||||
color,
|
|
||||||
font_family: settings.buffer_font.family.clone(),
|
|
||||||
font_features: settings.buffer_font.features.clone(),
|
|
||||||
font_fallbacks: settings.buffer_font.fallbacks.clone(),
|
|
||||||
font_size: rems(0.875).into(),
|
|
||||||
font_weight: settings.buffer_font.weight,
|
|
||||||
line_height: relative(1.3),
|
|
||||||
..TextStyle::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut editor_style = EditorStyle {
|
|
||||||
background: cx.theme().colors().toolbar_background,
|
|
||||||
local_player: cx.theme().players().local(),
|
|
||||||
text: text_style,
|
|
||||||
..EditorStyle::default()
|
|
||||||
};
|
|
||||||
if use_syntax {
|
|
||||||
editor_style.syntax = cx.theme().syntax().clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorElement::new(editor, editor_style)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for ProjectSearchBar {
|
impl Render for ProjectSearchBar {
|
||||||
|
@ -1973,6 +1941,35 @@ impl Render for ProjectSearchBar {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let project_search = search.entity.read(cx);
|
||||||
|
let limit_reached = project_search.limit_reached;
|
||||||
|
|
||||||
|
let color_override = match (
|
||||||
|
project_search.no_results,
|
||||||
|
&project_search.active_query,
|
||||||
|
&project_search.last_search_query_text,
|
||||||
|
) {
|
||||||
|
(Some(true), Some(q), Some(p)) if q.as_str() == p => Some(Color::Error),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
let match_text = search
|
||||||
|
.active_match_index
|
||||||
|
.and_then(|index| {
|
||||||
|
let index = index + 1;
|
||||||
|
let match_quantity = project_search.match_ranges.len();
|
||||||
|
if match_quantity > 0 {
|
||||||
|
debug_assert!(match_quantity >= index);
|
||||||
|
if limit_reached {
|
||||||
|
Some(format!("{index}/{match_quantity}+"))
|
||||||
|
} else {
|
||||||
|
Some(format!("{index}/{match_quantity}"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| "0/0".to_string());
|
||||||
|
|
||||||
let query_column = input_base_styles(BaseStyle::SingleInput, InputPanel::Query)
|
let query_column = input_base_styles(BaseStyle::SingleInput, InputPanel::Query)
|
||||||
.on_action(cx.listener(|this, action, window, cx| this.confirm(action, window, cx)))
|
.on_action(cx.listener(|this, action, window, cx| this.confirm(action, window, cx)))
|
||||||
.on_action(cx.listener(|this, action, window, cx| {
|
.on_action(cx.listener(|this, action, window, cx| {
|
||||||
|
@ -1981,7 +1978,7 @@ impl Render for ProjectSearchBar {
|
||||||
.on_action(
|
.on_action(
|
||||||
cx.listener(|this, action, window, cx| this.next_history_query(action, window, cx)),
|
cx.listener(|this, action, window, cx| this.next_history_query(action, window, cx)),
|
||||||
)
|
)
|
||||||
.child(self.render_text_input(&search.query_editor, cx))
|
.child(render_text_input(&search.query_editor, color_override, cx))
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.gap_1()
|
.gap_1()
|
||||||
|
@ -2050,26 +2047,6 @@ impl Render for ProjectSearchBar {
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
|
|
||||||
let limit_reached = search.entity.read(cx).limit_reached;
|
|
||||||
|
|
||||||
let match_text = search
|
|
||||||
.active_match_index
|
|
||||||
.and_then(|index| {
|
|
||||||
let index = index + 1;
|
|
||||||
let match_quantity = search.entity.read(cx).match_ranges.len();
|
|
||||||
if match_quantity > 0 {
|
|
||||||
debug_assert!(match_quantity >= index);
|
|
||||||
if limit_reached {
|
|
||||||
Some(format!("{index}/{match_quantity}+"))
|
|
||||||
} else {
|
|
||||||
Some(format!("{index}/{match_quantity}"))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| "0/0".to_string());
|
|
||||||
|
|
||||||
let matches_column = h_flex()
|
let matches_column = h_flex()
|
||||||
.pl_2()
|
.pl_2()
|
||||||
.ml_2()
|
.ml_2()
|
||||||
|
@ -2149,16 +2126,14 @@ impl Render for ProjectSearchBar {
|
||||||
|
|
||||||
let replace_line = search.replace_enabled.then(|| {
|
let replace_line = search.replace_enabled.then(|| {
|
||||||
let replace_column = input_base_styles(BaseStyle::SingleInput, InputPanel::Replacement)
|
let replace_column = input_base_styles(BaseStyle::SingleInput, InputPanel::Replacement)
|
||||||
.child(self.render_text_input(&search.replacement_editor, cx));
|
.child(render_text_input(&search.replacement_editor, None, cx));
|
||||||
|
|
||||||
let focus_handle = search.replacement_editor.read(cx).focus_handle(cx);
|
let focus_handle = search.replacement_editor.read(cx).focus_handle(cx);
|
||||||
|
|
||||||
let replace_actions =
|
let replace_actions = h_flex()
|
||||||
h_flex()
|
|
||||||
.min_w_64()
|
.min_w_64()
|
||||||
.gap_1()
|
.gap_1()
|
||||||
.when(search.replace_enabled, |this| {
|
.child(
|
||||||
this.child(
|
|
||||||
IconButton::new("project-search-replace-next", IconName::ReplaceNext)
|
IconButton::new("project-search-replace-next", IconName::ReplaceNext)
|
||||||
.shape(IconButtonShape::Square)
|
.shape(IconButtonShape::Square)
|
||||||
.on_click(cx.listener(|this, _, window, cx| {
|
.on_click(cx.listener(|this, _, window, cx| {
|
||||||
|
@ -2203,8 +2178,7 @@ impl Render for ProjectSearchBar {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
)
|
);
|
||||||
});
|
|
||||||
|
|
||||||
h_flex()
|
h_flex()
|
||||||
.w_full()
|
.w_full()
|
||||||
|
@ -2229,7 +2203,7 @@ impl Render for ProjectSearchBar {
|
||||||
.on_action(cx.listener(|this, action, window, cx| {
|
.on_action(cx.listener(|this, action, window, cx| {
|
||||||
this.next_history_query(action, window, cx)
|
this.next_history_query(action, window, cx)
|
||||||
}))
|
}))
|
||||||
.child(self.render_text_input(&search.included_files_editor, cx)),
|
.child(render_text_input(&search.included_files_editor, None, cx)),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
input_base_styles(BaseStyle::MultipleInputs, InputPanel::Exclude)
|
input_base_styles(BaseStyle::MultipleInputs, InputPanel::Exclude)
|
||||||
|
@ -2239,7 +2213,7 @@ impl Render for ProjectSearchBar {
|
||||||
.on_action(cx.listener(|this, action, window, cx| {
|
.on_action(cx.listener(|this, action, window, cx| {
|
||||||
this.next_history_query(action, window, cx)
|
this.next_history_query(action, window, cx)
|
||||||
}))
|
}))
|
||||||
.child(self.render_text_input(&search.excluded_files_editor, cx)),
|
.child(render_text_input(&search.excluded_files_editor, None, cx)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use gpui::{Action, FocusHandle, Hsla, IntoElement};
|
use editor::{Editor, EditorElement, EditorStyle};
|
||||||
|
use gpui::{Action, Entity, FocusHandle, Hsla, IntoElement, TextStyle};
|
||||||
|
use settings::Settings;
|
||||||
|
use theme::ThemeSettings;
|
||||||
use ui::{IconButton, IconButtonShape};
|
use ui::{IconButton, IconButtonShape};
|
||||||
use ui::{Tooltip, prelude::*};
|
use ui::{Tooltip, prelude::*};
|
||||||
|
|
||||||
|
@ -60,3 +63,42 @@ pub(crate) fn toggle_replace_button(
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn render_text_input(
|
||||||
|
editor: &Entity<Editor>,
|
||||||
|
color_override: Option<Color>,
|
||||||
|
app: &App,
|
||||||
|
) -> impl IntoElement {
|
||||||
|
let (color, use_syntax) = if editor.read(app).read_only(app) {
|
||||||
|
(app.theme().colors().text_disabled, false)
|
||||||
|
} else {
|
||||||
|
match color_override {
|
||||||
|
Some(color_override) => (color_override.color(app), false),
|
||||||
|
None => (app.theme().colors().text, true),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let settings = ThemeSettings::get_global(app);
|
||||||
|
let text_style = TextStyle {
|
||||||
|
color,
|
||||||
|
font_family: settings.buffer_font.family.clone(),
|
||||||
|
font_features: settings.buffer_font.features.clone(),
|
||||||
|
font_fallbacks: settings.buffer_font.fallbacks.clone(),
|
||||||
|
font_size: rems(0.875).into(),
|
||||||
|
font_weight: settings.buffer_font.weight,
|
||||||
|
line_height: relative(1.3),
|
||||||
|
..TextStyle::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut editor_style = EditorStyle {
|
||||||
|
background: app.theme().colors().toolbar_background,
|
||||||
|
local_player: app.theme().players().local(),
|
||||||
|
text: text_style,
|
||||||
|
..EditorStyle::default()
|
||||||
|
};
|
||||||
|
if use_syntax {
|
||||||
|
editor_style.syntax = app.theme().syntax().clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorElement::new(editor, editor_style)
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue