Merge branch 'main' into focus-handlers-on-draw

This commit is contained in:
Julia 2023-12-14 23:08:23 -05:00
commit 4be84f3db0
108 changed files with 4470 additions and 3168 deletions

View file

@ -23,7 +23,7 @@ use util::ResultExt;
use workspace::{
item::ItemHandle,
searchable::{Direction, SearchEvent, SearchableItemHandle, WeakSearchableItemHandle},
ToolbarItemLocation, ToolbarItemView, Workspace,
ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace,
};
#[derive(PartialEq, Clone, Deserialize)]
@ -456,6 +456,9 @@ impl BufferSearchBar {
cx.focus(&handle);
}
cx.emit(Event::UpdateLocation);
cx.emit(ToolbarItemEvent::ChangeLocation(
ToolbarItemLocation::Hidden,
));
cx.notify();
}
@ -488,6 +491,9 @@ impl BufferSearchBar {
self.dismissed = false;
cx.notify();
cx.emit(Event::UpdateLocation);
cx.emit(ToolbarItemEvent::ChangeLocation(
ToolbarItemLocation::Secondary,
));
true
}

View file

@ -10,11 +10,13 @@ use editor::{
items::active_match_index, scroll::autoscroll::Autoscroll, Anchor, Editor, EditorEvent,
MultiBuffer, SelectAll, MAX_TAB_TITLE_LEN,
};
use editor::{EditorElement, EditorStyle};
use gpui::{
actions, div, white, AnyElement, AnyView, AppContext, Context as _, Div, Element, EntityId,
EventEmitter, FocusableView, InteractiveElement, IntoElement, KeyContext, Model, ModelContext,
ParentElement, PromptLevel, Render, SharedString, Styled, Subscription, Task, View,
ViewContext, VisualContext, WeakModel, WeakView, WindowContext,
actions, div, AnyElement, AnyView, AppContext, Context as _, Div, Element, EntityId,
EventEmitter, FocusableView, FontStyle, FontWeight, 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::{
@ -23,6 +25,7 @@ use project::{
};
use semantic_index::{SemanticIndex, SemanticIndexStatus};
use settings::Settings;
use smol::stream::StreamExt;
use std::{
any::{Any, TypeId},
@ -32,6 +35,7 @@ use std::{
path::PathBuf,
time::{Duration, Instant},
};
use theme::ThemeSettings;
use ui::{
h_stack, prelude::*, v_stack, Button, Icon, IconButton, IconElement, Label, LabelCommon,
@ -425,7 +429,12 @@ impl Item for ProjectSearchView {
.filter(|query| !query.is_empty())
.unwrap_or_else(|| "Project search".into());
h_stack()
.child(IconElement::new(Icon::MagnifyingGlass))
.gap_2()
.child(IconElement::new(Icon::MagnifyingGlass).color(if selected {
Color::Default
} else {
Color::Muted
}))
.child(Label::new(tab_name).color(if selected {
Color::Default
} else {
@ -1428,6 +1437,36 @@ impl ProjectSearchBar {
};
new_placeholder_text
}
fn render_text_input(&self, editor: &View<Editor>, cx: &ViewContext<Self>) -> impl IntoElement {
let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle {
color: if editor.read(cx).read_only() {
cx.theme().colors().text_disabled
} else {
cx.theme().colors().text
},
font_family: settings.ui_font.family.clone(),
font_features: settings.ui_font.features,
font_size: rems(0.875).into(),
font_weight: FontWeight::NORMAL,
font_style: FontStyle::Normal,
line_height: relative(1.3).into(),
background_color: None,
underline: None,
white_space: WhiteSpace::Normal,
};
EditorElement::new(
&editor,
EditorStyle {
background: cx.theme().colors().editor_background,
local_player: cx.theme().players().local(),
text: text_style,
..Default::default()
},
)
}
}
impl Render for ProjectSearchBar {
@ -1448,122 +1487,62 @@ impl Render for ProjectSearchBar {
}
let search = search.read(cx);
let semantic_is_available = SemanticIndex::enabled(cx);
let query_column = v_stack()
//.flex_1()
.child(
h_stack()
.min_w_80()
.on_action(cx.listener(|this, action, cx| this.confirm(action, cx)))
.on_action(
cx.listener(|this, action, cx| this.previous_history_query(action, cx)),
)
.on_action(cx.listener(|this, action, cx| this.next_history_query(action, cx)))
.child(IconElement::new(Icon::MagnifyingGlass))
.child(search.query_editor.clone())
.child(
h_stack()
.child(
IconButton::new("project-search-filter-button", Icon::Filter)
.tooltip(|cx| {
Tooltip::for_action("Toggle filters", &ToggleFilters, cx)
})
.on_click(cx.listener(|this, _, cx| {
this.toggle_filters(cx);
}))
.selected(
self.active_project_search
.as_ref()
.map(|search| search.read(cx).filters_enabled)
.unwrap_or_default(),
),
)
.when(search.current_mode != SearchMode::Semantic, |this| {
this.child(
IconButton::new(
"project-search-case-sensitive",
Icon::CaseSensitive,
)
.tooltip(|cx| {
Tooltip::for_action(
"Toggle case sensitive",
&ToggleCaseSensitive,
cx,
)
})
.selected(
self.is_option_enabled(SearchOptions::CASE_SENSITIVE, cx),
)
.on_click(cx.listener(
|this, _, cx| {
this.toggle_search_option(
SearchOptions::CASE_SENSITIVE,
cx,
);
},
)),
)
.child(
IconButton::new("project-search-whole-word", Icon::WholeWord)
.tooltip(|cx| {
Tooltip::for_action(
"Toggle whole word",
&ToggleWholeWord,
cx,
)
})
.selected(
self.is_option_enabled(SearchOptions::WHOLE_WORD, cx),
)
.on_click(cx.listener(|this, _, cx| {
this.toggle_search_option(
SearchOptions::WHOLE_WORD,
cx,
);
})),
)
}),
)
.border_2()
.bg(white())
.rounded_lg(),
)
.when(search.filters_enabled, |this| {
this.child(
let query_column = v_stack().child(
h_stack()
.min_w(rems(512. / 16.))
.px_2()
.py_1()
.gap_2()
.bg(cx.theme().colors().editor_background)
.border_1()
.border_color(cx.theme().colors().border)
.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)))
.on_action(cx.listener(|this, action, cx| this.next_history_query(action, cx)))
.child(IconElement::new(Icon::MagnifyingGlass))
.child(self.render_text_input(&search.query_editor, cx))
.child(
h_stack()
.mt_2()
.flex_1()
.justify_between()
.child(
h_stack()
.flex_1()
.border_1()
.mr_2()
.child(search.included_files_editor.clone())
.when(search.current_mode != SearchMode::Semantic, |this| {
this.child(
SearchOptions::INCLUDE_IGNORED.as_button(
search
.search_options
.contains(SearchOptions::INCLUDE_IGNORED),
cx.listener(|this, _, cx| {
this.toggle_search_option(
SearchOptions::INCLUDE_IGNORED,
cx,
);
}),
),
)
}),
IconButton::new("project-search-filter-button", Icon::Filter)
.tooltip(|cx| {
Tooltip::for_action("Toggle filters", &ToggleFilters, cx)
})
.on_click(cx.listener(|this, _, cx| {
this.toggle_filters(cx);
}))
.selected(
self.active_project_search
.as_ref()
.map(|search| search.read(cx).filters_enabled)
.unwrap_or_default(),
),
)
.child(
h_stack()
.flex_1()
.border_1()
.ml_2()
.child(search.excluded_files_editor.clone()),
),
)
});
.when(search.current_mode != SearchMode::Semantic, |this| {
this.child(
IconButton::new(
"project-search-case-sensitive",
Icon::CaseSensitive,
)
.tooltip(|cx| {
Tooltip::for_action(
"Toggle case sensitive",
&ToggleCaseSensitive,
cx,
)
})
.selected(self.is_option_enabled(SearchOptions::WHOLE_WORD, cx))
.on_click(cx.listener(
|this, _, cx| {
this.toggle_search_option(SearchOptions::WHOLE_WORD, cx);
},
)),
)
}),
),
);
let mode_column = v_stack().items_start().justify_start().child(
h_stack()
.child(
@ -1619,12 +1598,16 @@ impl Render for ProjectSearchBar {
);
let replace_column = if search.replace_enabled {
h_stack()
.p_1()
.flex_1()
.border_2()
.h_full()
.gap_2()
.px_2()
.py_1()
.border_1()
.border_color(cx.theme().colors().border)
.rounded_lg()
.child(IconElement::new(Icon::Replace).size(ui::IconSize::Small))
.child(search.replacement_editor.clone())
.child(self.render_text_input(&search.replacement_editor, cx))
} else {
// Fill out the space if we don't have a replacement editor.
h_stack().flex_1()
@ -1685,12 +1668,12 @@ impl Render for ProjectSearchBar {
}))
.tooltip(|cx| Tooltip::for_action("Go to next match", &SelectNextMatch, cx)),
]);
h_stack()
v_stack()
.key_context(key_context)
.size_full()
.flex_grow()
.p_1()
.m_2()
.justify_between()
.gap_2()
.on_action(cx.listener(|this, _: &ToggleFilters, cx| {
this.toggle_filters(cx);
}))
@ -1742,10 +1725,59 @@ impl Render for ProjectSearchBar {
}))
})
})
.child(query_column)
.child(mode_column)
.child(replace_column)
.child(actions_column)
.child(
h_stack()
.justify_between()
.child(query_column)
.child(mode_column)
.child(replace_column)
.child(actions_column),
)
.when(search.filters_enabled, |this| {
this.child(
h_stack()
.flex_1()
.gap_2()
.justify_between()
.child(
h_stack()
.flex_1()
.h_full()
.px_2()
.py_1()
.border_1()
.border_color(cx.theme().colors().border)
.rounded_lg()
.child(self.render_text_input(&search.included_files_editor, cx))
.when(search.current_mode != SearchMode::Semantic, |this| {
this.child(
SearchOptions::INCLUDE_IGNORED.as_button(
search
.search_options
.contains(SearchOptions::INCLUDE_IGNORED),
cx.listener(|this, _, cx| {
this.toggle_search_option(
SearchOptions::INCLUDE_IGNORED,
cx,
);
}),
),
)
}),
)
.child(
h_stack()
.flex_1()
.h_full()
.px_2()
.py_1()
.border_1()
.border_color(cx.theme().colors().border)
.rounded_lg()
.child(self.render_text_input(&search.excluded_files_editor, cx)),
),
)
})
}
}
// impl Entity for ProjectSearchBar {