@@ -465,14 +465,8 @@ impl SearchData {
let match_offset_range = match_range.to_offset(multi_buffer_snapshot);
let mut search_match_indices = vec![
- multi_buffer_snapshot.clip_offset(
- match_offset_range.start - context_offset_range.start,
- Bias::Left,
- )
- ..multi_buffer_snapshot.clip_offset(
- match_offset_range.end - context_offset_range.start,
- Bias::Right,
- ),
+ match_offset_range.start - context_offset_range.start
+ ..match_offset_range.end - context_offset_range.start,
];
let entire_context_text = multi_buffer_snapshot
@@ -509,14 +503,8 @@ impl SearchData {
.next()
.is_some_and(|c| !c.is_whitespace());
search_match_indices.iter_mut().for_each(|range| {
- range.start = multi_buffer_snapshot.clip_offset(
- range.start.saturating_sub(left_whitespaces_offset),
- Bias::Left,
- );
- range.end = multi_buffer_snapshot.clip_offset(
- range.end.saturating_sub(left_whitespaces_offset),
- Bias::Right,
- );
+ range.start = range.start.saturating_sub(left_whitespaces_offset);
+ range.end = range.end.saturating_sub(left_whitespaces_offset);
});
let trimmed_row_offset_range =
@@ -5226,10 +5214,13 @@ mod tests {
use language::{Language, LanguageConfig, LanguageMatcher, tree_sitter_rust};
use pretty_assertions::assert_eq;
use project::FakeFs;
- use search::project_search::{self, perform_project_search};
+ use search::{
+ buffer_search,
+ project_search::{self, perform_project_search},
+ };
use serde_json::json;
use util::path;
- use workspace::{OpenOptions, OpenVisible};
+ use workspace::{OpenOptions, OpenVisible, ToolbarItemView};
use super::*;
@@ -5292,25 +5283,28 @@ mod tests {
ide/src/
inlay_hints/
fn_lifetime_fn.rs
- search: match config.param_names_for_lifetime_elision_hints {
- search: allocated_lifetimes.push(if config.param_names_for_lifetime_elision_hints {
- search: Some(it) if config.param_names_for_lifetime_elision_hints => {
- search: InlayHintsConfig { param_names_for_lifetime_elision_hints: true, ..TEST_CONFIG },
+ search: match config.«param_names_for_lifetime_elision_hints» {
+ search: allocated_lifetimes.push(if config.«param_names_for_lifetime_elision_hints» {
+ search: Some(it) if config.«param_names_for_lifetime_elision_hints» => {
+ search: InlayHintsConfig { «param_names_for_lifetime_elision_hints»: true, ..TEST_CONFIG },
inlay_hints.rs
- search: pub param_names_for_lifetime_elision_hints: bool,
- search: param_names_for_lifetime_elision_hints: self
+ search: pub «param_names_for_lifetime_elision_hints»: bool,
+ search: «param_names_for_lifetime_elision_hints»: self
static_index.rs
- search: param_names_for_lifetime_elision_hints: false,
+ search: «param_names_for_lifetime_elision_hints»: false,
rust-analyzer/src/
cli/
analysis_stats.rs
- search: param_names_for_lifetime_elision_hints: true,
+ search: «param_names_for_lifetime_elision_hints»: true,
config.rs
- search: param_names_for_lifetime_elision_hints: self"#
+ search: «param_names_for_lifetime_elision_hints»: self"#
.to_string();
let select_first_in_all_matches = |line_to_select: &str| {
- assert!(all_matches.contains(line_to_select));
+ assert!(
+ all_matches.contains(line_to_select),
+ "`{line_to_select}` was not found in all matches `{all_matches}`"
+ );
all_matches.replacen(
line_to_select,
&format!("{line_to_select}{SELECTED_MARKER}"),
@@ -5331,7 +5325,7 @@ mod tests {
cx,
),
select_first_in_all_matches(
- "search: match config.param_names_for_lifetime_elision_hints {"
+ "search: match config.«param_names_for_lifetime_elision_hints» {"
)
);
});
@@ -5371,16 +5365,16 @@ mod tests {
inlay_hints/
fn_lifetime_fn.rs{SELECTED_MARKER}
inlay_hints.rs
- search: pub param_names_for_lifetime_elision_hints: bool,
- search: param_names_for_lifetime_elision_hints: self
+ search: pub «param_names_for_lifetime_elision_hints»: bool,
+ search: «param_names_for_lifetime_elision_hints»: self
static_index.rs
- search: param_names_for_lifetime_elision_hints: false,
+ search: «param_names_for_lifetime_elision_hints»: false,
rust-analyzer/src/
cli/
analysis_stats.rs
- search: param_names_for_lifetime_elision_hints: true,
+ search: «param_names_for_lifetime_elision_hints»: true,
config.rs
- search: param_names_for_lifetime_elision_hints: self"#,
+ search: «param_names_for_lifetime_elision_hints»: self"#,
)
);
});
@@ -5441,9 +5435,9 @@ mod tests {
rust-analyzer/src/
cli/
analysis_stats.rs
- search: param_names_for_lifetime_elision_hints: true,
+ search: «param_names_for_lifetime_elision_hints»: true,
config.rs
- search: param_names_for_lifetime_elision_hints: self"#,
+ search: «param_names_for_lifetime_elision_hints»: self"#,
)
);
});
@@ -5523,21 +5517,21 @@ mod tests {
ide/src/
inlay_hints/
fn_lifetime_fn.rs
- search: match config.param_names_for_lifetime_elision_hints {
- search: allocated_lifetimes.push(if config.param_names_for_lifetime_elision_hints {
- search: Some(it) if config.param_names_for_lifetime_elision_hints => {
- search: InlayHintsConfig { param_names_for_lifetime_elision_hints: true, ..TEST_CONFIG },
+ search: match config.«param_names_for_lifetime_elision_hints» {
+ search: allocated_lifetimes.push(if config.«param_names_for_lifetime_elision_hints» {
+ search: Some(it) if config.«param_names_for_lifetime_elision_hints» => {
+ search: InlayHintsConfig { «param_names_for_lifetime_elision_hints»: true, ..TEST_CONFIG },
inlay_hints.rs
- search: pub param_names_for_lifetime_elision_hints: bool,
- search: param_names_for_lifetime_elision_hints: self
+ search: pub «param_names_for_lifetime_elision_hints»: bool,
+ search: «param_names_for_lifetime_elision_hints»: self
static_index.rs
- search: param_names_for_lifetime_elision_hints: false,
+ search: «param_names_for_lifetime_elision_hints»: false,
rust-analyzer/src/
cli/
analysis_stats.rs
- search: param_names_for_lifetime_elision_hints: true,
+ search: «param_names_for_lifetime_elision_hints»: true,
config.rs
- search: param_names_for_lifetime_elision_hints: self"#
+ search: «param_names_for_lifetime_elision_hints»: self"#
.to_string();
cx.executor()
@@ -5662,30 +5656,40 @@ mod tests {
ide/src/
inlay_hints/
fn_lifetime_fn.rs
- search: match config.param_names_for_lifetime_elision_hints {
- search: allocated_lifetimes.push(if config.param_names_for_lifetime_elision_hints {
- search: Some(it) if config.param_names_for_lifetime_elision_hints => {
- search: InlayHintsConfig { param_names_for_lifetime_elision_hints: true, ..TEST_CONFIG },
+ search: match config.«param_names_for_lifetime_elision_hints» {
+ search: allocated_lifetimes.push(if config.«param_names_for_lifetime_elision_hints» {
+ search: Some(it) if config.«param_names_for_lifetime_elision_hints» => {
+ search: InlayHintsConfig { «param_names_for_lifetime_elision_hints»: true, ..TEST_CONFIG },
inlay_hints.rs
- search: pub param_names_for_lifetime_elision_hints: bool,
- search: param_names_for_lifetime_elision_hints: self
+ search: pub «param_names_for_lifetime_elision_hints»: bool,
+ search: «param_names_for_lifetime_elision_hints»: self
static_index.rs
- search: param_names_for_lifetime_elision_hints: false,
+ search: «param_names_for_lifetime_elision_hints»: false,
rust-analyzer/src/
cli/
analysis_stats.rs
- search: param_names_for_lifetime_elision_hints: true,
+ search: «param_names_for_lifetime_elision_hints»: true,
config.rs
- search: param_names_for_lifetime_elision_hints: self"#
+ search: «param_names_for_lifetime_elision_hints»: self"#
.to_string();
let select_first_in_all_matches = |line_to_select: &str| {
- assert!(all_matches.contains(line_to_select));
+ assert!(
+ all_matches.contains(line_to_select),
+ "`{line_to_select}` was not found in all matches `{all_matches}`"
+ );
all_matches.replacen(
line_to_select,
&format!("{line_to_select}{SELECTED_MARKER}"),
1,
)
};
+ let clear_outline_metadata = |input: &str| {
+ input
+ .replace("search: ", "")
+ .replace("«", "")
+ .replace("»", "")
+ };
+
cx.executor()
.advance_clock(UPDATE_DEBOUNCE + Duration::from_millis(100));
cx.run_until_parked();
@@ -5696,7 +5700,7 @@ mod tests {
.expect("should have an active editor open")
});
let initial_outline_selection =
- "search: match config.param_names_for_lifetime_elision_hints {";
+ "search: match config.«param_names_for_lifetime_elision_hints» {";
outline_panel.update_in(cx, |outline_panel, window, cx| {
assert_eq!(
display_entries(
@@ -5710,7 +5714,7 @@ mod tests {
);
assert_eq!(
selected_row_text(&active_editor, cx),
- initial_outline_selection.replace("search: ", ""), // Clear outline metadata prefixes
+ clear_outline_metadata(initial_outline_selection),
"Should place the initial editor selection on the corresponding search result"
);
@@ -5719,7 +5723,7 @@ mod tests {
});
let navigated_outline_selection =
- "search: Some(it) if config.param_names_for_lifetime_elision_hints => {";
+ "search: Some(it) if config.«param_names_for_lifetime_elision_hints» => {";
outline_panel.update(cx, |outline_panel, cx| {
assert_eq!(
display_entries(
@@ -5737,7 +5741,7 @@ mod tests {
outline_panel.update(cx, |_, cx| {
assert_eq!(
selected_row_text(&active_editor, cx),
- navigated_outline_selection.replace("search: ", ""), // Clear outline metadata prefixes
+ clear_outline_metadata(navigated_outline_selection),
"Should still have the initial caret position after SelectNext calls"
);
});
@@ -5748,7 +5752,7 @@ mod tests {
outline_panel.update(cx, |_outline_panel, cx| {
assert_eq!(
selected_row_text(&active_editor, cx),
- navigated_outline_selection.replace("search: ", ""), // Clear outline metadata prefixes
+ clear_outline_metadata(navigated_outline_selection),
"After opening, should move the caret to the opened outline entry's position"
);
});
@@ -5756,7 +5760,7 @@ mod tests {
outline_panel.update_in(cx, |outline_panel, window, cx| {
outline_panel.select_next(&SelectNext, window, cx);
});
- let next_navigated_outline_selection = "search: InlayHintsConfig { param_names_for_lifetime_elision_hints: true, ..TEST_CONFIG },";
+ let next_navigated_outline_selection = "search: InlayHintsConfig { «param_names_for_lifetime_elision_hints»: true, ..TEST_CONFIG },";
outline_panel.update(cx, |outline_panel, cx| {
assert_eq!(
display_entries(
@@ -5774,7 +5778,7 @@ mod tests {
outline_panel.update(cx, |_outline_panel, cx| {
assert_eq!(
selected_row_text(&active_editor, cx),
- next_navigated_outline_selection.replace("search: ", ""), // Clear outline metadata prefixes
+ clear_outline_metadata(next_navigated_outline_selection),
"Should again preserve the selection after another SelectNext call"
);
});
@@ -5807,7 +5811,7 @@ mod tests {
);
assert_eq!(
selected_row_text(&new_active_editor, cx),
- next_navigated_outline_selection.replace("search: ", ""), // Clear outline metadata prefixes
+ clear_outline_metadata(next_navigated_outline_selection),
"When opening the excerpt, should navigate to the place corresponding the outline entry"
);
});
@@ -5909,11 +5913,11 @@ mod tests {
format!(
r#"one/
a.txt
- search: aaa aaa <==== selected
- search: aaa aaa
+ search: «aaa» aaa <==== selected
+ search: aaa «aaa»
two/
b.txt
- search: a aaa"#,
+ search: a «aaa»"#,
),
);
});
@@ -5939,7 +5943,7 @@ two/
a.txt <==== selected
two/
b.txt
- search: a aaa"#,
+ search: a «aaa»"#,
),
);
});
@@ -5988,7 +5992,7 @@ two/ <==== selected"#,
a.txt
two/ <==== selected
b.txt
- search: a aaa"#,
+ search: a «aaa»"#,
)
);
});
@@ -6453,18 +6457,18 @@ outline: struct OutlineEntryExcerpt
r#"frontend-project/
public/lottie/
syntax-tree.json
- search: {{ "something": "static" }} <==== selected
+ search: {{ "something": "«static»" }} <==== selected
src/
app/(site)/
(about)/jobs/[slug]/
page.tsx
- search: static
+ search: «static»
(blog)/post/[slug]/
page.tsx
- search: static
+ search: «static»
components/
ErrorBoundary.tsx
- search: static"#
+ search: «static»"#
)
);
});
@@ -6492,12 +6496,12 @@ outline: struct OutlineEntryExcerpt
r#"frontend-project/
public/lottie/
syntax-tree.json
- search: {{ "something": "static" }}
+ search: {{ "something": "«static»" }}
src/
app/(site)/ <==== selected
components/
ErrorBoundary.tsx
- search: static"#
+ search: «static»"#
)
);
});
@@ -6522,12 +6526,12 @@ outline: struct OutlineEntryExcerpt
r#"frontend-project/
public/lottie/
syntax-tree.json
- search: {{ "something": "static" }}
+ search: {{ "something": "«static»" }}
src/
app/(site)/
components/
ErrorBoundary.tsx
- search: static <==== selected"#
+ search: «static» <==== selected"#
)
);
});
@@ -6556,7 +6560,7 @@ outline: struct OutlineEntryExcerpt
r#"frontend-project/
public/lottie/
syntax-tree.json
- search: {{ "something": "static" }}
+ search: {{ "something": "«static»" }}
src/
app/(site)/
components/
@@ -6589,12 +6593,66 @@ outline: struct OutlineEntryExcerpt
r#"frontend-project/
public/lottie/
syntax-tree.json
- search: {{ "something": "static" }}
+ search: {{ "something": "«static»" }}
+ src/
+ app/(site)/
+ components/
+ ErrorBoundary.tsx <==== selected
+ search: «static»"#
+ )
+ );
+ });
+
+ outline_panel.update_in(cx, |outline_panel, window, cx| {
+ outline_panel.collapse_all_entries(&CollapseAllEntries, window, cx);
+ });
+ cx.executor()
+ .advance_clock(UPDATE_DEBOUNCE + Duration::from_millis(100));
+ cx.run_until_parked();
+ outline_panel.update(cx, |outline_panel, cx| {
+ assert_eq!(
+ display_entries(
+ &project,
+ &snapshot(outline_panel, cx),
+ &outline_panel.cached_entries,
+ outline_panel.selected_entry(),
+ cx,
+ ),
+ format!(r#"frontend-project/"#)
+ );
+ });
+
+ outline_panel.update_in(cx, |outline_panel, window, cx| {
+ outline_panel.expand_all_entries(&ExpandAllEntries, window, cx);
+ });
+ cx.executor()
+ .advance_clock(UPDATE_DEBOUNCE + Duration::from_millis(100));
+ cx.run_until_parked();
+ outline_panel.update(cx, |outline_panel, cx| {
+ assert_eq!(
+ display_entries(
+ &project,
+ &snapshot(outline_panel, cx),
+ &outline_panel.cached_entries,
+ outline_panel.selected_entry(),
+ cx,
+ ),
+ format!(
+ r#"frontend-project/
+ public/lottie/
+ syntax-tree.json
+ search: {{ "something": "«static»" }}
src/
app/(site)/
+ (about)/jobs/[slug]/
+ page.tsx
+ search: «static»
+ (blog)/post/[slug]/
+ page.tsx
+ search: «static»
components/
ErrorBoundary.tsx <==== selected
- search: static"#
+ search: «static»"#
)
);
});
@@ -6700,16 +6758,21 @@ outline: struct OutlineEntryExcerpt
}
},
PanelEntry::Search(search_entry) => {
- format!(
- "search: {}",
- search_entry
- .render_data
- .get_or_init(|| SearchData::new(
- &search_entry.match_range,
- multi_buffer_snapshot
- ))
- .context_text
- )
+ let search_data = search_entry.render_data.get_or_init(|| {
+ SearchData::new(&search_entry.match_range, multi_buffer_snapshot)
+ });
+ let mut search_result = String::new();
+ let mut last_end = 0;
+ for range in &search_data.search_match_indices {
+ search_result.push_str(&search_data.context_text[last_end..range.start]);
+ search_result.push('«');
+ search_result.push_str(&search_data.context_text[range.start..range.end]);
+ search_result.push('»');
+ last_end = range.end;
+ }
+ search_result.push_str(&search_data.context_text[last_end..]);
+
+ format!("search: {search_result}")
}
};
@@ -6732,6 +6795,7 @@ outline: struct OutlineEntryExcerpt
workspace::init_settings(cx);
Project::init_settings(cx);
project_search::init(cx);
+ buffer_search::init(cx);
super::init(cx);
});
}
@@ -7510,4 +7574,335 @@ outline: fn main()"
);
});
}
+
+ #[gpui::test]
+ async fn test_outline_expand_collapse_all(cx: &mut TestAppContext) {
+ init_test(cx);
+
+ let fs = FakeFs::new(cx.background_executor.clone());
+ fs.insert_tree(
+ "/test",
+ json!({
+ "src": {
+ "lib.rs": indoc!("
+ mod outer {
+ pub struct OuterStruct {
+ field: String,
+ }
+ impl OuterStruct {
+ pub fn new() -> Self {
+ Self { field: String::new() }
+ }
+ pub fn method(&self) {
+ println!(\"{}\", self.field);
+ }
+ }
+ mod inner {
+ pub fn inner_function() {
+ let x = 42;
+ println!(\"{}\", x);
+ }
+ pub struct InnerStruct {
+ value: i32,
+ }
+ }
+ }
+ fn main() {
+ let s = outer::OuterStruct::new();
+ s.method();
+ }
+ "),
+ }
+ }),
+ )
+ .await;
+
+ let project = Project::test(fs.clone(), ["/test".as_ref()], cx).await;
+ project.read_with(cx, |project, _| {
+ project.languages().add(Arc::new(
+ rust_lang()
+ .with_outline_query(
+ r#"
+ (struct_item
+ (visibility_modifier)? @context
+ "struct" @context
+ name: (_) @name) @item
+ (impl_item
+ "impl" @context
+ trait: (_)? @context
+ "for"? @context
+ type: (_) @context
+ body: (_)) @item
+ (function_item
+ (visibility_modifier)? @context
+ "fn" @context
+ name: (_) @name
+ parameters: (_) @context) @item
+ (mod_item
+ (visibility_modifier)? @context
+ "mod" @context
+ name: (_) @name) @item
+ (enum_item
+ (visibility_modifier)? @context
+ "enum" @context
+ name: (_) @name) @item
+ (field_declaration
+ (visibility_modifier)? @context
+ name: (_) @name
+ ":" @context
+ type: (_) @context) @item
+ "#,
+ )
+ .unwrap(),
+ ))
+ });
+ let workspace = add_outline_panel(&project, cx).await;
+ let cx = &mut VisualTestContext::from_window(*workspace, cx);
+ let outline_panel = outline_panel(&workspace, cx);
+
+ outline_panel.update_in(cx, |outline_panel, window, cx| {
+ outline_panel.set_active(true, window, cx)
+ });
+
+ workspace
+ .update(cx, |workspace, window, cx| {
+ workspace.open_abs_path(
+ PathBuf::from("/test/src/lib.rs"),
+ OpenOptions {
+ visible: Some(OpenVisible::All),
+ ..Default::default()
+ },
+ window,
+ cx,
+ )
+ })
+ .unwrap()
+ .await
+ .unwrap();
+
+ cx.executor()
+ .advance_clock(UPDATE_DEBOUNCE + Duration::from_millis(500));
+ cx.run_until_parked();
+
+ // Force another update cycle to ensure outlines are fetched
+ outline_panel.update_in(cx, |panel, window, cx| {
+ panel.update_non_fs_items(window, cx);
+ panel.update_cached_entries(Some(UPDATE_DEBOUNCE), window, cx);
+ });
+ cx.executor()
+ .advance_clock(UPDATE_DEBOUNCE + Duration::from_millis(500));
+ cx.run_until_parked();
+
+ outline_panel.update(cx, |outline_panel, cx| {
+ assert_eq!(
+ display_entries(
+ &project,
+ &snapshot(outline_panel, cx),
+ &outline_panel.cached_entries,
+ outline_panel.selected_entry(),
+ cx,
+ ),
+ indoc!(
+ "
+outline: mod outer <==== selected
+ outline: pub struct OuterStruct
+ outline: field: String
+ outline: impl OuterStruct
+ outline: pub fn new()
+ outline: pub fn method(&self)
+ outline: mod inner
+ outline: pub fn inner_function()
+ outline: pub struct InnerStruct
+ outline: value: i32
+outline: fn main()"
+ )
+ );
+ });
+
+ let _parent_outline = outline_panel
+ .read_with(cx, |panel, _cx| {
+ panel
+ .cached_entries
+ .iter()
+ .find_map(|entry| match &entry.entry {
+ PanelEntry::Outline(OutlineEntry::Outline(outline))
+ if panel
+ .outline_children_cache
+ .get(&outline.buffer_id)
+ .and_then(|children_map| {
+ let key =
+ (outline.outline.range.clone(), outline.outline.depth);
+ children_map.get(&key)
+ })
+ .copied()
+ .unwrap_or(false) =>
+ {
+ Some(entry.entry.clone())
+ }
+ _ => None,
+ })
+ })
+ .expect("Should find an outline with children");
+
+ // Collapse all entries
+ outline_panel.update_in(cx, |panel, window, cx| {
+ panel.collapse_all_entries(&CollapseAllEntries, window, cx);
+ });
+ cx.executor()
+ .advance_clock(UPDATE_DEBOUNCE + Duration::from_millis(100));
+ cx.run_until_parked();
+
+ let expected_collapsed_output = indoc!(
+ "
+ outline: mod outer <==== selected
+ outline: fn main()"
+ );
+
+ outline_panel.update(cx, |panel, cx| {
+ assert_eq! {
+ display_entries(
+ &project,
+ &snapshot(panel, cx),
+ &panel.cached_entries,
+ panel.selected_entry(),
+ cx,
+ ),
+ expected_collapsed_output
+ };
+ });
+
+ // Expand all entries
+ outline_panel.update_in(cx, |panel, window, cx| {
+ panel.expand_all_entries(&ExpandAllEntries, window, cx);
+ });
+ cx.executor()
+ .advance_clock(UPDATE_DEBOUNCE + Duration::from_millis(100));
+ cx.run_until_parked();
+
+ let expected_expanded_output = indoc!(
+ "
+ outline: mod outer <==== selected
+ outline: pub struct OuterStruct
+ outline: field: String
+ outline: impl OuterStruct
+ outline: pub fn new()
+ outline: pub fn method(&self)
+ outline: mod inner
+ outline: pub fn inner_function()
+ outline: pub struct InnerStruct
+ outline: value: i32
+ outline: fn main()"
+ );
+
+ outline_panel.update(cx, |panel, cx| {
+ assert_eq! {
+ display_entries(
+ &project,
+ &snapshot(panel, cx),
+ &panel.cached_entries,
+ panel.selected_entry(),
+ cx,
+ ),
+ expected_expanded_output
+ };
+ });
+ }
+
+ #[gpui::test]
+ async fn test_buffer_search(cx: &mut TestAppContext) {
+ init_test(cx);
+
+ let fs = FakeFs::new(cx.background_executor.clone());
+ fs.insert_tree(
+ "/test",
+ json!({
+ "foo.txt": r#"<_constitution>
+
+</_constitution>
+
+
+
+## 📊 Output
+
+| Field | Meaning |
+"#
+ }),
+ )
+ .await;
+
+ let project = Project::test(fs.clone(), ["/test".as_ref()], cx).await;
+ let workspace = add_outline_panel(&project, cx).await;
+ let cx = &mut VisualTestContext::from_window(*workspace, cx);
+
+ let editor = workspace
+ .update(cx, |workspace, window, cx| {
+ workspace.open_abs_path(
+ PathBuf::from("/test/foo.txt"),
+ OpenOptions {
+ visible: Some(OpenVisible::All),
+ ..OpenOptions::default()
+ },
+ window,
+ cx,
+ )
+ })
+ .unwrap()
+ .await
+ .unwrap()
+ .downcast::<Editor>()
+ .unwrap();
+
+ let search_bar = workspace
+ .update(cx, |_, window, cx| {
+ cx.new(|cx| {
+ let mut search_bar = BufferSearchBar::new(None, window, cx);
+ search_bar.set_active_pane_item(Some(&editor), window, cx);
+ search_bar.show(window, cx);
+ search_bar
+ })
+ })
+ .unwrap();
+
+ let outline_panel = outline_panel(&workspace, cx);
+
+ outline_panel.update_in(cx, |outline_panel, window, cx| {
+ outline_panel.set_active(true, window, cx)
+ });
+
+ search_bar
+ .update_in(cx, |search_bar, window, cx| {
+ search_bar.search(" ", None, true, window, cx)
+ })
+ .await
+ .unwrap();
+
+ cx.executor()
+ .advance_clock(UPDATE_DEBOUNCE + Duration::from_millis(500));
+ cx.run_until_parked();
+
+ outline_panel.update(cx, |outline_panel, cx| {
+ assert_eq!(
+ display_entries(
+ &project,
+ &snapshot(outline_panel, cx),
+ &outline_panel.cached_entries,
+ outline_panel.selected_entry(),
+ cx,
+ ),
+ "search: | Field« » | Meaning | <==== selected
+search: | Field « » | Meaning |
+search: | Field « » | Meaning |
+search: | Field « » | Meaning |
+search: | Field « »| Meaning |
+search: | Field | Meaning« » |
+search: | Field | Meaning « » |
+search: | Field | Meaning « » |
+search: | Field | Meaning « » |
+search: | Field | Meaning « » |
+search: | Field | Meaning « » |
+search: | Field | Meaning « » |
+search: | Field | Meaning « »|"
+ );
+ });
+ }
}