Merge pull request #262 from nushell/ctrlc

Add initial ctrl-c support
This commit is contained in:
JT 2021-10-28 17:22:48 +13:00 committed by GitHub
commit 520d9e1fb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 318 additions and 144 deletions

24
Cargo.lock generated
View File

@ -264,6 +264,16 @@ dependencies = [
"syn",
]
[[package]]
name = "ctrlc"
version = "3.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a19c6cedffdc8c03a3346d723eb20bd85a13362bb96dc2ac000842c6381ec7bf"
dependencies = [
"nix",
"winapi",
]
[[package]]
name = "dialoguer"
version = "0.9.0"
@ -339,6 +349,7 @@ version = "0.1.0"
dependencies = [
"assert_cmd",
"crossterm",
"ctrlc",
"dialoguer",
"miette",
"nu-cli",
@ -558,6 +569,19 @@ dependencies = [
"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]]
name = "ntapi"
version = "0.3.6"

View File

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

View File

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

View File

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

View File

@ -26,12 +26,12 @@ impl Command for SubCommand {
fn run(
&self,
_engine_state: &EngineState,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
into_filesize(call, input)
into_filesize(engine_state, call, input)
}
fn examples(&self) -> Vec<Example> {
@ -114,30 +114,34 @@ impl Command for SubCommand {
}
fn into_filesize(
engine_state: &EngineState,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let head = call.head;
// let call_paths: Vec<ColumnPath> = args.rest(0)?;
input.map(move |v| {
action(v, head)
input.map(
move |v| {
action(v, head)
// FIXME: Add back cell_path support
// if column_paths.is_empty() {
// action(&v, v.tag())
// } else {
// let mut ret = v;
// for path in &column_paths {
// ret = ret.swap_data_by_column_path(
// path,
// Box::new(move |old| action(old, old.tag())),
// )?;
// }
// FIXME: Add back cell_path support
// if column_paths.is_empty() {
// action(&v, v.tag())
// } else {
// let mut ret = v;
// for path in &column_paths {
// ret = ret.swap_data_by_column_path(
// path,
// Box::new(move |old| action(old, old.tag())),
// )?;
// }
// Ok(ret)
// }
})
// Ok(ret)
// }
},
engine_state.ctrlc.clone(),
)
}
pub fn action(input: Value, span: Span) -> Value {

View File

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

View File

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

View File

@ -1,8 +1,8 @@
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
span, Example, IntoPipelineData, PipelineData, ShellError, Signature, Spanned, SyntaxShape,
Value,
span, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError,
Signature, Spanned, SyntaxShape, Value,
};
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() {
@ -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 {
let mut name = String::new();
let mut output = String::new();

View File

@ -7,6 +7,7 @@ use crate::*;
pub fn create_default_context() -> EngineState {
let mut engine_state = EngineState::new();
let delta = {
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::EngineState;
use nu_protocol::engine::Stack;
use nu_protocol::IntoPipelineData;
use nu_protocol::IntoInterruptiblePipelineData;
use nu_protocol::PipelineData;
use nu_protocol::{Signature, Value};
@ -30,7 +30,7 @@ impl Command for ListGitBranches {
fn run(
&self,
_engine_state: &EngineState,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_input: PipelineData,
@ -62,7 +62,9 @@ impl Command for ListGitBranches {
})
.collect();
Ok(lines.into_iter().into_pipeline_data())
Ok(lines
.into_iter()
.into_pipeline_data(engine_state.ctrlc.clone()))
} else {
Ok(PipelineData::new())
}

View File

@ -2,7 +2,7 @@ use chrono::{DateTime, Utc};
use nu_engine::eval_expression;
use nu_protocol::ast::Call;
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)]
pub struct Ls;
@ -112,6 +112,6 @@ impl Command for Ls {
},
_ => 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_protocol::ast::Call;
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)]
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_protocol::ast::Call;
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)]
pub struct Rm;
@ -170,7 +172,9 @@ fn rm(
// let temp = rm_helper(call, args).flatten();
// 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 })
}

View File

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

View File

@ -3,7 +3,8 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
Value,
};
use std::convert::TryInto;
@ -54,7 +55,7 @@ impl Command for Last {
.into_iter()
.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::engine::{Command, EngineState, Stack};
use nu_protocol::{IntoPipelineData, PipelineData, ShellError, Signature, Value};
use nu_protocol::{IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Value};
#[derive(Clone)]
pub struct Lines;
@ -22,7 +22,7 @@ impl Command for Lines {
fn run(
&self,
_engine_state: &EngineState,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
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) => {
let iter = stream
@ -74,7 +74,7 @@ impl Command for Lines {
})
.flatten();
Ok(iter.into_pipeline_data())
Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
}
PipelineData::Value(val) => Err(ShellError::UnsupportedInput(
format!("Not supported input: {}", val.as_string()?),

View File

@ -1,7 +1,10 @@
use nu_engine::eval_block;
use nu_protocol::ast::Call;
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::*;
#[derive(Clone)]
@ -46,6 +49,7 @@ impl Command for ParEach {
.expect("internal error: expected block");
let numbered = call.has_flag("numbered");
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone();
let block = engine_state.get_block(block_id);
let mut stack = stack.collect_captures(&block.captures);
@ -92,7 +96,7 @@ impl Command for ParEach {
.collect::<Vec<_>>()
.into_iter()
.flatten()
.into_pipeline_data()),
.into_pipeline_data(ctrlc)),
PipelineData::Value(Value::List { vals: val, .. }) => Ok(val
.into_iter()
.enumerate()
@ -133,7 +137,7 @@ impl Command for ParEach {
.collect::<Vec<_>>()
.into_iter()
.flatten()
.into_pipeline_data()),
.into_pipeline_data(ctrlc)),
PipelineData::Stream(stream) => Ok(stream
.enumerate()
.par_bridge()
@ -173,7 +177,7 @@ impl Command for ParEach {
.collect::<Vec<_>>()
.into_iter()
.flatten()
.into_pipeline_data()),
.into_pipeline_data(ctrlc)),
PipelineData::Value(Value::Record { cols, vals, .. }) => {
let mut output_cols = 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::engine::{Command, EngineState, Stack};
use nu_protocol::{
Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError, Signature,
Span, SyntaxShape, Value,
};
#[derive(Clone)]
@ -35,7 +36,7 @@ impl Command for Select {
let columns: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let span = call.head;
select(span, columns, input)
select(engine_state, span, columns, input)
}
fn examples(&self) -> Vec<Example> {
@ -55,6 +56,7 @@ impl Command for Select {
}
fn select(
engine_state: &EngineState,
span: Span,
columns: Vec<CellPath>,
input: PipelineData,
@ -84,7 +86,9 @@ fn select(
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
.map(move |x| {
@ -106,7 +110,7 @@ fn select(
Value::Record { cols, vals, span }
})
.into_pipeline_data()),
.into_pipeline_data(engine_state.ctrlc.clone())),
PipelineData::Value(v) => {
let mut cols = vec![];
let mut vals = vec![];

View File

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

View File

@ -1,7 +1,9 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
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)]
pub struct Wrap;
@ -37,14 +39,14 @@ impl Command for Wrap {
vals: vec![x],
span,
})
.into_pipeline_data()),
.into_pipeline_data(engine_state.ctrlc.clone())),
PipelineData::Stream(stream) => Ok(stream
.map(move |x| Value::Record {
cols: vec![name.clone()],
vals: vec![x],
span,
})
.into_pipeline_data()),
.into_pipeline_data(engine_state.ctrlc.clone())),
PipelineData::Value(input) => Ok(Value::Record {
cols: vec![name],
vals: vec![input],

View File

@ -1,6 +1,9 @@
use nu_protocol::ast::Call;
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)]
pub struct FromJson;
@ -68,7 +71,7 @@ impl Command for FromJson {
fn run(
&self,
_engine_state: &EngineState,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
@ -90,7 +93,7 @@ impl Command for FromJson {
Err(error) => Value::Error { error },
}
})
.into_pipeline_data())
.into_pipeline_data(engine_state.ctrlc.clone()))
} else {
Ok(convert_string_to_value(string_input, span)?.into_pipeline_data())
}

View File

@ -20,13 +20,16 @@ impl Command for SubCommand {
fn run(
&self,
_engine_state: &EngineState,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
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> {

View File

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

View File

@ -39,22 +39,26 @@ impl Command for SubCommand {
fn run(
&self,
_engine_state: &EngineState,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
split_chars(call, input)
split_chars(engine_state, call, input)
}
}
fn split_chars(
engine_state: &EngineState,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
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> {

View File

@ -54,7 +54,10 @@ fn split_column(
let rest: Vec<Spanned<String>> = call.rest(engine_state, stack, 1)?;
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(

View File

@ -45,7 +45,10 @@ fn split_row(
let name_span = call.head;
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> {

View File

@ -1,7 +1,7 @@
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Example, IntoPipelineData, PipelineData, ShellError, Signature, Value,
Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Value,
};
use sysinfo::{ProcessExt, System, SystemExt};
@ -30,12 +30,12 @@ impl Command for Ps {
fn run(
&self,
_engine_state: &EngineState,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
run_ps(call)
run_ps(engine_state, call)
}
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 long = call.has_flag("long");
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::{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;
@ -49,7 +49,7 @@ impl Command for External {
last_expression,
env_vars,
};
command.run_with_input(input)
command.run_with_input(engine_state, input)
}
}
@ -61,9 +61,15 @@ pub struct 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 ctrlc = engine_state.ctrlc.clone();
// TODO. We don't have a way to know the current directory
// This should be information from the EvaluationContex or EngineState
let path = env::current_dir().unwrap();
@ -155,7 +161,7 @@ impl ExternalCommand {
});
// 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 {
PipelineData::new()
};

View File

@ -1,7 +1,10 @@
use super::Command;
use crate::{ast::Block, BlockId, DeclId, Example, Signature, Span, Type, VarId};
use core::panic;
use std::collections::HashMap;
use std::{
collections::HashMap,
sync::{atomic::AtomicBool, Arc},
};
#[derive(Clone)]
pub struct EngineState {
@ -11,6 +14,7 @@ pub struct EngineState {
decls: im::Vector<Box<dyn Command + 'static>>,
blocks: im::Vector<Block>,
pub scope: im::Vector<ScopeFrame>,
pub ctrlc: Option<Arc<AtomicBool>>,
}
// Tells whether a decl etc. is visible or not
@ -102,6 +106,7 @@ impl EngineState {
decls: im::vector![],
blocks: im::vector![],
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};
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
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
Self: Sized,
F: FnMut(Value) -> Value + 'static + Send,
{
match self {
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, .. }) => {
Ok(val.into_range_iter()?.map(f).into_pipeline_data())
Ok(val.into_range_iter()?.map(f).into_pipeline_data(ctrlc))
}
PipelineData::Value(v) => {
let output = f(v);
@ -64,7 +70,11 @@ impl PipelineData {
}
/// 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
Self: Sized,
U: IntoIterator<Item = Value>,
@ -73,14 +83,14 @@ impl PipelineData {
{
match self {
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() {
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),
},
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 {
match self {
PipelineData::Value(Value::List { vals, .. }) => PipelineIterator(
PipelineData::Stream(ValueStream(Box::new(vals.into_iter()))),
),
PipelineData::Value(Value::List { vals, .. }) => {
PipelineIterator(PipelineData::Stream(ValueStream {
stream: Box::new(vals.into_iter()),
ctrlc: None,
}))
}
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
T: Iterator<Item = Value> + Send + 'static,
{
fn into_pipeline_data(self) -> PipelineData {
PipelineData::Stream(ValueStream(Box::new(self)))
fn into_pipeline_data(self, ctrlc: Option<Arc<AtomicBool>>) -> PipelineData {
PipelineData::Stream(ValueStream {
stream: Box::new(self),
ctrlc,
})
}
}

View File

@ -1,7 +1,16 @@
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 {
pub fn into_string(self) -> String {
@ -19,8 +28,14 @@ impl ValueStream {
.join("\n")
}
pub fn from_stream(input: impl Iterator<Item = Value> + Send + 'static) -> ValueStream {
ValueStream(Box::new(input))
pub fn from_stream(
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;
fn next(&mut self) -> Option<Self::Item> {
{
self.0.next()
if let Some(ctrlc) = &self.ctrlc {
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::{
console::{Style, Term},
@ -84,6 +90,20 @@ fn main() -> Result<()> {
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) {
let file = std::fs::read(&path).into_diagnostic()?;
@ -153,6 +173,9 @@ fn main() -> Result<()> {
};
loop {
//Reset the ctrl-c handler
ctrlc.store(false, Ordering::SeqCst);
let line_editor = Reedline::create()
.into_diagnostic()?
.with_completion_action_handler(Box::new(FuzzyCompletion {