mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-07 20:39:04 +03:00
Merge branch 'main' into copilot-ui
This commit is contained in:
commit
316d48393a
5
Cargo.lock
generated
5
Cargo.lock
generated
@ -576,8 +576,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "4.0.3"
|
||||
source = "git+https://github.com/zed-industries/async-task?rev=341b57d6de98cdfd7b418567b8de2022ca993a6e#341b57d6de98cdfd7b418567b8de2022ca993a6e"
|
||||
version = "4.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799"
|
||||
|
||||
[[package]]
|
||||
name = "async-tls"
|
||||
|
@ -164,7 +164,6 @@ tree-sitter-uiua = {git = "https://github.com/shnarazk/tree-sitter-uiua", rev =
|
||||
|
||||
[patch.crates-io]
|
||||
tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "31c40449749c4263a91a43593831b82229049a4c" }
|
||||
async-task = { git = "https://github.com/zed-industries/async-task", rev = "341b57d6de98cdfd7b418567b8de2022ca993a6e" }
|
||||
# wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", rev = "v16.0.0" }
|
||||
|
||||
# TODO - Remove when a version is released with this PR: https://github.com/servo/core-foundation-rs/pull/457
|
||||
|
@ -402,7 +402,7 @@
|
||||
"cmd-r": "workspace::ToggleRightDock",
|
||||
"cmd-j": "workspace::ToggleBottomDock",
|
||||
"alt-cmd-y": "workspace::CloseAllDocks",
|
||||
"cmd-shift-f": "workspace::NewSearch",
|
||||
"cmd-shift-f": "workspace::DeploySearch",
|
||||
"cmd-k cmd-t": "theme_selector::Toggle",
|
||||
"cmd-k cmd-s": "zed::OpenKeymap",
|
||||
"cmd-t": "project_symbols::Toggle",
|
||||
|
@ -15,9 +15,11 @@ use language::{
|
||||
proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, CharKind, OffsetRangeExt,
|
||||
Point, SelectionGoal,
|
||||
};
|
||||
use project::repository::GitFileStatus;
|
||||
use project::{search::SearchQuery, FormatTrigger, Item as _, Project, ProjectPath};
|
||||
use rpc::proto::{self, update_view, PeerId};
|
||||
use settings::Settings;
|
||||
use workspace::item::ItemSettings;
|
||||
|
||||
use std::fmt::Write;
|
||||
use std::{
|
||||
@ -29,7 +31,7 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
use text::Selection;
|
||||
use theme::{ActiveTheme, Theme};
|
||||
use theme::Theme;
|
||||
use ui::{h_stack, prelude::*, Label};
|
||||
use util::{paths::PathExt, paths::FILE_ROW_COLUMN_DELIMITER, ResultExt, TryFutureExt};
|
||||
use workspace::{
|
||||
@ -579,7 +581,28 @@ impl Item for Editor {
|
||||
}
|
||||
|
||||
fn tab_content(&self, detail: Option<usize>, selected: bool, cx: &WindowContext) -> AnyElement {
|
||||
let _theme = cx.theme();
|
||||
let git_status = if ItemSettings::get_global(cx).git_status {
|
||||
self.buffer()
|
||||
.read(cx)
|
||||
.as_singleton()
|
||||
.and_then(|buffer| buffer.read(cx).project_path(cx))
|
||||
.and_then(|path| self.project.as_ref()?.read(cx).entry_for_path(&path, cx))
|
||||
.and_then(|entry| entry.git_status())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let label_color = match git_status {
|
||||
Some(GitFileStatus::Added) => Color::Created,
|
||||
Some(GitFileStatus::Modified) => Color::Modified,
|
||||
Some(GitFileStatus::Conflict) => Color::Conflict,
|
||||
None => {
|
||||
if selected {
|
||||
Color::Default
|
||||
} else {
|
||||
Color::Muted
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let description = detail.and_then(|detail| {
|
||||
let path = path_for_buffer(&self.buffer, detail, false, cx)?;
|
||||
@ -595,11 +618,7 @@ impl Item for Editor {
|
||||
|
||||
h_stack()
|
||||
.gap_2()
|
||||
.child(Label::new(self.title(cx).to_string()).color(if selected {
|
||||
Color::Default
|
||||
} else {
|
||||
Color::Muted
|
||||
}))
|
||||
.child(Label::new(self.title(cx).to_string()).color(label_color))
|
||||
.when_some(description, |this, description| {
|
||||
this.child(
|
||||
Label::new(description)
|
||||
|
@ -19,7 +19,7 @@ gpui_macros = { path = "../gpui_macros" }
|
||||
util = { path = "../util" }
|
||||
sum_tree = { path = "../sum_tree" }
|
||||
sqlez = { path = "../sqlez" }
|
||||
async-task = "4.0.3"
|
||||
async-task = "4.7"
|
||||
backtrace = { version = "0.3", optional = true }
|
||||
ctor.workspace = true
|
||||
linkme = "0.3"
|
||||
|
@ -1,8 +1,6 @@
|
||||
use crate::{private::Sealed, AppContext, Context, Entity, ModelContext};
|
||||
use anyhow::{anyhow, Result};
|
||||
use collections::HashMap;
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
|
||||
use slotmap::{SecondaryMap, SlotMap};
|
||||
use std::{
|
||||
@ -18,6 +16,9 @@ use std::{
|
||||
thread::panicking,
|
||||
};
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
use collections::HashMap;
|
||||
|
||||
slotmap::new_key_type! { pub struct EntityId; }
|
||||
|
||||
impl EntityId {
|
||||
@ -600,7 +601,7 @@ impl<T> PartialEq<Model<T>> for WeakModel<T> {
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
lazy_static! {
|
||||
lazy_static::lazy_static! {
|
||||
static ref LEAK_BACKTRACE: bool =
|
||||
std::env::var("LEAK_BACKTRACE").map_or(false, |b| !b.is_empty());
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ use objc::{
|
||||
};
|
||||
use parking::{Parker, Unparker};
|
||||
use parking_lot::Mutex;
|
||||
use std::{ffi::c_void, sync::Arc, time::Duration};
|
||||
use std::{ffi::c_void, ptr::NonNull, sync::Arc, time::Duration};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/dispatch_sys.rs"));
|
||||
|
||||
@ -47,7 +47,7 @@ impl PlatformDispatcher for MacDispatcher {
|
||||
unsafe {
|
||||
dispatch_async_f(
|
||||
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT.try_into().unwrap(), 0),
|
||||
runnable.into_raw() as *mut c_void,
|
||||
runnable.into_raw().as_ptr() as *mut c_void,
|
||||
Some(trampoline),
|
||||
);
|
||||
}
|
||||
@ -57,7 +57,7 @@ impl PlatformDispatcher for MacDispatcher {
|
||||
unsafe {
|
||||
dispatch_async_f(
|
||||
dispatch_get_main_queue(),
|
||||
runnable.into_raw() as *mut c_void,
|
||||
runnable.into_raw().as_ptr() as *mut c_void,
|
||||
Some(trampoline),
|
||||
);
|
||||
}
|
||||
@ -71,7 +71,7 @@ impl PlatformDispatcher for MacDispatcher {
|
||||
dispatch_after_f(
|
||||
when,
|
||||
queue,
|
||||
runnable.into_raw() as *mut c_void,
|
||||
runnable.into_raw().as_ptr() as *mut c_void,
|
||||
Some(trampoline),
|
||||
);
|
||||
}
|
||||
@ -91,6 +91,6 @@ impl PlatformDispatcher for MacDispatcher {
|
||||
}
|
||||
|
||||
extern "C" fn trampoline(runnable: *mut c_void) {
|
||||
let task = unsafe { Runnable::from_raw(runnable as *mut ()) };
|
||||
let task = unsafe { Runnable::<()>::from_raw(NonNull::new_unchecked(runnable as *mut ())) };
|
||||
task.run();
|
||||
}
|
||||
|
@ -61,12 +61,12 @@ struct ActiveSearches(HashMap<WeakModel<Project>, WeakView<ProjectSearchView>>);
|
||||
struct ActiveSettings(HashMap<WeakModel<Project>, ProjectSearchSettings>);
|
||||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
// todo!() po
|
||||
cx.set_global(ActiveSearches::default());
|
||||
cx.set_global(ActiveSettings::default());
|
||||
cx.observe_new_views(|workspace: &mut Workspace, _cx| {
|
||||
workspace
|
||||
.register_action(ProjectSearchView::deploy)
|
||||
.register_action(ProjectSearchView::new_search)
|
||||
.register_action(ProjectSearchView::deploy_search)
|
||||
.register_action(ProjectSearchBar::search_in_new);
|
||||
})
|
||||
.detach();
|
||||
@ -941,11 +941,41 @@ impl ProjectSearchView {
|
||||
});
|
||||
}
|
||||
|
||||
// Re-activate the most recently activated search or the most recent if it has been closed.
|
||||
// If no search exists in the workspace, create a new one.
|
||||
fn deploy_search(
|
||||
workspace: &mut Workspace,
|
||||
_: &workspace::DeploySearch,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) {
|
||||
let active_search = cx
|
||||
.global::<ActiveSearches>()
|
||||
.0
|
||||
.get(&workspace.project().downgrade());
|
||||
let existing = active_search
|
||||
.and_then(|active_search| {
|
||||
workspace
|
||||
.items_of_type::<ProjectSearchView>(cx)
|
||||
.filter(|search| &search.downgrade() == active_search)
|
||||
.last()
|
||||
})
|
||||
.or_else(|| workspace.item_of_type::<ProjectSearchView>(cx));
|
||||
Self::existing_or_new_search(workspace, existing, cx)
|
||||
}
|
||||
|
||||
// Add another search tab to the workspace.
|
||||
fn deploy(
|
||||
fn new_search(
|
||||
workspace: &mut Workspace,
|
||||
_: &workspace::NewSearch,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) {
|
||||
Self::existing_or_new_search(workspace, None, cx)
|
||||
}
|
||||
|
||||
fn existing_or_new_search(
|
||||
workspace: &mut Workspace,
|
||||
existing: Option<View<ProjectSearchView>>,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) {
|
||||
// Clean up entries for dropped projects
|
||||
cx.update_global(|state: &mut ActiveSearches, _cx| {
|
||||
@ -962,19 +992,27 @@ impl ProjectSearchView {
|
||||
}
|
||||
});
|
||||
|
||||
let settings = cx
|
||||
.global::<ActiveSettings>()
|
||||
.0
|
||||
.get(&workspace.project().downgrade());
|
||||
|
||||
let settings = if let Some(settings) = settings {
|
||||
Some(settings.clone())
|
||||
let search = if let Some(existing) = existing {
|
||||
workspace.activate_item(&existing, cx);
|
||||
existing
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let settings = cx
|
||||
.global::<ActiveSettings>()
|
||||
.0
|
||||
.get(&workspace.project().downgrade());
|
||||
|
||||
let model = cx.new_model(|cx| ProjectSearch::new(workspace.project().clone(), cx));
|
||||
let search = cx.new_view(|cx| ProjectSearchView::new(model, cx, settings));
|
||||
let settings = if let Some(settings) = settings {
|
||||
Some(settings.clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let model = cx.new_model(|cx| ProjectSearch::new(workspace.project().clone(), cx));
|
||||
let view = cx.new_view(|cx| ProjectSearchView::new(model, cx, settings));
|
||||
|
||||
workspace.add_item(Box::new(view.clone()), cx);
|
||||
view
|
||||
};
|
||||
|
||||
workspace.add_item(Box::new(search.clone()), cx);
|
||||
|
||||
@ -2060,7 +2098,7 @@ pub mod tests {
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_project_search_focus(cx: &mut TestAppContext) {
|
||||
async fn test_deploy_project_search_focus(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.background_executor.clone());
|
||||
@ -2101,7 +2139,237 @@ pub mod tests {
|
||||
.update(cx, |toolbar, cx| toolbar.add_item(search_bar, cx))
|
||||
});
|
||||
|
||||
ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx)
|
||||
ProjectSearchView::deploy_search(workspace, &workspace::DeploySearch, cx)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let Some(search_view) = cx.read(|cx| {
|
||||
workspace
|
||||
.read(cx)
|
||||
.unwrap()
|
||||
.active_pane()
|
||||
.read(cx)
|
||||
.active_item()
|
||||
.and_then(|item| item.downcast::<ProjectSearchView>())
|
||||
}) else {
|
||||
panic!("Search view expected to appear after new search event trigger")
|
||||
};
|
||||
|
||||
cx.spawn(|mut cx| async move {
|
||||
window
|
||||
.update(&mut cx, |_, cx| {
|
||||
cx.dispatch_action(ToggleFocus.boxed_clone())
|
||||
})
|
||||
.unwrap();
|
||||
})
|
||||
.detach();
|
||||
cx.background_executor.run_until_parked();
|
||||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_view.update(cx, |search_view, cx| {
|
||||
assert!(
|
||||
search_view.query_editor.focus_handle(cx).is_focused(cx),
|
||||
"Empty search view should be focused after the toggle focus event: no results panel to focus on",
|
||||
);
|
||||
});
|
||||
}).unwrap();
|
||||
|
||||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_view.update(cx, |search_view, cx| {
|
||||
let query_editor = &search_view.query_editor;
|
||||
assert!(
|
||||
query_editor.focus_handle(cx).is_focused(cx),
|
||||
"Search view should be focused after the new search view is activated",
|
||||
);
|
||||
let query_text = query_editor.read(cx).text(cx);
|
||||
assert!(
|
||||
query_text.is_empty(),
|
||||
"New search query should be empty but got '{query_text}'",
|
||||
);
|
||||
let results_text = search_view
|
||||
.results_editor
|
||||
.update(cx, |editor, cx| editor.display_text(cx));
|
||||
assert!(
|
||||
results_text.is_empty(),
|
||||
"Empty search view should have no results but got '{results_text}'"
|
||||
);
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_view.update(cx, |search_view, cx| {
|
||||
search_view.query_editor.update(cx, |query_editor, cx| {
|
||||
query_editor.set_text("sOMETHINGtHATsURELYdOESnOTeXIST", cx)
|
||||
});
|
||||
search_view.search(cx);
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
cx.background_executor.run_until_parked();
|
||||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_view.update(cx, |search_view, cx| {
|
||||
let results_text = search_view
|
||||
.results_editor
|
||||
.update(cx, |editor, cx| editor.display_text(cx));
|
||||
assert!(
|
||||
results_text.is_empty(),
|
||||
"Search view for mismatching query should have no results but got '{results_text}'"
|
||||
);
|
||||
assert!(
|
||||
search_view.query_editor.focus_handle(cx).is_focused(cx),
|
||||
"Search view should be focused after mismatching query had been used in search",
|
||||
);
|
||||
});
|
||||
}).unwrap();
|
||||
|
||||
cx.spawn(|mut cx| async move {
|
||||
window.update(&mut cx, |_, cx| {
|
||||
cx.dispatch_action(ToggleFocus.boxed_clone())
|
||||
})
|
||||
})
|
||||
.detach();
|
||||
cx.background_executor.run_until_parked();
|
||||
window.update(cx, |_, cx| {
|
||||
search_view.update(cx, |search_view, cx| {
|
||||
assert!(
|
||||
search_view.query_editor.focus_handle(cx).is_focused(cx),
|
||||
"Search view with mismatching query should be focused after the toggle focus event: still no results panel to focus on",
|
||||
);
|
||||
});
|
||||
}).unwrap();
|
||||
|
||||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_view.update(cx, |search_view, cx| {
|
||||
search_view
|
||||
.query_editor
|
||||
.update(cx, |query_editor, cx| query_editor.set_text("TWO", cx));
|
||||
search_view.search(cx);
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
cx.background_executor.run_until_parked();
|
||||
window.update(cx, |_, cx| {
|
||||
search_view.update(cx, |search_view, cx| {
|
||||
assert_eq!(
|
||||
search_view
|
||||
.results_editor
|
||||
.update(cx, |editor, cx| editor.display_text(cx)),
|
||||
"\n\nconst THREE: usize = one::ONE + two::TWO;\n\n\nconst TWO: usize = one::ONE + one::ONE;",
|
||||
"Search view results should match the query"
|
||||
);
|
||||
assert!(
|
||||
search_view.results_editor.focus_handle(cx).is_focused(cx),
|
||||
"Search view with mismatching query should be focused after search results are available",
|
||||
);
|
||||
});
|
||||
}).unwrap();
|
||||
cx.spawn(|mut cx| async move {
|
||||
window
|
||||
.update(&mut cx, |_, cx| {
|
||||
cx.dispatch_action(ToggleFocus.boxed_clone())
|
||||
})
|
||||
.unwrap();
|
||||
})
|
||||
.detach();
|
||||
cx.background_executor.run_until_parked();
|
||||
window.update(cx, |_, cx| {
|
||||
search_view.update(cx, |search_view, cx| {
|
||||
assert!(
|
||||
search_view.results_editor.focus_handle(cx).is_focused(cx),
|
||||
"Search view with matching query should still have its results editor focused after the toggle focus event",
|
||||
);
|
||||
});
|
||||
}).unwrap();
|
||||
|
||||
workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
ProjectSearchView::deploy_search(workspace, &workspace::DeploySearch, cx)
|
||||
})
|
||||
.unwrap();
|
||||
window.update(cx, |_, cx| {
|
||||
search_view.update(cx, |search_view, cx| {
|
||||
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");
|
||||
assert_eq!(
|
||||
search_view
|
||||
.results_editor
|
||||
.update(cx, |editor, cx| editor.display_text(cx)),
|
||||
"\n\nconst THREE: usize = one::ONE + two::TWO;\n\n\nconst TWO: usize = one::ONE + one::ONE;",
|
||||
"Results should be unchanged after search view 2nd open in a row"
|
||||
);
|
||||
assert!(
|
||||
search_view.query_editor.focus_handle(cx).is_focused(cx),
|
||||
"Focus should be moved into query editor again after search view 2nd open in a row"
|
||||
);
|
||||
});
|
||||
}).unwrap();
|
||||
|
||||
cx.spawn(|mut cx| async move {
|
||||
window
|
||||
.update(&mut cx, |_, cx| {
|
||||
cx.dispatch_action(ToggleFocus.boxed_clone())
|
||||
})
|
||||
.unwrap();
|
||||
})
|
||||
.detach();
|
||||
cx.background_executor.run_until_parked();
|
||||
window.update(cx, |_, cx| {
|
||||
search_view.update(cx, |search_view, cx| {
|
||||
assert!(
|
||||
search_view.results_editor.focus_handle(cx).is_focused(cx),
|
||||
"Search view with matching query should switch focus to the results editor after the toggle focus event",
|
||||
);
|
||||
});
|
||||
}).unwrap();
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_new_project_search_focus(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.background_executor.clone());
|
||||
fs.insert_tree(
|
||||
"/dir",
|
||||
json!({
|
||||
"one.rs": "const ONE: usize = 1;",
|
||||
"two.rs": "const TWO: usize = one::ONE + one::ONE;",
|
||||
"three.rs": "const THREE: usize = one::ONE + two::TWO;",
|
||||
"four.rs": "const FOUR: usize = one::ONE + three::THREE;",
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
|
||||
let window = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||
let workspace = window.clone();
|
||||
let search_bar = window.build_view(cx, |_| ProjectSearchBar::new());
|
||||
|
||||
let active_item = cx.read(|cx| {
|
||||
workspace
|
||||
.read(cx)
|
||||
.unwrap()
|
||||
.active_pane()
|
||||
.read(cx)
|
||||
.active_item()
|
||||
.and_then(|item| item.downcast::<ProjectSearchView>())
|
||||
});
|
||||
assert!(
|
||||
active_item.is_none(),
|
||||
"Expected no search panel to be active"
|
||||
);
|
||||
|
||||
window
|
||||
.update(cx, move |workspace, cx| {
|
||||
assert_eq!(workspace.panes().len(), 1);
|
||||
workspace.panes()[0].update(cx, move |pane, cx| {
|
||||
pane.toolbar()
|
||||
.update(cx, |toolbar, cx| toolbar.add_item(search_bar, cx))
|
||||
});
|
||||
|
||||
ProjectSearchView::new_search(workspace, &workspace::NewSearch, cx)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -2250,7 +2518,7 @@ pub mod tests {
|
||||
|
||||
workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx)
|
||||
ProjectSearchView::new_search(workspace, &workspace::NewSearch, cx)
|
||||
})
|
||||
.unwrap();
|
||||
cx.background_executor.run_until_parked();
|
||||
@ -2536,7 +2804,7 @@ pub mod tests {
|
||||
.update(cx, |toolbar, cx| toolbar.add_item(search_bar, cx))
|
||||
});
|
||||
|
||||
ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx)
|
||||
ProjectSearchView::new_search(workspace, &workspace::NewSearch, cx)
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
@ -53,7 +53,7 @@ pub struct TerminalPanel {
|
||||
|
||||
impl TerminalPanel {
|
||||
fn new(workspace: &Workspace, cx: &mut ViewContext<Self>) -> Self {
|
||||
let terminal_panel = cx.view().clone();
|
||||
let terminal_panel = cx.view().downgrade();
|
||||
let pane = cx.new_view(|cx| {
|
||||
let mut pane = Pane::new(
|
||||
workspace.weak_handle(),
|
||||
@ -77,14 +77,17 @@ impl TerminalPanel {
|
||||
pane.set_can_navigate(false, cx);
|
||||
pane.display_nav_history_buttons(false);
|
||||
pane.set_render_tab_bar_buttons(cx, move |pane, cx| {
|
||||
let terminal_panel = terminal_panel.clone();
|
||||
h_stack()
|
||||
.gap_2()
|
||||
.child(
|
||||
IconButton::new("plus", Icon::Plus)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click(cx.listener_for(&terminal_panel, |terminal_panel, _, cx| {
|
||||
terminal_panel.add_terminal(None, cx);
|
||||
}))
|
||||
.on_click(move |_, cx| {
|
||||
terminal_panel
|
||||
.update(cx, |panel, cx| panel.add_terminal(None, cx))
|
||||
.log_err();
|
||||
})
|
||||
.tooltip(|cx| Tooltip::text("New Terminal", cx)),
|
||||
)
|
||||
.child({
|
||||
|
@ -1128,7 +1128,12 @@ impl Pane {
|
||||
if self.items.len() == 1 && should_activate {
|
||||
self.focus_handle.focus(cx);
|
||||
} else {
|
||||
self.activate_item(index_to_activate, should_activate, should_activate, cx);
|
||||
self.activate_item(
|
||||
dbg!(index_to_activate),
|
||||
dbg!(should_activate),
|
||||
should_activate,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,7 +246,15 @@ impl Member {
|
||||
.size_full()
|
||||
.child(pane.clone())
|
||||
.when_some(leader_border, |this, color| {
|
||||
this.border_2().border_color(color)
|
||||
this.child(
|
||||
div()
|
||||
.absolute()
|
||||
.size_full()
|
||||
.left_0()
|
||||
.top_0()
|
||||
.border_2()
|
||||
.border_color(color),
|
||||
)
|
||||
})
|
||||
.when_some(leader_status_box, |this, status_box| {
|
||||
this.child(
|
||||
|
@ -107,6 +107,7 @@ actions!(
|
||||
NewCenterTerminal,
|
||||
ToggleTerminalFocus,
|
||||
NewSearch,
|
||||
DeploySearch,
|
||||
Feedback,
|
||||
Restart,
|
||||
Welcome,
|
||||
|
Loading…
Reference in New Issue
Block a user