From e77a0a48aacb1ed41da0d48ad7b2eefa5b3336b3 Mon Sep 17 00:00:00 2001 From: JT <547158+jntrnr@users.noreply.github.com> Date: Sat, 12 Aug 2023 05:58:49 +1200 Subject: [PATCH] Rename `main` to script name when running scripts (#9948) # Description This PR does three related changes: * Keeps the originally declared name in help outputs. * Updates the name of the commands called `main` in the user script to the name of the script. * Fixes the source of signature information in multiple places. This allows scripts to have more complete help output. Combined, the above allow the user to see the script name in the help output of scripts, like so: ![image](https://github.com/nushell/nushell/assets/547158/741d192c-0a39-45a7-8f36-3a0dc8eeae2b) NOTE: You still declare and call the definition `main`, so from inside the script `main` is still the correct name. But multiple folks agreed that seeing `main` in the script help was confusing, so this PR changes that. # User-Facing Changes One potential minor breaking change is that module renames will be shown as their originally defined name rather than the renamed name. I believe this to be a better default. # Tests + Formatting # After Submitting --- crates/nu-cli/src/eval_file.rs | 51 ++++++++++++++++--- crates/nu-command/src/help/help_commands.rs | 5 +- crates/nu-engine/src/eval.rs | 2 +- crates/nu-engine/src/scope.rs | 5 +- crates/nu-protocol/src/engine/engine_state.rs | 23 +++++---- crates/nu-protocol/src/plugin_signature.rs | 4 +- crates/nu-protocol/src/signature.rs | 3 +- 7 files changed, 65 insertions(+), 28 deletions(-) diff --git a/crates/nu-cli/src/eval_file.rs b/crates/nu-cli/src/eval_file.rs index a513ec56c..e28de2f08 100644 --- a/crates/nu-cli/src/eval_file.rs +++ b/crates/nu-cli/src/eval_file.rs @@ -2,6 +2,7 @@ use crate::util::eval_source; use log::info; use log::trace; use miette::{IntoDiagnostic, Result}; +use nu_engine::eval_block_with_early_return; use nu_engine::{convert_env_values, current_dir}; use nu_parser::parse; use nu_path::canonicalize_with; @@ -98,23 +99,59 @@ pub fn evaluate_file( Value::string(file_path.to_string_lossy(), Span::unknown()), ); + let source_filename = file_path + .file_name() + .expect("internal error: script missing filename"); + let mut working_set = StateWorkingSet::new(engine_state); trace!("parsing file: {}", file_path_str); - let _ = parse(&mut working_set, Some(file_path_str), &file, false); + let block = parse(&mut working_set, Some(file_path_str), &file, false); - if working_set.find_decl(b"main").is_some() { + for block in &mut working_set.delta.blocks { + if block.signature.name == "main" { + block.signature.name = source_filename.to_string_lossy().to_string(); + } else if block.signature.name.starts_with("main ") { + block.signature.name = source_filename.to_string_lossy().to_string() + + " " + + &String::from_utf8_lossy(&block.signature.name.as_bytes()[5..]); + } + } + + let _ = engine_state.merge_delta(working_set.delta); + + if engine_state.find_decl(b"main", &[]).is_some() { let args = format!("main {}", args.join(" ")); - if !eval_source( + let pipeline_data = eval_block_with_early_return( engine_state, stack, - &file, - file_path_str, + &block, PipelineData::empty(), - true, - ) { + false, + false, + ) + .unwrap_or_else(|e| { + let working_set = StateWorkingSet::new(engine_state); + report_error(&working_set, &e); std::process::exit(1); + }); + + let result = pipeline_data.print(engine_state, stack, true, false); + + match result { + Err(err) => { + let working_set = StateWorkingSet::new(engine_state); + + report_error(&working_set, &err); + std::process::exit(1); + } + Ok(exit_code) => { + if exit_code != 0 { + std::process::exit(exit_code as i32); + } + } } + if !eval_source( engine_state, stack, diff --git a/crates/nu-command/src/help/help_commands.rs b/crates/nu-command/src/help/help_commands.rs index ce360a244..621ba9e88 100644 --- a/crates/nu-command/src/help/help_commands.rs +++ b/crates/nu-command/src/help/help_commands.rs @@ -127,13 +127,12 @@ fn build_help_commands(engine_state: &EngineState, span: Span) -> Vec { let commands = engine_state.get_decls_sorted(false); let mut found_cmds_vec = Vec::new(); - for (name_bytes, decl_id) in commands { + for (_, decl_id) in commands { let mut cols = vec![]; let mut vals = vec![]; - let name = String::from_utf8_lossy(&name_bytes).to_string(); let decl = engine_state.get_decl(decl_id); - let sig = decl.signature().update_from_command(name, decl.borrow()); + let sig = decl.signature().update_from_command(decl.borrow()); let key = sig.name; let usage = sig.usage; diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index 33bf06ed6..4bfd2bc9f 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -38,7 +38,7 @@ pub fn eval_call( let decl = engine_state.get_decl(call.decl_id); if !decl.is_known_external() && call.named_iter().any(|(flag, _, _)| flag.item == "help") { - let mut signature = decl.signature(); + let mut signature = engine_state.get_signature(decl); signature.usage = decl.usage().to_string(); signature.extra_usage = decl.extra_usage().to_string(); diff --git a/crates/nu-engine/src/scope.rs b/crates/nu-engine/src/scope.rs index 36610b003..1961ff7a7 100644 --- a/crates/nu-engine/src/scope.rs +++ b/crates/nu-engine/src/scope.rs @@ -534,12 +534,11 @@ impl<'e, 's> ScopeData<'e, 's> { pub fn collect_aliases(&self, span: Span) -> Vec { let mut aliases = vec![]; - for (name_bytes, decl_id) in self.engine_state.get_decls_sorted(false) { + for (_, decl_id) in self.engine_state.get_decls_sorted(false) { if self.visibility.is_decl_id_visible(&decl_id) { let decl = self.engine_state.get_decl(decl_id); if let Some(alias) = decl.as_alias() { - let name = String::from_utf8_lossy(&name_bytes).to_string(); - let sig = decl.signature().update_from_command(name, decl.borrow()); + let sig = decl.signature().update_from_command(decl.borrow()); let key = sig.name; aliases.push(Value::Record { diff --git a/crates/nu-protocol/src/engine/engine_state.rs b/crates/nu-protocol/src/engine/engine_state.rs index d6c56eb68..5e8dbb5e6 100644 --- a/crates/nu-protocol/src/engine/engine_state.rs +++ b/crates/nu-protocol/src/engine/engine_state.rs @@ -783,16 +783,22 @@ impl EngineState { decls.into_iter() } + #[allow(clippy::borrowed_box)] + pub fn get_signature(&self, decl: &Box) -> Signature { + if let Some(block_id) = decl.get_block_id() { + *self.blocks[block_id].signature.clone() + } else { + decl.signature() + } + } + /// Get signatures of all commands within scope. pub fn get_signatures(&self, include_hidden: bool) -> Vec { self.get_decls_sorted(include_hidden) - .map(|(name_bytes, id)| { + .map(|(_, id)| { let decl = self.get_decl(id); - // the reason to create the name this way is because the command could be renamed - // during module imports but the signature still contains the old name - let name = String::from_utf8_lossy(&name_bytes).to_string(); - (*decl).signature().update_from_command(name, decl.borrow()) + self.get_signature(decl).update_from_command(decl.borrow()) }) .collect() } @@ -807,13 +813,10 @@ impl EngineState { include_hidden: bool, ) -> Vec<(Signature, Vec, bool, bool, bool)> { self.get_decls_sorted(include_hidden) - .map(|(name_bytes, id)| { + .map(|(_, id)| { let decl = self.get_decl(id); - // the reason to create the name this way is because the command could be renamed - // during module imports but the signature still contains the old name - let name = String::from_utf8_lossy(&name_bytes).to_string(); - let signature = (*decl).signature().update_from_command(name, decl.borrow()); + let signature = self.get_signature(decl).update_from_command(decl.borrow()); ( signature, diff --git a/crates/nu-protocol/src/plugin_signature.rs b/crates/nu-protocol/src/plugin_signature.rs index 215a7e2ab..45a5072d8 100644 --- a/crates/nu-protocol/src/plugin_signature.rs +++ b/crates/nu-protocol/src/plugin_signature.rs @@ -48,8 +48,8 @@ impl PluginSignature { } /// Update signature's fields from a Command trait implementation - pub fn update_from_command(mut self, name: String, command: &dyn Command) -> PluginSignature { - self.sig = self.sig.update_from_command(name, command); + pub fn update_from_command(mut self, command: &dyn Command) -> PluginSignature { + self.sig = self.sig.update_from_command(command); self } diff --git a/crates/nu-protocol/src/signature.rs b/crates/nu-protocol/src/signature.rs index 81168b32b..5689692aa 100644 --- a/crates/nu-protocol/src/signature.rs +++ b/crates/nu-protocol/src/signature.rs @@ -237,8 +237,7 @@ impl Signature { } /// Update signature's fields from a Command trait implementation - pub fn update_from_command(mut self, name: String, command: &dyn Command) -> Signature { - self.name = name; + pub fn update_from_command(mut self, command: &dyn Command) -> Signature { self.search_terms = command .search_terms() .into_iter()