diff --git a/crates/shell/src/commands.rs b/crates/shell/src/commands.rs index 66c8f24..5304be2 100644 --- a/crates/shell/src/commands.rs +++ b/crates/shell/src/commands.rs @@ -1,15 +1,19 @@ -use std::ffi::OsString; +use std::{ffi::OsString, fs}; use deno_task_shell::{EnvChange, ExecuteResult, ShellCommand, ShellCommandContext}; -use futures::future::LocalBoxFuture; +use futures::{future::LocalBoxFuture, FutureExt}; use uu_ls::uumain as uu_ls; + +use crate::execute; pub struct LsCommand; pub struct AliasCommand; pub struct UnAliasCommand; +pub struct SourceCommand; + impl ShellCommand for AliasCommand { fn execute(&self, context: ShellCommandContext) -> LocalBoxFuture<'static, ExecuteResult> { if context.args.len() != 1 { @@ -61,3 +65,33 @@ fn execute_ls(context: ShellCommandContext) -> ExecuteResult { let exit_code = uu_ls(args.into_iter()); ExecuteResult::from_exit_code(exit_code) } + +impl ShellCommand for SourceCommand { + fn execute(&self, context: ShellCommandContext) -> LocalBoxFuture<'static, ExecuteResult> { + if context.args.len() != 1 { + return Box::pin(futures::future::ready(ExecuteResult::from_exit_code(1))); + } + + let script = context.args[0].clone(); + let script_file = context.state.cwd().join(script); + match fs::read_to_string(&script_file) { + Ok(content) => { + let state = context.state.clone(); + async move { + execute::execute_inner(&content, state) + .await + .unwrap_or_else(|e| { + eprintln!("Could not source script: {:?}", script_file); + eprintln!("Error: {}", e); + ExecuteResult::from_exit_code(1) + }) + } + .boxed_local() + } + Err(e) => { + eprintln!("Could not read file: {:?} ({})", script_file, e); + Box::pin(futures::future::ready(ExecuteResult::from_exit_code(1))) + } + } + } +} diff --git a/crates/shell/src/execute.rs b/crates/shell/src/execute.rs new file mode 100644 index 0000000..6295992 --- /dev/null +++ b/crates/shell/src/execute.rs @@ -0,0 +1,44 @@ +use anyhow::Context; +use deno_task_shell::{ + execute_sequential_list, AsyncCommandBehavior, ExecuteResult, ShellPipeReader, ShellPipeWriter, + ShellState, +}; + +pub async fn execute_inner(text: &str, state: ShellState) -> anyhow::Result { + let list = deno_task_shell::parser::parse(text); + + let stderr = ShellPipeWriter::stderr(); + let stdout = ShellPipeWriter::stdout(); + let stdin = ShellPipeReader::stdin(); + + if let Err(e) = list { + anyhow::bail!("Syntax error: {}", e); + } + + // spawn a sequential list and pipe its output to the environment + let result = execute_sequential_list( + list.unwrap(), + state, + stdin, + stdout, + stderr, + AsyncCommandBehavior::Wait, + ) + .await; + + Ok(result) +} + +pub async fn execute(text: &str, state: &mut ShellState) -> anyhow::Result { + let result = execute_inner(text, state.clone()).await?; + + match result { + ExecuteResult::Continue(exit_code, changes, _) => { + // set CWD to the last command's CWD + state.apply_changes(&changes); + std::env::set_current_dir(state.cwd()).context("Failed to set CWD")?; + Ok(exit_code) + } + ExecuteResult::Exit(_, _) => Ok(0), + } +} diff --git a/crates/shell/src/main.rs b/crates/shell/src/main.rs index cdb2e69..95bf422 100644 --- a/crates/shell/src/main.rs +++ b/crates/shell/src/main.rs @@ -5,17 +5,17 @@ use std::rc::Rc; use anyhow::Context; use clap::Parser; use deno_task_shell::parser::debug_parse; -use deno_task_shell::{ - execute_sequential_list, AsyncCommandBehavior, ExecuteResult, ShellCommand, ShellPipeReader, - ShellPipeWriter, ShellState, -}; +use deno_task_shell::{ShellCommand, ShellState}; use rustyline::error::ReadlineError; use rustyline::{CompletionType, Config, Editor}; mod commands; mod completion; +mod execute; mod helper; +pub use execute::execute; + fn commands() -> HashMap> { HashMap::from([ ( @@ -30,43 +30,13 @@ fn commands() -> HashMap> { "unalias".to_string(), Rc::new(commands::AliasCommand) as Rc, ), + ( + "source".to_string(), + Rc::new(commands::SourceCommand) as Rc, + ), ]) } -async fn execute(text: &str, state: &mut ShellState) -> anyhow::Result { - let list = deno_task_shell::parser::parse(text); - - let mut stderr = ShellPipeWriter::stderr(); - let stdout = ShellPipeWriter::stdout(); - let stdin = ShellPipeReader::stdin(); - - if let Err(e) = list { - let _ = stderr.write_line(&format!("Syntax error: {}", e)); - return Ok(1); - } - - // spawn a sequential list and pipe its output to the environment - let result = execute_sequential_list( - list.unwrap(), - state.clone(), - stdin, - stdout, - stderr, - AsyncCommandBehavior::Wait, - ) - .await; - - match result { - ExecuteResult::Continue(exit_code, changes, _) => { - // set CWD to the last command's CWD - state.apply_changes(&changes); - std::env::set_current_dir(state.cwd()).context("Failed to set CWD")?; - Ok(exit_code) - } - ExecuteResult::Exit(_, _) => Ok(0), - } -} - #[derive(Parser)] struct Options { /// The path to the file that should be executed @@ -93,10 +63,6 @@ async fn interactive() -> anyhow::Result<()> { let helper = helper::ShellPromptHelper::default(); rl.set_helper(Some(helper)); - // let h = ShellCompleter {}; - - // rl.set_helper(Some(h)); - let mut state = init_state(); let home = dirs::home_dir().context("Couldn't get home directory")?;