Keep workspace presentation in numeric order

This commit is contained in:
Samuel Onoja committed 2026-09-29 21:29:58 +01:00
1 parent b2363a18b0
commit ae712b6b40
7 files changed
+59 -29

No files matched your search

+5 -14
View File
@@ -602,20 +602,11 @@ impl Ferese {
let Some(current) = self.output_workspaces.active_workspace(output) else { let Some(current) = self.output_workspaces.active_workspace(output) else {
return; return;
}; };
let mut candidates = self let mut candidates = self.workspaces.ordered();
.workspaces candidates.retain(|workspace| {
.iter() self.output_workspaces
.filter(|workspace| { .output_for_workspace(workspace.id)
self.output_workspaces .is_none_or(|owner| owner == output)
.output_for_workspace(workspace.id)
.is_none_or(|owner| owner == output)
})
.collect::<Vec<_>>();
candidates.sort_by_key(|workspace| {
(
workspace.name.parse::<u32>().unwrap_or(u32::MAX),
workspace.id.0,
)
}); });
let Some(index) = candidates let Some(index) = candidates
.iter() .iter()
+3 -3
View File
@@ -507,9 +507,10 @@ impl Ferese {
fn workspaces_json(&self) -> Value { fn workspaces_json(&self) -> Value {
let active = self.workspaces.active_id(); let active = self.workspaces.active_id();
let mut workspaces = self let workspaces = self
.workspaces .workspaces
.iter() .ordered()
.into_iter()
.map(|workspace| { .map(|workspace| {
let mode = match workspace.layout.mode() { let mode = match workspace.layout.mode() {
LayoutMode::Scrolling => "scrolling", LayoutMode::Scrolling => "scrolling",
@@ -525,7 +526,6 @@ impl Ferese {
}) })
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
workspaces.sort_by_key(|workspace| workspace["id"].as_u64());
Value::Array(workspaces) Value::Array(workspaces)
} }
+2 -4
View File
@@ -650,8 +650,7 @@ impl Ferese {
let selected = self.output_workspaces.active_workspace(output_id); let selected = self.output_workspaces.active_workspace(output_id);
let strip = workspace_strip(bounds); let strip = workspace_strip(bounds);
let capacity = strip_capacity(strip); let capacity = strip_capacity(strip);
let mut workspaces = self.workspaces.iter().collect::<Vec<_>>(); let workspaces = self.workspaces.ordered();
workspaces.sort_by_key(|workspace| workspace.name.parse::<u64>().unwrap_or(workspace.id.0));
let selected_index = workspaces let selected_index = workspaces
.iter() .iter()
.position(|workspace| Some(workspace.id) == selected) .position(|workspace| Some(workspace.id) == selected)
@@ -770,8 +769,7 @@ impl Ferese {
}; };
let capacity = strip_capacity(workspace_strip(bounds)); let capacity = strip_capacity(workspace_strip(bounds));
let cards = self.overview_workspace_cards(&output); let cards = self.overview_workspace_cards(&output);
let mut ordered = self.workspaces.iter().collect::<Vec<_>>(); let ordered = self.workspaces.ordered();
ordered.sort_by_key(|workspace| workspace.name.parse::<u64>().unwrap_or(workspace.id.0));
let current = cards let current = cards
.first() .first()
.and_then(|card| { .and_then(|card| {
+4 -7
View File
@@ -215,9 +215,9 @@ impl Ferese {
} }
fn workspace_snapshots(&self) -> Vec<WorkspaceSnapshot> { fn workspace_snapshots(&self) -> Vec<WorkspaceSnapshot> {
let mut workspaces = self self.workspaces
.workspaces .ordered()
.iter() .into_iter()
.map(|workspace| { .map(|workspace| {
let output = self.output_workspaces.output_for_workspace(workspace.id); let output = self.output_workspaces.output_for_workspace(workspace.id);
let active = output.is_some_and(|output| { let active = output.is_some_and(|output| {
@@ -231,10 +231,7 @@ impl Ferese {
active, active,
} }
}) })
.collect::<Vec<_>>(); .collect()
workspaces.sort_by_key(|workspace| workspace.id.0);
workspaces
} }
fn managed_window_snapshots(&self) -> Vec<ManagedWindowSnapshot> { fn managed_window_snapshots(&self) -> Vec<ManagedWindowSnapshot> {
+1 -1
View File
@@ -6,5 +6,5 @@ mod workspace;
pub use output::{OutputError, OutputGeometry, OutputId, OutputWorkspaceMap, WorkspaceSwitch}; pub use output::{OutputError, OutputGeometry, OutputId, OutputWorkspaceMap, WorkspaceSwitch};
pub use workspace::{ pub use workspace::{
LayoutMode, WindowPlacement, Workspace, WorkspaceError, WorkspaceId, WorkspaceLayout, LayoutMode, WindowPlacement, Workspace, WorkspaceError, WorkspaceId, WorkspaceLayout,
WorkspaceSet, WorkspaceSet, workspace_order_key,
}; };
+38
View File
@@ -10,6 +10,10 @@ use ferese_layout::{
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct WorkspaceId(pub u64); pub struct WorkspaceId(pub u64);
pub fn workspace_order_key(name: &str, id: WorkspaceId) -> (u64, u64) {
(name.parse::<u64>().unwrap_or(u64::MAX), id.0)
}
#[derive(Debug)] #[derive(Debug)]
pub struct Workspace { pub struct Workspace {
pub id: WorkspaceId, pub id: WorkspaceId,
@@ -537,6 +541,13 @@ impl WorkspaceSet {
self.workspaces.values() self.workspaces.values()
} }
pub fn ordered(&self) -> Vec<&Workspace> {
let mut workspaces = self.iter().collect::<Vec<_>>();
workspaces
.sort_unstable_by_key(|workspace| workspace_order_key(&workspace.name, workspace.id));
workspaces
}
pub fn prune_empty(&mut self, protected: &HashSet<WorkspaceId>) -> Vec<WorkspaceId> { pub fn prune_empty(&mut self, protected: &HashSet<WorkspaceId>) -> Vec<WorkspaceId> {
let mut empty = self let mut empty = self
.workspaces .workspaces
@@ -1134,6 +1145,33 @@ fn finite_or_zero(value: f64) -> f64 {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#[test]
fn numeric_order_survives_pruning_and_recreation() {
let mut set = super::WorkspaceSet::default();
let original_first = set.active_id();
let second = set.ensure_numeric(2).unwrap();
set.activate(second).unwrap();
assert_eq!(
set.prune_empty(&std::collections::HashSet::new()),
vec![original_first]
);
let tenth = set.ensure_numeric(10).unwrap();
let first = set.ensure_numeric(1).unwrap();
assert_ne!(first, original_first);
assert!(first.0 > tenth.0);
assert_eq!(
set.ordered()
.into_iter()
.map(|workspace| (workspace.name.as_str(), workspace.id))
.collect::<Vec<_>>(),
vec![("1", first), ("2", second), ("10", tenth)]
);
set.activate(first).unwrap();
assert_eq!(set.active().name, "1");
assert!(set.validate().is_ok());
}
#[test] #[test]
fn pruning_keeps_windows_and_one_empty_workspace() { fn pruning_keeps_windows_and_one_empty_workspace() {
let mut set = super::WorkspaceSet::default(); let mut set = super::WorkspaceSet::default();
+6
View File
@@ -272,6 +272,12 @@ impl Dispatch<FereseShellV1, ()> for ControlState {
ferese_shell_v1::Event::SnapshotEnd { serial } ferese_shell_v1::Event::SnapshotEnd { serial }
if state.serial.take() == Some(serial) => if state.serial.take() == Some(serial) =>
{ {
state.pending.workspaces.sort_unstable_by_key(|workspace| {
ferese_core::workspace_order_key(
&workspace.name,
ferese_core::WorkspaceId(workspace.id),
)
});
let _ = state let _ = state
.sender .sender
.send(ControlUpdate::Snapshot(state.pending.clone())); .send(ControlUpdate::Snapshot(state.pending.clone()));