vdswitcher 0.1.0

A simple tool to control virtual desktops on Windows 11
/*
    This file is part of VDSwitcher.
    CLI parsing and wrapper functions around winvd.

    Copyright (C) 2026 Ranosura

    VDSwitcher is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

*/
use winvd;

pub enum Flag {
    CreaetDesktop(String),
    Help,
    ListDesktops,
    RemoveDesktop(u32),
    SwithcDesktop(u32),
}

impl Flag {
    pub fn build(args: &[String]) -> Result<Flag, &'static str> {
        // Check if there's is a flag argument
        check_args_len(args, 3)?;

        // Match against the possible flags
        match args[1].as_str() {
            "-c" => {
                if args.len() < 3 {
                    return Ok(Self::CreaetDesktop("".to_string()));
                }

                Ok(Self::CreaetDesktop(args[2].to_string()))
            }
            "-h" => {
                check_args_len(args, 2)?;
                return Ok(Self::Help);
            }
            "-l" => {
                check_args_len(args, 2)?;
                return Ok(Self::ListDesktops);
            }
            "-r" => {
                if args.len() < 3 {
                    return Err("-r option requires an unsigned index");
                }

                let index: u32 = match args[2].parse() {
                    Ok(val) => val,
                    Err(_) => {
                        return Err("invalid index");
                    }
                };

                return Ok(Self::RemoveDesktop(index));
            }
            "-s" => {
                if args.len() < 3 {
                    return Err("-s option requires an unsigned index");
                }

                let index: u32 = match args[2].parse() {
                    Ok(val) => val,
                    Err(_) => {
                        return Err("invalid index");
                    }
                };

                return Ok(Self::SwithcDesktop(index));
            }
            _ => {
                return Err("there is no such flag");
            }
        }
    }
}

pub fn create_desktop(name: &str) -> Result<(), &'static str> {
    let Ok(desktop) = winvd::create_desktop() else {
        return Err("error with creating the desktop");
    };

    // if name is empty, then there's no reason to set it
    if name.is_empty() {
        return Ok(());
    }

    if desktop.set_name(name).is_err() {
        return Err("error with setting the desktop's name");
    }

    Ok(())
}

pub fn remove_desktop(index: u32) -> Result<(), &'static str> {
    let Ok(count) = winvd::get_desktop_count() else {
        return Err("error with retrieving the desktop count");
    };

    if count < 2 {
        return Err("cannot remove the desktop because it's the only one existing");
    }

    // It's impossible to delete a virtual desktop while the fallback's index is equal to the deleted one.
    // So I can't just specify constant fallback index.
    if index == 0 {
        if winvd::remove_desktop(index, index + 1).is_err() {
            return Err("error with removing the desktop");
        }
    } else {
        if winvd::remove_desktop(index, index - 1).is_err() {
            return Err("error with removing the desktop");
        }
    }

    Ok(())
}

fn check_args_len(args: &[String], max_len: usize) -> Result<(), &'static str> {
    if args.len() > max_len {
        help_message();
        return Err("too many arguments");
    } else if args.len() == 1 {
        help_message();
        return Err("not enough arguments");
    } else {
        return Ok(());
    }
}

pub fn help_message() {
    println!("\
vdswitcher.exe -c [NAME] | -l | -r [INDEX] | -s [INDEX] | -h

A simple tool to manage virtual desktops on Windows 11.

INDEX is a 32 bit unsigned number. The first desktop starts with zeroth index. 

-c [NAME]
    Creates a virtual desktop with NAME. If name isn't supplied, the desktop will have a default name.
    
-l 
    Lists all virtual desktops.

-r [INDEX]
    Removes a virtual desktop with INDEX.

-s [INDEX]
    Switches to a virtual desktop with INDEX.

-h
    Displays this message.
")
}