Start working on command_palette2

This commit is contained in:
Piotr Osiewicz 2023-11-09 17:54:05 +01:00
parent ad3b0bd227
commit d184e0d426
11 changed files with 822 additions and 156 deletions

34
Cargo.lock generated
View File

@ -1880,6 +1880,30 @@ dependencies = [
"zed-actions",
]
[[package]]
name = "command_palette2"
version = "0.1.0"
dependencies = [
"anyhow",
"collections",
"ctor",
"editor2",
"env_logger 0.9.3",
"fuzzy2",
"gpui2",
"language2",
"picker2",
"project2",
"serde",
"serde_json",
"settings2",
"theme2",
"ui2",
"util",
"workspace2",
"zed_actions2",
]
[[package]]
name = "component_test"
version = "0.1.0"
@ -11362,6 +11386,7 @@ dependencies = [
"cli",
"client2",
"collections",
"command_palette2",
"copilot2",
"ctor",
"db2",
@ -11448,6 +11473,15 @@ dependencies = [
"util",
"uuid 1.4.1",
"workspace2",
"zed_actions2",
]
[[package]]
name = "zed_actions2"
version = "0.1.0"
dependencies = [
"gpui2",
"serde",
]
[[package]]

View File

@ -20,6 +20,7 @@ members = [
"crates/collab_ui",
"crates/collections",
"crates/command_palette",
"crates/command_palette2",
"crates/component_test",
"crates/context_menu",
"crates/copilot",
@ -110,7 +111,8 @@ members = [
"crates/xtask",
"crates/zed",
"crates/zed2",
"crates/zed-actions"
"crates/zed-actions",
"crates/zed_actions2"
]
default-members = ["crates/zed"]
resolver = "2"

View File

@ -387,7 +387,8 @@
}
},
{
"context": "Workspace",
// todo!() fix context
// "context": "Workspace",
"bindings": {
"cmd-1": ["workspace::ActivatePane", 0],
"cmd-2": ["workspace::ActivatePane", 1],

View File

@ -0,0 +1,34 @@
[package]
name = "command_palette2"
version = "0.1.0"
edition = "2021"
publish = false
[lib]
path = "src/command_palette.rs"
doctest = false
[dependencies]
collections = { path = "../collections" }
editor = { package = "editor2", path = "../editor2" }
fuzzy = { package = "fuzzy2", path = "../fuzzy2" }
gpui = { package = "gpui2", path = "../gpui2" }
picker = { package = "picker2", path = "../picker2" }
project = { package = "project2", path = "../project2" }
settings = { package = "settings2", path = "../settings2" }
ui = { package = "ui2", path = "../ui2" }
util = { path = "../util" }
theme = { package = "theme2", path = "../theme2" }
workspace = { package="workspace2", path = "../workspace2" }
zed_actions = { package = "zed_actions2", path = "../zed_actions2" }
anyhow.workspace = true
serde.workspace = true
[dev-dependencies]
gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] }
editor = { package = "editor2", path = "../editor2", features = ["test-support"] }
language = { package="language2", path = "../language2", features = ["test-support"] }
project = { package="project2", path = "../project2", features = ["test-support"] }
serde_json.workspace = true
workspace = { package="workspace2", path = "../workspace2", features = ["test-support"] }
ctor.workspace = true
env_logger.workspace = true

View File

@ -0,0 +1,542 @@
use anyhow::anyhow;
use collections::{CommandPaletteFilter, HashMap};
use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{
actions, div, Action, AnyElement, AnyWindowHandle, AppContext, BorrowWindow, Div, Element,
EventEmitter, FocusHandle, Keystroke, ParentElement, Render, View, ViewContext, VisualContext,
WeakView,
};
use picker::{Picker, PickerDelegate};
use std::cmp::{self, Reverse};
use ui::modal;
use util::{
channel::{parse_zed_link, ReleaseChannel, RELEASE_CHANNEL},
ResultExt,
};
use workspace::{ModalEvent, Workspace};
use zed_actions::OpenZedURL;
actions!(Toggle);
pub fn init(cx: &mut AppContext) {
dbg!("init");
cx.set_global(HitCounts::default());
cx.observe_new_views(
|workspace: &mut Workspace, _: &mut ViewContext<Workspace>| {
dbg!("new workspace found");
workspace
.modal_layer()
.register_modal(Toggle, |workspace, cx| {
dbg!("hitting cmd-shift-p");
let Some(focus_handle) = cx.focused() else {
return None;
};
Some(cx.build_view(|cx| {
let delegate =
CommandPaletteDelegate::new(cx.view().downgrade(), focus_handle);
CommandPalette::new(delegate, cx)
}))
});
},
)
.detach();
}
pub struct CommandPalette {
picker: View<Picker<CommandPaletteDelegate>>,
}
impl CommandPalette {
fn new(delegate: CommandPaletteDelegate, cx: &mut ViewContext<Self>) -> Self {
let picker = cx.build_view(|cx| Picker::new(delegate, cx));
Self { picker }
}
}
impl EventEmitter<ModalEvent> for CommandPalette {}
impl Render for CommandPalette {
type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
dbg!("Rendering");
modal(cx).w_96().child(self.picker.clone())
}
}
pub type CommandPaletteInterceptor =
Box<dyn Fn(&str, &AppContext) -> Option<CommandInterceptResult>>;
pub struct CommandInterceptResult {
pub action: Box<dyn Action>,
pub string: String,
pub positions: Vec<usize>,
}
pub struct CommandPaletteDelegate {
command_palette: WeakView<CommandPalette>,
actions: Vec<Command>,
matches: Vec<StringMatch>,
selected_ix: usize,
focus_handle: FocusHandle,
}
pub enum Event {
Dismissed,
Confirmed {
window: AnyWindowHandle,
focused_view_id: usize,
action: Box<dyn Action>,
},
}
struct Command {
name: String,
action: Box<dyn Action>,
keystrokes: Vec<Keystroke>,
}
impl Clone for Command {
fn clone(&self) -> Self {
Self {
name: self.name.clone(),
action: self.action.boxed_clone(),
keystrokes: self.keystrokes.clone(),
}
}
}
/// Hit count for each command in the palette.
/// We only account for commands triggered directly via command palette and not by e.g. keystrokes because
/// if an user already knows a keystroke for a command, they are unlikely to use a command palette to look for it.
#[derive(Default)]
struct HitCounts(HashMap<String, usize>);
impl CommandPaletteDelegate {
pub fn new(command_palette: WeakView<CommandPalette>, focus_handle: FocusHandle) -> Self {
Self {
command_palette,
actions: Default::default(),
matches: vec![StringMatch {
candidate_id: 0,
score: 0.,
positions: vec![],
string: "Foo my bar".into(),
}],
selected_ix: 0,
focus_handle,
}
}
}
impl PickerDelegate for CommandPaletteDelegate {
type ListItem = Div<Picker<Self>>;
fn match_count(&self) -> usize {
self.matches.len()
}
fn selected_index(&self) -> usize {
self.selected_ix
}
fn set_selected_index(&mut self, ix: usize, _: &mut ViewContext<Picker<Self>>) {
self.selected_ix = ix;
}
fn update_matches(
&mut self,
query: String,
cx: &mut ViewContext<Picker<Self>>,
) -> gpui::Task<()> {
let view_id = &self.focus_handle;
let window = cx.window();
cx.spawn(move |picker, mut cx| async move {
let mut actions = picker
.update(&mut cx, |this, _| this.delegate.actions.clone())
.expect("todo: handle picker no longer being around");
// _ = window
// .available_actions(view_id, &cx)
// .into_iter()
// .flatten()
// .filter_map(|(name, action, bindings)| {
// let filtered = cx.read(|cx| {
// if cx.has_global::<CommandPaletteFilter>() {
// let filter = cx.global::<CommandPaletteFilter>();
// filter.filtered_namespaces.contains(action.namespace())
// } else {
// false
// }
// });
// if filtered {
// None
// } else {
// Some(Command {
// name: humanize_action_name(name),
// action,
// keystrokes: bindings
// .iter()
// .map(|binding| binding.keystrokes())
// .last()
// .map_or(Vec::new(), |keystrokes| keystrokes.to_vec()),
// })
// }
// })
// .collect::<Vec<_>>();
cx.read_global::<HitCounts, _>(|hit_counts, _| {
actions.sort_by_key(|action| {
(
Reverse(hit_counts.0.get(&action.name).cloned()),
action.name.clone(),
)
});
})
.ok();
let candidates = actions
.iter()
.enumerate()
.map(|(ix, command)| StringMatchCandidate {
id: ix,
string: command.name.to_string(),
char_bag: command.name.chars().collect(),
})
.collect::<Vec<_>>();
let mut matches = if query.is_empty() {
candidates
.into_iter()
.enumerate()
.map(|(index, candidate)| StringMatch {
candidate_id: index,
string: candidate.string,
positions: Vec::new(),
score: 0.0,
})
.collect()
} else {
fuzzy::match_strings(
&candidates,
&query,
true,
10000,
&Default::default(),
cx.background_executor().clone(),
)
.await
};
let mut intercept_result = None;
// todo!() for vim mode
// cx.read(|cx| {
// if cx.has_global::<CommandPaletteInterceptor>() {
// cx.global::<CommandPaletteInterceptor>()(&query, cx)
// } else {
// None
// }
// });
if *RELEASE_CHANNEL == ReleaseChannel::Dev {
if parse_zed_link(&query).is_some() {
intercept_result = Some(CommandInterceptResult {
action: OpenZedURL { url: query.clone() }.boxed_clone(),
string: query.clone(),
positions: vec![],
})
}
}
if let Some(CommandInterceptResult {
action,
string,
positions,
}) = intercept_result
{
if let Some(idx) = matches
.iter()
.position(|m| actions[m.candidate_id].action.type_id() == action.type_id())
{
matches.remove(idx);
}
actions.push(Command {
name: string.clone(),
action,
keystrokes: vec![],
});
matches.insert(
0,
StringMatch {
candidate_id: actions.len() - 1,
string,
positions,
score: 0.0,
},
)
}
picker
.update(&mut cx, |picker, _| {
let delegate = &mut picker.delegate;
delegate.actions = actions;
delegate.matches = matches;
if delegate.matches.is_empty() {
delegate.selected_ix = 0;
} else {
delegate.selected_ix =
cmp::min(delegate.selected_ix, delegate.matches.len() - 1);
}
})
.log_err();
})
}
fn dismissed(&mut self, cx: &mut ViewContext<Picker<Self>>) {
dbg!("dismissed");
self.command_palette
.update(cx, |command_palette, cx| cx.emit(ModalEvent::Dismissed))
.log_err();
}
fn confirm(&mut self, _: bool, cx: &mut ViewContext<Picker<Self>>) {
// if !self.matches.is_empty() {
// let window = cx.window();
// let focused_view_id = self.focused_view_id;
// let action_ix = self.matches[self.selected_ix].candidate_id;
// let command = self.actions.remove(action_ix);
// cx.update_default_global(|hit_counts: &mut HitCounts, _| {
// *hit_counts.0.entry(command.name).or_default() += 1;
// });
// let action = command.action;
// cx.app_context()
// .spawn(move |mut cx| async move {
// window
// .dispatch_action(focused_view_id, action.as_ref(), &mut cx)
// .ok_or_else(|| anyhow!("window was closed"))
// })
// .detach_and_log_err(cx);
// }
self.dismissed(cx)
}
fn render_match(
&self,
ix: usize,
selected: bool,
cx: &mut ViewContext<Picker<Self>>,
) -> Self::ListItem {
div().child("ooh yeah")
}
// fn render_match(
// &self,
// ix: usize,
// mouse_state: &mut MouseState,
// selected: bool,
// cx: &gpui::AppContext,
// ) -> AnyElement<Picker<Self>> {
// let mat = &self.matches[ix];
// let command = &self.actions[mat.candidate_id];
// let theme = theme::current(cx);
// let style = theme.picker.item.in_state(selected).style_for(mouse_state);
// let key_style = &theme.command_palette.key.in_state(selected);
// let keystroke_spacing = theme.command_palette.keystroke_spacing;
// Flex::row()
// .with_child(
// Label::new(mat.string.clone(), style.label.clone())
// .with_highlights(mat.positions.clone()),
// )
// .with_children(command.keystrokes.iter().map(|keystroke| {
// Flex::row()
// .with_children(
// [
// (keystroke.ctrl, "^"),
// (keystroke.alt, "⌥"),
// (keystroke.cmd, "⌘"),
// (keystroke.shift, "⇧"),
// ]
// .into_iter()
// .filter_map(|(modifier, label)| {
// if modifier {
// Some(
// Label::new(label, key_style.label.clone())
// .contained()
// .with_style(key_style.container),
// )
// } else {
// None
// }
// }),
// )
// .with_child(
// Label::new(keystroke.key.clone(), key_style.label.clone())
// .contained()
// .with_style(key_style.container),
// )
// .contained()
// .with_margin_left(keystroke_spacing)
// .flex_float()
// }))
// .contained()
// .with_style(style.container)
// .into_any()
// }
}
fn humanize_action_name(name: &str) -> String {
let capacity = name.len() + name.chars().filter(|c| c.is_uppercase()).count();
let mut result = String::with_capacity(capacity);
for char in name.chars() {
if char == ':' {
if result.ends_with(':') {
result.push(' ');
} else {
result.push(':');
}
} else if char == '_' {
result.push(' ');
} else if char.is_uppercase() {
if !result.ends_with(' ') {
result.push(' ');
}
result.extend(char.to_lowercase());
} else {
result.push(char);
}
}
result
}
impl std::fmt::Debug for Command {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Command")
.field("name", &self.name)
.field("keystrokes", &self.keystrokes)
.finish()
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use super::*;
use editor::Editor;
use gpui::{executor::Deterministic, TestAppContext};
use project::Project;
use workspace::{AppState, Workspace};
#[test]
fn test_humanize_action_name() {
assert_eq!(
humanize_action_name("editor::GoToDefinition"),
"editor: go to definition"
);
assert_eq!(
humanize_action_name("editor::Backspace"),
"editor: backspace"
);
assert_eq!(
humanize_action_name("go_to_line::Deploy"),
"go to line: deploy"
);
}
#[gpui::test]
async fn test_command_palette(deterministic: Arc<Deterministic>, cx: &mut TestAppContext) {
let app_state = init_test(cx);
let project = Project::test(app_state.fs.clone(), [], cx).await;
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
let workspace = window.root(cx);
let editor = window.add_view(cx, |cx| {
let mut editor = Editor::single_line(None, cx);
editor.set_text("abc", cx);
editor
});
workspace.update(cx, |workspace, cx| {
cx.focus(&editor);
workspace.add_item(Box::new(editor.clone()), cx)
});
workspace.update(cx, |workspace, cx| {
toggle_command_palette(workspace, &Toggle, cx);
});
let palette = workspace.read_with(cx, |workspace, _| {
workspace.modal::<CommandPalette>().unwrap()
});
palette
.update(cx, |palette, cx| {
// Fill up palette's command list by running an empty query;
// we only need it to subsequently assert that the palette is initially
// sorted by command's name.
palette.delegate_mut().update_matches("".to_string(), cx)
})
.await;
palette.update(cx, |palette, _| {
let is_sorted =
|actions: &[Command]| actions.windows(2).all(|pair| pair[0].name <= pair[1].name);
assert!(is_sorted(&palette.delegate().actions));
});
palette
.update(cx, |palette, cx| {
palette
.delegate_mut()
.update_matches("bcksp".to_string(), cx)
})
.await;
palette.update(cx, |palette, cx| {
assert_eq!(palette.delegate().matches[0].string, "editor: backspace");
palette.confirm(&Default::default(), cx);
});
deterministic.run_until_parked();
editor.read_with(cx, |editor, cx| {
assert_eq!(editor.text(cx), "ab");
});
// Add namespace filter, and redeploy the palette
cx.update(|cx| {
cx.update_default_global::<CommandPaletteFilter, _, _>(|filter, _| {
filter.filtered_namespaces.insert("editor");
})
});
workspace.update(cx, |workspace, cx| {
toggle_command_palette(workspace, &Toggle, cx);
});
// Assert editor command not present
let palette = workspace.read_with(cx, |workspace, _| {
workspace.modal::<CommandPalette>().unwrap()
});
palette
.update(cx, |palette, cx| {
palette
.delegate_mut()
.update_matches("bcksp".to_string(), cx)
})
.await;
palette.update(cx, |palette, _| {
assert!(palette.delegate().matches.is_empty())
});
}
fn init_test(cx: &mut TestAppContext) -> Arc<AppState> {
cx.update(|cx| {
let app_state = AppState::test(cx);
theme::init(cx);
language::init(cx);
editor::init(cx);
workspace::init(app_state.clone(), cx);
init(cx);
Project::init_settings(cx);
app_state
})
}
}

View File

@ -4,7 +4,7 @@ use collections::{HashMap, HashSet};
use lazy_static::lazy_static;
use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard};
use serde::Deserialize;
use std::any::{type_name, Any};
use std::any::{type_name, Any, TypeId};
/// Actions are used to implement keyboard-driven UI.
/// When you declare an action, you can bind keys to the action in the keymap and
@ -100,6 +100,11 @@ where
}
}
impl dyn Action {
pub fn type_id(&self) -> TypeId {
self.as_any().type_id()
}
}
type ActionBuilder = fn(json: Option<serde_json::Value>) -> anyhow::Result<Box<dyn Action>>;
lazy_static! {

View File

@ -37,10 +37,10 @@ use futures::{
};
use gpui::{
actions, div, point, rems, size, AnyModel, AnyView, AnyWeakView, AppContext, AsyncAppContext,
AsyncWindowContext, Bounds, Component, Div, Entity, EntityId, EventEmitter, FocusHandle,
GlobalPixels, Model, ModelContext, ParentElement, Point, Render, Size, StatefulInteractive,
Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowBounds,
WindowContext, WindowHandle, WindowOptions,
AsyncWindowContext, Bounds, Component, DispatchContext, Div, Entity, EntityId, EventEmitter,
FocusHandle, GlobalPixels, Model, ModelContext, ParentElement, Point, Render, Size,
StatefulInteractive, Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView,
WindowBounds, WindowContext, WindowHandle, WindowOptions,
};
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem};
use itertools::Itertools;
@ -3709,157 +3709,160 @@ impl Render for Workspace {
type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
div()
.relative()
.size_full()
.flex()
.flex_col()
.font("Zed Sans")
.gap_0()
.justify_start()
.items_start()
.text_color(cx.theme().colors().text)
.bg(cx.theme().colors().background)
.child(self.render_titlebar(cx))
.child(
// todo! should this be a component a view?
self.modal_layer
.wrapper_element(cx)
.relative()
.flex_1()
.w_full()
.flex()
.overflow_hidden()
.border_t()
.border_b()
.border_color(cx.theme().colors().border)
// .children(
// Some(
// Panel::new("project-panel-outer", cx)
// .side(PanelSide::Left)
// .child(ProjectPanel::new("project-panel-inner")),
// )
// .filter(|_| self.is_project_panel_open()),
// )
// .children(
// Some(
// Panel::new("collab-panel-outer", cx)
// .child(CollabPanel::new("collab-panel-inner"))
// .side(PanelSide::Left),
// )
// .filter(|_| self.is_collab_panel_open()),
// )
// .child(NotificationToast::new(
// "maxbrunsfeld has requested to add you as a contact.".into(),
// ))
.child(
div().flex().flex_col().flex_1().h_full().child(
div().flex().flex_1().child(self.center.render(
&self.project,
&self.follower_states,
self.active_call(),
&self.active_pane,
self.zoomed.as_ref(),
&self.app_state,
cx,
)),
let mut context = DispatchContext::default();
context.insert("Workspace");
cx.with_key_dispatch_context(context, |cx| {
div()
.relative()
.size_full()
.flex()
.flex_col()
.font("Zed Sans")
.gap_0()
.justify_start()
.items_start()
.text_color(cx.theme().colors().text)
.bg(cx.theme().colors().background)
.child(self.render_titlebar(cx))
.child(
// todo! should this be a component a view?
self.modal_layer
.wrapper_element(cx)
.relative()
.flex_1()
.w_full()
.flex()
.overflow_hidden()
.border_t()
.border_b()
.border_color(cx.theme().colors().border)
// .children(
// Some(
// Panel::new("project-panel-outer", cx)
// .side(PanelSide::Left)
// .child(ProjectPanel::new("project-panel-inner")),
// )
// .filter(|_| self.is_project_panel_open()),
// )
// .children(
// Some(
// Panel::new("collab-panel-outer", cx)
// .child(CollabPanel::new("collab-panel-inner"))
// .side(PanelSide::Left),
// )
// .filter(|_| self.is_collab_panel_open()),
// )
// .child(NotificationToast::new(
// "maxbrunsfeld has requested to add you as a contact.".into(),
// ))
.child(
div().flex().flex_col().flex_1().h_full().child(
div().flex().flex_1().child(self.center.render(
&self.project,
&self.follower_states,
self.active_call(),
&self.active_pane,
self.zoomed.as_ref(),
&self.app_state,
cx,
)),
), // .children(
// Some(
// Panel::new("terminal-panel", cx)
// .child(Terminal::new())
// .allowed_sides(PanelAllowedSides::BottomOnly)
// .side(PanelSide::Bottom),
// )
// .filter(|_| self.is_terminal_open()),
// ),
), // .children(
// Some(
// Panel::new("terminal-panel", cx)
// .child(Terminal::new())
// .allowed_sides(PanelAllowedSides::BottomOnly)
// .side(PanelSide::Bottom),
// Panel::new("chat-panel-outer", cx)
// .side(PanelSide::Right)
// .child(ChatPanel::new("chat-panel-inner").messages(vec![
// ChatMessage::new(
// "osiewicz".to_string(),
// "is this thing on?".to_string(),
// DateTime::parse_from_rfc3339("2023-09-27T15:40:52.707Z")
// .unwrap()
// .naive_local(),
// ),
// ChatMessage::new(
// "maxdeviant".to_string(),
// "Reading you loud and clear!".to_string(),
// DateTime::parse_from_rfc3339("2023-09-28T15:40:52.707Z")
// .unwrap()
// .naive_local(),
// ),
// ])),
// )
// .filter(|_| self.is_terminal_open()),
// .filter(|_| self.is_chat_panel_open()),
// )
// .children(
// Some(
// Panel::new("notifications-panel-outer", cx)
// .side(PanelSide::Right)
// .child(NotificationsPanel::new("notifications-panel-inner")),
// )
// .filter(|_| self.is_notifications_panel_open()),
// )
// .children(
// Some(
// Panel::new("assistant-panel-outer", cx)
// .child(AssistantPanel::new("assistant-panel-inner")),
// )
// .filter(|_| self.is_assistant_panel_open()),
// ),
), // .children(
// Some(
// Panel::new("chat-panel-outer", cx)
// .side(PanelSide::Right)
// .child(ChatPanel::new("chat-panel-inner").messages(vec![
// ChatMessage::new(
// "osiewicz".to_string(),
// "is this thing on?".to_string(),
// DateTime::parse_from_rfc3339("2023-09-27T15:40:52.707Z")
// .unwrap()
// .naive_local(),
// ),
// ChatMessage::new(
// "maxdeviant".to_string(),
// "Reading you loud and clear!".to_string(),
// DateTime::parse_from_rfc3339("2023-09-28T15:40:52.707Z")
// .unwrap()
// .naive_local(),
// ),
// ])),
// )
// .filter(|_| self.is_chat_panel_open()),
// )
// .children(
// Some(
// Panel::new("notifications-panel-outer", cx)
// .side(PanelSide::Right)
// .child(NotificationsPanel::new("notifications-panel-inner")),
// )
// .filter(|_| self.is_notifications_panel_open()),
// )
// .children(
// Some(
// Panel::new("assistant-panel-outer", cx)
// .child(AssistantPanel::new("assistant-panel-inner")),
// )
// .filter(|_| self.is_assistant_panel_open()),
// ),
)
.child(self.status_bar.clone())
// .when(self.debug.show_toast, |this| {
// this.child(Toast::new(ToastOrigin::Bottom).child(Label::new("A toast")))
// })
// .children(
// Some(
// div()
// .absolute()
// .top(px(50.))
// .left(px(640.))
// .z_index(8)
// .child(LanguageSelector::new("language-selector")),
// )
// .filter(|_| self.is_language_selector_open()),
// )
.z_index(8)
// Debug
.child(
div()
.flex()
.flex_col()
.z_index(9)
.absolute()
.top_20()
.left_1_4()
.w_40()
.gap_2(), // .when(self.show_debug, |this| {
// this.child(Button::<Workspace>::new("Toggle User Settings").on_click(
// Arc::new(|workspace, cx| workspace.debug_toggle_user_settings(cx)),
// ))
// .child(
// Button::<Workspace>::new("Toggle Toasts").on_click(Arc::new(
// |workspace, cx| workspace.debug_toggle_toast(cx),
// )),
// )
// .child(
// Button::<Workspace>::new("Toggle Livestream").on_click(Arc::new(
// |workspace, cx| workspace.debug_toggle_livestream(cx),
// )),
// )
// })
// .child(
// Button::<Workspace>::new("Toggle Debug")
// .on_click(Arc::new(|workspace, cx| workspace.toggle_debug(cx))),
// ),
)
)
.child(self.status_bar.clone())
// .when(self.debug.show_toast, |this| {
// this.child(Toast::new(ToastOrigin::Bottom).child(Label::new("A toast")))
// })
// .children(
// Some(
// div()
// .absolute()
// .top(px(50.))
// .left(px(640.))
// .z_index(8)
// .child(LanguageSelector::new("language-selector")),
// )
// .filter(|_| self.is_language_selector_open()),
// )
.z_index(8)
// Debug
.child(
div()
.flex()
.flex_col()
.z_index(9)
.absolute()
.top_20()
.left_1_4()
.w_40()
.gap_2(), // .when(self.show_debug, |this| {
// this.child(Button::<Workspace>::new("Toggle User Settings").on_click(
// Arc::new(|workspace, cx| workspace.debug_toggle_user_settings(cx)),
// ))
// .child(
// Button::<Workspace>::new("Toggle Toasts").on_click(Arc::new(
// |workspace, cx| workspace.debug_toggle_toast(cx),
// )),
// )
// .child(
// Button::<Workspace>::new("Toggle Livestream").on_click(Arc::new(
// |workspace, cx| workspace.debug_toggle_livestream(cx),
// )),
// )
// })
// .child(
// Button::<Workspace>::new("Toggle Debug")
// .on_click(Arc::new(|workspace, cx| workspace.toggle_debug(cx))),
// ),
)
})
}
}
// todo!()
// impl Entity for Workspace {
// type Event = Event;

View File

@ -25,7 +25,7 @@ call = { package = "call2", path = "../call2" }
cli = { path = "../cli" }
# collab_ui = { path = "../collab_ui" }
collections = { path = "../collections" }
# command_palette = { path = "../command_palette" }
command_palette = { package="command_palette2", path = "../command_palette2" }
# component_test = { path = "../component_test" }
# context_menu = { path = "../context_menu" }
client = { package = "client2", path = "../client2" }
@ -74,7 +74,7 @@ util = { path = "../util" }
# vim = { path = "../vim" }
workspace = { package = "workspace2", path = "../workspace2" }
# welcome = { path = "../welcome" }
# zed-actions = {path = "../zed-actions"}
zed_actions = {package = "zed_actions2", path = "../zed_actions2"}
anyhow.workspace = true
async-compression = { version = "0.3", features = ["gzip", "futures-bufread"] }
async-tar = "0.4.2"

View File

@ -142,7 +142,7 @@ fn main() {
// context_menu::init(cx);
project::Project::init(&client, cx);
client::init(&client, cx);
// command_palette::init(cx);
command_palette::init(cx);
language::init(cx);
editor::init(cx);
copilot::init(
@ -761,7 +761,7 @@ fn load_embedded_fonts(cx: &AppContext) {
// #[cfg(not(debug_assertions))]
// async fn watch_languages(_: Arc<dyn Fs>, _: Arc<LanguageRegistry>) -> Option<()> {
// None
// }
//
// #[cfg(not(debug_assertions))]
// fn watch_file_types(_fs: Arc<dyn Fs>, _cx: &mut AppContext) {}

View File

@ -0,0 +1,11 @@
[package]
name = "zed_actions2"
version = "0.1.0"
edition = "2021"
publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
gpui = { package = "gpui2", path = "../gpui2" }
serde.workspace = true

View File

@ -0,0 +1,34 @@
use gpui::{action, actions};
actions!(
About,
DebugElements,
DecreaseBufferFontSize,
Hide,
HideOthers,
IncreaseBufferFontSize,
Minimize,
OpenDefaultKeymap,
OpenDefaultSettings,
OpenKeymap,
OpenLicenses,
OpenLocalSettings,
OpenLog,
OpenSettings,
OpenTelemetryLog,
Quit,
ResetBufferFontSize,
ResetDatabase,
ShowAll,
ToggleFullScreen,
Zoom,
);
#[action]
pub struct OpenBrowser {
pub url: String,
}
#[action]
pub struct OpenZedURL {
pub url: String,
}