hyprswitch 3.3.2

A CLI/GUI that allows switching between windows in Hyprland
use anyhow::Context;
use hyprland::shared::{Address, MonitorId, WorkspaceId};
use tracing::{trace, warn};

use crate::{ClientData, DispatchConfig, MonitorData, WorkspaceData};

pub(crate) fn find_next_monitor<'a>(
    dispatch_config: &DispatchConfig,
    monitor_data: &'a [(MonitorId, MonitorData)],
    selected_id: Option<&MonitorId>,
) -> anyhow::Result<&'a (MonitorId, MonitorData)> {
    let filtered_monitors = monitor_data
        .iter()
        .filter(|(_, w)| w.enabled)
        .collect::<Vec<_>>();

    let index = match selected_id {
        Some(mid) => {
            let ind = filtered_monitors
                .iter()
                .filter(|(_, w)| w.enabled)
                .position(|(id, _)| *id == *mid);
            match ind {
                Some(si) => {
                    if dispatch_config.reverse {
                        if si == 0 {
                            filtered_monitors.len() - dispatch_config.offset as usize
                        } else {
                            si - dispatch_config.offset as usize
                        }
                    } else if si + dispatch_config.offset as usize >= filtered_monitors.len() {
                        si + dispatch_config.offset as usize - filtered_monitors.len()
                    } else {
                        si + dispatch_config.offset as usize
                    }
                }
                None => {
                    warn!("selected monitor not found");
                    if dispatch_config.reverse {
                        filtered_monitors.len() - dispatch_config.offset as usize
                    } else {
                        dispatch_config.offset as usize
                    }
                }
            }
        }
        None => {
            if dispatch_config.reverse {
                filtered_monitors.len() - dispatch_config.offset as usize
            } else {
                dispatch_config.offset as usize - 1
            }
        }
    };
    trace!("index: {}", index);

    let next_monitor = filtered_monitors
        .iter()
        .cycle()
        .nth(index)
        .context("No next monitor found")?;

    Ok(*next_monitor)
}

pub(crate) fn find_next_workspace<'a>(
    dispatch_config: &DispatchConfig,
    workspace_data: &'a [(WorkspaceId, WorkspaceData)],
    selected_id: Option<&WorkspaceId>,
) -> anyhow::Result<&'a (WorkspaceId, WorkspaceData)> {
    let filtered_workspaces = workspace_data
        .iter()
        .filter(|(_, w)| w.enabled)
        .collect::<Vec<_>>();

    let index = match selected_id {
        Some(wid) => {
            let ind = filtered_workspaces.iter().position(|(id, _)| *id == *wid);
            match ind {
                Some(si) => {
                    if dispatch_config.reverse {
                        if si == 0 {
                            filtered_workspaces.len() - dispatch_config.offset as usize
                        } else {
                            si - dispatch_config.offset as usize
                        }
                    } else if si + dispatch_config.offset as usize >= filtered_workspaces.len() {
                        si + dispatch_config.offset as usize - filtered_workspaces.len()
                    } else {
                        si + dispatch_config.offset as usize
                    }
                }
                None => {
                    warn!("selected workspace not found");
                    if dispatch_config.reverse {
                        filtered_workspaces.len() - dispatch_config.offset as usize
                    } else {
                        dispatch_config.offset as usize
                    }
                }
            }
        }
        None => {
            if dispatch_config.reverse {
                filtered_workspaces.len() - dispatch_config.offset as usize
            } else {
                dispatch_config.offset as usize - 1
            }
        }
    };
    trace!("index: {}", index);

    let next_workspace = filtered_workspaces
        .iter()
        .cycle()
        .nth(index)
        .context("No next client found")?;

    Ok(*next_workspace)
}

pub(crate) fn find_next_client<'a>(
    dispatch_config: &DispatchConfig,
    clients: &'a [(Address, ClientData)],
    selected_addr: Option<&Address>,
) -> anyhow::Result<&'a (Address, ClientData)> {
    let filtered_clients = clients
        .iter()
        .filter(|(_, c)| c.enabled)
        .collect::<Vec<_>>();

    let index = match selected_addr {
        Some(add) => {
            let ind = filtered_clients.iter().position(|(a, _)| *a == *add);
            match ind {
                Some(si) => {
                    if dispatch_config.reverse {
                        if si == 0 {
                            filtered_clients.len() - dispatch_config.offset as usize
                        } else {
                            si - dispatch_config.offset as usize
                        }
                    } else if si + dispatch_config.offset as usize >= filtered_clients.len() {
                        si + dispatch_config.offset as usize - filtered_clients.len()
                    } else {
                        si + dispatch_config.offset as usize
                    }
                }
                None => {
                    warn!("selected client not found");
                    if dispatch_config.reverse {
                        filtered_clients.len() - dispatch_config.offset as usize
                    } else {
                        dispatch_config.offset as usize
                    }
                }
            }
        }
        None => {
            if dispatch_config.reverse {
                filtered_clients.len() - dispatch_config.offset as usize
            } else {
                dispatch_config.offset as usize - 1
            }
        }
    };

    let next_client = filtered_clients
        .iter()
        .cycle()
        .nth(index)
        .context("No next client found")?;

    Ok(*next_client)
}