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
576576
577577 [[package]]
578578 name = "async-task"
579−version = "4.0.3"
580−source = "git+https://github.com/zed-industries/async-task?rev=341b57d6de98cdfd7b418567b8de2022ca993a6e#341b57d6de98cdfd7b418567b8de2022ca993a6e"
579+version = "4.7.0"
580+source = "registry+https://github.com/rust-lang/crates.io-index"
581+checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799"
581582
582583 [[package]]
583584 name = "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
164164
165165 [patch.crates-io]
166166 tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "31c40449749c4263a91a43593831b82229049a4c" }
167−async-task = { git = "https://github.com/zed-industries/async-task", rev = "341b57d6de98cdfd7b418567b8de2022ca993a6e" }
168167 # wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", rev = "v16.0.0" }
169168
170169 # 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
402402 "cmd-r": "workspace::ToggleRightDock",
403403 "cmd-j": "workspace::ToggleBottomDock",
404404 "alt-cmd-y": "workspace::CloseAllDocks",
405− "cmd-shift-f": "workspace::NewSearch",
405+ "cmd-shift-f": "workspace::DeploySearch",
406406 "cmd-k cmd-t": "theme_selector::Toggle",
407407 "cmd-k cmd-s": "zed::OpenKeymap",
408408 "cmd-t": "project_symbols::Toggle",
crates/editor/src/items.rs+26−7
@@ -15,9 +15,11 @@ use language::{ · 14 unmodified lines
1515 proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, CharKind, OffsetRangeExt,
1616 Point, SelectionGoal,
1717 };
18+use project::repository::GitFileStatus;
1819 use project::{search::SearchQuery, FormatTrigger, Item as _, Project, ProjectPath};
1920 use rpc::proto::{self, update_view, PeerId};
2021 use settings::Settings;
22+use workspace::item::ItemSettings;
2123
2224 use std::fmt::Write;
2325 use std::{
@@ -29,7 +31,7 @@ use std::{ · 5 unmodified lines
2931 sync::Arc,
3032 };
3133 use text::Selection;
32−use theme::{ActiveTheme, Theme};
34+use theme::Theme;
3335 use ui::{h_stack, prelude::*, Label};
3436 use util::{paths::PathExt, paths::FILE_ROW_COLUMN_DELIMITER, ResultExt, TryFutureExt};
3537 use workspace::{
@@ -579,7 +581,28 @@ impl Item for Editor { · 543 unmodified lines
579581 }
580582
581583 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+ };
583606
584607 let description = detail.and_then(|detail| {
585608 let path = path_for_buffer(&self.buffer, detail, false, cx)?;
@@ -595,11 +618,7 @@ impl Item for Editor { · 9 unmodified lines
595618
596619 h_stack()
597620 .gap_2()
598− .child(Label::new(self.title(cx).to_string()).color(if selected {
599− Color::Default
600− } else {
601− Color::Muted
602− }))
621+ .child(Label::new(self.title(cx).to_string()).color(label_color))
603622 .when_some(description, |this, description| {
604623 this.child(
605624 Label::new(description)
crates/gpui/Cargo.toml+1−1
@@ -19,7 +19,7 @@ gpui_macros = { path = "../gpui_macros" } · 18 unmodified lines
1919 util = { path = "../util" }
2020 sum_tree = { path = "../sum_tree" }
2121 sqlez = { path = "../sqlez" }
22−async-task = "4.0.3"
22+async-task = "4.7"
2323 backtrace = { version = "0.3", optional = true }
2424 ctor.workspace = true
2525 linkme = "0.3"
crates/gpui/src/app/entity_map.rs+4−3
@@ -1,8 +1,6 @@
11 use crate::{private::Sealed, AppContext, Context, Entity, ModelContext};
22 use anyhow::{anyhow, Result};
3−use collections::HashMap;
43 use derive_more::{Deref, DerefMut};
5−use lazy_static::lazy_static;
64 use parking_lot::{RwLock, RwLockUpgradableReadGuard};
75 use slotmap::{SecondaryMap, SlotMap};
86 use std::{
@@ -18,6 +16,9 @@ use std::{ · 9 unmodified lines
1816 thread::panicking,
1917 };
2018
19+#[cfg(any(test, feature = "test-support"))]
20+use collections::HashMap;
21+
2122 slotmap::new_key_type! { pub struct EntityId; }
2223
2324 impl EntityId {
@@ -600,7 +601,7 @@ impl<T> PartialEq<Model<T>> for WeakModel<T> { · 576 unmodified lines
600601 }
601602
602603 #[cfg(any(test, feature = "test-support"))]
603−lazy_static! {
604+lazy_static::lazy_static! {
604605 static ref LEAK_BACKTRACE: bool =
605606 std::env::var("LEAK_BACKTRACE").map_or(false, |b| !b.is_empty());
606607 }
crates/gpui/src/platform/mac/dispatcher.rs+5−5
@@ -11,7 +11,7 @@ use objc::{ · 10 unmodified lines
1111 };
1212 use parking::{Parker, Unparker};
1313 use parking_lot::Mutex;
14−use std::{ffi::c_void, sync::Arc, time::Duration};
14+use std::{ffi::c_void, ptr::NonNull, sync::Arc, time::Duration};
1515
1616 include!(concat!(env!("OUT_DIR"), "/dispatch_sys.rs"));
1717
@@ -47,7 +47,7 @@ impl PlatformDispatcher for MacDispatcher { · 29 unmodified lines
4747 unsafe {
4848 dispatch_async_f(
4949 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,
5151 Some(trampoline),
5252 );
5353 }
@@ -57,7 +57,7 @@ impl PlatformDispatcher for MacDispatcher { · 3 unmodified lines
5757 unsafe {
5858 dispatch_async_f(
5959 dispatch_get_main_queue(),
60− runnable.into_raw() as *mut c_void,
60+ runnable.into_raw().as_ptr() as *mut c_void,
6161 Some(trampoline),
6262 );
6363 }
@@ -71,7 +71,7 @@ impl PlatformDispatcher for MacDispatcher { · 7 unmodified lines
7171 dispatch_after_f(
7272 when,
7373 queue,
74− runnable.into_raw() as *mut c_void,
74+ runnable.into_raw().as_ptr() as *mut c_void,
7575 Some(trampoline),
7676 );
7777 }
@@ -91,6 +91,6 @@ impl PlatformDispatcher for MacDispatcher { · 13 unmodified lines
9191 }
9292
9393 extern "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 ())) };
9595 task.run();
9696 }
crates/search/src/project_search.rs+286−18
@@ -61,12 +61,12 @@ struct ActiveSearches(HashMap<WeakModel<Project>, WeakView<ProjectSearchView>>); · 60 unmodified lines
6161 struct ActiveSettings(HashMap<WeakModel<Project>, ProjectSearchSettings>);
6262
6363 pub fn init(cx: &mut AppContext) {
64− // todo!() po
6564 cx.set_global(ActiveSearches::default());
6665 cx.set_global(ActiveSettings::default());
6766 cx.observe_new_views(|workspace: &mut Workspace, _cx| {
6867 workspace
69− .register_action(ProjectSearchView::deploy)
68+ .register_action(ProjectSearchView::new_search)
69+ .register_action(ProjectSearchView::deploy_search)
7070 .register_action(ProjectSearchBar::search_in_new);
7171 })
7272 .detach();
@@ -941,11 +941,41 @@ impl ProjectSearchView { · 868 unmodified lines
941941 });
942942 }
943943
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+
944966 // Add another search tab to the workspace.
945− fn deploy(
967+ fn new_search(
946968 workspace: &mut Workspace,
947969 _: &workspace::NewSearch,
948970 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>,
949979 ) {
950980 // Clean up entries for dropped projects
951981 cx.update_global(|state: &mut ActiveSearches, _cx| {
@@ -962,19 +992,27 @@ impl ProjectSearchView { · 10 unmodified lines
962992 }
963993 });
964994
965− let settings = cx
966− .global::<ActiveSettings>()
967− .0
968− .get(&workspace.project().downgrade());
969−
970− let settings = if let Some(settings) = settings {
971− Some(settings.clone())
995+ let search = if let Some(existing) = existing {
996+ workspace.activate_item(&existing, cx);
997+ existing
972998 } else {
973− None
974− };
999+ let settings = cx
1000+ .global::<ActiveSettings>()
1001+ .0
1002+ .get(&workspace.project().downgrade());
9751003
976− let model = cx.new_model(|cx| ProjectSearch::new(workspace.project().clone(), cx));
977− let search = cx.new_view(|cx| ProjectSearchView::new(model, cx, settings));
1004+ let settings = if let Some(settings) = 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+ };
9781016
9791017 workspace.add_item(Box::new(search.clone()), cx);
9801018
@@ -2060,7 +2098,237 @@ pub mod tests { · 1079 unmodified lines
20602098 }
20612099
20622100 #[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) {
20642332 init_test(cx);
20652333
20662334 let fs = FakeFs::new(cx.background_executor.clone());
@@ -2101,7 +2369,7 @@ pub mod tests { · 34 unmodified lines
21012369 .update(cx, |toolbar, cx| toolbar.add_item(search_bar, cx))
21022370 });
21032371
2104− ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx)
2372+ ProjectSearchView::new_search(workspace, &workspace::NewSearch, cx)
21052373 })
21062374 .unwrap();
21072375
@@ -2250,7 +2518,7 @@ pub mod tests { · 142 unmodified lines
22502518
22512519 workspace
22522520 .update(cx, |workspace, cx| {
2253− ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx)
2521+ ProjectSearchView::new_search(workspace, &workspace::NewSearch, cx)
22542522 })
22552523 .unwrap();
22562524 cx.background_executor.run_until_parked();
@@ -2536,7 +2804,7 @@ pub mod tests { · 279 unmodified lines
25362804 .update(cx, |toolbar, cx| toolbar.add_item(search_bar, cx))
25372805 });
25382806
2539− ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx)
2807+ ProjectSearchView::new_search(workspace, &workspace::NewSearch, cx)
25402808 }
25412809 })
25422810 .unwrap();
crates/terminal_view/src/terminal_panel.rs+7−4
@@ -53,7 +53,7 @@ pub struct TerminalPanel { · 52 unmodified lines
5353
5454 impl TerminalPanel {
5555 fn new(workspace: &Workspace, cx: &mut ViewContext<Self>) -> Self {
56− let terminal_panel = cx.view().clone();
56+ let terminal_panel = cx.view().downgrade();
5757 let pane = cx.new_view(|cx| {
5858 let mut pane = Pane::new(
5959 workspace.weak_handle(),
@@ -77,14 +77,17 @@ impl TerminalPanel { · 17 unmodified lines
7777 pane.set_can_navigate(false, cx);
7878 pane.display_nav_history_buttons(false);
7979 pane.set_render_tab_bar_buttons(cx, move |pane, cx| {
80+ let terminal_panel = terminal_panel.clone();
8081 h_stack()
8182 .gap_2()
8283 .child(
8384 IconButton::new("plus", Icon::Plus)
8485 .icon_size(IconSize::Small)
85− .on_click(cx.listener_for(&terminal_panel, |terminal_panel, _, cx| {
86− terminal_panel.add_terminal(None, cx);
87− }))
86+ .on_click(move |_, cx| {
87+ terminal_panel
88+ .update(cx, |panel, cx| panel.add_terminal(None, cx))
89+ .log_err();
90+ })
8891 .tooltip(|cx| Tooltip::text("New Terminal", cx)),
8992 )
9093 .child({
crates/workspace/src/pane.rs+6−1
@@ -1128,7 +1128,12 @@ impl Pane { · 1127 unmodified lines
11281128 if self.items.len() == 1 && should_activate {
11291129 self.focus_handle.focus(cx);
11301130 } 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+ );
11321137 }
11331138 }
11341139
crates/workspace/src/pane_group.rs+9−1
@@ -246,7 +246,15 @@ impl Member { · 245 unmodified lines
246246 .size_full()
247247 .child(pane.clone())
248248 .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+ )
250258 })
251259 .when_some(leader_status_box, |this, status_box| {
252260 this.child(
crates/workspace/src/workspace.rs+1−0
@@ -107,6 +107,7 @@ actions!( · 106 unmodified lines
107107 NewCenterTerminal,
108108 ToggleTerminalFocus,
109109 NewSearch,
110+ DeploySearch,
110111 Feedback,
111112 Restart,
112113 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