terminal: Update terminal reopening from global to per-workspace (#25336)

Closes #7145

Currently, terminal persistence is global, i.e. split configurations are
restored across all workspaces.

This PR changes it to per-workspace, so configurations are restored only
within the same workspace. Opening a new window will start with a fresh
terminal.


https://github.com/user-attachments/assets/d43fe747-9f28-4723-b409-e8dbb3a23912


Release Notes:

- Improved terminal reopening to be per workspace instead of global.
This commit is contained in:
smit 2025-02-22 00:05:52 +05:30 committed by GitHub
parent 144d8a1db6
commit 3759e0bf55
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 72 additions and 24 deletions

View file

@ -217,35 +217,67 @@ impl TerminalPanel {
}); });
} }
fn serialization_key(workspace: &Workspace) -> Option<String> {
workspace
.database_id()
.map(|id| i64::from(id).to_string())
.or(workspace.session_id())
.map(|id| format!("{:?}-{:?}", TERMINAL_PANEL_KEY, id))
}
pub async fn load( pub async fn load(
workspace: WeakEntity<Workspace>, workspace: WeakEntity<Workspace>,
mut cx: AsyncWindowContext, mut cx: AsyncWindowContext,
) -> Result<Entity<Self>> { ) -> Result<Entity<Self>> {
let serialized_panel = cx let mut terminal_panel = None;
.background_spawn(async move { KEY_VALUE_STORE.read_kvp(TERMINAL_PANEL_KEY) })
.await
.log_err()
.flatten()
.map(|panel| serde_json::from_str::<SerializedTerminalPanel>(&panel))
.transpose()
.log_err()
.flatten();
let terminal_panel = workspace match workspace
.update_in(&mut cx, |workspace, window, cx| { .read_with(&mut cx, |workspace, _| {
match serialized_panel.zip(workspace.database_id()) { workspace
Some((serialized_panel, database_id)) => deserialize_terminal_panel( .database_id()
workspace.weak_handle(), .zip(TerminalPanel::serialization_key(workspace))
workspace.project().clone(), })
database_id, .ok()
serialized_panel, .flatten()
window, {
cx, Some((database_id, serialization_key)) => {
), if let Some(serialized_panel) = cx
None => Task::ready(Ok(cx.new(|cx| TerminalPanel::new(workspace, window, cx)))), .background_spawn(async move { KEY_VALUE_STORE.read_kvp(&serialization_key) })
.await
.log_err()
.flatten()
.map(|panel| serde_json::from_str::<SerializedTerminalPanel>(&panel))
.transpose()
.log_err()
.flatten()
{
if let Ok(serialized) = workspace
.update_in(&mut cx, |workspace, window, cx| {
deserialize_terminal_panel(
workspace.weak_handle(),
workspace.project().clone(),
database_id,
serialized_panel,
window,
cx,
)
})?
.await
{
terminal_panel = Some(serialized);
}
} }
}
_ => {}
}
let terminal_panel = if let Some(panel) = terminal_panel {
panel
} else {
workspace.update_in(&mut cx, |workspace, window, cx| {
cx.new(|cx| TerminalPanel::new(workspace, window, cx))
})? })?
.await?; };
if let Some(workspace) = workspace.upgrade() { if let Some(workspace) = workspace.upgrade() {
terminal_panel terminal_panel
@ -727,6 +759,16 @@ impl TerminalPanel {
fn serialize(&mut self, cx: &mut Context<Self>) { fn serialize(&mut self, cx: &mut Context<Self>) {
let height = self.height; let height = self.height;
let width = self.width; let width = self.width;
let Some(serialization_key) = self
.workspace
.update(cx, |workspace, _| {
TerminalPanel::serialization_key(workspace)
})
.ok()
.flatten()
else {
return;
};
self.pending_serialization = cx.spawn(|terminal_panel, mut cx| async move { self.pending_serialization = cx.spawn(|terminal_panel, mut cx| async move {
cx.background_executor() cx.background_executor()
.timer(Duration::from_millis(50)) .timer(Duration::from_millis(50))
@ -745,7 +787,7 @@ impl TerminalPanel {
async move { async move {
KEY_VALUE_STORE KEY_VALUE_STORE
.write_kvp( .write_kvp(
TERMINAL_PANEL_KEY.into(), serialization_key,
serde_json::to_string(&SerializedTerminalPanel { serde_json::to_string(&SerializedTerminalPanel {
items, items,
active_item_id: None, active_item_id: None,
@ -1351,8 +1393,10 @@ impl Panel for TerminalPanel {
DockPosition::Left | DockPosition::Right => self.width = size, DockPosition::Left | DockPosition::Right => self.width = size,
DockPosition::Bottom => self.height = size, DockPosition::Bottom => self.height = size,
} }
self.serialize(cx);
cx.notify(); cx.notify();
cx.defer_in(window, |this, _, cx| {
this.serialize(cx);
})
} }
fn is_zoomed(&self, _window: &Window, cx: &App) -> bool { fn is_zoomed(&self, _window: &Window, cx: &App) -> bool {

View file

@ -4385,6 +4385,10 @@ impl Workspace {
self.database_id self.database_id
} }
pub fn session_id(&self) -> Option<String> {
self.session_id.clone()
}
fn local_paths(&self, cx: &App) -> Option<Vec<Arc<Path>>> { fn local_paths(&self, cx: &App) -> Option<Vec<Arc<Path>>> {
let project = self.project().read(cx); let project = self.project().read(cx);