pub mod model; use std::path::Path; use anyhow::{anyhow, bail, Context, Result};use client::DevServerProjectId;use db::{define_connection, query, sqlez::connection::Connection, sqlez_macros::sql};use gpui::{point, size, Axis, Bounds, WindowBounds, WindowId}; use sqlez::{ bindable::{Bind, Column, StaticColumnCount}, statement::Statement,}; use ui::px;use util::{maybe, ResultExt};use uuid::Uuid; use crate::WorkspaceId; use model::{ GroupId, LocalPaths, PaneId, SerializedItem, SerializedPane, SerializedPaneGroup, SerializedWorkspace,}; use self::model::{ DockStructure, LocalPathsOrder, SerializedDevServerProject, SerializedWorkspaceLocation,}; #[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(Copy, Clone, Debug, PartialEq, Default)]pub(crate) struct SerializedWindowBounds(pub(crate) WindowBounds); impl StaticColumnCount for SerializedWindowBounds { fn column_count() -> usize { 5 }} impl Bind for SerializedWindowBounds { fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> { match self.0 { WindowBounds::Windowed(bounds) => { let next_index = statement.bind(&"Windowed", start_index)?; statement.bind( &( SerializedPixels(bounds.origin.x), SerializedPixels(bounds.origin.y), SerializedPixels(bounds.size.width), SerializedPixels(bounds.size.height), ), next_index, ) } WindowBounds::Maximized(bounds) => { let next_index = statement.bind(&"Maximized", start_index)?; statement.bind( &( SerializedPixels(bounds.origin.x), SerializedPixels(bounds.origin.y), SerializedPixels(bounds.size.width), SerializedPixels(bounds.size.height), ), next_index, ) } WindowBounds::Fullscreen(bounds) => { let next_index = statement.bind(&"FullScreen", start_index)?; statement.bind( &( SerializedPixels(bounds.origin.x), SerializedPixels(bounds.origin.y), SerializedPixels(bounds.size.width), SerializedPixels(bounds.size.height), ), next_index, ) } } }} impl Column for SerializedWindowBounds { fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> { let (window_state, next_index) = String::column(statement, start_index)?; let ((x, y, width, height), _): ((i32, i32, i32, i32), _) = Column::column(statement, next_index)?; let bounds = Bounds { origin: point(px(x as f32), px(y as f32)), size: size(px(width as f32), px(height as f32)), }; let status = match window_state.as_str() { "Windowed" | "Fixed" => SerializedWindowBounds(WindowBounds::Windowed(bounds)), "Maximized" => SerializedWindowBounds(WindowBounds::Maximized(bounds)), "FullScreen" => SerializedWindowBounds(WindowBounds::Fullscreen(bounds)), _ => bail!("Window State did not have a valid string"), }; Ok((status, next_index + 4)) }} #[derive(Clone, Debug, PartialEq)]struct SerializedPixels(gpui::Pixels);impl sqlez::bindable::StaticColumnCount for SerializedPixels {} impl sqlez::bindable::Bind for SerializedPixels { fn bind( &self, statement: &sqlez::statement::Statement, start_index: i32, ) -> anyhow::Result<i32> { let this: i32 = self.0 .0 as i32; this.bind(statement, start_index) }} define_connection! { // Current schema shape using pseudo-rust syntax: // // workspaces( // workspace_id: usize, // Primary key for workspaces // local_paths: Bincode<Vec<PathBuf>>, // local_paths_order: Bincode<Vec<usize>>, // dock_visible: bool, // Deprecated // dock_anchor: DockAnchor, // Deprecated // dock_pane: Option<usize>, // Deprecated // left_sidebar_open: boolean, // timestamp: String, // UTC YYYY-MM-DD HH:MM:SS // window_state: String, // WindowBounds Discriminant // window_x: Option<f32>, // WindowBounds::Fixed RectF x // window_y: Option<f32>, // WindowBounds::Fixed RectF y // window_width: Option<f32>, // WindowBounds::Fixed RectF width // window_height: Option<f32>, // WindowBounds::Fixed RectF height // display: Option<Uuid>, // Display id // fullscreen: Option<bool>, // Is the window fullscreen? // centered_layout: Option<bool>, // Is the Centered Layout mode activated? // session_id: Option<String>, // Session id // window_id: Option<u64>, // Window Id // ) // // pane_groups( // group_id: usize, // Primary key for pane_groups // workspace_id: usize, // References workspaces table // parent_group_id: Option<usize>, // None indicates that this is the root node // position: Optiopn<usize>, // None indicates that this is the root node // axis: Option<Axis>, // 'Vertical', 'Horizontal' // flexes: Option<Vec<f32>>, // A JSON array of floats // ) // // panes( // pane_id: usize, // Primary key for panes // workspace_id: usize, // References workspaces table // active: bool, // ) // // center_panes( // pane_id: usize, // Primary key for center_panes // parent_group_id: Option<usize>, // References pane_groups. If none, this is the root // position: Option<usize>, // None indicates this is the root // ) // // CREATE TABLE items( // item_id: usize, // This is the item's view id, so this is not unique // workspace_id: usize, // References workspaces table // pane_id: usize, // References panes table // kind: String, // Indicates which view this connects to. This is the key in the item_deserializers global // position: usize, // Position of the item in the parent pane. This is equivalent to panes' position column // active: bool, // Indicates if this item is the active one in the pane // preview: bool // Indicates if this item is a preview item // ) pub static ref DB: WorkspaceDb<()> = &[sql!( CREATE TABLE workspaces( workspace_id INTEGER PRIMARY KEY, workspace_location BLOB UNIQUE, dock_visible INTEGER, // Deprecated. Preserving so users can downgrade Zed. dock_anchor TEXT, // Deprecated. Preserving so users can downgrade Zed. dock_pane INTEGER, // Deprecated. Preserving so users can downgrade Zed. left_sidebar_open INTEGER, // Boolean timestamp TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL, FOREIGN KEY(dock_pane) REFERENCES panes(pane_id) ) STRICT; CREATE TABLE pane_groups( group_id INTEGER PRIMARY KEY, workspace_id INTEGER NOT NULL, parent_group_id INTEGER, // NULL indicates that this is a root node position INTEGER, // NULL indicates that this is a root node axis TEXT NOT NULL, // Enum: 'Vertical' / 'Horizontal' FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY(parent_group_id) REFERENCES pane_groups(group_id) ON DELETE CASCADE ) STRICT; CREATE TABLE panes( pane_id INTEGER PRIMARY KEY, workspace_id INTEGER NOT NULL, active INTEGER NOT NULL, // Boolean FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE CASCADE ON UPDATE CASCADE ) STRICT; CREATE TABLE center_panes( pane_id INTEGER PRIMARY KEY, parent_group_id INTEGER, // NULL means that this is a root pane position INTEGER, // NULL means that this is a root pane FOREIGN KEY(pane_id) REFERENCES panes(pane_id) ON DELETE CASCADE, FOREIGN KEY(parent_group_id) REFERENCES pane_groups(group_id) ON DELETE CASCADE ) STRICT; CREATE TABLE items( item_id INTEGER NOT NULL, // This is the item's view id, so this is not unique workspace_id INTEGER NOT NULL, pane_id INTEGER NOT NULL, kind TEXT NOT NULL, position INTEGER NOT NULL, active INTEGER NOT NULL, FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY(pane_id) REFERENCES panes(pane_id) ON DELETE CASCADE, PRIMARY KEY(item_id, workspace_id) ) STRICT; ), sql!( ALTER TABLE workspaces ADD COLUMN window_state TEXT; ALTER TABLE workspaces ADD COLUMN window_x REAL; ALTER TABLE workspaces ADD COLUMN window_y REAL; ALTER TABLE workspaces ADD COLUMN window_width REAL; ALTER TABLE workspaces ADD COLUMN window_height REAL; ALTER TABLE workspaces ADD COLUMN display BLOB; ), // Drop foreign key constraint from workspaces.dock_pane to panes table. sql!( CREATE TABLE workspaces_2( workspace_id INTEGER PRIMARY KEY, workspace_location BLOB UNIQUE, dock_visible INTEGER, // Deprecated. Preserving so users can downgrade Zed. dock_anchor TEXT, // Deprecated. Preserving so users can downgrade Zed. dock_pane INTEGER, // Deprecated. Preserving so users can downgrade Zed. left_sidebar_open INTEGER, // Boolean timestamp TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL, window_state TEXT, window_x REAL, window_y REAL, window_width REAL, window_height REAL, display BLOB ) STRICT; INSERT INTO workspaces_2 SELECT * FROM workspaces; DROP TABLE workspaces; ALTER TABLE workspaces_2 RENAME TO workspaces; ), // Add panels related information sql!( ALTER TABLE workspaces ADD COLUMN left_dock_visible INTEGER; //bool ALTER TABLE workspaces ADD COLUMN left_dock_active_panel TEXT; ALTER TABLE workspaces ADD COLUMN right_dock_visible INTEGER; //bool ALTER TABLE workspaces ADD COLUMN right_dock_active_panel TEXT; ALTER TABLE workspaces ADD COLUMN bottom_dock_visible INTEGER; //bool ALTER TABLE workspaces ADD COLUMN bottom_dock_active_panel TEXT; ), // Add panel zoom persistence sql!( ALTER TABLE workspaces ADD COLUMN left_dock_zoom INTEGER; //bool ALTER TABLE workspaces ADD COLUMN right_dock_zoom INTEGER; //bool ALTER TABLE workspaces ADD COLUMN bottom_dock_zoom INTEGER; //bool ), // Add pane group flex data sql!( ALTER TABLE pane_groups ADD COLUMN flexes TEXT; ), // Add fullscreen field to workspace // Deprecated, `WindowBounds` holds the fullscreen state now. // Preserving so users can downgrade Zed. sql!( ALTER TABLE workspaces ADD COLUMN fullscreen INTEGER; //bool ), // Add preview field to items sql!( ALTER TABLE items ADD COLUMN preview INTEGER; //bool ), // Add centered_layout field to workspace sql!( ALTER TABLE workspaces ADD COLUMN centered_layout INTEGER; //bool ), sql!( CREATE TABLE remote_projects ( remote_project_id INTEGER NOT NULL UNIQUE, path TEXT, dev_server_name TEXT ); ALTER TABLE workspaces ADD COLUMN remote_project_id INTEGER; ALTER TABLE workspaces RENAME COLUMN workspace_location TO local_paths; ), sql!( DROP TABLE remote_projects; CREATE TABLE dev_server_projects ( id INTEGER NOT NULL UNIQUE, path TEXT, dev_server_name TEXT ); ALTER TABLE workspaces DROP COLUMN remote_project_id; ALTER TABLE workspaces ADD COLUMN dev_server_project_id INTEGER; ), sql!( ALTER TABLE workspaces ADD COLUMN local_paths_order BLOB; ), sql!( ALTER TABLE workspaces ADD COLUMN session_id TEXT DEFAULT NULL; ), sql!( ALTER TABLE workspaces ADD COLUMN window_id INTEGER DEFAULT NULL; ), sql!( ALTER TABLE panes ADD COLUMN pinned_count INTEGER DEFAULT 0; ) ];} 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(crate) fn workspace_for_roots<P: AsRef<Path>>( &self, worktree_roots: &[P], ) -> Option<SerializedWorkspace> { let local_paths = LocalPaths::new(worktree_roots); // Note that we re-assign the workspace_id here in case it's empty // and we've grabbed the most recent workspace let ( workspace_id, local_paths, local_paths_order, dev_server_project_id, window_bounds, display, centered_layout, docks, window_id, ): ( WorkspaceId, Option<LocalPaths>, Option<LocalPathsOrder>, Option<u64>, Option<SerializedWindowBounds>, Option<Uuid>, Option<bool>, DockStructure, Option<u64>, ) = self .select_row_bound(sql! { SELECT workspace_id, local_paths, local_paths_order, dev_server_project_id, window_state, window_x, window_y, window_width, window_height, display, centered_layout, left_dock_visible, left_dock_active_panel, left_dock_zoom, right_dock_visible, right_dock_active_panel, right_dock_zoom, bottom_dock_visible, bottom_dock_active_panel, bottom_dock_zoom, window_id FROM workspaces WHERE local_paths = ? }) .and_then(|mut prepared_statement| (prepared_statement)(&local_paths)) .context("No workspaces found") .warn_on_err() .flatten()?; let location = if let Some(dev_server_project_id) = dev_server_project_id { let dev_server_project: SerializedDevServerProject = self .select_row_bound(sql! { SELECT id, path, dev_server_name FROM dev_server_projects WHERE id = ? }) .and_then(|mut prepared_statement| (prepared_statement)(dev_server_project_id)) .context("No remote project found") .warn_on_err() .flatten()?; SerializedWorkspaceLocation::DevServer(dev_server_project) } else if let Some(local_paths) = local_paths { match local_paths_order { Some(order) => SerializedWorkspaceLocation::Local(local_paths, order), None => { let order = LocalPathsOrder::default_for_paths(&local_paths); SerializedWorkspaceLocation::Local(local_paths, order) } } } else { return None; }; Some(SerializedWorkspace { id: workspace_id, location, center_group: self .get_center_pane_group(workspace_id) .context("Getting center group") .log_err()?, window_bounds, centered_layout: centered_layout.unwrap_or(false), display, docks, session_id: None, window_id, }) } pub(crate) fn workspace_for_dev_server_project( &self, dev_server_project_id: DevServerProjectId, ) -> Option<SerializedWorkspace> { // Note that we re-assign the workspace_id here in case it's empty // and we've grabbed the most recent workspace let ( workspace_id, local_paths, local_paths_order, dev_server_project_id, window_bounds, display, centered_layout, docks, window_id, ): ( WorkspaceId, Option<LocalPaths>, Option<LocalPathsOrder>, Option<u64>, Option<SerializedWindowBounds>, Option<Uuid>, Option<bool>, DockStructure, Option<u64>, ) = self .select_row_bound(sql! { SELECT workspace_id, local_paths, local_paths_order, dev_server_project_id, window_state, window_x, window_y,Lines 1–500 of 1645. Load more
pub mod model; use std::path::Path; use anyhow::{anyhow, bail, Context, Result}; use client::DevServerProjectId; use db::{define_connection, query, sqlez::connection::Connection, sqlez_macros::sql}; use gpui::{point, size, Axis, Bounds, WindowBounds, WindowId}; use sqlez::{ bindable::{Bind, Column, StaticColumnCount}, statement::Statement, }; use ui::px; use util::{maybe, ResultExt}; use uuid::Uuid; use crate::WorkspaceId; use model::{ GroupId, LocalPaths, PaneId, SerializedItem, SerializedPane, SerializedPaneGroup, SerializedWorkspace, }; use self::model::{ DockStructure, LocalPathsOrder, SerializedDevServerProject, SerializedWorkspaceLocation, }; #[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(Copy, Clone, Debug, PartialEq, Default)] pub(crate) struct SerializedWindowBounds(pub(crate) WindowBounds); impl StaticColumnCount for SerializedWindowBounds { fn column_count() -> usize { 5 } } impl Bind for SerializedWindowBounds { fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> { match self.0 { WindowBounds::Windowed(bounds) => { let next_index = statement.bind(&"Windowed", start_index)?; statement.bind( &( SerializedPixels(bounds.origin.x), SerializedPixels(bounds.origin.y), SerializedPixels(bounds.size.width), SerializedPixels(bounds.size.height), ), next_index, ) } WindowBounds::Maximized(bounds) => { let next_index = statement.bind(&"Maximized", start_index)?; statement.bind( &( SerializedPixels(bounds.origin.x), SerializedPixels(bounds.origin.y), SerializedPixels(bounds.size.width), SerializedPixels(bounds.size.height), ), next_index, ) } WindowBounds::Fullscreen(bounds) => { let next_index = statement.bind(&"FullScreen", start_index)?; statement.bind( &( SerializedPixels(bounds.origin.x), SerializedPixels(bounds.origin.y), SerializedPixels(bounds.size.width), SerializedPixels(bounds.size.height), ), next_index, ) } } } } impl Column for SerializedWindowBounds { fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> { let (window_state, next_index) = String::column(statement, start_index)?; let ((x, y, width, height), _): ((i32, i32, i32, i32), _) = Column::column(statement, next_index)?; let bounds = Bounds { origin: point(px(x as f32), px(y as f32)), size: size(px(width as f32), px(height as f32)), }; let status = match window_state.as_str() { "Windowed" | "Fixed" => SerializedWindowBounds(WindowBounds::Windowed(bounds)), "Maximized" => SerializedWindowBounds(WindowBounds::Maximized(bounds)), "FullScreen" => SerializedWindowBounds(WindowBounds::Fullscreen(bounds)), _ => bail!("Window State did not have a valid string"), }; Ok((status, next_index + 4)) } } #[derive(Clone, Debug, PartialEq)] struct SerializedPixels(gpui::Pixels); impl sqlez::bindable::StaticColumnCount for SerializedPixels {} impl sqlez::bindable::Bind for SerializedPixels { fn bind( &self, statement: &sqlez::statement::Statement, start_index: i32, ) -> anyhow::Result<i32> { let this: i32 = self.0 .0 as i32; this.bind(statement, start_index) } } define_connection! { // Current schema shape using pseudo-rust syntax: // // workspaces( // workspace_id: usize, // Primary key for workspaces // local_paths: Bincode<Vec<PathBuf>>, // local_paths_order: Bincode<Vec<usize>>, // dock_visible: bool, // Deprecated // dock_anchor: DockAnchor, // Deprecated // dock_pane: Option<usize>, // Deprecated // left_sidebar_open: boolean, // timestamp: String, // UTC YYYY-MM-DD HH:MM:SS // window_state: String, // WindowBounds Discriminant // window_x: Option<f32>, // WindowBounds::Fixed RectF x // window_y: Option<f32>, // WindowBounds::Fixed RectF y // window_width: Option<f32>, // WindowBounds::Fixed RectF width // window_height: Option<f32>, // WindowBounds::Fixed RectF height // display: Option<Uuid>, // Display id // fullscreen: Option<bool>, // Is the window fullscreen? // centered_layout: Option<bool>, // Is the Centered Layout mode activated? // session_id: Option<String>, // Session id // window_id: Option<u64>, // Window Id // ) // // pane_groups( // group_id: usize, // Primary key for pane_groups // workspace_id: usize, // References workspaces table // parent_group_id: Option<usize>, // None indicates that this is the root node // position: Optiopn<usize>, // None indicates that this is the root node // axis: Option<Axis>, // 'Vertical', 'Horizontal' // flexes: Option<Vec<f32>>, // A JSON array of floats // ) // // panes( // pane_id: usize, // Primary key for panes // workspace_id: usize, // References workspaces table // active: bool, // ) // // center_panes( // pane_id: usize, // Primary key for center_panes // parent_group_id: Option<usize>, // References pane_groups. If none, this is the root // position: Option<usize>, // None indicates this is the root // ) // // CREATE TABLE items( // item_id: usize, // This is the item's view id, so this is not unique // workspace_id: usize, // References workspaces table // pane_id: usize, // References panes table // kind: String, // Indicates which view this connects to. This is the key in the item_deserializers global // position: usize, // Position of the item in the parent pane. This is equivalent to panes' position column // active: bool, // Indicates if this item is the active one in the pane // preview: bool // Indicates if this item is a preview item // ) pub static ref DB: WorkspaceDb<()> = &[sql!( CREATE TABLE workspaces( workspace_id INTEGER PRIMARY KEY, workspace_location BLOB UNIQUE, dock_visible INTEGER, // Deprecated. Preserving so users can downgrade Zed. dock_anchor TEXT, // Deprecated. Preserving so users can downgrade Zed. dock_pane INTEGER, // Deprecated. Preserving so users can downgrade Zed. left_sidebar_open INTEGER, // Boolean timestamp TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL, FOREIGN KEY(dock_pane) REFERENCES panes(pane_id) ) STRICT; CREATE TABLE pane_groups( group_id INTEGER PRIMARY KEY, workspace_id INTEGER NOT NULL, parent_group_id INTEGER, // NULL indicates that this is a root node position INTEGER, // NULL indicates that this is a root node axis TEXT NOT NULL, // Enum: 'Vertical' / 'Horizontal' FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY(parent_group_id) REFERENCES pane_groups(group_id) ON DELETE CASCADE ) STRICT; CREATE TABLE panes( pane_id INTEGER PRIMARY KEY, workspace_id INTEGER NOT NULL, active INTEGER NOT NULL, // Boolean FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE CASCADE ON UPDATE CASCADE ) STRICT; CREATE TABLE center_panes( pane_id INTEGER PRIMARY KEY, parent_group_id INTEGER, // NULL means that this is a root pane position INTEGER, // NULL means that this is a root pane FOREIGN KEY(pane_id) REFERENCES panes(pane_id) ON DELETE CASCADE, FOREIGN KEY(parent_group_id) REFERENCES pane_groups(group_id) ON DELETE CASCADE ) STRICT; CREATE TABLE items( item_id INTEGER NOT NULL, // This is the item's view id, so this is not unique workspace_id INTEGER NOT NULL, pane_id INTEGER NOT NULL, kind TEXT NOT NULL, position INTEGER NOT NULL, active INTEGER NOT NULL, FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY(pane_id) REFERENCES panes(pane_id) ON DELETE CASCADE, PRIMARY KEY(item_id, workspace_id) ) STRICT; ), sql!( ALTER TABLE workspaces ADD COLUMN window_state TEXT; ALTER TABLE workspaces ADD COLUMN window_x REAL; ALTER TABLE workspaces ADD COLUMN window_y REAL; ALTER TABLE workspaces ADD COLUMN window_width REAL; ALTER TABLE workspaces ADD COLUMN window_height REAL; ALTER TABLE workspaces ADD COLUMN display BLOB; ), // Drop foreign key constraint from workspaces.dock_pane to panes table. sql!( CREATE TABLE workspaces_2( workspace_id INTEGER PRIMARY KEY, workspace_location BLOB UNIQUE, dock_visible INTEGER, // Deprecated. Preserving so users can downgrade Zed. dock_anchor TEXT, // Deprecated. Preserving so users can downgrade Zed. dock_pane INTEGER, // Deprecated. Preserving so users can downgrade Zed. left_sidebar_open INTEGER, // Boolean timestamp TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL, window_state TEXT, window_x REAL, window_y REAL, window_width REAL, window_height REAL, display BLOB ) STRICT; INSERT INTO workspaces_2 SELECT * FROM workspaces; DROP TABLE workspaces; ALTER TABLE workspaces_2 RENAME TO workspaces; ), // Add panels related information sql!( ALTER TABLE workspaces ADD COLUMN left_dock_visible INTEGER; //bool ALTER TABLE workspaces ADD COLUMN left_dock_active_panel TEXT; ALTER TABLE workspaces ADD COLUMN right_dock_visible INTEGER; //bool ALTER TABLE workspaces ADD COLUMN right_dock_active_panel TEXT; ALTER TABLE workspaces ADD COLUMN bottom_dock_visible INTEGER; //bool ALTER TABLE workspaces ADD COLUMN bottom_dock_active_panel TEXT; ), // Add panel zoom persistence sql!( ALTER TABLE workspaces ADD COLUMN left_dock_zoom INTEGER; //bool ALTER TABLE workspaces ADD COLUMN right_dock_zoom INTEGER; //bool ALTER TABLE workspaces ADD COLUMN bottom_dock_zoom INTEGER; //bool ), // Add pane group flex data sql!( ALTER TABLE pane_groups ADD COLUMN flexes TEXT; ), // Add fullscreen field to workspace // Deprecated, `WindowBounds` holds the fullscreen state now. // Preserving so users can downgrade Zed. sql!( ALTER TABLE workspaces ADD COLUMN fullscreen INTEGER; //bool ), // Add preview field to items sql!( ALTER TABLE items ADD COLUMN preview INTEGER; //bool ), // Add centered_layout field to workspace sql!( ALTER TABLE workspaces ADD COLUMN centered_layout INTEGER; //bool ), sql!( CREATE TABLE remote_projects ( remote_project_id INTEGER NOT NULL UNIQUE, path TEXT, dev_server_name TEXT ); ALTER TABLE workspaces ADD COLUMN remote_project_id INTEGER; ALTER TABLE workspaces RENAME COLUMN workspace_location TO local_paths; ), sql!( DROP TABLE remote_projects; CREATE TABLE dev_server_projects ( id INTEGER NOT NULL UNIQUE, path TEXT, dev_server_name TEXT ); ALTER TABLE workspaces DROP COLUMN remote_project_id; ALTER TABLE workspaces ADD COLUMN dev_server_project_id INTEGER; ), sql!( ALTER TABLE workspaces ADD COLUMN local_paths_order BLOB; ), sql!( ALTER TABLE workspaces ADD COLUMN session_id TEXT DEFAULT NULL; ), sql!( ALTER TABLE workspaces ADD COLUMN window_id INTEGER DEFAULT NULL; ), sql!( ALTER TABLE panes ADD COLUMN pinned_count INTEGER DEFAULT 0; ) ]; } 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(crate) fn workspace_for_roots<P: AsRef<Path>>( &self, worktree_roots: &[P], ) -> Option<SerializedWorkspace> { let local_paths = LocalPaths::new(worktree_roots); // Note that we re-assign the workspace_id here in case it's empty // and we've grabbed the most recent workspace let ( workspace_id, local_paths, local_paths_order, dev_server_project_id, window_bounds, display, centered_layout, docks, window_id, ): ( WorkspaceId, Option<LocalPaths>, Option<LocalPathsOrder>, Option<u64>, Option<SerializedWindowBounds>, Option<Uuid>, Option<bool>, DockStructure, Option<u64>, ) = self .select_row_bound(sql! { SELECT workspace_id, local_paths, local_paths_order, dev_server_project_id, window_state, window_x, window_y, window_width, window_height, display, centered_layout, left_dock_visible, left_dock_active_panel, left_dock_zoom, right_dock_visible, right_dock_active_panel, right_dock_zoom, bottom_dock_visible, bottom_dock_active_panel, bottom_dock_zoom, window_id FROM workspaces WHERE local_paths = ? }) .and_then(|mut prepared_statement| (prepared_statement)(&local_paths)) .context("No workspaces found") .warn_on_err() .flatten()?; let location = if let Some(dev_server_project_id) = dev_server_project_id { let dev_server_project: SerializedDevServerProject = self .select_row_bound(sql! { SELECT id, path, dev_server_name FROM dev_server_projects WHERE id = ? }) .and_then(|mut prepared_statement| (prepared_statement)(dev_server_project_id)) .context("No remote project found") .warn_on_err() .flatten()?; SerializedWorkspaceLocation::DevServer(dev_server_project) } else if let Some(local_paths) = local_paths { match local_paths_order { Some(order) => SerializedWorkspaceLocation::Local(local_paths, order), None => { let order = LocalPathsOrder::default_for_paths(&local_paths); SerializedWorkspaceLocation::Local(local_paths, order) } } } else { return None; }; Some(SerializedWorkspace { id: workspace_id, location, center_group: self .get_center_pane_group(workspace_id) .context("Getting center group") .log_err()?, window_bounds, centered_layout: centered_layout.unwrap_or(false), display, docks, session_id: None, window_id, }) } pub(crate) fn workspace_for_dev_server_project( &self, dev_server_project_id: DevServerProjectId, ) -> Option<SerializedWorkspace> { // Note that we re-assign the workspace_id here in case it's empty // and we've grabbed the most recent workspace let ( workspace_id, local_paths, local_paths_order, dev_server_project_id, window_bounds, display, centered_layout, docks, window_id, ): ( WorkspaceId, Option<LocalPaths>, Option<LocalPathsOrder>, Option<u64>, Option<SerializedWindowBounds>, Option<Uuid>, Option<bool>, DockStructure, Option<u64>, ) = self .select_row_bound(sql! { SELECT workspace_id, local_paths, local_paths_order, dev_server_project_id, window_state, window_x, window_y,