From 109d99fe82205b144e68e4571140d32d28db2597 Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Thu, 16 May 2024 10:54:24 +0400 Subject: [PATCH] Make workspace names case-insensitive --- niri-config/src/lib.rs | 11 ++++--- src/layout/mod.rs | 66 ++++++++++++++++++++++++++++-------------- src/layout/monitor.rs | 22 +++++++++----- 3 files changed, 67 insertions(+), 32 deletions(-) diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs index 355007f6..5e04f6ed 100644 --- a/niri-config/src/lib.rs +++ b/niri-config/src/lib.rs @@ -1502,14 +1502,15 @@ impl knuffel::DecodeScalar for WorkspaceName { ctx: &mut knuffel::decode::Context, ) -> Result> { #[derive(Debug)] - struct WorkspaceNameSet(HashSet); + struct WorkspaceNameSet(Vec); match &**val { knuffel::ast::Literal::String(ref s) => { - let mut name_set: HashSet = match ctx.get::() { + let mut name_set: Vec = match ctx.get::() { Some(h) => h.0.clone(), - None => HashSet::new(), + None => Vec::new(), }; - if !name_set.insert(s.clone().to_string()) { + + if name_set.iter().any(|name| name.eq_ignore_ascii_case(s)) { ctx.emit_error(DecodeError::unexpected( val, "named workspace", @@ -1517,6 +1518,8 @@ impl knuffel::DecodeScalar for WorkspaceName { )); return Ok(Self(String::new())); } + + name_set.push(s.to_string()); ctx.set(WorkspaceNameSet(name_set)); Ok(Self(s.clone().into())) } diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 0eb451e6..544b2186 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -531,7 +531,11 @@ impl Layout { MonitorSet::NoOutputs { workspaces } => { let ws = workspaces .iter_mut() - .find(|ws| ws.name.as_deref() == Some(workspace_name)) + .find(|ws| { + ws.name + .as_ref() + .map_or(false, |name| name.eq_ignore_ascii_case(workspace_name)) + }) .unwrap(); ws.add_window(window, true, width, is_full_width); None @@ -799,22 +803,23 @@ impl Layout { match &self.monitor_set { MonitorSet::Normal { ref monitors, .. } => { for mon in monitors { - if let Some((index, workspace)) = mon - .workspaces - .iter() - .enumerate() - .find(|(_, w)| w.name.as_deref() == Some(workspace_name)) + if let Some((index, workspace)) = + mon.workspaces.iter().enumerate().find(|(_, w)| { + w.name + .as_ref() + .map_or(false, |name| name.eq_ignore_ascii_case(workspace_name)) + }) { return Some((index, workspace)); } } } MonitorSet::NoOutputs { workspaces } => { - if let Some((index, workspace)) = workspaces - .iter() - .enumerate() - .find(|(_, w)| w.name.as_deref() == Some(workspace_name)) - { + if let Some((index, workspace)) = workspaces.iter().enumerate().find(|(_, w)| { + w.name + .as_ref() + .map_or(false, |name| name.eq_ignore_ascii_case(workspace_name)) + }) { return Some((index, workspace)); } } @@ -837,7 +842,11 @@ impl Layout { } MonitorSet::NoOutputs { workspaces } => { for (idx, ws) in workspaces.iter_mut().enumerate() { - if ws.name.as_deref() == Some(workspace_name) { + if ws + .name + .as_ref() + .map_or(false, |name| name.eq_ignore_ascii_case(workspace_name)) + { ws.unname(); // Clean up empty workspaces. @@ -1110,10 +1119,11 @@ impl Layout { }; monitors.iter().find(|monitor| { - monitor - .workspaces - .iter() - .any(|ws| ws.name.as_deref() == Some(workspace_name)) + monitor.workspaces.iter().any(|ws| { + ws.name + .as_ref() + .map_or(false, |name| name.eq_ignore_ascii_case(workspace_name)) + }) }) } @@ -1416,7 +1426,7 @@ impl Layout { use crate::layout::monitor::WorkspaceSwitch; let mut seen_workspace_id = HashSet::new(); - let mut seen_workspace_name = HashSet::new(); + let mut seen_workspace_name = Vec::::new(); let (monitors, &primary_idx, &active_monitor_idx) = match &self.monitor_set { MonitorSet::Normal { @@ -1443,9 +1453,12 @@ impl Layout { if let Some(name) = &workspace.name { assert!( - seen_workspace_name.insert(name), + !seen_workspace_name + .iter() + .any(|n| n.eq_ignore_ascii_case(name)), "workspace name must be unique" ); + seen_workspace_name.push(name.clone()); } workspace.verify_invariants(); @@ -1544,9 +1557,12 @@ impl Layout { if let Some(name) = &workspace.name { assert!( - seen_workspace_name.insert(name), + !seen_workspace_name + .iter() + .any(|n| n.eq_ignore_ascii_case(name)), "workspace name must be unique" ); + seen_workspace_name.push(name.clone()); } workspace.verify_invariants(); @@ -2788,7 +2804,11 @@ mod tests { } } - if ws.name.as_deref() == Some(&ws_name) { + if ws + .name + .as_ref() + .map_or(false, |name| name.eq_ignore_ascii_case(&ws_name)) + { found_workspace = true; } } @@ -2802,7 +2822,11 @@ mod tests { } } - if ws.name.as_deref() == Some(&ws_name) { + if ws + .name + .as_ref() + .map_or(false, |name| name.eq_ignore_ascii_case(&ws_name)) + { found_workspace = true; } } diff --git a/src/layout/monitor.rs b/src/layout/monitor.rs index 9dcc552e..c56146a4 100644 --- a/src/layout/monitor.rs +++ b/src/layout/monitor.rs @@ -104,15 +104,19 @@ impl Monitor { } pub fn find_named_workspace(&self, workspace_name: &str) -> Option<&Workspace> { - self.workspaces - .iter() - .find(|w| w.name.as_deref() == Some(workspace_name)) + self.workspaces.iter().find(|ws| { + ws.name + .as_ref() + .map_or(false, |name| name.eq_ignore_ascii_case(workspace_name)) + }) } pub fn find_named_workspace_index(&self, workspace_name: &str) -> Option { - self.workspaces - .iter() - .position(|w| w.name.as_deref() == Some(workspace_name)) + self.workspaces.iter().position(|ws| { + ws.name + .as_ref() + .map_or(false, |name| name.eq_ignore_ascii_case(workspace_name)) + }) } pub fn active_workspace(&mut self) -> &mut Workspace { @@ -227,7 +231,11 @@ impl Monitor { pub fn unname_workspace(&mut self, workspace_name: &str) -> bool { for ws in &mut self.workspaces { - if ws.name.as_deref() == Some(workspace_name) { + if ws + .name + .as_ref() + .map_or(false, |name| name.eq_ignore_ascii_case(workspace_name)) + { ws.unname(); return true; }