Merge branch 'main' into following-tests
This commit is contained in:
commit
204ef451d0
224 changed files with 12664 additions and 23906 deletions
|
@ -672,9 +672,13 @@ impl Render for PanelButtons {
|
|||
&& panel.position_is_valid(position, cx)
|
||||
{
|
||||
let panel = panel.clone();
|
||||
menu = menu.entry(position.to_label(), None, move |cx| {
|
||||
panel.set_position(position, cx);
|
||||
})
|
||||
menu = menu.entry(
|
||||
format!("Dock {}", position.to_label()),
|
||||
None,
|
||||
move |cx| {
|
||||
panel.set_position(position, cx);
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
menu
|
||||
|
|
|
@ -246,7 +246,15 @@ impl Member {
|
|||
.size_full()
|
||||
.child(pane.clone())
|
||||
.when_some(leader_border, |this, color| {
|
||||
this.border_2().border_color(color)
|
||||
this.child(
|
||||
div()
|
||||
.absolute()
|
||||
.size_full()
|
||||
.left_0()
|
||||
.top_0()
|
||||
.border_2()
|
||||
.border_color(color),
|
||||
)
|
||||
})
|
||||
.when_some(leader_status_box, |this, status_box| {
|
||||
this.child(
|
||||
|
|
|
@ -6,7 +6,12 @@ use std::path::Path;
|
|||
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use db::{define_connection, query, sqlez::connection::Connection, sqlez_macros::sql};
|
||||
use gpui::{Axis, WindowBounds};
|
||||
use gpui::{point, size, Axis, Bounds, WindowBounds};
|
||||
|
||||
use sqlez::{
|
||||
bindable::{Bind, Column, StaticColumnCount},
|
||||
statement::Statement,
|
||||
};
|
||||
|
||||
use util::{unzip_option, ResultExt};
|
||||
use uuid::Uuid;
|
||||
|
@ -20,6 +25,121 @@ use model::{
|
|||
|
||||
use self::model::DockStructure;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub(crate) struct SerializedAxis(pub(crate) gpui::Axis);
|
||||
impl sqlez::bindable::StaticColumnCount for SerializedAxis {}
|
||||
impl sqlez::bindable::Bind for SerializedAxis {
|
||||
fn bind(
|
||||
&self,
|
||||
statement: &sqlez::statement::Statement,
|
||||
start_index: i32,
|
||||
) -> anyhow::Result<i32> {
|
||||
match self.0 {
|
||||
gpui::Axis::Horizontal => "Horizontal",
|
||||
gpui::Axis::Vertical => "Vertical",
|
||||
}
|
||||
.bind(statement, start_index)
|
||||
}
|
||||
}
|
||||
|
||||
impl sqlez::bindable::Column for SerializedAxis {
|
||||
fn column(
|
||||
statement: &mut sqlez::statement::Statement,
|
||||
start_index: i32,
|
||||
) -> anyhow::Result<(Self, i32)> {
|
||||
String::column(statement, start_index).and_then(|(axis_text, next_index)| {
|
||||
Ok((
|
||||
match axis_text.as_str() {
|
||||
"Horizontal" => Self(Axis::Horizontal),
|
||||
"Vertical" => Self(Axis::Vertical),
|
||||
_ => anyhow::bail!("Stored serialized item kind is incorrect"),
|
||||
},
|
||||
next_index,
|
||||
))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub(crate) struct SerializedWindowsBounds(pub(crate) WindowBounds);
|
||||
|
||||
impl StaticColumnCount for SerializedWindowsBounds {
|
||||
fn column_count() -> usize {
|
||||
5
|
||||
}
|
||||
}
|
||||
|
||||
impl Bind for SerializedWindowsBounds {
|
||||
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
|
||||
let (region, next_index) = match self.0 {
|
||||
WindowBounds::Fullscreen => {
|
||||
let next_index = statement.bind(&"Fullscreen", start_index)?;
|
||||
(None, next_index)
|
||||
}
|
||||
WindowBounds::Maximized => {
|
||||
let next_index = statement.bind(&"Maximized", start_index)?;
|
||||
(None, next_index)
|
||||
}
|
||||
WindowBounds::Fixed(region) => {
|
||||
let next_index = statement.bind(&"Fixed", start_index)?;
|
||||
(Some(region), next_index)
|
||||
}
|
||||
};
|
||||
|
||||
statement.bind(
|
||||
®ion.map(|region| {
|
||||
(
|
||||
SerializedGlobalPixels(region.origin.x),
|
||||
SerializedGlobalPixels(region.origin.y),
|
||||
SerializedGlobalPixels(region.size.width),
|
||||
SerializedGlobalPixels(region.size.height),
|
||||
)
|
||||
}),
|
||||
next_index,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Column for SerializedWindowsBounds {
|
||||
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
|
||||
let (window_state, next_index) = String::column(statement, start_index)?;
|
||||
let bounds = match window_state.as_str() {
|
||||
"Fullscreen" => SerializedWindowsBounds(WindowBounds::Fullscreen),
|
||||
"Maximized" => SerializedWindowsBounds(WindowBounds::Maximized),
|
||||
"Fixed" => {
|
||||
let ((x, y, width, height), _) = Column::column(statement, next_index)?;
|
||||
let x: f64 = x;
|
||||
let y: f64 = y;
|
||||
let width: f64 = width;
|
||||
let height: f64 = height;
|
||||
SerializedWindowsBounds(WindowBounds::Fixed(Bounds {
|
||||
origin: point(x.into(), y.into()),
|
||||
size: size(width.into(), height.into()),
|
||||
}))
|
||||
}
|
||||
_ => bail!("Window State did not have a valid string"),
|
||||
};
|
||||
|
||||
Ok((bounds, next_index + 4))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
struct SerializedGlobalPixels(gpui::GlobalPixels);
|
||||
impl sqlez::bindable::StaticColumnCount for SerializedGlobalPixels {}
|
||||
|
||||
impl sqlez::bindable::Bind for SerializedGlobalPixels {
|
||||
fn bind(
|
||||
&self,
|
||||
statement: &sqlez::statement::Statement,
|
||||
start_index: i32,
|
||||
) -> anyhow::Result<i32> {
|
||||
let this: f64 = self.0.into();
|
||||
let this: f32 = this as _;
|
||||
this.bind(statement, start_index)
|
||||
}
|
||||
}
|
||||
|
||||
define_connection! {
|
||||
// Current schema shape using pseudo-rust syntax:
|
||||
//
|
||||
|
@ -181,7 +301,7 @@ impl WorkspaceDb {
|
|||
/// Returns a serialized workspace for the given worktree_roots. If the passed array
|
||||
/// is empty, the most recent workspace is returned instead. If no workspace for the
|
||||
/// passed roots is stored, returns none.
|
||||
pub fn workspace_for_roots<P: AsRef<Path>>(
|
||||
pub(crate) fn workspace_for_roots<P: AsRef<Path>>(
|
||||
&self,
|
||||
worktree_roots: &[P],
|
||||
) -> Option<SerializedWorkspace> {
|
||||
|
@ -192,7 +312,7 @@ impl WorkspaceDb {
|
|||
let (workspace_id, workspace_location, bounds, display, docks): (
|
||||
WorkspaceId,
|
||||
WorkspaceLocation,
|
||||
Option<WindowBounds>,
|
||||
Option<SerializedWindowsBounds>,
|
||||
Option<Uuid>,
|
||||
DockStructure,
|
||||
) = self
|
||||
|
@ -230,7 +350,7 @@ impl WorkspaceDb {
|
|||
.get_center_pane_group(workspace_id)
|
||||
.context("Getting center group")
|
||||
.log_err()?,
|
||||
bounds,
|
||||
bounds: bounds.map(|bounds| bounds.0),
|
||||
display,
|
||||
docks,
|
||||
})
|
||||
|
@ -238,7 +358,7 @@ impl WorkspaceDb {
|
|||
|
||||
/// Saves a workspace using the worktree roots. Will garbage collect any workspaces
|
||||
/// that used this workspace previously
|
||||
pub async fn save_workspace(&self, workspace: SerializedWorkspace) {
|
||||
pub(crate) async fn save_workspace(&self, workspace: SerializedWorkspace) {
|
||||
self.write(move |conn| {
|
||||
conn.with_savepoint("update_worktrees", || {
|
||||
// Clear out panes and pane_groups
|
||||
|
@ -367,7 +487,7 @@ impl WorkspaceDb {
|
|||
type GroupKey = (Option<GroupId>, WorkspaceId);
|
||||
type GroupOrPane = (
|
||||
Option<GroupId>,
|
||||
Option<Axis>,
|
||||
Option<SerializedAxis>,
|
||||
Option<PaneId>,
|
||||
Option<bool>,
|
||||
Option<String>,
|
||||
|
@ -536,7 +656,7 @@ impl WorkspaceDb {
|
|||
}
|
||||
|
||||
query! {
|
||||
pub async fn set_window_bounds(workspace_id: WorkspaceId, bounds: WindowBounds, display: Uuid) -> Result<()> {
|
||||
pub(crate) async fn set_window_bounds(workspace_id: WorkspaceId, bounds: SerializedWindowsBounds, display: Uuid) -> Result<()> {
|
||||
UPDATE workspaces
|
||||
SET window_state = ?2,
|
||||
window_x = ?3,
|
||||
|
@ -683,7 +803,7 @@ mod tests {
|
|||
|
||||
fn group(axis: Axis, children: Vec<SerializedPaneGroup>) -> SerializedPaneGroup {
|
||||
SerializedPaneGroup::Group {
|
||||
axis,
|
||||
axis: SerializedAxis(axis),
|
||||
flexes: None,
|
||||
children,
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use super::SerializedAxis;
|
||||
use crate::{item::ItemHandle, ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId};
|
||||
use anyhow::{Context, Result};
|
||||
use async_recursion::async_recursion;
|
||||
|
@ -5,7 +6,7 @@ use db::sqlez::{
|
|||
bindable::{Bind, Column, StaticColumnCount},
|
||||
statement::Statement,
|
||||
};
|
||||
use gpui::{AsyncWindowContext, Axis, Model, Task, View, WeakView, WindowBounds};
|
||||
use gpui::{AsyncWindowContext, Model, Task, View, WeakView, WindowBounds};
|
||||
use project::Project;
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
|
@ -54,13 +55,13 @@ impl Column for WorkspaceLocation {
|
|||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct SerializedWorkspace {
|
||||
pub id: WorkspaceId,
|
||||
pub location: WorkspaceLocation,
|
||||
pub center_group: SerializedPaneGroup,
|
||||
pub bounds: Option<WindowBounds>,
|
||||
pub display: Option<Uuid>,
|
||||
pub docks: DockStructure,
|
||||
pub(crate) struct SerializedWorkspace {
|
||||
pub(crate) id: WorkspaceId,
|
||||
pub(crate) location: WorkspaceLocation,
|
||||
pub(crate) center_group: SerializedPaneGroup,
|
||||
pub(crate) bounds: Option<WindowBounds>,
|
||||
pub(crate) display: Option<Uuid>,
|
||||
pub(crate) docks: DockStructure,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Default)]
|
||||
|
@ -126,9 +127,9 @@ impl Bind for DockData {
|
|||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum SerializedPaneGroup {
|
||||
pub(crate) enum SerializedPaneGroup {
|
||||
Group {
|
||||
axis: Axis,
|
||||
axis: SerializedAxis,
|
||||
flexes: Option<Vec<f32>>,
|
||||
children: Vec<SerializedPaneGroup>,
|
||||
},
|
||||
|
@ -183,7 +184,7 @@ impl SerializedPaneGroup {
|
|||
}
|
||||
|
||||
Some((
|
||||
Member::Axis(PaneAxis::load(axis, members, flexes)),
|
||||
Member::Axis(PaneAxis::load(axis.0, members, flexes)),
|
||||
current_active_pane,
|
||||
items,
|
||||
))
|
||||
|
|
|
@ -42,9 +42,9 @@ use node_runtime::NodeRuntime;
|
|||
use notifications::{simple_message_notification::MessageNotification, NotificationHandle};
|
||||
pub use pane::*;
|
||||
pub use pane_group::*;
|
||||
use persistence::DB;
|
||||
use persistence::{model::SerializedWorkspace, SerializedWindowsBounds, DB};
|
||||
pub use persistence::{
|
||||
model::{ItemId, SerializedWorkspace, WorkspaceLocation},
|
||||
model::{ItemId, WorkspaceLocation},
|
||||
WorkspaceDb, DB as WORKSPACE_DB,
|
||||
};
|
||||
use postage::stream::Stream;
|
||||
|
@ -70,8 +70,9 @@ use util::ResultExt;
|
|||
use uuid::Uuid;
|
||||
pub use workspace_settings::{AutosaveSetting, WorkspaceSettings};
|
||||
|
||||
use crate::persistence::model::{
|
||||
DockData, DockStructure, SerializedItem, SerializedPane, SerializedPaneGroup,
|
||||
use crate::persistence::{
|
||||
model::{DockData, DockStructure, SerializedItem, SerializedPane, SerializedPaneGroup},
|
||||
SerializedAxis,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
|
@ -107,6 +108,7 @@ actions!(
|
|||
NewCenterTerminal,
|
||||
ToggleTerminalFocus,
|
||||
NewSearch,
|
||||
DeploySearch,
|
||||
Feedback,
|
||||
Restart,
|
||||
Welcome,
|
||||
|
@ -624,7 +626,11 @@ impl Workspace {
|
|||
|
||||
if let Some(display_uuid) = display.uuid().log_err() {
|
||||
cx.background_executor()
|
||||
.spawn(DB.set_window_bounds(workspace_id, bounds, display_uuid))
|
||||
.spawn(DB.set_window_bounds(
|
||||
workspace_id,
|
||||
SerializedWindowsBounds(bounds),
|
||||
display_uuid,
|
||||
))
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
}
|
||||
|
@ -1186,7 +1192,7 @@ impl Workspace {
|
|||
mut save_intent: SaveIntent,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Task<Result<bool>> {
|
||||
if self.project.read(cx).is_read_only() {
|
||||
if self.project.read(cx).is_disconnected() {
|
||||
return Task::ready(Ok(true));
|
||||
}
|
||||
let dirty_items = self
|
||||
|
@ -2509,7 +2515,7 @@ impl Workspace {
|
|||
}
|
||||
|
||||
fn update_window_edited(&mut self, cx: &mut ViewContext<Self>) {
|
||||
let is_edited = !self.project.read(cx).is_read_only()
|
||||
let is_edited = !self.project.read(cx).is_disconnected()
|
||||
&& self
|
||||
.items(cx)
|
||||
.any(|item| item.has_conflict(cx) || item.is_dirty(cx));
|
||||
|
@ -2988,7 +2994,7 @@ impl Workspace {
|
|||
flexes,
|
||||
bounding_boxes: _,
|
||||
}) => SerializedPaneGroup::Group {
|
||||
axis: *axis,
|
||||
axis: SerializedAxis(*axis),
|
||||
children: members
|
||||
.iter()
|
||||
.map(|member| build_serialized_pane_group(member, cx))
|
||||
|
@ -3265,6 +3271,7 @@ impl Workspace {
|
|||
let user_store = project.read(cx).user_store();
|
||||
|
||||
let workspace_store = cx.new_model(|cx| WorkspaceStore::new(client.clone(), cx));
|
||||
cx.activate_window();
|
||||
let app_state = Arc::new(AppState {
|
||||
languages: project.read(cx).languages().clone(),
|
||||
workspace_store,
|
||||
|
@ -3633,7 +3640,7 @@ impl Render for Workspace {
|
|||
})),
|
||||
)
|
||||
.child(self.status_bar.clone())
|
||||
.children(if self.project.read(cx).is_read_only() {
|
||||
.children(if self.project.read(cx).is_disconnected() {
|
||||
Some(DisconnectedOverlay)
|
||||
} else {
|
||||
None
|
||||
|
@ -4763,8 +4770,7 @@ mod tests {
|
|||
});
|
||||
|
||||
// Deactivating the window saves the file.
|
||||
cx.simulate_deactivation();
|
||||
cx.executor().run_until_parked();
|
||||
cx.deactivate_window();
|
||||
item.update(cx, |item, _| assert_eq!(item.save_count, 1));
|
||||
|
||||
// Autosave on focus change.
|
||||
|
@ -4784,14 +4790,13 @@ mod tests {
|
|||
item.update(cx, |item, _| assert_eq!(item.save_count, 2));
|
||||
|
||||
// Deactivating the window still saves the file.
|
||||
cx.simulate_activation();
|
||||
cx.update(|cx| cx.activate_window());
|
||||
item.update(cx, |item, cx| {
|
||||
cx.focus_self();
|
||||
item.is_dirty = true;
|
||||
});
|
||||
cx.simulate_deactivation();
|
||||
cx.deactivate_window();
|
||||
|
||||
cx.executor().run_until_parked();
|
||||
item.update(cx, |item, _| assert_eq!(item.save_count, 3));
|
||||
|
||||
// Autosave after delay.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue