fn has_force_delete_cmdlet()

in codex-rs/shell-command/src/command_safety/windows_dangerous_commands.rs [225:290]


fn has_force_delete_cmdlet(tokens: &[String]) -> bool {
    const DELETE_CMDLETS: &[&str] = &["remove-item", "ri", "rm", "del", "erase", "rd", "rmdir"];

    // Hard separators that end a command segment (so -Force must be in same segment)
    const SEG_SEPS: &[char] = &[';', '|', '&', '\n', '\r', '\t'];

    // Soft separators: punctuation that can stick to tokens (blocks, parens, brackets, commas, etc.)
    const SOFT_SEPS: &[char] = &['{', '}', '(', ')', '[', ']', ',', ';'];

    // Build rough command segments first
    let mut segments: Vec<Vec<String>> = vec![Vec::new()];
    for tok in tokens {
        // If token itself contains segment separators, split it (best-effort)
        let mut cur = String::new();
        for ch in tok.chars() {
            if SEG_SEPS.contains(&ch) {
                let s = cur.trim();
                if let Some(msg) = segments.last_mut()
                    && !s.is_empty()
                {
                    msg.push(s.to_string());
                }
                cur.clear();
                if let Some(last) = segments.last()
                    && !last.is_empty()
                {
                    segments.push(Vec::new());
                }
            } else {
                cur.push(ch);
            }
        }
        let s = cur.trim();
        if let Some(segment) = segments.last_mut()
            && !s.is_empty()
        {
            segment.push(s.to_string());
        }
    }

    // Now, inside each segment, normalize tokens by splitting on soft punctuation
    segments.into_iter().any(|seg| {
        let atoms = seg
            .iter()
            .flat_map(|t| t.split(|c| SOFT_SEPS.contains(&c)))
            .map(str::trim)
            .filter(|s| !s.is_empty());

        let mut has_delete = false;
        let mut has_force = false;

        for a in atoms {
            if DELETE_CMDLETS.iter().any(|cmd| a.eq_ignore_ascii_case(cmd)) {
                has_delete = true;
            }
            if a.eq_ignore_ascii_case("-force")
                || a.get(..7)
                    .is_some_and(|p| p.eq_ignore_ascii_case("-force:"))
            {
                has_force = true;
            }
        }

        has_delete && has_force
    })
}