2022-11-11 22:20:28 +00:00
|
|
|
use crate::{current_dir_str, get_full_help, scope::create_scope};
|
2022-01-16 13:55:56 +00:00
|
|
|
use nu_path::expand_path_with;
|
2021-10-25 04:01:02 +00:00
|
|
|
use nu_protocol::{
|
2022-11-11 07:16:07 +00:00
|
|
|
ast::{
|
2022-11-22 18:26:13 +00:00
|
|
|
Argument, Assignment, Bits, Block, Boolean, Call, Comparison, Expr, Expression, Math,
|
|
|
|
Operator, PathMember, PipelineElement, Redirection,
|
2022-11-11 07:16:07 +00:00
|
|
|
},
|
2022-11-11 22:20:28 +00:00
|
|
|
engine::{EngineState, Stack},
|
2022-07-25 17:00:31 +00:00
|
|
|
Config, HistoryFileFormat, IntoInterruptiblePipelineData, IntoPipelineData, ListStream,
|
2022-11-11 22:20:28 +00:00
|
|
|
PipelineData, Range, RawStream, ShellError, Span, Spanned, Unit, Value, VarId, ENV_VARIABLE_ID,
|
2021-10-25 04:01:02 +00:00
|
|
|
};
|
2022-05-17 18:28:18 +00:00
|
|
|
use nu_utils::stdout_write_all_and_flush;
|
2022-04-23 21:33:27 +00:00
|
|
|
use std::collections::HashMap;
|
|
|
|
use sysinfo::SystemExt;
|
2021-10-13 17:53:27 +00:00
|
|
|
|
2021-08-15 22:33:34 +00:00
|
|
|
pub fn eval_operator(op: &Expression) -> Result<Operator, ShellError> {
|
2021-07-23 05:14:49 +00:00
|
|
|
match op {
|
|
|
|
Expression {
|
|
|
|
expr: Expr::Operator(operator),
|
|
|
|
..
|
|
|
|
} => Ok(operator.clone()),
|
2021-09-05 23:16:27 +00:00
|
|
|
Expression { span, expr, .. } => {
|
|
|
|
Err(ShellError::UnknownOperator(format!("{:?}", expr), *span))
|
|
|
|
}
|
2021-07-16 01:10:22 +00:00
|
|
|
}
|
2021-07-23 05:14:49 +00:00
|
|
|
}
|
2021-07-16 01:10:22 +00:00
|
|
|
|
2022-03-10 07:49:02 +00:00
|
|
|
pub fn eval_call(
|
2021-10-25 06:31:39 +00:00
|
|
|
engine_state: &EngineState,
|
2021-12-25 19:39:42 +00:00
|
|
|
caller_stack: &mut Stack,
|
2021-10-25 04:01:02 +00:00
|
|
|
call: &Call,
|
|
|
|
input: PipelineData,
|
|
|
|
) -> Result<PipelineData, ShellError> {
|
2022-05-02 08:18:25 +00:00
|
|
|
if let Some(ctrlc) = &engine_state.ctrlc {
|
|
|
|
if ctrlc.load(core::sync::atomic::Ordering::SeqCst) {
|
|
|
|
return Ok(Value::Nothing { span: call.head }.into_pipeline_data());
|
|
|
|
}
|
|
|
|
}
|
2021-12-06 04:09:49 +00:00
|
|
|
let decl = engine_state.get_decl(call.decl_id);
|
2021-11-28 19:35:02 +00:00
|
|
|
|
2022-04-09 05:17:48 +00:00
|
|
|
if !decl.is_known_external() && call.named_iter().any(|(flag, _, _)| flag.item == "help") {
|
2022-02-10 02:24:29 +00:00
|
|
|
let mut signature = decl.signature();
|
|
|
|
signature.usage = decl.usage().to_string();
|
|
|
|
signature.extra_usage = decl.extra_usage().to_string();
|
|
|
|
|
2022-11-20 13:22:42 +00:00
|
|
|
let full_help = get_full_help(
|
|
|
|
&signature,
|
|
|
|
&decl.examples(),
|
|
|
|
engine_state,
|
|
|
|
caller_stack,
|
|
|
|
decl.is_parser_keyword(),
|
|
|
|
);
|
2021-10-13 17:53:27 +00:00
|
|
|
Ok(Value::String {
|
|
|
|
val: full_help,
|
|
|
|
span: call.head,
|
2021-10-25 04:01:02 +00:00
|
|
|
}
|
|
|
|
.into_pipeline_data())
|
2021-10-13 17:53:27 +00:00
|
|
|
} else if let Some(block_id) = decl.get_block_id() {
|
2021-10-25 20:04:23 +00:00
|
|
|
let block = engine_state.get_block(block_id);
|
|
|
|
|
2022-01-12 04:06:56 +00:00
|
|
|
let mut callee_stack = caller_stack.gather_captures(&block.captures);
|
2021-12-20 06:58:09 +00:00
|
|
|
|
|
|
|
for (param_idx, param) in decl
|
|
|
|
.signature()
|
|
|
|
.required_positional
|
|
|
|
.iter()
|
|
|
|
.chain(decl.signature().optional_positional.iter())
|
|
|
|
.enumerate()
|
|
|
|
{
|
2021-07-23 21:19:30 +00:00
|
|
|
let var_id = param
|
|
|
|
.var_id
|
|
|
|
.expect("internal error: all custom parameters must have var_ids");
|
|
|
|
|
2022-04-09 02:55:02 +00:00
|
|
|
if let Some(arg) = call.positional_nth(param_idx) {
|
2021-12-25 19:39:42 +00:00
|
|
|
let result = eval_expression(engine_state, caller_stack, arg)?;
|
|
|
|
callee_stack.add_var(var_id, result);
|
2022-03-07 20:08:56 +00:00
|
|
|
} else if let Some(arg) = ¶m.default_value {
|
|
|
|
let result = eval_expression(engine_state, caller_stack, arg)?;
|
|
|
|
callee_stack.add_var(var_id, result);
|
2021-12-20 06:58:09 +00:00
|
|
|
} else {
|
2021-12-25 19:39:42 +00:00
|
|
|
callee_stack.add_var(var_id, Value::nothing(call.head));
|
2021-12-20 06:58:09 +00:00
|
|
|
}
|
2021-07-23 21:19:30 +00:00
|
|
|
}
|
2021-09-07 03:37:02 +00:00
|
|
|
|
|
|
|
if let Some(rest_positional) = decl.signature().rest_positional {
|
|
|
|
let mut rest_items = vec![];
|
|
|
|
|
2022-04-09 02:55:02 +00:00
|
|
|
for arg in call.positional_iter().skip(
|
2021-09-07 03:37:02 +00:00
|
|
|
decl.signature().required_positional.len()
|
|
|
|
+ decl.signature().optional_positional.len(),
|
|
|
|
) {
|
2021-12-25 19:39:42 +00:00
|
|
|
let result = eval_expression(engine_state, caller_stack, arg)?;
|
2021-09-07 03:37:02 +00:00
|
|
|
rest_items.push(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
let span = if let Some(rest_item) = rest_items.first() {
|
2021-10-11 18:45:31 +00:00
|
|
|
rest_item.span()?
|
2021-09-07 03:37:02 +00:00
|
|
|
} else {
|
2021-12-19 07:46:13 +00:00
|
|
|
call.head
|
2021-09-07 03:37:02 +00:00
|
|
|
};
|
|
|
|
|
2021-12-25 19:39:42 +00:00
|
|
|
callee_stack.add_var(
|
2021-09-07 03:37:02 +00:00
|
|
|
rest_positional
|
|
|
|
.var_id
|
|
|
|
.expect("Internal error: rest positional parameter lacks var_id"),
|
|
|
|
Value::List {
|
2021-09-07 07:07:11 +00:00
|
|
|
vals: rest_items,
|
2021-09-07 03:37:02 +00:00
|
|
|
span,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
2021-10-11 21:17:45 +00:00
|
|
|
|
|
|
|
for named in decl.signature().named {
|
2021-10-13 17:53:27 +00:00
|
|
|
if let Some(var_id) = named.var_id {
|
|
|
|
let mut found = false;
|
2022-04-09 02:55:02 +00:00
|
|
|
for call_named in call.named_iter() {
|
2021-10-13 17:53:27 +00:00
|
|
|
if call_named.0.item == named.long {
|
2022-04-09 05:17:48 +00:00
|
|
|
if let Some(arg) = &call_named.2 {
|
2021-12-25 19:39:42 +00:00
|
|
|
let result = eval_expression(engine_state, caller_stack, arg)?;
|
2021-10-12 04:49:17 +00:00
|
|
|
|
2022-03-07 20:08:56 +00:00
|
|
|
callee_stack.add_var(var_id, result);
|
|
|
|
} else if let Some(arg) = &named.default_value {
|
|
|
|
let result = eval_expression(engine_state, caller_stack, arg)?;
|
|
|
|
|
2021-12-25 19:39:42 +00:00
|
|
|
callee_stack.add_var(var_id, result);
|
2021-10-13 17:53:27 +00:00
|
|
|
} else {
|
2021-12-25 19:39:42 +00:00
|
|
|
callee_stack.add_var(
|
2021-10-13 17:53:27 +00:00
|
|
|
var_id,
|
|
|
|
Value::Bool {
|
|
|
|
val: true,
|
|
|
|
span: call.head,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
found = true;
|
2021-10-11 21:17:45 +00:00
|
|
|
}
|
|
|
|
}
|
2021-10-12 04:49:17 +00:00
|
|
|
|
2022-01-06 20:32:47 +00:00
|
|
|
if !found {
|
|
|
|
if named.arg.is_none() {
|
|
|
|
callee_stack.add_var(
|
|
|
|
var_id,
|
|
|
|
Value::Bool {
|
|
|
|
val: false,
|
|
|
|
span: call.head,
|
|
|
|
},
|
|
|
|
)
|
2022-03-07 20:08:56 +00:00
|
|
|
} else if let Some(arg) = &named.default_value {
|
|
|
|
let result = eval_expression(engine_state, caller_stack, arg)?;
|
|
|
|
|
|
|
|
callee_stack.add_var(var_id, result);
|
2022-01-06 20:32:47 +00:00
|
|
|
} else {
|
|
|
|
callee_stack.add_var(var_id, Value::Nothing { span: call.head })
|
|
|
|
}
|
2021-10-13 17:53:27 +00:00
|
|
|
}
|
2021-10-12 04:49:17 +00:00
|
|
|
}
|
2021-10-11 21:17:45 +00:00
|
|
|
}
|
2022-02-04 18:02:03 +00:00
|
|
|
|
2022-03-02 12:52:24 +00:00
|
|
|
let result = eval_block(
|
|
|
|
engine_state,
|
|
|
|
&mut callee_stack,
|
|
|
|
block,
|
|
|
|
input,
|
|
|
|
call.redirect_stdout,
|
|
|
|
call.redirect_stderr,
|
|
|
|
);
|
2022-02-04 18:02:03 +00:00
|
|
|
|
2022-01-29 20:45:46 +00:00
|
|
|
if block.redirect_env {
|
2022-08-18 20:24:39 +00:00
|
|
|
redirect_env(engine_state, caller_stack, &callee_stack);
|
2022-01-29 20:45:46 +00:00
|
|
|
}
|
2022-02-04 18:02:03 +00:00
|
|
|
|
2022-01-29 20:45:46 +00:00
|
|
|
result
|
2021-07-29 22:56:51 +00:00
|
|
|
} else {
|
2021-12-25 19:39:42 +00:00
|
|
|
// We pass caller_stack here with the knowledge that internal commands
|
|
|
|
// are going to be specifically looking for global state in the stack
|
|
|
|
// rather than any local state.
|
|
|
|
decl.run(engine_state, caller_stack, call, input)
|
2021-07-16 01:10:22 +00:00
|
|
|
}
|
2021-07-23 05:14:49 +00:00
|
|
|
}
|
2021-07-16 01:10:22 +00:00
|
|
|
|
2022-08-18 20:24:39 +00:00
|
|
|
/// Redirect the environment from callee to the caller.
|
|
|
|
pub fn redirect_env(engine_state: &EngineState, caller_stack: &mut Stack, callee_stack: &Stack) {
|
2022-08-31 20:32:56 +00:00
|
|
|
// Grab all environment variables from the callee
|
2022-08-18 20:24:39 +00:00
|
|
|
let caller_env_vars = caller_stack.get_env_var_names(engine_state);
|
|
|
|
|
|
|
|
// remove env vars that are present in the caller but not in the callee
|
|
|
|
// (the callee hid them)
|
|
|
|
for var in caller_env_vars.iter() {
|
|
|
|
if !callee_stack.has_env_var(engine_state, var) {
|
|
|
|
caller_stack.remove_env_var(engine_state, var);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add new env vars from callee to caller
|
|
|
|
for (var, value) in callee_stack.get_stack_env_vars() {
|
|
|
|
caller_stack.add_env_var(var, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-20 12:44:42 +00:00
|
|
|
/// Eval extarnal expression
|
|
|
|
///
|
|
|
|
/// It returns PipelineData with a boolean flag, indicate that if the external runs to failed.
|
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.
2022-11-23 03:51:57 +00:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2021-09-19 21:48:33 +00:00
|
|
|
fn eval_external(
|
2021-10-25 06:31:39 +00:00
|
|
|
engine_state: &EngineState,
|
|
|
|
stack: &mut Stack,
|
2022-01-13 08:17:45 +00:00
|
|
|
head: &Expression,
|
2021-10-08 21:51:47 +00:00
|
|
|
args: &[Expression],
|
2021-10-25 04:01:02 +00:00
|
|
|
input: PipelineData,
|
2022-02-21 22:22:21 +00:00
|
|
|
redirect_stdout: bool,
|
|
|
|
redirect_stderr: bool,
|
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.
2022-11-23 03:51:57 +00:00
|
|
|
is_subexpression: bool,
|
2022-09-30 12:13:46 +00:00
|
|
|
) -> Result<PipelineData, ShellError> {
|
2021-10-25 06:31:39 +00:00
|
|
|
let decl_id = engine_state
|
2022-05-07 19:39:22 +00:00
|
|
|
.find_decl("run-external".as_bytes(), &[])
|
2022-01-13 08:17:45 +00:00
|
|
|
.ok_or(ShellError::ExternalNotSupported(head.span))?;
|
2021-09-19 21:48:33 +00:00
|
|
|
|
2021-10-25 06:31:39 +00:00
|
|
|
let command = engine_state.get_decl(decl_id);
|
2021-09-19 21:48:33 +00:00
|
|
|
|
2022-02-04 02:01:45 +00:00
|
|
|
let mut call = Call::new(head.span);
|
2021-10-08 21:51:47 +00:00
|
|
|
|
2022-04-09 02:55:02 +00:00
|
|
|
call.add_positional(head.clone());
|
2021-10-08 21:51:47 +00:00
|
|
|
|
|
|
|
for arg in args {
|
2022-04-09 02:55:02 +00:00
|
|
|
call.add_positional(arg.clone())
|
2021-10-08 21:51:47 +00:00
|
|
|
}
|
2021-09-19 21:48:33 +00:00
|
|
|
|
2022-02-21 22:22:21 +00:00
|
|
|
if redirect_stdout {
|
2022-04-09 02:55:02 +00:00
|
|
|
call.add_named((
|
2021-10-11 21:17:45 +00:00
|
|
|
Spanned {
|
2022-02-21 22:22:21 +00:00
|
|
|
item: "redirect-stdout".into(),
|
|
|
|
span: head.span,
|
|
|
|
},
|
|
|
|
None,
|
2022-04-09 05:17:48 +00:00
|
|
|
None,
|
2022-02-21 22:22:21 +00:00
|
|
|
))
|
|
|
|
}
|
|
|
|
|
|
|
|
if redirect_stderr {
|
2022-04-09 02:55:02 +00:00
|
|
|
call.add_named((
|
2022-02-21 22:22:21 +00:00
|
|
|
Spanned {
|
|
|
|
item: "redirect-stderr".into(),
|
2022-01-13 08:17:45 +00:00
|
|
|
span: head.span,
|
2021-10-11 21:17:45 +00:00
|
|
|
},
|
|
|
|
None,
|
2022-04-09 05:17:48 +00:00
|
|
|
None,
|
2021-10-11 21:17:45 +00:00
|
|
|
))
|
2021-09-23 16:42:03 +00: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.
2022-11-23 03:51:57 +00:00
|
|
|
if is_subexpression {
|
|
|
|
call.add_named((
|
|
|
|
Spanned {
|
|
|
|
item: "trim-end-newline".into(),
|
|
|
|
span: head.span,
|
|
|
|
},
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
2022-09-30 12:13:46 +00:00
|
|
|
command.run(engine_state, stack, &call, input)
|
2021-09-19 21:48:33 +00:00
|
|
|
}
|
|
|
|
|
2021-09-02 22:58:15 +00:00
|
|
|
pub fn eval_expression(
|
2021-10-25 06:31:39 +00:00
|
|
|
engine_state: &EngineState,
|
|
|
|
stack: &mut Stack,
|
2021-09-02 22:58:15 +00:00
|
|
|
expr: &Expression,
|
|
|
|
) -> Result<Value, ShellError> {
|
2021-07-23 05:14:49 +00:00
|
|
|
match &expr.expr {
|
2021-07-24 05:57:17 +00:00
|
|
|
Expr::Bool(b) => Ok(Value::Bool {
|
|
|
|
val: *b,
|
|
|
|
span: expr.span,
|
|
|
|
}),
|
2021-07-23 05:14:49 +00:00
|
|
|
Expr::Int(i) => Ok(Value::Int {
|
|
|
|
val: *i,
|
|
|
|
span: expr.span,
|
|
|
|
}),
|
2021-08-08 20:21:21 +00:00
|
|
|
Expr::Float(f) => Ok(Value::Float {
|
|
|
|
val: *f,
|
|
|
|
span: expr.span,
|
|
|
|
}),
|
2022-02-28 23:31:53 +00:00
|
|
|
Expr::Binary(b) => Ok(Value::Binary {
|
|
|
|
val: b.clone(),
|
|
|
|
span: expr.span,
|
|
|
|
}),
|
2021-10-25 06:31:39 +00:00
|
|
|
Expr::ValueWithUnit(e, unit) => match eval_expression(engine_state, stack, e)? {
|
2021-10-05 02:27:39 +00:00
|
|
|
Value::Int { val, .. } => Ok(compute(val, unit.item, unit.span)),
|
2021-11-06 05:50:33 +00:00
|
|
|
x => Err(ShellError::CantConvert(
|
|
|
|
"unit value".into(),
|
|
|
|
x.get_type().to_string(),
|
|
|
|
e.span,
|
2022-04-18 12:34:10 +00:00
|
|
|
None,
|
2021-11-06 05:50:33 +00:00
|
|
|
)),
|
2021-10-05 02:27:39 +00:00
|
|
|
},
|
2021-09-11 11:13:04 +00:00
|
|
|
Expr::Range(from, next, to, operator) => {
|
2021-09-04 21:52:57 +00:00
|
|
|
let from = if let Some(f) = from {
|
2021-10-25 06:31:39 +00:00
|
|
|
eval_expression(engine_state, stack, f)?
|
2021-09-04 21:52:57 +00:00
|
|
|
} else {
|
2021-12-19 07:46:13 +00:00
|
|
|
Value::Nothing { span: expr.span }
|
2021-09-04 21:52:57 +00:00
|
|
|
};
|
|
|
|
|
2021-09-11 11:13:04 +00:00
|
|
|
let next = if let Some(s) = next {
|
2021-10-25 06:31:39 +00:00
|
|
|
eval_expression(engine_state, stack, s)?
|
2021-09-04 21:52:57 +00:00
|
|
|
} else {
|
2021-12-19 07:46:13 +00:00
|
|
|
Value::Nothing { span: expr.span }
|
2021-09-04 21:52:57 +00:00
|
|
|
};
|
|
|
|
|
2021-09-11 11:13:04 +00:00
|
|
|
let to = if let Some(t) = to {
|
2021-10-25 06:31:39 +00:00
|
|
|
eval_expression(engine_state, stack, t)?
|
2021-09-11 11:13:04 +00:00
|
|
|
} else {
|
2021-12-19 07:46:13 +00:00
|
|
|
Value::Nothing { span: expr.span }
|
2021-09-04 21:52:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(Value::Range {
|
2021-09-11 11:13:04 +00:00
|
|
|
val: Box::new(Range::new(expr.span, from, next, to, operator)?),
|
2021-09-04 21:52:57 +00:00
|
|
|
span: expr.span,
|
|
|
|
})
|
|
|
|
}
|
2021-10-29 18:15:17 +00:00
|
|
|
Expr::Var(var_id) => eval_variable(engine_state, stack, *var_id, expr.span),
|
2021-10-25 20:04:23 +00:00
|
|
|
Expr::VarDecl(_) => Ok(Value::Nothing { span: expr.span }),
|
2021-10-02 02:59:11 +00:00
|
|
|
Expr::CellPath(cell_path) => Ok(Value::CellPath {
|
|
|
|
val: cell_path.clone(),
|
|
|
|
span: expr.span,
|
|
|
|
}),
|
2021-09-26 18:39:19 +00:00
|
|
|
Expr::FullCellPath(cell_path) => {
|
2021-10-25 06:31:39 +00:00
|
|
|
let value = eval_expression(engine_state, stack, &cell_path.head)?;
|
2021-09-06 22:02:24 +00:00
|
|
|
|
2022-06-01 13:34:42 +00:00
|
|
|
value.follow_cell_path(&cell_path.tail, false)
|
2021-09-06 22:02:24 +00:00
|
|
|
}
|
2021-12-19 07:46:13 +00:00
|
|
|
Expr::ImportPattern(_) => Ok(Value::Nothing { span: expr.span }),
|
2022-09-04 15:36:42 +00:00
|
|
|
Expr::Overlay(_) => {
|
|
|
|
let name =
|
|
|
|
String::from_utf8_lossy(engine_state.get_span_contents(&expr.span)).to_string();
|
|
|
|
|
|
|
|
Ok(Value::String {
|
|
|
|
val: name,
|
|
|
|
span: expr.span,
|
|
|
|
})
|
|
|
|
}
|
2021-10-25 04:01:02 +00:00
|
|
|
Expr::Call(call) => {
|
|
|
|
// FIXME: protect this collect with ctrl-c
|
2021-11-06 05:50:33 +00:00
|
|
|
Ok(
|
|
|
|
eval_call(engine_state, stack, call, PipelineData::new(call.head))?
|
|
|
|
.into_value(call.head),
|
|
|
|
)
|
2021-10-25 04:01:02 +00: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.
2022-11-23 03:51:57 +00:00
|
|
|
Expr::ExternalCall(head, args, is_subexpression) => {
|
2022-01-13 08:17:45 +00:00
|
|
|
let span = head.span;
|
2021-10-25 04:01:02 +00:00
|
|
|
// FIXME: protect this collect with ctrl-c
|
2021-10-25 21:14:21 +00:00
|
|
|
Ok(eval_external(
|
|
|
|
engine_state,
|
|
|
|
stack,
|
2022-01-13 08:17:45 +00:00
|
|
|
head,
|
2021-10-25 21:14:21 +00:00
|
|
|
args,
|
2022-01-13 08:17:45 +00:00
|
|
|
PipelineData::new(span),
|
2021-12-27 14:58:53 +00:00
|
|
|
false,
|
2022-02-21 22:22:21 +00:00
|
|
|
false,
|
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.
2022-11-23 03:51:57 +00:00
|
|
|
*is_subexpression,
|
2021-10-25 21:14:21 +00:00
|
|
|
)?
|
2022-01-13 08:17:45 +00:00
|
|
|
.into_value(span))
|
2021-09-23 16:42:03 +00:00
|
|
|
}
|
2022-02-24 02:02:48 +00:00
|
|
|
Expr::DateTime(dt) => Ok(Value::Date {
|
|
|
|
val: *dt,
|
|
|
|
span: expr.span,
|
|
|
|
}),
|
2021-08-08 21:02:47 +00:00
|
|
|
Expr::Operator(_) => Ok(Value::Nothing { span: expr.span }),
|
2022-04-06 19:10:25 +00:00
|
|
|
Expr::UnaryNot(expr) => {
|
|
|
|
let lhs = eval_expression(engine_state, stack, expr)?;
|
|
|
|
match lhs {
|
|
|
|
Value::Bool { val, .. } => Ok(Value::Bool {
|
|
|
|
val: !val,
|
|
|
|
span: expr.span,
|
|
|
|
}),
|
|
|
|
_ => Err(ShellError::TypeMismatch("bool".to_string(), expr.span)),
|
|
|
|
}
|
|
|
|
}
|
2021-07-23 05:14:49 +00:00
|
|
|
Expr::BinaryOp(lhs, op, rhs) => {
|
2021-08-10 06:31:34 +00:00
|
|
|
let op_span = op.span;
|
2021-08-15 22:33:34 +00:00
|
|
|
let op = eval_operator(op)?;
|
2021-07-23 05:14:49 +00:00
|
|
|
|
|
|
|
match op {
|
2022-11-11 06:51:08 +00:00
|
|
|
Operator::Boolean(boolean) => {
|
|
|
|
let lhs = eval_expression(engine_state, stack, lhs)?;
|
|
|
|
match boolean {
|
|
|
|
Boolean::And => {
|
|
|
|
if lhs.is_false() {
|
|
|
|
Ok(Value::Bool {
|
|
|
|
val: false,
|
|
|
|
span: expr.span,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
let rhs = eval_expression(engine_state, stack, rhs)?;
|
|
|
|
lhs.and(op_span, &rhs, expr.span)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Boolean::Or => {
|
|
|
|
if lhs.is_true() {
|
|
|
|
Ok(Value::Bool {
|
|
|
|
val: true,
|
|
|
|
span: expr.span,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
let rhs = eval_expression(engine_state, stack, rhs)?;
|
|
|
|
lhs.or(op_span, &rhs, expr.span)
|
|
|
|
}
|
|
|
|
}
|
2022-02-27 22:02:53 +00:00
|
|
|
}
|
|
|
|
}
|
2022-11-11 06:51:08 +00:00
|
|
|
Operator::Math(math) => {
|
|
|
|
let lhs = eval_expression(engine_state, stack, lhs)?;
|
2022-02-27 22:02:53 +00:00
|
|
|
let rhs = eval_expression(engine_state, stack, rhs)?;
|
2022-11-11 06:51:08 +00:00
|
|
|
|
|
|
|
match math {
|
|
|
|
Math::Plus => lhs.add(op_span, &rhs, expr.span),
|
|
|
|
Math::Minus => lhs.sub(op_span, &rhs, expr.span),
|
|
|
|
Math::Multiply => lhs.mul(op_span, &rhs, expr.span),
|
|
|
|
Math::Divide => lhs.div(op_span, &rhs, expr.span),
|
|
|
|
Math::Append => lhs.append(op_span, &rhs, expr.span),
|
|
|
|
Math::Modulo => lhs.modulo(op_span, &rhs, expr.span),
|
|
|
|
Math::FloorDivision => lhs.floor_div(op_span, &rhs, expr.span),
|
|
|
|
Math::Pow => lhs.pow(op_span, &rhs, expr.span),
|
|
|
|
}
|
2022-07-03 11:45:20 +00:00
|
|
|
}
|
2022-11-11 06:51:08 +00:00
|
|
|
Operator::Comparison(comparison) => {
|
|
|
|
let lhs = eval_expression(engine_state, stack, lhs)?;
|
2022-07-02 18:03:36 +00:00
|
|
|
let rhs = eval_expression(engine_state, stack, rhs)?;
|
2022-11-11 06:51:08 +00:00
|
|
|
match comparison {
|
|
|
|
Comparison::LessThan => lhs.lt(op_span, &rhs, expr.span),
|
|
|
|
Comparison::LessThanOrEqual => lhs.lte(op_span, &rhs, expr.span),
|
|
|
|
Comparison::GreaterThan => lhs.gt(op_span, &rhs, expr.span),
|
|
|
|
Comparison::GreaterThanOrEqual => lhs.gte(op_span, &rhs, expr.span),
|
|
|
|
Comparison::Equal => lhs.eq(op_span, &rhs, expr.span),
|
|
|
|
Comparison::NotEqual => lhs.ne(op_span, &rhs, expr.span),
|
|
|
|
Comparison::In => lhs.r#in(op_span, &rhs, expr.span),
|
|
|
|
Comparison::NotIn => lhs.not_in(op_span, &rhs, expr.span),
|
|
|
|
Comparison::RegexMatch => lhs.regex_match(op_span, &rhs, false, expr.span),
|
|
|
|
Comparison::NotRegexMatch => {
|
|
|
|
lhs.regex_match(op_span, &rhs, true, expr.span)
|
|
|
|
}
|
|
|
|
Comparison::StartsWith => lhs.starts_with(op_span, &rhs, expr.span),
|
|
|
|
Comparison::EndsWith => lhs.ends_with(op_span, &rhs, expr.span),
|
|
|
|
}
|
2022-07-02 18:03:36 +00:00
|
|
|
}
|
2022-11-11 06:51:08 +00:00
|
|
|
Operator::Bits(bits) => {
|
|
|
|
let lhs = eval_expression(engine_state, stack, lhs)?;
|
2022-07-02 11:48:43 +00:00
|
|
|
let rhs = eval_expression(engine_state, stack, rhs)?;
|
2022-11-11 06:51:08 +00:00
|
|
|
match bits {
|
|
|
|
Bits::BitAnd => lhs.bit_and(op_span, &rhs, expr.span),
|
|
|
|
Bits::BitOr => lhs.bit_or(op_span, &rhs, expr.span),
|
|
|
|
Bits::BitXor => lhs.bit_xor(op_span, &rhs, expr.span),
|
|
|
|
Bits::ShiftLeft => lhs.bit_shl(op_span, &rhs, expr.span),
|
|
|
|
Bits::ShiftRight => lhs.bit_shr(op_span, &rhs, expr.span),
|
|
|
|
}
|
2022-07-02 11:48:43 +00:00
|
|
|
}
|
2022-11-11 18:50:43 +00:00
|
|
|
Operator::Assignment(assignment) => {
|
2022-07-02 11:48:43 +00:00
|
|
|
let rhs = eval_expression(engine_state, stack, rhs)?;
|
2022-11-11 06:51:08 +00:00
|
|
|
|
2022-11-11 18:50:43 +00:00
|
|
|
let rhs = match assignment {
|
|
|
|
Assignment::Assign => rhs,
|
|
|
|
Assignment::PlusAssign => {
|
|
|
|
let lhs = eval_expression(engine_state, stack, lhs)?;
|
|
|
|
lhs.add(op_span, &rhs, op_span)?
|
|
|
|
}
|
|
|
|
Assignment::MinusAssign => {
|
|
|
|
let lhs = eval_expression(engine_state, stack, lhs)?;
|
|
|
|
lhs.sub(op_span, &rhs, op_span)?
|
|
|
|
}
|
|
|
|
Assignment::MultiplyAssign => {
|
|
|
|
let lhs = eval_expression(engine_state, stack, lhs)?;
|
|
|
|
lhs.mul(op_span, &rhs, op_span)?
|
|
|
|
}
|
|
|
|
Assignment::DivideAssign => {
|
|
|
|
let lhs = eval_expression(engine_state, stack, lhs)?;
|
|
|
|
lhs.div(op_span, &rhs, op_span)?
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-11-11 06:51:08 +00:00
|
|
|
match &lhs.expr {
|
|
|
|
Expr::Var(var_id) | Expr::VarDecl(var_id) => {
|
|
|
|
let var_info = engine_state.get_var(*var_id);
|
|
|
|
if var_info.mutable {
|
|
|
|
stack.vars.insert(*var_id, rhs);
|
|
|
|
Ok(Value::nothing(lhs.span))
|
|
|
|
} else {
|
|
|
|
Err(ShellError::AssignmentRequiresMutableVar(lhs.span))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Expr::FullCellPath(cell_path) => match &cell_path.head.expr {
|
|
|
|
Expr::Var(var_id) | Expr::VarDecl(var_id) => {
|
2022-11-11 07:16:07 +00:00
|
|
|
if var_id == &ENV_VARIABLE_ID {
|
|
|
|
// let mut lhs =
|
|
|
|
// eval_expression(engine_state, stack, &cell_path.head)?;
|
|
|
|
//lhs.update_data_at_cell_path(&cell_path.tail, rhs)?;
|
|
|
|
match &cell_path.tail[0] {
|
|
|
|
PathMember::String { val, .. } => {
|
|
|
|
stack.add_env_var(val.to_string(), rhs);
|
|
|
|
}
|
|
|
|
PathMember::Int { val, .. } => {
|
|
|
|
stack.add_env_var(val.to_string(), rhs);
|
|
|
|
}
|
|
|
|
}
|
2022-11-11 06:51:08 +00:00
|
|
|
Ok(Value::nothing(cell_path.head.span))
|
|
|
|
} else {
|
2022-11-11 07:16:07 +00:00
|
|
|
let var_info = engine_state.get_var(*var_id);
|
|
|
|
if var_info.mutable {
|
|
|
|
let mut lhs =
|
|
|
|
eval_expression(engine_state, stack, &cell_path.head)?;
|
|
|
|
lhs.update_data_at_cell_path(&cell_path.tail, rhs)?;
|
|
|
|
stack.vars.insert(*var_id, lhs);
|
|
|
|
Ok(Value::nothing(cell_path.head.span))
|
|
|
|
} else {
|
|
|
|
Err(ShellError::AssignmentRequiresMutableVar(lhs.span))
|
|
|
|
}
|
2022-11-11 06:51:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => Err(ShellError::AssignmentRequiresVar(lhs.span)),
|
|
|
|
},
|
|
|
|
_ => Err(ShellError::AssignmentRequiresVar(lhs.span)),
|
|
|
|
}
|
2022-07-02 11:48:43 +00:00
|
|
|
}
|
2021-07-23 05:14:49 +00:00
|
|
|
}
|
2021-07-16 01:10:22 +00:00
|
|
|
}
|
2022-01-12 04:06:56 +00:00
|
|
|
Expr::Subexpression(block_id) => {
|
2021-10-25 06:31:39 +00:00
|
|
|
let block = engine_state.get_block(*block_id);
|
2021-07-23 05:14:49 +00:00
|
|
|
|
2021-10-25 04:01:02 +00:00
|
|
|
// FIXME: protect this collect with ctrl-c
|
2021-11-06 05:50:33 +00:00
|
|
|
Ok(
|
|
|
|
eval_subexpression(engine_state, stack, block, PipelineData::new(expr.span))?
|
|
|
|
.into_value(expr.span),
|
|
|
|
)
|
2021-07-23 05:14:49 +00:00
|
|
|
}
|
2022-11-10 08:21:49 +00:00
|
|
|
Expr::RowCondition(block_id) | Expr::Closure(block_id) => {
|
2022-01-12 04:06:56 +00:00
|
|
|
let mut captures = HashMap::new();
|
|
|
|
let block = engine_state.get_block(*block_id);
|
|
|
|
|
|
|
|
for var_id in &block.captures {
|
2022-01-29 13:00:48 +00:00
|
|
|
captures.insert(*var_id, stack.get_var(*var_id, expr.span)?);
|
2022-01-12 04:06:56 +00:00
|
|
|
}
|
2022-11-10 08:21:49 +00:00
|
|
|
Ok(Value::Closure {
|
2022-01-12 04:06:56 +00:00
|
|
|
val: *block_id,
|
|
|
|
captures,
|
|
|
|
span: expr.span,
|
|
|
|
})
|
|
|
|
}
|
2022-11-10 08:21:49 +00:00
|
|
|
Expr::Block(block_id) => Ok(Value::Block {
|
|
|
|
val: *block_id,
|
|
|
|
span: expr.span,
|
|
|
|
}),
|
2021-07-23 21:19:30 +00:00
|
|
|
Expr::List(x) => {
|
|
|
|
let mut output = vec![];
|
|
|
|
for expr in x {
|
2021-10-25 06:31:39 +00:00
|
|
|
output.push(eval_expression(engine_state, stack, expr)?);
|
2021-07-23 21:19:30 +00:00
|
|
|
}
|
2021-08-08 21:02:47 +00:00
|
|
|
Ok(Value::List {
|
2021-09-07 07:07:11 +00:00
|
|
|
vals: output,
|
2021-08-08 21:02:47 +00:00
|
|
|
span: expr.span,
|
|
|
|
})
|
2021-07-23 21:19:30 +00:00
|
|
|
}
|
2021-11-10 23:14:00 +00:00
|
|
|
Expr::Record(fields) => {
|
|
|
|
let mut cols = vec![];
|
|
|
|
let mut vals = vec![];
|
|
|
|
for (col, val) in fields {
|
2022-05-26 00:10:31 +00:00
|
|
|
// avoid duplicate cols.
|
|
|
|
let col_name = eval_expression(engine_state, stack, col)?.as_string()?;
|
|
|
|
let pos = cols.iter().position(|c| c == &col_name);
|
|
|
|
match pos {
|
|
|
|
Some(index) => {
|
|
|
|
vals[index] = eval_expression(engine_state, stack, val)?;
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
cols.push(col_name);
|
|
|
|
vals.push(eval_expression(engine_state, stack, val)?);
|
|
|
|
}
|
|
|
|
}
|
2021-11-10 23:14:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Value::Record {
|
|
|
|
cols,
|
|
|
|
vals,
|
|
|
|
span: expr.span,
|
|
|
|
})
|
|
|
|
}
|
2021-08-28 19:17:30 +00:00
|
|
|
Expr::Table(headers, vals) => {
|
|
|
|
let mut output_headers = vec![];
|
|
|
|
for expr in headers {
|
2021-10-25 06:31:39 +00:00
|
|
|
output_headers.push(eval_expression(engine_state, stack, expr)?.as_string()?);
|
2021-08-28 19:17:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut output_rows = vec![];
|
|
|
|
for val in vals {
|
|
|
|
let mut row = vec![];
|
|
|
|
for expr in val {
|
2021-10-25 06:31:39 +00:00
|
|
|
row.push(eval_expression(engine_state, stack, expr)?);
|
2021-08-28 19:17:30 +00:00
|
|
|
}
|
2021-09-07 07:07:11 +00:00
|
|
|
output_rows.push(Value::Record {
|
|
|
|
cols: output_headers.clone(),
|
|
|
|
vals: row,
|
|
|
|
span: expr.span,
|
|
|
|
});
|
2021-08-28 19:17:30 +00:00
|
|
|
}
|
2021-09-07 07:07:11 +00:00
|
|
|
Ok(Value::List {
|
|
|
|
vals: output_rows,
|
2021-08-28 19:17:30 +00:00
|
|
|
span: expr.span,
|
|
|
|
})
|
|
|
|
}
|
2021-10-25 06:31:39 +00:00
|
|
|
Expr::Keyword(_, _, expr) => eval_expression(engine_state, stack, expr),
|
2021-12-25 20:50:02 +00:00
|
|
|
Expr::StringInterpolation(exprs) => {
|
|
|
|
let mut parts = vec![];
|
|
|
|
for expr in exprs {
|
|
|
|
parts.push(eval_expression(engine_state, stack, expr)?);
|
|
|
|
}
|
|
|
|
|
2022-04-18 22:28:01 +00:00
|
|
|
let config = engine_state.get_config();
|
2021-12-25 20:50:02 +00:00
|
|
|
|
|
|
|
parts
|
|
|
|
.into_iter()
|
|
|
|
.into_pipeline_data(None)
|
2022-04-18 22:28:01 +00:00
|
|
|
.collect_string("", config)
|
2021-12-25 20:50:02 +00:00
|
|
|
.map(|x| Value::String {
|
|
|
|
val: x,
|
|
|
|
span: expr.span,
|
|
|
|
})
|
|
|
|
}
|
2021-07-23 21:19:30 +00:00
|
|
|
Expr::String(s) => Ok(Value::String {
|
|
|
|
val: s.clone(),
|
|
|
|
span: expr.span,
|
|
|
|
}),
|
2022-01-16 13:55:56 +00:00
|
|
|
Expr::Filepath(s) => {
|
|
|
|
let cwd = current_dir_str(engine_state, stack)?;
|
|
|
|
let path = expand_path_with(s, cwd);
|
|
|
|
|
|
|
|
Ok(Value::String {
|
|
|
|
val: path.to_string_lossy().to_string(),
|
|
|
|
span: expr.span,
|
|
|
|
})
|
|
|
|
}
|
2022-04-22 20:18:51 +00:00
|
|
|
Expr::Directory(s) => {
|
2022-04-22 23:48:10 +00:00
|
|
|
if s == "-" {
|
|
|
|
Ok(Value::String {
|
|
|
|
val: "-".to_string(),
|
|
|
|
span: expr.span,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
let cwd = current_dir_str(engine_state, stack)?;
|
|
|
|
let path = expand_path_with(s, cwd);
|
2022-04-22 20:18:51 +00:00
|
|
|
|
2022-04-22 23:48:10 +00:00
|
|
|
Ok(Value::String {
|
|
|
|
val: path.to_string_lossy().to_string(),
|
|
|
|
span: expr.span,
|
|
|
|
})
|
|
|
|
}
|
2022-04-22 20:18:51 +00:00
|
|
|
}
|
2022-01-16 13:55:56 +00:00
|
|
|
Expr::GlobPattern(s) => {
|
|
|
|
let cwd = current_dir_str(engine_state, stack)?;
|
|
|
|
let path = expand_path_with(s, cwd);
|
|
|
|
|
|
|
|
Ok(Value::String {
|
|
|
|
val: path.to_string_lossy().to_string(),
|
|
|
|
span: expr.span,
|
|
|
|
})
|
|
|
|
}
|
2021-08-08 21:02:47 +00:00
|
|
|
Expr::Signature(_) => Ok(Value::Nothing { span: expr.span }),
|
|
|
|
Expr::Garbage => Ok(Value::Nothing { span: expr.span }),
|
2021-12-20 01:05:33 +00:00
|
|
|
Expr::Nothing => Ok(Value::Nothing { span: expr.span }),
|
2021-07-16 01:10:22 +00:00
|
|
|
}
|
2021-07-23 05:14:49 +00:00
|
|
|
}
|
|
|
|
|
2022-01-26 19:00:25 +00:00
|
|
|
/// Checks the expression to see if it's a internal or external call. If so, passes the input
|
|
|
|
/// into the call and gets out the result
|
|
|
|
/// Otherwise, invokes the expression
|
2022-07-20 12:44:42 +00:00
|
|
|
///
|
|
|
|
/// It returns PipelineData with a boolean flag, indicate that if the external runs to failed.
|
|
|
|
/// The boolean flag **may only be true** for external calls, for internal calls, it always to be false.
|
2022-01-26 19:00:25 +00:00
|
|
|
pub fn eval_expression_with_input(
|
|
|
|
engine_state: &EngineState,
|
|
|
|
stack: &mut Stack,
|
|
|
|
expr: &Expression,
|
|
|
|
mut input: PipelineData,
|
2022-02-21 22:22:21 +00:00
|
|
|
redirect_stdout: bool,
|
|
|
|
redirect_stderr: bool,
|
2022-07-20 12:44:42 +00:00
|
|
|
) -> Result<(PipelineData, bool), ShellError> {
|
2022-01-26 19:00:25 +00:00
|
|
|
match expr {
|
|
|
|
Expression {
|
|
|
|
expr: Expr::Call(call),
|
|
|
|
..
|
|
|
|
} => {
|
2022-02-21 22:22:21 +00:00
|
|
|
if !redirect_stdout || redirect_stderr {
|
|
|
|
// we're doing something different than the defaults
|
|
|
|
let mut call = call.clone();
|
|
|
|
call.redirect_stdout = redirect_stdout;
|
|
|
|
call.redirect_stderr = redirect_stderr;
|
|
|
|
input = eval_call(engine_state, stack, &call, input)?;
|
|
|
|
} else {
|
|
|
|
input = eval_call(engine_state, stack, call, input)?;
|
|
|
|
}
|
2022-01-26 19:00:25 +00:00
|
|
|
}
|
|
|
|
Expression {
|
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.
2022-11-23 03:51:57 +00:00
|
|
|
expr: Expr::ExternalCall(head, args, is_subexpression),
|
2022-01-26 19:00:25 +00:00
|
|
|
..
|
|
|
|
} => {
|
2022-09-30 12:13:46 +00:00
|
|
|
input = eval_external(
|
2022-02-21 22:22:21 +00:00
|
|
|
engine_state,
|
|
|
|
stack,
|
|
|
|
head,
|
|
|
|
args,
|
|
|
|
input,
|
|
|
|
redirect_stdout,
|
|
|
|
redirect_stderr,
|
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.
2022-11-23 03:51:57 +00:00
|
|
|
*is_subexpression,
|
2022-02-21 22:22:21 +00:00
|
|
|
)?;
|
2022-01-26 19:00:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Expression {
|
|
|
|
expr: Expr::Subexpression(block_id),
|
|
|
|
..
|
|
|
|
} => {
|
|
|
|
let block = engine_state.get_block(*block_id);
|
|
|
|
|
|
|
|
// FIXME: protect this collect with ctrl-c
|
|
|
|
input = eval_subexpression(engine_state, stack, block, input)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
elem => {
|
|
|
|
input = eval_expression(engine_state, stack, elem)?.into_pipeline_data();
|
|
|
|
}
|
2022-09-30 12:13:46 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(might_consume_external_result(input))
|
|
|
|
}
|
2022-01-26 19:00:25 +00:00
|
|
|
|
2022-09-30 12:13:46 +00:00
|
|
|
// if the result is ExternalStream without redirecting output.
|
|
|
|
// that indicates we have no more commands to execute currently.
|
|
|
|
// we can try to catch and detect if external command runs to failed.
|
|
|
|
//
|
|
|
|
// This is useful to commands with semicolon, we can detect errors early to avoid
|
|
|
|
// commands after semicolon running.
|
|
|
|
fn might_consume_external_result(input: PipelineData) -> (PipelineData, bool) {
|
|
|
|
let mut runs_to_failed = false;
|
|
|
|
if let PipelineData::ExternalStream {
|
|
|
|
stdout: None,
|
|
|
|
stderr,
|
|
|
|
mut exit_code,
|
|
|
|
span,
|
|
|
|
metadata,
|
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.
2022-11-23 03:51:57 +00:00
|
|
|
trim_end_newline,
|
2022-09-30 12:13:46 +00:00
|
|
|
} = input
|
|
|
|
{
|
|
|
|
let exit_code = exit_code.take();
|
2022-10-12 13:41:20 +00:00
|
|
|
|
|
|
|
// Note:
|
|
|
|
// In run-external's implementation detail, the result sender thread
|
|
|
|
// send out stderr message first, then stdout message, then exit_code.
|
|
|
|
//
|
|
|
|
// In this clause, we already make sure that `stdout` is None
|
|
|
|
// But not the case of `stderr`, so if `stderr` is not None
|
|
|
|
// We need to consume stderr message before reading external commands' exit code.
|
|
|
|
//
|
|
|
|
// Or we'll never have a chance to read exit_code if stderr producer produce too much stderr message.
|
|
|
|
// So we consume stderr stream and rebuild it.
|
|
|
|
let stderr = stderr.map(|stderr_stream| {
|
|
|
|
let stderr_ctrlc = stderr_stream.ctrlc.clone();
|
|
|
|
let stderr_span = stderr_stream.span;
|
|
|
|
let stderr_bytes = match stderr_stream.into_bytes() {
|
|
|
|
Err(_) => vec![],
|
|
|
|
Ok(bytes) => bytes.item,
|
|
|
|
};
|
|
|
|
RawStream::new(
|
|
|
|
Box::new(vec![Ok(stderr_bytes)].into_iter()),
|
|
|
|
stderr_ctrlc,
|
|
|
|
stderr_span,
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
2022-09-30 12:13:46 +00:00
|
|
|
match exit_code {
|
|
|
|
Some(exit_code_stream) => {
|
|
|
|
let ctrlc = exit_code_stream.ctrlc.clone();
|
|
|
|
let exit_code: Vec<Value> = exit_code_stream.into_iter().collect();
|
|
|
|
if let Some(Value::Int { val: code, .. }) = exit_code.last() {
|
|
|
|
// if exit_code is not 0, it indicates error occured, return back Err.
|
|
|
|
if *code != 0 {
|
|
|
|
runs_to_failed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(
|
|
|
|
PipelineData::ExternalStream {
|
|
|
|
stdout: None,
|
|
|
|
stderr,
|
|
|
|
exit_code: Some(ListStream::from_stream(exit_code.into_iter(), ctrlc)),
|
|
|
|
span,
|
|
|
|
metadata,
|
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.
2022-11-23 03:51:57 +00:00
|
|
|
trim_end_newline,
|
2022-09-30 12:13:46 +00:00
|
|
|
},
|
|
|
|
runs_to_failed,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
None => (
|
|
|
|
PipelineData::ExternalStream {
|
|
|
|
stdout: None,
|
|
|
|
stderr,
|
|
|
|
exit_code: None,
|
|
|
|
span,
|
|
|
|
metadata,
|
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.
2022-11-23 03:51:57 +00:00
|
|
|
trim_end_newline,
|
2022-09-30 12:13:46 +00:00
|
|
|
},
|
|
|
|
runs_to_failed,
|
|
|
|
),
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
(input, false)
|
|
|
|
}
|
2022-01-26 19:00:25 +00:00
|
|
|
}
|
|
|
|
|
2022-11-18 21:46:48 +00:00
|
|
|
pub fn eval_element_with_input(
|
|
|
|
engine_state: &EngineState,
|
|
|
|
stack: &mut Stack,
|
|
|
|
element: &PipelineElement,
|
|
|
|
input: PipelineData,
|
|
|
|
redirect_stdout: bool,
|
|
|
|
redirect_stderr: bool,
|
|
|
|
) -> Result<(PipelineData, bool), ShellError> {
|
|
|
|
match element {
|
2022-11-22 18:26:13 +00:00
|
|
|
PipelineElement::Expression(_, expr) => eval_expression_with_input(
|
2022-11-18 21:46:48 +00:00
|
|
|
engine_state,
|
|
|
|
stack,
|
|
|
|
expr,
|
|
|
|
input,
|
|
|
|
redirect_stdout,
|
|
|
|
redirect_stderr,
|
|
|
|
),
|
2022-11-22 18:26:13 +00:00
|
|
|
PipelineElement::Redirection(span, redirection, expr) => match &expr.expr {
|
|
|
|
Expr::String(_) => {
|
|
|
|
let input = match (redirection, input) {
|
|
|
|
(
|
|
|
|
Redirection::Stderr,
|
|
|
|
PipelineData::ExternalStream {
|
|
|
|
stderr,
|
|
|
|
exit_code,
|
|
|
|
span,
|
|
|
|
metadata,
|
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.
2022-11-23 03:51:57 +00:00
|
|
|
trim_end_newline,
|
2022-11-22 18:26:13 +00:00
|
|
|
..
|
|
|
|
},
|
|
|
|
) => PipelineData::ExternalStream {
|
|
|
|
stdout: stderr,
|
|
|
|
stderr: None,
|
|
|
|
exit_code,
|
|
|
|
span,
|
|
|
|
metadata,
|
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.
2022-11-23 03:51:57 +00:00
|
|
|
trim_end_newline,
|
2022-11-22 18:26:13 +00:00
|
|
|
},
|
|
|
|
(
|
|
|
|
Redirection::StdoutAndStderr,
|
|
|
|
PipelineData::ExternalStream {
|
|
|
|
stdout,
|
|
|
|
stderr,
|
|
|
|
exit_code,
|
|
|
|
span,
|
|
|
|
metadata,
|
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.
2022-11-23 03:51:57 +00:00
|
|
|
trim_end_newline,
|
2022-11-22 18:26:13 +00:00
|
|
|
},
|
|
|
|
) => match (stdout, stderr) {
|
|
|
|
(Some(stdout), Some(stderr)) => PipelineData::ExternalStream {
|
|
|
|
stdout: Some(stdout.chain(stderr)),
|
|
|
|
stderr: None,
|
|
|
|
exit_code,
|
|
|
|
span,
|
|
|
|
metadata,
|
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.
2022-11-23 03:51:57 +00:00
|
|
|
trim_end_newline,
|
2022-11-22 18:26:13 +00:00
|
|
|
},
|
|
|
|
(None, Some(stderr)) => PipelineData::ExternalStream {
|
|
|
|
stdout: Some(stderr),
|
|
|
|
stderr: None,
|
|
|
|
exit_code,
|
|
|
|
span,
|
|
|
|
metadata,
|
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.
2022-11-23 03:51:57 +00:00
|
|
|
trim_end_newline,
|
2022-11-22 18:26:13 +00:00
|
|
|
},
|
|
|
|
(Some(stdout), None) => PipelineData::ExternalStream {
|
|
|
|
stdout: Some(stdout),
|
|
|
|
stderr: None,
|
|
|
|
exit_code,
|
|
|
|
span,
|
|
|
|
metadata,
|
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.
2022-11-23 03:51:57 +00:00
|
|
|
trim_end_newline,
|
2022-11-22 18:26:13 +00:00
|
|
|
},
|
|
|
|
(None, None) => PipelineData::ExternalStream {
|
|
|
|
stdout: None,
|
|
|
|
stderr: None,
|
|
|
|
exit_code,
|
|
|
|
span,
|
|
|
|
metadata,
|
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.
2022-11-23 03:51:57 +00:00
|
|
|
trim_end_newline,
|
2022-11-22 18:26:13 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
(_, input) => input,
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(save_command) = engine_state.find_decl(b"save", &[]) {
|
|
|
|
eval_call(
|
|
|
|
engine_state,
|
|
|
|
stack,
|
|
|
|
&Call {
|
|
|
|
decl_id: save_command,
|
|
|
|
head: *span,
|
|
|
|
arguments: vec![
|
|
|
|
Argument::Positional(expr.clone()),
|
|
|
|
Argument::Named((
|
|
|
|
Spanned {
|
|
|
|
item: "--raw".into(),
|
|
|
|
span: *span,
|
|
|
|
},
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
)),
|
|
|
|
],
|
|
|
|
redirect_stdout: false,
|
|
|
|
redirect_stderr: false,
|
|
|
|
},
|
|
|
|
input,
|
|
|
|
)
|
|
|
|
.map(|x| (x, false))
|
|
|
|
} else {
|
|
|
|
Err(ShellError::CommandNotFound(*span))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => Err(ShellError::CommandNotFound(*span)),
|
|
|
|
},
|
|
|
|
PipelineElement::And(_, expr) => eval_expression_with_input(
|
2022-11-18 21:46:48 +00:00
|
|
|
engine_state,
|
|
|
|
stack,
|
|
|
|
expr,
|
|
|
|
input,
|
|
|
|
redirect_stdout,
|
|
|
|
redirect_stderr,
|
|
|
|
),
|
2022-11-22 18:26:13 +00:00
|
|
|
PipelineElement::Or(_, expr) => eval_expression_with_input(
|
2022-11-18 21:46:48 +00:00
|
|
|
engine_state,
|
|
|
|
stack,
|
|
|
|
expr,
|
|
|
|
input,
|
|
|
|
redirect_stdout,
|
|
|
|
redirect_stderr,
|
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-03 02:15:01 +00:00
|
|
|
pub fn eval_block(
|
2021-10-25 06:31:39 +00:00
|
|
|
engine_state: &EngineState,
|
|
|
|
stack: &mut Stack,
|
2021-09-03 02:15:01 +00:00
|
|
|
block: &Block,
|
2021-10-25 04:01:02 +00:00
|
|
|
mut input: PipelineData,
|
2022-02-21 22:22:21 +00:00
|
|
|
redirect_stdout: bool,
|
|
|
|
redirect_stderr: bool,
|
2021-10-25 04:01:02 +00:00
|
|
|
) -> Result<PipelineData, ShellError> {
|
2022-02-15 19:31:14 +00:00
|
|
|
let num_pipelines = block.len();
|
|
|
|
for (pipeline_idx, pipeline) in block.pipelines.iter().enumerate() {
|
2022-11-22 18:26:13 +00:00
|
|
|
let mut i = 0;
|
|
|
|
|
|
|
|
while i < pipeline.elements.len() {
|
2022-07-20 12:44:42 +00:00
|
|
|
// if eval internal command failed, it can just make early return with `Err(ShellError)`.
|
2022-11-18 21:46:48 +00:00
|
|
|
let eval_result = eval_element_with_input(
|
2022-02-15 19:31:14 +00:00
|
|
|
engine_state,
|
|
|
|
stack,
|
2022-11-22 18:26:13 +00:00
|
|
|
&pipeline.elements[i],
|
2022-02-15 19:31:14 +00:00
|
|
|
input,
|
2022-11-23 02:18:34 +00:00
|
|
|
redirect_stdout
|
|
|
|
|| (i != pipeline.elements.len() - 1)
|
|
|
|
&& (matches!(
|
|
|
|
pipeline.elements[i + 1],
|
|
|
|
PipelineElement::Redirection(_, Redirection::Stdout, _)
|
|
|
|
| PipelineElement::Redirection(_, Redirection::StdoutAndStderr, _)
|
|
|
|
| PipelineElement::Expression(..)
|
|
|
|
)),
|
2022-11-22 18:26:13 +00:00
|
|
|
redirect_stderr
|
|
|
|
|| ((i < pipeline.elements.len() - 1)
|
|
|
|
&& (matches!(
|
|
|
|
pipeline.elements[i + 1],
|
|
|
|
PipelineElement::Redirection(_, Redirection::Stderr, _)
|
|
|
|
| PipelineElement::Redirection(_, Redirection::StdoutAndStderr, _)
|
|
|
|
))),
|
2022-07-20 12:44:42 +00:00
|
|
|
)?;
|
|
|
|
input = eval_result.0;
|
|
|
|
// external command may runs to failed
|
|
|
|
// make early return so remaining commands will not be executed.
|
|
|
|
// don't return `Err(ShellError)`, so nushell wouldn't show extra error message.
|
|
|
|
if eval_result.1 {
|
|
|
|
return Ok(input);
|
|
|
|
}
|
2022-11-22 18:26:13 +00:00
|
|
|
|
|
|
|
i += 1;
|
2021-11-06 05:50:33 +00:00
|
|
|
}
|
2022-02-06 02:03:06 +00:00
|
|
|
|
2022-02-15 19:31:14 +00:00
|
|
|
if pipeline_idx < (num_pipelines) - 1 {
|
2022-02-06 02:03:06 +00:00
|
|
|
match input {
|
|
|
|
PipelineData::Value(Value::Nothing { .. }, ..) => {}
|
2022-03-04 22:46:18 +00:00
|
|
|
PipelineData::ExternalStream {
|
|
|
|
ref mut exit_code, ..
|
|
|
|
} => {
|
|
|
|
let exit_code = exit_code.take();
|
|
|
|
|
|
|
|
// Drain the input to the screen via tabular output
|
2022-04-18 22:28:01 +00:00
|
|
|
let config = engine_state.get_config();
|
2022-03-04 22:46:18 +00:00
|
|
|
|
2022-05-07 19:39:22 +00:00
|
|
|
match engine_state.find_decl("table".as_bytes(), &[]) {
|
2022-03-04 22:46:18 +00:00
|
|
|
Some(decl_id) => {
|
|
|
|
let table = engine_state.get_decl(decl_id).run(
|
|
|
|
engine_state,
|
|
|
|
stack,
|
|
|
|
&Call::new(Span::new(0, 0)),
|
|
|
|
input,
|
|
|
|
)?;
|
|
|
|
|
2022-07-25 17:00:31 +00:00
|
|
|
print_or_return(table, config)?;
|
2022-03-04 22:46:18 +00:00
|
|
|
}
|
|
|
|
None => {
|
2022-07-25 17:00:31 +00:00
|
|
|
print_or_return(input, config)?;
|
2022-03-04 22:46:18 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(exit_code) = exit_code {
|
2022-08-31 23:09:40 +00:00
|
|
|
let mut v: Vec<_> = exit_code.collect();
|
2022-03-04 22:46:18 +00:00
|
|
|
|
|
|
|
if let Some(v) = v.pop() {
|
|
|
|
stack.add_env_var("LAST_EXIT_CODE".into(), v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-02-06 02:03:06 +00:00
|
|
|
_ => {
|
|
|
|
// Drain the input to the screen via tabular output
|
2022-04-18 22:28:01 +00:00
|
|
|
let config = engine_state.get_config();
|
2022-02-06 02:03:06 +00:00
|
|
|
|
2022-05-07 19:39:22 +00:00
|
|
|
match engine_state.find_decl("table".as_bytes(), &[]) {
|
2022-02-06 02:03:06 +00:00
|
|
|
Some(decl_id) => {
|
|
|
|
let table = engine_state.get_decl(decl_id).run(
|
|
|
|
engine_state,
|
|
|
|
stack,
|
|
|
|
&Call::new(Span::new(0, 0)),
|
|
|
|
input,
|
|
|
|
)?;
|
|
|
|
|
2022-07-25 17:00:31 +00:00
|
|
|
print_or_return(table, config)?;
|
2022-02-06 02:03:06 +00:00
|
|
|
}
|
|
|
|
None => {
|
2022-07-25 17:00:31 +00:00
|
|
|
print_or_return(input, config)?;
|
2022-02-06 02:03:06 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
input = PipelineData::new(Span { start: 0, end: 0 })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(input)
|
|
|
|
}
|
|
|
|
|
2022-07-25 17:00:31 +00:00
|
|
|
fn print_or_return(pipeline_data: PipelineData, config: &Config) -> Result<(), ShellError> {
|
|
|
|
for item in pipeline_data {
|
|
|
|
if let Value::Error { error } = item {
|
|
|
|
return Err(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut out = item.into_string("\n", config);
|
|
|
|
out.push('\n');
|
|
|
|
|
|
|
|
stdout_write_all_and_flush(out)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-11-06 05:50:33 +00:00
|
|
|
pub fn eval_subexpression(
|
|
|
|
engine_state: &EngineState,
|
|
|
|
stack: &mut Stack,
|
|
|
|
block: &Block,
|
|
|
|
mut input: PipelineData,
|
|
|
|
) -> Result<PipelineData, ShellError> {
|
2022-02-15 19:31:14 +00:00
|
|
|
for pipeline in block.pipelines.iter() {
|
2022-11-18 21:46:48 +00:00
|
|
|
for expr in pipeline.elements.iter() {
|
|
|
|
input = eval_element_with_input(engine_state, stack, expr, input, true, false)?.0
|
2021-07-16 01:10:22 +00:00
|
|
|
}
|
|
|
|
}
|
2021-07-23 05:14:49 +00:00
|
|
|
|
2021-09-03 02:15:01 +00:00
|
|
|
Ok(input)
|
2021-07-16 01:10:22 +00:00
|
|
|
}
|
2021-10-05 02:27:39 +00:00
|
|
|
|
2021-10-29 18:15:17 +00:00
|
|
|
pub fn eval_variable(
|
2021-11-02 03:08:05 +00:00
|
|
|
engine_state: &EngineState,
|
2021-10-29 18:15:17 +00:00
|
|
|
stack: &Stack,
|
|
|
|
var_id: VarId,
|
|
|
|
span: Span,
|
|
|
|
) -> Result<Value, ShellError> {
|
2022-01-29 13:00:48 +00:00
|
|
|
match var_id {
|
|
|
|
nu_protocol::NU_VARIABLE_ID => {
|
|
|
|
// $nu
|
|
|
|
let mut output_cols = vec![];
|
|
|
|
let mut output_vals = vec![];
|
2021-10-29 18:15:17 +00:00
|
|
|
|
2022-08-22 16:30:09 +00:00
|
|
|
if let Some(path) = engine_state.get_config_path("config-path") {
|
|
|
|
output_cols.push("config-path".into());
|
|
|
|
output_vals.push(Value::String {
|
|
|
|
val: path.to_string_lossy().to_string(),
|
|
|
|
span,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(path) = engine_state.get_config_path("env-path") {
|
|
|
|
output_cols.push("env-path".into());
|
|
|
|
output_vals.push(Value::String {
|
|
|
|
val: path.to_string_lossy().to_string(),
|
|
|
|
span,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-01-29 13:00:48 +00:00
|
|
|
if let Some(mut config_path) = nu_path::config_dir() {
|
|
|
|
config_path.push("nushell");
|
2022-04-06 17:11:51 +00:00
|
|
|
let mut env_config_path = config_path.clone();
|
2022-06-06 11:52:37 +00:00
|
|
|
let mut loginshell_path = config_path.clone();
|
2021-10-29 18:15:17 +00:00
|
|
|
|
2022-01-29 13:00:48 +00:00
|
|
|
let mut history_path = config_path.clone();
|
2021-10-29 18:15:17 +00:00
|
|
|
|
2022-06-15 08:06:49 +00:00
|
|
|
match engine_state.config.history_file_format {
|
|
|
|
HistoryFileFormat::Sqlite => {
|
|
|
|
history_path.push("history.sqlite3");
|
|
|
|
}
|
|
|
|
HistoryFileFormat::PlainText => {
|
|
|
|
history_path.push("history.txt");
|
|
|
|
}
|
|
|
|
}
|
2022-06-14 20:53:33 +00:00
|
|
|
// let mut history_path = config_files::get_history_path(); // todo: this should use the get_history_path method but idk where to put that function
|
2021-10-29 18:15:17 +00:00
|
|
|
|
2022-01-29 13:00:48 +00:00
|
|
|
output_cols.push("history-path".into());
|
|
|
|
output_vals.push(Value::String {
|
|
|
|
val: history_path.to_string_lossy().to_string(),
|
|
|
|
span,
|
|
|
|
});
|
2021-10-29 18:15:17 +00:00
|
|
|
|
2022-08-22 16:30:09 +00:00
|
|
|
if engine_state.get_config_path("config-path").is_none() {
|
|
|
|
config_path.push("config.nu");
|
2021-12-11 19:29:56 +00:00
|
|
|
|
2022-08-22 16:30:09 +00:00
|
|
|
output_cols.push("config-path".into());
|
|
|
|
output_vals.push(Value::String {
|
|
|
|
val: config_path.to_string_lossy().to_string(),
|
|
|
|
span,
|
|
|
|
});
|
|
|
|
}
|
2022-04-06 17:11:51 +00:00
|
|
|
|
2022-08-22 16:30:09 +00:00
|
|
|
if engine_state.get_config_path("env-path").is_none() {
|
|
|
|
env_config_path.push("env.nu");
|
2022-04-06 17:11:51 +00:00
|
|
|
|
2022-08-22 16:30:09 +00:00
|
|
|
output_cols.push("env-path".into());
|
|
|
|
output_vals.push(Value::String {
|
|
|
|
val: env_config_path.to_string_lossy().to_string(),
|
|
|
|
span,
|
|
|
|
});
|
|
|
|
}
|
2022-06-06 11:52:37 +00:00
|
|
|
|
|
|
|
loginshell_path.push("login.nu");
|
|
|
|
|
|
|
|
output_cols.push("loginshell-path".into());
|
|
|
|
output_vals.push(Value::String {
|
|
|
|
val: loginshell_path.to_string_lossy().to_string(),
|
|
|
|
span,
|
|
|
|
});
|
2022-01-29 13:00:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "plugin")]
|
|
|
|
if let Some(path) = &engine_state.plugin_signatures {
|
|
|
|
if let Some(path_str) = path.to_str() {
|
|
|
|
output_cols.push("plugin-path".into());
|
|
|
|
output_vals.push(Value::String {
|
|
|
|
val: path_str.into(),
|
|
|
|
span,
|
|
|
|
});
|
|
|
|
}
|
2021-12-02 06:35:32 +00:00
|
|
|
}
|
|
|
|
|
2022-03-04 16:36:11 +00:00
|
|
|
output_cols.push("scope".into());
|
|
|
|
output_vals.push(create_scope(engine_state, stack, span)?);
|
|
|
|
|
2022-01-29 13:00:48 +00:00
|
|
|
if let Some(home_path) = nu_path::home_dir() {
|
|
|
|
if let Some(home_path_str) = home_path.to_str() {
|
|
|
|
output_cols.push("home-path".into());
|
|
|
|
output_vals.push(Value::String {
|
|
|
|
val: home_path_str.into(),
|
|
|
|
span,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-12-11 19:38:36 +00:00
|
|
|
|
2022-01-29 13:00:48 +00:00
|
|
|
let temp = std::env::temp_dir();
|
|
|
|
if let Some(temp_path) = temp.to_str() {
|
|
|
|
output_cols.push("temp-path".into());
|
2021-12-11 19:12:30 +00:00
|
|
|
output_vals.push(Value::String {
|
2022-01-29 13:00:48 +00:00
|
|
|
val: temp_path.into(),
|
2021-12-11 19:12:30 +00:00
|
|
|
span,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-03-12 16:54:59 +00:00
|
|
|
let pid = std::process::id();
|
|
|
|
output_cols.push("pid".into());
|
|
|
|
output_vals.push(Value::int(pid as i64, span));
|
|
|
|
|
2022-04-23 21:33:27 +00:00
|
|
|
let sys = sysinfo::System::new();
|
|
|
|
let ver = match sys.kernel_version() {
|
|
|
|
Some(v) => v,
|
|
|
|
None => "unknown".into(),
|
|
|
|
};
|
|
|
|
|
2022-04-19 19:11:58 +00:00
|
|
|
let os_record = Value::Record {
|
2022-04-23 21:33:27 +00:00
|
|
|
cols: vec![
|
|
|
|
"name".into(),
|
|
|
|
"arch".into(),
|
|
|
|
"family".into(),
|
|
|
|
"kernel_version".into(),
|
|
|
|
],
|
2022-04-19 19:11:58 +00:00
|
|
|
vals: vec![
|
|
|
|
Value::string(std::env::consts::OS, span),
|
|
|
|
Value::string(std::env::consts::ARCH, span),
|
|
|
|
Value::string(std::env::consts::FAMILY, span),
|
2022-04-23 21:33:27 +00:00
|
|
|
Value::string(ver, span),
|
2022-04-19 19:11:58 +00:00
|
|
|
],
|
|
|
|
span,
|
|
|
|
};
|
|
|
|
output_cols.push("os-info".into());
|
|
|
|
output_vals.push(os_record);
|
|
|
|
|
2022-01-29 13:00:48 +00:00
|
|
|
Ok(Value::Record {
|
|
|
|
cols: output_cols,
|
|
|
|
vals: output_vals,
|
2021-12-11 20:00:29 +00:00
|
|
|
span,
|
|
|
|
})
|
|
|
|
}
|
2022-01-29 13:00:48 +00:00
|
|
|
ENV_VARIABLE_ID => {
|
|
|
|
let env_vars = stack.get_env_vars(engine_state);
|
|
|
|
let env_columns = env_vars.keys();
|
|
|
|
let env_values = env_vars.values();
|
|
|
|
|
|
|
|
let mut pairs = env_columns
|
|
|
|
.map(|x| x.to_string())
|
|
|
|
.zip(env_values.cloned())
|
|
|
|
.collect::<Vec<(String, Value)>>();
|
|
|
|
|
|
|
|
pairs.sort_by(|a, b| a.0.cmp(&b.0));
|
|
|
|
|
|
|
|
let (env_columns, env_values) = pairs.into_iter().unzip();
|
|
|
|
|
|
|
|
Ok(Value::Record {
|
|
|
|
cols: env_columns,
|
|
|
|
vals: env_values,
|
|
|
|
span,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
var_id => stack.get_var(var_id, span),
|
2021-10-29 18:15:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-17 01:04:54 +00:00
|
|
|
fn compute(size: i64, unit: Unit, span: Span) -> Value {
|
2021-10-05 02:27:39 +00:00
|
|
|
match unit {
|
|
|
|
Unit::Byte => Value::Filesize { val: size, span },
|
|
|
|
Unit::Kilobyte => Value::Filesize {
|
|
|
|
val: size * 1000,
|
|
|
|
span,
|
|
|
|
},
|
|
|
|
Unit::Megabyte => Value::Filesize {
|
|
|
|
val: size * 1000 * 1000,
|
|
|
|
span,
|
|
|
|
},
|
|
|
|
Unit::Gigabyte => Value::Filesize {
|
|
|
|
val: size * 1000 * 1000 * 1000,
|
|
|
|
span,
|
|
|
|
},
|
|
|
|
Unit::Terabyte => Value::Filesize {
|
|
|
|
val: size * 1000 * 1000 * 1000 * 1000,
|
|
|
|
span,
|
|
|
|
},
|
|
|
|
Unit::Petabyte => Value::Filesize {
|
|
|
|
val: size * 1000 * 1000 * 1000 * 1000 * 1000,
|
|
|
|
span,
|
|
|
|
},
|
2022-07-26 13:05:37 +00:00
|
|
|
Unit::Exabyte => Value::Filesize {
|
|
|
|
val: size * 1000 * 1000 * 1000 * 1000 * 1000 * 1000,
|
|
|
|
span,
|
|
|
|
},
|
|
|
|
Unit::Zettabyte => Value::Filesize {
|
|
|
|
val: size * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000,
|
|
|
|
span,
|
|
|
|
},
|
2021-10-05 02:27:39 +00:00
|
|
|
|
|
|
|
Unit::Kibibyte => Value::Filesize {
|
|
|
|
val: size * 1024,
|
|
|
|
span,
|
|
|
|
},
|
|
|
|
Unit::Mebibyte => Value::Filesize {
|
|
|
|
val: size * 1024 * 1024,
|
|
|
|
span,
|
|
|
|
},
|
|
|
|
Unit::Gibibyte => Value::Filesize {
|
|
|
|
val: size * 1024 * 1024 * 1024,
|
|
|
|
span,
|
|
|
|
},
|
|
|
|
Unit::Tebibyte => Value::Filesize {
|
|
|
|
val: size * 1024 * 1024 * 1024 * 1024,
|
|
|
|
span,
|
|
|
|
},
|
|
|
|
Unit::Pebibyte => Value::Filesize {
|
|
|
|
val: size * 1024 * 1024 * 1024 * 1024 * 1024,
|
|
|
|
span,
|
|
|
|
},
|
2022-07-26 13:05:37 +00:00
|
|
|
Unit::Exbibyte => Value::Filesize {
|
|
|
|
val: size * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
|
|
|
|
span,
|
|
|
|
},
|
|
|
|
Unit::Zebibyte => Value::Filesize {
|
|
|
|
val: size * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
|
|
|
|
span,
|
|
|
|
},
|
2021-10-05 02:27:39 +00:00
|
|
|
|
|
|
|
Unit::Nanosecond => Value::Duration { val: size, span },
|
|
|
|
Unit::Microsecond => Value::Duration {
|
|
|
|
val: size * 1000,
|
|
|
|
span,
|
|
|
|
},
|
|
|
|
Unit::Millisecond => Value::Duration {
|
|
|
|
val: size * 1000 * 1000,
|
|
|
|
span,
|
|
|
|
},
|
|
|
|
Unit::Second => Value::Duration {
|
|
|
|
val: size * 1000 * 1000 * 1000,
|
|
|
|
span,
|
|
|
|
},
|
2022-09-29 18:24:17 +00:00
|
|
|
Unit::Minute => match size.checked_mul(1000 * 1000 * 1000 * 60) {
|
|
|
|
Some(val) => Value::Duration { val, span },
|
|
|
|
None => Value::Error {
|
|
|
|
error: ShellError::GenericError(
|
|
|
|
"duration too large".into(),
|
|
|
|
"duration too large".into(),
|
|
|
|
Some(span),
|
|
|
|
None,
|
|
|
|
Vec::new(),
|
|
|
|
),
|
|
|
|
},
|
2021-10-05 02:27:39 +00:00
|
|
|
},
|
2022-09-29 18:24:17 +00:00
|
|
|
Unit::Hour => match size.checked_mul(1000 * 1000 * 1000 * 60 * 60) {
|
|
|
|
Some(val) => Value::Duration { val, span },
|
|
|
|
None => Value::Error {
|
|
|
|
error: ShellError::GenericError(
|
|
|
|
"duration too large".into(),
|
|
|
|
"duration too large".into(),
|
|
|
|
Some(span),
|
|
|
|
None,
|
|
|
|
Vec::new(),
|
|
|
|
),
|
|
|
|
},
|
2021-10-05 02:27:39 +00:00
|
|
|
},
|
2022-02-02 20:59:01 +00:00
|
|
|
Unit::Day => match size.checked_mul(1000 * 1000 * 1000 * 60 * 60 * 24) {
|
|
|
|
Some(val) => Value::Duration { val, span },
|
|
|
|
None => Value::Error {
|
2022-04-18 12:34:10 +00:00
|
|
|
error: ShellError::GenericError(
|
2022-09-29 18:24:17 +00:00
|
|
|
"duration too large".into(),
|
|
|
|
"duration too large".into(),
|
2022-04-18 12:34:10 +00:00
|
|
|
Some(span),
|
|
|
|
None,
|
|
|
|
Vec::new(),
|
2022-02-02 20:59:01 +00:00
|
|
|
),
|
|
|
|
},
|
2021-10-05 02:27:39 +00:00
|
|
|
},
|
2022-02-02 20:59:01 +00:00
|
|
|
Unit::Week => match size.checked_mul(1000 * 1000 * 1000 * 60 * 60 * 24 * 7) {
|
|
|
|
Some(val) => Value::Duration { val, span },
|
|
|
|
None => Value::Error {
|
2022-04-18 12:34:10 +00:00
|
|
|
error: ShellError::GenericError(
|
2022-09-29 18:24:17 +00:00
|
|
|
"duration too large".into(),
|
|
|
|
"duration too large".into(),
|
2022-07-26 13:05:37 +00:00
|
|
|
Some(span),
|
|
|
|
None,
|
|
|
|
Vec::new(),
|
|
|
|
),
|
|
|
|
},
|
|
|
|
},
|
2021-10-05 02:27:39 +00:00
|
|
|
}
|
|
|
|
}
|