mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 13:15:58 +02:00
Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description As title, when execute external sub command, auto-trimming end new-lines, like how fish shell does. And if the command is executed directly like: `cat tmp`, the result won't change. Fixes: #6816 Fixes: #3980 Note that although nushell works correctly by directly replace output of external command to variable(or other places like string interpolation), it's not friendly to user, and users almost want to use `str trim` to trim trailing newline, I think that's why fish shell do this automatically. If the pr is ok, as a result, no more `str trim -r` is required when user is writing scripts which using external commands. # User-Facing Changes Before: <img width="523" alt="img" src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png"> After: <img width="505" alt="img" src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png"> # 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 --features=extra -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` to check that you're using the standard code style - `cargo test --workspace --features=extra` to check that all tests pass # 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:
@ -116,6 +116,7 @@ impl Command for Do {
|
||||
exit_code,
|
||||
span,
|
||||
metadata,
|
||||
trim_end_newline,
|
||||
}) if capture_errors => {
|
||||
let mut exit_code_ctrlc = None;
|
||||
let exit_code: Vec<Value> = match exit_code {
|
||||
@ -149,6 +150,7 @@ impl Command for Do {
|
||||
)),
|
||||
span,
|
||||
metadata,
|
||||
trim_end_newline,
|
||||
})
|
||||
}
|
||||
Ok(PipelineData::ExternalStream {
|
||||
@ -157,12 +159,14 @@ impl Command for Do {
|
||||
exit_code: _,
|
||||
span,
|
||||
metadata,
|
||||
trim_end_newline,
|
||||
}) if ignore_program_errors => Ok(PipelineData::ExternalStream {
|
||||
stdout,
|
||||
stderr,
|
||||
exit_code: None,
|
||||
span,
|
||||
metadata,
|
||||
trim_end_newline,
|
||||
}),
|
||||
Err(_) if ignore_shell_errors => Ok(PipelineData::new(call.head)),
|
||||
r => r,
|
||||
|
@ -74,6 +74,7 @@ impl Command for ConfigEnv {
|
||||
redirect_stdout: false,
|
||||
redirect_stderr: false,
|
||||
env_vars: env_vars_str,
|
||||
trim_end_newline: false,
|
||||
};
|
||||
|
||||
command.run_with_input(engine_state, stack, input, true)
|
||||
|
@ -74,6 +74,7 @@ impl Command for ConfigNu {
|
||||
redirect_stdout: false,
|
||||
redirect_stderr: false,
|
||||
env_vars: env_vars_str,
|
||||
trim_end_newline: false,
|
||||
};
|
||||
|
||||
command.run_with_input(engine_state, stack, input, true)
|
||||
|
@ -142,6 +142,7 @@ impl Command for Open {
|
||||
exit_code: None,
|
||||
span: call_span,
|
||||
metadata: None,
|
||||
trim_end_newline: false,
|
||||
};
|
||||
|
||||
let ext = if raw {
|
||||
|
@ -582,6 +582,7 @@ fn response_to_buffer(
|
||||
exit_code: None,
|
||||
span,
|
||||
metadata: None,
|
||||
trim_end_newline: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -430,6 +430,7 @@ fn response_to_buffer(
|
||||
exit_code: None,
|
||||
span,
|
||||
metadata: None,
|
||||
trim_end_newline: false,
|
||||
}
|
||||
}
|
||||
// Only panics if the user agent is invalid but we define it statically so either
|
||||
|
@ -273,7 +273,7 @@ fn format_record(
|
||||
}
|
||||
}
|
||||
FormatOperation::ValueNeedEval(_col_name, span) => {
|
||||
let (exp, may_parse_err) = parse_expression(working_set, &[*span], &[]);
|
||||
let (exp, may_parse_err) = parse_expression(working_set, &[*span], &[], false);
|
||||
match may_parse_err {
|
||||
None => {
|
||||
let parsed_result = eval_expression(engine_state, stack, &exp);
|
||||
|
@ -93,6 +93,7 @@ fn exec(
|
||||
env_vars,
|
||||
redirect_stdout: true,
|
||||
redirect_stderr: false,
|
||||
trim_end_newline: false,
|
||||
};
|
||||
|
||||
let mut command = external_command.spawn_simple_command(&cwd.to_string_lossy())?;
|
||||
|
@ -36,6 +36,7 @@ impl Command for External {
|
||||
Signature::build(self.name())
|
||||
.switch("redirect-stdout", "redirect stdout to the pipeline", None)
|
||||
.switch("redirect-stderr", "redirect stderr to the pipeline", None)
|
||||
.switch("trim-end-newline", "trimming end newlines", None)
|
||||
.required("command", SyntaxShape::Any, "external command to run")
|
||||
.rest("args", SyntaxShape::Any, "arguments for external command")
|
||||
.category(Category::System)
|
||||
@ -52,6 +53,7 @@ impl Command for External {
|
||||
let args: Vec<Value> = call.rest(engine_state, stack, 1)?;
|
||||
let redirect_stdout = call.has_flag("redirect-stdout");
|
||||
let redirect_stderr = call.has_flag("redirect-stderr");
|
||||
let trim_end_newline = call.has_flag("trim-end-newline");
|
||||
|
||||
// Translate environment variables from Values to Strings
|
||||
let env_vars_str = env_to_strings(engine_state, stack)?;
|
||||
@ -109,6 +111,7 @@ impl Command for External {
|
||||
redirect_stdout,
|
||||
redirect_stderr,
|
||||
env_vars: env_vars_str,
|
||||
trim_end_newline,
|
||||
};
|
||||
command.run_with_input(engine_state, stack, input, false)
|
||||
}
|
||||
@ -137,6 +140,7 @@ pub struct ExternalCommand {
|
||||
pub redirect_stdout: bool,
|
||||
pub redirect_stderr: bool,
|
||||
pub env_vars: HashMap<String, String>,
|
||||
pub trim_end_newline: bool,
|
||||
}
|
||||
|
||||
impl ExternalCommand {
|
||||
@ -466,6 +470,7 @@ impl ExternalCommand {
|
||||
)),
|
||||
span: head,
|
||||
metadata: None,
|
||||
trim_end_newline: self.trim_end_newline,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -256,6 +256,7 @@ fn handle_table_command(
|
||||
exit_code: None,
|
||||
span: call.head,
|
||||
metadata: None,
|
||||
trim_end_newline: false,
|
||||
}),
|
||||
PipelineData::Value(Value::List { vals, .. }, metadata) => handle_row_stream(
|
||||
engine_state,
|
||||
@ -709,6 +710,7 @@ fn handle_row_stream(
|
||||
exit_code: None,
|
||||
span: head,
|
||||
metadata: None,
|
||||
trim_end_newline: false,
|
||||
})
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user