aurora-modules 0.1.0

Git, filesystem, system, network, archive, docker, unix, crypto, calculator, QR, color, timer, notes, clipboard, and text processing modules
Documentation
use aurora_core::{AuroraResult, Pipeline, Value};
use std::process::Command;

fn try_cmds(cmds: &[&[&str]]) -> Option<String> {
    for args in cmds {
        if let Ok(output) = Command::new(args[0]).args(&args[1..]).output() {
            if output.status.success() {
                let s = String::from_utf8_lossy(&output.stdout).trim().to_string();
                if !s.is_empty() {
                    return Some(s);
                }
            }
        }
    }
    None
}

fn exec_cmd(args: &[&str]) -> AuroraResult<()> {
    let result = Command::new(args[0])
        .args(&args[1..])
        .output()
        .map_err(|e| aurora_core::AuroraError::ModuleError(
            format!("clipboard command failed: {}", e)
        ))?;
    if !result.status.success() {
        let stderr = String::from_utf8_lossy(&result.stderr);
        return Err(aurora_core::AuroraError::ModuleError(
            format!("clipboard command failed: {}", stderr)
        ));
    }
    Ok(())
}

pub fn clip_get() -> AuroraResult<Pipeline> {
    let content = try_cmds(&[
        &["xclip", "-o", "-selection", "clipboard"],
        &["wl-paste"],
        &["pbpaste"],
        &["powershell", "-Command", "Get-Clipboard"],
    ])
    .unwrap_or_default();

    Ok(Pipeline::table(
        vec!["clipboard".into()],
        vec![vec![Value::String(content)]],
    ))
}

pub fn clip_set(text: &[String]) -> AuroraResult<Pipeline> {
    let input = text.join(" ");

    let cmds: &[&[&str]] = &[
        &["xclip", "-i", "-selection", "clipboard"],
        &["wl-copy"],
        &["pbcopy"],
    ];

    let mut success = false;
    for args in cmds {
        let child = Command::new(args[0])
            .args(&args[1..])
            .stdin(std::process::Stdio::piped())
            .spawn()
            .ok();

        if let Some(mut c) = child {
            use std::io::Write;
            if let Some(mut stdin) = c.stdin.take() {
                let _ = stdin.write_all(input.as_bytes());
                drop(stdin);
            }
            if let Ok(status) = c.wait() {
                if status.success() {
                    success = true;
                    break;
                }
            }
        }
    }

    if !success && cfg!(target_os = "windows") {
        let escaped = input.replace('\'', "''");
        exec_cmd(&["powershell", "-Command", &format!("Set-Clipboard '{}'", escaped)])?;
        success = true;
    }

    if !success {
        return Err(aurora_core::AuroraError::CommandNotFound(
            "no clipboard tool found (install xclip, wl-clipboard, or pbcopy)".into()
        ));
    }

    Ok(Pipeline::table(
        vec!["action".into(), "content".into()],
        vec![vec![
            Value::String("set".into()),
            Value::String(input),
        ]],
    ))
}

pub fn clip_clear() -> AuroraResult<Pipeline> {
    clip_set(&[String::new()])
}