Properly restore window position for SSH projects (#29904)

Release Notes:

- Fixed SSH projects not restoring their window position on reopen
This commit is contained in:
Kirill Bulatov 2025-05-05 11:46:49 +03:00 committed by GitHub
parent 0119b66426
commit 0048e67832
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 84 additions and 6 deletions

View file

@ -1,7 +1,7 @@
use std::collections::BTreeSet;
use std::{path::PathBuf, sync::Arc, time::Duration};
use anyhow::{Result, anyhow};
use anyhow::{Context as _, Result, anyhow};
use auto_update::AutoUpdater;
use editor::Editor;
use extension_host::ExtensionStore;
@ -565,7 +565,23 @@ pub async fn open_ssh_project(
let window = if let Some(window) = open_options.replace_window {
window
} else {
let options = cx.update(|cx| (app_state.build_window_options)(None, cx))?;
let workspace_position = cx
.update(|cx| {
workspace::ssh_workspace_position_from_db(
connection_options.host.clone(),
connection_options.port,
connection_options.username.clone(),
&paths,
cx,
)
})?
.await
.context("fetching ssh workspace position from db")?;
let mut options =
cx.update(|cx| (app_state.build_window_options)(workspace_position.display, cx))?;
options.window_bounds = workspace_position.window_bounds;
cx.open_window(options, |window, cx| {
let project = project::Project::local(
app_state.client.clone(),
@ -576,7 +592,11 @@ pub async fn open_ssh_project(
None,
cx,
);
cx.new(|cx| Workspace::new(None, project, app_state.clone(), window, cx))
cx.new(|cx| {
let mut workspace = Workspace::new(None, project, app_state.clone(), window, cx);
workspace.centered_layout = workspace_position.centered_layout;
workspace
})
})?
};
@ -634,7 +654,7 @@ pub async fn open_ssh_project(
.ok();
if let Err(e) = did_open_ssh_project {
log::error!("Failed to open project: {:?}", e);
log::error!("Failed to open project: {e:?}");
let response = window
.update(cx, |_, window, cx| {
window.prompt(

View file

@ -937,7 +937,7 @@ pub struct Workspace {
_schedule_serialize: Option<Task<()>>,
pane_history_timestamp: Arc<AtomicUsize>,
bounds: Bounds<Pixels>,
centered_layout: bool,
pub centered_layout: bool,
bounds_save_task_queued: Option<Task<()>>,
on_prompt_for_new_path: Option<PromptForNewPath>,
on_prompt_for_open_path: Option<PromptForOpenPath>,
@ -1313,7 +1313,7 @@ impl Workspace {
}
}
let serialized_workspace: Option<SerializedWorkspace> =
let serialized_workspace =
persistence::DB.workspace_for_roots(paths_to_open.as_slice());
let workspace_location = serialized_workspace
@ -7445,6 +7445,64 @@ pub fn move_active_item(
});
}
#[derive(Debug)]
pub struct WorkspacePosition {
pub window_bounds: Option<WindowBounds>,
pub display: Option<Uuid>,
pub centered_layout: bool,
}
pub fn ssh_workspace_position_from_db(
host: String,
port: Option<u16>,
user: Option<String>,
paths_to_open: &[PathBuf],
cx: &App,
) -> Task<Result<WorkspacePosition>> {
let paths = paths_to_open
.iter()
.map(|path| path.to_string_lossy().to_string())
.collect::<Vec<_>>();
cx.background_spawn(async move {
let serialized_ssh_project = persistence::DB
.get_or_create_ssh_project(host, port, paths, user)
.await
.context("fetching serialized ssh project")?;
let serialized_workspace =
persistence::DB.workspace_for_ssh_project(&serialized_ssh_project);
let (window_bounds, display) = if let Some(bounds) = window_bounds_env_override() {
(Some(WindowBounds::Windowed(bounds)), None)
} else {
let restorable_bounds = serialized_workspace
.as_ref()
.and_then(|workspace| Some((workspace.display?, workspace.window_bounds?)))
.or_else(|| {
let (display, window_bounds) = DB.last_window().log_err()?;
Some((display?, window_bounds?))
});
if let Some((serialized_display, serialized_status)) = restorable_bounds {
(Some(serialized_status.0), Some(serialized_display))
} else {
(None, None)
}
};
let centered_layout = serialized_workspace
.as_ref()
.map(|w| w.centered_layout)
.unwrap_or(false);
Ok(WorkspacePosition {
window_bounds,
display,
centered_layout,
})
})
}
#[cfg(test)]
mod tests {
use std::{cell::RefCell, rc::Rc};