mirror of
https://github.com/nushell/nushell.git
synced 2024-11-07 17:14:23 +01:00
Remove the Value::Block
case (#12582)
# Description `Value` describes the types of first-class values that users and scripts can create, manipulate, pass around, and store. However, `Block`s are not first-class values in the language, so this PR removes it from `Value`. This removes some unnecessary code, and this change should be invisible to the user except for the change to `scope modules` described below. # User-Facing Changes Breaking change: the output of `scope modules` was changed so that `env_block` is now `has_env_block` which is a boolean value instead of a `Block`. # After Submitting Update the language guide possibly.
This commit is contained in:
parent
5fd34320e9
commit
3b1d405b96
@ -7,8 +7,8 @@ use nu_engine::eval_block;
|
|||||||
use nu_parser::{flatten_pipeline_element, parse, FlatShape};
|
use nu_parser::{flatten_pipeline_element, parse, FlatShape};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
debugger::WithoutDebug,
|
debugger::WithoutDebug,
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{Closure, EngineState, Stack, StateWorkingSet},
|
||||||
BlockId, PipelineData, Span, Value,
|
PipelineData, Span, Value,
|
||||||
};
|
};
|
||||||
use reedline::{Completer as ReedlineCompleter, Suggestion};
|
use reedline::{Completer as ReedlineCompleter, Suggestion};
|
||||||
use std::{str, sync::Arc};
|
use std::{str, sync::Arc};
|
||||||
@ -63,15 +63,15 @@ impl NuCompleter {
|
|||||||
|
|
||||||
fn external_completion(
|
fn external_completion(
|
||||||
&self,
|
&self,
|
||||||
block_id: BlockId,
|
closure: &Closure,
|
||||||
spans: &[String],
|
spans: &[String],
|
||||||
offset: usize,
|
offset: usize,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Option<Vec<SemanticSuggestion>> {
|
) -> Option<Vec<SemanticSuggestion>> {
|
||||||
let block = self.engine_state.get_block(block_id);
|
let block = self.engine_state.get_block(closure.block_id);
|
||||||
let mut callee_stack = self
|
let mut callee_stack = self
|
||||||
.stack
|
.stack
|
||||||
.gather_captures(&self.engine_state, &block.captures);
|
.captures_to_stack_preserve_out_dest(closure.captures.clone());
|
||||||
|
|
||||||
// Line
|
// Line
|
||||||
if let Some(pos_arg) = block.signature.required_positional.first() {
|
if let Some(pos_arg) = block.signature.required_positional.first() {
|
||||||
@ -210,13 +210,10 @@ impl NuCompleter {
|
|||||||
|
|
||||||
// We got no results for internal completion
|
// We got no results for internal completion
|
||||||
// now we can check if external completer is set and use it
|
// now we can check if external completer is set and use it
|
||||||
if let Some(block_id) = config.external_completer {
|
if let Some(closure) = config.external_completer.as_ref() {
|
||||||
if let Some(external_result) = self.external_completion(
|
if let Some(external_result) =
|
||||||
block_id,
|
self.external_completion(closure, &spans, fake_offset, new_span)
|
||||||
&spans,
|
{
|
||||||
fake_offset,
|
|
||||||
new_span,
|
|
||||||
) {
|
|
||||||
return external_result;
|
return external_result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -360,9 +357,9 @@ impl NuCompleter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try to complete using an external completer (if set)
|
// Try to complete using an external completer (if set)
|
||||||
if let Some(block_id) = config.external_completer {
|
if let Some(closure) = config.external_completer.as_ref() {
|
||||||
if let Some(external_result) = self.external_completion(
|
if let Some(external_result) = self.external_completion(
|
||||||
block_id,
|
closure,
|
||||||
&spans,
|
&spans,
|
||||||
fake_offset,
|
fake_offset,
|
||||||
new_span,
|
new_span,
|
||||||
|
@ -59,24 +59,6 @@ fn get_prompt_string(
|
|||||||
})
|
})
|
||||||
.ok()
|
.ok()
|
||||||
}
|
}
|
||||||
Value::Block { val: block_id, .. } => {
|
|
||||||
let block = engine_state.get_block(block_id);
|
|
||||||
// Use eval_subexpression to force a redirection of output, so we can use everything in prompt
|
|
||||||
let ret_val = eval_subexpression(engine_state, stack, block, PipelineData::empty());
|
|
||||||
trace!(
|
|
||||||
"get_prompt_string (block) {}:{}:{}",
|
|
||||||
file!(),
|
|
||||||
line!(),
|
|
||||||
column!()
|
|
||||||
);
|
|
||||||
|
|
||||||
ret_val
|
|
||||||
.map_err(|err| {
|
|
||||||
let working_set = StateWorkingSet::new(engine_state);
|
|
||||||
report_error(&working_set, &err);
|
|
||||||
})
|
|
||||||
.ok()
|
|
||||||
}
|
|
||||||
Value::String { .. } => Some(PipelineData::Value(v.clone(), None)),
|
Value::String { .. } => Some(PipelineData::Value(v.clone(), None)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
pub mod support;
|
pub mod support;
|
||||||
|
|
||||||
use nu_cli::NuCompleter;
|
use nu_cli::NuCompleter;
|
||||||
|
use nu_engine::eval_block;
|
||||||
use nu_parser::parse;
|
use nu_parser::parse;
|
||||||
use nu_protocol::engine::StateWorkingSet;
|
use nu_protocol::{debugger::WithoutDebug, engine::StateWorkingSet, PipelineData};
|
||||||
use reedline::{Completer, Suggestion};
|
use reedline::{Completer, Suggestion};
|
||||||
use rstest::{fixture, rstest};
|
use rstest::{fixture, rstest};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -177,7 +178,7 @@ fn dotnu_completions() {
|
|||||||
#[ignore]
|
#[ignore]
|
||||||
fn external_completer_trailing_space() {
|
fn external_completer_trailing_space() {
|
||||||
// https://github.com/nushell/nushell/issues/6378
|
// https://github.com/nushell/nushell/issues/6378
|
||||||
let block = "let external_completer = {|spans| $spans}";
|
let block = "{|spans| $spans}";
|
||||||
let input = "gh alias ".to_string();
|
let input = "gh alias ".to_string();
|
||||||
|
|
||||||
let suggestions = run_external_completion(block, &input);
|
let suggestions = run_external_completion(block, &input);
|
||||||
@ -847,12 +848,14 @@ fn alias_of_another_alias() {
|
|||||||
match_suggestions(expected_paths, suggestions)
|
match_suggestions(expected_paths, suggestions)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_external_completion(block: &str, input: &str) -> Vec<Suggestion> {
|
fn run_external_completion(completer: &str, input: &str) -> Vec<Suggestion> {
|
||||||
|
let completer = format!("$env.config.completions.external.completer = {completer}");
|
||||||
|
|
||||||
// Create a new engine
|
// Create a new engine
|
||||||
let (dir, _, mut engine_state, mut stack) = new_engine();
|
let (dir, _, mut engine_state, mut stack) = new_engine();
|
||||||
let (_, delta) = {
|
let (block, delta) = {
|
||||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
let block = parse(&mut working_set, None, block.as_bytes(), false);
|
let block = parse(&mut working_set, None, completer.as_bytes(), false);
|
||||||
assert!(working_set.parse_errors.is_empty());
|
assert!(working_set.parse_errors.is_empty());
|
||||||
|
|
||||||
(block, working_set.render())
|
(block, working_set.render())
|
||||||
@ -860,16 +863,13 @@ fn run_external_completion(block: &str, input: &str) -> Vec<Suggestion> {
|
|||||||
|
|
||||||
assert!(engine_state.merge_delta(delta).is_ok());
|
assert!(engine_state.merge_delta(delta).is_ok());
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
eval_block::<WithoutDebug>(&engine_state, &mut stack, &block, PipelineData::Empty).is_ok()
|
||||||
|
);
|
||||||
|
|
||||||
// Merge environment into the permanent state
|
// Merge environment into the permanent state
|
||||||
assert!(engine_state.merge_env(&mut stack, &dir).is_ok());
|
assert!(engine_state.merge_env(&mut stack, &dir).is_ok());
|
||||||
|
|
||||||
let latest_block_id = engine_state.num_blocks() - 1;
|
|
||||||
|
|
||||||
// Change config adding the external completer
|
|
||||||
let mut config = engine_state.get_config().clone();
|
|
||||||
config.external_completer = Some(latest_block_id);
|
|
||||||
engine_state.set_config(config);
|
|
||||||
|
|
||||||
// Instantiate a new completer
|
// Instantiate a new completer
|
||||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine_state), stack);
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine_state), stack);
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@ use nu_parser::parse;
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
cli_error::{report_error, report_error_new},
|
cli_error::{report_error, report_error_new},
|
||||||
debugger::WithoutDebug,
|
debugger::WithoutDebug,
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{Closure, EngineState, Stack, StateWorkingSet},
|
||||||
BlockId, PipelineData, PositionalArg, ShellError, Span, Type, Value, VarId,
|
PipelineData, PositionalArg, ShellError, Span, Type, Value, VarId,
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@ -153,11 +153,11 @@ pub fn eval_hook(
|
|||||||
// If it returns true (the default if a condition block is not specified), the hook should be run.
|
// If it returns true (the default if a condition block is not specified), the hook should be run.
|
||||||
let do_run_hook = if let Some(condition) = val.get("condition") {
|
let do_run_hook = if let Some(condition) = val.get("condition") {
|
||||||
let other_span = condition.span();
|
let other_span = condition.span();
|
||||||
if let Ok(block_id) = condition.coerce_block() {
|
if let Ok(closure) = condition.as_closure() {
|
||||||
match run_hook_block(
|
match run_hook(
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
block_id,
|
closure,
|
||||||
None,
|
None,
|
||||||
arguments.clone(),
|
arguments.clone(),
|
||||||
other_span,
|
other_span,
|
||||||
@ -259,25 +259,8 @@ pub fn eval_hook(
|
|||||||
stack.remove_var(*var_id);
|
stack.remove_var(*var_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::Block { val: block_id, .. } => {
|
|
||||||
run_hook_block(
|
|
||||||
engine_state,
|
|
||||||
stack,
|
|
||||||
*block_id,
|
|
||||||
input,
|
|
||||||
arguments,
|
|
||||||
source_span,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
Value::Closure { val, .. } => {
|
Value::Closure { val, .. } => {
|
||||||
run_hook_block(
|
run_hook(engine_state, stack, val, input, arguments, source_span)?;
|
||||||
engine_state,
|
|
||||||
stack,
|
|
||||||
val.block_id,
|
|
||||||
input,
|
|
||||||
arguments,
|
|
||||||
source_span,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
return Err(ShellError::UnsupportedConfigValue {
|
return Err(ShellError::UnsupportedConfigValue {
|
||||||
@ -289,11 +272,8 @@ pub fn eval_hook(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::Block { val: block_id, .. } => {
|
|
||||||
output = run_hook_block(engine_state, stack, *block_id, input, arguments, span)?;
|
|
||||||
}
|
|
||||||
Value::Closure { val, .. } => {
|
Value::Closure { val, .. } => {
|
||||||
output = run_hook_block(engine_state, stack, val.block_id, input, arguments, span)?;
|
output = run_hook(engine_state, stack, val, input, arguments, span)?;
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
return Err(ShellError::UnsupportedConfigValue {
|
return Err(ShellError::UnsupportedConfigValue {
|
||||||
@ -310,20 +290,20 @@ pub fn eval_hook(
|
|||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_hook_block(
|
fn run_hook(
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
block_id: BlockId,
|
closure: &Closure,
|
||||||
optional_input: Option<PipelineData>,
|
optional_input: Option<PipelineData>,
|
||||||
arguments: Vec<(String, Value)>,
|
arguments: Vec<(String, Value)>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let block = engine_state.get_block(block_id);
|
let block = engine_state.get_block(closure.block_id);
|
||||||
|
|
||||||
let input = optional_input.unwrap_or_else(PipelineData::empty);
|
let input = optional_input.unwrap_or_else(PipelineData::empty);
|
||||||
|
|
||||||
let mut callee_stack = stack
|
let mut callee_stack = stack
|
||||||
.gather_captures(engine_state, &block.captures)
|
.captures_to_stack_preserve_out_dest(closure.captures.clone())
|
||||||
.reset_pipes();
|
.reset_pipes();
|
||||||
|
|
||||||
for (idx, PositionalArg { var_id, .. }) in
|
for (idx, PositionalArg { var_id, .. }) in
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::{
|
use nu_protocol::{engine::StateWorkingSet, PipelineMetadata};
|
||||||
engine::{Closure, StateWorkingSet},
|
|
||||||
PipelineMetadata,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Describe;
|
pub struct Describe;
|
||||||
@ -336,16 +333,12 @@ fn describe_value(
|
|||||||
),
|
),
|
||||||
head,
|
head,
|
||||||
),
|
),
|
||||||
Value::Block { val, .. }
|
Value::Closure { val, .. } => {
|
||||||
| Value::Closure {
|
let block = engine_state.map(|engine_state| engine_state.get_block(val.block_id));
|
||||||
val: Closure { block_id: val, .. },
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
let block = engine_state.map(|engine_state| engine_state.get_block(val));
|
|
||||||
|
|
||||||
if let Some(block) = block {
|
if let Some(block) = block {
|
||||||
let mut record = Record::new();
|
let mut record = Record::new();
|
||||||
record.push("type", Value::string(value.get_type().to_string(), head));
|
record.push("type", Value::string("closure", head));
|
||||||
record.push(
|
record.push(
|
||||||
"signature",
|
"signature",
|
||||||
Value::record(
|
Value::record(
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use nu_engine::{command_prelude::*, get_eval_block, get_eval_expression};
|
use nu_engine::{command_prelude::*, get_eval_block, get_eval_expression};
|
||||||
use nu_protocol::{engine::Block, ListStream};
|
use nu_protocol::ListStream;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct For;
|
pub struct For;
|
||||||
@ -66,18 +66,22 @@ impl Command for For {
|
|||||||
.as_keyword()
|
.as_keyword()
|
||||||
.expect("internal error: missing keyword");
|
.expect("internal error: missing keyword");
|
||||||
|
|
||||||
|
let block_id = call
|
||||||
|
.positional_nth(2)
|
||||||
|
.expect("checked through parser")
|
||||||
|
.as_block()
|
||||||
|
.expect("internal error: missing block");
|
||||||
|
|
||||||
let eval_expression = get_eval_expression(engine_state);
|
let eval_expression = get_eval_expression(engine_state);
|
||||||
let eval_block = get_eval_block(engine_state);
|
let eval_block = get_eval_block(engine_state);
|
||||||
|
|
||||||
let value = eval_expression(engine_state, stack, keyword_expr)?;
|
let value = eval_expression(engine_state, stack, keyword_expr)?;
|
||||||
|
|
||||||
let block: Block = call.req(engine_state, stack, 2)?;
|
|
||||||
|
|
||||||
let numbered = call.has_flag(engine_state, stack, "numbered")?;
|
let numbered = call.has_flag(engine_state, stack, "numbered")?;
|
||||||
|
|
||||||
let ctrlc = engine_state.ctrlc.clone();
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
let engine_state = engine_state.clone();
|
let engine_state = engine_state.clone();
|
||||||
let block = engine_state.get_block(block.block_id).clone();
|
let block = engine_state.get_block(block_id);
|
||||||
|
|
||||||
let stack = &mut stack.push_redirection(None, None);
|
let stack = &mut stack.push_redirection(None, None);
|
||||||
|
|
||||||
@ -104,7 +108,7 @@ impl Command for For {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
match eval_block(&engine_state, stack, &block, PipelineData::empty()) {
|
match eval_block(&engine_state, stack, block, PipelineData::empty()) {
|
||||||
Err(ShellError::Break { .. }) => {
|
Err(ShellError::Break { .. }) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -142,7 +146,7 @@ impl Command for For {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
match eval_block(&engine_state, stack, &block, PipelineData::empty()) {
|
match eval_block(&engine_state, stack, block, PipelineData::empty()) {
|
||||||
Err(ShellError::Break { .. }) => {
|
Err(ShellError::Break { .. }) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -166,7 +170,7 @@ impl Command for For {
|
|||||||
x => {
|
x => {
|
||||||
stack.add_var(var_id, x);
|
stack.add_var(var_id, x);
|
||||||
|
|
||||||
eval_block(&engine_state, stack, &block, PipelineData::empty())?.into_value(head);
|
eval_block(&engine_state, stack, block, PipelineData::empty())?.into_value(head);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(PipelineData::empty())
|
Ok(PipelineData::empty())
|
||||||
|
@ -2,7 +2,7 @@ use nu_engine::{
|
|||||||
command_prelude::*, get_eval_block, get_eval_expression, get_eval_expression_with_input,
|
command_prelude::*, get_eval_block, get_eval_expression, get_eval_expression_with_input,
|
||||||
};
|
};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{Block, StateWorkingSet},
|
engine::StateWorkingSet,
|
||||||
eval_const::{eval_const_subexpression, eval_constant, eval_constant_with_input},
|
eval_const::{eval_const_subexpression, eval_constant, eval_constant_with_input},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,14 +52,18 @@ impl Command for If {
|
|||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let cond = call.positional_nth(0).expect("checked through parser");
|
let cond = call.positional_nth(0).expect("checked through parser");
|
||||||
let then_block: Block = call.req_const(working_set, 1)?;
|
let then_block = call
|
||||||
|
.positional_nth(1)
|
||||||
|
.expect("checked through parser")
|
||||||
|
.as_block()
|
||||||
|
.expect("internal error: missing block");
|
||||||
let else_case = call.positional_nth(2);
|
let else_case = call.positional_nth(2);
|
||||||
|
|
||||||
let result = eval_constant(working_set, cond)?;
|
let result = eval_constant(working_set, cond)?;
|
||||||
match &result {
|
match &result {
|
||||||
Value::Bool { val, .. } => {
|
Value::Bool { val, .. } => {
|
||||||
if *val {
|
if *val {
|
||||||
let block = working_set.get_block(then_block.block_id);
|
let block = working_set.get_block(then_block);
|
||||||
eval_const_subexpression(
|
eval_const_subexpression(
|
||||||
working_set,
|
working_set,
|
||||||
block,
|
block,
|
||||||
@ -103,8 +107,13 @@ impl Command for If {
|
|||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let cond = call.positional_nth(0).expect("checked through parser");
|
let cond = call.positional_nth(0).expect("checked through parser");
|
||||||
let then_block: Block = call.req(engine_state, stack, 1)?;
|
let then_block = call
|
||||||
|
.positional_nth(1)
|
||||||
|
.expect("checked through parser")
|
||||||
|
.as_block()
|
||||||
|
.expect("internal error: missing block");
|
||||||
let else_case = call.positional_nth(2);
|
let else_case = call.positional_nth(2);
|
||||||
|
|
||||||
let eval_expression = get_eval_expression(engine_state);
|
let eval_expression = get_eval_expression(engine_state);
|
||||||
let eval_expression_with_input = get_eval_expression_with_input(engine_state);
|
let eval_expression_with_input = get_eval_expression_with_input(engine_state);
|
||||||
let eval_block = get_eval_block(engine_state);
|
let eval_block = get_eval_block(engine_state);
|
||||||
@ -113,7 +122,7 @@ impl Command for If {
|
|||||||
match &result {
|
match &result {
|
||||||
Value::Bool { val, .. } => {
|
Value::Bool { val, .. } => {
|
||||||
if *val {
|
if *val {
|
||||||
let block = engine_state.get_block(then_block.block_id);
|
let block = engine_state.get_block(then_block);
|
||||||
eval_block(engine_state, stack, block, input)
|
eval_block(engine_state, stack, block, input)
|
||||||
} else if let Some(else_case) = else_case {
|
} else if let Some(else_case) = else_case {
|
||||||
if let Some(else_expr) = else_case.as_keyword() {
|
if let Some(else_expr) = else_case.as_keyword() {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use nu_engine::{command_prelude::*, get_eval_block};
|
use nu_engine::{command_prelude::*, get_eval_block};
|
||||||
use nu_protocol::engine::Block;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Loop;
|
pub struct Loop;
|
||||||
@ -28,7 +27,13 @@ impl Command for Loop {
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let block: Block = call.req(engine_state, stack, 0)?;
|
let block_id = call
|
||||||
|
.positional_nth(0)
|
||||||
|
.expect("checked through parser")
|
||||||
|
.as_block()
|
||||||
|
.expect("internal error: missing block");
|
||||||
|
|
||||||
|
let block = engine_state.get_block(block_id);
|
||||||
let eval_block = get_eval_block(engine_state);
|
let eval_block = get_eval_block(engine_state);
|
||||||
|
|
||||||
let stack = &mut stack.push_redirection(None, None);
|
let stack = &mut stack.push_redirection(None, None);
|
||||||
@ -38,8 +43,6 @@ impl Command for Loop {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let block = engine_state.get_block(block.block_id);
|
|
||||||
|
|
||||||
match eval_block(engine_state, stack, block, PipelineData::empty()) {
|
match eval_block(engine_state, stack, block, PipelineData::empty()) {
|
||||||
Err(ShellError::Break { .. }) => {
|
Err(ShellError::Break { .. }) => {
|
||||||
break;
|
break;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use nu_engine::{command_prelude::*, get_eval_block, EvalBlockFn};
|
use nu_engine::{command_prelude::*, get_eval_block, EvalBlockFn};
|
||||||
use nu_protocol::engine::{Block, Closure};
|
use nu_protocol::engine::Closure;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Try;
|
pub struct Try;
|
||||||
@ -38,10 +38,15 @@ impl Command for Try {
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let try_block: Block = call.req(engine_state, stack, 0)?;
|
let try_block = call
|
||||||
|
.positional_nth(0)
|
||||||
|
.expect("checked through parser")
|
||||||
|
.as_block()
|
||||||
|
.expect("internal error: missing block");
|
||||||
|
|
||||||
let catch_block: Option<Closure> = call.opt(engine_state, stack, 1)?;
|
let catch_block: Option<Closure> = call.opt(engine_state, stack, 1)?;
|
||||||
|
|
||||||
let try_block = engine_state.get_block(try_block.block_id);
|
let try_block = engine_state.get_block(try_block);
|
||||||
let eval_block = get_eval_block(engine_state);
|
let eval_block = get_eval_block(engine_state);
|
||||||
|
|
||||||
let result = eval_block(engine_state, stack, try_block, input);
|
let result = eval_block(engine_state, stack, try_block, input);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use nu_engine::{command_prelude::*, get_eval_block, get_eval_expression};
|
use nu_engine::{command_prelude::*, get_eval_block, get_eval_expression};
|
||||||
use nu_protocol::engine::Block;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct While;
|
pub struct While;
|
||||||
@ -38,7 +37,11 @@ impl Command for While {
|
|||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let cond = call.positional_nth(0).expect("checked through parser");
|
let cond = call.positional_nth(0).expect("checked through parser");
|
||||||
let block: Block = call.req(engine_state, stack, 1)?;
|
let block_id = call
|
||||||
|
.positional_nth(1)
|
||||||
|
.expect("checked through parser")
|
||||||
|
.as_block()
|
||||||
|
.expect("internal error: missing block");
|
||||||
|
|
||||||
let eval_expression = get_eval_expression(engine_state);
|
let eval_expression = get_eval_expression(engine_state);
|
||||||
let eval_block = get_eval_block(engine_state);
|
let eval_block = get_eval_block(engine_state);
|
||||||
@ -55,7 +58,7 @@ impl Command for While {
|
|||||||
match &result {
|
match &result {
|
||||||
Value::Bool { val, .. } => {
|
Value::Bool { val, .. } => {
|
||||||
if *val {
|
if *val {
|
||||||
let block = engine_state.get_block(block.block_id);
|
let block = engine_state.get_block(block_id);
|
||||||
|
|
||||||
match eval_block(engine_state, stack, block, PipelineData::empty()) {
|
match eval_block(engine_state, stack, block, PipelineData::empty()) {
|
||||||
Err(ShellError::Break { .. }) => {
|
Err(ShellError::Break { .. }) => {
|
||||||
|
@ -288,9 +288,6 @@ impl<'a> std::fmt::Debug for DebuggableValue<'a> {
|
|||||||
}
|
}
|
||||||
write!(f, "]")
|
write!(f, "]")
|
||||||
}
|
}
|
||||||
Value::Block { val, .. } => {
|
|
||||||
write!(f, "Block({:?})", val)
|
|
||||||
}
|
|
||||||
Value::Closure { val, .. } => {
|
Value::Closure { val, .. } => {
|
||||||
write!(f, "Closure({:?})", val)
|
write!(f, "Closure({:?})", val)
|
||||||
}
|
}
|
||||||
|
@ -126,9 +126,7 @@ impl<'a> StyleComputer<'a> {
|
|||||||
Value::Nothing { .. } => TextStyle::with_style(Left, s),
|
Value::Nothing { .. } => TextStyle::with_style(Left, s),
|
||||||
Value::Binary { .. } => TextStyle::with_style(Left, s),
|
Value::Binary { .. } => TextStyle::with_style(Left, s),
|
||||||
Value::CellPath { .. } => TextStyle::with_style(Left, s),
|
Value::CellPath { .. } => TextStyle::with_style(Left, s),
|
||||||
Value::Record { .. } | Value::List { .. } | Value::Block { .. } => {
|
Value::Record { .. } | Value::List { .. } => TextStyle::with_style(Left, s),
|
||||||
TextStyle::with_style(Left, s)
|
|
||||||
}
|
|
||||||
Value::Closure { .. }
|
Value::Closure { .. }
|
||||||
| Value::Custom { .. }
|
| Value::Custom { .. }
|
||||||
| Value::Error { .. }
|
| Value::Error { .. }
|
||||||
|
@ -276,8 +276,7 @@ pub fn debug_string_without_formatting(value: &Value) -> String {
|
|||||||
Ok(val) => debug_string_without_formatting(&val),
|
Ok(val) => debug_string_without_formatting(&val),
|
||||||
Err(error) => format!("{error:?}"),
|
Err(error) => format!("{error:?}"),
|
||||||
},
|
},
|
||||||
//TODO: It would be good to drill in deeper to blocks and closures.
|
//TODO: It would be good to drill deeper into closures.
|
||||||
Value::Block { val, .. } => format!("<Block {val}>"),
|
|
||||||
Value::Closure { val, .. } => format!("<Closure {}>", val.block_id),
|
Value::Closure { val, .. } => format!("<Closure {}>", val.block_id),
|
||||||
Value::Nothing { .. } => String::new(),
|
Value::Nothing { .. } => String::new(),
|
||||||
Value::Error { error, .. } => format!("{error:?}"),
|
Value::Error { error, .. } => format!("{error:?}"),
|
||||||
|
@ -173,8 +173,8 @@ impl Command for ViewSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
value => {
|
value => {
|
||||||
if let Ok(block_id) = value.coerce_block() {
|
if let Ok(closure) = value.as_closure() {
|
||||||
let block = engine_state.get_block(block_id);
|
let block = engine_state.get_block(closure.block_id);
|
||||||
|
|
||||||
if let Some(span) = block.span {
|
if let Some(span) = block.span {
|
||||||
let contents = engine_state.get_span_contents(span);
|
let contents = engine_state.get_span_contents(span);
|
||||||
|
12
crates/nu-command/src/env/export_env.rs
vendored
12
crates/nu-command/src/env/export_env.rs
vendored
@ -1,5 +1,4 @@
|
|||||||
use nu_engine::{command_prelude::*, get_eval_block, redirect_env};
|
use nu_engine::{command_prelude::*, get_eval_block, redirect_env};
|
||||||
use nu_protocol::engine::Closure;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ExportEnv;
|
pub struct ExportEnv;
|
||||||
@ -31,10 +30,15 @@ impl Command for ExportEnv {
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let capture_block: Closure = call.req(engine_state, caller_stack, 0)?;
|
let block_id = call
|
||||||
let block = engine_state.get_block(capture_block.block_id);
|
.positional_nth(0)
|
||||||
|
.expect("checked through parser")
|
||||||
|
.as_block()
|
||||||
|
.expect("internal error: missing block");
|
||||||
|
|
||||||
|
let block = engine_state.get_block(block_id);
|
||||||
let mut callee_stack = caller_stack
|
let mut callee_stack = caller_stack
|
||||||
.captures_to_stack(capture_block.captures)
|
.gather_captures(engine_state, &block.captures)
|
||||||
.reset_pipes();
|
.reset_pipes();
|
||||||
|
|
||||||
let eval_block = get_eval_block(engine_state);
|
let eval_block = get_eval_block(engine_state);
|
||||||
|
@ -522,7 +522,6 @@ fn value_should_be_printed(
|
|||||||
| Value::Date { .. }
|
| Value::Date { .. }
|
||||||
| Value::Range { .. }
|
| Value::Range { .. }
|
||||||
| Value::Float { .. }
|
| Value::Float { .. }
|
||||||
| Value::Block { .. }
|
|
||||||
| Value::Closure { .. }
|
| Value::Closure { .. }
|
||||||
| Value::Nothing { .. }
|
| Value::Nothing { .. }
|
||||||
| Value::Error { .. } => term_equals_value(term, &lower_value, span),
|
| Value::Error { .. } => term_equals_value(term, &lower_value, span),
|
||||||
|
@ -2,7 +2,6 @@ use nu_engine::{command_prelude::*, get_eval_block, EvalBlockFn};
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Block, PathMember},
|
ast::{Block, PathMember},
|
||||||
engine::Closure,
|
engine::Closure,
|
||||||
FromValue,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -132,25 +131,23 @@ fn insert(
|
|||||||
|
|
||||||
let cell_path: CellPath = call.req(engine_state, stack, 0)?;
|
let cell_path: CellPath = call.req(engine_state, stack, 0)?;
|
||||||
let replacement: Value = call.req(engine_state, stack, 1)?;
|
let replacement: Value = call.req(engine_state, stack, 1)?;
|
||||||
|
let replacement_span = replacement.span();
|
||||||
let ctrlc = engine_state.ctrlc.clone();
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
|
|
||||||
let eval_block = get_eval_block(engine_state);
|
let eval_block = get_eval_block(engine_state);
|
||||||
|
|
||||||
match input {
|
match input {
|
||||||
PipelineData::Value(mut value, metadata) => {
|
PipelineData::Value(mut value, metadata) => {
|
||||||
if replacement.coerce_block().is_ok() {
|
if let Value::Closure { val: closure, .. } = replacement {
|
||||||
match (cell_path.members.first(), &mut value) {
|
match (cell_path.members.first(), &mut value) {
|
||||||
(Some(PathMember::String { .. }), Value::List { vals, .. }) => {
|
(Some(PathMember::String { .. }), Value::List { vals, .. }) => {
|
||||||
let span = replacement.span();
|
let block = engine_state.get_block(closure.block_id);
|
||||||
let capture_block = Closure::from_value(replacement)?;
|
let stack = stack.captures_to_stack(closure.captures);
|
||||||
let block = engine_state.get_block(capture_block.block_id);
|
|
||||||
let stack = stack.captures_to_stack(capture_block.captures.clone());
|
|
||||||
for val in vals {
|
for val in vals {
|
||||||
let mut stack = stack.clone();
|
let mut stack = stack.clone();
|
||||||
insert_value_by_closure(
|
insert_value_by_closure(
|
||||||
val,
|
val,
|
||||||
span,
|
replacement_span,
|
||||||
engine_state,
|
engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
block,
|
block,
|
||||||
@ -163,7 +160,8 @@ fn insert(
|
|||||||
(first, _) => {
|
(first, _) => {
|
||||||
insert_single_value_by_closure(
|
insert_single_value_by_closure(
|
||||||
&mut value,
|
&mut value,
|
||||||
replacement,
|
closure,
|
||||||
|
replacement_span,
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
&cell_path.members,
|
&cell_path.members,
|
||||||
@ -201,14 +199,12 @@ fn insert(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if path.is_empty() {
|
if path.is_empty() {
|
||||||
if replacement.coerce_block().is_ok() {
|
if let Value::Closure { val: closure, .. } = replacement {
|
||||||
let span = replacement.span();
|
|
||||||
let value = stream.next();
|
let value = stream.next();
|
||||||
let end_of_stream = value.is_none();
|
let end_of_stream = value.is_none();
|
||||||
let value = value.unwrap_or(Value::nothing(span));
|
let value = value.unwrap_or(Value::nothing(replacement_span));
|
||||||
let capture_block = Closure::from_value(replacement)?;
|
let block = engine_state.get_block(closure.block_id);
|
||||||
let block = engine_state.get_block(capture_block.block_id);
|
let mut stack = stack.captures_to_stack(closure.captures);
|
||||||
let mut stack = stack.captures_to_stack(capture_block.captures);
|
|
||||||
|
|
||||||
if let Some(var) = block.signature.get_positional(0) {
|
if let Some(var) = block.signature.get_positional(0) {
|
||||||
if let Some(var_id) = &var.var_id {
|
if let Some(var_id) = &var.var_id {
|
||||||
@ -223,7 +219,7 @@ fn insert(
|
|||||||
value.clone().into_pipeline_data(),
|
value.clone().into_pipeline_data(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
pre_elems.push(output.into_value(span));
|
pre_elems.push(output.into_value(replacement_span));
|
||||||
if !end_of_stream {
|
if !end_of_stream {
|
||||||
pre_elems.push(value);
|
pre_elems.push(value);
|
||||||
}
|
}
|
||||||
@ -231,10 +227,11 @@ fn insert(
|
|||||||
pre_elems.push(replacement);
|
pre_elems.push(replacement);
|
||||||
}
|
}
|
||||||
} else if let Some(mut value) = stream.next() {
|
} else if let Some(mut value) = stream.next() {
|
||||||
if replacement.coerce_block().is_ok() {
|
if let Value::Closure { val: closure, .. } = replacement {
|
||||||
insert_single_value_by_closure(
|
insert_single_value_by_closure(
|
||||||
&mut value,
|
&mut value,
|
||||||
replacement,
|
closure,
|
||||||
|
replacement_span,
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
path,
|
path,
|
||||||
@ -256,12 +253,10 @@ fn insert(
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(stream)
|
.chain(stream)
|
||||||
.into_pipeline_data_with_metadata(metadata, ctrlc))
|
.into_pipeline_data_with_metadata(metadata, ctrlc))
|
||||||
} else if replacement.coerce_block().is_ok() {
|
} else if let Value::Closure { val: closure, .. } = replacement {
|
||||||
let engine_state = engine_state.clone();
|
let engine_state = engine_state.clone();
|
||||||
let replacement_span = replacement.span();
|
let block = engine_state.get_block(closure.block_id).clone();
|
||||||
let capture_block = Closure::from_value(replacement)?;
|
let stack = stack.captures_to_stack(closure.captures);
|
||||||
let block = engine_state.get_block(capture_block.block_id).clone();
|
|
||||||
let stack = stack.captures_to_stack(capture_block.captures.clone());
|
|
||||||
|
|
||||||
Ok(stream
|
Ok(stream
|
||||||
.map(move |mut input| {
|
.map(move |mut input| {
|
||||||
@ -348,17 +343,16 @@ fn insert_value_by_closure(
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn insert_single_value_by_closure(
|
fn insert_single_value_by_closure(
|
||||||
value: &mut Value,
|
value: &mut Value,
|
||||||
replacement: Value,
|
closure: Closure,
|
||||||
|
span: Span,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
cell_path: &[PathMember],
|
cell_path: &[PathMember],
|
||||||
first_path_member_int: bool,
|
first_path_member_int: bool,
|
||||||
eval_block_fn: EvalBlockFn,
|
eval_block_fn: EvalBlockFn,
|
||||||
) -> Result<(), ShellError> {
|
) -> Result<(), ShellError> {
|
||||||
let span = replacement.span();
|
let block = engine_state.get_block(closure.block_id);
|
||||||
let capture_block = Closure::from_value(replacement)?;
|
let mut stack = stack.captures_to_stack(closure.captures);
|
||||||
let block = engine_state.get_block(capture_block.block_id);
|
|
||||||
let mut stack = stack.captures_to_stack(capture_block.captures);
|
|
||||||
|
|
||||||
insert_value_by_closure(
|
insert_value_by_closure(
|
||||||
value,
|
value,
|
||||||
|
@ -2,7 +2,6 @@ use nu_engine::{command_prelude::*, get_eval_block, EvalBlockFn};
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Block, PathMember},
|
ast::{Block, PathMember},
|
||||||
engine::Closure,
|
engine::Closure,
|
||||||
FromValue,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -116,25 +115,23 @@ fn update(
|
|||||||
|
|
||||||
let cell_path: CellPath = call.req(engine_state, stack, 0)?;
|
let cell_path: CellPath = call.req(engine_state, stack, 0)?;
|
||||||
let replacement: Value = call.req(engine_state, stack, 1)?;
|
let replacement: Value = call.req(engine_state, stack, 1)?;
|
||||||
|
let replacement_span = replacement.span();
|
||||||
let ctrlc = engine_state.ctrlc.clone();
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
|
|
||||||
let eval_block = get_eval_block(engine_state);
|
let eval_block = get_eval_block(engine_state);
|
||||||
|
|
||||||
match input {
|
match input {
|
||||||
PipelineData::Value(mut value, metadata) => {
|
PipelineData::Value(mut value, metadata) => {
|
||||||
if replacement.coerce_block().is_ok() {
|
if let Value::Closure { val: closure, .. } = replacement {
|
||||||
match (cell_path.members.first(), &mut value) {
|
match (cell_path.members.first(), &mut value) {
|
||||||
(Some(PathMember::String { .. }), Value::List { vals, .. }) => {
|
(Some(PathMember::String { .. }), Value::List { vals, .. }) => {
|
||||||
let span = replacement.span();
|
let block = engine_state.get_block(closure.block_id);
|
||||||
let capture_block = Closure::from_value(replacement)?;
|
let stack = stack.captures_to_stack(closure.captures);
|
||||||
let block = engine_state.get_block(capture_block.block_id);
|
|
||||||
let stack = stack.captures_to_stack(capture_block.captures.clone());
|
|
||||||
for val in vals {
|
for val in vals {
|
||||||
let mut stack = stack.clone();
|
let mut stack = stack.clone();
|
||||||
update_value_by_closure(
|
update_value_by_closure(
|
||||||
val,
|
val,
|
||||||
span,
|
replacement_span,
|
||||||
engine_state,
|
engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
block,
|
block,
|
||||||
@ -147,7 +144,8 @@ fn update(
|
|||||||
(first, _) => {
|
(first, _) => {
|
||||||
update_single_value_by_closure(
|
update_single_value_by_closure(
|
||||||
&mut value,
|
&mut value,
|
||||||
replacement,
|
closure,
|
||||||
|
replacement_span,
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
&cell_path.members,
|
&cell_path.members,
|
||||||
@ -189,10 +187,11 @@ fn update(
|
|||||||
// cannot fail since loop above does at least one iteration or returns an error
|
// cannot fail since loop above does at least one iteration or returns an error
|
||||||
let value = pre_elems.last_mut().expect("one element");
|
let value = pre_elems.last_mut().expect("one element");
|
||||||
|
|
||||||
if replacement.coerce_block().is_ok() {
|
if let Value::Closure { val: closure, .. } = replacement {
|
||||||
update_single_value_by_closure(
|
update_single_value_by_closure(
|
||||||
value,
|
value,
|
||||||
replacement,
|
closure,
|
||||||
|
replacement_span,
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
path,
|
path,
|
||||||
@ -207,12 +206,10 @@ fn update(
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(stream)
|
.chain(stream)
|
||||||
.into_pipeline_data_with_metadata(metadata, ctrlc))
|
.into_pipeline_data_with_metadata(metadata, ctrlc))
|
||||||
} else if replacement.coerce_block().is_ok() {
|
} else if let Value::Closure { val: closure, .. } = replacement {
|
||||||
let replacement_span = replacement.span();
|
|
||||||
let engine_state = engine_state.clone();
|
let engine_state = engine_state.clone();
|
||||||
let capture_block = Closure::from_value(replacement)?;
|
let block = engine_state.get_block(closure.block_id).clone();
|
||||||
let block = engine_state.get_block(capture_block.block_id).clone();
|
let stack = stack.captures_to_stack(closure.captures);
|
||||||
let stack = stack.captures_to_stack(capture_block.captures.clone());
|
|
||||||
|
|
||||||
Ok(stream
|
Ok(stream
|
||||||
.map(move |mut input| {
|
.map(move |mut input| {
|
||||||
@ -302,17 +299,16 @@ fn update_value_by_closure(
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn update_single_value_by_closure(
|
fn update_single_value_by_closure(
|
||||||
value: &mut Value,
|
value: &mut Value,
|
||||||
replacement: Value,
|
closure: Closure,
|
||||||
|
span: Span,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
cell_path: &[PathMember],
|
cell_path: &[PathMember],
|
||||||
first_path_member_int: bool,
|
first_path_member_int: bool,
|
||||||
eval_block_fn: EvalBlockFn,
|
eval_block_fn: EvalBlockFn,
|
||||||
) -> Result<(), ShellError> {
|
) -> Result<(), ShellError> {
|
||||||
let span = replacement.span();
|
let block = engine_state.get_block(closure.block_id);
|
||||||
let capture_block = Closure::from_value(replacement)?;
|
let mut stack = stack.captures_to_stack(closure.captures);
|
||||||
let block = engine_state.get_block(capture_block.block_id);
|
|
||||||
let mut stack = stack.captures_to_stack(capture_block.captures);
|
|
||||||
|
|
||||||
update_value_by_closure(
|
update_value_by_closure(
|
||||||
value,
|
value,
|
||||||
|
@ -2,7 +2,6 @@ use nu_engine::{command_prelude::*, get_eval_block, EvalBlockFn};
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Block, PathMember},
|
ast::{Block, PathMember},
|
||||||
engine::Closure,
|
engine::Closure,
|
||||||
FromValue,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -162,24 +161,23 @@ fn upsert(
|
|||||||
|
|
||||||
let cell_path: CellPath = call.req(engine_state, stack, 0)?;
|
let cell_path: CellPath = call.req(engine_state, stack, 0)?;
|
||||||
let replacement: Value = call.req(engine_state, stack, 1)?;
|
let replacement: Value = call.req(engine_state, stack, 1)?;
|
||||||
|
let replacement_span = replacement.span();
|
||||||
let eval_block = get_eval_block(engine_state);
|
let eval_block = get_eval_block(engine_state);
|
||||||
|
|
||||||
let ctrlc = engine_state.ctrlc.clone();
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
|
|
||||||
match input {
|
match input {
|
||||||
PipelineData::Value(mut value, metadata) => {
|
PipelineData::Value(mut value, metadata) => {
|
||||||
if replacement.coerce_block().is_ok() {
|
if let Value::Closure { val: closure, .. } = replacement {
|
||||||
match (cell_path.members.first(), &mut value) {
|
match (cell_path.members.first(), &mut value) {
|
||||||
(Some(PathMember::String { .. }), Value::List { vals, .. }) => {
|
(Some(PathMember::String { .. }), Value::List { vals, .. }) => {
|
||||||
let span = replacement.span();
|
let block = engine_state.get_block(closure.block_id);
|
||||||
let capture_block = Closure::from_value(replacement)?;
|
let stack = stack.captures_to_stack(closure.captures);
|
||||||
let block = engine_state.get_block(capture_block.block_id);
|
|
||||||
let stack = stack.captures_to_stack(capture_block.captures.clone());
|
|
||||||
for val in vals {
|
for val in vals {
|
||||||
let mut stack = stack.clone();
|
let mut stack = stack.clone();
|
||||||
upsert_value_by_closure(
|
upsert_value_by_closure(
|
||||||
val,
|
val,
|
||||||
span,
|
replacement_span,
|
||||||
engine_state,
|
engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
block,
|
block,
|
||||||
@ -192,7 +190,8 @@ fn upsert(
|
|||||||
(first, _) => {
|
(first, _) => {
|
||||||
upsert_single_value_by_closure(
|
upsert_single_value_by_closure(
|
||||||
&mut value,
|
&mut value,
|
||||||
replacement,
|
closure,
|
||||||
|
replacement_span,
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
&cell_path.members,
|
&cell_path.members,
|
||||||
@ -230,12 +229,10 @@ fn upsert(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if path.is_empty() {
|
if path.is_empty() {
|
||||||
let span = replacement.span();
|
|
||||||
let value = stream.next().unwrap_or(Value::nothing(span));
|
let value = stream.next().unwrap_or(Value::nothing(span));
|
||||||
if replacement.coerce_block().is_ok() {
|
if let Value::Closure { val: closure, .. } = replacement {
|
||||||
let capture_block = Closure::from_value(replacement)?;
|
let block = engine_state.get_block(closure.block_id);
|
||||||
let block = engine_state.get_block(capture_block.block_id);
|
let mut stack = stack.captures_to_stack(closure.captures);
|
||||||
let mut stack = stack.captures_to_stack(capture_block.captures);
|
|
||||||
|
|
||||||
if let Some(var) = block.signature.get_positional(0) {
|
if let Some(var) = block.signature.get_positional(0) {
|
||||||
if let Some(var_id) = &var.var_id {
|
if let Some(var_id) = &var.var_id {
|
||||||
@ -250,15 +247,16 @@ fn upsert(
|
|||||||
value.clone().into_pipeline_data(),
|
value.clone().into_pipeline_data(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
pre_elems.push(output.into_value(span));
|
pre_elems.push(output.into_value(replacement_span));
|
||||||
} else {
|
} else {
|
||||||
pre_elems.push(replacement);
|
pre_elems.push(replacement);
|
||||||
}
|
}
|
||||||
} else if let Some(mut value) = stream.next() {
|
} else if let Some(mut value) = stream.next() {
|
||||||
if replacement.coerce_block().is_ok() {
|
if let Value::Closure { val: closure, .. } = replacement {
|
||||||
upsert_single_value_by_closure(
|
upsert_single_value_by_closure(
|
||||||
&mut value,
|
&mut value,
|
||||||
replacement,
|
closure,
|
||||||
|
replacement_span,
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
path,
|
path,
|
||||||
@ -280,12 +278,10 @@ fn upsert(
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(stream)
|
.chain(stream)
|
||||||
.into_pipeline_data_with_metadata(metadata, ctrlc))
|
.into_pipeline_data_with_metadata(metadata, ctrlc))
|
||||||
} else if replacement.coerce_block().is_ok() {
|
} else if let Value::Closure { val: closure, .. } = replacement {
|
||||||
let engine_state = engine_state.clone();
|
let engine_state = engine_state.clone();
|
||||||
let replacement_span = replacement.span();
|
let block = engine_state.get_block(closure.block_id).clone();
|
||||||
let capture_block = Closure::from_value(replacement)?;
|
let stack = stack.captures_to_stack(closure.captures);
|
||||||
let block = engine_state.get_block(capture_block.block_id).clone();
|
|
||||||
let stack = stack.captures_to_stack(capture_block.captures.clone());
|
|
||||||
|
|
||||||
Ok(stream
|
Ok(stream
|
||||||
.map(move |mut input| {
|
.map(move |mut input| {
|
||||||
@ -374,17 +370,16 @@ fn upsert_value_by_closure(
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn upsert_single_value_by_closure(
|
fn upsert_single_value_by_closure(
|
||||||
value: &mut Value,
|
value: &mut Value,
|
||||||
replacement: Value,
|
closure: Closure,
|
||||||
|
span: Span,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
cell_path: &[PathMember],
|
cell_path: &[PathMember],
|
||||||
first_path_member_int: bool,
|
first_path_member_int: bool,
|
||||||
eval_block_fn: EvalBlockFn,
|
eval_block_fn: EvalBlockFn,
|
||||||
) -> Result<(), ShellError> {
|
) -> Result<(), ShellError> {
|
||||||
let span = replacement.span();
|
let block = engine_state.get_block(closure.block_id);
|
||||||
let capture_block = Closure::from_value(replacement)?;
|
let mut stack = stack.captures_to_stack(closure.captures);
|
||||||
let block = engine_state.get_block(capture_block.block_id);
|
|
||||||
let mut stack = stack.captures_to_stack(capture_block.captures);
|
|
||||||
|
|
||||||
upsert_value_by_closure(
|
upsert_value_by_closure(
|
||||||
value,
|
value,
|
||||||
|
@ -124,7 +124,7 @@ pub fn value_to_json_value(v: &Value) -> Result<nu_json::Value, ShellError> {
|
|||||||
|
|
||||||
Value::List { vals, .. } => nu_json::Value::Array(json_list(vals)?),
|
Value::List { vals, .. } => nu_json::Value::Array(json_list(vals)?),
|
||||||
Value::Error { error, .. } => return Err(*error.clone()),
|
Value::Error { error, .. } => return Err(*error.clone()),
|
||||||
Value::Closure { .. } | Value::Block { .. } | Value::Range { .. } => nu_json::Value::Null,
|
Value::Closure { .. } | Value::Range { .. } => nu_json::Value::Null,
|
||||||
Value::Binary { val, .. } => {
|
Value::Binary { val, .. } => {
|
||||||
nu_json::Value::Array(val.iter().map(|x| nu_json::Value::U64(*x as u64)).collect())
|
nu_json::Value::Array(val.iter().map(|x| nu_json::Value::U64(*x as u64)).collect())
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,6 @@ fn local_into_string(value: Value, separator: &str, config: &Config) -> String {
|
|||||||
Ok(val) => local_into_string(val, separator, config),
|
Ok(val) => local_into_string(val, separator, config),
|
||||||
Err(error) => format!("{error:?}"),
|
Err(error) => format!("{error:?}"),
|
||||||
},
|
},
|
||||||
Value::Block { val, .. } => format!("<Block {val}>"),
|
|
||||||
Value::Closure { val, .. } => format!("<Closure {}>", val.block_id),
|
Value::Closure { val, .. } => format!("<Closure {}>", val.block_id),
|
||||||
Value::Nothing { .. } => String::new(),
|
Value::Nothing { .. } => String::new(),
|
||||||
Value::Error { error, .. } => format!("{error:?}"),
|
Value::Error { error, .. } => format!("{error:?}"),
|
||||||
|
@ -67,11 +67,6 @@ fn helper(engine_state: &EngineState, v: &Value) -> Result<toml::Value, ShellErr
|
|||||||
helper(engine_state, &collected)?
|
helper(engine_state, &collected)?
|
||||||
}
|
}
|
||||||
Value::List { vals, .. } => toml::Value::Array(toml_list(engine_state, vals)?),
|
Value::List { vals, .. } => toml::Value::Array(toml_list(engine_state, vals)?),
|
||||||
Value::Block { .. } => {
|
|
||||||
let code = engine_state.get_span_contents(span);
|
|
||||||
let code = String::from_utf8_lossy(code).to_string();
|
|
||||||
toml::Value::String(code)
|
|
||||||
}
|
|
||||||
Value::Closure { .. } => {
|
Value::Closure { .. } => {
|
||||||
let code = engine_state.get_span_contents(span);
|
let code = engine_state.get_span_contents(span);
|
||||||
let code = String::from_utf8_lossy(code).to_string();
|
let code = String::from_utf8_lossy(code).to_string();
|
||||||
|
@ -75,7 +75,6 @@ pub fn value_to_yaml_value(v: &Value) -> Result<serde_yaml::Value, ShellError> {
|
|||||||
|
|
||||||
serde_yaml::Value::Sequence(out)
|
serde_yaml::Value::Sequence(out)
|
||||||
}
|
}
|
||||||
Value::Block { .. } => serde_yaml::Value::Null,
|
|
||||||
Value::Closure { .. } => serde_yaml::Value::Null,
|
Value::Closure { .. } => serde_yaml::Value::Null,
|
||||||
Value::Nothing { .. } => serde_yaml::Value::Null,
|
Value::Nothing { .. } => serde_yaml::Value::Null,
|
||||||
Value::Error { error, .. } => return Err(*error.clone()),
|
Value::Error { error, .. } => return Err(*error.clone()),
|
||||||
|
@ -475,11 +475,6 @@ impl<'e, 's> ScopeData<'e, 's> {
|
|||||||
sort_rows(&mut export_submodules);
|
sort_rows(&mut export_submodules);
|
||||||
sort_rows(&mut export_consts);
|
sort_rows(&mut export_consts);
|
||||||
|
|
||||||
let export_env_block = module.env_block.map_or_else(
|
|
||||||
|| Value::nothing(span),
|
|
||||||
|block_id| Value::block(block_id, span),
|
|
||||||
);
|
|
||||||
|
|
||||||
let (module_usage, module_extra_usage) = self
|
let (module_usage, module_extra_usage) = self
|
||||||
.engine_state
|
.engine_state
|
||||||
.build_module_usage(*module_id)
|
.build_module_usage(*module_id)
|
||||||
@ -493,7 +488,7 @@ impl<'e, 's> ScopeData<'e, 's> {
|
|||||||
"externs" => Value::list(export_externs, span),
|
"externs" => Value::list(export_externs, span),
|
||||||
"submodules" => Value::list(export_submodules, span),
|
"submodules" => Value::list(export_submodules, span),
|
||||||
"constants" => Value::list(export_consts, span),
|
"constants" => Value::list(export_consts, span),
|
||||||
"env_block" => export_env_block,
|
"has_env_block" => Value::bool(module.env_block.is_some(), span),
|
||||||
"usage" => Value::string(module_usage, span),
|
"usage" => Value::string(module_usage, span),
|
||||||
"extra_usage" => Value::string(module_extra_usage, span),
|
"extra_usage" => Value::string(module_extra_usage, span),
|
||||||
"module_id" => Value::int(*module_id as i64, span),
|
"module_id" => Value::int(*module_id as i64, span),
|
||||||
|
@ -36,8 +36,8 @@ impl ReconstructVal for CompletionAlgorithm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn reconstruct_external_completer(config: &Config, span: Span) -> Value {
|
pub(super) fn reconstruct_external_completer(config: &Config, span: Span) -> Value {
|
||||||
if let Some(block) = config.external_completer {
|
if let Some(closure) = config.external_completer.as_ref() {
|
||||||
Value::block(block, span)
|
Value::closure(closure.clone(), span)
|
||||||
} else {
|
} else {
|
||||||
Value::nothing(span)
|
Value::nothing(span)
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ use self::output::*;
|
|||||||
use self::reedline::*;
|
use self::reedline::*;
|
||||||
use self::table::*;
|
use self::table::*;
|
||||||
|
|
||||||
|
use crate::engine::Closure;
|
||||||
use crate::{record, ShellError, Span, Value};
|
use crate::{record, ShellError, Span, Value};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -48,7 +49,7 @@ impl Default for HistoryConfig {
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub external_completer: Option<usize>,
|
pub external_completer: Option<Closure>,
|
||||||
pub filesize_metric: bool,
|
pub filesize_metric: bool,
|
||||||
pub table_mode: TableMode,
|
pub table_mode: TableMode,
|
||||||
pub table_move_header: bool,
|
pub table_move_header: bool,
|
||||||
@ -334,13 +335,13 @@ impl Value {
|
|||||||
process_int_config(value, &mut errors, &mut config.max_external_completion_results);
|
process_int_config(value, &mut errors, &mut config.max_external_completion_results);
|
||||||
}
|
}
|
||||||
"completer" => {
|
"completer" => {
|
||||||
if let Ok(v) = value.coerce_block() {
|
if let Ok(v) = value.as_closure() {
|
||||||
config.external_completer = Some(v)
|
config.external_completer = Some(v.clone())
|
||||||
} else {
|
} else {
|
||||||
match value {
|
match value {
|
||||||
Value::Nothing { .. } => {}
|
Value::Nothing { .. } => {}
|
||||||
_ => {
|
_ => {
|
||||||
report_invalid_value("should be a block or null", span, &mut errors);
|
report_invalid_value("should be a closure or null", span, &mut errors);
|
||||||
// Reconstruct
|
// Reconstruct
|
||||||
*value = reconstruct_external_completer(&config,
|
*value = reconstruct_external_completer(&config,
|
||||||
span
|
span
|
||||||
|
@ -7,8 +7,3 @@ pub struct Closure {
|
|||||||
pub block_id: BlockId,
|
pub block_id: BlockId,
|
||||||
pub captures: Vec<(VarId, Value)>,
|
pub captures: Vec<(VarId, Value)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Block {
|
|
||||||
pub block_id: BlockId,
|
|
||||||
}
|
|
||||||
|
@ -267,7 +267,6 @@ pub trait Eval {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Block(block_id) => Ok(Value::block(*block_id, expr.span)),
|
|
||||||
Expr::RowCondition(block_id) | Expr::Closure(block_id) => {
|
Expr::RowCondition(block_id) | Expr::Closure(block_id) => {
|
||||||
Self::eval_row_condition_or_closure(state, mut_state, *block_id, expr.span)
|
Self::eval_row_condition_or_closure(state, mut_state, *block_id, expr.span)
|
||||||
}
|
}
|
||||||
@ -292,6 +291,7 @@ pub trait Eval {
|
|||||||
Ok(Value::glob(pattern, *quoted, expr.span))
|
Ok(Value::glob(pattern, *quoted, expr.span))
|
||||||
}
|
}
|
||||||
Expr::MatchBlock(_) // match blocks are handled by `match`
|
Expr::MatchBlock(_) // match blocks are handled by `match`
|
||||||
|
| Expr::Block(_) // blocks are handled directly by core commands
|
||||||
| Expr::VarDecl(_)
|
| Expr::VarDecl(_)
|
||||||
| Expr::ImportPattern(_)
|
| Expr::ImportPattern(_)
|
||||||
| Expr::Signature(_)
|
| Expr::Signature(_)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
ast::{CellPath, PathMember},
|
ast::{CellPath, PathMember},
|
||||||
engine::{Block, Closure},
|
engine::Closure,
|
||||||
NuGlob, Range, Record, ShellError, Spanned, Value,
|
NuGlob, Range, Record, ShellError, Spanned, Value,
|
||||||
};
|
};
|
||||||
use chrono::{DateTime, FixedOffset};
|
use chrono::{DateTime, FixedOffset};
|
||||||
@ -553,10 +553,6 @@ impl FromValue for Closure {
|
|||||||
fn from_value(v: Value) -> Result<Self, ShellError> {
|
fn from_value(v: Value) -> Result<Self, ShellError> {
|
||||||
match v {
|
match v {
|
||||||
Value::Closure { val, .. } => Ok(val),
|
Value::Closure { val, .. } => Ok(val),
|
||||||
Value::Block { val, .. } => Ok(Closure {
|
|
||||||
block_id: val,
|
|
||||||
captures: Vec::new(),
|
|
||||||
}),
|
|
||||||
v => Err(ShellError::CantConvert {
|
v => Err(ShellError::CantConvert {
|
||||||
to_type: "Closure".into(),
|
to_type: "Closure".into(),
|
||||||
from_type: v.get_type().to_string(),
|
from_type: v.get_type().to_string(),
|
||||||
@ -567,20 +563,6 @@ impl FromValue for Closure {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromValue for Block {
|
|
||||||
fn from_value(v: Value) -> Result<Self, ShellError> {
|
|
||||||
match v {
|
|
||||||
Value::Block { val, .. } => Ok(Block { block_id: val }),
|
|
||||||
v => Err(ShellError::CantConvert {
|
|
||||||
to_type: "Block".into(),
|
|
||||||
from_type: v.get_type().to_string(),
|
|
||||||
span: v.span(),
|
|
||||||
help: None,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromValue for Spanned<Closure> {
|
impl FromValue for Spanned<Closure> {
|
||||||
fn from_value(v: Value) -> Result<Self, ShellError> {
|
fn from_value(v: Value) -> Result<Self, ShellError> {
|
||||||
let span = v.span();
|
let span = v.span();
|
||||||
|
@ -21,7 +21,7 @@ use crate::{
|
|||||||
ast::{Bits, Boolean, CellPath, Comparison, Math, Operator, PathMember},
|
ast::{Bits, Boolean, CellPath, Comparison, Math, Operator, PathMember},
|
||||||
did_you_mean,
|
did_you_mean,
|
||||||
engine::{Closure, EngineState},
|
engine::{Closure, EngineState},
|
||||||
BlockId, Config, ShellError, Span, Type,
|
Config, ShellError, Span, Type,
|
||||||
};
|
};
|
||||||
use chrono::{DateTime, Datelike, FixedOffset, Locale, TimeZone};
|
use chrono::{DateTime, Datelike, FixedOffset, Locale, TimeZone};
|
||||||
use chrono_humanize::HumanTime;
|
use chrono_humanize::HumanTime;
|
||||||
@ -123,13 +123,6 @@ pub enum Value {
|
|||||||
#[serde(rename = "span")]
|
#[serde(rename = "span")]
|
||||||
internal_span: Span,
|
internal_span: Span,
|
||||||
},
|
},
|
||||||
Block {
|
|
||||||
val: BlockId,
|
|
||||||
// note: spans are being refactored out of Value
|
|
||||||
// please use .span() instead of matching this span value
|
|
||||||
#[serde(rename = "span")]
|
|
||||||
internal_span: Span,
|
|
||||||
},
|
|
||||||
Closure {
|
Closure {
|
||||||
val: Closure,
|
val: Closure,
|
||||||
// note: spans are being refactored out of Value
|
// note: spans are being refactored out of Value
|
||||||
@ -227,10 +220,6 @@ impl Clone for Value {
|
|||||||
vals: vals.clone(),
|
vals: vals.clone(),
|
||||||
internal_span: *internal_span,
|
internal_span: *internal_span,
|
||||||
},
|
},
|
||||||
Value::Block { val, internal_span } => Value::Block {
|
|
||||||
val: *val,
|
|
||||||
internal_span: *internal_span,
|
|
||||||
},
|
|
||||||
Value::Closure { val, internal_span } => Value::Closure {
|
Value::Closure { val, internal_span } => Value::Closure {
|
||||||
val: val.clone(),
|
val: val.clone(),
|
||||||
internal_span: *internal_span,
|
internal_span: *internal_span,
|
||||||
@ -562,38 +551,6 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the inner [`BlockId`] or an error if this `Value` is not a block
|
|
||||||
pub fn as_block(&self) -> Result<BlockId, ShellError> {
|
|
||||||
if let Value::Block { val, .. } = self {
|
|
||||||
Ok(*val)
|
|
||||||
} else {
|
|
||||||
self.cant_convert_to("block")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns this `Value`'s [`BlockId`] or an error if it does not have one
|
|
||||||
///
|
|
||||||
/// Only the following `Value` cases will return an `Ok` result:
|
|
||||||
/// - `Block`
|
|
||||||
/// - `Closure`
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use nu_protocol::Value;
|
|
||||||
/// for val in Value::test_values() {
|
|
||||||
/// assert_eq!(
|
|
||||||
/// matches!(val, Value::Block { .. } | Value::Closure { .. }),
|
|
||||||
/// val.coerce_block().is_ok(),
|
|
||||||
/// );
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn coerce_block(&self) -> Result<BlockId, ShellError> {
|
|
||||||
match self {
|
|
||||||
Value::Block { val, .. } => Ok(*val),
|
|
||||||
Value::Closure { val, .. } => Ok(val.block_id),
|
|
||||||
val => val.cant_convert_to("block"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a reference to the inner [`Closure`] value or an error if this `Value` is not a closure
|
/// Returns a reference to the inner [`Closure`] value or an error if this `Value` is not a closure
|
||||||
pub fn as_closure(&self) -> Result<&Closure, ShellError> {
|
pub fn as_closure(&self) -> Result<&Closure, ShellError> {
|
||||||
if let Value::Closure { val, .. } = self {
|
if let Value::Closure { val, .. } = self {
|
||||||
@ -747,7 +704,6 @@ impl Value {
|
|||||||
| Value::Glob { internal_span, .. }
|
| Value::Glob { internal_span, .. }
|
||||||
| Value::Record { internal_span, .. }
|
| Value::Record { internal_span, .. }
|
||||||
| Value::List { internal_span, .. }
|
| Value::List { internal_span, .. }
|
||||||
| Value::Block { internal_span, .. }
|
|
||||||
| Value::Closure { internal_span, .. }
|
| Value::Closure { internal_span, .. }
|
||||||
| Value::Nothing { internal_span, .. }
|
| Value::Nothing { internal_span, .. }
|
||||||
| Value::Binary { internal_span, .. }
|
| Value::Binary { internal_span, .. }
|
||||||
@ -774,7 +730,6 @@ impl Value {
|
|||||||
| Value::LazyRecord { internal_span, .. }
|
| Value::LazyRecord { internal_span, .. }
|
||||||
| Value::List { internal_span, .. }
|
| Value::List { internal_span, .. }
|
||||||
| Value::Closure { internal_span, .. }
|
| Value::Closure { internal_span, .. }
|
||||||
| Value::Block { internal_span, .. }
|
|
||||||
| Value::Nothing { internal_span, .. }
|
| Value::Nothing { internal_span, .. }
|
||||||
| Value::Binary { internal_span, .. }
|
| Value::Binary { internal_span, .. }
|
||||||
| Value::CellPath { internal_span, .. }
|
| Value::CellPath { internal_span, .. }
|
||||||
@ -834,7 +789,6 @@ impl Value {
|
|||||||
Err(..) => Type::Error,
|
Err(..) => Type::Error,
|
||||||
},
|
},
|
||||||
Value::Nothing { .. } => Type::Nothing,
|
Value::Nothing { .. } => Type::Nothing,
|
||||||
Value::Block { .. } => Type::Block,
|
|
||||||
Value::Closure { .. } => Type::Closure,
|
Value::Closure { .. } => Type::Closure,
|
||||||
Value::Error { .. } => Type::Error,
|
Value::Error { .. } => Type::Error,
|
||||||
Value::Binary { .. } => Type::Binary,
|
Value::Binary { .. } => Type::Binary,
|
||||||
@ -943,7 +897,6 @@ impl Value {
|
|||||||
.collect()
|
.collect()
|
||||||
.unwrap_or_else(|err| Value::error(err, span))
|
.unwrap_or_else(|err| Value::error(err, span))
|
||||||
.to_expanded_string(separator, config),
|
.to_expanded_string(separator, config),
|
||||||
Value::Block { val, .. } => format!("<Block {val}>"),
|
|
||||||
Value::Closure { val, .. } => format!("<Closure {}>", val.block_id),
|
Value::Closure { val, .. } => format!("<Closure {}>", val.block_id),
|
||||||
Value::Nothing { .. } => String::new(),
|
Value::Nothing { .. } => String::new(),
|
||||||
Value::Error { error, .. } => format!("{error:?}"),
|
Value::Error { error, .. } => format!("{error:?}"),
|
||||||
@ -1879,7 +1832,6 @@ impl Value {
|
|||||||
| Value::Range { .. }
|
| Value::Range { .. }
|
||||||
| Value::String { .. }
|
| Value::String { .. }
|
||||||
| Value::Glob { .. }
|
| Value::Glob { .. }
|
||||||
| Value::Block { .. }
|
|
||||||
| Value::Nothing { .. }
|
| Value::Nothing { .. }
|
||||||
| Value::Error { .. }
|
| Value::Error { .. }
|
||||||
| Value::Binary { .. }
|
| Value::Binary { .. }
|
||||||
@ -2004,13 +1956,6 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn block(val: BlockId, span: Span) -> Value {
|
|
||||||
Value::Block {
|
|
||||||
val,
|
|
||||||
internal_span: span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn closure(val: Closure, span: Span) -> Value {
|
pub fn closure(val: Closure, span: Span) -> Value {
|
||||||
Value::Closure {
|
Value::Closure {
|
||||||
val,
|
val,
|
||||||
@ -2126,12 +2071,6 @@ impl Value {
|
|||||||
Value::list(vals, Span::test_data())
|
Value::list(vals, Span::test_data())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
|
|
||||||
/// when used in errors.
|
|
||||||
pub fn test_block(val: BlockId) -> Value {
|
|
||||||
Value::block(val, Span::test_data())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
|
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
|
||||||
/// when used in errors.
|
/// when used in errors.
|
||||||
pub fn test_closure(val: Closure) -> Value {
|
pub fn test_closure(val: Closure) -> Value {
|
||||||
@ -2190,7 +2129,6 @@ impl Value {
|
|||||||
Value::test_record(Record::new()),
|
Value::test_record(Record::new()),
|
||||||
// Value::test_lazy_record(Box::new(todo!())),
|
// Value::test_lazy_record(Box::new(todo!())),
|
||||||
Value::test_list(Vec::new()),
|
Value::test_list(Vec::new()),
|
||||||
Value::test_block(0),
|
|
||||||
Value::test_closure(Closure {
|
Value::test_closure(Closure {
|
||||||
block_id: 0,
|
block_id: 0,
|
||||||
captures: Vec::new(),
|
captures: Vec::new(),
|
||||||
@ -2245,7 +2183,6 @@ impl PartialOrd for Value {
|
|||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
Value::LazyRecord { .. } => Some(Ordering::Less),
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Block { .. } => Some(Ordering::Less),
|
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
Value::Error { .. } => Some(Ordering::Less),
|
Value::Error { .. } => Some(Ordering::Less),
|
||||||
@ -2266,7 +2203,6 @@ impl PartialOrd for Value {
|
|||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
Value::LazyRecord { .. } => Some(Ordering::Less),
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Block { .. } => Some(Ordering::Less),
|
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
Value::Error { .. } => Some(Ordering::Less),
|
Value::Error { .. } => Some(Ordering::Less),
|
||||||
@ -2287,7 +2223,6 @@ impl PartialOrd for Value {
|
|||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
Value::LazyRecord { .. } => Some(Ordering::Less),
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Block { .. } => Some(Ordering::Less),
|
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
Value::Error { .. } => Some(Ordering::Less),
|
Value::Error { .. } => Some(Ordering::Less),
|
||||||
@ -2308,7 +2243,6 @@ impl PartialOrd for Value {
|
|||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
Value::LazyRecord { .. } => Some(Ordering::Less),
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Block { .. } => Some(Ordering::Less),
|
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
Value::Error { .. } => Some(Ordering::Less),
|
Value::Error { .. } => Some(Ordering::Less),
|
||||||
@ -2329,7 +2263,6 @@ impl PartialOrd for Value {
|
|||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
Value::LazyRecord { .. } => Some(Ordering::Less),
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Block { .. } => Some(Ordering::Less),
|
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
Value::Error { .. } => Some(Ordering::Less),
|
Value::Error { .. } => Some(Ordering::Less),
|
||||||
@ -2350,7 +2283,6 @@ impl PartialOrd for Value {
|
|||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
Value::LazyRecord { .. } => Some(Ordering::Less),
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Block { .. } => Some(Ordering::Less),
|
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
Value::Error { .. } => Some(Ordering::Less),
|
Value::Error { .. } => Some(Ordering::Less),
|
||||||
@ -2371,7 +2303,6 @@ impl PartialOrd for Value {
|
|||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
Value::LazyRecord { .. } => Some(Ordering::Less),
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Block { .. } => Some(Ordering::Less),
|
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
Value::Error { .. } => Some(Ordering::Less),
|
Value::Error { .. } => Some(Ordering::Less),
|
||||||
@ -2392,7 +2323,6 @@ impl PartialOrd for Value {
|
|||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
Value::LazyRecord { .. } => Some(Ordering::Less),
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Block { .. } => Some(Ordering::Less),
|
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
Value::Error { .. } => Some(Ordering::Less),
|
Value::Error { .. } => Some(Ordering::Less),
|
||||||
@ -2413,7 +2343,6 @@ impl PartialOrd for Value {
|
|||||||
Value::Record { .. } => Some(Ordering::Less),
|
Value::Record { .. } => Some(Ordering::Less),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Less),
|
Value::LazyRecord { .. } => Some(Ordering::Less),
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Block { .. } => Some(Ordering::Less),
|
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
Value::Error { .. } => Some(Ordering::Less),
|
Value::Error { .. } => Some(Ordering::Less),
|
||||||
@ -2466,7 +2395,6 @@ impl PartialOrd for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::List { .. } => Some(Ordering::Less),
|
Value::List { .. } => Some(Ordering::Less),
|
||||||
Value::Block { .. } => Some(Ordering::Less),
|
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
Value::Error { .. } => Some(Ordering::Less),
|
Value::Error { .. } => Some(Ordering::Less),
|
||||||
@ -2487,28 +2415,6 @@ impl PartialOrd for Value {
|
|||||||
Value::Record { .. } => Some(Ordering::Greater),
|
Value::Record { .. } => Some(Ordering::Greater),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
||||||
Value::List { vals: rhs, .. } => lhs.partial_cmp(rhs),
|
Value::List { vals: rhs, .. } => lhs.partial_cmp(rhs),
|
||||||
Value::Block { .. } => Some(Ordering::Less),
|
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
|
||||||
Value::Error { .. } => Some(Ordering::Less),
|
|
||||||
Value::Binary { .. } => Some(Ordering::Less),
|
|
||||||
Value::CellPath { .. } => Some(Ordering::Less),
|
|
||||||
Value::Custom { .. } => Some(Ordering::Less),
|
|
||||||
},
|
|
||||||
(Value::Block { val: lhs, .. }, rhs) => match rhs {
|
|
||||||
Value::Bool { .. } => Some(Ordering::Greater),
|
|
||||||
Value::Int { .. } => Some(Ordering::Greater),
|
|
||||||
Value::Float { .. } => Some(Ordering::Greater),
|
|
||||||
Value::Filesize { .. } => Some(Ordering::Greater),
|
|
||||||
Value::Duration { .. } => Some(Ordering::Greater),
|
|
||||||
Value::Date { .. } => Some(Ordering::Greater),
|
|
||||||
Value::Range { .. } => Some(Ordering::Greater),
|
|
||||||
Value::String { .. } => Some(Ordering::Greater),
|
|
||||||
Value::Glob { .. } => Some(Ordering::Greater),
|
|
||||||
Value::Record { .. } => Some(Ordering::Greater),
|
|
||||||
Value::List { .. } => Some(Ordering::Greater),
|
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
|
||||||
Value::Block { val: rhs, .. } => lhs.partial_cmp(rhs),
|
|
||||||
Value::Closure { .. } => Some(Ordering::Less),
|
Value::Closure { .. } => Some(Ordering::Less),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
Value::Error { .. } => Some(Ordering::Less),
|
Value::Error { .. } => Some(Ordering::Less),
|
||||||
@ -2529,7 +2435,6 @@ impl PartialOrd for Value {
|
|||||||
Value::Record { .. } => Some(Ordering::Greater),
|
Value::Record { .. } => Some(Ordering::Greater),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
||||||
Value::List { .. } => Some(Ordering::Greater),
|
Value::List { .. } => Some(Ordering::Greater),
|
||||||
Value::Block { .. } => Some(Ordering::Greater),
|
|
||||||
Value::Closure { val: rhs, .. } => lhs.block_id.partial_cmp(&rhs.block_id),
|
Value::Closure { val: rhs, .. } => lhs.block_id.partial_cmp(&rhs.block_id),
|
||||||
Value::Nothing { .. } => Some(Ordering::Less),
|
Value::Nothing { .. } => Some(Ordering::Less),
|
||||||
Value::Error { .. } => Some(Ordering::Less),
|
Value::Error { .. } => Some(Ordering::Less),
|
||||||
@ -2550,7 +2455,6 @@ impl PartialOrd for Value {
|
|||||||
Value::Record { .. } => Some(Ordering::Greater),
|
Value::Record { .. } => Some(Ordering::Greater),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
||||||
Value::List { .. } => Some(Ordering::Greater),
|
Value::List { .. } => Some(Ordering::Greater),
|
||||||
Value::Block { .. } => Some(Ordering::Greater),
|
|
||||||
Value::Closure { .. } => Some(Ordering::Greater),
|
Value::Closure { .. } => Some(Ordering::Greater),
|
||||||
Value::Nothing { .. } => Some(Ordering::Equal),
|
Value::Nothing { .. } => Some(Ordering::Equal),
|
||||||
Value::Error { .. } => Some(Ordering::Less),
|
Value::Error { .. } => Some(Ordering::Less),
|
||||||
@ -2571,7 +2475,6 @@ impl PartialOrd for Value {
|
|||||||
Value::Record { .. } => Some(Ordering::Greater),
|
Value::Record { .. } => Some(Ordering::Greater),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
||||||
Value::List { .. } => Some(Ordering::Greater),
|
Value::List { .. } => Some(Ordering::Greater),
|
||||||
Value::Block { .. } => Some(Ordering::Greater),
|
|
||||||
Value::Closure { .. } => Some(Ordering::Greater),
|
Value::Closure { .. } => Some(Ordering::Greater),
|
||||||
Value::Nothing { .. } => Some(Ordering::Greater),
|
Value::Nothing { .. } => Some(Ordering::Greater),
|
||||||
Value::Error { .. } => Some(Ordering::Equal),
|
Value::Error { .. } => Some(Ordering::Equal),
|
||||||
@ -2592,7 +2495,6 @@ impl PartialOrd for Value {
|
|||||||
Value::Record { .. } => Some(Ordering::Greater),
|
Value::Record { .. } => Some(Ordering::Greater),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
||||||
Value::List { .. } => Some(Ordering::Greater),
|
Value::List { .. } => Some(Ordering::Greater),
|
||||||
Value::Block { .. } => Some(Ordering::Greater),
|
|
||||||
Value::Closure { .. } => Some(Ordering::Greater),
|
Value::Closure { .. } => Some(Ordering::Greater),
|
||||||
Value::Nothing { .. } => Some(Ordering::Greater),
|
Value::Nothing { .. } => Some(Ordering::Greater),
|
||||||
Value::Error { .. } => Some(Ordering::Greater),
|
Value::Error { .. } => Some(Ordering::Greater),
|
||||||
@ -2613,7 +2515,6 @@ impl PartialOrd for Value {
|
|||||||
Value::Record { .. } => Some(Ordering::Greater),
|
Value::Record { .. } => Some(Ordering::Greater),
|
||||||
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
Value::LazyRecord { .. } => Some(Ordering::Greater),
|
||||||
Value::List { .. } => Some(Ordering::Greater),
|
Value::List { .. } => Some(Ordering::Greater),
|
||||||
Value::Block { .. } => Some(Ordering::Greater),
|
|
||||||
Value::Closure { .. } => Some(Ordering::Greater),
|
Value::Closure { .. } => Some(Ordering::Greater),
|
||||||
Value::Nothing { .. } => Some(Ordering::Greater),
|
Value::Nothing { .. } => Some(Ordering::Greater),
|
||||||
Value::Error { .. } => Some(Ordering::Greater),
|
Value::Error { .. } => Some(Ordering::Greater),
|
||||||
|
@ -39,7 +39,7 @@ pub enum ToStyle {
|
|||||||
|
|
||||||
/// convert an actual Nushell [`Value`] to a raw string representation of the NUON data
|
/// convert an actual Nushell [`Value`] to a raw string representation of the NUON data
|
||||||
///
|
///
|
||||||
/// > **Note**
|
/// > **Note**
|
||||||
/// > a [`Span`] can be passed to [`to_nuon`] if there is context available to the caller, e.g. when
|
/// > a [`Span`] can be passed to [`to_nuon`] if there is context available to the caller, e.g. when
|
||||||
/// > using this function in a command implementation such as [`to nuon`](https://www.nushell.sh/commands/docs/to_nuon.html).
|
/// > using this function in a command implementation such as [`to nuon`](https://www.nushell.sh/commands/docs/to_nuon.html).
|
||||||
///
|
///
|
||||||
@ -84,12 +84,6 @@ fn value_to_string(
|
|||||||
}
|
}
|
||||||
Ok(format!("0x[{s}]"))
|
Ok(format!("0x[{s}]"))
|
||||||
}
|
}
|
||||||
Value::Block { .. } => Err(ShellError::UnsupportedInput {
|
|
||||||
msg: "blocks are currently not nuon-compatible".into(),
|
|
||||||
input: "value originates from here".into(),
|
|
||||||
msg_span: span,
|
|
||||||
input_span: v.span(),
|
|
||||||
}),
|
|
||||||
Value::Closure { .. } => Err(ShellError::UnsupportedInput {
|
Value::Closure { .. } => Err(ShellError::UnsupportedInput {
|
||||||
msg: "closures are currently not nuon-compatible".into(),
|
msg: "closures are currently not nuon-compatible".into(),
|
||||||
input: "value originates from here".into(),
|
input: "value originates from here".into(),
|
||||||
|
@ -134,10 +134,10 @@ fn correct_scope_modules_fields() {
|
|||||||
|
|
||||||
let inp = &[
|
let inp = &[
|
||||||
"use spam.nu",
|
"use spam.nu",
|
||||||
"scope modules | where name == spam | get 0.env_block | is-empty",
|
"scope modules | where name == spam | get 0.has_env_block",
|
||||||
];
|
];
|
||||||
let actual = nu!(cwd: dirs.test(), &inp.join("; "));
|
let actual = nu!(cwd: dirs.test(), &inp.join("; "));
|
||||||
assert_eq!(actual.out, "false");
|
assert_eq!(actual.out, "true");
|
||||||
|
|
||||||
let inp = &[
|
let inp = &[
|
||||||
"use spam.nu",
|
"use spam.nu",
|
||||||
|
Loading…
Reference in New Issue
Block a user