mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-27 11:17:01 -06:00
UI.7: match workspace names whatever their case
find_saved matched names case-insensitively but save_as, remember and switch compared them exactly: "Mine" saved over "mine" made a second workspace, and changes kept as "Mine" didn't come back when switching to "mine". save_as now replaces a user workspace of the name in any case, remembered layouts are kept under the saved spelling and looked up whatever the case, and sanitized maps remembered layouts to the saved spelling and keeps one per workspace. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KcHisW1vt6pkVPYbzL6Cpg
This commit is contained in:
committed by
bflatastic
co-authored by
Claude Opus 5.5
parent
e3e761fe32
commit
d6d91c0954
@@ -775,10 +775,16 @@ impl UiState {
|
||||
crate::edit_toolbar::sanitize(&mut self.toolbar_edits);
|
||||
self.docking = self.docking.filter(crate::panel_docking::valid);
|
||||
self.docking_icons.retain(|id| ICON_PANELS.iter().any(|entry| entry.0 == id));
|
||||
// Changes kept for workspaces that still exist, one per workspace (a hand-edited file).
|
||||
// Changes kept for workspaces that still exist, under their saved spelling and one per
|
||||
// workspace whatever the case (a hand-edited file).
|
||||
let mut seen = std::collections::BTreeSet::new();
|
||||
let custom: Vec<String> = self.custom_workspaces.iter().map(|w| w.name.clone()).collect();
|
||||
self.workspace_changes.retain(|w| (crate::workspaces::is_builtin(&w.name) || custom.contains(&w.name)) && seen.insert(w.name.clone()));
|
||||
let saved: Vec<String> =
|
||||
self.custom_workspaces.iter().map(|w| w.name.clone()).chain(crate::workspaces::builtins().into_iter().map(|w| w.name)).collect();
|
||||
self.workspace_changes.retain_mut(|w| {
|
||||
let Some(name) = saved.iter().find(|n| n.eq_ignore_ascii_case(&w.name)) else { return false };
|
||||
w.name = name.clone();
|
||||
seen.insert(name.to_ascii_lowercase())
|
||||
});
|
||||
self.workspace_changes.truncate(64);
|
||||
// Overrides that can't fire (modifier-only chords recorded by older versions, #487) give
|
||||
// the default back.
|
||||
|
||||
@@ -216,12 +216,10 @@ pub fn apply(ui: &mut UiState, w: &Workspace) {
|
||||
|
||||
/// Keep the layout of the current workspace as it is now, so switching back brings it back.
|
||||
fn remember(ui: &mut UiState) {
|
||||
let current = ui.workspace.clone();
|
||||
if find_saved(ui, ¤t).is_none() {
|
||||
return;
|
||||
}
|
||||
let w = capture(ui, ¤t);
|
||||
ui.workspace_changes.retain(|x| x.name != current);
|
||||
// Kept under the saved workspace's spelling, which `find_saved` matches whatever the case.
|
||||
let Some(saved) = find_saved(ui, &ui.workspace.clone()) else { return };
|
||||
let w = capture(ui, &saved.name);
|
||||
ui.workspace_changes.retain(|x| !x.name.eq_ignore_ascii_case(&saved.name));
|
||||
ui.workspace_changes.push(w);
|
||||
// Over the cap, the oldest go: the layout just kept is the newest.
|
||||
let over = ui.workspace_changes.len().saturating_sub(64);
|
||||
@@ -232,7 +230,7 @@ fn remember(ui: &mut UiState) {
|
||||
pub fn switch(ui: &mut UiState, name: &str) -> Result<String, String> {
|
||||
let saved = find_saved(ui, name).ok_or_else(|| format!("unknown workspace (one of {})", names(ui).join(", ")))?;
|
||||
remember(ui);
|
||||
let w = ui.workspace_changes.iter().find(|w| w.name == saved.name).cloned().unwrap_or(saved);
|
||||
let w = ui.workspace_changes.iter().find(|w| w.name.eq_ignore_ascii_case(&saved.name)).cloned().unwrap_or(saved);
|
||||
apply(ui, &w);
|
||||
Ok(w.name)
|
||||
}
|
||||
@@ -240,7 +238,7 @@ pub fn switch(ui: &mut UiState, name: &str) -> Result<String, String> {
|
||||
/// Reset the current workspace to the way it was saved, dropping its changes.
|
||||
pub fn reset(ui: &mut UiState) -> String {
|
||||
let w = find_saved(ui, &ui.workspace.clone()).unwrap_or_default();
|
||||
ui.workspace_changes.retain(|x| x.name != w.name);
|
||||
ui.workspace_changes.retain(|x| !x.name.eq_ignore_ascii_case(&w.name));
|
||||
apply(ui, &w);
|
||||
w.name
|
||||
}
|
||||
@@ -275,12 +273,13 @@ pub fn save_as(ui: &mut UiState, name: &str) -> Result<(), String> {
|
||||
}
|
||||
// The changes go into the workspace saved, which starts with none; the one left keeps the
|
||||
// changes it had (none of these).
|
||||
// A user workspace of that name in another case is replaced, as `find_saved` would find it.
|
||||
let w = capture(ui, name);
|
||||
match ui.custom_workspaces.iter_mut().find(|x| x.name == name) {
|
||||
match ui.custom_workspaces.iter_mut().find(|x| x.name.eq_ignore_ascii_case(name)) {
|
||||
Some(x) => *x = w,
|
||||
None => ui.custom_workspaces.push(w),
|
||||
}
|
||||
ui.workspace_changes.retain(|x| x.name != name);
|
||||
ui.workspace_changes.retain(|x| !x.name.eq_ignore_ascii_case(name));
|
||||
ui.workspace = name.into();
|
||||
Ok(())
|
||||
}
|
||||
@@ -626,6 +625,31 @@ mod tests {
|
||||
assert!(ui.control_bar, "the layout just left is kept");
|
||||
}
|
||||
|
||||
/// Workspace names match whatever their case, as `find` does: "Mine" saved over "mine" replaces
|
||||
/// it, and changes made under one spelling come back under the other.
|
||||
#[test]
|
||||
fn workspace_names_match_whatever_their_case() {
|
||||
let mut ui = UiState::default();
|
||||
save_as(&mut ui, "mine").unwrap();
|
||||
save_as(&mut ui, "Mine").unwrap();
|
||||
assert_eq!(ui.custom_workspaces.len(), 1, "one workspace, not two spellings");
|
||||
ui.control_bar = true;
|
||||
switch(&mut ui, ESSENTIALS).unwrap();
|
||||
assert_eq!(switch(&mut ui, "MINE").unwrap(), "Mine");
|
||||
assert!(ui.control_bar, "its changes came back");
|
||||
// A preferences file with a remembered layout under another spelling, twice: it maps to the
|
||||
// saved one, once.
|
||||
ui.control_bar = false;
|
||||
switch(&mut ui, ESSENTIALS).unwrap();
|
||||
let mut odd = capture(&ui, "MINE");
|
||||
odd.control_bar = true;
|
||||
ui.workspace_changes = vec![odd.clone(), Workspace { name: "mine".into(), ..odd }];
|
||||
let mut ui = ui.sanitized();
|
||||
assert_eq!(ui.workspace_changes.iter().map(|w| w.name.as_str()).collect::<Vec<_>>(), ["Mine"]);
|
||||
switch(&mut ui, "Mine").unwrap();
|
||||
assert!(ui.control_bar);
|
||||
}
|
||||
|
||||
/// Saving a workspace takes the current layout into it, which then starts with no changes.
|
||||
#[test]
|
||||
fn saving_a_workspace_moves_the_changes_into_it() {
|
||||
|
||||
Reference in New Issue
Block a user