diff --git a/assets/keymaps/default.json b/assets/keymaps/default.json index 63b00c1d9ecfd2f1df71cf8b0361c365a9b6be3d..2782dd7d6a76c47c3f1e13f739969f4d8586acc5 100644 --- a/assets/keymaps/default.json +++ b/assets/keymaps/default.json @@ -31,7 +31,7 @@ "cmd-n": "workspace::NewFile", "cmd-shift-n": "workspace::NewWindow", "cmd-o": "workspace::Open", - "ctrl-`": "terminal::Deploy" + "ctrl-`": "workspace::NewTerminal" } }, { @@ -300,7 +300,7 @@ 8 ], "cmd-b": "workspace::ToggleLeftSidebar", - "cmd-shift-f": "project_search::Deploy", + "cmd-shift-f": "workspace::NewSearch", "cmd-k cmd-t": "theme_selector::Toggle", "cmd-k cmd-s": "zed::OpenKeymap", "cmd-t": "project_symbols::Toggle", diff --git a/crates/context_menu/src/context_menu.rs b/crates/context_menu/src/context_menu.rs index 53f6bfe58776c221f9f1c761a8ffdfd78951c1c7..d49f817de64a2fd0d9817e101a37f124f4d75d91 100644 --- a/crates/context_menu/src/context_menu.rs +++ b/crates/context_menu/src/context_menu.rs @@ -22,6 +22,7 @@ pub fn init(cx: &mut MutableAppContext) { cx.add_action(ContextMenu::cancel); } +// pub enum ContextMenuItem { Item { label: String, @@ -258,6 +259,7 @@ impl ContextMenu { let style = style .item .style_for(Default::default(), Some(ix) == self.selected_index); + Label::new(label.to_string(), style.label.clone()) .contained() .with_style(style.container) @@ -319,9 +321,12 @@ impl ContextMenu { MouseEventHandler::new::(ix, cx, |state, _| { let style = style.item.style_for(state, Some(ix) == self.selected_index); + Flex::row() .with_child( - Label::new(label.to_string(), style.label.clone()).boxed(), + Label::new(label.to_string(), style.label.clone()) + .contained() + .boxed(), ) .with_child({ KeystrokeLabel::new( diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 0becd0d1840aa28b2f716ea5a20f65287dea27fe..ab130c135081f4b88225b2dbfc9e1409fb1baa46 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -24,7 +24,7 @@ use workspace::{ Item, ItemHandle, ItemNavHistory, Pane, ToolbarItemLocation, ToolbarItemView, Workspace, }; -actions!(project_search, [Deploy, SearchInNew, ToggleFocus]); +actions!(project_search, [SearchInNew, ToggleFocus]); #[derive(Default)] struct ActiveSearches(HashMap, WeakViewHandle>); @@ -431,7 +431,11 @@ 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(workspace: &mut Workspace, _: &Deploy, cx: &mut ViewContext) { + fn deploy( + workspace: &mut Workspace, + _: &workspace::NewSearch, + cx: &mut ViewContext, + ) { // Clean up entries for dropped projects cx.update_global(|state: &mut ActiveSearches, cx| { state.0.retain(|project, _| project.is_upgradable(cx)) diff --git a/crates/terminal/src/terminal_view.rs b/crates/terminal/src/terminal_view.rs index 8acf1c233acf822931ce7864eef731d1c1446b1a..40a882e4885ddda8fd992d069e0d5e292638bec9 100644 --- a/crates/terminal/src/terminal_view.rs +++ b/crates/terminal/src/terminal_view.rs @@ -5,17 +5,17 @@ use gpui::{ actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, View, ViewContext, ViewHandle, }; +use workspace::{Item, Workspace}; use crate::TerminalSize; use project::{LocalWorktree, Project, ProjectPath}; use settings::{Settings, WorkingDirectory}; use smallvec::SmallVec; use std::path::{Path, PathBuf}; -use workspace::{Item, Workspace}; use crate::connected_el::TerminalEl; -actions!(terminal, [Deploy, DeployModal]); +actions!(terminal, [DeployModal]); //Make terminal view an enum, that can give you views for the error and non-error states //Take away all the result unwrapping in the current TerminalView by making it 'infallible' @@ -59,7 +59,11 @@ impl Entity for ErrorView { impl TerminalView { ///Create a new Terminal in the current working directory or the user's home directory - pub fn deploy(workspace: &mut Workspace, _: &Deploy, cx: &mut ViewContext) { + pub fn deploy( + workspace: &mut Workspace, + _: &workspace::NewTerminal, + cx: &mut ViewContext, + ) { let strategy = cx .global::() .terminal_overrides diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 349a505a08d0cb52b04ce5256530b92fb71e55fa..1aaeed2d7829739c4006f6aa645a89f739012367 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -267,6 +267,8 @@ pub struct ContextMenuItem { pub container: ContainerStyle, pub label: TextStyle, pub keystroke: ContainedText, + pub icon_width: f32, + pub icon_spacing: f32, } #[derive(Debug, Deserialize, Default)] diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 7ba8badc9dce7d39d85c552574433a45cd558e53..a05b9ac1a822b34e36701b226085c95d287ce98c 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1,5 +1,5 @@ use super::{ItemHandle, SplitDirection}; -use crate::{toolbar::Toolbar, Item, WeakItemHandle, Workspace}; +use crate::{toolbar::Toolbar, Item, NewFile, NewSearch, NewTerminal, WeakItemHandle, Workspace}; use anyhow::Result; use collections::{HashMap, HashSet, VecDeque}; use context_menu::{ContextMenu, ContextMenuItem}; @@ -65,8 +65,13 @@ pub struct DeploySplitMenu { position: Vector2F, } +#[derive(Clone, PartialEq)] +pub struct DeployNewMenu { + position: Vector2F, +} + impl_actions!(pane, [GoBack, GoForward, ActivateItem]); -impl_internal_actions!(pane, [CloseItem, DeploySplitMenu]); +impl_internal_actions!(pane, [CloseItem, DeploySplitMenu, DeployNewMenu]); const MAX_NAVIGATION_HISTORY_LEN: usize = 1024; @@ -98,6 +103,7 @@ pub fn init(cx: &mut MutableAppContext) { cx.add_action(|pane: &mut Pane, _: &SplitRight, cx| pane.split(SplitDirection::Right, cx)); cx.add_action(|pane: &mut Pane, _: &SplitDown, cx| pane.split(SplitDirection::Down, cx)); cx.add_action(Pane::deploy_split_menu); + cx.add_action(Pane::deploy_new_menu); cx.add_action(|workspace: &mut Workspace, _: &ReopenClosedItem, cx| { Pane::reopen_closed_item(workspace, cx).detach(); }); @@ -141,7 +147,7 @@ pub struct Pane { autoscroll: bool, nav_history: Rc>, toolbar: ViewHandle, - split_menu: ViewHandle, + context_menu: ViewHandle, } pub struct ItemNavHistory { @@ -182,7 +188,7 @@ pub struct NavigationEntry { impl Pane { pub fn new(cx: &mut ViewContext) -> Self { let handle = cx.weak_handle(); - let split_menu = cx.add_view(|cx| ContextMenu::new(cx)); + let context_menu = cx.add_view(|cx| ContextMenu::new(cx)); Self { items: Vec::new(), is_active: true, @@ -197,7 +203,7 @@ impl Pane { pane: handle.clone(), })), toolbar: cx.add_view(|_| Toolbar::new(handle)), - split_menu, + context_menu, } } @@ -831,7 +837,7 @@ impl Pane { } fn deploy_split_menu(&mut self, action: &DeploySplitMenu, cx: &mut ViewContext) { - self.split_menu.update(cx, |menu, cx| { + self.context_menu.update(cx, |menu, cx| { menu.show( action.position, vec![ @@ -845,6 +851,20 @@ impl Pane { }); } + fn deploy_new_menu(&mut self, action: &DeployNewMenu, cx: &mut ViewContext) { + self.context_menu.update(cx, |menu, cx| { + menu.show( + action.position, + vec![ + ContextMenuItem::item("New File", NewFile), + ContextMenuItem::item("New Terminal", NewTerminal), + ContextMenuItem::item("New Search", NewSearch), + ], + cx, + ); + }); + } + pub fn toolbar(&self) -> &ViewHandle { &self.toolbar } @@ -1083,10 +1103,40 @@ impl View for Pane { .with_child(self.render_tabs(cx).flex(1., true).named("tabs")); if self.is_active { - tab_row.add_child( + tab_row.add_children([ MouseEventHandler::new::( 0, cx, + |mouse_state, cx| { + let theme = + &cx.global::().theme.workspace.tab_bar; + let style = + theme.pane_button.style_for(mouse_state, false); + Svg::new("icons/plus_12.svg") + .with_color(style.color) + .constrained() + .with_width(style.icon_width) + .aligned() + .contained() + .with_style(style.container) + .constrained() + .with_width(style.button_width) + .with_height(style.button_width) + .aligned() + .boxed() + }, + ) + .with_cursor_style(CursorStyle::PointingHand) + .on_down( + MouseButton::Left, + |MouseButtonEvent { position, .. }, cx| { + cx.dispatch_action(DeployNewMenu { position }); + }, + ) + .boxed(), + MouseEventHandler::new::( + 1, + cx, |mouse_state, cx| { let theme = &cx.global::().theme.workspace.tab_bar; @@ -1114,7 +1164,7 @@ impl View for Pane { }, ) .boxed(), - ) + ]) } tab_row @@ -1155,7 +1205,7 @@ impl View for Pane { }) .boxed(), ) - .with_child(ChildView::new(&self.split_menu).boxed()) + .with_child(ChildView::new(&self.context_menu).boxed()) .named("pane") } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index c060f57072692767305e12e55fed7c2c80ce7481..045e9c6f90de3cc5ed54411607519391a76fea6b 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -96,6 +96,8 @@ actions!( FollowNextCollaborator, ToggleLeftSidebar, ToggleRightSidebar, + NewTerminal, + NewSearch ] ); diff --git a/crates/zed/src/menus.rs b/crates/zed/src/menus.rs index f4a5e5e24dfd270430b593429e52a7735c9dde6f..71ab1d14e5213a73c0214778811843d2fda60a1a 100644 --- a/crates/zed/src/menus.rs +++ b/crates/zed/src/menus.rs @@ -136,7 +136,7 @@ pub fn menus() -> Vec> { }, MenuItem::Action { name: "Find In Project", - action: Box::new(search::project_search::Deploy), + action: Box::new(workspace::NewSearch), }, MenuItem::Separator, MenuItem::Action { diff --git a/styles/src/styleTree/contextMenu.ts b/styles/src/styleTree/contextMenu.ts index 0244641ec77ec62d21160ef719ac14b7d3b0c895..6236c2bc602371838bd28c4d708c9696556eca29 100644 --- a/styles/src/styleTree/contextMenu.ts +++ b/styles/src/styleTree/contextMenu.ts @@ -16,6 +16,8 @@ export default function contextMenu(theme: Theme) { border: border(theme, "primary"), keystrokeMargin: 30, item: { + iconSpacing: 8, + iconWidth: 14, padding: { left: 4, right: 4, top: 2, bottom: 2 }, cornerRadius: 6, label: text(theme, "sans", "primary", { size: "sm" }),