Merge pull request #1467 from zed-industries/new-button
Add discoverable 'New' button
This commit is contained in:
commit
5a372cecaa
9 changed files with 87 additions and 18 deletions
|
@ -31,7 +31,7 @@
|
||||||
"cmd-n": "workspace::NewFile",
|
"cmd-n": "workspace::NewFile",
|
||||||
"cmd-shift-n": "workspace::NewWindow",
|
"cmd-shift-n": "workspace::NewWindow",
|
||||||
"cmd-o": "workspace::Open",
|
"cmd-o": "workspace::Open",
|
||||||
"ctrl-`": "terminal::Deploy"
|
"ctrl-`": "workspace::NewTerminal"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -300,7 +300,7 @@
|
||||||
8
|
8
|
||||||
],
|
],
|
||||||
"cmd-b": "workspace::ToggleLeftSidebar",
|
"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-t": "theme_selector::Toggle",
|
||||||
"cmd-k cmd-s": "zed::OpenKeymap",
|
"cmd-k cmd-s": "zed::OpenKeymap",
|
||||||
"cmd-t": "project_symbols::Toggle",
|
"cmd-t": "project_symbols::Toggle",
|
||||||
|
|
|
@ -22,6 +22,7 @@ pub fn init(cx: &mut MutableAppContext) {
|
||||||
cx.add_action(ContextMenu::cancel);
|
cx.add_action(ContextMenu::cancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
pub enum ContextMenuItem {
|
pub enum ContextMenuItem {
|
||||||
Item {
|
Item {
|
||||||
label: String,
|
label: String,
|
||||||
|
@ -258,6 +259,7 @@ impl ContextMenu {
|
||||||
let style = style
|
let style = style
|
||||||
.item
|
.item
|
||||||
.style_for(Default::default(), Some(ix) == self.selected_index);
|
.style_for(Default::default(), Some(ix) == self.selected_index);
|
||||||
|
|
||||||
Label::new(label.to_string(), style.label.clone())
|
Label::new(label.to_string(), style.label.clone())
|
||||||
.contained()
|
.contained()
|
||||||
.with_style(style.container)
|
.with_style(style.container)
|
||||||
|
@ -319,9 +321,12 @@ impl ContextMenu {
|
||||||
MouseEventHandler::new::<MenuItem, _, _>(ix, cx, |state, _| {
|
MouseEventHandler::new::<MenuItem, _, _>(ix, cx, |state, _| {
|
||||||
let style =
|
let style =
|
||||||
style.item.style_for(state, Some(ix) == self.selected_index);
|
style.item.style_for(state, Some(ix) == self.selected_index);
|
||||||
|
|
||||||
Flex::row()
|
Flex::row()
|
||||||
.with_child(
|
.with_child(
|
||||||
Label::new(label.to_string(), style.label.clone()).boxed(),
|
Label::new(label.to_string(), style.label.clone())
|
||||||
|
.contained()
|
||||||
|
.boxed(),
|
||||||
)
|
)
|
||||||
.with_child({
|
.with_child({
|
||||||
KeystrokeLabel::new(
|
KeystrokeLabel::new(
|
||||||
|
|
|
@ -24,7 +24,7 @@ use workspace::{
|
||||||
Item, ItemHandle, ItemNavHistory, Pane, ToolbarItemLocation, ToolbarItemView, Workspace,
|
Item, ItemHandle, ItemNavHistory, Pane, ToolbarItemLocation, ToolbarItemView, Workspace,
|
||||||
};
|
};
|
||||||
|
|
||||||
actions!(project_search, [Deploy, SearchInNew, ToggleFocus]);
|
actions!(project_search, [SearchInNew, ToggleFocus]);
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct ActiveSearches(HashMap<WeakModelHandle<Project>, WeakViewHandle<ProjectSearchView>>);
|
struct ActiveSearches(HashMap<WeakModelHandle<Project>, WeakViewHandle<ProjectSearchView>>);
|
||||||
|
@ -431,7 +431,11 @@ impl ProjectSearchView {
|
||||||
|
|
||||||
// Re-activate the most recently activated search or the most recent if it has been closed.
|
// 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.
|
// If no search exists in the workspace, create a new one.
|
||||||
fn deploy(workspace: &mut Workspace, _: &Deploy, cx: &mut ViewContext<Workspace>) {
|
fn deploy(
|
||||||
|
workspace: &mut Workspace,
|
||||||
|
_: &workspace::NewSearch,
|
||||||
|
cx: &mut ViewContext<Workspace>,
|
||||||
|
) {
|
||||||
// Clean up entries for dropped projects
|
// Clean up entries for dropped projects
|
||||||
cx.update_global(|state: &mut ActiveSearches, cx| {
|
cx.update_global(|state: &mut ActiveSearches, cx| {
|
||||||
state.0.retain(|project, _| project.is_upgradable(cx))
|
state.0.retain(|project, _| project.is_upgradable(cx))
|
||||||
|
|
|
@ -5,17 +5,17 @@ use gpui::{
|
||||||
actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, View, ViewContext,
|
actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, View, ViewContext,
|
||||||
ViewHandle,
|
ViewHandle,
|
||||||
};
|
};
|
||||||
|
use workspace::{Item, Workspace};
|
||||||
|
|
||||||
use crate::TerminalSize;
|
use crate::TerminalSize;
|
||||||
use project::{LocalWorktree, Project, ProjectPath};
|
use project::{LocalWorktree, Project, ProjectPath};
|
||||||
use settings::{Settings, WorkingDirectory};
|
use settings::{Settings, WorkingDirectory};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use workspace::{Item, Workspace};
|
|
||||||
|
|
||||||
use crate::connected_el::TerminalEl;
|
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
|
//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'
|
//Take away all the result unwrapping in the current TerminalView by making it 'infallible'
|
||||||
|
@ -59,7 +59,11 @@ impl Entity for ErrorView {
|
||||||
|
|
||||||
impl TerminalView {
|
impl TerminalView {
|
||||||
///Create a new Terminal in the current working directory or the user's home directory
|
///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<Workspace>) {
|
pub fn deploy(
|
||||||
|
workspace: &mut Workspace,
|
||||||
|
_: &workspace::NewTerminal,
|
||||||
|
cx: &mut ViewContext<Workspace>,
|
||||||
|
) {
|
||||||
let strategy = cx
|
let strategy = cx
|
||||||
.global::<Settings>()
|
.global::<Settings>()
|
||||||
.terminal_overrides
|
.terminal_overrides
|
||||||
|
|
|
@ -267,6 +267,8 @@ pub struct ContextMenuItem {
|
||||||
pub container: ContainerStyle,
|
pub container: ContainerStyle,
|
||||||
pub label: TextStyle,
|
pub label: TextStyle,
|
||||||
pub keystroke: ContainedText,
|
pub keystroke: ContainedText,
|
||||||
|
pub icon_width: f32,
|
||||||
|
pub icon_spacing: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Default)]
|
#[derive(Debug, Deserialize, Default)]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::{ItemHandle, SplitDirection};
|
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 anyhow::Result;
|
||||||
use collections::{HashMap, HashSet, VecDeque};
|
use collections::{HashMap, HashSet, VecDeque};
|
||||||
use context_menu::{ContextMenu, ContextMenuItem};
|
use context_menu::{ContextMenu, ContextMenuItem};
|
||||||
|
@ -65,8 +65,13 @@ pub struct DeploySplitMenu {
|
||||||
position: Vector2F,
|
position: Vector2F,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub struct DeployNewMenu {
|
||||||
|
position: Vector2F,
|
||||||
|
}
|
||||||
|
|
||||||
impl_actions!(pane, [GoBack, GoForward, ActivateItem]);
|
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;
|
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, _: &SplitRight, cx| pane.split(SplitDirection::Right, cx));
|
||||||
cx.add_action(|pane: &mut Pane, _: &SplitDown, cx| pane.split(SplitDirection::Down, 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_split_menu);
|
||||||
|
cx.add_action(Pane::deploy_new_menu);
|
||||||
cx.add_action(|workspace: &mut Workspace, _: &ReopenClosedItem, cx| {
|
cx.add_action(|workspace: &mut Workspace, _: &ReopenClosedItem, cx| {
|
||||||
Pane::reopen_closed_item(workspace, cx).detach();
|
Pane::reopen_closed_item(workspace, cx).detach();
|
||||||
});
|
});
|
||||||
|
@ -141,7 +147,7 @@ pub struct Pane {
|
||||||
autoscroll: bool,
|
autoscroll: bool,
|
||||||
nav_history: Rc<RefCell<NavHistory>>,
|
nav_history: Rc<RefCell<NavHistory>>,
|
||||||
toolbar: ViewHandle<Toolbar>,
|
toolbar: ViewHandle<Toolbar>,
|
||||||
split_menu: ViewHandle<ContextMenu>,
|
context_menu: ViewHandle<ContextMenu>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ItemNavHistory {
|
pub struct ItemNavHistory {
|
||||||
|
@ -182,7 +188,7 @@ pub struct NavigationEntry {
|
||||||
impl Pane {
|
impl Pane {
|
||||||
pub fn new(cx: &mut ViewContext<Self>) -> Self {
|
pub fn new(cx: &mut ViewContext<Self>) -> Self {
|
||||||
let handle = cx.weak_handle();
|
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 {
|
Self {
|
||||||
items: Vec::new(),
|
items: Vec::new(),
|
||||||
is_active: true,
|
is_active: true,
|
||||||
|
@ -197,7 +203,7 @@ impl Pane {
|
||||||
pane: handle.clone(),
|
pane: handle.clone(),
|
||||||
})),
|
})),
|
||||||
toolbar: cx.add_view(|_| Toolbar::new(handle)),
|
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>) {
|
fn deploy_split_menu(&mut self, action: &DeploySplitMenu, cx: &mut ViewContext<Self>) {
|
||||||
self.split_menu.update(cx, |menu, cx| {
|
self.context_menu.update(cx, |menu, cx| {
|
||||||
menu.show(
|
menu.show(
|
||||||
action.position,
|
action.position,
|
||||||
vec![
|
vec![
|
||||||
|
@ -845,6 +851,20 @@ impl Pane {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deploy_new_menu(&mut self, action: &DeployNewMenu, cx: &mut ViewContext<Self>) {
|
||||||
|
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<Toolbar> {
|
pub fn toolbar(&self) -> &ViewHandle<Toolbar> {
|
||||||
&self.toolbar
|
&self.toolbar
|
||||||
}
|
}
|
||||||
|
@ -1083,10 +1103,40 @@ impl View for Pane {
|
||||||
.with_child(self.render_tabs(cx).flex(1., true).named("tabs"));
|
.with_child(self.render_tabs(cx).flex(1., true).named("tabs"));
|
||||||
|
|
||||||
if self.is_active {
|
if self.is_active {
|
||||||
tab_row.add_child(
|
tab_row.add_children([
|
||||||
MouseEventHandler::new::<SplitIcon, _, _>(
|
MouseEventHandler::new::<SplitIcon, _, _>(
|
||||||
0,
|
0,
|
||||||
cx,
|
cx,
|
||||||
|
|mouse_state, cx| {
|
||||||
|
let theme =
|
||||||
|
&cx.global::<Settings>().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::<SplitIcon, _, _>(
|
||||||
|
1,
|
||||||
|
cx,
|
||||||
|mouse_state, cx| {
|
|mouse_state, cx| {
|
||||||
let theme =
|
let theme =
|
||||||
&cx.global::<Settings>().theme.workspace.tab_bar;
|
&cx.global::<Settings>().theme.workspace.tab_bar;
|
||||||
|
@ -1114,7 +1164,7 @@ impl View for Pane {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.boxed(),
|
.boxed(),
|
||||||
)
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
tab_row
|
tab_row
|
||||||
|
@ -1155,7 +1205,7 @@ impl View for Pane {
|
||||||
})
|
})
|
||||||
.boxed(),
|
.boxed(),
|
||||||
)
|
)
|
||||||
.with_child(ChildView::new(&self.split_menu).boxed())
|
.with_child(ChildView::new(&self.context_menu).boxed())
|
||||||
.named("pane")
|
.named("pane")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,8 @@ actions!(
|
||||||
FollowNextCollaborator,
|
FollowNextCollaborator,
|
||||||
ToggleLeftSidebar,
|
ToggleLeftSidebar,
|
||||||
ToggleRightSidebar,
|
ToggleRightSidebar,
|
||||||
|
NewTerminal,
|
||||||
|
NewSearch
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,7 @@ pub fn menus() -> Vec<Menu<'static>> {
|
||||||
},
|
},
|
||||||
MenuItem::Action {
|
MenuItem::Action {
|
||||||
name: "Find In Project",
|
name: "Find In Project",
|
||||||
action: Box::new(search::project_search::Deploy),
|
action: Box::new(workspace::NewSearch),
|
||||||
},
|
},
|
||||||
MenuItem::Separator,
|
MenuItem::Separator,
|
||||||
MenuItem::Action {
|
MenuItem::Action {
|
||||||
|
|
|
@ -16,6 +16,8 @@ export default function contextMenu(theme: Theme) {
|
||||||
border: border(theme, "primary"),
|
border: border(theme, "primary"),
|
||||||
keystrokeMargin: 30,
|
keystrokeMargin: 30,
|
||||||
item: {
|
item: {
|
||||||
|
iconSpacing: 8,
|
||||||
|
iconWidth: 14,
|
||||||
padding: { left: 4, right: 4, top: 2, bottom: 2 },
|
padding: { left: 4, right: 4, top: 2, bottom: 2 },
|
||||||
cornerRadius: 6,
|
cornerRadius: 6,
|
||||||
label: text(theme, "sans", "primary", { size: "sm" }),
|
label: text(theme, "sans", "primary", { size: "sm" }),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue