Merge remote-tracking branch 'origin/main' into cache
# Conflicts: # crates/copilot/src/sign_in.rs # crates/gpui/src/window.rs # crates/workspace/src/pane_group.rs
This commit is contained in:
commit
1c260e6dfd
216 changed files with 4218 additions and 2389 deletions
|
@ -28,7 +28,7 @@ pub trait Panel: FocusableView + EventEmitter<PanelEvent> {
|
|||
fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext<Self>);
|
||||
fn size(&self, cx: &WindowContext) -> Pixels;
|
||||
fn set_size(&mut self, size: Option<Pixels>, cx: &mut ViewContext<Self>);
|
||||
fn icon(&self, cx: &WindowContext) -> Option<ui::Icon>;
|
||||
fn icon(&self, cx: &WindowContext) -> Option<ui::IconName>;
|
||||
fn icon_tooltip(&self, cx: &WindowContext) -> Option<&'static str>;
|
||||
fn toggle_action(&self) -> Box<dyn Action>;
|
||||
fn icon_label(&self, _: &WindowContext) -> Option<String> {
|
||||
|
@ -52,7 +52,7 @@ pub trait PanelHandle: Send + Sync {
|
|||
fn set_active(&self, active: bool, cx: &mut WindowContext);
|
||||
fn size(&self, cx: &WindowContext) -> Pixels;
|
||||
fn set_size(&self, size: Option<Pixels>, cx: &mut WindowContext);
|
||||
fn icon(&self, cx: &WindowContext) -> Option<ui::Icon>;
|
||||
fn icon(&self, cx: &WindowContext) -> Option<ui::IconName>;
|
||||
fn icon_tooltip(&self, cx: &WindowContext) -> Option<&'static str>;
|
||||
fn toggle_action(&self, cx: &WindowContext) -> Box<dyn Action>;
|
||||
fn icon_label(&self, cx: &WindowContext) -> Option<String>;
|
||||
|
@ -104,7 +104,7 @@ where
|
|||
self.update(cx, |this, cx| this.set_size(size, cx))
|
||||
}
|
||||
|
||||
fn icon(&self, cx: &WindowContext) -> Option<ui::Icon> {
|
||||
fn icon(&self, cx: &WindowContext) -> Option<ui::IconName> {
|
||||
self.read(cx).icon(cx)
|
||||
}
|
||||
|
||||
|
@ -167,15 +167,6 @@ impl DockPosition {
|
|||
}
|
||||
}
|
||||
|
||||
// todo!()
|
||||
// fn to_resize_handle_side(self) -> HandleSide {
|
||||
// match self {
|
||||
// Self::Left => HandleSide::Right,
|
||||
// Self::Bottom => HandleSide::Top,
|
||||
// Self::Right => HandleSide::Left,
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn axis(&self) -> Axis {
|
||||
match self {
|
||||
Self::Left | Self::Right => Axis::Horizontal,
|
||||
|
@ -186,8 +177,6 @@ impl DockPosition {
|
|||
|
||||
struct PanelEntry {
|
||||
panel: Arc<dyn PanelHandle>,
|
||||
// todo!()
|
||||
// context_menu: View<ContextMenu>,
|
||||
_subscriptions: [Subscription; 2],
|
||||
}
|
||||
|
||||
|
@ -265,12 +254,6 @@ impl Dock {
|
|||
self.is_open
|
||||
}
|
||||
|
||||
// todo!()
|
||||
// pub fn has_focus(&self, cx: &WindowContext) -> bool {
|
||||
// self.visible_panel()
|
||||
// .map_or(false, |panel| panel.has_focus(cx))
|
||||
// }
|
||||
|
||||
pub fn panel<T: Panel>(&self) -> Option<View<T>> {
|
||||
self.panel_entries
|
||||
.iter()
|
||||
|
@ -395,7 +378,6 @@ impl Dock {
|
|||
})
|
||||
.ok();
|
||||
}
|
||||
// todo!() we do not use this event in the production code (even in zed1), remove it
|
||||
PanelEvent::Activate => {
|
||||
if let Some(ix) = this
|
||||
.panel_entries
|
||||
|
@ -418,16 +400,8 @@ impl Dock {
|
|||
}),
|
||||
];
|
||||
|
||||
// todo!()
|
||||
// let dock_view_id = cx.view_id();
|
||||
self.panel_entries.push(PanelEntry {
|
||||
panel: Arc::new(panel),
|
||||
// todo!()
|
||||
// context_menu: cx.add_view(|cx| {
|
||||
// let mut menu = ContextMenu::new(dock_view_id, cx);
|
||||
// menu.set_position_mode(OverlayPositionMode::Local);
|
||||
// menu
|
||||
// }),
|
||||
_subscriptions: subscriptions,
|
||||
});
|
||||
cx.notify()
|
||||
|
@ -619,7 +593,6 @@ impl PanelButtons {
|
|||
|
||||
impl Render for PanelButtons {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
// todo!()
|
||||
let dock = self.dock.read(cx);
|
||||
let active_index = dock.active_panel_index;
|
||||
let is_open = dock.is_open;
|
||||
|
@ -775,7 +748,7 @@ pub mod test {
|
|||
self.size = size.unwrap_or(px(300.));
|
||||
}
|
||||
|
||||
fn icon(&self, _: &WindowContext) -> Option<ui::Icon> {
|
||||
fn icon(&self, _: &WindowContext) -> Option<ui::IconName> {
|
||||
None
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,13 @@ impl ClosePosition {
|
|||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct ItemSettingsContent {
|
||||
/// Whether to show the Git file status on a tab item.
|
||||
///
|
||||
/// Default: true
|
||||
git_status: Option<bool>,
|
||||
/// Position of the close button in a tab.
|
||||
///
|
||||
/// Default: right
|
||||
close_position: Option<ClosePosition>,
|
||||
}
|
||||
|
||||
|
|
|
@ -101,6 +101,10 @@ impl ModalLayer {
|
|||
let active_modal = self.active_modal.as_ref()?;
|
||||
active_modal.modal.view().downcast::<V>().ok()
|
||||
}
|
||||
|
||||
pub fn has_active_modal(&self) -> bool {
|
||||
self.active_modal.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for ModalLayer {
|
||||
|
|
|
@ -2,14 +2,12 @@ use crate::{Toast, Workspace};
|
|||
use collections::HashMap;
|
||||
use gpui::{
|
||||
AnyView, AppContext, AsyncWindowContext, DismissEvent, Entity, EntityId, EventEmitter, Render,
|
||||
View, ViewContext, VisualContext,
|
||||
Task, View, ViewContext, VisualContext, WindowContext,
|
||||
};
|
||||
use std::{any::TypeId, ops::DerefMut};
|
||||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
cx.set_global(NotificationTracker::new());
|
||||
// todo!()
|
||||
// simple_message_notification::init(cx);
|
||||
}
|
||||
|
||||
pub trait Notification: EventEmitter<DismissEvent> + Render {}
|
||||
|
@ -175,7 +173,7 @@ pub mod simple_message_notification {
|
|||
};
|
||||
use std::sync::Arc;
|
||||
use ui::prelude::*;
|
||||
use ui::{h_stack, v_stack, Button, Icon, IconElement, Label, StyledExt};
|
||||
use ui::{h_stack, v_stack, Button, Icon, IconName, Label, StyledExt};
|
||||
|
||||
pub struct MessageNotification {
|
||||
message: SharedString,
|
||||
|
@ -230,7 +228,7 @@ pub mod simple_message_notification {
|
|||
.child(
|
||||
div()
|
||||
.id("cancel")
|
||||
.child(IconElement::new(Icon::Close))
|
||||
.child(Icon::new(IconName::Close))
|
||||
.cursor_pointer()
|
||||
.on_click(cx.listener(|this, _, cx| this.dismiss(cx))),
|
||||
),
|
||||
|
@ -247,105 +245,6 @@ pub mod simple_message_notification {
|
|||
}))
|
||||
}
|
||||
}
|
||||
// todo!()
|
||||
// impl View for MessageNotification {
|
||||
// fn ui_name() -> &'static str {
|
||||
// "MessageNotification"
|
||||
// }
|
||||
|
||||
// fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> gpui::AnyElement<Self> {
|
||||
// let theme = theme::current(cx).clone();
|
||||
// let theme = &theme.simple_message_notification;
|
||||
|
||||
// enum MessageNotificationTag {}
|
||||
|
||||
// let click_message = self.click_message.clone();
|
||||
// let message = match &self.message {
|
||||
// NotificationMessage::Text(text) => {
|
||||
// Text::new(text.to_owned(), theme.message.text.clone()).into_any()
|
||||
// }
|
||||
// NotificationMessage::Element(e) => e(theme.message.text.clone(), cx),
|
||||
// };
|
||||
// let on_click = self.on_click.clone();
|
||||
// let has_click_action = on_click.is_some();
|
||||
|
||||
// Flex::column()
|
||||
// .with_child(
|
||||
// Flex::row()
|
||||
// .with_child(
|
||||
// message
|
||||
// .contained()
|
||||
// .with_style(theme.message.container)
|
||||
// .aligned()
|
||||
// .top()
|
||||
// .left()
|
||||
// .flex(1., true),
|
||||
// )
|
||||
// .with_child(
|
||||
// MouseEventHandler::new::<Cancel, _>(0, cx, |state, _| {
|
||||
// let style = theme.dismiss_button.style_for(state);
|
||||
// Svg::new("icons/x.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)
|
||||
// })
|
||||
// .with_padding(Padding::uniform(5.))
|
||||
// .on_click(MouseButton::Left, move |_, this, cx| {
|
||||
// this.dismiss(&Default::default(), cx);
|
||||
// })
|
||||
// .with_cursor_style(CursorStyle::PointingHand)
|
||||
// .aligned()
|
||||
// .constrained()
|
||||
// .with_height(cx.font_cache().line_height(theme.message.text.font_size))
|
||||
// .aligned()
|
||||
// .top()
|
||||
// .flex_float(),
|
||||
// ),
|
||||
// )
|
||||
// .with_children({
|
||||
// click_message
|
||||
// .map(|click_message| {
|
||||
// MouseEventHandler::new::<MessageNotificationTag, _>(
|
||||
// 0,
|
||||
// cx,
|
||||
// |state, _| {
|
||||
// let style = theme.action_message.style_for(state);
|
||||
|
||||
// Flex::row()
|
||||
// .with_child(
|
||||
// Text::new(click_message, style.text.clone())
|
||||
// .contained()
|
||||
// .with_style(style.container),
|
||||
// )
|
||||
// .contained()
|
||||
// },
|
||||
// )
|
||||
// .on_click(MouseButton::Left, move |_, this, cx| {
|
||||
// if let Some(on_click) = on_click.as_ref() {
|
||||
// on_click(cx);
|
||||
// this.dismiss(&Default::default(), cx);
|
||||
// }
|
||||
// })
|
||||
// // Since we're not using a proper overlay, we have to capture these extra events
|
||||
// .on_down(MouseButton::Left, |_, _, _| {})
|
||||
// .on_up(MouseButton::Left, |_, _, _| {})
|
||||
// .with_cursor_style(if has_click_action {
|
||||
// CursorStyle::PointingHand
|
||||
// } else {
|
||||
// CursorStyle::Arrow
|
||||
// })
|
||||
// })
|
||||
// .into_iter()
|
||||
// })
|
||||
// .into_any()
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
pub trait NotifyResultExt {
|
||||
|
@ -393,3 +292,18 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NotifyTaskExt {
|
||||
fn detach_and_notify_err(self, cx: &mut WindowContext);
|
||||
}
|
||||
|
||||
impl<R, E> NotifyTaskExt for Task<Result<R, E>>
|
||||
where
|
||||
E: std::fmt::Debug + 'static,
|
||||
R: 'static,
|
||||
{
|
||||
fn detach_and_notify_err(self, cx: &mut WindowContext) {
|
||||
cx.spawn(|mut cx| async move { self.await.notify_async_err(&mut cx) })
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ use std::{
|
|||
use theme::ThemeSettings;
|
||||
|
||||
use ui::{
|
||||
prelude::*, right_click_menu, ButtonSize, Color, Icon, IconButton, IconSize, Indicator, Label,
|
||||
Tab, TabBar, TabPosition, Tooltip,
|
||||
prelude::*, right_click_menu, ButtonSize, Color, IconButton, IconName, IconSize, Indicator,
|
||||
Label, Tab, TabBar, TabPosition, Tooltip,
|
||||
};
|
||||
use ui::{v_stack, ContextMenu};
|
||||
use util::{maybe, truncate_and_remove_front, ResultExt};
|
||||
|
@ -242,87 +242,6 @@ pub struct DraggedTab {
|
|||
pub is_active: bool,
|
||||
}
|
||||
|
||||
// pub struct DraggedItem {
|
||||
// pub handle: Box<dyn ItemHandle>,
|
||||
// pub pane: WeakView<Pane>,
|
||||
// }
|
||||
|
||||
// pub enum ReorderBehavior {
|
||||
// None,
|
||||
// MoveAfterActive,
|
||||
// MoveToIndex(usize),
|
||||
// }
|
||||
|
||||
// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
// enum TabBarContextMenuKind {
|
||||
// New,
|
||||
// Split,
|
||||
// }
|
||||
|
||||
// struct TabBarContextMenu {
|
||||
// kind: TabBarContextMenuKind,
|
||||
// handle: View<ContextMenu>,
|
||||
// }
|
||||
|
||||
// impl TabBarContextMenu {
|
||||
// fn handle_if_kind(&self, kind: TabBarContextMenuKind) -> Option<View<ContextMenu>> {
|
||||
// if self.kind == kind {
|
||||
// return Some(self.handle.clone());
|
||||
// }
|
||||
// None
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[allow(clippy::too_many_arguments)]
|
||||
// fn nav_button<A: Action, F: 'static + Fn(&mut Pane, &mut ViewContext<Pane>)>(
|
||||
// svg_path: &'static str,
|
||||
// style: theme::Interactive<theme2::IconButton>,
|
||||
// nav_button_height: f32,
|
||||
// tooltip_style: TooltipStyle,
|
||||
// enabled: bool,
|
||||
// on_click: F,
|
||||
// tooltip_action: A,
|
||||
// action_name: &str,
|
||||
// cx: &mut ViewContext<Pane>,
|
||||
// ) -> AnyElement<Pane> {
|
||||
// MouseEventHandler::new::<A, _>(0, cx, |state, _| {
|
||||
// let style = if enabled {
|
||||
// style.style_for(state)
|
||||
// } else {
|
||||
// style.disabled_style()
|
||||
// };
|
||||
// Svg::new(svg_path)
|
||||
// .with_color(style.color)
|
||||
// .constrained()
|
||||
// .with_width(style.icon_width)
|
||||
// .aligned()
|
||||
// .contained()
|
||||
// .with_style(style.container)
|
||||
// .constrained()
|
||||
// .with_width(style.button_width)
|
||||
// .with_height(nav_button_height)
|
||||
// .aligned()
|
||||
// .top()
|
||||
// })
|
||||
// .with_cursor_style(if enabled {
|
||||
// CursorStyle::PointingHand
|
||||
// } else {
|
||||
// CursorStyle::default()
|
||||
// })
|
||||
// .on_click(MouseButton::Left, move |_, toolbar, cx| {
|
||||
// on_click(toolbar, cx)
|
||||
// })
|
||||
// .with_tooltip::<A>(
|
||||
// 0,
|
||||
// action_name.to_string(),
|
||||
// Some(Box::new(tooltip_action)),
|
||||
// tooltip_style,
|
||||
// cx,
|
||||
// )
|
||||
// .contained()
|
||||
// .into_any_named("nav button")
|
||||
// }
|
||||
|
||||
impl EventEmitter<Event> for Pane {}
|
||||
|
||||
impl Pane {
|
||||
|
@ -333,13 +252,6 @@ impl Pane {
|
|||
can_drop_predicate: Option<Arc<dyn Fn(&dyn Any, &mut WindowContext) -> bool + 'static>>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Self {
|
||||
// todo!("context menu")
|
||||
// let pane_view_id = cx.view_id();
|
||||
// let context_menu = cx.build_view(|cx| ContextMenu::new(pane_view_id, cx));
|
||||
// context_menu.update(cx, |menu, _| {
|
||||
// menu.set_position_mode(OverlayPositionMode::Local)
|
||||
// });
|
||||
//
|
||||
let focus_handle = cx.focus_handle();
|
||||
|
||||
let subscriptions = vec![
|
||||
|
@ -370,11 +282,6 @@ impl Pane {
|
|||
split_item_menu: None,
|
||||
tab_bar_scroll_handle: ScrollHandle::new(),
|
||||
drag_split_direction: None,
|
||||
// tab_bar_context_menu: TabBarContextMenu {
|
||||
// kind: TabBarContextMenuKind::New,
|
||||
// handle: context_menu,
|
||||
// },
|
||||
// tab_context_menu: cx.build_view(|_| ContextMenu::new(pane_view_id, cx)),
|
||||
workspace,
|
||||
project,
|
||||
can_drop_predicate,
|
||||
|
@ -384,7 +291,7 @@ impl Pane {
|
|||
h_stack()
|
||||
.gap_2()
|
||||
.child(
|
||||
IconButton::new("plus", Icon::Plus)
|
||||
IconButton::new("plus", IconName::Plus)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.on_click(cx.listener(|pane, _, cx| {
|
||||
|
@ -406,7 +313,7 @@ impl Pane {
|
|||
el.child(Self::render_menu_overlay(new_item_menu))
|
||||
})
|
||||
.child(
|
||||
IconButton::new("split", Icon::Split)
|
||||
IconButton::new("split", IconName::Split)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.on_click(cx.listener(|pane, _, cx| {
|
||||
|
@ -427,11 +334,11 @@ impl Pane {
|
|||
)
|
||||
.child({
|
||||
let zoomed = pane.is_zoomed();
|
||||
IconButton::new("toggle_zoom", Icon::Maximize)
|
||||
IconButton::new("toggle_zoom", IconName::Maximize)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.selected(zoomed)
|
||||
.selected_icon(Icon::Minimize)
|
||||
.selected_icon(IconName::Minimize)
|
||||
.on_click(cx.listener(|pane, _, cx| {
|
||||
pane.toggle_zoom(&crate::ToggleZoom, cx);
|
||||
}))
|
||||
|
@ -450,7 +357,6 @@ impl Pane {
|
|||
}
|
||||
|
||||
pub fn has_focus(&self, cx: &WindowContext) -> bool {
|
||||
// todo!(); // inline this manually
|
||||
self.focus_handle.contains_focused(cx)
|
||||
}
|
||||
|
||||
|
@ -1570,7 +1476,7 @@ impl Pane {
|
|||
})
|
||||
.start_slot::<Indicator>(indicator)
|
||||
.end_slot(
|
||||
IconButton::new("close tab", Icon::Close)
|
||||
IconButton::new("close tab", IconName::Close)
|
||||
.icon_color(Color::Muted)
|
||||
.size(ButtonSize::None)
|
||||
.icon_size(IconSize::XSmall)
|
||||
|
@ -1676,7 +1582,7 @@ impl Pane {
|
|||
h_stack()
|
||||
.gap_2()
|
||||
.child(
|
||||
IconButton::new("navigate_backward", Icon::ArrowLeft)
|
||||
IconButton::new("navigate_backward", IconName::ArrowLeft)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click({
|
||||
let view = cx.view().clone();
|
||||
|
@ -1686,7 +1592,7 @@ impl Pane {
|
|||
.tooltip(|cx| Tooltip::for_action("Go Back", &GoBack, cx)),
|
||||
)
|
||||
.child(
|
||||
IconButton::new("navigate_forward", Icon::ArrowRight)
|
||||
IconButton::new("navigate_forward", IconName::ArrowRight)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click({
|
||||
let view = cx.view().clone();
|
||||
|
|
|
@ -12,7 +12,7 @@ use serde::Deserialize;
|
|||
use std::sync::Arc;
|
||||
use ui::{prelude::*, Button};
|
||||
|
||||
const HANDLE_HITBOX_SIZE: f32 = 10.0; //todo!(change this back to 4)
|
||||
pub const HANDLE_HITBOX_SIZE: f32 = 4.0;
|
||||
const HORIZONTAL_MIN_SIZE: f32 = 80.;
|
||||
const VERTICAL_MIN_SIZE: f32 = 100.;
|
||||
|
||||
|
@ -268,15 +268,6 @@ impl Member {
|
|||
)
|
||||
})
|
||||
.into_any()
|
||||
|
||||
// let el = div()
|
||||
// .flex()
|
||||
// .flex_1()
|
||||
// .gap_px()
|
||||
// .w_full()
|
||||
// .h_full()
|
||||
// .bg(cx.theme().colors().editor)
|
||||
// .children();
|
||||
}
|
||||
Member::Axis(axis) => axis
|
||||
.render(
|
||||
|
@ -487,6 +478,7 @@ impl PaneAxis {
|
|||
basis,
|
||||
self.flexes.clone(),
|
||||
self.bounding_boxes.clone(),
|
||||
cx.view().downgrade(),
|
||||
)
|
||||
.children(self.members.iter().enumerate().map(|(ix, member)| {
|
||||
if member.contains(active_pane) {
|
||||
|
@ -575,21 +567,28 @@ mod element {
|
|||
use gpui::{
|
||||
px, relative, Along, AnyElement, Axis, Bounds, CursorStyle, Element, InteractiveBounds,
|
||||
IntoElement, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point,
|
||||
Size, Style, WindowContext,
|
||||
Size, Style, WeakView, WindowContext,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use settings::Settings;
|
||||
use smallvec::SmallVec;
|
||||
use ui::prelude::*;
|
||||
use util::ResultExt;
|
||||
|
||||
use crate::Workspace;
|
||||
|
||||
use crate::WorkspaceSettings;
|
||||
|
||||
use super::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE};
|
||||
|
||||
const DIVIDER_SIZE: f32 = 1.0;
|
||||
|
||||
pub fn pane_axis(
|
||||
pub(super) fn pane_axis(
|
||||
axis: Axis,
|
||||
basis: usize,
|
||||
flexes: Arc<Mutex<Vec<f32>>>,
|
||||
bounding_boxes: Arc<Mutex<Vec<Option<Bounds<Pixels>>>>>,
|
||||
workspace: WeakView<Workspace>,
|
||||
) -> PaneAxisElement {
|
||||
PaneAxisElement {
|
||||
axis,
|
||||
|
@ -598,6 +597,7 @@ mod element {
|
|||
bounding_boxes,
|
||||
children: SmallVec::new(),
|
||||
active_pane_ix: None,
|
||||
workspace,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -608,6 +608,7 @@ mod element {
|
|||
bounding_boxes: Arc<Mutex<Vec<Option<Bounds<Pixels>>>>>,
|
||||
children: SmallVec<[AnyElement; 2]>,
|
||||
active_pane_ix: Option<usize>,
|
||||
workspace: WeakView<Workspace>,
|
||||
}
|
||||
|
||||
impl PaneAxisElement {
|
||||
|
@ -623,6 +624,7 @@ mod element {
|
|||
axis: Axis,
|
||||
child_start: Point<Pixels>,
|
||||
container_size: Size<Pixels>,
|
||||
workspace: WeakView<Workspace>,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
let min_size = match axis {
|
||||
|
@ -696,8 +698,9 @@ mod element {
|
|||
proposed_current_pixel_change -= current_pixel_change;
|
||||
}
|
||||
|
||||
// todo!(schedule serialize)
|
||||
// workspace.schedule_serialize(cx);
|
||||
workspace
|
||||
.update(cx, |this, cx| this.schedule_serialize(cx))
|
||||
.log_err();
|
||||
cx.refresh();
|
||||
}
|
||||
|
||||
|
@ -708,6 +711,7 @@ mod element {
|
|||
ix: usize,
|
||||
pane_bounds: Bounds<Pixels>,
|
||||
axis_bounds: Bounds<Pixels>,
|
||||
workspace: WeakView<Workspace>,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
let handle_bounds = Bounds {
|
||||
|
@ -742,24 +746,39 @@ mod element {
|
|||
|
||||
cx.on_mouse_event({
|
||||
let dragged_handle = dragged_handle.clone();
|
||||
move |e: &MouseDownEvent, phase, _cx| {
|
||||
let flexes = flexes.clone();
|
||||
let workspace = workspace.clone();
|
||||
move |e: &MouseDownEvent, phase, cx| {
|
||||
if phase.bubble() && handle_bounds.contains(&e.position) {
|
||||
dragged_handle.replace(Some(ix));
|
||||
if e.click_count >= 2 {
|
||||
let mut borrow = flexes.lock();
|
||||
*borrow = vec![1.; borrow.len()];
|
||||
workspace
|
||||
.update(cx, |this, cx| this.schedule_serialize(cx))
|
||||
.log_err();
|
||||
cx.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
cx.on_mouse_event(move |e: &MouseMoveEvent, phase, cx| {
|
||||
let dragged_handle = dragged_handle.borrow();
|
||||
if phase.bubble() && *dragged_handle == Some(ix) {
|
||||
Self::compute_resize(
|
||||
&flexes,
|
||||
e,
|
||||
ix,
|
||||
axis,
|
||||
pane_bounds.origin,
|
||||
axis_bounds.size,
|
||||
cx,
|
||||
)
|
||||
cx.on_mouse_event({
|
||||
let workspace = workspace.clone();
|
||||
move |e: &MouseMoveEvent, phase, cx| {
|
||||
let dragged_handle = dragged_handle.borrow();
|
||||
|
||||
if phase.bubble() && *dragged_handle == Some(ix) {
|
||||
Self::compute_resize(
|
||||
&flexes,
|
||||
e,
|
||||
ix,
|
||||
axis,
|
||||
pane_bounds.origin,
|
||||
axis_bounds.size,
|
||||
workspace.clone(),
|
||||
cx,
|
||||
)
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -808,20 +827,39 @@ mod element {
|
|||
debug_assert!(flexes.len() == len);
|
||||
debug_assert!(flex_values_in_bounds(flexes.as_slice()));
|
||||
|
||||
let magnification_value = WorkspaceSettings::get(None, cx).active_pane_magnification;
|
||||
let active_pane_magnification = if magnification_value == 1. {
|
||||
None
|
||||
} else {
|
||||
Some(magnification_value)
|
||||
};
|
||||
|
||||
let total_flex = if let Some(flex) = active_pane_magnification {
|
||||
self.children.len() as f32 - 1. + flex
|
||||
} else {
|
||||
len as f32
|
||||
};
|
||||
|
||||
let mut origin = bounds.origin;
|
||||
let space_per_flex = bounds.size.along(self.axis) / len as f32;
|
||||
let space_per_flex = bounds.size.along(self.axis) / total_flex;
|
||||
|
||||
let mut bounding_boxes = self.bounding_boxes.lock();
|
||||
bounding_boxes.clear();
|
||||
|
||||
for (ix, child) in self.children.iter_mut().enumerate() {
|
||||
//todo!(active_pane_magnification)
|
||||
// If using active pane magnification, need to switch to using
|
||||
// 1 for all non-active panes, and then the magnification for the
|
||||
// active pane.
|
||||
let child_flex = active_pane_magnification
|
||||
.map(|magnification| {
|
||||
if self.active_pane_ix == Some(ix) {
|
||||
magnification
|
||||
} else {
|
||||
1.
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| flexes[ix]);
|
||||
|
||||
let child_size = bounds
|
||||
.size
|
||||
.apply_along(self.axis, |_| space_per_flex * flexes[ix]);
|
||||
.apply_along(self.axis, |_| space_per_flex * child_flex);
|
||||
|
||||
let child_bounds = Bounds {
|
||||
origin,
|
||||
|
@ -831,19 +869,23 @@ mod element {
|
|||
cx.with_z_index(0, |cx| {
|
||||
child.draw(origin, child_size.into(), cx);
|
||||
});
|
||||
cx.with_z_index(1, |cx| {
|
||||
if ix < len - 1 {
|
||||
Self::push_handle(
|
||||
self.flexes.clone(),
|
||||
state.clone(),
|
||||
self.axis,
|
||||
ix,
|
||||
child_bounds,
|
||||
bounds,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if active_pane_magnification.is_none() {
|
||||
cx.with_z_index(1, |cx| {
|
||||
if ix < len - 1 {
|
||||
Self::push_handle(
|
||||
self.flexes.clone(),
|
||||
state.clone(),
|
||||
self.axis,
|
||||
ix,
|
||||
child_bounds,
|
||||
bounds,
|
||||
self.workspace.clone(),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
origin = origin.apply_along(self.axis, |val| val + child_size.along(self.axis));
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::{any::Any, sync::Arc};
|
||||
|
||||
use gpui::{
|
||||
AnyView, AppContext, EventEmitter, Subscription, Task, View, ViewContext, WeakView,
|
||||
WindowContext,
|
||||
AnyView, AnyWeakView, AppContext, EventEmitter, Subscription, Task, View, ViewContext,
|
||||
WeakView, WindowContext,
|
||||
};
|
||||
use project::search::SearchQuery;
|
||||
|
||||
|
@ -127,7 +127,6 @@ pub trait SearchableItemHandle: ItemHandle {
|
|||
) -> Option<usize>;
|
||||
}
|
||||
|
||||
// todo!("here is where we need to use AnyWeakView");
|
||||
impl<T: SearchableItem> SearchableItemHandle for View<T> {
|
||||
fn downgrade(&self) -> Box<dyn WeakSearchableItemHandle> {
|
||||
Box::new(self.downgrade())
|
||||
|
@ -249,7 +248,7 @@ impl Eq for Box<dyn SearchableItemHandle> {}
|
|||
pub trait WeakSearchableItemHandle: WeakItemHandle {
|
||||
fn upgrade(&self, cx: &AppContext) -> Option<Box<dyn SearchableItemHandle>>;
|
||||
|
||||
// fn into_any(self) -> AnyWeakView;
|
||||
fn into_any(self) -> AnyWeakView;
|
||||
}
|
||||
|
||||
impl<T: SearchableItem> WeakSearchableItemHandle for WeakView<T> {
|
||||
|
@ -257,9 +256,9 @@ impl<T: SearchableItem> WeakSearchableItemHandle for WeakView<T> {
|
|||
Some(Box::new(self.upgrade()?))
|
||||
}
|
||||
|
||||
// fn into_any(self) -> AnyView {
|
||||
// self.into_any()
|
||||
// }
|
||||
fn into_any(self) -> AnyWeakView {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Box<dyn WeakSearchableItemHandle> {
|
||||
|
|
|
@ -12,7 +12,7 @@ use gpui::{
|
|||
WindowContext,
|
||||
};
|
||||
use std::sync::{Arc, Weak};
|
||||
use ui::{h_stack, prelude::*, Icon, IconElement, Label};
|
||||
use ui::{h_stack, prelude::*, Icon, IconName, Label};
|
||||
|
||||
pub enum Event {
|
||||
Close,
|
||||
|
@ -100,7 +100,7 @@ impl Item for SharedScreen {
|
|||
) -> gpui::AnyElement {
|
||||
h_stack()
|
||||
.gap_1()
|
||||
.child(IconElement::new(Icon::Screen))
|
||||
.child(Icon::new(IconName::Screen))
|
||||
.child(
|
||||
Label::new(format!("{}'s screen", self.user.github_login)).color(if selected {
|
||||
Color::Default
|
||||
|
|
|
@ -133,82 +133,6 @@ impl Render for Toolbar {
|
|||
}
|
||||
}
|
||||
|
||||
// todo!()
|
||||
// impl View for Toolbar {
|
||||
// fn ui_name() -> &'static str {
|
||||
// "Toolbar"
|
||||
// }
|
||||
|
||||
// fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
|
||||
// let theme = &theme::current(cx).workspace.toolbar;
|
||||
|
||||
// let mut primary_left_items = Vec::new();
|
||||
// let mut primary_right_items = Vec::new();
|
||||
// let mut secondary_item = None;
|
||||
// let spacing = theme.item_spacing;
|
||||
// let mut primary_items_row_count = 1;
|
||||
|
||||
// for (item, position) in &self.items {
|
||||
// match *position {
|
||||
// ToolbarItemLocation::Hidden => {}
|
||||
|
||||
// ToolbarItemLocation::PrimaryLeft { flex } => {
|
||||
// primary_items_row_count = primary_items_row_count.max(item.row_count(cx));
|
||||
// let left_item = ChildView::new(item.as_any(), cx).aligned();
|
||||
// if let Some((flex, expanded)) = flex {
|
||||
// primary_left_items.push(left_item.flex(flex, expanded).into_any());
|
||||
// } else {
|
||||
// primary_left_items.push(left_item.into_any());
|
||||
// }
|
||||
// }
|
||||
|
||||
// ToolbarItemLocation::PrimaryRight { flex } => {
|
||||
// primary_items_row_count = primary_items_row_count.max(item.row_count(cx));
|
||||
// let right_item = ChildView::new(item.as_any(), cx).aligned().flex_float();
|
||||
// if let Some((flex, expanded)) = flex {
|
||||
// primary_right_items.push(right_item.flex(flex, expanded).into_any());
|
||||
// } else {
|
||||
// primary_right_items.push(right_item.into_any());
|
||||
// }
|
||||
// }
|
||||
|
||||
// ToolbarItemLocation::Secondary => {
|
||||
// secondary_item = Some(
|
||||
// ChildView::new(item.as_any(), cx)
|
||||
// .constrained()
|
||||
// .with_height(theme.height * item.row_count(cx) as f32)
|
||||
// .into_any(),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// let container_style = theme.container;
|
||||
// let height = theme.height * primary_items_row_count as f32;
|
||||
|
||||
// let mut primary_items = Flex::row().with_spacing(spacing);
|
||||
// primary_items.extend(primary_left_items);
|
||||
// primary_items.extend(primary_right_items);
|
||||
|
||||
// let mut toolbar = Flex::column();
|
||||
// if !primary_items.is_empty() {
|
||||
// toolbar.add_child(primary_items.constrained().with_height(height));
|
||||
// }
|
||||
// if let Some(secondary_item) = secondary_item {
|
||||
// toolbar.add_child(secondary_item);
|
||||
// }
|
||||
|
||||
// if toolbar.is_empty() {
|
||||
// toolbar.into_any_named("toolbar")
|
||||
// } else {
|
||||
// toolbar
|
||||
// .contained()
|
||||
// .with_style(container_style)
|
||||
// .into_any_named("toolbar")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl Toolbar {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
|
@ -312,10 +236,3 @@ impl<T: ToolbarItemView> ToolbarItemViewHandle for View<T> {
|
|||
self.read(cx).row_count(cx)
|
||||
}
|
||||
}
|
||||
|
||||
// todo!()
|
||||
// impl From<&dyn ToolbarItemViewHandle> for AnyViewHandle {
|
||||
// fn from(val: &dyn ToolbarItemViewHandle) -> Self {
|
||||
// val.as_any().clone()
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -26,12 +26,12 @@ use futures::{
|
|||
};
|
||||
use gpui::{
|
||||
actions, canvas, div, impl_actions, point, size, Action, AnyElement, AnyModel, AnyView,
|
||||
AnyWeakView, AnyWindowHandle, AppContext, AsyncAppContext, AsyncWindowContext, BorrowWindow,
|
||||
Bounds, Context, Div, DragMoveEvent, Element, Entity, EntityId, EventEmitter, FocusHandle,
|
||||
FocusableView, GlobalPixels, InteractiveElement, IntoElement, KeyContext, LayoutId,
|
||||
ManagedView, Model, ModelContext, ParentElement, PathPromptOptions, Pixels, Point, PromptLevel,
|
||||
Render, Size, Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView,
|
||||
WindowBounds, WindowContext, WindowHandle, WindowOptions,
|
||||
AnyWeakView, AppContext, AsyncAppContext, AsyncWindowContext, BorrowWindow, Bounds, Context,
|
||||
Div, DragMoveEvent, Element, Entity, EntityId, EventEmitter, FocusHandle, FocusableView,
|
||||
GlobalPixels, InteractiveElement, IntoElement, KeyContext, LayoutId, ManagedView, Model,
|
||||
ModelContext, ParentElement, PathPromptOptions, Pixels, Point, PromptLevel, Render, Size,
|
||||
Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowBounds,
|
||||
WindowContext, WindowHandle, WindowOptions,
|
||||
};
|
||||
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem};
|
||||
use itertools::Itertools;
|
||||
|
@ -537,7 +537,7 @@ impl Workspace {
|
|||
})
|
||||
.detach();
|
||||
|
||||
cx.on_blur_window(|this, cx| {
|
||||
cx.on_focus_lost(|this, cx| {
|
||||
let focus_handle = this.focus_handle(cx);
|
||||
cx.focus(&focus_handle);
|
||||
})
|
||||
|
@ -852,6 +852,10 @@ impl Workspace {
|
|||
&self.right_dock
|
||||
}
|
||||
|
||||
pub fn is_edited(&self) -> bool {
|
||||
self.window_edited
|
||||
}
|
||||
|
||||
pub fn add_panel<T: Panel>(&mut self, panel: View<T>, cx: &mut ViewContext<Self>) {
|
||||
let dock = match panel.position(cx) {
|
||||
DockPosition::Left => &self.left_dock,
|
||||
|
@ -943,10 +947,8 @@ impl Workspace {
|
|||
cx: &mut ViewContext<Workspace>,
|
||||
) -> Task<Result<()>> {
|
||||
let to_load = if let Some(pane) = pane.upgrade() {
|
||||
// todo!("focus")
|
||||
// cx.focus(&pane);
|
||||
|
||||
pane.update(cx, |pane, cx| {
|
||||
pane.focus(cx);
|
||||
loop {
|
||||
// Retrieve the weak item handle from the history.
|
||||
let entry = pane.nav_history_mut().pop(mode, cx)?;
|
||||
|
@ -1145,7 +1147,6 @@ impl Workspace {
|
|||
quitting: bool,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Task<Result<bool>> {
|
||||
//todo!(saveing)
|
||||
let active_call = self.active_call().cloned();
|
||||
let window = cx.window_handle();
|
||||
|
||||
|
@ -1631,8 +1632,7 @@ impl Workspace {
|
|||
});
|
||||
}
|
||||
|
||||
// todo!("focus")
|
||||
// cx.focus_self();
|
||||
cx.focus_self();
|
||||
cx.notify();
|
||||
self.serialize_workspace(cx);
|
||||
}
|
||||
|
@ -1697,27 +1697,6 @@ impl Workspace {
|
|||
None
|
||||
}
|
||||
|
||||
// todo!("implement zoom")
|
||||
#[allow(unused)]
|
||||
fn zoom_out(&mut self, cx: &mut ViewContext<Self>) {
|
||||
for pane in &self.panes {
|
||||
pane.update(cx, |pane, cx| pane.set_zoomed(false, cx));
|
||||
}
|
||||
|
||||
self.left_dock.update(cx, |dock, cx| dock.zoom_out(cx));
|
||||
self.bottom_dock.update(cx, |dock, cx| dock.zoom_out(cx));
|
||||
self.right_dock.update(cx, |dock, cx| dock.zoom_out(cx));
|
||||
self.zoomed = None;
|
||||
self.zoomed_position = None;
|
||||
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
// #[cfg(any(test, feature = "test-support"))]
|
||||
// pub fn zoomed_view(&self, cx: &AppContext) -> Option<AnyViewHandle> {
|
||||
// self.zoomed.and_then(|view| view.upgrade(cx))
|
||||
// }
|
||||
|
||||
fn dismiss_zoomed_items_to_reveal(
|
||||
&mut self,
|
||||
dock_to_reveal: Option<DockPosition>,
|
||||
|
@ -2080,7 +2059,7 @@ impl Workspace {
|
|||
_ => bounding_box.center(),
|
||||
};
|
||||
|
||||
let distance_to_next = 8.; //todo(pane dividers styling)
|
||||
let distance_to_next = pane_group::HANDLE_HITBOX_SIZE;
|
||||
|
||||
let target = match direction {
|
||||
SplitDirection::Left => {
|
||||
|
@ -2992,7 +2971,6 @@ impl Workspace {
|
|||
cx.notify();
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
fn schedule_serialize(&mut self, cx: &mut ViewContext<Self>) {
|
||||
self._schedule_serialize = Some(cx.spawn(|this, mut cx| async move {
|
||||
cx.background_executor()
|
||||
|
@ -3386,6 +3364,10 @@ impl Workspace {
|
|||
div
|
||||
}
|
||||
|
||||
pub fn has_active_modal(&self, cx: &WindowContext<'_>) -> bool {
|
||||
self.modal_layer.read(cx).has_active_modal()
|
||||
}
|
||||
|
||||
pub fn active_modal<V: ManagedView + 'static>(
|
||||
&mut self,
|
||||
cx: &ViewContext<Self>,
|
||||
|
@ -4034,34 +4016,34 @@ pub fn join_channel(
|
|||
return anyhow::Ok(());
|
||||
}
|
||||
|
||||
if requesting_window.is_some() {
|
||||
return anyhow::Ok(());
|
||||
}
|
||||
|
||||
// find an existing workspace to focus and show call controls
|
||||
let mut active_window = activate_any_workspace_window(&mut cx);
|
||||
let mut active_window =
|
||||
requesting_window.or_else(|| activate_any_workspace_window(&mut cx));
|
||||
if active_window.is_none() {
|
||||
// no open workspaces, make one to show the error in (blergh)
|
||||
cx.update(|cx| Workspace::new_local(vec![], app_state.clone(), requesting_window, cx))?
|
||||
let (window_handle, _) = cx
|
||||
.update(|cx| {
|
||||
Workspace::new_local(vec![], app_state.clone(), requesting_window, cx)
|
||||
})?
|
||||
.await?;
|
||||
|
||||
active_window = Some(window_handle);
|
||||
}
|
||||
|
||||
active_window = activate_any_workspace_window(&mut cx);
|
||||
let Some(active_window) = active_window else {
|
||||
return anyhow::Ok(());
|
||||
};
|
||||
|
||||
if let Err(err) = result {
|
||||
active_window
|
||||
.update(&mut cx, |_, cx| {
|
||||
cx.prompt(
|
||||
PromptLevel::Critical,
|
||||
&format!("Failed to join channel: {}", err),
|
||||
&["Ok"],
|
||||
)
|
||||
})?
|
||||
.await
|
||||
.ok();
|
||||
log::error!("failed to join channel: {}", err);
|
||||
if let Some(active_window) = active_window {
|
||||
active_window
|
||||
.update(&mut cx, |_, cx| {
|
||||
cx.prompt(
|
||||
PromptLevel::Critical,
|
||||
&format!("Failed to join channel: {}", err),
|
||||
&["Ok"],
|
||||
)
|
||||
})?
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
// return ok, we showed the error to the user.
|
||||
|
@ -4079,19 +4061,17 @@ pub async fn get_any_active_workspace(
|
|||
cx.update(|cx| Workspace::new_local(vec![], app_state.clone(), None, cx))?
|
||||
.await?;
|
||||
}
|
||||
activate_any_workspace_window(&mut cx)
|
||||
.context("could not open zed")?
|
||||
.downcast::<Workspace>()
|
||||
.context("could not open zed workspace window")
|
||||
activate_any_workspace_window(&mut cx).context("could not open zed")
|
||||
}
|
||||
|
||||
fn activate_any_workspace_window(cx: &mut AsyncAppContext) -> Option<AnyWindowHandle> {
|
||||
fn activate_any_workspace_window(cx: &mut AsyncAppContext) -> Option<WindowHandle<Workspace>> {
|
||||
cx.update(|cx| {
|
||||
for window in cx.windows() {
|
||||
let is_workspace = window.downcast::<Workspace>().is_some();
|
||||
if is_workspace {
|
||||
window.update(cx, |_, cx| cx.activate_window()).ok();
|
||||
return Some(window);
|
||||
if let Some(workspace_window) = window.downcast::<Workspace>() {
|
||||
workspace_window
|
||||
.update(cx, |_, cx| cx.activate_window())
|
||||
.ok();
|
||||
return Some(workspace_window);
|
||||
}
|
||||
}
|
||||
None
|
||||
|
|
|
@ -12,35 +12,39 @@ pub struct WorkspaceSettings {
|
|||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct WorkspaceSettingsContent {
|
||||
/// Scale by which to zoom the active pane.
|
||||
/// When set to 1.0, the active pane has the same size as others,
|
||||
/// but when set to a larger value, the active pane takes up more space.
|
||||
///
|
||||
/// Default: `1.0`
|
||||
pub active_pane_magnification: Option<f32>,
|
||||
/// Whether or not to prompt the user to confirm before closing the application.
|
||||
///
|
||||
/// Default: false
|
||||
pub confirm_quit: Option<bool>,
|
||||
/// Whether or not to show the call status icon in the status bar.
|
||||
///
|
||||
/// Default: true
|
||||
pub show_call_status_icon: Option<bool>,
|
||||
/// When to automatically save edited buffers.
|
||||
///
|
||||
/// Default: off
|
||||
pub autosave: Option<AutosaveSetting>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum AutosaveSetting {
|
||||
/// Disable autosave.
|
||||
Off,
|
||||
/// Save after inactivity period of `milliseconds`.
|
||||
AfterDelay { milliseconds: u64 },
|
||||
/// Autosave when focus changes.
|
||||
OnFocusChange,
|
||||
/// Autosave when the active window changes.
|
||||
OnWindowChange,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct GitSettings {
|
||||
pub git_gutter: Option<GitGutterSetting>,
|
||||
pub gutter_debounce: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum GitGutterSetting {
|
||||
#[default]
|
||||
TrackedFiles,
|
||||
Hide,
|
||||
}
|
||||
|
||||
impl Settings for WorkspaceSettings {
|
||||
const KEY: Option<&'static str> = None;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue