History

Project search bar layout improvements (#7963)

The PR matches project search layout with the recent changes in the buffer project layout. https://github.com/zed-industries/zed/assets/2101250/91b905ea-aed8-4740-9e60-67f3052885e2 Release Notes: - Improve project search bar layout, match it with the buffer search bar ([7722](https://github.com/zed-industries/zed/issues/7722))

Andrew Lygin committed 2 years ago

Commit f7d2cb11 parent 78dcd722 files · +173 −176Browse files

Unified · Split

2 files
  1. crates/search/src/buffer_search.rs +1 −2
  2. crates/search/src/project_search.rs +172 −174
crates/search/src/buffer_search.rs+1−2
@@ -38,7 +38,7 @@ pub use registrar::DivRegistrar; · 37 unmodified lines
3838 use registrar::{ForDeployed, ForDismissed, SearchActionsRegistrar, WithResults};
3939
4040 const MIN_INPUT_WIDTH_REMS: f32 = 15.;
41−const MAX_INPUT_WIDTH_REMS: f32 = 25.;
41+const MAX_INPUT_WIDTH_REMS: f32 = 30.;
4242
4343 #[derive(PartialEq, Clone, Deserialize)]
4444 pub struct Deploy {
@@ -217,7 +217,6 @@ impl Render for BufferSearchBar { · 172 unmodified lines
217217 .flex_1()
218218 .px_2()
219219 .py_1()
220− .gap_2()
221220 .border_1()
222221 .border_color(editor_border)
223222 .min_w(rems(MIN_INPUT_WIDTH_REMS))
crates/search/src/project_search.rs+172−174
@@ -50,6 +50,9 @@ use workspace::{ · 49 unmodified lines
5050 WorkspaceId,
5151 };
5252
53+const MIN_INPUT_WIDTH_REMS: f32 = 15.;
54+const MAX_INPUT_WIDTH_REMS: f32 = 30.;
55+
5356 actions!(
5457 project_search,
5558 [SearchInNew, ToggleFocus, NextField, ToggleFilters]
@@ -1409,25 +1412,22 @@ impl ProjectSearchBar { · 1353 unmodified lines
14091412
14101413 active_project_search.update(cx, |project_view, cx| {
14111414 let mut views = vec![&project_view.query_editor];
1415+ if project_view.replace_enabled {
1416+ views.push(&project_view.replacement_editor);
1417+ }
14121418 if project_view.filters_enabled {
14131419 views.extend([
14141420 &project_view.included_files_editor,
14151421 &project_view.excluded_files_editor,
14161422 ]);
14171423 }
1418− if project_view.replace_enabled {
1419− views.push(&project_view.replacement_editor);
1420− }
14211424 let current_index = match views
14221425 .iter()
14231426 .enumerate()
14241427 .find(|(_, view)| view.focus_handle(cx).is_focused(cx))
14251428 {
14261429 Some((index, _)) => index,
1427−
1428− None => {
1429− return;
1430− }
1430+ None => return,
14311431 };
14321432
14331433 let new_index = match direction {
@@ -1665,78 +1665,64 @@ impl Render for ProjectSearchBar { · 231 unmodified lines
16651665 let search = search.read(cx);
16661666 let semantic_is_available = SemanticIndex::enabled(cx);
16671667
1668− let query_column = v_flex().child(
1669− h_flex()
1670− .min_w(rems(512. / 16.))
1671− .px_2()
1672− .py_1()
1673− .gap_2()
1674− .bg(cx.theme().colors().editor_background)
1675− .border_1()
1676− .border_color(search.border_color_for(InputPanel::Query, cx))
1677− .rounded_lg()
1678− .on_action(cx.listener(|this, action, cx| this.confirm(action, cx)))
1679− .on_action(cx.listener(|this, action, cx| this.previous_history_query(action, cx)))
1680− .on_action(cx.listener(|this, action, cx| this.next_history_query(action, cx)))
1681− .child(Icon::new(IconName::MagnifyingGlass))
1682− .child(self.render_text_input(&search.query_editor, cx))
1683− .child(
1684− h_flex()
1668+ let query_column = h_flex()
1669+ .flex_1()
1670+ .px_2()
1671+ .py_1()
1672+ .border_1()
1673+ .border_color(search.border_color_for(InputPanel::Query, cx))
1674+ .rounded_lg()
1675+ .min_w(rems(MIN_INPUT_WIDTH_REMS))
1676+ .max_w(rems(MAX_INPUT_WIDTH_REMS))
1677+ .on_action(cx.listener(|this, action, cx| this.confirm(action, cx)))
1678+ .on_action(cx.listener(|this, action, cx| this.previous_history_query(action, cx)))
1679+ .on_action(cx.listener(|this, action, cx| this.next_history_query(action, cx)))
1680+ .child(self.render_text_input(&search.query_editor, cx))
1681+ .child(
1682+ h_flex()
1683+ .child(
1684+ IconButton::new("project-search-filter-button", IconName::Filter)
1685+ .tooltip(|cx| Tooltip::for_action("Toggle filters", &ToggleFilters, cx))
1686+ .on_click(cx.listener(|this, _, cx| {
1687+ this.toggle_filters(cx);
1688+ }))
1689+ .selected(
1690+ self.active_project_search
1691+ .as_ref()
1692+ .map(|search| search.read(cx).filters_enabled)
1693+ .unwrap_or_default(),
1694+ ),
1695+ )
1696+ .when(search.current_mode != SearchMode::Semantic, |this| {
1697+ this.child(
1698+ IconButton::new(
1699+ "project-search-case-sensitive",
1700+ IconName::CaseSensitive,
1701+ )
1702+ .tooltip(|cx| {
1703+ Tooltip::for_action(
1704+ "Toggle case sensitive",
1705+ &ToggleCaseSensitive,
1706+ cx,
1707+ )
1708+ })
1709+ .selected(self.is_option_enabled(SearchOptions::CASE_SENSITIVE, cx))
1710+ .on_click(cx.listener(|this, _, cx| {
1711+ this.toggle_search_option(SearchOptions::CASE_SENSITIVE, cx);
1712+ })),
1713+ )
16851714 .child(
1686− IconButton::new("project-search-filter-button", IconName::Filter)
1715+ IconButton::new("project-search-whole-word", IconName::WholeWord)
16871716 .tooltip(|cx| {
1688− Tooltip::for_action("Toggle filters", &ToggleFilters, cx)
1717+ Tooltip::for_action("Toggle whole word", &ToggleWholeWord, cx)
16891718 })
1719+ .selected(self.is_option_enabled(SearchOptions::WHOLE_WORD, cx))
16901720 .on_click(cx.listener(|this, _, cx| {
1691− this.toggle_filters(cx);
1692− }))
1693− .selected(
1694− self.active_project_search
1695− .as_ref()
1696− .map(|search| search.read(cx).filters_enabled)
1697− .unwrap_or_default(),
1698− ),
1721+ this.toggle_search_option(SearchOptions::WHOLE_WORD, cx);
1722+ })),
16991723 )
1700− .when(search.current_mode != SearchMode::Semantic, |this| {
1701− this.child(
1702− IconButton::new(
1703− "project-search-case-sensitive",
1704− IconName::CaseSensitive,
1705− )
1706− .tooltip(|cx| {
1707− Tooltip::for_action(
1708− "Toggle case sensitive",
1709− &ToggleCaseSensitive,
1710− cx,
1711− )
1712− })
1713− .selected(self.is_option_enabled(SearchOptions::CASE_SENSITIVE, cx))
1714− .on_click(cx.listener(
1715− |this, _, cx| {
1716− this.toggle_search_option(
1717− SearchOptions::CASE_SENSITIVE,
1718− cx,
1719− );
1720− },
1721− )),
1722− )
1723− .child(
1724− IconButton::new("project-search-whole-word", IconName::WholeWord)
1725− .tooltip(|cx| {
1726− Tooltip::for_action(
1727− "Toggle whole word",
1728− &ToggleWholeWord,
1729− cx,
1730− )
1731− })
1732− .selected(self.is_option_enabled(SearchOptions::WHOLE_WORD, cx))
1733− .on_click(cx.listener(|this, _, cx| {
1734− this.toggle_search_option(SearchOptions::WHOLE_WORD, cx);
1735− })),
1736− )
1737− }),
1738− ),
1739− );
1724+ }),
1725+ );
17401726
17411727 let mode_column = v_flex().items_start().justify_start().child(
17421728 h_flex()
@@ -1807,56 +1793,23 @@ impl Render for ProjectSearchBar { · 64 unmodified lines
18071793 .tooltip(|cx| Tooltip::for_action("Toggle replace", &ToggleReplace, cx)),
18081794 ),
18091795 );
1810− let replace_column = if search.replace_enabled {
1811− h_flex()
1812− .flex_1()
1813− .h_full()
1814− .gap_2()
1815− .px_2()
1816− .py_1()
1817− .border_1()
1818− .border_color(cx.theme().colors().border)
1819− .rounded_lg()
1820− .child(Icon::new(IconName::Replace).size(ui::IconSize::Small))
1821− .child(self.render_text_input(&search.replacement_editor, cx))
1822− } else {
1823− // Fill out the space if we don't have a replacement editor.
1824− h_flex().flex_1()
1825− };
1826− let actions_column = h_flex()
1827− .when(search.replace_enabled, |this| {
1828− this.child(
1829− IconButton::new("project-search-replace-next", IconName::ReplaceNext)
1830− .on_click(cx.listener(|this, _, cx| {
1831− if let Some(search) = this.active_project_search.as_ref() {
1832− search.update(cx, |this, cx| {
1833− this.replace_next(&ReplaceNext, cx);
1834− })
1835− }
1836− }))
1837− .tooltip(|cx| Tooltip::for_action("Replace next match", &ReplaceNext, cx)),
1838− )
1839− .child(
1840− IconButton::new("project-search-replace-all", IconName::ReplaceAll)
1841− .on_click(cx.listener(|this, _, cx| {
1842− if let Some(search) = this.active_project_search.as_ref() {
1843− search.update(cx, |this, cx| {
1844− this.replace_all(&ReplaceAll, cx);
1845− })
1846− }
1847− }))
1848− .tooltip(|cx| Tooltip::for_action("Replace all matches", &ReplaceAll, cx)),
1849− )
1850− })
1851− .when_some(search.active_match_index, |mut this, index| {
1796+
1797+ let match_text = search
1798+ .active_match_index
1799+ .and_then(|index| {
18521800 let index = index + 1;
18531801 let match_quantity = search.model.read(cx).match_ranges.len();
18541802 if match_quantity > 0 {
18551803 debug_assert!(match_quantity >= index);
1856− this = this.child(Label::new(format!("{index}/{match_quantity}")))
1804+ Some(format!("{index}/{match_quantity}").to_string())
1805+ } else {
1806+ None
18571807 }
1858− this
18591808 })
1809+ .unwrap_or_else(|| "No matches".to_string());
1810+
1811+ let matches_column = h_flex()
1812+ .child(div().min_w(rems(6.)).child(Label::new(match_text)))
18601813 .child(
18611814 IconButton::new("project-search-prev-match", IconName::ChevronLeft)
18621815 .disabled(search.active_match_index.is_none())
@@ -1884,10 +1837,104 @@ impl Render for ProjectSearchBar { · 21 unmodified lines
18841837 .tooltip(|cx| Tooltip::for_action("Go to next match", &SelectNextMatch, cx)),
18851838 );
18861839
1840+ let search_line = h_flex()
1841+ .gap_2()
1842+ .flex_1()
1843+ .child(query_column)
1844+ .child(mode_column)
1845+ .child(matches_column);
1846+
1847+ let replace_line = search.replace_enabled.then(|| {
1848+ let replace_column = h_flex()
1849+ .flex_1()
1850+ .min_w(rems(MIN_INPUT_WIDTH_REMS))
1851+ .max_w(rems(MAX_INPUT_WIDTH_REMS))
1852+ .h_8()
1853+ .px_2()
1854+ .py_1()
1855+ .border_1()
1856+ .border_color(cx.theme().colors().border)
1857+ .rounded_lg()
1858+ .child(self.render_text_input(&search.replacement_editor, cx));
1859+ let replace_actions = h_flex().when(search.replace_enabled, |this| {
1860+ this.child(
1861+ IconButton::new("project-search-replace-next", IconName::ReplaceNext)
1862+ .on_click(cx.listener(|this, _, cx| {
1863+ if let Some(search) = this.active_project_search.as_ref() {
1864+ search.update(cx, |this, cx| {
1865+ this.replace_next(&ReplaceNext, cx);
1866+ })
1867+ }
1868+ }))
1869+ .tooltip(|cx| Tooltip::for_action("Replace next match", &ReplaceNext, cx)),
1870+ )
1871+ .child(
1872+ IconButton::new("project-search-replace-all", IconName::ReplaceAll)
1873+ .on_click(cx.listener(|this, _, cx| {
1874+ if let Some(search) = this.active_project_search.as_ref() {
1875+ search.update(cx, |this, cx| {
1876+ this.replace_all(&ReplaceAll, cx);
1877+ })
1878+ }
1879+ }))
1880+ .tooltip(|cx| Tooltip::for_action("Replace all matches", &ReplaceAll, cx)),
1881+ )
1882+ });
1883+ h_flex()
1884+ .gap_2()
1885+ .child(replace_column)
1886+ .child(replace_actions)
1887+ });
1888+
1889+ let filter_line = search.filters_enabled.then(|| {
1890+ h_flex()
1891+ .w_full()
1892+ .gap_2()
1893+ .child(
1894+ h_flex()
1895+ .flex_1()
1896+ .min_w(rems(MIN_INPUT_WIDTH_REMS))
1897+ .max_w(rems(MAX_INPUT_WIDTH_REMS))
1898+ .h_8()
1899+ .px_2()
1900+ .py_1()
1901+ .border_1()
1902+ .border_color(search.border_color_for(InputPanel::Include, cx))
1903+ .rounded_lg()
1904+ .child(self.render_text_input(&search.included_files_editor, cx))
1905+ .when(search.current_mode != SearchMode::Semantic, |this| {
1906+ this.child(
1907+ SearchOptions::INCLUDE_IGNORED.as_button(
1908+ search
1909+ .search_options
1910+ .contains(SearchOptions::INCLUDE_IGNORED),
1911+ cx.listener(|this, _, cx| {
1912+ this.toggle_search_option(
1913+ SearchOptions::INCLUDE_IGNORED,
1914+ cx,
1915+ );
1916+ }),
1917+ ),
1918+ )
1919+ }),
1920+ )
1921+ .child(
1922+ h_flex()
1923+ .flex_1()
1924+ .min_w(rems(MIN_INPUT_WIDTH_REMS))
1925+ .max_w(rems(MAX_INPUT_WIDTH_REMS))
1926+ .h_8()
1927+ .px_2()
1928+ .py_1()
1929+ .border_1()
1930+ .border_color(search.border_color_for(InputPanel::Exclude, cx))
1931+ .rounded_lg()
1932+ .child(self.render_text_input(&search.excluded_files_editor, cx)),
1933+ )
1934+ });
1935+
18871936 v_flex()
18881937 .key_context(key_context)
1889− .flex_grow()
1890− .gap_2()
18911938 .on_action(cx.listener(|this, _: &ToggleFocus, cx| this.move_focus_to_results(cx)))
18921939 .on_action(cx.listener(|this, _: &ToggleFilters, cx| {
18931940 this.toggle_filters(cx);
@@ -1945,60 +1992,11 @@ impl Render for ProjectSearchBar { · 51 unmodified lines
19451992 })
19461993 .on_action(cx.listener(Self::select_next_match))
19471994 .on_action(cx.listener(Self::select_prev_match))
1948− .child(
1949− h_flex()
1950− .justify_between()
1951− .gap_2()
1952− .child(query_column)
1953− .child(mode_column)
1954− .child(replace_column)
1955− .child(actions_column),
1956− )
1957− .when(search.filters_enabled, |this| {
1958− this.child(
1959− h_flex()
1960− .flex_1()
1961− .gap_2()
1962− .justify_between()
1963− .child(
1964− h_flex()
1965− .flex_1()
1966− .h_full()
1967− .px_2()
1968− .py_1()
1969− .border_1()
1970− .border_color(search.border_color_for(InputPanel::Include, cx))
1971− .rounded_lg()
1972− .child(self.render_text_input(&search.included_files_editor, cx))
1973− .when(search.current_mode != SearchMode::Semantic, |this| {
1974− this.child(
1975− SearchOptions::INCLUDE_IGNORED.as_button(
1976− search
1977− .search_options
1978− .contains(SearchOptions::INCLUDE_IGNORED),
1979− cx.listener(|this, _, cx| {
1980− this.toggle_search_option(
1981− SearchOptions::INCLUDE_IGNORED,
1982− cx,
1983− );
1984− }),
1985− ),
1986− )
1987− }),
1988− )
1989− .child(
1990− h_flex()
1991− .flex_1()
1992− .h_full()
1993− .px_2()
1994− .py_1()
1995− .border_1()
1996− .border_color(search.border_color_for(InputPanel::Exclude, cx))
1997− .rounded_lg()
1998− .child(self.render_text_input(&search.excluded_files_editor, cx)),
1999− ),
2000− )
2001− })
1995+ .gap_2()
1996+ .w_full()
1997+ .child(search_line)
1998+ .children(replace_line)
1999+ .children(filter_line)
20022000 }
20032001 }
20042002