<commit_before>use ion_shell::{
    builtins::{man_pages::check_help, Status},
    sys::SIGTERM,
    types::Str,
    Shell,
};
use std::{error::Error, process::Command};

const MAN_EXEC: &str = r#"NAME
    exec - Replace the shell with the given command.

SYNOPSIS
    exec [-ch] [--help] [command [arguments ...]]

DESCRIPTION
    Execute <command>, replacing the shell with the specified program.
    The <arguments> following the command become the arguments to
    <command>.

OPTIONS
    -c  Execute command with an empty environment."#;

pub const MAN_EXIT: &str = r#"NAME
    exit - exit the shell

SYNOPSIS
    exit

DESCRIPTION
    Makes ion exit. The exit status will be that of the last command executed."#;

/// Executes the givent commmand.
pub fn _exec(args: &[Str]) -> Result<(), Str> {
    let mut clear_env = false;
    let mut idx = 0;
    for arg in args.iter() {
        match &**arg {
            "-c" => clear_env = true,
            _ if check_help(args, MAN_EXEC) => {
                return Ok(());
            }
            _ => break,
        }
        idx += 1;
    }

    match args.get(idx) {
        Some(argument) => {
            let args = if args.len() > idx + 1 { &args[idx + 1..] } else { &[] };
            let mut command = Command::new(argument.as_str());
            command.args(args.iter().map(Str::as_str));
            if clear_env {
                command.env_clear();
            }
            command.spawn().map(|_| ()).map_err(|err| err.description().into())
        }
        None => Err("no command provided".into()),
    }
}

pub fn exit(args: &[Str], shell: &mut Shell<'_>) -> Status {
    if check_help(args, MAN_EXIT) {
        return Status::SUCCESS;
    }
    // Kill all active background tasks before exiting the shell.
    shell.background_send(SIGTERM);
    let exit_code = args
        .get(1)
        .and_then(|status| status.parse::<i32>().ok())
        .unwrap_or_else(|| shell.previous_status().as_os_code());
    std::process::exit(exit_code);
}

pub fn exec(args: &[Str], _shell: &mut Shell<'_>) -> Status {
    match _exec(&args[1..]) {
        // Shouldn't ever hit this case.
        Ok(()) => unreachable!(),
        Err(err) => Status::error(format!("ion: exec: {}", err)),
    }
}<commit_msg>Called spawn instead of exec :facepalm:<commit_after>use ion_shell::{
    builtins::{man_pages::check_help, Status},
    sys::SIGTERM,
    types::Str,
    Shell,
};
use std::{error::Error, os::unix::process::CommandExt, process::Command};

const MAN_EXEC: &str = r#"NAME
    exec - Replace the shell with the given command.

SYNOPSIS
    exec [-ch] [--help] [command [arguments ...]]

DESCRIPTION
    Execute <command>, replacing the shell with the specified program.
    The <arguments> following the command become the arguments to
    <command>.

OPTIONS
    -c  Execute command with an empty environment."#;

pub const MAN_EXIT: &str = r#"NAME
    exit - exit the shell

SYNOPSIS
    exit

DESCRIPTION
    Makes ion exit. The exit status will be that of the last command executed."#;

/// Executes the givent commmand.
pub fn _exec(args: &[Str]) -> Result<(), Str> {
    let mut clear_env = false;
    let mut idx = 0;
    for arg in args.iter() {
        match &**arg {
            "-c" => clear_env = true,
            _ if check_help(args, MAN_EXEC) => {
                return Ok(());
            }
            _ => break,
        }
        idx += 1;
    }

    match args.get(idx) {
        Some(argument) => {
            let args = if args.len() > idx + 1 { &args[idx + 1..] } else { &[] };
            let mut command = Command::new(argument.as_str());
            command.args(args.iter().map(Str::as_str));
            if clear_env {
                command.env_clear();
            }
            Err(command.exec().description().into())
        }
        None => Err("no command provided".into()),
    }
}

pub fn exit(args: &[Str], shell: &mut Shell<'_>) -> Status {
    if check_help(args, MAN_EXIT) {
        return Status::SUCCESS;
    }
    // Kill all active background tasks before exiting the shell.
    shell.background_send(SIGTERM);
    let exit_code = args
        .get(1)
        .and_then(|status| status.parse::<i32>().ok())
        .unwrap_or_else(|| shell.previous_status().as_os_code());
    std::process::exit(exit_code);
}

pub fn exec(args: &[Str], _shell: &mut Shell<'_>) -> Status {
    match _exec(&args[1..]) {
        // Shouldn't ever hit this case.
        Ok(()) => unreachable!(),
        Err(err) => Status::error(format!("ion: exec: {}", err)),
    }
}
{'fraction_non_alphanumeric': 0.15433450087565675, 'fraction_numerical': 0.0035026269702276708, 'mean_word_length': 2.322909090909091, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7622685', 'n_tokens_mistral': 1455, 'n_tokens_neox': 1440, 'n_words': 398}