swap_as_main: keep slot IDs stable, set_leader(n) (Bug #11)

Bug from Grok round-1 #11. swap_as_main used to renumber slot IDs to
1..=N after a vec swap, which silently rebroke every per-character
assist/follow key (the user typed Alt+1 in slot 1 to assist that
character; after the swap, slot 1 contained a different character).

Fix: do not renumber. Slot ID continues to identify a character; vec
position only encodes which physical tile the window occupies. set_leader
is called with n (the user's chosen new main). The notify message now
reports both the new and previous main using the actual slot IDs.

cargo test 96+/0; clippy clean.
This commit is contained in:
en 2026-09-16 08:03:27 +02:00
parent 84941247c4
commit 3dbc1b11df

View File

@ -624,17 +624,23 @@ async fn swap_prev(session: &Arc<Mutex<Session>>) -> Result<()> {
}
async fn swap_as_main(session: &Arc<Mutex<Session>>, n: u32) -> Result<()> {
let (wins, tiles) = {
let (wins, tiles, prev_leader) = {
let mut g = session.lock().await;
if n < 2 || n as usize > g.slots.len() {
return Ok(());
}
// Swap vec positions so the new leader's window sits at index 0
// (the "main" tile for layout purposes). Do NOT renumber slot
// IDs: a slot ID identifies a character (and therefore a
// per-character assist/follow key), while vec position only
// identifies which physical tile the window currently occupies.
// Mixing the two was Bug #11 -- swapping then renumbering made
// every per-character macro target a different character than
// before.
g.slots.swap(0, n as usize - 1);
for (i, (id, _)) in g.slots.iter_mut().enumerate() {
*id = i as u32 + 1;
}
g.engine.set_leader(1);
(g.slots.clone(), g.engine.profile.layout.slots.clone())
let prev = g.engine.leader_slot;
g.engine.set_leader(n);
(g.slots.clone(), g.engine.profile.layout.slots.clone(), prev)
};
if !tiles.is_empty() {
crate::layout::apply(&tiles, &wins).await?;
@ -642,7 +648,9 @@ async fn swap_as_main(session: &Arc<Mutex<Session>>, n: u32) -> Result<()> {
if let Some((_, c)) = wins.first() {
hypr::focus_window(&c.address_selector()).await.ok();
}
hypr::notify(&format!("main is slot 1 (was {n})"))
hypr::notify(&format!(
"main is slot {n} (was {prev_leader})"
))
.await
.ok();
Ok(())