mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-19 02:17:35 +03:00
Add blank pane experience
This commit is contained in:
parent
dad66eb3fb
commit
152755b043
@ -198,6 +198,7 @@ impl TestServer {
|
||||
build_window_options: |_, _, _| Default::default(),
|
||||
initialize_workspace: |_, _, _| unimplemented!(),
|
||||
dock_default_item_factory: |_, _| unimplemented!(),
|
||||
background_actions: || unimplemented!(),
|
||||
});
|
||||
|
||||
Project::init(&client);
|
||||
@ -434,15 +435,7 @@ impl TestClient {
|
||||
cx: &mut TestAppContext,
|
||||
) -> ViewHandle<Workspace> {
|
||||
let (_, root_view) = cx.add_window(|_| EmptyView);
|
||||
cx.add_view(&root_view, |cx| {
|
||||
Workspace::new(
|
||||
Default::default(),
|
||||
0,
|
||||
project.clone(),
|
||||
|_, _| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
cx.add_view(&root_view, |cx| Workspace::test_new(project.clone(), cx))
|
||||
}
|
||||
|
||||
fn create_new_root_dir(&mut self) -> PathBuf {
|
||||
|
@ -1449,15 +1449,7 @@ async fn test_host_disconnect(
|
||||
deterministic.run_until_parked();
|
||||
assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared()));
|
||||
|
||||
let (_, workspace_b) = cx_b.add_window(|cx| {
|
||||
Workspace::new(
|
||||
Default::default(),
|
||||
0,
|
||||
project_b.clone(),
|
||||
|_, _| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (_, workspace_b) = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
|
||||
let editor_b = workspace_b
|
||||
.update(cx_b, |workspace, cx| {
|
||||
workspace.open_path((worktree_id, "b.txt"), None, true, cx)
|
||||
@ -4706,15 +4698,7 @@ async fn test_collaborating_with_code_actions(
|
||||
|
||||
// Join the project as client B.
|
||||
let project_b = client_b.build_remote_project(project_id, cx_b).await;
|
||||
let (_window_b, workspace_b) = cx_b.add_window(|cx| {
|
||||
Workspace::new(
|
||||
Default::default(),
|
||||
0,
|
||||
project_b.clone(),
|
||||
|_, _| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
|
||||
let editor_b = workspace_b
|
||||
.update(cx_b, |workspace, cx| {
|
||||
workspace.open_path((worktree_id, "main.rs"), None, true, cx)
|
||||
@ -4937,15 +4921,7 @@ async fn test_collaborating_with_renames(
|
||||
.unwrap();
|
||||
let project_b = client_b.build_remote_project(project_id, cx_b).await;
|
||||
|
||||
let (_window_b, workspace_b) = cx_b.add_window(|cx| {
|
||||
Workspace::new(
|
||||
Default::default(),
|
||||
0,
|
||||
project_b.clone(),
|
||||
|_, _| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
|
||||
let editor_b = workspace_b
|
||||
.update(cx_b, |workspace, cx| {
|
||||
workspace.open_path((worktree_id, "one.rs"), None, true, cx)
|
||||
|
@ -86,6 +86,7 @@ fn join_project(action: &JoinProject, app_state: Arc<AppState>, cx: &mut Mutable
|
||||
0,
|
||||
project,
|
||||
app_state.dock_default_item_factory,
|
||||
app_state.background_actions,
|
||||
cx,
|
||||
);
|
||||
(app_state.initialize_workspace)(&mut workspace, &app_state, cx);
|
||||
|
@ -352,9 +352,7 @@ mod tests {
|
||||
});
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), [], cx).await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||
let editor = cx.add_view(&workspace, |cx| {
|
||||
let mut editor = Editor::single_line(None, cx);
|
||||
editor.set_text("abc", cx);
|
||||
|
@ -805,15 +805,7 @@ mod tests {
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), ["/test".as_ref()], cx).await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(
|
||||
Default::default(),
|
||||
0,
|
||||
project.clone(),
|
||||
|_, _| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||
|
||||
// Create some diagnostics
|
||||
project.update(cx, |project, cx| {
|
||||
|
@ -484,7 +484,9 @@ fn test_navigation_history(cx: &mut gpui::MutableAppContext) {
|
||||
cx.set_global(Settings::test(cx));
|
||||
cx.set_global(DragAndDrop::<Workspace>::default());
|
||||
use workspace::item::Item;
|
||||
let (_, pane) = cx.add_window(Default::default(), |cx| Pane::new(None, cx));
|
||||
let (_, pane) = cx.add_window(Default::default(), |cx| {
|
||||
Pane::new(None, || unimplemented!(), cx)
|
||||
});
|
||||
let buffer = MultiBuffer::build_simple(&sample_text(300, 5, 'a'), cx);
|
||||
|
||||
cx.add_view(&pane, |cx| {
|
||||
@ -2354,10 +2356,10 @@ async fn test_clipboard(cx: &mut gpui::TestAppContext) {
|
||||
e.handle_input(") ", cx);
|
||||
});
|
||||
cx.assert_editor_state(indoc! {"
|
||||
( one✅
|
||||
three
|
||||
five ) ˇtwo one✅ four three six five ( one✅
|
||||
three
|
||||
( one✅
|
||||
three
|
||||
five ) ˇtwo one✅ four three six five ( one✅
|
||||
three
|
||||
five ) ˇ"});
|
||||
|
||||
// Cut with three selections, one of which is full-line.
|
||||
@ -5562,7 +5564,7 @@ async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) {
|
||||
Settings::test_async(cx);
|
||||
let fs = FakeFs::new(cx.background());
|
||||
let project = Project::test(fs, ["/file.rs".as_ref()], cx).await;
|
||||
let (_, pane) = cx.add_window(|cx| Pane::new(None, cx));
|
||||
let (_, pane) = cx.add_window(|cx| Pane::new(None, || unimplemented!(), cx));
|
||||
|
||||
let leader = pane.update(cx, |_, cx| {
|
||||
let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
|
||||
@ -5831,11 +5833,11 @@ async fn go_to_hunk(deterministic: Arc<Deterministic>, cx: &mut gpui::TestAppCon
|
||||
cx.assert_editor_state(
|
||||
&r#"
|
||||
ˇuse some::modified;
|
||||
|
||||
|
||||
|
||||
|
||||
fn main() {
|
||||
println!("hello there");
|
||||
|
||||
|
||||
println!("around the");
|
||||
println!("world");
|
||||
}
|
||||
|
@ -65,15 +65,7 @@ impl<'a> EditorLspTestContext<'a> {
|
||||
.insert_tree("/root", json!({ "dir": { file_name.clone(): "" }}))
|
||||
.await;
|
||||
|
||||
let (window_id, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(
|
||||
Default::default(),
|
||||
0,
|
||||
project.clone(),
|
||||
|_, _| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||
project
|
||||
.update(cx, |project, cx| {
|
||||
project.find_or_create_local_worktree("/root", true, cx)
|
||||
@ -134,7 +126,7 @@ impl<'a> EditorLspTestContext<'a> {
|
||||
(let_chain)
|
||||
(await_expression)
|
||||
] @indent
|
||||
|
||||
|
||||
(_ "[" "]" @end) @indent
|
||||
(_ "<" ">" @end) @indent
|
||||
(_ "{" "}" @end) @indent
|
||||
|
@ -329,9 +329,7 @@ mod tests {
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||
let (window_id, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx)
|
||||
});
|
||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||
cx.dispatch_action(window_id, Toggle);
|
||||
|
||||
let finder = cx.read(|cx| workspace.read(cx).modal::<FileFinder>().unwrap());
|
||||
@ -385,9 +383,7 @@ mod tests {
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), ["/dir".as_ref()], cx).await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||
let (_, finder) =
|
||||
cx.add_window(|cx| FileFinder::new(workspace.read(cx).project().clone(), None, cx));
|
||||
|
||||
@ -461,9 +457,7 @@ mod tests {
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||
let (_, finder) =
|
||||
cx.add_window(|cx| FileFinder::new(workspace.read(cx).project().clone(), None, cx));
|
||||
finder
|
||||
@ -487,9 +481,7 @@ mod tests {
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||
let (_, finder) =
|
||||
cx.add_window(|cx| FileFinder::new(workspace.read(cx).project().clone(), None, cx));
|
||||
|
||||
@ -541,9 +533,7 @@ mod tests {
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||
|
||||
let (_, finder) =
|
||||
cx.add_window(|cx| FileFinder::new(workspace.read(cx).project().clone(), None, cx));
|
||||
@ -585,9 +575,7 @@ mod tests {
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||
|
||||
// When workspace has an active item, sort items which are closer to that item
|
||||
// first when they have the same name. In this case, b.txt is closer to dir2's a.txt
|
||||
@ -624,9 +612,7 @@ mod tests {
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||
let (_, finder) =
|
||||
cx.add_window(|cx| FileFinder::new(workspace.read(cx).project().clone(), None, cx));
|
||||
finder
|
||||
|
@ -6,15 +6,14 @@ use gpui::{
|
||||
actions,
|
||||
anyhow::{anyhow, Result},
|
||||
elements::{
|
||||
AnchorCorner, ChildView, ConstrainedBox, Container, ContainerStyle, Empty, Flex,
|
||||
KeystrokeLabel, Label, MouseEventHandler, ParentElement, ScrollTarget, Stack, Svg,
|
||||
UniformList, UniformListState,
|
||||
AnchorCorner, ChildView, ConstrainedBox, ContainerStyle, Empty, Flex, Label,
|
||||
MouseEventHandler, ParentElement, ScrollTarget, Stack, Svg, UniformList, UniformListState,
|
||||
},
|
||||
geometry::vector::Vector2F,
|
||||
impl_internal_actions,
|
||||
keymap_matcher::KeymapContext,
|
||||
platform::CursorStyle,
|
||||
Action, AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, MouseButton,
|
||||
AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, MouseButton,
|
||||
MutableAppContext, PromptLevel, RenderContext, Task, View, ViewContext, ViewHandle,
|
||||
};
|
||||
use menu::{Confirm, SelectNext, SelectPrev};
|
||||
@ -28,7 +27,7 @@ use std::{
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use theme::{ContainedText, ProjectPanelEntry};
|
||||
use theme::ProjectPanelEntry;
|
||||
use unicase::UniCase;
|
||||
use workspace::Workspace;
|
||||
|
||||
@ -1315,7 +1314,6 @@ impl View for ProjectPanel {
|
||||
.with_child(ChildView::new(&self.context_menu, cx).boxed())
|
||||
.boxed()
|
||||
} else {
|
||||
let parent_view_id = cx.handle().id();
|
||||
Flex::column()
|
||||
.with_child(
|
||||
MouseEventHandler::<Self>::new(2, cx, {
|
||||
@ -1327,12 +1325,11 @@ impl View for ProjectPanel {
|
||||
let context_menu_item =
|
||||
context_menu_item_style.style_for(state, true).clone();
|
||||
|
||||
keystroke_label(
|
||||
parent_view_id,
|
||||
theme::ui::keystroke_label(
|
||||
"Open a project",
|
||||
&button_style,
|
||||
context_menu_item.keystroke,
|
||||
workspace::Open,
|
||||
&context_menu_item.keystroke,
|
||||
Box::new(workspace::Open),
|
||||
cx,
|
||||
)
|
||||
.boxed()
|
||||
@ -1357,38 +1354,6 @@ impl View for ProjectPanel {
|
||||
}
|
||||
}
|
||||
|
||||
fn keystroke_label<A>(
|
||||
view_id: usize,
|
||||
label_text: &'static str,
|
||||
label_style: &ContainedText,
|
||||
keystroke_style: ContainedText,
|
||||
action: A,
|
||||
cx: &mut RenderContext<ProjectPanel>,
|
||||
) -> Container
|
||||
where
|
||||
A: Action,
|
||||
{
|
||||
Flex::row()
|
||||
.with_child(
|
||||
Label::new(label_text, label_style.text.clone())
|
||||
.contained()
|
||||
.boxed(),
|
||||
)
|
||||
.with_child({
|
||||
KeystrokeLabel::new(
|
||||
cx.window_id(),
|
||||
view_id,
|
||||
Box::new(action),
|
||||
keystroke_style.container,
|
||||
keystroke_style.text.clone(),
|
||||
)
|
||||
.flex_float()
|
||||
.boxed()
|
||||
})
|
||||
.contained()
|
||||
.with_style(label_style.container)
|
||||
}
|
||||
|
||||
impl Entity for ProjectPanel {
|
||||
type Event = Event;
|
||||
}
|
||||
@ -1474,15 +1439,7 @@ mod tests {
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(
|
||||
Default::default(),
|
||||
0,
|
||||
project.clone(),
|
||||
|_, _| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||
let panel = workspace.update(cx, |_, cx| ProjectPanel::new(project, cx));
|
||||
assert_eq!(
|
||||
visible_entries_as_strings(&panel, 0..50, cx),
|
||||
@ -1574,15 +1531,7 @@ mod tests {
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(
|
||||
Default::default(),
|
||||
0,
|
||||
project.clone(),
|
||||
|_, _| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||
let panel = workspace.update(cx, |_, cx| ProjectPanel::new(project, cx));
|
||||
|
||||
select_path(&panel, "root1", cx);
|
||||
|
@ -970,15 +970,7 @@ mod tests {
|
||||
let params = cx.update(AppState::test);
|
||||
|
||||
let project = Project::test(params.fs.clone(), [], cx).await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(
|
||||
Default::default(),
|
||||
0,
|
||||
project.clone(),
|
||||
|_, _| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||
|
||||
(project, workspace)
|
||||
}
|
||||
|
@ -9,6 +9,9 @@ use gpui::{
|
||||
use serde::{de::DeserializeOwned, Deserialize};
|
||||
use serde_json::Value;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use ui::{CheckboxStyle, IconStyle};
|
||||
|
||||
pub mod ui;
|
||||
|
||||
pub use theme_registry::*;
|
||||
|
||||
@ -50,6 +53,7 @@ pub struct ThemeMeta {
|
||||
#[derive(Deserialize, Default)]
|
||||
pub struct Workspace {
|
||||
pub background: Color,
|
||||
pub blank_pane: BlankPaneStyle,
|
||||
pub titlebar: Titlebar,
|
||||
pub tab_bar: TabBar,
|
||||
pub pane_divider: Border,
|
||||
@ -69,6 +73,14 @@ pub struct Workspace {
|
||||
pub drop_target_overlay_color: Color,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
pub struct BlankPaneStyle {
|
||||
pub logo: IconStyle,
|
||||
pub keyboard_hints: ContainerStyle,
|
||||
pub keyboard_hint: Interactive<ContainedText>,
|
||||
pub keyboard_hint_width: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
pub struct Titlebar {
|
||||
#[serde(flatten)]
|
||||
@ -858,46 +870,18 @@ pub struct WelcomeStyle {
|
||||
pub logo: IconStyle,
|
||||
pub logo_subheading: ContainedText,
|
||||
pub checkbox: CheckboxStyle,
|
||||
pub checkbox_container: ContainerStyle,
|
||||
pub button: Interactive<ContainedText>,
|
||||
pub button_group: ContainerStyle,
|
||||
pub heading_group: ContainerStyle,
|
||||
pub checkbox_group: ContainerStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
pub struct IconStyle {
|
||||
pub color: Color,
|
||||
pub icon: String,
|
||||
pub dimensions: Dimensions,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
pub struct Dimensions {
|
||||
pub width: f32,
|
||||
pub height: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
pub struct CheckboxStyle {
|
||||
pub check_icon: String,
|
||||
pub check_icon_color: Color,
|
||||
pub label: ContainedText,
|
||||
pub container: ContainerStyle,
|
||||
pub width: f32,
|
||||
pub height: f32,
|
||||
pub default: ContainerStyle,
|
||||
pub checked: ContainerStyle,
|
||||
pub hovered: ContainerStyle,
|
||||
pub hovered_and_checked: ContainerStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
pub struct ColorScheme {
|
||||
pub name: String,
|
||||
pub is_light: bool,
|
||||
|
||||
pub ramps: RampSet,
|
||||
|
||||
pub lowest: Layer,
|
||||
pub middle: Layer,
|
||||
pub highest: Layer,
|
||||
|
119
crates/theme/src/ui.rs
Normal file
119
crates/theme/src/ui.rs
Normal file
@ -0,0 +1,119 @@
|
||||
use gpui::{
|
||||
color::Color,
|
||||
elements::{
|
||||
ConstrainedBox, Container, ContainerStyle, Empty, Flex, KeystrokeLabel, Label,
|
||||
MouseEventHandler, ParentElement, Svg,
|
||||
},
|
||||
Action, Element, EventContext, RenderContext, View,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::ContainedText;
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
pub struct CheckboxStyle {
|
||||
pub icon: IconStyle,
|
||||
pub label: ContainedText,
|
||||
pub default: ContainerStyle,
|
||||
pub checked: ContainerStyle,
|
||||
pub hovered: ContainerStyle,
|
||||
pub hovered_and_checked: ContainerStyle,
|
||||
}
|
||||
|
||||
pub fn checkbox<T: 'static, V: View>(
|
||||
label: &'static str,
|
||||
style: &CheckboxStyle,
|
||||
checked: bool,
|
||||
cx: &mut RenderContext<V>,
|
||||
change: fn(checked: bool, cx: &mut EventContext) -> (),
|
||||
) -> MouseEventHandler<T> {
|
||||
MouseEventHandler::<T>::new(0, cx, |state, _| {
|
||||
let indicator = if checked {
|
||||
icon(&style.icon)
|
||||
} else {
|
||||
Empty::new()
|
||||
.constrained()
|
||||
.with_width(style.icon.dimensions.width)
|
||||
.with_height(style.icon.dimensions.height)
|
||||
};
|
||||
|
||||
Flex::row()
|
||||
.with_children([
|
||||
indicator
|
||||
.contained()
|
||||
.with_style(if checked {
|
||||
if state.hovered() {
|
||||
style.hovered_and_checked
|
||||
} else {
|
||||
style.checked
|
||||
}
|
||||
} else {
|
||||
if state.hovered() {
|
||||
style.hovered
|
||||
} else {
|
||||
style.default
|
||||
}
|
||||
})
|
||||
.boxed(),
|
||||
Label::new(label, style.label.text.clone())
|
||||
.contained()
|
||||
.with_style(style.label.container)
|
||||
.boxed(),
|
||||
])
|
||||
.align_children_center()
|
||||
.boxed()
|
||||
})
|
||||
.on_click(gpui::MouseButton::Left, move |_, cx| change(!checked, cx))
|
||||
.with_cursor_style(gpui::CursorStyle::PointingHand)
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
pub struct IconStyle {
|
||||
pub color: Color,
|
||||
pub icon: String,
|
||||
pub dimensions: Dimensions,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
pub struct Dimensions {
|
||||
pub width: f32,
|
||||
pub height: f32,
|
||||
}
|
||||
|
||||
pub fn icon(style: &IconStyle) -> ConstrainedBox {
|
||||
Svg::new(style.icon.clone())
|
||||
.with_color(style.color)
|
||||
.constrained()
|
||||
.with_width(style.dimensions.width)
|
||||
.with_height(style.dimensions.height)
|
||||
}
|
||||
|
||||
pub fn keystroke_label<V: View>(
|
||||
label_text: &'static str,
|
||||
label_style: &ContainedText,
|
||||
keystroke_style: &ContainedText,
|
||||
action: Box<dyn Action>,
|
||||
cx: &mut RenderContext<V>,
|
||||
) -> Container {
|
||||
// FIXME: Put the theme in it's own global so we can
|
||||
// query the keystroke style on our own
|
||||
Flex::row()
|
||||
.with_child(
|
||||
Label::new(label_text, label_style.text.clone())
|
||||
.contained()
|
||||
.boxed(),
|
||||
)
|
||||
.with_child({
|
||||
KeystrokeLabel::new(
|
||||
cx.window_id(),
|
||||
cx.handle().id(),
|
||||
action,
|
||||
keystroke_style.container,
|
||||
keystroke_style.text.clone(),
|
||||
)
|
||||
.flex_float()
|
||||
.boxed()
|
||||
})
|
||||
.contained()
|
||||
.with_style(label_style.container)
|
||||
}
|
@ -4,12 +4,12 @@ use std::{borrow::Cow, sync::Arc};
|
||||
|
||||
use db::kvp::KEY_VALUE_STORE;
|
||||
use gpui::{
|
||||
elements::{Empty, Flex, Label, MouseEventHandler, ParentElement, Svg},
|
||||
elements::{Flex, Label, MouseEventHandler, ParentElement},
|
||||
Action, Element, ElementBox, Entity, MouseButton, MutableAppContext, RenderContext,
|
||||
Subscription, View, ViewContext,
|
||||
};
|
||||
use settings::{settings_file::SettingsFile, Settings, SettingsFileContent};
|
||||
use theme::CheckboxStyle;
|
||||
use settings::{settings_file::SettingsFile, Settings};
|
||||
|
||||
use workspace::{
|
||||
item::Item, open_new, sidebar::SidebarSide, AppState, PaneBackdrop, Welcome, Workspace,
|
||||
WorkspaceId,
|
||||
@ -77,11 +77,7 @@ impl View for WelcomePage {
|
||||
.with_children([
|
||||
Flex::column()
|
||||
.with_children([
|
||||
Svg::new(theme.welcome.logo.icon.clone())
|
||||
.with_color(theme.welcome.logo.color)
|
||||
.constrained()
|
||||
.with_width(theme.welcome.logo.dimensions.width)
|
||||
.with_height(theme.welcome.logo.dimensions.height)
|
||||
theme::ui::icon(&theme.welcome.logo)
|
||||
.aligned()
|
||||
.contained()
|
||||
.aligned()
|
||||
@ -128,20 +124,34 @@ impl View for WelcomePage {
|
||||
.boxed(),
|
||||
Flex::column()
|
||||
.with_children([
|
||||
self.render_settings_checkbox::<Metrics>(
|
||||
theme::ui::checkbox::<Metrics, Self>(
|
||||
"Do you want to send telemetry?",
|
||||
&theme.welcome.checkbox,
|
||||
metrics,
|
||||
cx,
|
||||
|content, checked| content.telemetry.set_metrics(checked),
|
||||
),
|
||||
self.render_settings_checkbox::<Diagnostics>(
|
||||
|checked, cx| {
|
||||
SettingsFile::update(cx, move |file| {
|
||||
file.telemetry.set_metrics(checked)
|
||||
})
|
||||
},
|
||||
)
|
||||
.contained()
|
||||
.with_style(theme.welcome.checkbox_container)
|
||||
.boxed(),
|
||||
theme::ui::checkbox::<Diagnostics, Self>(
|
||||
"Send crash reports",
|
||||
&theme.welcome.checkbox,
|
||||
diagnostics,
|
||||
cx,
|
||||
|content, checked| content.telemetry.set_diagnostics(checked),
|
||||
),
|
||||
|checked, cx| {
|
||||
SettingsFile::update(cx, move |file| {
|
||||
file.telemetry.set_diagnostics(checked)
|
||||
})
|
||||
},
|
||||
)
|
||||
.contained()
|
||||
.with_style(theme.welcome.checkbox_container)
|
||||
.boxed(),
|
||||
])
|
||||
.contained()
|
||||
.with_style(theme.welcome.checkbox_group)
|
||||
@ -204,59 +214,59 @@ impl WelcomePage {
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn render_settings_checkbox<T: 'static>(
|
||||
&self,
|
||||
label: &'static str,
|
||||
style: &CheckboxStyle,
|
||||
checked: bool,
|
||||
cx: &mut RenderContext<Self>,
|
||||
set_value: fn(&mut SettingsFileContent, checked: bool) -> (),
|
||||
) -> ElementBox {
|
||||
MouseEventHandler::<T>::new(0, cx, |state, _| {
|
||||
let indicator = if checked {
|
||||
Svg::new(style.check_icon.clone())
|
||||
.with_color(style.check_icon_color)
|
||||
.constrained()
|
||||
} else {
|
||||
Empty::new().constrained()
|
||||
};
|
||||
// fn render_settings_checkbox<T: 'static>(
|
||||
// &self,
|
||||
// label: &'static str,
|
||||
// style: &CheckboxStyle,
|
||||
// checked: bool,
|
||||
// cx: &mut RenderContext<Self>,
|
||||
// set_value: fn(&mut SettingsFileContent, checked: bool) -> (),
|
||||
// ) -> ElementBox {
|
||||
// MouseEventHandler::<T>::new(0, cx, |state, _| {
|
||||
// let indicator = if checked {
|
||||
// Svg::new(style.check_icon.clone())
|
||||
// .with_color(style.check_icon_color)
|
||||
// .constrained()
|
||||
// } else {
|
||||
// Empty::new().constrained()
|
||||
// };
|
||||
|
||||
Flex::row()
|
||||
.with_children([
|
||||
indicator
|
||||
.with_width(style.width)
|
||||
.with_height(style.height)
|
||||
.contained()
|
||||
.with_style(if checked {
|
||||
if state.hovered() {
|
||||
style.hovered_and_checked
|
||||
} else {
|
||||
style.checked
|
||||
}
|
||||
} else {
|
||||
if state.hovered() {
|
||||
style.hovered
|
||||
} else {
|
||||
style.default
|
||||
}
|
||||
})
|
||||
.boxed(),
|
||||
Label::new(label, style.label.text.clone())
|
||||
.contained()
|
||||
.with_style(style.label.container)
|
||||
.boxed(),
|
||||
])
|
||||
.align_children_center()
|
||||
.boxed()
|
||||
})
|
||||
.on_click(gpui::MouseButton::Left, move |_, cx| {
|
||||
SettingsFile::update(cx, move |content| set_value(content, !checked))
|
||||
})
|
||||
.with_cursor_style(gpui::CursorStyle::PointingHand)
|
||||
.contained()
|
||||
.with_style(style.container)
|
||||
.boxed()
|
||||
}
|
||||
// Flex::row()
|
||||
// .with_children([
|
||||
// indicator
|
||||
// .with_width(style.width)
|
||||
// .with_height(style.height)
|
||||
// .contained()
|
||||
// .with_style(if checked {
|
||||
// if state.hovered() {
|
||||
// style.hovered_and_checked
|
||||
// } else {
|
||||
// style.checked
|
||||
// }
|
||||
// } else {
|
||||
// if state.hovered() {
|
||||
// style.hovered
|
||||
// } else {
|
||||
// style.default
|
||||
// }
|
||||
// })
|
||||
// .boxed(),
|
||||
// Label::new(label, style.label.text.clone())
|
||||
// .contained()
|
||||
// .with_style(style.label.container)
|
||||
// .boxed(),
|
||||
// ])
|
||||
// .align_children_center()
|
||||
// .boxed()
|
||||
// })
|
||||
// .on_click(gpui::MouseButton::Left, move |_, cx| {
|
||||
// SettingsFile::update(cx, move |content| set_value(content, !checked))
|
||||
// })
|
||||
// .with_cursor_style(gpui::CursorStyle::PointingHand)
|
||||
// .contained()
|
||||
// .with_style(style.container)
|
||||
// .boxed()
|
||||
// }
|
||||
}
|
||||
|
||||
impl Item for WelcomePage {
|
||||
|
@ -13,7 +13,7 @@ use gpui::{
|
||||
use settings::{DockAnchor, Settings};
|
||||
use theme::Theme;
|
||||
|
||||
use crate::{sidebar::SidebarSide, ItemHandle, Pane, Workspace};
|
||||
use crate::{sidebar::SidebarSide, BackgroundActions, ItemHandle, Pane, Workspace};
|
||||
pub use toggle_dock_button::ToggleDockButton;
|
||||
|
||||
#[derive(PartialEq, Clone, Deserialize)]
|
||||
@ -182,11 +182,12 @@ pub struct Dock {
|
||||
impl Dock {
|
||||
pub fn new(
|
||||
default_item_factory: DockDefaultItemFactory,
|
||||
background_actions: BackgroundActions,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) -> Self {
|
||||
let position = DockPosition::Hidden(cx.global::<Settings>().default_dock_anchor);
|
||||
|
||||
let pane = cx.add_view(|cx| Pane::new(Some(position.anchor()), cx));
|
||||
let pane = cx.add_view(|cx| Pane::new(Some(position.anchor()), background_actions, cx));
|
||||
pane.update(cx, |pane, cx| {
|
||||
pane.set_active(false, cx);
|
||||
});
|
||||
@ -492,6 +493,7 @@ mod tests {
|
||||
0,
|
||||
project.clone(),
|
||||
default_item_factory,
|
||||
|| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
@ -620,7 +622,14 @@ mod tests {
|
||||
cx.update(|cx| init(cx));
|
||||
let project = Project::test(fs, [], cx).await;
|
||||
let (window_id, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, default_item_factory, cx)
|
||||
Workspace::new(
|
||||
Default::default(),
|
||||
0,
|
||||
project,
|
||||
default_item_factory,
|
||||
|| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
|
@ -110,6 +110,8 @@ impl_internal_actions!(
|
||||
|
||||
const MAX_NAVIGATION_HISTORY_LEN: usize = 1024;
|
||||
|
||||
pub type BackgroundActions = fn() -> &'static [(&'static str, &'static dyn Action)];
|
||||
|
||||
pub fn init(cx: &mut MutableAppContext) {
|
||||
cx.add_action(|pane: &mut Pane, action: &ActivateItem, cx| {
|
||||
pane.activate_item(action.0, true, true, cx);
|
||||
@ -215,6 +217,7 @@ pub struct Pane {
|
||||
toolbar: ViewHandle<Toolbar>,
|
||||
tab_bar_context_menu: ViewHandle<ContextMenu>,
|
||||
docked: Option<DockAnchor>,
|
||||
background_actions: BackgroundActions,
|
||||
}
|
||||
|
||||
pub struct ItemNavHistory {
|
||||
@ -271,7 +274,11 @@ enum ItemType {
|
||||
}
|
||||
|
||||
impl Pane {
|
||||
pub fn new(docked: Option<DockAnchor>, cx: &mut ViewContext<Self>) -> Self {
|
||||
pub fn new(
|
||||
docked: Option<DockAnchor>,
|
||||
background_actions: BackgroundActions,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Self {
|
||||
let handle = cx.weak_handle();
|
||||
let context_menu = cx.add_view(ContextMenu::new);
|
||||
Self {
|
||||
@ -292,6 +299,7 @@ impl Pane {
|
||||
toolbar: cx.add_view(|_| Toolbar::new(handle)),
|
||||
tab_bar_context_menu: context_menu,
|
||||
docked,
|
||||
background_actions,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1415,6 +1423,64 @@ impl Pane {
|
||||
.flex(1., false)
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn render_blank_pane(&mut self, theme: &Theme, cx: &mut RenderContext<Self>) -> ElementBox {
|
||||
let background = theme.workspace.background;
|
||||
let keystroke_style = &theme.context_menu.item;
|
||||
let theme = &theme.workspace.blank_pane;
|
||||
Stack::new()
|
||||
.with_children([
|
||||
Empty::new()
|
||||
.contained()
|
||||
.with_background_color(background)
|
||||
.boxed(),
|
||||
Flex::column()
|
||||
.align_children_center()
|
||||
.with_children([
|
||||
theme::ui::icon(&theme.logo).aligned().boxed(),
|
||||
Flex::column()
|
||||
.with_children({
|
||||
enum KeyboardHint {}
|
||||
let keyboard_hint = &theme.keyboard_hint;
|
||||
(self.background_actions)().into_iter().enumerate().map(
|
||||
move |(idx, (text, action))| {
|
||||
let hint_action = action.boxed_clone();
|
||||
MouseEventHandler::<KeyboardHint>::new(
|
||||
idx,
|
||||
cx,
|
||||
move |state, cx| {
|
||||
theme::ui::keystroke_label(
|
||||
text,
|
||||
&keyboard_hint.style_for(state, false),
|
||||
&keystroke_style
|
||||
.style_for(state, false)
|
||||
.keystroke,
|
||||
hint_action,
|
||||
cx,
|
||||
)
|
||||
.boxed()
|
||||
},
|
||||
)
|
||||
.on_click(MouseButton::Left, move |_, cx| {
|
||||
cx.dispatch_any_action(action.boxed_clone())
|
||||
})
|
||||
.with_cursor_style(CursorStyle::PointingHand)
|
||||
.boxed()
|
||||
},
|
||||
)
|
||||
})
|
||||
.contained()
|
||||
.with_style(theme.keyboard_hints)
|
||||
.constrained()
|
||||
.with_max_width(theme.keyboard_hint_width)
|
||||
.aligned()
|
||||
.boxed(),
|
||||
])
|
||||
.aligned()
|
||||
.boxed(),
|
||||
])
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
impl Entity for Pane {
|
||||
@ -1508,11 +1574,8 @@ impl View for Pane {
|
||||
enum EmptyPane {}
|
||||
let theme = cx.global::<Settings>().theme.clone();
|
||||
|
||||
dragged_item_receiver::<EmptyPane, _>(0, 0, false, None, cx, |_, _| {
|
||||
Empty::new()
|
||||
.contained()
|
||||
.with_background_color(theme.workspace.background)
|
||||
.boxed()
|
||||
dragged_item_receiver::<EmptyPane, _>(0, 0, false, None, cx, |_, cx| {
|
||||
self.render_blank_pane(&theme, cx)
|
||||
})
|
||||
.on_down(MouseButton::Left, |_, cx| {
|
||||
cx.focus_parent_view();
|
||||
@ -1809,9 +1872,7 @@ mod tests {
|
||||
let fs = FakeFs::new(cx.background());
|
||||
|
||||
let project = Project::test(fs, None, cx).await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||
|
||||
// 1. Add with a destination index
|
||||
@ -1899,9 +1960,7 @@ mod tests {
|
||||
let fs = FakeFs::new(cx.background());
|
||||
|
||||
let project = Project::test(fs, None, cx).await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||
|
||||
// 1. Add with a destination index
|
||||
@ -1977,9 +2036,7 @@ mod tests {
|
||||
let fs = FakeFs::new(cx.background());
|
||||
|
||||
let project = Project::test(fs, None, cx).await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||
|
||||
// singleton view
|
||||
@ -2088,8 +2145,7 @@ mod tests {
|
||||
let fs = FakeFs::new(cx.background());
|
||||
|
||||
let project = Project::test(fs, None, cx).await;
|
||||
let (_, workspace) =
|
||||
cx.add_window(|cx| Workspace::new(None, 0, project, |_, _| unimplemented!(), cx));
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||
|
||||
add_labled_item(&workspace, &pane, "A", cx);
|
||||
|
@ -432,6 +432,7 @@ pub struct AppState {
|
||||
fn(Option<WindowBounds>, Option<uuid::Uuid>, &dyn Platform) -> WindowOptions<'static>,
|
||||
pub initialize_workspace: fn(&mut Workspace, &Arc<AppState>, &mut ViewContext<Workspace>),
|
||||
pub dock_default_item_factory: DockDefaultItemFactory,
|
||||
pub background_actions: BackgroundActions,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
@ -455,6 +456,7 @@ impl AppState {
|
||||
initialize_workspace: |_, _, _| {},
|
||||
build_window_options: |_, _, _| Default::default(),
|
||||
dock_default_item_factory: |_, _| unimplemented!(),
|
||||
background_actions: || unimplemented!(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -542,6 +544,7 @@ pub struct Workspace {
|
||||
active_call: Option<(ModelHandle<ActiveCall>, Vec<gpui::Subscription>)>,
|
||||
leader_updates_tx: mpsc::UnboundedSender<(PeerId, proto::UpdateFollowers)>,
|
||||
database_id: WorkspaceId,
|
||||
background_actions: BackgroundActions,
|
||||
_window_subscriptions: [Subscription; 3],
|
||||
_apply_leader_updates: Task<Result<()>>,
|
||||
_observe_current_user: Task<()>,
|
||||
@ -572,6 +575,7 @@ impl Workspace {
|
||||
workspace_id: WorkspaceId,
|
||||
project: ModelHandle<Project>,
|
||||
dock_default_factory: DockDefaultItemFactory,
|
||||
background_actions: BackgroundActions,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Self {
|
||||
cx.observe(&project, |_, _, cx| cx.notify()).detach();
|
||||
@ -602,7 +606,7 @@ impl Workspace {
|
||||
})
|
||||
.detach();
|
||||
|
||||
let center_pane = cx.add_view(|cx| Pane::new(None, cx));
|
||||
let center_pane = cx.add_view(|cx| Pane::new(None, background_actions, cx));
|
||||
let pane_id = center_pane.id();
|
||||
cx.subscribe(¢er_pane, move |this, _, event, cx| {
|
||||
this.handle_pane_event(pane_id, event, cx)
|
||||
@ -610,7 +614,7 @@ impl Workspace {
|
||||
.detach();
|
||||
cx.focus(¢er_pane);
|
||||
cx.emit(Event::PaneAdded(center_pane.clone()));
|
||||
let dock = Dock::new(dock_default_factory, cx);
|
||||
let dock = Dock::new(dock_default_factory, background_actions, cx);
|
||||
let dock_pane = dock.pane().clone();
|
||||
|
||||
let fs = project.read(cx).fs().clone();
|
||||
@ -730,6 +734,7 @@ impl Workspace {
|
||||
window_edited: false,
|
||||
active_call,
|
||||
database_id: workspace_id,
|
||||
background_actions,
|
||||
_observe_current_user,
|
||||
_apply_leader_updates,
|
||||
leader_updates_tx,
|
||||
@ -818,6 +823,7 @@ impl Workspace {
|
||||
workspace_id,
|
||||
project_handle,
|
||||
app_state.dock_default_item_factory,
|
||||
app_state.background_actions,
|
||||
cx,
|
||||
);
|
||||
(app_state.initialize_workspace)(&mut workspace, &app_state, cx);
|
||||
@ -1432,7 +1438,7 @@ impl Workspace {
|
||||
}
|
||||
|
||||
fn add_pane(&mut self, cx: &mut ViewContext<Self>) -> ViewHandle<Pane> {
|
||||
let pane = cx.add_view(|cx| Pane::new(None, cx));
|
||||
let pane = cx.add_view(|cx| Pane::new(None, self.background_actions, cx));
|
||||
let pane_id = pane.id();
|
||||
cx.subscribe(&pane, move |this, _, event, cx| {
|
||||
this.handle_pane_event(pane_id, event, cx)
|
||||
@ -2648,6 +2654,11 @@ impl Workspace {
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn test_new(project: ModelHandle<Project>, cx: &mut ViewContext<Self>) -> Self {
|
||||
Self::new(None, 0, project, |_, _| None, || &[], cx)
|
||||
}
|
||||
}
|
||||
|
||||
fn notify_if_database_failed(workspace: &ViewHandle<Workspace>, cx: &mut AsyncAppContext) {
|
||||
@ -2988,17 +2999,10 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
use fs::FakeFs;
|
||||
use gpui::{executor::Deterministic, TestAppContext, ViewContext};
|
||||
use gpui::{executor::Deterministic, TestAppContext};
|
||||
use project::{Project, ProjectEntryId};
|
||||
use serde_json::json;
|
||||
|
||||
pub fn default_item_factory(
|
||||
_workspace: &mut Workspace,
|
||||
_cx: &mut ViewContext<Workspace>,
|
||||
) -> Option<Box<dyn ItemHandle>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_tab_disambiguation(cx: &mut TestAppContext) {
|
||||
cx.foreground().forbid_parking();
|
||||
@ -3011,7 +3015,8 @@ mod tests {
|
||||
Default::default(),
|
||||
0,
|
||||
project.clone(),
|
||||
default_item_factory,
|
||||
|_, _| unimplemented!(),
|
||||
|| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
@ -3083,7 +3088,8 @@ mod tests {
|
||||
Default::default(),
|
||||
0,
|
||||
project.clone(),
|
||||
default_item_factory,
|
||||
|_, _| unimplemented!(),
|
||||
|| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
@ -3183,7 +3189,8 @@ mod tests {
|
||||
Default::default(),
|
||||
0,
|
||||
project.clone(),
|
||||
default_item_factory,
|
||||
|_, _| unimplemented!(),
|
||||
|| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
@ -3222,7 +3229,14 @@ mod tests {
|
||||
|
||||
let project = Project::test(fs, None, cx).await;
|
||||
let (window_id, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, default_item_factory, cx)
|
||||
Workspace::new(
|
||||
Default::default(),
|
||||
0,
|
||||
project,
|
||||
|_, _| unimplemented!(),
|
||||
|| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let item1 = cx.add_view(&workspace, |cx| {
|
||||
@ -3331,7 +3345,14 @@ mod tests {
|
||||
|
||||
let project = Project::test(fs, [], cx).await;
|
||||
let (window_id, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, default_item_factory, cx)
|
||||
Workspace::new(
|
||||
Default::default(),
|
||||
0,
|
||||
project,
|
||||
|_, _| unimplemented!(),
|
||||
|| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
// Create several workspace items with single project entries, and two
|
||||
@ -3440,7 +3461,14 @@ mod tests {
|
||||
|
||||
let project = Project::test(fs, [], cx).await;
|
||||
let (window_id, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, default_item_factory, cx)
|
||||
Workspace::new(
|
||||
Default::default(),
|
||||
0,
|
||||
project,
|
||||
|_, _| unimplemented!(),
|
||||
|| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let item = cx.add_view(&workspace, |cx| {
|
||||
@ -3559,7 +3587,14 @@ mod tests {
|
||||
|
||||
let project = Project::test(fs, [], cx).await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, default_item_factory, cx)
|
||||
Workspace::new(
|
||||
Default::default(),
|
||||
0,
|
||||
project,
|
||||
|_, _| unimplemented!(),
|
||||
|| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let item = cx.add_view(&workspace, |cx| {
|
||||
|
@ -18,7 +18,7 @@ use futures::{
|
||||
channel::{mpsc, oneshot},
|
||||
FutureExt, SinkExt, StreamExt,
|
||||
};
|
||||
use gpui::{App, AssetSource, AsyncAppContext, MutableAppContext, Task, ViewContext};
|
||||
use gpui::{Action, App, AssetSource, AsyncAppContext, MutableAppContext, Task, ViewContext};
|
||||
use isahc::{config::Configurable, Request};
|
||||
use language::LanguageRegistry;
|
||||
use log::LevelFilter;
|
||||
@ -45,9 +45,10 @@ use theme::ThemeRegistry;
|
||||
use util::StaffMode;
|
||||
use util::{channel::RELEASE_CHANNEL, paths, ResultExt, TryFutureExt};
|
||||
use workspace::{
|
||||
self, item::ItemHandle, notifications::NotifyResultExt, AppState, NewFile, OpenPaths, Workspace,
|
||||
self, dock::FocusDock, item::ItemHandle, notifications::NotifyResultExt, AppState, NewFile,
|
||||
OpenPaths, Workspace,
|
||||
};
|
||||
use zed::{self, build_window_options, initialize_workspace, languages, menus};
|
||||
use zed::{self, build_window_options, initialize_workspace, languages, menus, OpenSettings};
|
||||
|
||||
fn main() {
|
||||
let http = http::client();
|
||||
@ -186,6 +187,7 @@ fn main() {
|
||||
build_window_options,
|
||||
initialize_workspace,
|
||||
dock_default_item_factory,
|
||||
background_actions,
|
||||
});
|
||||
auto_update::init(http, client::ZED_SERVER_URL.clone(), cx);
|
||||
|
||||
@ -703,3 +705,13 @@ pub fn dock_default_item_factory(
|
||||
|
||||
Some(Box::new(terminal_view))
|
||||
}
|
||||
|
||||
pub fn background_actions() -> &'static [(&'static str, &'static dyn Action)] {
|
||||
&[
|
||||
("Go to file", &file_finder::Toggle),
|
||||
("Open the command palette", &command_palette::Toggle),
|
||||
("Focus the dock", &FocusDock),
|
||||
("Open recent projects", &recent_projects::OpenRecent),
|
||||
("Change your settings", &OpenSettings),
|
||||
]
|
||||
}
|
||||
|
@ -889,9 +889,7 @@ mod tests {
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||
|
||||
let entries = cx.read(|cx| workspace.file_project_paths(cx));
|
||||
let file1 = entries[0].clone();
|
||||
@ -1010,9 +1008,7 @@ mod tests {
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), ["/dir1".as_ref()], cx).await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||
|
||||
// Open a file within an existing worktree.
|
||||
cx.update(|cx| {
|
||||
@ -1171,9 +1167,7 @@ mod tests {
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||
let (window_id, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx)
|
||||
});
|
||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||
|
||||
// Open a file within an existing worktree.
|
||||
cx.update(|cx| {
|
||||
@ -1215,9 +1209,7 @@ mod tests {
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||
project.update(cx, |project, _| project.languages().add(rust_lang()));
|
||||
let (window_id, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx)
|
||||
});
|
||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||
let worktree = cx.read(|cx| workspace.read(cx).worktrees(cx).next().unwrap());
|
||||
|
||||
// Create a new untitled buffer
|
||||
@ -1306,9 +1298,7 @@ mod tests {
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), [], cx).await;
|
||||
project.update(cx, |project, _| project.languages().add(rust_lang()));
|
||||
let (window_id, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx)
|
||||
});
|
||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||
|
||||
// Create a new untitled buffer
|
||||
cx.dispatch_action(window_id, NewFile);
|
||||
@ -1361,9 +1351,7 @@ mod tests {
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||
let (window_id, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx)
|
||||
});
|
||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||
|
||||
let entries = cx.read(|cx| workspace.file_project_paths(cx));
|
||||
let file1 = entries[0].clone();
|
||||
@ -1437,15 +1425,7 @@ mod tests {
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(
|
||||
Default::default(),
|
||||
0,
|
||||
project.clone(),
|
||||
|_, _| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||
|
||||
let entries = cx.read(|cx| workspace.file_project_paths(cx));
|
||||
let file1 = entries[0].clone();
|
||||
@ -1709,15 +1689,7 @@ mod tests {
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
Workspace::new(
|
||||
Default::default(),
|
||||
0,
|
||||
project.clone(),
|
||||
|_, _| unimplemented!(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
|
||||
let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
|
||||
|
||||
let entries = cx.read(|cx| workspace.file_project_paths(cx));
|
||||
|
@ -26,14 +26,19 @@ export default function contextMenu(colorScheme: ColorScheme) {
|
||||
hover: {
|
||||
background: background(layer, "hovered"),
|
||||
label: text(layer, "sans", "hovered", { size: "sm" }),
|
||||
keystroke: {
|
||||
...text(layer, "sans", "hovered", {
|
||||
size: "sm",
|
||||
weight: "bold",
|
||||
}),
|
||||
padding: { left: 3, right: 3 },
|
||||
},
|
||||
},
|
||||
active: {
|
||||
background: background(layer, "active"),
|
||||
label: text(layer, "sans", "active", { size: "sm" }),
|
||||
},
|
||||
activeHover: {
|
||||
background: background(layer, "active"),
|
||||
label: text(layer, "sans", "active", { size: "sm" }),
|
||||
},
|
||||
},
|
||||
separator: {
|
||||
|
@ -86,20 +86,24 @@ export default function welcome(colorScheme: ColorScheme) {
|
||||
border: border(layer, "active"),
|
||||
},
|
||||
},
|
||||
checkboxContainer: {
|
||||
margin: {
|
||||
top: 4,
|
||||
},
|
||||
},
|
||||
checkbox: {
|
||||
label: {
|
||||
...text(layer, "sans", interactive_text_size),
|
||||
// Also supports margin, container, border, etc.
|
||||
},
|
||||
container: {
|
||||
margin: {
|
||||
top: 4,
|
||||
},
|
||||
icon: {
|
||||
color: foreground(layer, "on"),
|
||||
icon: "icons/check_12.svg",
|
||||
dimensions: {
|
||||
width: 12,
|
||||
height: 12,
|
||||
}
|
||||
},
|
||||
width: 12,
|
||||
height: 12,
|
||||
checkIcon: "icons/check_12.svg",
|
||||
checkIconColor: foreground(layer, "on"),
|
||||
default: {
|
||||
...checkboxBase,
|
||||
background: background(layer, "default"),
|
||||
|
@ -41,6 +41,34 @@ export default function workspace(colorScheme: ColorScheme) {
|
||||
|
||||
return {
|
||||
background: background(layer),
|
||||
blankPane: {
|
||||
logo: {
|
||||
color: background(layer, "on"),
|
||||
icon: "icons/logo_96.svg",
|
||||
dimensions: {
|
||||
width: 240,
|
||||
height: 240,
|
||||
}
|
||||
},
|
||||
keyboardHints: {
|
||||
margin: {
|
||||
top: 32
|
||||
},
|
||||
padding: {
|
||||
bottom: -8.
|
||||
}
|
||||
},
|
||||
keyboardHint: {
|
||||
...text(colorScheme.lowest, "sans", "variant", { size: "sm" }),
|
||||
margin: {
|
||||
bottom: 8
|
||||
},
|
||||
hover: {
|
||||
...text(colorScheme.lowest, "sans", "hovered", { size: "sm" }),
|
||||
}
|
||||
},
|
||||
keyboardHintWidth: 240,
|
||||
},
|
||||
joiningProjectAvatar: {
|
||||
cornerRadius: 40,
|
||||
width: 80,
|
||||
|
Loading…
Reference in New Issue
Block a user