History

Merge branch 'main' into copilot-ui

Piotr Osiewicz committed 2 years ago

Commit 316d4832 parents 0602953 eceed7112 files · +349 −44Browse files

Unified · Split

12 files
  1. Cargo.lock +3 −2
  2. Cargo.toml +0 −1
  3. assets/keymaps/default.json +1 −1
  4. crates/editor/src/items.rs +26 −7
  5. crates/gpui/Cargo.toml +1 −1
  6. crates/gpui/src/app/entity_map.rs +4 −3
  7. crates/gpui/src/platform/mac/dispatcher.rs +5 −5
  8. crates/search/src/project_search.rs +286 −18
  9. crates/terminal_view/src/terminal_panel.rs +7 −4
  10. crates/workspace/src/pane.rs +6 −1
  11. crates/workspace/src/pane_group.rs +9 −1
  12. crates/workspace/src/workspace.rs +1 −0
Cargo.lock+3−2
@@ -576,8 +576,9 @@ dependencies = [ · 575 unmodified lines
576 576
577[[package]]577[[package]]
578name = "async-task"578name = "async-task"
579version = "4.0.3"579version = "4.7.0"
580source = "git+https://github.com/zed-industries/async-task?rev=341b57d6de98cdfd7b418567b8de2022ca993a6e#341b57d6de98cdfd7b418567b8de2022ca993a6e"580source = "registry+https://github.com/rust-lang/crates.io-index"
581checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799"
581 582
582[[package]]583[[package]]
583name = "async-tls"584name = "async-tls"
Cargo.toml+0−1
@@ -164,7 +164,6 @@ tree-sitter-uiua = {git = "https://github.com/shnarazk/tree-sitter-uiua", rev = · 163 unmodified lines
164 164
165[patch.crates-io]165[patch.crates-io]
166tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "31c40449749c4263a91a43593831b82229049a4c" }166tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "31c40449749c4263a91a43593831b82229049a4c" }
167async-task = { git = "https://github.com/zed-industries/async-task", rev = "341b57d6de98cdfd7b418567b8de2022ca993a6e" }
168# wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", rev = "v16.0.0" }167# wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", rev = "v16.0.0" }
169 168
170# TODO - Remove when a version is released with this PR: https://github.com/servo/core-foundation-rs/pull/457169# TODO - Remove when a version is released with this PR: https://github.com/servo/core-foundation-rs/pull/457
assets/keymaps/default.json+1−1
@@ -402,7 +402,7 @@ · 401 unmodified lines
402 "cmd-r": "workspace::ToggleRightDock",402 "cmd-r": "workspace::ToggleRightDock",
403 "cmd-j": "workspace::ToggleBottomDock",403 "cmd-j": "workspace::ToggleBottomDock",
404 "alt-cmd-y": "workspace::CloseAllDocks",404 "alt-cmd-y": "workspace::CloseAllDocks",
405 "cmd-shift-f": "workspace::NewSearch",405 "cmd-shift-f": "workspace::DeploySearch",
406 "cmd-k cmd-t": "theme_selector::Toggle",406 "cmd-k cmd-t": "theme_selector::Toggle",
407 "cmd-k cmd-s": "zed::OpenKeymap",407 "cmd-k cmd-s": "zed::OpenKeymap",
408 "cmd-t": "project_symbols::Toggle",408 "cmd-t": "project_symbols::Toggle",
crates/editor/src/items.rs+26−7
@@ -15,9 +15,11 @@ use language::{ · 14 unmodified lines
15 proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, CharKind, OffsetRangeExt,15 proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, CharKind, OffsetRangeExt,
16 Point, SelectionGoal,16 Point, SelectionGoal,
17};17};
18use project::repository::GitFileStatus;
18use project::{search::SearchQuery, FormatTrigger, Item as _, Project, ProjectPath};19use project::{search::SearchQuery, FormatTrigger, Item as _, Project, ProjectPath};
19use rpc::proto::{self, update_view, PeerId};20use rpc::proto::{self, update_view, PeerId};
20use settings::Settings;21use settings::Settings;
22use workspace::item::ItemSettings;
21 23
22use std::fmt::Write;24use std::fmt::Write;
23use std::{25use std::{
@@ -29,7 +31,7 @@ use std::{ · 5 unmodified lines
29 sync::Arc,31 sync::Arc,
30};32};
31use text::Selection;33use text::Selection;
32use theme::{ActiveTheme, Theme};34use theme::Theme;
33use ui::{h_stack, prelude::*, Label};35use ui::{h_stack, prelude::*, Label};
34use util::{paths::PathExt, paths::FILE_ROW_COLUMN_DELIMITER, ResultExt, TryFutureExt};36use util::{paths::PathExt, paths::FILE_ROW_COLUMN_DELIMITER, ResultExt, TryFutureExt};
35use workspace::{37use workspace::{
@@ -579,7 +581,28 @@ impl Item for Editor { · 543 unmodified lines
579 }581 }
580 582
581 fn tab_content(&self, detail: Option<usize>, selected: bool, cx: &WindowContext) -> AnyElement {583 fn tab_content(&self, detail: Option<usize>, selected: bool, cx: &WindowContext) -> AnyElement {
582 let _theme = cx.theme();584 let git_status = if ItemSettings::get_global(cx).git_status {
585 self.buffer()
586 .read(cx)
587 .as_singleton()
588 .and_then(|buffer| buffer.read(cx).project_path(cx))
589 .and_then(|path| self.project.as_ref()?.read(cx).entry_for_path(&path, cx))
590 .and_then(|entry| entry.git_status())
591 } else {
592 None
593 };
594 let label_color = match git_status {
595 Some(GitFileStatus::Added) => Color::Created,
596 Some(GitFileStatus::Modified) => Color::Modified,
597 Some(GitFileStatus::Conflict) => Color::Conflict,
598 None => {
599 if selected {
600 Color::Default
601 } else {
602 Color::Muted
603 }
604 }
605 };
583 606
584 let description = detail.and_then(|detail| {607 let description = detail.and_then(|detail| {
585 let path = path_for_buffer(&self.buffer, detail, false, cx)?;608 let path = path_for_buffer(&self.buffer, detail, false, cx)?;
@@ -595,11 +618,7 @@ impl Item for Editor { · 9 unmodified lines
595 618
596 h_stack()619 h_stack()
597 .gap_2()620 .gap_2()
598 .child(Label::new(self.title(cx).to_string()).color(if selected {621 .child(Label::new(self.title(cx).to_string()).color(label_color))
599 Color::Default
600 } else {
601 Color::Muted
602 }))
603 .when_some(description, |this, description| {622 .when_some(description, |this, description| {
604 this.child(623 this.child(
605 Label::new(description)624 Label::new(description)
crates/gpui/Cargo.toml+1−1
@@ -19,7 +19,7 @@ gpui_macros = { path = "../gpui_macros" } · 18 unmodified lines
19util = { path = "../util" }19util = { path = "../util" }
20sum_tree = { path = "../sum_tree" }20sum_tree = { path = "../sum_tree" }
21sqlez = { path = "../sqlez" }21sqlez = { path = "../sqlez" }
22async-task = "4.0.3"22async-task = "4.7"
23backtrace = { version = "0.3", optional = true }23backtrace = { version = "0.3", optional = true }
24ctor.workspace = true24ctor.workspace = true
25linkme = "0.3"25linkme = "0.3"
crates/gpui/src/app/entity_map.rs+4−3
@@ -1,8 +1,6 @@
1use crate::{private::Sealed, AppContext, Context, Entity, ModelContext};1use crate::{private::Sealed, AppContext, Context, Entity, ModelContext};
2use anyhow::{anyhow, Result};2use anyhow::{anyhow, Result};
3use collections::HashMap;
4use derive_more::{Deref, DerefMut};3use derive_more::{Deref, DerefMut};
5use lazy_static::lazy_static;
6use parking_lot::{RwLock, RwLockUpgradableReadGuard};4use parking_lot::{RwLock, RwLockUpgradableReadGuard};
7use slotmap::{SecondaryMap, SlotMap};5use slotmap::{SecondaryMap, SlotMap};
8use std::{6use std::{
@@ -18,6 +16,9 @@ use std::{ · 9 unmodified lines
18 thread::panicking,16 thread::panicking,
19};17};
20 18
19#[cfg(any(test, feature = "test-support"))]
20use collections::HashMap;
21
21slotmap::new_key_type! { pub struct EntityId; }22slotmap::new_key_type! { pub struct EntityId; }
22 23
23impl EntityId {24impl EntityId {
@@ -600,7 +601,7 @@ impl<T> PartialEq<Model<T>> for WeakModel<T> { · 576 unmodified lines
600}601}
601 602
602#[cfg(any(test, feature = "test-support"))]603#[cfg(any(test, feature = "test-support"))]
603lazy_static! {604lazy_static::lazy_static! {
604 static ref LEAK_BACKTRACE: bool =605 static ref LEAK_BACKTRACE: bool =
605 std::env::var("LEAK_BACKTRACE").map_or(false, |b| !b.is_empty());606 std::env::var("LEAK_BACKTRACE").map_or(false, |b| !b.is_empty());
606}607}
crates/gpui/src/platform/mac/dispatcher.rs+5−5
@@ -11,7 +11,7 @@ use objc::{ · 10 unmodified lines
11};11};
12use parking::{Parker, Unparker};12use parking::{Parker, Unparker};
13use parking_lot::Mutex;13use parking_lot::Mutex;
14use std::{ffi::c_void, sync::Arc, time::Duration};14use std::{ffi::c_void, ptr::NonNull, sync::Arc, time::Duration};
15 15
16include!(concat!(env!("OUT_DIR"), "/dispatch_sys.rs"));16include!(concat!(env!("OUT_DIR"), "/dispatch_sys.rs"));
17 17
@@ -47,7 +47,7 @@ impl PlatformDispatcher for MacDispatcher { · 29 unmodified lines
47 unsafe {47 unsafe {
48 dispatch_async_f(48 dispatch_async_f(
49 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT.try_into().unwrap(), 0),49 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT.try_into().unwrap(), 0),
50 runnable.into_raw() as *mut c_void,50 runnable.into_raw().as_ptr() as *mut c_void,
51 Some(trampoline),51 Some(trampoline),
52 );52 );
53 }53 }
@@ -57,7 +57,7 @@ impl PlatformDispatcher for MacDispatcher { · 3 unmodified lines
57 unsafe {57 unsafe {
58 dispatch_async_f(58 dispatch_async_f(
59 dispatch_get_main_queue(),59 dispatch_get_main_queue(),
60 runnable.into_raw() as *mut c_void,60 runnable.into_raw().as_ptr() as *mut c_void,
61 Some(trampoline),61 Some(trampoline),
62 );62 );
63 }63 }
@@ -71,7 +71,7 @@ impl PlatformDispatcher for MacDispatcher { · 7 unmodified lines
71 dispatch_after_f(71 dispatch_after_f(
72 when,72 when,
73 queue,73 queue,
74 runnable.into_raw() as *mut c_void,74 runnable.into_raw().as_ptr() as *mut c_void,
75 Some(trampoline),75 Some(trampoline),
76 );76 );
77 }77 }
@@ -91,6 +91,6 @@ impl PlatformDispatcher for MacDispatcher { · 13 unmodified lines
91}91}
92 92
93extern "C" fn trampoline(runnable: *mut c_void) {93extern "C" fn trampoline(runnable: *mut c_void) {
94 let task = unsafe { Runnable::from_raw(runnable as *mut ()) };94 let task = unsafe { Runnable::<()>::from_raw(NonNull::new_unchecked(runnable as *mut ())) };
95 task.run();95 task.run();
96}96}
crates/search/src/project_search.rs+286−18
@@ -61,12 +61,12 @@ struct ActiveSearches(HashMap<WeakModel<Project>, WeakView<ProjectSearchView>>); · 60 unmodified lines
61struct ActiveSettings(HashMap<WeakModel<Project>, ProjectSearchSettings>);61struct ActiveSettings(HashMap<WeakModel<Project>, ProjectSearchSettings>);
62 62
63pub fn init(cx: &mut AppContext) {63pub fn init(cx: &mut AppContext) {
64 // todo!() po
65 cx.set_global(ActiveSearches::default());64 cx.set_global(ActiveSearches::default());
66 cx.set_global(ActiveSettings::default());65 cx.set_global(ActiveSettings::default());
67 cx.observe_new_views(|workspace: &mut Workspace, _cx| {66 cx.observe_new_views(|workspace: &mut Workspace, _cx| {
68 workspace67 workspace
69 .register_action(ProjectSearchView::deploy)68 .register_action(ProjectSearchView::new_search)
69 .register_action(ProjectSearchView::deploy_search)
70 .register_action(ProjectSearchBar::search_in_new);70 .register_action(ProjectSearchBar::search_in_new);
71 })71 })
72 .detach();72 .detach();
@@ -941,11 +941,41 @@ impl ProjectSearchView { · 868 unmodified lines
941 });941 });
942 }942 }
943 943
944 // Re-activate the most recently activated search or the most recent if it has been closed.
945 // If no search exists in the workspace, create a new one.
946 fn deploy_search(
947 workspace: &mut Workspace,
948 _: &workspace::DeploySearch,
949 cx: &mut ViewContext<Workspace>,
950 ) {
951 let active_search = cx
952 .global::<ActiveSearches>()
953 .0
954 .get(&workspace.project().downgrade());
955 let existing = active_search
956 .and_then(|active_search| {
957 workspace
958 .items_of_type::<ProjectSearchView>(cx)
959 .filter(|search| &search.downgrade() == active_search)
960 .last()
961 })
962 .or_else(|| workspace.item_of_type::<ProjectSearchView>(cx));
963 Self::existing_or_new_search(workspace, existing, cx)
964 }
965
944 // Add another search tab to the workspace.966 // Add another search tab to the workspace.
945 fn deploy(967 fn new_search(
946 workspace: &mut Workspace,968 workspace: &mut Workspace,
947 _: &workspace::NewSearch,969 _: &workspace::NewSearch,
948 cx: &mut ViewContext<Workspace>,970 cx: &mut ViewContext<Workspace>,
971 ) {
972 Self::existing_or_new_search(workspace, None, cx)
973 }
974
975 fn existing_or_new_search(
976 workspace: &mut Workspace,
977 existing: Option<View<ProjectSearchView>>,
978 cx: &mut ViewContext<Workspace>,
949 ) {979 ) {
950 // Clean up entries for dropped projects980 // Clean up entries for dropped projects
951 cx.update_global(|state: &mut ActiveSearches, _cx| {981 cx.update_global(|state: &mut ActiveSearches, _cx| {
@@ -962,19 +992,27 @@ impl ProjectSearchView { · 10 unmodified lines
962 }992 }
963 });993 });
964 994
965 let settings = cx995 let search = if let Some(existing) = existing {
966 .global::<ActiveSettings>()996 workspace.activate_item(&existing, cx);
967 .0997 existing
968 .get(&workspace.project().downgrade());
969
970 let settings = if let Some(settings) = settings {
971 Some(settings.clone())
972 } else {998 } else {
973 None999 let settings = cx
974 };1000 .global::<ActiveSettings>()
1001 .0
1002 .get(&workspace.project().downgrade());
975 1003
976 let model = cx.new_model(|cx| ProjectSearch::new(workspace.project().clone(), cx));1004 let settings = if let Some(settings) = settings {
977 let search = cx.new_view(|cx| ProjectSearchView::new(model, cx, settings));1005 Some(settings.clone())
1006 } else {
1007 None
1008 };
1009
1010 let model = cx.new_model(|cx| ProjectSearch::new(workspace.project().clone(), cx));
1011 let view = cx.new_view(|cx| ProjectSearchView::new(model, cx, settings));
1012
1013 workspace.add_item(Box::new(view.clone()), cx);
1014 view
1015 };
978 1016
979 workspace.add_item(Box::new(search.clone()), cx);1017 workspace.add_item(Box::new(search.clone()), cx);
980 1018
@@ -2060,7 +2098,237 @@ pub mod tests { · 1079 unmodified lines
2060 }2098 }
2061 2099
2062 #[gpui::test]2100 #[gpui::test]
2063 async fn test_project_search_focus(cx: &mut TestAppContext) {2101 async fn test_deploy_project_search_focus(cx: &mut TestAppContext) {
2102 init_test(cx);
2103
2104 let fs = FakeFs::new(cx.background_executor.clone());
2105 fs.insert_tree(
2106 "/dir",
2107 json!({
2108 "one.rs": "const ONE: usize = 1;",
2109 "two.rs": "const TWO: usize = one::ONE + one::ONE;",
2110 "three.rs": "const THREE: usize = one::ONE + two::TWO;",
2111 "four.rs": "const FOUR: usize = one::ONE + three::THREE;",
2112 }),
2113 )
2114 .await;
2115 let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
2116 let window = cx.add_window(|cx| Workspace::test_new(project, cx));
2117 let workspace = window.clone();
2118 let search_bar = window.build_view(cx, |_| ProjectSearchBar::new());
2119
2120 let active_item = cx.read(|cx| {
2121 workspace
2122 .read(cx)
2123 .unwrap()
2124 .active_pane()
2125 .read(cx)
2126 .active_item()
2127 .and_then(|item| item.downcast::<ProjectSearchView>())
2128 });
2129 assert!(
2130 active_item.is_none(),
2131 "Expected no search panel to be active"
2132 );
2133
2134 window
2135 .update(cx, move |workspace, cx| {
2136 assert_eq!(workspace.panes().len(), 1);
2137 workspace.panes()[0].update(cx, move |pane, cx| {
2138 pane.toolbar()
2139 .update(cx, |toolbar, cx| toolbar.add_item(search_bar, cx))
2140 });
2141
2142 ProjectSearchView::deploy_search(workspace, &workspace::DeploySearch, cx)
2143 })
2144 .unwrap();
2145
2146 let Some(search_view) = cx.read(|cx| {
2147 workspace
2148 .read(cx)
2149 .unwrap()
2150 .active_pane()
2151 .read(cx)
2152 .active_item()
2153 .and_then(|item| item.downcast::<ProjectSearchView>())
2154 }) else {
2155 panic!("Search view expected to appear after new search event trigger")
2156 };
2157
2158 cx.spawn(|mut cx| async move {
2159 window
2160 .update(&mut cx, |_, cx| {
2161 cx.dispatch_action(ToggleFocus.boxed_clone())
2162 })
2163 .unwrap();
2164 })
2165 .detach();
2166 cx.background_executor.run_until_parked();
2167 window
2168 .update(cx, |_, cx| {
2169 search_view.update(cx, |search_view, cx| {
2170 assert!(
2171 search_view.query_editor.focus_handle(cx).is_focused(cx),
2172 "Empty search view should be focused after the toggle focus event: no results panel to focus on",
2173 );
2174 });
2175 }).unwrap();
2176
2177 window
2178 .update(cx, |_, cx| {
2179 search_view.update(cx, |search_view, cx| {
2180 let query_editor = &search_view.query_editor;
2181 assert!(
2182 query_editor.focus_handle(cx).is_focused(cx),
2183 "Search view should be focused after the new search view is activated",
2184 );
2185 let query_text = query_editor.read(cx).text(cx);
2186 assert!(
2187 query_text.is_empty(),
2188 "New search query should be empty but got '{query_text}'",
2189 );
2190 let results_text = search_view
2191 .results_editor
2192 .update(cx, |editor, cx| editor.display_text(cx));
2193 assert!(
2194 results_text.is_empty(),
2195 "Empty search view should have no results but got '{results_text}'"
2196 );
2197 });
2198 })
2199 .unwrap();
2200
2201 window
2202 .update(cx, |_, cx| {
2203 search_view.update(cx, |search_view, cx| {
2204 search_view.query_editor.update(cx, |query_editor, cx| {
2205 query_editor.set_text("sOMETHINGtHATsURELYdOESnOTeXIST", cx)
2206 });
2207 search_view.search(cx);
2208 });
2209 })
2210 .unwrap();
2211 cx.background_executor.run_until_parked();
2212 window
2213 .update(cx, |_, cx| {
2214 search_view.update(cx, |search_view, cx| {
2215 let results_text = search_view
2216 .results_editor
2217 .update(cx, |editor, cx| editor.display_text(cx));
2218 assert!(
2219 results_text.is_empty(),
2220 "Search view for mismatching query should have no results but got '{results_text}'"
2221 );
2222 assert!(
2223 search_view.query_editor.focus_handle(cx).is_focused(cx),
2224 "Search view should be focused after mismatching query had been used in search",
2225 );
2226 });
2227 }).unwrap();
2228
2229 cx.spawn(|mut cx| async move {
2230 window.update(&mut cx, |_, cx| {
2231 cx.dispatch_action(ToggleFocus.boxed_clone())
2232 })
2233 })
2234 .detach();
2235 cx.background_executor.run_until_parked();
2236 window.update(cx, |_, cx| {
2237 search_view.update(cx, |search_view, cx| {
2238 assert!(
2239 search_view.query_editor.focus_handle(cx).is_focused(cx),
2240 "Search view with mismatching query should be focused after the toggle focus event: still no results panel to focus on",
2241 );
2242 });
2243 }).unwrap();
2244
2245 window
2246 .update(cx, |_, cx| {
2247 search_view.update(cx, |search_view, cx| {
2248 search_view
2249 .query_editor
2250 .update(cx, |query_editor, cx| query_editor.set_text("TWO", cx));
2251 search_view.search(cx);
2252 });
2253 })
2254 .unwrap();
2255 cx.background_executor.run_until_parked();
2256 window.update(cx, |_, cx| {
2257 search_view.update(cx, |search_view, cx| {
2258 assert_eq!(
2259 search_view
2260 .results_editor
2261 .update(cx, |editor, cx| editor.display_text(cx)),
2262 "\n\nconst THREE: usize = one::ONE + two::TWO;\n\n\nconst TWO: usize = one::ONE + one::ONE;",
2263 "Search view results should match the query"
2264 );
2265 assert!(
2266 search_view.results_editor.focus_handle(cx).is_focused(cx),
2267 "Search view with mismatching query should be focused after search results are available",
2268 );
2269 });
2270 }).unwrap();
2271 cx.spawn(|mut cx| async move {
2272 window
2273 .update(&mut cx, |_, cx| {
2274 cx.dispatch_action(ToggleFocus.boxed_clone())
2275 })
2276 .unwrap();
2277 })
2278 .detach();
2279 cx.background_executor.run_until_parked();
2280 window.update(cx, |_, cx| {
2281 search_view.update(cx, |search_view, cx| {
2282 assert!(
2283 search_view.results_editor.focus_handle(cx).is_focused(cx),
2284 "Search view with matching query should still have its results editor focused after the toggle focus event",
2285 );
2286 });
2287 }).unwrap();
2288
2289 workspace
2290 .update(cx, |workspace, cx| {
2291 ProjectSearchView::deploy_search(workspace, &workspace::DeploySearch, cx)
2292 })
2293 .unwrap();
2294 window.update(cx, |_, cx| {
2295 search_view.update(cx, |search_view, cx| {
2296 assert_eq!(search_view.query_editor.read(cx).text(cx), "two", "Query should be updated to first search result after search view 2nd open in a row");
2297 assert_eq!(
2298 search_view
2299 .results_editor
2300 .update(cx, |editor, cx| editor.display_text(cx)),
2301 "\n\nconst THREE: usize = one::ONE + two::TWO;\n\n\nconst TWO: usize = one::ONE + one::ONE;",
2302 "Results should be unchanged after search view 2nd open in a row"
2303 );
2304 assert!(
2305 search_view.query_editor.focus_handle(cx).is_focused(cx),
2306 "Focus should be moved into query editor again after search view 2nd open in a row"
2307 );
2308 });
2309 }).unwrap();
2310
2311 cx.spawn(|mut cx| async move {
2312 window
2313 .update(&mut cx, |_, cx| {
2314 cx.dispatch_action(ToggleFocus.boxed_clone())
2315 })
2316 .unwrap();
2317 })
2318 .detach();
2319 cx.background_executor.run_until_parked();
2320 window.update(cx, |_, cx| {
2321 search_view.update(cx, |search_view, cx| {
2322 assert!(
2323 search_view.results_editor.focus_handle(cx).is_focused(cx),
2324 "Search view with matching query should switch focus to the results editor after the toggle focus event",
2325 );
2326 });
2327 }).unwrap();
2328 }
2329
2330 #[gpui::test]
2331 async fn test_new_project_search_focus(cx: &mut TestAppContext) {
2064 init_test(cx);2332 init_test(cx);
2065 2333
2066 let fs = FakeFs::new(cx.background_executor.clone());2334 let fs = FakeFs::new(cx.background_executor.clone());
@@ -2101,7 +2369,7 @@ pub mod tests { · 34 unmodified lines
2101 .update(cx, |toolbar, cx| toolbar.add_item(search_bar, cx))2369 .update(cx, |toolbar, cx| toolbar.add_item(search_bar, cx))
2102 });2370 });
2103 2371
2104 ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx)2372 ProjectSearchView::new_search(workspace, &workspace::NewSearch, cx)
2105 })2373 })
2106 .unwrap();2374 .unwrap();
2107 2375
@@ -2250,7 +2518,7 @@ pub mod tests { · 142 unmodified lines
2250 2518
2251 workspace2519 workspace
2252 .update(cx, |workspace, cx| {2520 .update(cx, |workspace, cx| {
2253 ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx)2521 ProjectSearchView::new_search(workspace, &workspace::NewSearch, cx)
2254 })2522 })
2255 .unwrap();2523 .unwrap();
2256 cx.background_executor.run_until_parked();2524 cx.background_executor.run_until_parked();
@@ -2536,7 +2804,7 @@ pub mod tests { · 279 unmodified lines
2536 .update(cx, |toolbar, cx| toolbar.add_item(search_bar, cx))2804 .update(cx, |toolbar, cx| toolbar.add_item(search_bar, cx))
2537 });2805 });
2538 2806
2539 ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx)2807 ProjectSearchView::new_search(workspace, &workspace::NewSearch, cx)
2540 }2808 }
2541 })2809 })
2542 .unwrap();2810 .unwrap();
crates/terminal_view/src/terminal_panel.rs+7−4
@@ -53,7 +53,7 @@ pub struct TerminalPanel { · 52 unmodified lines
53 53
54impl TerminalPanel {54impl TerminalPanel {
55 fn new(workspace: &Workspace, cx: &mut ViewContext<Self>) -> Self {55 fn new(workspace: &Workspace, cx: &mut ViewContext<Self>) -> Self {
56 let terminal_panel = cx.view().clone();56 let terminal_panel = cx.view().downgrade();
57 let pane = cx.new_view(|cx| {57 let pane = cx.new_view(|cx| {
58 let mut pane = Pane::new(58 let mut pane = Pane::new(
59 workspace.weak_handle(),59 workspace.weak_handle(),
@@ -77,14 +77,17 @@ impl TerminalPanel { · 17 unmodified lines
77 pane.set_can_navigate(false, cx);77 pane.set_can_navigate(false, cx);
78 pane.display_nav_history_buttons(false);78 pane.display_nav_history_buttons(false);
79 pane.set_render_tab_bar_buttons(cx, move |pane, cx| {79 pane.set_render_tab_bar_buttons(cx, move |pane, cx| {
80 let terminal_panel = terminal_panel.clone();
80 h_stack()81 h_stack()
81 .gap_2()82 .gap_2()
82 .child(83 .child(
83 IconButton::new("plus", Icon::Plus)84 IconButton::new("plus", Icon::Plus)
84 .icon_size(IconSize::Small)85 .icon_size(IconSize::Small)
85 .on_click(cx.listener_for(&terminal_panel, |terminal_panel, _, cx| {86 .on_click(move |_, cx| {
86 terminal_panel.add_terminal(None, cx);87 terminal_panel
87 }))88 .update(cx, |panel, cx| panel.add_terminal(None, cx))
89 .log_err();
90 })
88 .tooltip(|cx| Tooltip::text("New Terminal", cx)),91 .tooltip(|cx| Tooltip::text("New Terminal", cx)),
89 )92 )
90 .child({93 .child({
crates/workspace/src/pane.rs+6−1
@@ -1128,7 +1128,12 @@ impl Pane { · 1127 unmodified lines
1128 if self.items.len() == 1 && should_activate {1128 if self.items.len() == 1 && should_activate {
1129 self.focus_handle.focus(cx);1129 self.focus_handle.focus(cx);
1130 } else {1130 } else {
1131 self.activate_item(index_to_activate, should_activate, should_activate, cx);1131 self.activate_item(
1132 dbg!(index_to_activate),
1133 dbg!(should_activate),
1134 should_activate,
1135 cx,
1136 );
1132 }1137 }
1133 }1138 }
1134 1139
crates/workspace/src/pane_group.rs+9−1
@@ -246,7 +246,15 @@ impl Member { · 245 unmodified lines
246 .size_full()246 .size_full()
247 .child(pane.clone())247 .child(pane.clone())
248 .when_some(leader_border, |this, color| {248 .when_some(leader_border, |this, color| {
249 this.border_2().border_color(color)249 this.child(
250 div()
251 .absolute()
252 .size_full()
253 .left_0()
254 .top_0()
255 .border_2()
256 .border_color(color),
257 )
250 })258 })
251 .when_some(leader_status_box, |this, status_box| {259 .when_some(leader_status_box, |this, status_box| {
252 this.child(260 this.child(
crates/workspace/src/workspace.rs+1−0
@@ -107,6 +107,7 @@ actions!( · 106 unmodified lines
107 NewCenterTerminal,107 NewCenterTerminal,
108 ToggleTerminalFocus,108 ToggleTerminalFocus,
109 NewSearch,109 NewSearch,
110 DeploySearch,
110 Feedback,111 Feedback,
111 Restart,112 Restart,
112 Welcome,113 Welcome,

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t