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
<!--
Don't forget to add tests that cover your changes.

Make sure you've run and fixed any issues with these commands:

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect -A clippy::result_large_err` to check that
you're using the standard code style
- `cargo test --workspace` to check that all tests pass
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library

> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
This commit is contained in:
JT 2023-08-12 05:58:49 +12:00 committed by GitHub
parent aa37572ddc
commit e77a0a48aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 65 additions and 28 deletions

View File

@ -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,

View File

@ -127,13 +127,12 @@ fn build_help_commands(engine_state: &EngineState, span: Span) -> Vec<Value> {
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;

View File

@ -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();

View File

@ -534,12 +534,11 @@ impl<'e, 's> ScopeData<'e, 's> {
pub fn collect_aliases(&self, span: Span) -> Vec<Value> {
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 {

View File

@ -783,16 +783,22 @@ impl EngineState {
decls.into_iter()
}
#[allow(clippy::borrowed_box)]
pub fn get_signature(&self, decl: &Box<dyn Command>) -> 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<Signature> {
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<Example>, 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,

View File

@ -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
}

View File

@ -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()