rmux-server 0.1.1

Tokio daemon and request dispatcher for the RMUX terminal multiplexer.
Documentation
use std::path::{Path, PathBuf};

use rmux_proto::{
    IfShellRequest, Request, RmuxError, RunShellDelaySeconds, RunShellRequest, WaitForMode,
    WaitForRequest,
};

use super::tokens::{rebuild_shell_command, CommandTokens};
use super::values::{missing_argument, parse_f64};
use super::{parse_pane_target, parse_target_arg};

pub(super) fn parse_run_shell(mut args: CommandTokens) -> Result<Request, RmuxError> {
    let mut background = false;
    let mut as_commands = false;
    let mut show_stderr = false;
    let mut delay_seconds = None;
    let mut start_directory = None;
    let mut target = None;

    while let Some(token) = args.peek() {
        match token {
            "--" => {
                let _ = args.optional();
                break;
            }
            "-b" => {
                let _ = args.optional();
                background = true;
            }
            "-C" => {
                let _ = args.optional();
                as_commands = true;
            }
            "-E" => {
                let _ = args.optional();
                show_stderr = true;
            }
            "-d" => {
                let _ = args.optional();
                delay_seconds = Some(parse_f64("run-shell", "-d", &args.required("-d delay")?)?);
            }
            flag if flag.starts_with("-d") && flag.len() > 2 => {
                let flag = args
                    .optional()
                    .expect("peeked run-shell -d<delay> flag must still be present");
                delay_seconds = Some(parse_f64("run-shell", "-d", &flag[2..])?);
            }
            "-c" => {
                let _ = args.optional();
                start_directory = Some(PathBuf::from(args.required("-c start-directory")?));
            }
            "-t" => {
                let _ = args.optional();
                target = Some(parse_pane_target("run-shell", args.required("-t target")?)?);
            }
            _ => break,
        }
    }
    let command_parts = args.remaining();
    if command_parts.is_empty() && delay_seconds.is_none() {
        return Err(missing_argument("run-shell", "command"));
    }
    let command = if command_parts.is_empty() {
        String::new()
    } else if as_commands {
        command_parts.join(" ")
    } else {
        rebuild_shell_command(command_parts)
    };

    Ok(Request::RunShell(RunShellRequest {
        command,
        background,
        as_commands,
        show_stderr,
        delay_seconds: delay_seconds.map(RunShellDelaySeconds),
        start_directory,
        target,
    }))
}

pub(super) fn parse_if_shell(
    mut args: CommandTokens,
    caller_cwd: Option<&Path>,
) -> Result<Request, RmuxError> {
    let mut format_mode = false;
    let mut background = false;
    let mut target = None;

    while let Some(token) = args.peek() {
        match token {
            "--" => {
                let _ = args.optional();
                break;
            }
            "-b" => {
                let _ = args.optional();
                background = true;
            }
            "-F" => {
                let _ = args.optional();
                format_mode = true;
            }
            "-t" => {
                let _ = args.optional();
                target = Some(parse_target_arg("if-shell", args.required("-t target")?)?);
            }
            _ => break,
        }
    }

    let request = Request::IfShell(IfShellRequest {
        condition: args.required("if-shell condition")?,
        format_mode,
        then_command: args.required("if-shell then command")?,
        else_command: args.optional(),
        target,
        caller_cwd: caller_cwd.map(Path::to_path_buf),
        background,
    });
    args.no_extra("if-shell")?;
    Ok(request)
}

pub(super) fn parse_wait_for(mut args: CommandTokens) -> Result<Request, RmuxError> {
    let mut mode = WaitForMode::Wait;
    while let Some(token) = args.peek() {
        let next_mode = match token {
            "--" => {
                let _ = args.optional();
                break;
            }
            "-S" => WaitForMode::Signal,
            "-L" => WaitForMode::Lock,
            "-U" => WaitForMode::Unlock,
            _ => break,
        };
        let _ = args.optional();
        if mode != WaitForMode::Wait {
            return Err(RmuxError::Server(
                "wait-for accepts only one of -S, -L, or -U".to_owned(),
            ));
        }
        mode = next_mode;
    }
    let channel = args.required("wait-for channel")?;
    args.no_extra("wait-for")?;

    Ok(Request::WaitFor(WaitForRequest { channel, mode }))
}