Fix incorrect handling of boolean flags for builtin commands (#11492)

# Description
Possible fix of #11456
This PR fixes a bug where builtin commands did not respect the logic of
dynamically passed boolean flags. The reason is
[has_flag](6f59abaf43/crates/nu-protocol/src/ast/call.rs (L204C5-L212C6))
method did not evaluate and take into consideration expression used with
flag.

To address this issue a solution is proposed:
1. `has_flag` method is moved to `CallExt` and new logic to evaluate
expression and check if it is a boolean value is added
2. `has_flag_const` method is added to `CallExt` which is a constant
version of `has_flag`
3. `has_named` method is added to `Call` which is basically the old
logic of `has_flag`
4. All usages of `has_flag` in code are updated, mostly to pass
`engine_state` and `stack` to new `has_flag`. In `run_const` commands it
is replaced with `has_flag_const`. And in a few select places: parser,
`to nuon` and `into string` old logic via `has_named` is used.

# User-Facing Changes
Explicit values of boolean flags are now respected in builtin commands.
Before:

![image](https://github.com/nushell/nushell/assets/17511668/f9fbabb2-3cfd-43f9-ba9e-ece76d80043c)
After:

![image](https://github.com/nushell/nushell/assets/17511668/21867596-2075-437f-9c85-45563ac70083)

Another example:
Before:

![image](https://github.com/nushell/nushell/assets/17511668/efdbc5ca-5227-45a4-ac5b-532cdc2bbf5f)
After:

![image](https://github.com/nushell/nushell/assets/17511668/2907d5c5-aa93-404d-af1c-21cdc3d44646)


# Tests + Formatting
Added test reproducing some variants of original issue.
This commit is contained in:
Artemiy
2024-01-11 18:19:48 +03:00
committed by GitHub
parent 62272975f2
commit 1867bb1a88
149 changed files with 771 additions and 504 deletions

View File

@ -75,7 +75,7 @@ impl Command for BytesAdd {
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let index: Option<usize> = call.get_flag(engine_state, stack, "index")?;
let end = call.has_flag("end");
let end = call.has_flag(engine_state, stack, "end")?;
let arg = Arguments {
added_data,

View File

@ -1,4 +1,4 @@
use nu_engine::{eval_expression, CallExt};
use nu_engine::eval_expression;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{

View File

@ -73,8 +73,8 @@ impl Command for BytesIndexOf {
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let arg = Arguments {
pattern,
end: call.has_flag("end"),
all: call.has_flag("all"),
end: call.has_flag(engine_state, stack, "end")?,
all: call.has_flag(engine_state, stack, "all")?,
cell_paths,
};
operate(index_of, arg, input, call.head, engine_state.ctrlc.clone())

View File

@ -74,9 +74,9 @@ impl Command for BytesRemove {
let pattern_to_remove: Vec<u8> = pattern_to_remove.item;
let arg = Arguments {
pattern: pattern_to_remove,
end: call.has_flag("end"),
end: call.has_flag(engine_state, stack, "end")?,
cell_paths,
all: call.has_flag("all"),
all: call.has_flag(engine_state, stack, "all")?,
};
operate(remove, arg, input, call.head, engine_state.ctrlc.clone())

View File

@ -76,7 +76,7 @@ impl Command for BytesReplace {
find: find.item,
replace: call.req::<Vec<u8>>(engine_state, stack, 1)?,
cell_paths,
all: call.has_flag("all"),
all: call.has_flag(engine_state, stack, "all")?,
};
operate(replace, arg, input, call.head, engine_state.ctrlc.clone())

View File

@ -148,7 +148,7 @@ fn into_binary(
_ => {
let args = Arguments {
cell_paths,
compact: call.has_flag("compact"),
compact: call.has_flag(engine_state, stack, "compact")?,
};
operate(action, args, input, call.head, engine_state.ctrlc.clone())
}

View File

@ -116,9 +116,9 @@ impl Command for SubCommand {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
if call.has_flag("list") {
if call.has_flag(engine_state, stack, "list")? {
Ok(generate_strftime_list(call.head, true).into_pipeline_data())
} else if call.has_flag("list-human") {
} else if call.has_flag(engine_state, stack, "list-human")? {
Ok(list_human_readable_examples(call.head).into_pipeline_data())
} else {
let cell_paths = call.rest(engine_state, stack, 0)?;

View File

@ -11,7 +11,6 @@ use num_format::ToFormattedString;
struct Arguments {
decimals_value: Option<i64>,
decimals: bool,
cell_paths: Option<Vec<CellPath>>,
config: Config,
}
@ -148,11 +147,10 @@ fn string_helper(
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let decimals = call.has_flag("decimals");
let head = call.head;
let decimals_value: Option<i64> = call.get_flag(engine_state, stack, "decimals")?;
if let Some(decimal_val) = decimals_value {
if decimals && decimal_val.is_negative() {
if decimal_val.is_negative() {
return Err(ShellError::TypeMismatch {
err_message: "Cannot accept negative integers for decimals arguments".to_string(),
span: head,
@ -164,7 +162,6 @@ fn string_helper(
let config = engine_state.get_config().clone();
let args = Arguments {
decimals_value,
decimals,
cell_paths,
config,
};
@ -186,7 +183,6 @@ fn string_helper(
}
fn action(input: &Value, args: &Arguments, span: Span) -> Value {
let decimals = args.decimals;
let digits = args.decimals_value;
let config = &args.config;
match input {
@ -196,8 +192,8 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
Value::string(res, span)
}
Value::Float { val, .. } => {
if decimals {
let decimal_value = digits.unwrap_or(2) as usize;
if let Some(decimal_value) = digits {
let decimal_value = decimal_value as usize;
Value::string(format!("{val:.decimal_value$}"), span)
} else {
Value::string(val.to_string(), span)

View File

@ -41,8 +41,8 @@ impl Command for Ast {
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let pipeline: Spanned<String> = call.req(engine_state, stack, 0)?;
let to_json = call.has_flag("json");
let minify = call.has_flag("minify");
let to_json = call.has_flag(engine_state, stack, "json")?;
let minify = call.has_flag(engine_state, stack, "minify")?;
let mut working_set = StateWorkingSet::new(engine_state);
let block_output = parse(&mut working_set, None, pipeline.item.as_bytes(), false);
let error_output = working_set.parse_errors.first();

View File

@ -1,3 +1,4 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Span, Type, Value};
@ -31,13 +32,13 @@ impl Command for Debug {
fn run(
&self,
engine_state: &EngineState,
_stack: &mut Stack,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let config = engine_state.get_config().clone();
let raw = call.has_flag("raw");
let raw = call.has_flag(engine_state, stack, "raw")?;
// Should PipelineData::Empty result in an error here?

View File

@ -1,4 +1,4 @@
use nu_engine::env_to_strings;
use nu_engine::{env_to_strings, CallExt};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
@ -59,7 +59,7 @@ impl Command for ConfigEnv {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
// `--default` flag handling
if call.has_flag("default") {
if call.has_flag(engine_state, stack, "default")? {
let head = call.head;
return Ok(Value::string(nu_utils::get_default_env(), head).into_pipeline_data());
}

View File

@ -1,4 +1,4 @@
use nu_engine::env_to_strings;
use nu_engine::{env_to_strings, CallExt};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
@ -63,7 +63,7 @@ impl Command for ConfigNu {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
// `--default` flag handling
if call.has_flag("default") {
if call.has_flag(engine_state, stack, "default")? {
let head = call.head;
return Ok(Value::string(nu_utils::get_default_config(), head).into_pipeline_data());
}

View File

@ -1,4 +1,5 @@
use chrono::Local;
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
@ -39,14 +40,14 @@ impl Command for ConfigReset {
fn run(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let only_nu = call.has_flag("nu");
let only_env = call.has_flag("env");
let no_backup = call.has_flag("without-backup");
let only_nu = call.has_flag(engine_state, stack, "nu")?;
let only_env = call.has_flag(engine_state, stack, "env")?;
let no_backup = call.has_flag(engine_state, stack, "without-backup")?;
let span = call.head;
let mut config_path = match nu_path::config_dir() {
Some(path) => path,

View File

@ -76,11 +76,11 @@ impl Command for Cp {
) -> Result<PipelineData, ShellError> {
let src: Spanned<String> = call.req(engine_state, stack, 0)?;
let dst: Spanned<String> = call.req(engine_state, stack, 1)?;
let recursive = call.has_flag("recursive");
let verbose = call.has_flag("verbose");
let interactive = call.has_flag("interactive");
let progress = call.has_flag("progress");
let update_mode = call.has_flag("update");
let recursive = call.has_flag(engine_state, stack, "recursive")?;
let verbose = call.has_flag(engine_state, stack, "verbose")?;
let interactive = call.has_flag(engine_state, stack, "interactive")?;
let progress = call.has_flag(engine_state, stack, "progress")?;
let update_mode = call.has_flag(engine_state, stack, "update")?;
let current_dir_path = current_dir(engine_state, stack)?;
let destination = current_dir_path.join(dst.item.as_str());
@ -229,7 +229,7 @@ impl Command for Cp {
inner: vec![],
})?;
let not_follow_symlink = call.has_flag("no-symlink");
let not_follow_symlink = call.has_flag(engine_state, stack, "no-symlink")?;
let sources = sources.paths_applying_with(|(source_file, depth_level)| {
let mut dest = destination.clone();

View File

@ -137,9 +137,9 @@ impl Command for Glob {
let span = call.head;
let glob_pattern: Spanned<String> = call.req(engine_state, stack, 0)?;
let depth = call.get_flag(engine_state, stack, "depth")?;
let no_dirs = call.has_flag("no-dir");
let no_files = call.has_flag("no-file");
let no_symlinks = call.has_flag("no-symlink");
let no_dirs = call.has_flag(engine_state, stack, "no-dir")?;
let no_files = call.has_flag(engine_state, stack, "no-file")?;
let no_symlinks = call.has_flag(engine_state, stack, "no-symlink")?;
let paths_to_exclude: Option<Value> = call.get_flag(engine_state, stack, "exclude")?;

View File

@ -73,13 +73,13 @@ impl Command for Ls {
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let all = call.has_flag("all");
let long = call.has_flag("long");
let short_names = call.has_flag("short-names");
let full_paths = call.has_flag("full-paths");
let du = call.has_flag("du");
let directory = call.has_flag("directory");
let use_mime_type = call.has_flag("mime-type");
let all = call.has_flag(engine_state, stack, "all")?;
let long = call.has_flag(engine_state, stack, "long")?;
let short_names = call.has_flag(engine_state, stack, "short-names")?;
let full_paths = call.has_flag(engine_state, stack, "full-paths")?;
let du = call.has_flag(engine_state, stack, "du")?;
let directory = call.has_flag(engine_state, stack, "directory")?;
let use_mime_type = call.has_flag(engine_state, stack, "mime-type")?;
let ctrl_c = engine_state.ctrlc.clone();
let call_span = call.head;
let cwd = current_dir(engine_state, stack)?;

View File

@ -51,7 +51,7 @@ impl Command for Mkdir {
.map(|dir| path.join(dir))
.peekable();
let is_verbose = call.has_flag("verbose");
let is_verbose = call.has_flag(engine_state, stack, "verbose")?;
let mut stream: VecDeque<Value> = VecDeque::new();
if directories.peek().is_none() {

View File

@ -84,9 +84,9 @@ impl Command for Mktemp {
.cloned()
.map(|i: Spanned<String>| i.item)
.unwrap_or("tmp.XXXXXXXXXX".to_string()); // same as default in coreutils
let directory = call.has_flag("directory");
let directory = call.has_flag(engine_state, stack, "directory")?;
let suffix = call.get_flag(engine_state, stack, "suffix")?;
let tmpdir = call.has_flag("tmpdir");
let tmpdir = call.has_flag(engine_state, stack, "tmpdir")?;
let tmpdir_path = call
.get_flag(engine_state, stack, "tmpdir-path")?
.map(|i: Spanned<PathBuf>| i.item);

View File

@ -65,10 +65,10 @@ impl Command for Mv {
// TODO: handle invalid directory or insufficient permissions when moving
let spanned_source: Spanned<String> = call.req(engine_state, stack, 0)?;
let spanned_destination: Spanned<String> = call.req(engine_state, stack, 1)?;
let verbose = call.has_flag("verbose");
let interactive = call.has_flag("interactive");
let force = call.has_flag("force");
let update_mode = call.has_flag("update");
let verbose = call.has_flag(engine_state, stack, "verbose")?;
let interactive = call.has_flag(engine_state, stack, "interactive")?;
let force = call.has_flag(engine_state, stack, "force")?;
let update_mode = call.has_flag(engine_state, stack, "update")?;
let ctrlc = engine_state.ctrlc.clone();

View File

@ -59,7 +59,7 @@ impl Command for Open {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let raw = call.has_flag("raw");
let raw = call.has_flag(engine_state, stack, "raw")?;
let call_span = call.head;
let ctrlc = engine_state.ctrlc.clone();
let cwd = current_dir(engine_state, stack)?;

View File

@ -124,13 +124,13 @@ fn rm(
stack: &mut Stack,
call: &Call,
) -> Result<PipelineData, ShellError> {
let trash = call.has_flag("trash");
let permanent = call.has_flag("permanent");
let recursive = call.has_flag("recursive");
let force = call.has_flag("force");
let verbose = call.has_flag("verbose");
let interactive = call.has_flag("interactive");
let interactive_once = call.has_flag("interactive-once") && !interactive;
let trash = call.has_flag(engine_state, stack, "trash")?;
let permanent = call.has_flag(engine_state, stack, "permanent")?;
let recursive = call.has_flag(engine_state, stack, "recursive")?;
let force = call.has_flag(engine_state, stack, "force")?;
let verbose = call.has_flag(engine_state, stack, "verbose")?;
let interactive = call.has_flag(engine_state, stack, "interactive")?;
let interactive_once = call.has_flag(engine_state, stack, "interactive-once")? && !interactive;
let ctrlc = engine_state.ctrlc.clone();

View File

@ -63,10 +63,10 @@ impl Command for Save {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let raw = call.has_flag("raw");
let append = call.has_flag("append");
let force = call.has_flag("force");
let progress = call.has_flag("progress");
let raw = call.has_flag(engine_state, stack, "raw")?;
let append = call.has_flag(engine_state, stack, "append")?;
let force = call.has_flag(engine_state, stack, "force")?;
let progress = call.has_flag(engine_state, stack, "progress")?;
let out_append = if let Some(Expression {
expr: Expr::Bool(out_append),
..

View File

@ -67,10 +67,10 @@ impl Command for Touch {
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let mut change_mtime: bool = call.has_flag("modified");
let mut change_atime: bool = call.has_flag("access");
let use_reference: bool = call.has_flag("reference");
let no_create: bool = call.has_flag("no-create");
let mut change_mtime: bool = call.has_flag(engine_state, stack, "modified")?;
let mut change_atime: bool = call.has_flag(engine_state, stack, "access")?;
let use_reference: bool = call.has_flag(engine_state, stack, "reference")?;
let no_create: bool = call.has_flag(engine_state, stack, "no-create")?;
let target: String = call.req(engine_state, stack, 0)?;
let rest: Vec<String> = call.rest(engine_state, stack, 1)?;

View File

@ -96,19 +96,19 @@ impl Command for UCp {
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let interactive = call.has_flag("interactive");
let (update, copy_mode) = if call.has_flag("update") {
let interactive = call.has_flag(engine_state, stack, "interactive")?;
let (update, copy_mode) = if call.has_flag(engine_state, stack, "update")? {
(UpdateMode::ReplaceIfOlder, CopyMode::Update)
} else {
(UpdateMode::ReplaceAll, CopyMode::Copy)
};
let force = call.has_flag("force");
let no_clobber = call.has_flag("no-clobber");
let progress = call.has_flag("progress");
let recursive = call.has_flag("recursive");
let verbose = call.has_flag("verbose");
let force = call.has_flag(engine_state, stack, "force")?;
let no_clobber = call.has_flag(engine_state, stack, "no-clobber")?;
let progress = call.has_flag(engine_state, stack, "progress")?;
let recursive = call.has_flag(engine_state, stack, "recursive")?;
let verbose = call.has_flag(engine_state, stack, "verbose")?;
let debug = call.has_flag("debug");
let debug = call.has_flag(engine_state, stack, "debug")?;
let overwrite = if no_clobber {
uu_cp::OverwriteMode::NoClobber
} else if interactive {

View File

@ -57,7 +57,7 @@ impl Command for UMkdir {
.map(|dir| nu_path::expand_path_with(dir, &cwd))
.peekable();
let is_verbose = call.has_flag("verbose");
let is_verbose = call.has_flag(engine_state, stack, "verbose")?;
if directories.peek().is_none() {
return Err(ShellError::MissingParameter {

View File

@ -96,7 +96,7 @@ impl Command for Watch {
.get_block(capture_block.block_id)
.clone();
let verbose = call.has_flag("verbose");
let verbose = call.has_flag(engine_state, stack, "verbose")?;
let debounce_duration_flag: Option<Spanned<i64>> =
call.get_flag(engine_state, stack, "debounce-ms")?;

View File

@ -51,7 +51,7 @@ impl Command for Compact {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let empty = call.has_flag("empty");
let empty = call.has_flag(engine_state, stack, "empty")?;
compact(engine_state, stack, call, input, empty)
}

View File

@ -114,7 +114,7 @@ with 'transpose' first."#
) -> Result<PipelineData, ShellError> {
let capture_block: Closure = call.req(engine_state, stack, 0)?;
let keep_empty = call.has_flag("keep-empty");
let keep_empty = call.has_flag(engine_state, stack, "keep-empty")?;
let metadata = input.metadata();
let ctrlc = engine_state.ctrlc.clone();

View File

@ -71,7 +71,7 @@ impl Command for Every {
stride => stride,
};
let skip = call.has_flag("skip");
let skip = call.has_flag(engine_state, stack, "skip")?;
let metadata = input.metadata();

View File

@ -219,7 +219,7 @@ impl Command for Find {
fn find_with_regex(
regex: String,
engine_state: &EngineState,
_stack: &mut Stack,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
@ -227,10 +227,10 @@ fn find_with_regex(
let ctrlc = engine_state.ctrlc.clone();
let config = engine_state.get_config().clone();
let insensitive = call.has_flag("ignore-case");
let multiline = call.has_flag("multiline");
let dotall = call.has_flag("dotall");
let invert = call.has_flag("invert");
let insensitive = call.has_flag(engine_state, stack, "ignore-case")?;
let multiline = call.has_flag(engine_state, stack, "multiline")?;
let dotall = call.has_flag(engine_state, stack, "dotall")?;
let invert = call.has_flag(engine_state, stack, "invert")?;
let flags = match (insensitive, multiline, dotall) {
(false, false, false) => "",
@ -336,7 +336,7 @@ fn find_with_rest_and_highlight(
let engine_state = engine_state.clone();
let config = engine_state.get_config().clone();
let filter_config = engine_state.get_config().clone();
let invert = call.has_flag("invert");
let invert = call.has_flag(&engine_state, stack, "invert")?;
let terms = call.rest::<Value>(&engine_state, stack, 0)?;
let lower_terms = terms
.iter()

View File

@ -128,7 +128,7 @@ fn flatten(
) -> Result<PipelineData, ShellError> {
let columns: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let metadata = input.metadata();
let flatten_all = call.has_flag("all");
let flatten_all = call.has_flag(engine_state, stack, "all")?;
input
.flat_map(

View File

@ -66,8 +66,8 @@ If multiple cell paths are given, this will produce a list of values."#
let span = call.head;
let mut cell_path: CellPath = call.req(engine_state, stack, 0)?;
let mut rest: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let ignore_errors = call.has_flag("ignore-errors");
let sensitive = call.has_flag("sensitive");
let ignore_errors = call.has_flag(engine_state, stack, "ignore-errors")?;
let sensitive = call.has_flag(engine_state, stack, "sensitive")?;
let ctrlc = engine_state.ctrlc.clone();
let metadata = input.metadata();

View File

@ -188,7 +188,7 @@ pub fn group_by(
None => group_no_grouper(values)?,
};
let value = if call.has_flag("to-table") {
let value = if call.has_flag(engine_state, stack, "to-table")? {
groups_to_table(groups, span)
} else {
groups_to_record(groups, span)

View File

@ -75,7 +75,7 @@ impl Command for Join {
.opt(engine_state, stack, 2)?
.unwrap_or_else(|| l_on.clone());
let span = call.head;
let join_type = join_type(call)?;
let join_type = join_type(engine_state, stack, call)?;
// FIXME: we should handle ListStreams properly instead of collecting
let collected_input = input.into_value(span);
@ -116,12 +116,16 @@ impl Command for Join {
}
}
fn join_type(call: &Call) -> Result<JoinType, nu_protocol::ShellError> {
fn join_type(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
) -> Result<JoinType, nu_protocol::ShellError> {
match (
call.has_flag("inner"),
call.has_flag("left"),
call.has_flag("right"),
call.has_flag("outer"),
call.has_flag(engine_state, stack, "inner")?,
call.has_flag(engine_state, stack, "left")?,
call.has_flag(engine_state, stack, "right")?,
call.has_flag(engine_state, stack, "outer")?,
) {
(_, false, false, false) => Ok(JoinType::Inner),
(false, true, false, false) => Ok(JoinType::Left),

View File

@ -1,3 +1,4 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
@ -30,13 +31,13 @@ impl Command for Lines {
fn run(
&self,
engine_state: &EngineState,
_stack: &mut Stack,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let ctrlc = engine_state.ctrlc.clone();
let skip_empty = call.has_flag("skip-empty");
let skip_empty = call.has_flag(engine_state, stack, "skip-empty")?;
// match \r\n or \n
static LINE_BREAK_REGEX: Lazy<Regex> =

View File

@ -121,7 +121,7 @@ impl Command for ParEach {
let capture_block: Closure = call.req(engine_state, stack, 0)?;
let threads: Option<usize> = call.get_flag(engine_state, stack, "threads")?;
let max_threads = threads.unwrap_or(0);
let keep_order = call.has_flag("keep-order");
let keep_order = call.has_flag(engine_state, stack, "keep-order")?;
let metadata = input.metadata();
let ctrlc = engine_state.ctrlc.clone();
let outer_ctrlc = engine_state.ctrlc.clone();

View File

@ -133,7 +133,7 @@ impl Command for Reject {
}
let span = call.head;
let ignore_errors = call.has_flag("ignore-errors");
let ignore_errors = call.has_flag(engine_state, stack, "ignore-errors")?;
if ignore_errors {
for cell_path in &mut new_columns {
cell_path.make_optional();

View File

@ -137,7 +137,7 @@ produce a table, a list will produce a list, and a record will produce a record.
}
}
}
let ignore_errors = call.has_flag("ignore-errors");
let ignore_errors = call.has_flag(engine_state, stack, "ignore-errors")?;
let span = call.head;
if ignore_errors {
@ -235,7 +235,7 @@ fn select(
let columns = new_columns;
let input = if !unique_rows.is_empty() {
// let skip = call.has_flag("skip");
// let skip = call.has_flag(engine_state, stack, "skip")?;
let metadata = input.metadata();
let pipeline_iter: PipelineIterator = input.into_iter();

View File

@ -1,4 +1,5 @@
use alphanumeric_sort::compare_str;
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
@ -134,20 +135,20 @@ impl Command for Sort {
fn run(
&self,
engine_state: &EngineState,
_stack: &mut Stack,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let reverse = call.has_flag("reverse");
let insensitive = call.has_flag("ignore-case");
let natural = call.has_flag("natural");
let reverse = call.has_flag(engine_state, stack, "reverse")?;
let insensitive = call.has_flag(engine_state, stack, "ignore-case")?;
let natural = call.has_flag(engine_state, stack, "natural")?;
let metadata = &input.metadata();
let span = input.span().unwrap_or(call.head);
match input {
// Records have two sorting methods, toggled by presence or absence of -v
PipelineData::Value(Value::Record { val, .. }, ..) => {
let sort_by_value = call.has_flag("values");
let sort_by_value = call.has_flag(engine_state, stack, "values")?;
let record = sort_record(val, span, sort_by_value, reverse, insensitive, natural);
Ok(record.into_pipeline_data())
}

View File

@ -85,9 +85,9 @@ impl Command for SortBy {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let columns: Vec<String> = call.rest(engine_state, stack, 0)?;
let reverse = call.has_flag("reverse");
let insensitive = call.has_flag("ignore-case");
let natural = call.has_flag("natural");
let reverse = call.has_flag(engine_state, stack, "reverse")?;
let insensitive = call.has_flag(engine_state, stack, "ignore-case")?;
let natural = call.has_flag(engine_state, stack, "natural")?;
let metadata = &input.metadata();
let mut vec: Vec<_> = input.into_iter_strict(call.head)?.collect();

View File

@ -145,11 +145,11 @@ pub fn transpose(
) -> Result<PipelineData, ShellError> {
let name = call.head;
let args = TransposeArgs {
header_row: call.has_flag("header-row"),
ignore_titles: call.has_flag("ignore-titles"),
as_record: call.has_flag("as-record"),
keep_last: call.has_flag("keep-last"),
keep_all: call.has_flag("keep-all"),
header_row: call.has_flag(engine_state, stack, "header-row")?,
ignore_titles: call.has_flag(engine_state, stack, "ignore-titles")?,
as_record: call.has_flag(engine_state, stack, "as-record")?,
keep_last: call.has_flag(engine_state, stack, "keep-last")?,
keep_all: call.has_flag(engine_state, stack, "keep-all")?,
rest: call.rest(engine_state, stack, 0)?,
};

View File

@ -1,5 +1,6 @@
use crate::formats::value_to_string;
use itertools::Itertools;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
@ -247,7 +248,7 @@ fn generate_results_with_count(head: Span, uniq_values: Vec<ValueCounter>) -> Ve
pub fn uniq(
engine_state: &EngineState,
_stack: &mut Stack,
stack: &mut Stack,
call: &Call,
input: Vec<Value>,
item_mapper: Box<dyn Fn(ItemMapperState) -> ValueCounter>,
@ -255,10 +256,10 @@ pub fn uniq(
) -> Result<PipelineData, ShellError> {
let ctrlc = engine_state.ctrlc.clone();
let head = call.head;
let flag_show_count = call.has_flag("count");
let flag_show_repeated = call.has_flag("repeated");
let flag_ignore_case = call.has_flag("ignore-case");
let flag_only_uniques = call.has_flag("unique");
let flag_show_count = call.has_flag(engine_state, stack, "count")?;
let flag_show_repeated = call.has_flag(engine_state, stack, "repeated")?;
let flag_ignore_case = call.has_flag(engine_state, stack, "ignore-case")?;
let flag_only_uniques = call.has_flag(engine_state, stack, "unique")?;
let uniq_values = input
.into_iter()

View File

@ -120,7 +120,7 @@ impl Command for Window {
let ctrlc = engine_state.ctrlc.clone();
let metadata = input.metadata();
let stride: Option<usize> = call.get_flag(engine_state, stack, "stride")?;
let remainder = call.has_flag("remainder");
let remainder = call.has_flag(engine_state, stack, "remainder")?;
let stride = stride.unwrap_or(1);

View File

@ -166,9 +166,9 @@ fn from_csv(
.get_flag(engine_state, stack, "escape")?
.map(|v: Value| v.as_char())
.transpose()?;
let no_infer = call.has_flag("no-infer");
let noheaders = call.has_flag("noheaders");
let flexible = call.has_flag("flexible");
let no_infer = call.has_flag(engine_state, stack, "no-infer")?;
let noheaders = call.has_flag(engine_state, stack, "noheaders")?;
let flexible = call.has_flag(engine_state, stack, "flexible")?;
let trim = trim_from_str(call.get_flag(engine_state, stack, "trim")?)?;
let config = DelimitedReaderConfig {

View File

@ -1,3 +1,4 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
@ -47,7 +48,7 @@ impl Command for FromJson {
fn run(
&self,
engine_state: &EngineState,
_stack: &mut Stack,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
@ -59,7 +60,7 @@ impl Command for FromJson {
}
// TODO: turn this into a structured underline of the nu_json error
if call.has_flag("objects") {
if call.has_flag(engine_state, stack, "objects")? {
let converted_lines: Vec<Value> = string_input
.lines()
.filter_map(move |x| {

View File

@ -289,8 +289,8 @@ fn from_ssv(
) -> Result<PipelineData, ShellError> {
let name = call.head;
let noheaders = call.has_flag("noheaders");
let aligned_columns = call.has_flag("aligned-columns");
let noheaders = call.has_flag(engine_state, stack, "noheaders")?;
let aligned_columns = call.has_flag(engine_state, stack, "aligned-columns")?;
let minimum_spaces: Option<Spanned<usize>> =
call.get_flag(engine_state, stack, "minimum-spaces")?;

View File

@ -132,9 +132,9 @@ fn from_tsv(
.get_flag(engine_state, stack, "escape")?
.map(|v: Value| v.as_char())
.transpose()?;
let no_infer = call.has_flag("no-infer");
let noheaders = call.has_flag("noheaders");
let flexible = call.has_flag("flexible");
let no_infer = call.has_flag(engine_state, stack, "no-infer")?;
let noheaders = call.has_flag(engine_state, stack, "noheaders")?;
let flexible = call.has_flag(engine_state, stack, "flexible")?;
let trim = trim_from_str(call.get_flag(engine_state, stack, "trim")?)?;
let config = DelimitedReaderConfig {

View File

@ -1,5 +1,6 @@
use crate::formats::nu_xml_format::{COLUMN_ATTRS_NAME, COLUMN_CONTENT_NAME, COLUMN_TAG_NAME};
use indexmap::map::IndexMap;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
@ -46,14 +47,14 @@ string. This way content of every tag is always a table and is easier to parse"#
fn run(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let keep_comments = call.has_flag("keep-comments");
let keep_processing_instructions = call.has_flag("keep-pi");
let keep_comments = call.has_flag(engine_state, stack, "keep-comments")?;
let keep_processing_instructions = call.has_flag(engine_state, stack, "keep-pi")?;
let info = ParsingInfo {
span: head,
keep_comments,

View File

@ -67,7 +67,7 @@ impl Command for ToCsv {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let noheaders = call.has_flag("noheaders");
let noheaders = call.has_flag(engine_state, stack, "noheaders")?;
let separator: Option<Spanned<String>> = call.get_flag(engine_state, stack, "separator")?;
let config = engine_state.get_config();
to_csv(input, noheaders, separator, head, config)

View File

@ -44,8 +44,8 @@ impl Command for ToJson {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let raw = call.has_flag("raw");
let use_tabs = call.has_flag("tabs");
let raw = call.has_flag(engine_state, stack, "raw")?;
let use_tabs = call.has_flag(engine_state, stack, "tabs")?;
let span = call.head;
// allow ranges to expand and turn into array

View File

@ -1,5 +1,6 @@
use indexmap::map::IndexMap;
use nu_cmd_base::formats::to::delimited::merge_descriptors;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
@ -67,13 +68,13 @@ impl Command for ToMd {
fn run(
&self,
engine_state: &EngineState,
_stack: &mut Stack,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let pretty = call.has_flag("pretty");
let per_element = call.has_flag("per-element");
let pretty = call.has_flag(engine_state, stack, "pretty")?;
let per_element = call.has_flag(engine_state, stack, "per-element")?;
let config = engine_state.get_config();
to_md(input, pretty, per_element, config, head)
}

View File

@ -53,20 +53,18 @@ impl Command for ToNuon {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let raw = call.has_flag("raw");
let use_tabs = call.has_flag("tabs");
let use_indent = call.has_flag("indent");
let raw = call.has_flag(engine_state, stack, "raw")?;
let tabs: Option<usize> = call.get_flag(engine_state, stack, "tabs")?;
let indent: Option<usize> = call.get_flag(engine_state, stack, "indent")?;
let span = call.head;
let value = input.into_value(span);
let nuon_result = if raw {
value_to_string(&value, span, 0, None)
} else if use_tabs {
let tab_count: usize = call.get_flag(engine_state, stack, "tabs")?.unwrap_or(1);
} else if let Some(tab_count) = tabs {
value_to_string(&value, span, 0, Some(&"\t".repeat(tab_count)))
} else if use_indent {
let indent: usize = call.get_flag(engine_state, stack, "indent")?.unwrap_or(2);
} else if let Some(indent) = indent {
value_to_string(&value, span, 0, Some(&" ".repeat(indent)))
} else {
value_to_string(&value, span, 0, None)

View File

@ -1,4 +1,5 @@
use crate::formats::to::delimited::to_delimited_data;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
@ -49,12 +50,12 @@ impl Command for ToTsv {
fn run(
&self,
engine_state: &EngineState,
_stack: &mut Stack,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let noheaders = call.has_flag("noheaders");
let noheaders = call.has_flag(engine_state, stack, "noheaders")?;
let config = engine_state.get_config();
to_tsv(input, noheaders, head, config)
}

View File

@ -101,10 +101,10 @@ pub fn cal(
let (current_year, current_month, current_day) = get_current_date();
let arguments = Arguments {
year: call.has_flag("year"),
month: call.has_flag("month"),
month_names: call.has_flag("month-names"),
quarter: call.has_flag("quarter"),
year: call.has_flag(engine_state, stack, "year")?,
month: call.has_flag(engine_state, stack, "month")?,
month_names: call.has_flag(engine_state, stack, "month-names")?,
quarter: call.has_flag(engine_state, stack, "quarter")?,
full_year: call.get_flag(engine_state, stack, "full-year")?,
week_start: call.get_flag(engine_state, stack, "week-start")?,
};

View File

@ -129,7 +129,7 @@ impl Command for SeqDate {
let end_date: Option<Spanned<String>> = call.get_flag(engine_state, stack, "end-date")?;
let increment: Option<Spanned<i64>> = call.get_flag(engine_state, stack, "increment")?;
let days: Option<Spanned<i64>> = call.get_flag(engine_state, stack, "days")?;
let reverse = call.has_flag("reverse");
let reverse = call.has_flag(engine_state, stack, "reverse")?;
let outformat = match output_format {
Some(s) => Some(Value::string(s.item, s.span)),

View File

@ -87,7 +87,7 @@ where
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let binary = call.has_flag("binary");
let binary = call.has_flag(engine_state, stack, "binary")?;
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let args = Arguments { binary, cell_paths };

View File

@ -1,5 +1,6 @@
use super::variance::compute_variance as variance;
use crate::math::utils::run_with_function;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Span, Type, Value};
@ -40,12 +41,12 @@ impl Command for SubCommand {
fn run(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let sample = call.has_flag("sample");
let sample = call.has_flag(engine_state, stack, "sample")?;
run_with_function(call, input, compute_stddev(sample))
}

View File

@ -1,4 +1,5 @@
use crate::math::utils::run_with_function;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Span, Type, Value};
@ -32,12 +33,12 @@ impl Command for SubCommand {
fn run(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let sample = call.has_flag("sample");
let sample = call.has_flag(engine_state, stack, "sample")?;
run_with_function(call, input, compute_variance(sample))
}

View File

@ -170,13 +170,13 @@ fn run_delete(
headers: call.get_flag(engine_state, stack, "headers")?,
data: call.get_flag(engine_state, stack, "data")?,
content_type: call.get_flag(engine_state, stack, "content-type")?,
raw: call.has_flag("raw"),
insecure: call.has_flag("insecure"),
raw: call.has_flag(engine_state, stack, "raw")?,
insecure: call.has_flag(engine_state, stack, "insecure")?,
user: call.get_flag(engine_state, stack, "user")?,
password: call.get_flag(engine_state, stack, "password")?,
timeout: call.get_flag(engine_state, stack, "max-time")?,
full: call.has_flag("full"),
allow_errors: call.has_flag("allow-errors"),
full: call.has_flag(engine_state, stack, "full")?,
allow_errors: call.has_flag(engine_state, stack, "allow-errors")?,
redirect: call.get_flag(engine_state, stack, "redirect-mode")?,
};

View File

@ -154,13 +154,13 @@ fn run_get(
let args = Arguments {
url: call.req(engine_state, stack, 0)?,
headers: call.get_flag(engine_state, stack, "headers")?,
raw: call.has_flag("raw"),
insecure: call.has_flag("insecure"),
raw: call.has_flag(engine_state, stack, "raw")?,
insecure: call.has_flag(engine_state, stack, "insecure")?,
user: call.get_flag(engine_state, stack, "user")?,
password: call.get_flag(engine_state, stack, "password")?,
timeout: call.get_flag(engine_state, stack, "max-time")?,
full: call.has_flag("full"),
allow_errors: call.has_flag("allow-errors"),
full: call.has_flag(engine_state, stack, "full")?,
allow_errors: call.has_flag(engine_state, stack, "allow-errors")?,
redirect: call.get_flag(engine_state, stack, "redirect-mode")?,
};
helper(engine_state, stack, call, args)

View File

@ -132,7 +132,7 @@ fn run_head(
let args = Arguments {
url: call.req(engine_state, stack, 0)?,
headers: call.get_flag(engine_state, stack, "headers")?,
insecure: call.has_flag("insecure"),
insecure: call.has_flag(engine_state, stack, "insecure")?,
user: call.get_flag(engine_state, stack, "user")?,
password: call.get_flag(engine_state, stack, "password")?,
timeout: call.get_flag(engine_state, stack, "max-time")?,

View File

@ -139,11 +139,11 @@ fn run_get(
let args = Arguments {
url: call.req(engine_state, stack, 0)?,
headers: call.get_flag(engine_state, stack, "headers")?,
insecure: call.has_flag("insecure"),
insecure: call.has_flag(engine_state, stack, "insecure")?,
user: call.get_flag(engine_state, stack, "user")?,
password: call.get_flag(engine_state, stack, "password")?,
timeout: call.get_flag(engine_state, stack, "max-time")?,
allow_errors: call.has_flag("allow-errors"),
allow_errors: call.has_flag(engine_state, stack, "allow-errors")?,
};
helper(engine_state, stack, call, args)
}

View File

@ -162,13 +162,13 @@ fn run_patch(
headers: call.get_flag(engine_state, stack, "headers")?,
data: call.req(engine_state, stack, 1)?,
content_type: call.get_flag(engine_state, stack, "content-type")?,
raw: call.has_flag("raw"),
insecure: call.has_flag("insecure"),
raw: call.has_flag(engine_state, stack, "raw")?,
insecure: call.has_flag(engine_state, stack, "insecure")?,
user: call.get_flag(engine_state, stack, "user")?,
password: call.get_flag(engine_state, stack, "password")?,
timeout: call.get_flag(engine_state, stack, "max-time")?,
full: call.has_flag("full"),
allow_errors: call.has_flag("allow-errors"),
full: call.has_flag(engine_state, stack, "full")?,
allow_errors: call.has_flag(engine_state, stack, "allow-errors")?,
redirect: call.get_flag(engine_state, stack, "redirect-mode")?,
};

View File

@ -160,13 +160,13 @@ fn run_post(
headers: call.get_flag(engine_state, stack, "headers")?,
data: call.req(engine_state, stack, 1)?,
content_type: call.get_flag(engine_state, stack, "content-type")?,
raw: call.has_flag("raw"),
insecure: call.has_flag("insecure"),
raw: call.has_flag(engine_state, stack, "raw")?,
insecure: call.has_flag(engine_state, stack, "insecure")?,
user: call.get_flag(engine_state, stack, "user")?,
password: call.get_flag(engine_state, stack, "password")?,
timeout: call.get_flag(engine_state, stack, "max-time")?,
full: call.has_flag("full"),
allow_errors: call.has_flag("allow-errors"),
full: call.has_flag(engine_state, stack, "full")?,
allow_errors: call.has_flag(engine_state, stack, "allow-errors")?,
redirect: call.get_flag(engine_state, stack, "redirect-mode")?,
};

View File

@ -160,13 +160,13 @@ fn run_put(
headers: call.get_flag(engine_state, stack, "headers")?,
data: call.req(engine_state, stack, 1)?,
content_type: call.get_flag(engine_state, stack, "content-type")?,
raw: call.has_flag("raw"),
insecure: call.has_flag("insecure"),
raw: call.has_flag(engine_state, stack, "raw")?,
insecure: call.has_flag(engine_state, stack, "insecure")?,
user: call.get_flag(engine_state, stack, "user")?,
password: call.get_flag(engine_state, stack, "password")?,
timeout: call.get_flag(engine_state, stack, "max-time")?,
full: call.has_flag("full"),
allow_errors: call.has_flag("allow-errors"),
full: call.has_flag(engine_state, stack, "full")?,
allow_errors: call.has_flag(engine_state, stack, "allow-errors")?,
redirect: call.get_flag(engine_state, stack, "redirect-mode")?,
};

View File

@ -53,7 +53,7 @@ impl Command for SubCommand {
) -> Result<PipelineData, ShellError> {
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let args = CellPathOnlyArgs::from(cell_paths);
if call.has_flag("all") {
if call.has_flag(engine_state, stack, "all")? {
operate(
action_all,
args,

View File

@ -1,6 +1,7 @@
use std::path::Path;
use nu_engine::env::{current_dir_str, current_dir_str_const};
use nu_engine::CallExt;
use nu_path::{canonicalize_with, expand_path_with};
use nu_protocol::ast::Call;
use nu_protocol::engine::{EngineState, Stack, StateWorkingSet};
@ -61,9 +62,9 @@ impl Command for SubCommand {
) -> Result<PipelineData, ShellError> {
let head = call.head;
let args = Arguments {
strict: call.has_flag("strict"),
strict: call.has_flag(engine_state, stack, "strict")?,
cwd: current_dir_str(engine_state, stack)?,
not_follow_symlink: call.has_flag("no-symlink"),
not_follow_symlink: call.has_flag(engine_state, stack, "no-symlink")?,
};
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
@ -83,9 +84,9 @@ impl Command for SubCommand {
) -> Result<PipelineData, ShellError> {
let head = call.head;
let args = Arguments {
strict: call.has_flag("strict"),
strict: call.has_flag_const(working_set, "strict")?,
cwd: current_dir_str_const(working_set)?,
not_follow_symlink: call.has_flag("no-symlink"),
not_follow_symlink: call.has_flag_const(working_set, "no-symlink")?,
};
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {

View File

@ -653,9 +653,9 @@ Operating system commands:
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let list: bool = call.has_flag("list");
let escape: bool = call.has_flag("escape");
let osc: bool = call.has_flag("osc");
let list: bool = call.has_flag(engine_state, stack, "list")?;
let escape: bool = call.has_flag(engine_state, stack, "escape")?;
let osc: bool = call.has_flag(engine_state, stack, "osc")?;
let use_ansi_coloring = engine_state.get_config().use_ansi_coloring;
if list {

View File

@ -98,8 +98,8 @@ impl Command for Du {
let args = DuArgs {
path: call.opt(engine_state, stack, 0)?,
all: call.has_flag("all"),
deref: call.has_flag("deref"),
all: call.has_flag(engine_state, stack, "all")?,
deref: call.has_flag(engine_state, stack, "deref")?,
exclude: call.get_flag(engine_state, stack, "exclude")?,
max_depth,
min_size,

View File

@ -65,7 +65,7 @@ impl Command for Input {
) -> Result<PipelineData, ShellError> {
let prompt: Option<String> = call.opt(engine_state, stack, 0)?;
let bytes_until: Option<String> = call.get_flag(engine_state, stack, "bytes-until-any")?;
let suppress_output = call.has_flag("suppress-output");
let suppress_output = call.has_flag(engine_state, stack, "suppress-output")?;
let numchar: Option<Spanned<i64>> = call.get_flag(engine_state, stack, "numchar")?;
let numchar: Spanned<i64> = numchar.unwrap_or(Spanned {
item: i64::MAX,

View File

@ -85,7 +85,7 @@ There are 4 `key_type` variants:
) -> Result<PipelineData, ShellError> {
let head = call.head;
let event_type_filter = get_event_type_filter(engine_state, stack, call, head)?;
let add_raw = call.has_flag("raw");
let add_raw = call.has_flag(engine_state, stack, "raw")?;
terminal::enable_raw_mode()?;
let console_state = event_type_filter.enable_events()?;

View File

@ -78,6 +78,8 @@ impl Command for InputList {
) -> Result<PipelineData, ShellError> {
let head = call.head;
let prompt: Option<String> = call.opt(engine_state, stack, 0)?;
let multi = call.has_flag(engine_state, stack, "multi")?;
let fuzzy = call.has_flag(engine_state, stack, "fuzzy")?;
let options: Vec<Options> = match input {
PipelineData::Value(Value::Range { .. }, ..)
@ -105,7 +107,7 @@ impl Command for InputList {
});
}
if call.has_flag("multi") && call.has_flag("fuzzy") {
if multi && fuzzy {
return Err(ShellError::TypeMismatch {
err_message: "Fuzzy search is not supported for multi select".to_string(),
span: head,
@ -118,7 +120,7 @@ impl Command for InputList {
// ..Default::default()
// };
let ans: InteractMode = if call.has_flag("multi") {
let ans: InteractMode = if multi {
let multi_select = MultiSelect::new(); //::with_theme(&theme);
InteractMode::Multi(
@ -134,7 +136,7 @@ impl Command for InputList {
msg: format!("{}: {}", INTERACT_ERROR, err),
})?,
)
} else if call.has_flag("fuzzy") {
} else if fuzzy {
let fuzzy_select = FuzzySelect::new(); //::with_theme(&theme);
InteractMode::Single(

View File

@ -1,3 +1,4 @@
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
@ -40,14 +41,14 @@ impl Command for IsTerminal {
fn run(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let stdin = call.has_flag("stdin");
let stdout = call.has_flag("stdout");
let stderr = call.has_flag("stderr");
let stdin = call.has_flag(engine_state, stack, "stdin")?;
let stdout = call.has_flag(engine_state, stack, "stdout")?;
let stderr = call.has_flag(engine_state, stack, "stderr")?;
let is_terminal = match (stdin, stdout, stderr) {
(true, false, false) => std::io::stdin().is_terminal(),

View File

@ -58,9 +58,9 @@ impl Command for Kill {
) -> Result<PipelineData, ShellError> {
let pid: i64 = call.req(engine_state, stack, 0)?;
let rest: Vec<i64> = call.rest(engine_state, stack, 1)?;
let force: bool = call.has_flag("force");
let force: bool = call.has_flag(engine_state, stack, "force")?;
let signal: Option<Spanned<i64>> = call.get_flag(engine_state, stack, "signal")?;
let quiet: bool = call.has_flag("quiet");
let quiet: bool = call.has_flag(engine_state, stack, "quiet")?;
let mut cmd = if cfg!(windows) {
let mut cmd = CommandSys::new("taskkill");

View File

@ -267,12 +267,17 @@ fn limit_to_value(limit: rlim_t, multiplier: rlim_t, span: Span) -> Result<Value
}
/// Get maximum length of all flag descriptions
fn max_desc_len(call: &Call, print_all: bool) -> usize {
fn max_desc_len(
call: &Call,
engine_state: &EngineState,
stack: &mut Stack,
print_all: bool,
) -> Result<usize, ShellError> {
let mut desc_len = 0;
let mut unit_len = 0;
for res in RESOURCE_ARRAY.iter() {
if !print_all && !call.has_flag(res.name) {
if !print_all && !call.has_flag(engine_state, stack, res.name)? {
continue;
}
@ -288,7 +293,7 @@ fn max_desc_len(call: &Call, print_all: bool) -> usize {
}
// desc.len() + unit.len() + '-X)'.len()
desc_len + unit_len + 3
Ok(desc_len + unit_len + 3)
}
/// Fill `ResourceInfo` to the record entry
@ -359,18 +364,20 @@ fn set_limits(
/// Print limits
fn print_limits(
call: &Call,
engine_state: &EngineState,
stack: &mut Stack,
print_all: bool,
soft: bool,
hard: bool,
) -> Result<PipelineData, ShellError> {
let mut output = Vec::new();
let mut print_default_limit = true;
let max_len = max_desc_len(call, print_all);
let max_len = max_desc_len(call, engine_state, stack, print_all)?;
for res in RESOURCE_ARRAY.iter() {
if !print_all {
// Print specified limit.
if !call.has_flag(res.name) {
if !call.has_flag(engine_state, stack, res.name)? {
continue;
}
}
@ -527,9 +534,9 @@ impl Command for ULimit {
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let mut soft = call.has_flag("soft");
let mut hard = call.has_flag("hard");
let all = call.has_flag("all");
let mut soft = call.has_flag(engine_state, stack, "soft")?;
let mut hard = call.has_flag(engine_state, stack, "hard")?;
let all = call.has_flag(engine_state, stack, "all")?;
if !hard && !soft {
// Set both hard and soft limits if neither was specified.
@ -541,7 +548,7 @@ impl Command for ULimit {
let mut set_default_limit = true;
for res in RESOURCE_ARRAY.iter() {
if call.has_flag(res.name) {
if call.has_flag(engine_state, stack, res.name)? {
set_limits(&limit_value, res, soft, hard, call.head)?;
if set_default_limit {
@ -558,7 +565,7 @@ impl Command for ULimit {
Ok(PipelineData::Empty)
} else {
print_limits(call, all, soft, hard)
print_limits(call, engine_state, stack, all, soft, hard)
}
}

View File

@ -229,7 +229,7 @@ impl Command for Char {
) -> Result<PipelineData, ShellError> {
let call_span = call.head;
// handle -l flag
if call.has_flag("list") {
if call.has_flag(engine_state, stack, "list")? {
return Ok(CHAR_MAP
.iter()
.map(move |(name, s)| {
@ -251,7 +251,7 @@ impl Command for Char {
.into_pipeline_data(engine_state.ctrlc.clone()));
}
// handle -u flag
if call.has_flag("integer") {
if call.has_flag(engine_state, stack, "integer")? {
let args: Vec<i64> = call.rest(engine_state, stack, 0)?;
if args.is_empty() {
return Err(ShellError::MissingParameter {
@ -268,7 +268,7 @@ impl Command for Char {
multi_byte.push(integer_to_unicode_char(arg, span)?)
}
Ok(Value::string(multi_byte, call_span).into_pipeline_data())
} else if call.has_flag("unicode") {
} else if call.has_flag(engine_state, stack, "unicode")? {
let args: Vec<String> = call.rest(engine_state, stack, 0)?;
if args.is_empty() {
return Err(ShellError::MissingParameter {

View File

@ -103,7 +103,7 @@ fn detect_columns(
) -> Result<PipelineData, ShellError> {
let name_span = call.head;
let num_rows_to_skip: Option<usize> = call.get_flag(engine_state, stack, "skip")?;
let noheader = call.has_flag("no-headers");
let noheader = call.has_flag(engine_state, stack, "no-headers")?;
let range: Option<Range> = call.get_flag(engine_state, stack, "combine-columns")?;
let ctrlc = engine_state.ctrlc.clone();
let config = engine_state.get_config();

View File

@ -46,7 +46,7 @@ pub fn operate(
let head = call.head;
let character_set: Option<Spanned<String>> =
call.get_flag(engine_state, stack, "character-set")?;
let binary = call.has_flag("binary");
let binary = call.has_flag(engine_state, stack, "binary")?;
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);

View File

@ -83,7 +83,7 @@ documentation link at https://docs.rs/encoding_rs/latest/encoding_rs/#statics"#
) -> Result<PipelineData, ShellError> {
let head = call.head;
let encoding: Spanned<String> = call.req(engine_state, stack, 0)?;
let ignore_errors = call.has_flag("ignore-errors");
let ignore_errors = call.has_flag(engine_state, stack, "ignore-errors")?;
match input {
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::empty()),

View File

@ -53,7 +53,7 @@ impl Command for FormatDate {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
if call.has_flag("list") {
if call.has_flag(engine_state, stack, "list")? {
return Ok(PipelineData::Value(
generate_strftime_list(head, false),
None,

View File

@ -10,26 +10,35 @@ pub use char_::Char;
pub use detect_columns::*;
pub use encode_decode::*;
pub use format::*;
use nu_engine::CallExt;
pub use parse::*;
pub use split::*;
pub use str_::*;
use nu_protocol::{ast::Call, ShellError};
use nu_protocol::{
ast::Call,
engine::{EngineState, Stack, StateWorkingSet},
ShellError,
};
// For handling the grapheme_cluster related flags on some commands.
// This ensures the error messages are consistent.
pub fn grapheme_flags(call: &Call) -> Result<bool, ShellError> {
let g_flag = call.has_flag("grapheme-clusters");
pub fn grapheme_flags(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
) -> Result<bool, ShellError> {
let g_flag = call.has_flag(engine_state, stack, "grapheme-clusters")?;
// Check for the other flags and produce errors if they exist.
// Note that Nushell already prevents nonexistent flags from being used with commands,
// so this function can be reused for both the --utf-8-bytes commands and the --code-points commands.
if g_flag && call.has_flag("utf-8-bytes") {
if g_flag && call.has_flag(engine_state, stack, "utf-8-bytes")? {
Err(ShellError::IncompatibleParametersSingle {
msg: "Incompatible flags: --grapheme-clusters (-g) and --utf-8-bytes (-b)".to_string(),
span: call.head,
})?
}
if g_flag && call.has_flag("code-points") {
if g_flag && call.has_flag(engine_state, stack, "code-points")? {
Err(ShellError::IncompatibleParametersSingle {
msg: "Incompatible flags: --grapheme-clusters (-g) and --utf-8-bytes (-b)".to_string(),
span: call.head,
@ -38,3 +47,24 @@ pub fn grapheme_flags(call: &Call) -> Result<bool, ShellError> {
// Grapheme cluster usage is decided by the non-default -g flag
Ok(g_flag)
}
// Const version of grapheme_flags
pub fn grapheme_flags_const(
working_set: &StateWorkingSet,
call: &Call,
) -> Result<bool, ShellError> {
let g_flag = call.has_flag_const(working_set, "grapheme-clusters")?;
if g_flag && call.has_flag_const(working_set, "utf-8-bytes")? {
Err(ShellError::IncompatibleParametersSingle {
msg: "Incompatible flags: --grapheme-clusters (-g) and --utf-8-bytes (-b)".to_string(),
span: call.head,
})?
}
if g_flag && call.has_flag_const(working_set, "code-points")? {
Err(ShellError::IncompatibleParametersSingle {
msg: "Incompatible flags: --grapheme-clusters (-g) and --utf-8-bytes (-b)".to_string(),
span: call.head,
})?
}
Ok(g_flag)
}

View File

@ -122,7 +122,7 @@ fn operate(
) -> Result<PipelineData, ShellError> {
let head = call.head;
let pattern: Spanned<String> = call.req(engine_state, stack, 0)?;
let regex: bool = call.has_flag("regex");
let regex: bool = call.has_flag(engine_state, stack, "regex")?;
let ctrlc = engine_state.ctrlc.clone();
let pattern_item = pattern.item;

View File

@ -95,22 +95,23 @@ impl Command for SubCommand {
fn run(
&self,
engine_state: &EngineState,
_stack: &mut Stack,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
split_chars(engine_state, call, input)
split_chars(engine_state, stack, call, input)
}
}
fn split_chars(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let span = call.head;
let graphemes = grapheme_flags(call)?;
let graphemes = grapheme_flags(engine_state, stack, call)?;
input.map(
move |x| split_chars_helper(&x, span, graphemes),
engine_state.ctrlc.clone(),

View File

@ -119,9 +119,9 @@ fn split_column(
let name_span = call.head;
let separator: Spanned<String> = call.req(engine_state, stack, 0)?;
let rest: Vec<Spanned<String>> = call.rest(engine_state, stack, 1)?;
let collapse_empty = call.has_flag("collapse-empty");
let collapse_empty = call.has_flag(engine_state, stack, "collapse-empty")?;
let regex = if call.has_flag("regex") {
let regex = if call.has_flag(engine_state, stack, "regex")? {
Regex::new(&separator.item)
} else {
let escaped = regex::escape(&separator.item);

View File

@ -202,7 +202,7 @@ fn split_list(
let mut returned_list = Vec::new();
let iter = input.into_interruptible_iter(engine_state.ctrlc.clone());
let matcher = Matcher::new(call.has_flag("regex"), separator)?;
let matcher = Matcher::new(call.has_flag(engine_state, stack, "regex")?, separator)?;
for val in iter {
if matcher.compare(&val)? {
if !temp_list.is_empty() {

View File

@ -123,7 +123,7 @@ fn split_row(
) -> Result<PipelineData, ShellError> {
let name_span = call.head;
let separator: Spanned<String> = call.req(engine_state, stack, 0)?;
let regex = if call.has_flag("regex") {
let regex = if call.has_flag(engine_state, stack, "regex")? {
Regex::new(&separator.item)
} else {
let escaped = regex::escape(&separator.item);

View File

@ -118,26 +118,26 @@ fn split_words(
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let span = call.head;
// let ignore_hyphenated = call.has_flag("ignore-hyphenated");
// let ignore_apostrophes = call.has_flag("ignore-apostrophes");
// let ignore_punctuation = call.has_flag("ignore-punctuation");
// let ignore_hyphenated = call.has_flag(engine_state, stack, "ignore-hyphenated")?;
// let ignore_apostrophes = call.has_flag(engine_state, stack, "ignore-apostrophes")?;
// let ignore_punctuation = call.has_flag(engine_state, stack, "ignore-punctuation")?;
let word_length: Option<usize> = call.get_flag(engine_state, stack, "min-word-length")?;
if word_length.is_none() {
if call.has_flag("grapheme-clusters") {
if call.has_flag(engine_state, stack, "grapheme-clusters")? {
return Err(ShellError::IncompatibleParametersSingle {
msg: "--grapheme-clusters (-g) requires --min-word-length (-l)".to_string(),
span,
});
}
if call.has_flag("utf-8-bytes") {
if call.has_flag(engine_state, stack, "utf-8-bytes")? {
return Err(ShellError::IncompatibleParametersSingle {
msg: "--utf-8-bytes (-b) requires --min-word-length (-l)".to_string(),
span,
});
}
}
let graphemes = grapheme_flags(call)?;
let graphemes = grapheme_flags(engine_state, stack, call)?;
input.map(
move |x| split_words_helper(&x, word_length, span, graphemes),

View File

@ -70,8 +70,8 @@ impl Command for SubCommand {
let args = Arguments {
substring: call.req::<String>(engine_state, stack, 0)?,
cell_paths,
case_insensitive: call.has_flag("ignore-case"),
not_contain: call.has_flag("not"),
case_insensitive: call.has_flag(engine_state, stack, "ignore-case")?,
not_contain: call.has_flag(engine_state, stack, "not")?,
};
operate(action, args, input, call.head, engine_state.ctrlc.clone())
}

View File

@ -66,7 +66,7 @@ impl Command for SubCommand {
let args = Arguments {
substring: call.req::<String>(engine_state, stack, 0)?,
cell_paths,
case_insensitive: call.has_flag("ignore-case"),
case_insensitive: call.has_flag(engine_state, stack, "ignore-case")?,
};
operate(action, args, input, call.head, engine_state.ctrlc.clone())
}

View File

@ -1,3 +1,4 @@
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
@ -186,7 +187,7 @@ impl Command for SubCommand {
fn run(
&self,
engine_state: &EngineState,
_stack: &mut Stack,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
@ -194,7 +195,7 @@ impl Command for SubCommand {
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty { dst_span: span });
}
let is_path = call.has_flag("path");
let is_path = call.has_flag(engine_state, stack, "path")?;
input.map(
move |v| {
let value_span = v.span();

View File

@ -91,9 +91,9 @@ impl Command for SubCommand {
let args = Arguments {
substring: substring.item,
range: call.get_flag(engine_state, stack, "range")?,
end: call.has_flag("end"),
end: call.has_flag(engine_state, stack, "end")?,
cell_paths,
graphemes: grapheme_flags(call)?,
graphemes: grapheme_flags(engine_state, stack, call)?,
};
operate(action, args, input, call.head, engine_state.ctrlc.clone())
}

View File

@ -1,4 +1,5 @@
use crate::grapheme_flags;
use crate::grapheme_flags_const;
use nu_cmd_base::input_handler::{operate, CmdArgument};
use nu_engine::CallExt;
use nu_protocol::ast::Call;
@ -74,7 +75,13 @@ impl Command for SubCommand {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
run(cell_paths, engine_state, call, input)
run(
cell_paths,
engine_state,
call,
input,
grapheme_flags(engine_state, stack, call)?,
)
}
fn run_const(
@ -84,7 +91,13 @@ impl Command for SubCommand {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let cell_paths: Vec<CellPath> = call.rest_const(working_set, 0)?;
run(cell_paths, working_set.permanent(), call, input)
run(
cell_paths,
working_set.permanent(),
call,
input,
grapheme_flags_const(working_set, call)?,
)
}
fn examples(&self) -> Vec<Example> {
@ -116,10 +129,11 @@ fn run(
engine_state: &EngineState,
call: &Call,
input: PipelineData,
graphemes: bool,
) -> Result<PipelineData, ShellError> {
let args = Arguments {
cell_paths: (!cell_paths.is_empty()).then_some(cell_paths),
graphemes: grapheme_flags(call)?,
graphemes,
};
operate(action, args, input, call.head, engine_state.ctrlc.clone())
}

View File

@ -90,12 +90,13 @@ impl Command for SubCommand {
let replace: Spanned<String> = call.req(engine_state, stack, 1)?;
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 2)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let literal_replace = call.has_flag("no-expand");
let no_regex = !call.has_flag("regex") && !call.has_flag("multiline");
let multiline = call.has_flag("multiline");
let literal_replace = call.has_flag(engine_state, stack, "no-expand")?;
let no_regex = !call.has_flag(engine_state, stack, "regex")?
&& !call.has_flag(engine_state, stack, "multiline")?;
let multiline = call.has_flag(engine_state, stack, "multiline")?;
let args = Arguments {
all: call.has_flag("all"),
all: call.has_flag(engine_state, stack, "all")?,
find,
replace,
cell_paths,

View File

@ -69,7 +69,7 @@ impl Command for SubCommand {
let args = Arguments {
substring: substring.item,
cell_paths,
case_insensitive: call.has_flag("ignore-case"),
case_insensitive: call.has_flag(engine_state, stack, "ignore-case")?,
};
operate(action, args, input, call.head, engine_state.ctrlc.clone())
}

View File

@ -102,7 +102,7 @@ impl Command for SubCommand {
let args = Arguments {
indexes,
cell_paths,
graphemes: grapheme_flags(call)?,
graphemes: grapheme_flags(engine_state, stack, call)?,
};
operate(action, args, input, call.head, engine_state.ctrlc.clone())
}

View File

@ -107,8 +107,8 @@ impl Command for SubCommand {
Some(_) => ActionMode::Local,
};
let left = call.has_flag("left");
let right = call.has_flag("right");
let left = call.has_flag(engine_state, stack, "left")?;
let right = call.has_flag(engine_state, stack, "right")?;
let trim_side = match (left, right) {
(true, true) => TrimSide::Both,
(true, false) => TrimSide::Left,

View File

@ -43,9 +43,9 @@ impl Command for NuCheck {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let path: Option<Spanned<String>> = call.opt(engine_state, stack, 0)?;
let is_module = call.has_flag("as-module");
let is_debug = call.has_flag("debug");
let is_all = call.has_flag("all");
let is_module = call.has_flag(engine_state, stack, "as-module")?;
let is_debug = call.has_flag(engine_state, stack, "debug")?;
let is_all = call.has_flag(engine_state, stack, "all")?;
let config = engine_state.get_config();
let mut contents = vec![];

View File

@ -1,5 +1,6 @@
#[cfg(windows)]
use itertools::Itertools;
use nu_engine::CallExt;
#[cfg(all(
unix,
not(target_os = "macos"),
@ -54,11 +55,11 @@ impl Command for Ps {
fn run(
&self,
engine_state: &EngineState,
_stack: &mut Stack,
stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
run_ps(engine_state, call)
run_ps(engine_state, stack, call)
}
fn examples(&self) -> Vec<Example> {
@ -92,10 +93,14 @@ impl Command for Ps {
}
}
fn run_ps(engine_state: &EngineState, call: &Call) -> Result<PipelineData, ShellError> {
fn run_ps(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
) -> Result<PipelineData, ShellError> {
let mut output = vec![];
let span = call.head;
let long = call.has_flag("long");
let long = call.has_flag(engine_state, stack, "long")?;
for proc in nu_system::collect_proc(Duration::from_millis(100), false) {
let mut record = Record::new();

View File

@ -88,13 +88,13 @@ fn registry_query(
) -> Result<PipelineData, ShellError> {
let call_span = call.head;
let skip_expand = call.has_flag("no-expand");
let skip_expand = call.has_flag(engine_state, stack, "no-expand")?;
let registry_key: Spanned<String> = call.req(engine_state, stack, 0)?;
let registry_key_span = &registry_key.clone().span;
let registry_value: Option<Spanned<String>> = call.opt(engine_state, stack, 1)?;
let reg_hive = get_reg_hive(call)?;
let reg_hive = get_reg_hive(engine_state, stack, call)?;
let reg_key = reg_hive.open_subkey(registry_key.item)?;
if registry_value.is_none() {
@ -144,14 +144,22 @@ fn registry_query(
}
}
fn get_reg_hive(call: &Call) -> Result<RegKey, ShellError> {
let flags: Vec<_> = [
fn get_reg_hive(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
) -> Result<RegKey, ShellError> {
let flags = [
"hkcr", "hkcu", "hklm", "hku", "hkpd", "hkpt", "hkpnls", "hkcc", "hkdd", "hkculs",
]
.iter()
.copied()
.filter(|flag| call.has_flag(flag))
.collect();
.filter_map(|flag| match call.has_flag(engine_state, stack, flag) {
Ok(true) => Some(Ok(flag)),
Ok(false) => None,
Err(e) => Some(Err(e)),
})
.collect::<Result<Vec<_>, ShellError>>()?;
if flags.len() > 1 {
return Err(ShellError::GenericError {
error: "Only one registry key can be specified".into(),

View File

@ -60,10 +60,10 @@ impl Command for External {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let redirect_stdout = call.has_flag("redirect-stdout");
let redirect_stderr = call.has_flag("redirect-stderr");
let redirect_combine = call.has_flag("redirect-combine");
let trim_end_newline = call.has_flag("trim-end-newline");
let redirect_stdout = call.has_flag(engine_state, stack, "redirect-stdout")?;
let redirect_stderr = call.has_flag(engine_state, stack, "redirect-stderr")?;
let redirect_combine = call.has_flag(engine_state, stack, "redirect-combine")?;
let trim_end_newline = call.has_flag(engine_state, stack, "trim-end-newline")?;
if redirect_combine && (redirect_stdout || redirect_stderr) {
return Err(ShellError::ExternalCommand {

Some files were not shown because too many files have changed in this diff Show More