Persist selections for editors (#25083)

Part of https://github.com/zed-industries/zed/issues/7371
Closes https://github.com/zed-industries/zed/issues/12853

Release Notes:

- Started to persist latest selections for editors, to restore those on
restart
This commit is contained in:
Kirill Bulatov 2025-02-18 16:27:00 +02:00 committed by GitHub
parent b34037876e
commit 80458ffb96
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 159 additions and 5 deletions

View file

@ -2,6 +2,7 @@ use anyhow::Result;
use db::sqlez::bindable::{Bind, Column, StaticColumnCount};
use db::sqlez::statement::Statement;
use fs::MTime;
use itertools::Itertools as _;
use std::path::PathBuf;
use db::sqlez_macros::sql;
@ -134,9 +135,26 @@ define_connection!(
ALTER TABLE editors ADD COLUMN mtime_seconds INTEGER DEFAULT NULL;
ALTER TABLE editors ADD COLUMN mtime_nanos INTEGER DEFAULT NULL;
),
sql! (
CREATE TABLE editor_selections (
item_id INTEGER NOT NULL,
editor_id INTEGER NOT NULL,
workspace_id INTEGER NOT NULL,
start INTEGER NOT NULL,
end INTEGER NOT NULL,
PRIMARY KEY(item_id),
FOREIGN KEY(editor_id, workspace_id) REFERENCES editors(item_id, workspace_id)
ON DELETE CASCADE
) STRICT;
),
];
);
// https://www.sqlite.org/limits.html
// > <..> the maximum value of a host parameter number is SQLITE_MAX_VARIABLE_NUMBER,
// > which defaults to <..> 32766 for SQLite versions after 3.32.0.
const MAX_QUERY_PLACEHOLDERS: usize = 32000;
impl EditorDb {
query! {
pub fn get_serialized_editor(item_id: ItemId, workspace_id: WorkspaceId) -> Result<Option<SerializedEditor>> {
@ -188,6 +206,68 @@ impl EditorDb {
}
}
query! {
pub fn get_editor_selections(
editor_id: ItemId,
workspace_id: WorkspaceId
) -> Result<Vec<(usize, usize)>> {
SELECT start, end
FROM editor_selections
WHERE editor_id = ?1 AND workspace_id = ?2
}
}
pub async fn save_editor_selections(
&self,
editor_id: ItemId,
workspace_id: WorkspaceId,
selections: Vec<(usize, usize)>,
) -> Result<()> {
let mut first_selection;
let mut last_selection = 0_usize;
for (count, placeholders) in std::iter::once("(?1, ?2, ?, ?)")
.cycle()
.take(selections.len())
.chunks(MAX_QUERY_PLACEHOLDERS / 4)
.into_iter()
.map(|chunk| {
let mut count = 0;
let placeholders = chunk
.inspect(|_| {
count += 1;
})
.join(", ");
(count, placeholders)
})
.collect::<Vec<_>>()
{
first_selection = last_selection;
last_selection = last_selection + count;
let query = format!(
r#"
DELETE FROM editor_selections WHERE editor_id = ?1 AND workspace_id = ?2;
INSERT INTO editor_selections (editor_id, workspace_id, start, end)
VALUES {placeholders};
"#
);
let selections = selections[first_selection..last_selection].to_vec();
self.write(move |conn| {
let mut statement = Statement::prepare(conn, query)?;
statement.bind(&editor_id, 1)?;
let mut next_index = statement.bind(&workspace_id, 2)?;
for (start, end) in selections {
next_index = statement.bind(&start, next_index)?;
next_index = statement.bind(&end, next_index)?;
}
statement.exec()
})
.await?;
}
Ok(())
}
pub async fn delete_unloaded_items(
&self,
workspace: WorkspaceId,