Add initial ctrl-c support

This commit is contained in:
JT 2021-10-28 17:13:10 +13:00
parent 1308eb45d5
commit bac8b8a450
32 changed files with 318 additions and 144 deletions

24
Cargo.lock generated
View File

@ -264,6 +264,16 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "ctrlc"
version = "3.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a19c6cedffdc8c03a3346d723eb20bd85a13362bb96dc2ac000842c6381ec7bf"
dependencies = [
"nix",
"winapi",
]
[[package]] [[package]]
name = "dialoguer" name = "dialoguer"
version = "0.9.0" version = "0.9.0"
@ -339,6 +349,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"assert_cmd", "assert_cmd",
"crossterm", "crossterm",
"ctrlc",
"dialoguer", "dialoguer",
"miette", "miette",
"nu-cli", "nu-cli",
@ -558,6 +569,19 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "nix"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f305c2c2e4c39a82f7bf0bf65fb557f9070ce06781d4f2454295cc34b1c43188"
dependencies = [
"bitflags",
"cc",
"cfg-if",
"libc",
"memoffset",
]
[[package]] [[package]]
name = "ntapi" name = "ntapi"
version = "0.3.6" version = "0.3.6"

View File

@ -22,6 +22,7 @@ nu-protocol = { path = "./crates/nu-protocol" }
nu-table = { path = "./crates/nu-table" } nu-table = { path = "./crates/nu-table" }
nu-term-grid = { path = "./crates/nu-term-grid" } nu-term-grid = { path = "./crates/nu-term-grid" }
miette = "3.0.0" miette = "3.0.0"
ctrlc = "3.2.1"
# mimalloc = { version = "*", default-features = false } # mimalloc = { version = "*", default-features = false }
[dev-dependencies] [dev-dependencies]

View File

@ -32,8 +32,8 @@
- [x] Config file loading - [x] Config file loading
- [x] block variable captures - [x] block variable captures
- [x] improved history and config paths - [x] improved history and config paths
- [x] ctrl-c support
- [ ] Support for `$in` - [ ] Support for `$in`
- [ ] ctrl-c support
- [ ] operator overflow - [ ] operator overflow
- [ ] shells - [ ] shells
- [ ] plugins - [ ] plugins

View File

@ -26,12 +26,12 @@ impl Command for SubCommand {
fn run( fn run(
&self, &self,
_engine_state: &EngineState, engine_state: &EngineState,
_stack: &mut Stack, _stack: &mut Stack,
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
into_binary(call, input) into_binary(engine_state, call, input)
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
@ -86,13 +86,15 @@ impl Command for SubCommand {
} }
fn into_binary( fn into_binary(
engine_state: &EngineState,
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let head = call.head; let head = call.head;
// let column_paths: Vec<CellPath> = call.rest(context, 0)?; // let column_paths: Vec<CellPath> = call.rest(context, 0)?;
input.map(move |v| { input.map(
move |v| {
action(v, head) action(v, head)
// FIXME: Add back in cell_path support // FIXME: Add back in cell_path support
// if column_paths.is_empty() { // if column_paths.is_empty() {
@ -106,7 +108,9 @@ fn into_binary(
// Ok(ret) // Ok(ret)
// } // }
}) },
engine_state.ctrlc.clone(),
)
} }
fn int_to_endian(n: i64) -> Vec<u8> { fn int_to_endian(n: i64) -> Vec<u8> {

View File

@ -26,12 +26,12 @@ impl Command for SubCommand {
fn run( fn run(
&self, &self,
_engine_state: &EngineState, engine_state: &EngineState,
_stack: &mut Stack, _stack: &mut Stack,
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
into_filesize(call, input) into_filesize(engine_state, call, input)
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
@ -114,13 +114,15 @@ impl Command for SubCommand {
} }
fn into_filesize( fn into_filesize(
engine_state: &EngineState,
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let head = call.head; let head = call.head;
// let call_paths: Vec<ColumnPath> = args.rest(0)?; // let call_paths: Vec<ColumnPath> = args.rest(0)?;
input.map(move |v| { input.map(
move |v| {
action(v, head) action(v, head)
// FIXME: Add back cell_path support // FIXME: Add back cell_path support
@ -137,7 +139,9 @@ fn into_filesize(
// Ok(ret) // Ok(ret)
// } // }
}) },
engine_state.ctrlc.clone(),
)
} }
pub fn action(input: Value, span: Span) -> Value { pub fn action(input: Value, span: Span) -> Value {

View File

@ -26,12 +26,12 @@ impl Command for SubCommand {
fn run( fn run(
&self, &self,
_engine_state: &EngineState, engine_state: &EngineState,
_stack: &mut Stack, _stack: &mut Stack,
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
into_int(call, input) into_int(engine_state, call, input)
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
@ -90,13 +90,15 @@ impl Command for SubCommand {
} }
fn into_int( fn into_int(
engine_state: &EngineState,
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let head = call.head; let head = call.head;
// let column_paths: Vec<CellPath> = call.rest(context, 0)?; // let column_paths: Vec<CellPath> = call.rest(context, 0)?;
input.map(move |v| { input.map(
move |v| {
action(v, head) action(v, head)
// FIXME: Add back cell_path support // FIXME: Add back cell_path support
// if column_paths.is_empty() { // if column_paths.is_empty() {
@ -110,7 +112,9 @@ fn into_int(
// Ok(ret) // Ok(ret)
// } // }
}) },
engine_state.ctrlc.clone(),
)
} }
pub fn action(input: Value, span: Span) -> Value { pub fn action(input: Value, span: Span) -> Value {

View File

@ -1,7 +1,9 @@
use nu_engine::{eval_block, eval_expression}; use nu_engine::{eval_block, eval_expression};
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Example, IntoPipelineData, PipelineData, Signature, Span, SyntaxShape, Value}; use nu_protocol::{
Example, IntoInterruptiblePipelineData, PipelineData, Signature, Span, SyntaxShape, Value,
};
#[derive(Clone)] #[derive(Clone)]
pub struct For; pub struct For;
@ -55,6 +57,7 @@ impl Command for For {
.as_block() .as_block()
.expect("internal error: expected block"); .expect("internal error: expected block");
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_id).clone(); let block = engine_state.get_block(block_id).clone();
let mut stack = stack.collect_captures(&block.captures); let mut stack = stack.collect_captures(&block.captures);
@ -71,7 +74,7 @@ impl Command for For {
Err(error) => Value::Error { error }, Err(error) => Value::Error { error },
} }
}) })
.into_pipeline_data()), .into_pipeline_data(ctrlc)),
Value::Range { val, .. } => Ok(val Value::Range { val, .. } => Ok(val
.into_range_iter()? .into_range_iter()?
.map(move |x| { .map(move |x| {
@ -83,7 +86,7 @@ impl Command for For {
Err(error) => Value::Error { error }, Err(error) => Value::Error { error },
} }
}) })
.into_pipeline_data()), .into_pipeline_data(ctrlc)),
x => { x => {
stack.add_var(var_id, x); stack.add_var(var_id, x);

View File

@ -1,8 +1,8 @@
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EngineState, Stack}, engine::{Command, EngineState, Stack},
span, Example, IntoPipelineData, PipelineData, ShellError, Signature, Spanned, SyntaxShape, span, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError,
Value, Signature, Spanned, SyntaxShape, Value,
}; };
use nu_engine::{get_full_help, CallExt}; use nu_engine::{get_full_help, CallExt};
@ -121,7 +121,9 @@ fn help(
} }
} }
return Ok(found_cmds_vec.into_iter().into_pipeline_data()); return Ok(found_cmds_vec
.into_iter()
.into_pipeline_data(engine_state.ctrlc.clone()));
} }
if !rest.is_empty() { if !rest.is_empty() {
@ -155,7 +157,9 @@ fn help(
}); });
} }
Ok(found_cmds_vec.into_iter().into_pipeline_data()) Ok(found_cmds_vec
.into_iter()
.into_pipeline_data(engine_state.ctrlc.clone()))
} else { } else {
let mut name = String::new(); let mut name = String::new();
let mut output = String::new(); let mut output = String::new();

View File

@ -7,6 +7,7 @@ use crate::*;
pub fn create_default_context() -> EngineState { pub fn create_default_context() -> EngineState {
let mut engine_state = EngineState::new(); let mut engine_state = EngineState::new();
let delta = { let delta = {
let mut working_set = StateWorkingSet::new(&engine_state); let mut working_set = StateWorkingSet::new(&engine_state);

View File

@ -7,7 +7,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::Command; use nu_protocol::engine::Command;
use nu_protocol::engine::EngineState; use nu_protocol::engine::EngineState;
use nu_protocol::engine::Stack; use nu_protocol::engine::Stack;
use nu_protocol::IntoPipelineData; use nu_protocol::IntoInterruptiblePipelineData;
use nu_protocol::PipelineData; use nu_protocol::PipelineData;
use nu_protocol::{Signature, Value}; use nu_protocol::{Signature, Value};
@ -30,7 +30,7 @@ impl Command for ListGitBranches {
fn run( fn run(
&self, &self,
_engine_state: &EngineState, engine_state: &EngineState,
_stack: &mut Stack, _stack: &mut Stack,
call: &Call, call: &Call,
_input: PipelineData, _input: PipelineData,
@ -62,7 +62,9 @@ impl Command for ListGitBranches {
}) })
.collect(); .collect();
Ok(lines.into_iter().into_pipeline_data()) Ok(lines
.into_iter()
.into_pipeline_data(engine_state.ctrlc.clone()))
} else { } else {
Ok(PipelineData::new()) Ok(PipelineData::new())
} }

View File

@ -2,7 +2,7 @@ use chrono::{DateTime, Utc};
use nu_engine::eval_expression; use nu_engine::eval_expression;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{IntoPipelineData, PipelineData, Signature, SyntaxShape, Value}; use nu_protocol::{IntoInterruptiblePipelineData, PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)] #[derive(Clone)]
pub struct Ls; pub struct Ls;
@ -112,6 +112,6 @@ impl Command for Ls {
}, },
_ => Value::Nothing { span: call_span }, _ => Value::Nothing { span: call_span },
}) })
.into_pipeline_data()) .into_pipeline_data(engine_state.ctrlc.clone()))
} }
} }

View File

@ -4,7 +4,9 @@ use std::env::current_dir;
use nu_engine::CallExt; use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value}; use nu_protocol::{
IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
};
#[derive(Clone)] #[derive(Clone)]
pub struct Mkdir; pub struct Mkdir;
@ -69,6 +71,8 @@ impl Command for Mkdir {
} }
} }
Ok(stream.into_iter().into_pipeline_data()) Ok(stream
.into_iter()
.into_pipeline_data(engine_state.ctrlc.clone()))
} }
} }

View File

@ -8,7 +8,9 @@ use super::util::get_interactive_confirmation;
use nu_engine::CallExt; use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value}; use nu_protocol::{
IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
};
#[derive(Clone)] #[derive(Clone)]
pub struct Rm; pub struct Rm;
@ -170,7 +172,9 @@ fn rm(
// let temp = rm_helper(call, args).flatten(); // let temp = rm_helper(call, args).flatten();
// let temp = input.flatten(call.head, move |_| rm_helper(call, args)); // let temp = input.flatten(call.head, move |_| rm_helper(call, args));
Ok(response.into_iter().into_pipeline_data()) Ok(response
.into_iter()
.into_pipeline_data(engine_state.ctrlc.clone()))
// Ok(Value::Nothing { span }) // Ok(Value::Nothing { span })
} }

View File

@ -1,7 +1,10 @@
use nu_engine::eval_block; use nu_engine::eval_block;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Example, IntoPipelineData, PipelineData, Signature, Span, SyntaxShape, Value}; use nu_protocol::{
Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Signature, Span,
SyntaxShape, Value,
};
#[derive(Clone)] #[derive(Clone)]
pub struct Each; pub struct Each;
@ -63,6 +66,7 @@ impl Command for Each {
.expect("internal error: expected block"); .expect("internal error: expected block");
let numbered = call.has_flag("numbered"); let numbered = call.has_flag("numbered");
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_id).clone(); let block = engine_state.get_block(block_id).clone();
let mut stack = stack.collect_captures(&block.captures); let mut stack = stack.collect_captures(&block.captures);
@ -101,7 +105,7 @@ impl Command for Each {
Err(error) => Value::Error { error }, Err(error) => Value::Error { error },
} }
}) })
.into_pipeline_data()), .into_pipeline_data(ctrlc)),
PipelineData::Value(Value::List { vals: val, .. }) => Ok(val PipelineData::Value(Value::List { vals: val, .. }) => Ok(val
.into_iter() .into_iter()
.enumerate() .enumerate()
@ -134,7 +138,7 @@ impl Command for Each {
Err(error) => Value::Error { error }, Err(error) => Value::Error { error },
} }
}) })
.into_pipeline_data()), .into_pipeline_data(ctrlc)),
PipelineData::Stream(stream) => Ok(stream PipelineData::Stream(stream) => Ok(stream
.enumerate() .enumerate()
.map(move |(idx, x)| { .map(move |(idx, x)| {
@ -166,7 +170,7 @@ impl Command for Each {
Err(error) => Value::Error { error }, Err(error) => Value::Error { error },
} }
}) })
.into_pipeline_data()), .into_pipeline_data(ctrlc)),
PipelineData::Value(Value::Record { cols, vals, .. }) => { PipelineData::Value(Value::Record { cols, vals, .. }) => {
let mut output_cols = vec![]; let mut output_cols = vec![];
let mut output_vals = vec![]; let mut output_vals = vec![];

View File

@ -3,7 +3,8 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
Value,
}; };
use std::convert::TryInto; use std::convert::TryInto;
@ -54,7 +55,7 @@ impl Command for Last {
.into_iter() .into_iter()
.skip(beginning_rows_to_skip.try_into().unwrap()); .skip(beginning_rows_to_skip.try_into().unwrap());
Ok(iter.into_pipeline_data()) Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
} }
} }

View File

@ -1,6 +1,6 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{IntoPipelineData, PipelineData, ShellError, Signature, Value}; use nu_protocol::{IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Value};
#[derive(Clone)] #[derive(Clone)]
pub struct Lines; pub struct Lines;
@ -22,7 +22,7 @@ impl Command for Lines {
fn run( fn run(
&self, &self,
_engine_state: &EngineState, engine_state: &EngineState,
_stack: &mut Stack, _stack: &mut Stack,
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
@ -46,7 +46,7 @@ impl Command for Lines {
} }
}); });
Ok(iter.into_pipeline_data()) Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
} }
PipelineData::Stream(stream) => { PipelineData::Stream(stream) => {
let iter = stream let iter = stream
@ -74,7 +74,7 @@ impl Command for Lines {
}) })
.flatten(); .flatten();
Ok(iter.into_pipeline_data()) Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
} }
PipelineData::Value(val) => Err(ShellError::UnsupportedInput( PipelineData::Value(val) => Err(ShellError::UnsupportedInput(
format!("Not supported input: {}", val.as_string()?), format!("Not supported input: {}", val.as_string()?),

View File

@ -1,7 +1,10 @@
use nu_engine::eval_block; use nu_engine::eval_block;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Example, IntoPipelineData, PipelineData, Signature, SyntaxShape, Value}; use nu_protocol::{
Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Signature, SyntaxShape,
Value,
};
use rayon::prelude::*; use rayon::prelude::*;
#[derive(Clone)] #[derive(Clone)]
@ -46,6 +49,7 @@ impl Command for ParEach {
.expect("internal error: expected block"); .expect("internal error: expected block");
let numbered = call.has_flag("numbered"); let numbered = call.has_flag("numbered");
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_id); let block = engine_state.get_block(block_id);
let mut stack = stack.collect_captures(&block.captures); let mut stack = stack.collect_captures(&block.captures);
@ -92,7 +96,7 @@ impl Command for ParEach {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_iter() .into_iter()
.flatten() .flatten()
.into_pipeline_data()), .into_pipeline_data(ctrlc)),
PipelineData::Value(Value::List { vals: val, .. }) => Ok(val PipelineData::Value(Value::List { vals: val, .. }) => Ok(val
.into_iter() .into_iter()
.enumerate() .enumerate()
@ -133,7 +137,7 @@ impl Command for ParEach {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_iter() .into_iter()
.flatten() .flatten()
.into_pipeline_data()), .into_pipeline_data(ctrlc)),
PipelineData::Stream(stream) => Ok(stream PipelineData::Stream(stream) => Ok(stream
.enumerate() .enumerate()
.par_bridge() .par_bridge()
@ -173,7 +177,7 @@ impl Command for ParEach {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_iter() .into_iter()
.flatten() .flatten()
.into_pipeline_data()), .into_pipeline_data(ctrlc)),
PipelineData::Value(Value::Record { cols, vals, .. }) => { PipelineData::Value(Value::Record { cols, vals, .. }) => {
let mut output_cols = vec![]; let mut output_cols = vec![];
let mut output_vals = vec![]; let mut output_vals = vec![];

View File

@ -2,7 +2,8 @@ use nu_engine::CallExt;
use nu_protocol::ast::{Call, CellPath}; use nu_protocol::ast::{Call, CellPath};
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError, Signature,
Span, SyntaxShape, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -35,7 +36,7 @@ impl Command for Select {
let columns: Vec<CellPath> = call.rest(engine_state, stack, 0)?; let columns: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let span = call.head; let span = call.head;
select(span, columns, input) select(engine_state, span, columns, input)
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
@ -55,6 +56,7 @@ impl Command for Select {
} }
fn select( fn select(
engine_state: &EngineState,
span: Span, span: Span,
columns: Vec<CellPath>, columns: Vec<CellPath>,
input: PipelineData, input: PipelineData,
@ -84,7 +86,9 @@ fn select(
output.push(Value::Record { cols, vals, span }) output.push(Value::Record { cols, vals, span })
} }
Ok(output.into_iter().into_pipeline_data()) Ok(output
.into_iter()
.into_pipeline_data(engine_state.ctrlc.clone()))
} }
PipelineData::Stream(stream) => Ok(stream PipelineData::Stream(stream) => Ok(stream
.map(move |x| { .map(move |x| {
@ -106,7 +110,7 @@ fn select(
Value::Record { cols, vals, span } Value::Record { cols, vals, span }
}) })
.into_pipeline_data()), .into_pipeline_data(engine_state.ctrlc.clone())),
PipelineData::Value(v) => { PipelineData::Value(v) => {
let mut cols = vec![]; let mut cols = vec![];
let mut vals = vec![]; let mut vals = vec![];

View File

@ -1,7 +1,10 @@
use nu_engine::eval_expression; use nu_engine::eval_expression;
use nu_protocol::ast::{Call, Expr, Expression}; use nu_protocol::ast::{Call, Expr, Expression};
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value}; use nu_protocol::{
IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError, Signature,
SyntaxShape, Value,
};
#[derive(Clone)] #[derive(Clone)]
pub struct Where; pub struct Where;
@ -28,6 +31,7 @@ impl Command for Where {
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let cond = call.positional[0].clone(); let cond = call.positional[0].clone();
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone(); let engine_state = engine_state.clone();
// FIXME: very expensive // FIXME: very expensive
@ -53,7 +57,7 @@ impl Command for Where {
_ => false, _ => false,
} }
}) })
.into_pipeline_data()), .into_pipeline_data(ctrlc)),
PipelineData::Value(Value::List { vals, .. }) => Ok(vals PipelineData::Value(Value::List { vals, .. }) => Ok(vals
.into_iter() .into_iter()
.filter(move |value| { .filter(move |value| {
@ -66,7 +70,7 @@ impl Command for Where {
_ => false, _ => false,
} }
}) })
.into_pipeline_data()), .into_pipeline_data(ctrlc)),
PipelineData::Value(x) => { PipelineData::Value(x) => {
stack.add_var(var_id, x.clone()); stack.add_var(var_id, x.clone());

View File

@ -1,7 +1,9 @@
use nu_engine::CallExt; use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{IntoPipelineData, PipelineData, Signature, SyntaxShape, Value}; use nu_protocol::{
IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Signature, SyntaxShape, Value,
};
#[derive(Clone)] #[derive(Clone)]
pub struct Wrap; pub struct Wrap;
@ -37,14 +39,14 @@ impl Command for Wrap {
vals: vec![x], vals: vec![x],
span, span,
}) })
.into_pipeline_data()), .into_pipeline_data(engine_state.ctrlc.clone())),
PipelineData::Stream(stream) => Ok(stream PipelineData::Stream(stream) => Ok(stream
.map(move |x| Value::Record { .map(move |x| Value::Record {
cols: vec![name.clone()], cols: vec![name.clone()],
vals: vec![x], vals: vec![x],
span, span,
}) })
.into_pipeline_data()), .into_pipeline_data(engine_state.ctrlc.clone())),
PipelineData::Value(input) => Ok(Value::Record { PipelineData::Value(input) => Ok(Value::Record {
cols: vec![name], cols: vec![name],
vals: vec![input], vals: vec![input],

View File

@ -1,6 +1,9 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Value}; use nu_protocol::{
Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError, Signature,
Span, Value,
};
#[derive(Clone)] #[derive(Clone)]
pub struct FromJson; pub struct FromJson;
@ -68,7 +71,7 @@ impl Command for FromJson {
fn run( fn run(
&self, &self,
_engine_state: &EngineState, engine_state: &EngineState,
_stack: &mut Stack, _stack: &mut Stack,
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
@ -90,7 +93,7 @@ impl Command for FromJson {
Err(error) => Value::Error { error }, Err(error) => Value::Error { error },
} }
}) })
.into_pipeline_data()) .into_pipeline_data(engine_state.ctrlc.clone()))
} else { } else {
Ok(convert_string_to_value(string_input, span)?.into_pipeline_data()) Ok(convert_string_to_value(string_input, span)?.into_pipeline_data())
} }

View File

@ -20,13 +20,16 @@ impl Command for SubCommand {
fn run( fn run(
&self, &self,
_engine_state: &EngineState, engine_state: &EngineState,
_stack: &mut Stack, _stack: &mut Stack,
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let head = call.head; let head = call.head;
input.map(move |value| abs_helper(value, head)) input.map(
move |value| abs_helper(value, head),
engine_state.ctrlc.clone(),
)
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {

View File

@ -24,12 +24,12 @@ impl Command for Size {
fn run( fn run(
&self, &self,
_engine_state: &EngineState, engine_state: &EngineState,
_stack: &mut Stack, _stack: &mut Stack,
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
size(call, input) size(engine_state, call, input)
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
@ -100,9 +100,14 @@ impl Command for Size {
} }
} }
fn size(call: &Call, input: PipelineData) -> Result<PipelineData, ShellError> { fn size(
engine_state: &EngineState,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let span = call.head; let span = call.head;
input.map(move |v| match v.as_string() { input.map(
move |v| match v.as_string() {
Ok(s) => count(&s, span), Ok(s) => count(&s, span),
Err(_) => Value::Error { Err(_) => Value::Error {
error: ShellError::PipelineMismatch { error: ShellError::PipelineMismatch {
@ -111,7 +116,9 @@ fn size(call: &Call, input: PipelineData) -> Result<PipelineData, ShellError> {
origin: span, origin: span,
}, },
}, },
}) },
engine_state.ctrlc.clone(),
)
} }
fn count(contents: &str, span: Span) -> Value { fn count(contents: &str, span: Span) -> Value {

View File

@ -39,22 +39,26 @@ impl Command for SubCommand {
fn run( fn run(
&self, &self,
_engine_state: &EngineState, engine_state: &EngineState,
_stack: &mut Stack, _stack: &mut Stack,
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
split_chars(call, input) split_chars(engine_state, call, input)
} }
} }
fn split_chars( fn split_chars(
engine_state: &EngineState,
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let span = call.head; let span = call.head;
input.flat_map(move |x| split_chars_helper(&x, span)) input.flat_map(
move |x| split_chars_helper(&x, span),
engine_state.ctrlc.clone(),
)
} }
fn split_chars_helper(v: &Value, name: Span) -> Vec<Value> { fn split_chars_helper(v: &Value, name: Span) -> Vec<Value> {

View File

@ -54,7 +54,10 @@ fn split_column(
let rest: Vec<Spanned<String>> = call.rest(engine_state, stack, 1)?; 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("collapse-empty");
input.flat_map(move |x| split_column_helper(&x, &separator, &rest, collapse_empty, name_span)) input.flat_map(
move |x| split_column_helper(&x, &separator, &rest, collapse_empty, name_span),
engine_state.ctrlc.clone(),
)
} }
fn split_column_helper( fn split_column_helper(

View File

@ -45,7 +45,10 @@ fn split_row(
let name_span = call.head; let name_span = call.head;
let separator: Spanned<String> = call.req(engine_state, stack, 0)?; let separator: Spanned<String> = call.req(engine_state, stack, 0)?;
input.flat_map(move |x| split_row_helper(&x, &separator, name_span)) input.flat_map(
move |x| split_row_helper(&x, &separator, name_span),
engine_state.ctrlc.clone(),
)
} }
fn split_row_helper(v: &Value, separator: &Spanned<String>, name: Span) -> Vec<Value> { fn split_row_helper(v: &Value, separator: &Spanned<String>, name: Span) -> Vec<Value> {

View File

@ -1,7 +1,7 @@
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EngineState, Stack}, engine::{Command, EngineState, Stack},
Example, IntoPipelineData, PipelineData, ShellError, Signature, Value, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Value,
}; };
use sysinfo::{ProcessExt, System, SystemExt}; use sysinfo::{ProcessExt, System, SystemExt};
@ -30,12 +30,12 @@ impl Command for Ps {
fn run( fn run(
&self, &self,
_engine_state: &EngineState, engine_state: &EngineState,
_stack: &mut Stack, _stack: &mut Stack,
call: &Call, call: &Call,
_input: PipelineData, _input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
run_ps(call) run_ps(engine_state, call)
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
@ -47,7 +47,7 @@ impl Command for Ps {
} }
} }
fn run_ps(call: &Call) -> Result<PipelineData, ShellError> { fn run_ps(engine_state: &EngineState, call: &Call) -> Result<PipelineData, ShellError> {
let span = call.head; let span = call.head;
let long = call.has_flag("long"); let long = call.has_flag("long");
let mut sys = System::new_all(); let mut sys = System::new_all();
@ -126,5 +126,7 @@ fn run_ps(call: &Call) -> Result<PipelineData, ShellError> {
} }
} }
Ok(output.into_iter().into_pipeline_data()) Ok(output
.into_iter()
.into_pipeline_data(engine_state.ctrlc.clone()))
} }

View File

@ -7,7 +7,7 @@ use std::sync::mpsc;
use nu_protocol::engine::{EngineState, Stack}; use nu_protocol::engine::{EngineState, Stack};
use nu_protocol::{ast::Call, engine::Command, ShellError, Signature, SyntaxShape, Value}; use nu_protocol::{ast::Call, engine::Command, ShellError, Signature, SyntaxShape, Value};
use nu_protocol::{IntoPipelineData, PipelineData, Span, Spanned}; use nu_protocol::{IntoInterruptiblePipelineData, PipelineData, Span, Spanned};
use nu_engine::CallExt; use nu_engine::CallExt;
@ -49,7 +49,7 @@ impl Command for External {
last_expression, last_expression,
env_vars, env_vars,
}; };
command.run_with_input(input) command.run_with_input(engine_state, input)
} }
} }
@ -61,9 +61,15 @@ pub struct ExternalCommand {
} }
impl ExternalCommand { impl ExternalCommand {
pub fn run_with_input(&self, input: PipelineData) -> Result<PipelineData, ShellError> { pub fn run_with_input(
&self,
engine_state: &EngineState,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let mut process = self.create_command(); let mut process = self.create_command();
let ctrlc = engine_state.ctrlc.clone();
// TODO. We don't have a way to know the current directory // TODO. We don't have a way to know the current directory
// This should be information from the EvaluationContex or EngineState // This should be information from the EvaluationContex or EngineState
let path = env::current_dir().unwrap(); let path = env::current_dir().unwrap();
@ -155,7 +161,7 @@ impl ExternalCommand {
}); });
// The ValueStream is consumed by the next expression in the pipeline // The ValueStream is consumed by the next expression in the pipeline
ChannelReceiver::new(rx).into_pipeline_data() ChannelReceiver::new(rx).into_pipeline_data(ctrlc)
} else { } else {
PipelineData::new() PipelineData::new()
}; };

View File

@ -1,7 +1,10 @@
use super::Command; use super::Command;
use crate::{ast::Block, BlockId, DeclId, Example, Signature, Span, Type, VarId}; use crate::{ast::Block, BlockId, DeclId, Example, Signature, Span, Type, VarId};
use core::panic; use core::panic;
use std::collections::HashMap; use std::{
collections::HashMap,
sync::{atomic::AtomicBool, Arc},
};
#[derive(Clone)] #[derive(Clone)]
pub struct EngineState { pub struct EngineState {
@ -11,6 +14,7 @@ pub struct EngineState {
decls: im::Vector<Box<dyn Command + 'static>>, decls: im::Vector<Box<dyn Command + 'static>>,
blocks: im::Vector<Block>, blocks: im::Vector<Block>,
pub scope: im::Vector<ScopeFrame>, pub scope: im::Vector<ScopeFrame>,
pub ctrlc: Option<Arc<AtomicBool>>,
} }
// Tells whether a decl etc. is visible or not // Tells whether a decl etc. is visible or not
@ -102,6 +106,7 @@ impl EngineState {
decls: im::vector![], decls: im::vector![],
blocks: im::vector![], blocks: im::vector![],
scope: im::vector![ScopeFrame::new()], scope: im::vector![ScopeFrame::new()],
ctrlc: None,
} }
} }

View File

@ -1,3 +1,5 @@
use std::sync::{atomic::AtomicBool, Arc};
use crate::{ast::PathMember, ShellError, Span, Value, ValueStream}; use crate::{ast::PathMember, ShellError, Span, Value, ValueStream};
pub enum PipelineData { pub enum PipelineData {
@ -40,18 +42,22 @@ impl PipelineData {
} }
/// Simplified mapper to help with simple values also. For full iterator support use `.into_iter()` instead /// Simplified mapper to help with simple values also. For full iterator support use `.into_iter()` instead
pub fn map<F>(self, mut f: F) -> Result<PipelineData, ShellError> pub fn map<F>(
self,
mut f: F,
ctrlc: Option<Arc<AtomicBool>>,
) -> Result<PipelineData, ShellError>
where where
Self: Sized, Self: Sized,
F: FnMut(Value) -> Value + 'static + Send, F: FnMut(Value) -> Value + 'static + Send,
{ {
match self { match self {
PipelineData::Value(Value::List { vals, .. }) => { PipelineData::Value(Value::List { vals, .. }) => {
Ok(vals.into_iter().map(f).into_pipeline_data()) Ok(vals.into_iter().map(f).into_pipeline_data(ctrlc))
} }
PipelineData::Stream(stream) => Ok(stream.map(f).into_pipeline_data()), PipelineData::Stream(stream) => Ok(stream.map(f).into_pipeline_data(ctrlc)),
PipelineData::Value(Value::Range { val, .. }) => { PipelineData::Value(Value::Range { val, .. }) => {
Ok(val.into_range_iter()?.map(f).into_pipeline_data()) Ok(val.into_range_iter()?.map(f).into_pipeline_data(ctrlc))
} }
PipelineData::Value(v) => { PipelineData::Value(v) => {
let output = f(v); let output = f(v);
@ -64,7 +70,11 @@ impl PipelineData {
} }
/// Simplified flatmapper. For full iterator support use `.into_iter()` instead /// Simplified flatmapper. For full iterator support use `.into_iter()` instead
pub fn flat_map<U, F>(self, mut f: F) -> Result<PipelineData, ShellError> pub fn flat_map<U, F>(
self,
mut f: F,
ctrlc: Option<Arc<AtomicBool>>,
) -> Result<PipelineData, ShellError>
where where
Self: Sized, Self: Sized,
U: IntoIterator<Item = Value>, U: IntoIterator<Item = Value>,
@ -73,14 +83,14 @@ impl PipelineData {
{ {
match self { match self {
PipelineData::Value(Value::List { vals, .. }) => { PipelineData::Value(Value::List { vals, .. }) => {
Ok(vals.into_iter().map(f).flatten().into_pipeline_data()) Ok(vals.into_iter().map(f).flatten().into_pipeline_data(ctrlc))
} }
PipelineData::Stream(stream) => Ok(stream.map(f).flatten().into_pipeline_data()), PipelineData::Stream(stream) => Ok(stream.map(f).flatten().into_pipeline_data(ctrlc)),
PipelineData::Value(Value::Range { val, .. }) => match val.into_range_iter() { PipelineData::Value(Value::Range { val, .. }) => match val.into_range_iter() {
Ok(iter) => Ok(iter.map(f).flatten().into_pipeline_data()), Ok(iter) => Ok(iter.map(f).flatten().into_pipeline_data(ctrlc)),
Err(error) => Err(error), Err(error) => Err(error),
}, },
PipelineData::Value(v) => Ok(f(v).into_iter().into_pipeline_data()), PipelineData::Value(v) => Ok(f(v).into_iter().into_pipeline_data(ctrlc)),
} }
} }
} }
@ -100,9 +110,12 @@ impl IntoIterator for PipelineData {
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
match self { match self {
PipelineData::Value(Value::List { vals, .. }) => PipelineIterator( PipelineData::Value(Value::List { vals, .. }) => {
PipelineData::Stream(ValueStream(Box::new(vals.into_iter()))), PipelineIterator(PipelineData::Stream(ValueStream {
), stream: Box::new(vals.into_iter()),
ctrlc: None,
}))
}
x => PipelineIterator(x), x => PipelineIterator(x),
} }
} }
@ -133,11 +146,18 @@ impl IntoPipelineData for Value {
} }
} }
impl<T> IntoPipelineData for T pub trait IntoInterruptiblePipelineData {
fn into_pipeline_data(self, ctrlc: Option<Arc<AtomicBool>>) -> PipelineData;
}
impl<T> IntoInterruptiblePipelineData for T
where where
T: Iterator<Item = Value> + Send + 'static, T: Iterator<Item = Value> + Send + 'static,
{ {
fn into_pipeline_data(self) -> PipelineData { fn into_pipeline_data(self, ctrlc: Option<Arc<AtomicBool>>) -> PipelineData {
PipelineData::Stream(ValueStream(Box::new(self))) PipelineData::Stream(ValueStream {
stream: Box::new(self),
ctrlc,
})
} }
} }

View File

@ -1,7 +1,16 @@
use crate::*; use crate::*;
use std::fmt::Debug; use std::{
fmt::Debug,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
};
pub struct ValueStream(pub Box<dyn Iterator<Item = Value> + Send + 'static>); pub struct ValueStream {
pub stream: Box<dyn Iterator<Item = Value> + Send + 'static>,
pub ctrlc: Option<Arc<AtomicBool>>,
}
impl ValueStream { impl ValueStream {
pub fn into_string(self) -> String { pub fn into_string(self) -> String {
@ -19,8 +28,14 @@ impl ValueStream {
.join("\n") .join("\n")
} }
pub fn from_stream(input: impl Iterator<Item = Value> + Send + 'static) -> ValueStream { pub fn from_stream(
ValueStream(Box::new(input)) input: impl Iterator<Item = Value> + Send + 'static,
ctrlc: Option<Arc<AtomicBool>>,
) -> ValueStream {
ValueStream {
stream: Box::new(input),
ctrlc,
}
} }
} }
@ -34,8 +49,14 @@ impl Iterator for ValueStream {
type Item = Value; type Item = Value;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
{ if let Some(ctrlc) = &self.ctrlc {
self.0.next() if ctrlc.load(Ordering::SeqCst) {
None
} else {
self.stream.next()
}
} else {
self.stream.next()
} }
} }
} }

View File

@ -1,4 +1,10 @@
use std::io::Write; use std::{
io::Write,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
};
use dialoguer::{ use dialoguer::{
console::{Style, Term}, console::{Style, Term},
@ -84,6 +90,20 @@ fn main() -> Result<()> {
let mut engine_state = create_default_context(); let mut engine_state = create_default_context();
// TODO: make this conditional in the future
// Ctrl-c protection section
let ctrlc = Arc::new(AtomicBool::new(false));
let handler_ctrlc = ctrlc.clone();
let engine_state_ctrlc = ctrlc.clone();
ctrlc::set_handler(move || {
handler_ctrlc.store(true, Ordering::SeqCst);
})
.expect("Error setting Ctrl-C handler");
engine_state.ctrlc = Some(engine_state_ctrlc);
// End ctrl-c protection section
if let Some(path) = std::env::args().nth(1) { if let Some(path) = std::env::args().nth(1) {
let file = std::fs::read(&path).into_diagnostic()?; let file = std::fs::read(&path).into_diagnostic()?;
@ -153,6 +173,9 @@ fn main() -> Result<()> {
}; };
loop { loop {
//Reset the ctrl-c handler
ctrlc.store(false, Ordering::SeqCst);
let line_editor = Reedline::create() let line_editor = Reedline::create()
.into_diagnostic()? .into_diagnostic()?
.with_completion_action_handler(Box::new(FuzzyCompletion { .with_completion_action_handler(Box::new(FuzzyCompletion {