Saved selections: keep Edit Selection linear in the number saved (#318 follow-up)

A file can hold any number of saved selections; the duplicate-name check and the name lookup were quadratic.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 9bcb695ad3904565ed84b7562aa99dd818604cec)
This commit is contained in:
Brandon Thomas 2026-10-07 16:55:57 -04:00
parent e91183f0df
commit 79bd76c7e9
1 changed files with 9 additions and 3 deletions

View File

@ -324,9 +324,14 @@ fn edit_saved(s: &mut Session, p: &Value) -> Result<Value> {
let before = s.doc()?.doc.saved_selections.clone();
// Edits name the selections as they are now, so they don't depend on each other's order.
let mut after: Vec<Option<SavedSelection>> = before.iter().cloned().map(Some).collect();
// Files may hold any number of saved selections: keep this linear.
let mut index = std::collections::HashMap::with_capacity(before.len());
for (i, x) in before.iter().enumerate() {
index.entry(x.name.as_str()).or_insert(i);
}
for e in edits {
let name = str_param(e, "name").ok_or_else(|| bad(C, "missing name"))?;
let i = before.iter().position(|x| x.name == name).ok_or_else(|| bad(C, format!("no saved selection `{name}`")))?;
let i = *index.get(name).ok_or_else(|| bad(C, format!("no saved selection `{name}`")))?;
let Some(slot) = after.get_mut(i) else { continue };
if bool_or(e, "delete", false) {
*slot = None;
@ -337,8 +342,9 @@ fn edit_saved(s: &mut Session, p: &Value) -> Result<Value> {
}
}
let after: Vec<SavedSelection> = after.into_iter().flatten().collect();
for (i, x) in after.iter().enumerate() {
if after.iter().take(i).any(|y| y.name == x.name) {
let mut names = std::collections::HashSet::with_capacity(after.len());
for x in &after {
if !names.insert(x.name.as_str()) {
return Err(bad(C, format!("two saved selections would be named `{}`", x.name)));
}
}