rmux-server 0.1.1

Tokio daemon and request dispatcher for the RMUX terminal multiplexer.
Documentation
pub(super) fn apply_template_override(
    target: &mut Option<String>,
    value: Option<&str>,
    remove: bool,
) {
    if remove {
        *target = None;
    } else if let Some(value) = value {
        *target = Some(decode_capability_string(value));
    }
}

pub(super) fn parse_capability_override(spec: &str) -> Option<(&str, Option<&str>, bool)> {
    let spec = spec.trim();
    if spec.is_empty() {
        return None;
    }
    if let Some((name, value)) = spec.split_once('=') {
        return Some((name.trim(), Some(value.trim()), false));
    }
    if let Some(name) = spec.strip_suffix('@') {
        return Some((name.trim(), None, true));
    }
    Some((spec, None, false))
}

pub(super) fn split_override_segments(entry: &str) -> Vec<String> {
    let mut segments = Vec::new();
    let mut current = String::new();
    let mut chars = entry.chars().peekable();

    while let Some(ch) = chars.next() {
        if ch == ':' {
            if chars.peek() == Some(&':') {
                current.push(':');
                let _ = chars.next();
            } else {
                segments.push(current);
                current = String::new();
            }
        } else {
            current.push(ch);
        }
    }
    segments.push(current);
    segments
}

pub(super) fn decode_capability_string(value: &str) -> String {
    let mut decoded = String::with_capacity(value.len());
    let mut chars = value.chars().peekable();

    while let Some(ch) = chars.next() {
        if ch != '\\' {
            decoded.push(ch);
            continue;
        }

        match chars.peek() {
            Some('0'..='7') => {
                let octal_value = consume_octal(&mut chars);
                if let Some(byte) = char::from_u32(octal_value) {
                    decoded.push(byte);
                }
            }
            _ => match chars.next() {
                Some('E' | 'e') => decoded.push('\x1b'),
                Some('a') => decoded.push('\x07'),
                Some('b') => decoded.push('\x08'),
                Some('f') => decoded.push('\x0c'),
                Some('n') => decoded.push('\n'),
                Some('r') => decoded.push('\r'),
                Some('s') => decoded.push(' '),
                Some('t') => decoded.push('\t'),
                Some('v') => decoded.push('\x0b'),
                Some('\\') => decoded.push('\\'),
                Some(':') => decoded.push(':'),
                Some('^') => {
                    if let Some(ctrl) = chars.next() {
                        if ctrl == '?' {
                            decoded.push('\x7f');
                        } else {
                            decoded.push(char::from((ctrl as u8) & 0x1f));
                        }
                    }
                }
                Some(other) => decoded.push(other),
                None => decoded.push('\\'),
            },
        }
    }

    decoded
}

fn consume_octal(chars: &mut std::iter::Peekable<std::str::Chars<'_>>) -> u32 {
    let mut value: u32 = 0;
    for _ in 0..3 {
        match chars.peek() {
            Some('0'..='7') => {
                let digit = chars.next().unwrap();
                value = (value << 3) | (digit as u32 - '0' as u32);
            }
            _ => break,
        }
    }
    value
}