From e5b136f70d4152e786ef358ec4bd20dbbb89aca7 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Sat, 19 Dec 2020 20:47:34 +1300 Subject: [PATCH] Add script sourcing (#2803) * Add script sourcing * clippy --- crates/nu-cli/src/cli.rs | 15 +++--- crates/nu-cli/src/commands.rs | 2 + .../nu-cli/src/commands/autoview/command.rs | 1 - .../src/commands/classified/internal.rs | 25 +++++++++- crates/nu-cli/src/commands/command.rs | 3 -- crates/nu-cli/src/commands/math/avg.rs | 1 - crates/nu-cli/src/commands/math/ceil.rs | 1 - crates/nu-cli/src/commands/math/floor.rs | 1 - crates/nu-cli/src/commands/math/max.rs | 1 - crates/nu-cli/src/commands/math/median.rs | 1 - crates/nu-cli/src/commands/math/min.rs | 1 - crates/nu-cli/src/commands/math/mode.rs | 1 - crates/nu-cli/src/commands/math/product.rs | 1 - crates/nu-cli/src/commands/math/sum.rs | 1 - crates/nu-cli/src/commands/run_external.rs | 1 - crates/nu-cli/src/commands/save.rs | 2 +- crates/nu-cli/src/commands/source.rs | 48 +++++++++++++++++++ crates/nu-cli/src/evaluation_context.rs | 11 ++--- crates/nu-cli/src/examples.rs | 8 ++-- crates/nu-cli/src/shell/shell_manager.rs | 12 ++--- crates/nu-protocol/src/return_value.rs | 3 ++ 21 files changed, 98 insertions(+), 42 deletions(-) create mode 100644 crates/nu-cli/src/commands/source.rs diff --git a/crates/nu-cli/src/cli.rs b/crates/nu-cli/src/cli.rs index 796f95c54..a82600d21 100644 --- a/crates/nu-cli/src/cli.rs +++ b/crates/nu-cli/src/cli.rs @@ -58,7 +58,7 @@ pub fn search_paths() -> Vec { } pub fn create_default_context(interactive: bool) -> Result> { - let mut context = EvaluationContext::basic()?; + let context = EvaluationContext::basic()?; { use crate::commands::*; @@ -69,6 +69,7 @@ pub fn create_default_context(interactive: bool) -> Result Result<(), Box> { LineResult::Success(_) => { process_script( &session_text[line_start..], - &mut context, + &context, false, line_start, true, @@ -648,7 +649,7 @@ async fn run_startup_commands( pub async fn run_script_standalone( script_text: String, redirect_stdin: bool, - context: &mut EvaluationContext, + context: &EvaluationContext, exit_on_error: bool, ) -> Result<(), Box> { let line = process_script(&script_text, context, redirect_stdin, 0, false).await; @@ -888,7 +889,7 @@ pub enum LineResult { ClearHistory, } -pub async fn parse_and_eval(line: &str, ctx: &mut EvaluationContext) -> Result { +pub async fn parse_and_eval(line: &str, ctx: &EvaluationContext) -> Result { // FIXME: do we still need this? let line = if let Some(s) = line.strip_suffix('\n') { s @@ -917,7 +918,7 @@ pub async fn parse_and_eval(line: &str, ctx: &mut EvaluationContext) -> Result match action { @@ -188,6 +188,29 @@ pub(crate) async fn run_internal_command( context.scope.add_env_var(name, value); InputStream::from_stream(futures::stream::iter(vec![])) } + CommandAction::SourceScript(filename) => { + let contents = std::fs::read_to_string(&filename); + if let Ok(contents) = contents { + let result = crate::cli::run_script_standalone( + contents, true, &context, false, + ) + .await; + + if let Err(err) = result { + return InputStream::one( + UntaggedValue::Error(err.into()).into_untagged_value(), + ); + } + InputStream::from_stream(futures::stream::iter(vec![])) + } else { + InputStream::one( + UntaggedValue::Error(ShellError::untagged_runtime_error( + format!("could not source '{}'", filename), + )) + .into_untagged_value(), + ) + } + } CommandAction::AddPlugins(path) => { match crate::plugin::scan(vec![std::path::PathBuf::from(path)]) { Ok(plugins) => { diff --git a/crates/nu-cli/src/commands/command.rs b/crates/nu-cli/src/commands/command.rs index 645d1a122..ebbd1a8c8 100644 --- a/crates/nu-cli/src/commands/command.rs +++ b/crates/nu-cli/src/commands/command.rs @@ -43,7 +43,6 @@ pub struct CommandArgs { pub call_info: UnevaluatedCallInfo, pub scope: Scope, pub input: InputStream, - pub raw_input: String, } #[derive(Getters, Clone)] @@ -67,7 +66,6 @@ impl RawCommandArgs { call_info: self.call_info, scope: self.scope, input: input.into(), - raw_input: String::default(), } } } @@ -116,7 +114,6 @@ pub struct RunnableContext { pub current_errors: Arc>>, pub scope: Scope, pub name: Tag, - pub raw_input: String, } impl RunnableContext { diff --git a/crates/nu-cli/src/commands/math/avg.rs b/crates/nu-cli/src/commands/math/avg.rs index 330c84b65..c0b80fa7c 100644 --- a/crates/nu-cli/src/commands/math/avg.rs +++ b/crates/nu-cli/src/commands/math/avg.rs @@ -38,7 +38,6 @@ impl WholeStreamCommand for SubCommand { ctrl_c: args.ctrl_c, current_errors: args.current_errors, name: args.call_info.name_tag, - raw_input: args.raw_input, }, average, ) diff --git a/crates/nu-cli/src/commands/math/ceil.rs b/crates/nu-cli/src/commands/math/ceil.rs index acbe035d2..6c2ea6288 100644 --- a/crates/nu-cli/src/commands/math/ceil.rs +++ b/crates/nu-cli/src/commands/math/ceil.rs @@ -31,7 +31,6 @@ impl WholeStreamCommand for SubCommand { ctrl_c: args.ctrl_c, current_errors: args.current_errors, name: args.call_info.name_tag, - raw_input: args.raw_input, }, ceil_big_int, ceil_big_decimal, diff --git a/crates/nu-cli/src/commands/math/floor.rs b/crates/nu-cli/src/commands/math/floor.rs index 8ce4da44b..c3d4f362d 100644 --- a/crates/nu-cli/src/commands/math/floor.rs +++ b/crates/nu-cli/src/commands/math/floor.rs @@ -31,7 +31,6 @@ impl WholeStreamCommand for SubCommand { ctrl_c: args.ctrl_c, current_errors: args.current_errors, name: args.call_info.name_tag, - raw_input: args.raw_input, }, floor_big_int, floor_big_decimal, diff --git a/crates/nu-cli/src/commands/math/max.rs b/crates/nu-cli/src/commands/math/max.rs index 698c366ba..18cd2496c 100644 --- a/crates/nu-cli/src/commands/math/max.rs +++ b/crates/nu-cli/src/commands/math/max.rs @@ -31,7 +31,6 @@ impl WholeStreamCommand for SubCommand { ctrl_c: args.ctrl_c, current_errors: args.current_errors, name: args.call_info.name_tag, - raw_input: args.raw_input, }, maximum, ) diff --git a/crates/nu-cli/src/commands/math/median.rs b/crates/nu-cli/src/commands/math/median.rs index 744c2fc65..da7ada1eb 100644 --- a/crates/nu-cli/src/commands/math/median.rs +++ b/crates/nu-cli/src/commands/math/median.rs @@ -35,7 +35,6 @@ impl WholeStreamCommand for SubCommand { ctrl_c: args.ctrl_c, current_errors: args.current_errors, name: args.call_info.name_tag, - raw_input: args.raw_input, }, median, ) diff --git a/crates/nu-cli/src/commands/math/min.rs b/crates/nu-cli/src/commands/math/min.rs index 243e2ca8d..bb8b3bf0a 100644 --- a/crates/nu-cli/src/commands/math/min.rs +++ b/crates/nu-cli/src/commands/math/min.rs @@ -31,7 +31,6 @@ impl WholeStreamCommand for SubCommand { ctrl_c: args.ctrl_c, current_errors: args.current_errors, name: args.call_info.name_tag, - raw_input: args.raw_input, }, minimum, ) diff --git a/crates/nu-cli/src/commands/math/mode.rs b/crates/nu-cli/src/commands/math/mode.rs index 0b594988b..504dc234a 100644 --- a/crates/nu-cli/src/commands/math/mode.rs +++ b/crates/nu-cli/src/commands/math/mode.rs @@ -31,7 +31,6 @@ impl WholeStreamCommand for SubCommand { ctrl_c: args.ctrl_c, current_errors: args.current_errors, name: args.call_info.name_tag, - raw_input: args.raw_input, }, mode, ) diff --git a/crates/nu-cli/src/commands/math/product.rs b/crates/nu-cli/src/commands/math/product.rs index 6a617b540..f07fa0bed 100644 --- a/crates/nu-cli/src/commands/math/product.rs +++ b/crates/nu-cli/src/commands/math/product.rs @@ -34,7 +34,6 @@ impl WholeStreamCommand for SubCommand { ctrl_c: args.ctrl_c, current_errors: args.current_errors, name: args.call_info.name_tag, - raw_input: args.raw_input, }, product, ) diff --git a/crates/nu-cli/src/commands/math/sum.rs b/crates/nu-cli/src/commands/math/sum.rs index 0f3992748..debb4de7a 100644 --- a/crates/nu-cli/src/commands/math/sum.rs +++ b/crates/nu-cli/src/commands/math/sum.rs @@ -35,7 +35,6 @@ impl WholeStreamCommand for SubCommand { ctrl_c: args.ctrl_c, current_errors: args.current_errors, name: args.call_info.name_tag, - raw_input: args.raw_input, }, summation, ) diff --git a/crates/nu-cli/src/commands/run_external.rs b/crates/nu-cli/src/commands/run_external.rs index 85eb3d007..8875542b7 100644 --- a/crates/nu-cli/src/commands/run_external.rs +++ b/crates/nu-cli/src/commands/run_external.rs @@ -88,7 +88,6 @@ impl WholeStreamCommand for RunExternalCommand { ctrl_c: args.ctrl_c.clone(), current_errors: Arc::new(Mutex::new(vec![])), windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())), - raw_input: String::default(), } }; diff --git a/crates/nu-cli/src/commands/save.rs b/crates/nu-cli/src/commands/save.rs index 001d4460b..d1f4f1549 100644 --- a/crates/nu-cli/src/commands/save.rs +++ b/crates/nu-cli/src/commands/save.rs @@ -165,7 +165,7 @@ async fn save(raw_args: CommandArgs) -> Result { let host = raw_args.host.clone(); let ctrl_c = raw_args.ctrl_c.clone(); let current_errors = raw_args.current_errors.clone(); - let mut shell_manager = raw_args.shell_manager.clone(); + let shell_manager = raw_args.shell_manager.clone(); let head = raw_args.call_info.args.head.clone(); let ( diff --git a/crates/nu-cli/src/commands/source.rs b/crates/nu-cli/src/commands/source.rs new file mode 100644 index 000000000..cdc59a954 --- /dev/null +++ b/crates/nu-cli/src/commands/source.rs @@ -0,0 +1,48 @@ +use crate::commands::WholeStreamCommand; +use crate::prelude::*; + +use nu_errors::ShellError; +use nu_protocol::{CommandAction, ReturnSuccess, Signature, SyntaxShape}; +use nu_source::Tagged; + +pub struct Source; + +#[derive(Deserialize)] +pub struct SourceArgs { + pub filename: Tagged, +} + +#[async_trait] +impl WholeStreamCommand for Source { + fn name(&self) -> &str { + "source" + } + + fn signature(&self) -> Signature { + Signature::build("source").required( + "filename", + SyntaxShape::String, + "the filepath to the script file to source", + ) + } + + fn usage(&self) -> &str { + "Runs a script file in the current context." + } + + async fn run(&self, args: CommandArgs) -> Result { + source(args).await + } + + fn examples(&self) -> Vec { + vec![] + } +} + +pub async fn source(args: CommandArgs) -> Result { + let (SourceArgs { filename }, _) = args.process().await?; + + Ok(OutputStream::one(ReturnSuccess::action( + CommandAction::SourceScript(filename.item), + ))) +} diff --git a/crates/nu-cli/src/evaluation_context.rs b/crates/nu-cli/src/evaluation_context.rs index a0ac7d448..7e6f5e805 100644 --- a/crates/nu-cli/src/evaluation_context.rs +++ b/crates/nu-cli/src/evaluation_context.rs @@ -16,7 +16,6 @@ pub struct EvaluationContext { pub host: Arc>>, pub current_errors: Arc>>, pub ctrl_c: Arc, - pub raw_input: String, pub user_recently_used_autoenv_untrust: Arc, pub(crate) shell_manager: ShellManager, @@ -34,7 +33,6 @@ impl EvaluationContext { shell_manager: raw_args.shell_manager.clone(), user_recently_used_autoenv_untrust: Arc::new(AtomicBool::new(false)), windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())), - raw_input: String::default(), } } @@ -47,7 +45,6 @@ impl EvaluationContext { shell_manager: args.shell_manager.clone(), user_recently_used_autoenv_untrust: Arc::new(AtomicBool::new(false)), windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())), - raw_input: String::default(), } } @@ -62,7 +59,6 @@ impl EvaluationContext { user_recently_used_autoenv_untrust: Arc::new(AtomicBool::new(false)), shell_manager: ShellManager::basic()?, windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())), - raw_input: String::default(), }) } @@ -82,7 +78,7 @@ impl EvaluationContext { self.current_errors.lock().push(err); } - pub(crate) fn maybe_print_errors(&mut self, source: Text) -> bool { + pub(crate) fn maybe_print_errors(&self, source: Text) -> bool { let errors = self.current_errors.clone(); let mut errors = errors.lock(); @@ -105,7 +101,7 @@ impl EvaluationContext { block(config, &mut *self); } - pub(crate) fn with_host(&mut self, block: impl FnOnce(&mut dyn Host) -> T) -> T { + pub(crate) fn with_host(&self, block: impl FnOnce(&mut dyn Host) -> T) -> T { let mut host = self.host.lock(); block(&mut *host) @@ -117,7 +113,7 @@ impl EvaluationContext { block(&mut *errors) } - pub fn add_commands(&mut self, commands: Vec) { + pub fn add_commands(&self, commands: Vec) { for command in commands { self.scope.add_command(command.name().to_string(), command); } @@ -156,7 +152,6 @@ impl EvaluationContext { call_info: self.call_info(args, name_tag), scope: self.scope.clone(), input, - raw_input: self.raw_input.clone(), } } diff --git a/crates/nu-cli/src/examples.rs b/crates/nu-cli/src/examples.rs index 5fd0568d6..28ce79378 100644 --- a/crates/nu-cli/src/examples.rs +++ b/crates/nu-cli/src/examples.rs @@ -26,7 +26,7 @@ use serde::Deserialize; pub fn test_examples(cmd: Command) -> Result<(), ShellError> { let examples = cmd.examples(); - let mut base_context = EvaluationContext::basic()?; + let base_context = EvaluationContext::basic()?; base_context.add_commands(vec![ // Mocks @@ -89,7 +89,7 @@ pub fn test_examples(cmd: Command) -> Result<(), ShellError> { pub fn test(cmd: impl WholeStreamCommand + 'static) -> Result<(), ShellError> { let examples = cmd.examples(); - let mut base_context = EvaluationContext::basic()?; + let base_context = EvaluationContext::basic()?; base_context.add_commands(vec![ whole_stream_command(Echo {}), @@ -144,7 +144,7 @@ pub fn test(cmd: impl WholeStreamCommand + 'static) -> Result<(), ShellError> { pub fn test_anchors(cmd: Command) -> Result<(), ShellError> { let examples = cmd.examples(); - let mut base_context = EvaluationContext::basic()?; + let base_context = EvaluationContext::basic()?; base_context.add_commands(vec![ // Minimal restricted commands to aid in testing @@ -192,7 +192,7 @@ pub fn test_anchors(cmd: Command) -> Result<(), ShellError> { } /// Parse and run a nushell pipeline -fn parse_line(line: &str, ctx: &mut EvaluationContext) -> Result { +fn parse_line(line: &str, ctx: &EvaluationContext) -> Result { //FIXME: do we still need this? let line = if let Some(line) = line.strip_suffix('\n') { line diff --git a/crates/nu-cli/src/shell/shell_manager.rs b/crates/nu-cli/src/shell/shell_manager.rs index e3925d097..ec1156d1f 100644 --- a/crates/nu-cli/src/shell/shell_manager.rs +++ b/crates/nu-cli/src/shell/shell_manager.rs @@ -33,7 +33,7 @@ impl ShellManager { }) } - pub fn insert_at_current(&mut self, shell: Box) { + pub fn insert_at_current(&self, shell: Box) { self.shells.lock().push(shell); self.current_shell .store(self.shells.lock().len() - 1, Ordering::SeqCst); @@ -44,7 +44,7 @@ impl ShellManager { self.current_shell.load(Ordering::SeqCst) } - pub fn remove_at_current(&mut self) { + pub fn remove_at_current(&self) { { let mut shells = self.shells.lock(); if shells.len() > 0 { @@ -78,7 +78,7 @@ impl ShellManager { env[self.current_shell()].pwd(args) } - pub fn set_path(&mut self, path: String) { + pub fn set_path(&self, path: String) { self.shells.lock()[self.current_shell()].set_path(path) } @@ -93,7 +93,7 @@ impl ShellManager { } pub fn save( - &mut self, + &self, full_path: &PathBuf, save_data: &[u8], name: Span, @@ -101,7 +101,7 @@ impl ShellManager { self.shells.lock()[self.current_shell()].save(full_path, save_data, name) } - pub fn next(&mut self) { + pub fn next(&self) { { let shell_len = self.shells.lock().len(); if self.current_shell() == (shell_len - 1) { @@ -114,7 +114,7 @@ impl ShellManager { self.set_path(self.path()) } - pub fn prev(&mut self) { + pub fn prev(&self) { { let shell_len = self.shells.lock().len(); if self.current_shell() == 0 { diff --git a/crates/nu-protocol/src/return_value.rs b/crates/nu-protocol/src/return_value.rs index 63eeb2ab2..dbcb388af 100644 --- a/crates/nu-protocol/src/return_value.rs +++ b/crates/nu-protocol/src/return_value.rs @@ -26,6 +26,8 @@ pub enum CommandAction { AddEnvVariable(String, String), /// Add plugins from path given AddPlugins(String), + /// Run the given script in the current context (given filename) + SourceScript(String), /// Go to the previous shell in the shell ring buffer PreviousShell, /// Go to the next shell in the shell ring buffer @@ -49,6 +51,7 @@ impl PrettyDebug for CommandAction { CommandAction::EnterHelpShell(v) => b::typed("enter help shell", v.pretty()), CommandAction::AddVariable(..) => b::description("add variable"), CommandAction::AddEnvVariable(..) => b::description("add environment variable"), + CommandAction::SourceScript(..) => b::description("source script"), CommandAction::AddPlugins(..) => b::description("add plugins"), CommandAction::PreviousShell => b::description("previous shell"), CommandAction::NextShell => b::description("next shell"),