forked from extern/nushell
Add and use new Signals
struct (#13314)
# Description This PR introduces a new `Signals` struct to replace our adhoc passing around of `ctrlc: Option<Arc<AtomicBool>>`. Doing so has a few benefits: - We can better enforce when/where resetting or triggering an interrupt is allowed. - Consolidates `nu_utils::ctrl_c::was_pressed` and other ad-hoc re-implementations into a single place: `Signals::check`. - This allows us to add other types of signals later if we want. E.g., exiting or suspension. - Similarly, we can more easily change the underlying implementation if we need to in the future. - Places that used to have a `ctrlc` of `None` now use `Signals::empty()`, so we can double check these usages for correctness in the future.
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
use indexmap::{indexmap, IndexMap};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
use nu_protocol::Signals;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::sync::{atomic::AtomicBool, Arc};
|
||||
|
||||
// Character used to separate directories in a Path Environment variable on windows is ";"
|
||||
#[cfg(target_family = "windows")]
|
||||
@@ -229,11 +229,13 @@ impl Command for Char {
|
||||
let list = call.has_flag_const(working_set, "list")?;
|
||||
let integer = call.has_flag_const(working_set, "integer")?;
|
||||
let unicode = call.has_flag_const(working_set, "unicode")?;
|
||||
let ctrlc = working_set.permanent().ctrlc.clone();
|
||||
|
||||
// handle -l flag
|
||||
if list {
|
||||
return Ok(generate_character_list(ctrlc, call.head));
|
||||
return Ok(generate_character_list(
|
||||
working_set.permanent().signals().clone(),
|
||||
call.head,
|
||||
));
|
||||
}
|
||||
|
||||
// handle -i flag
|
||||
@@ -264,11 +266,13 @@ impl Command for Char {
|
||||
let list = call.has_flag(engine_state, stack, "list")?;
|
||||
let integer = call.has_flag(engine_state, stack, "integer")?;
|
||||
let unicode = call.has_flag(engine_state, stack, "unicode")?;
|
||||
let ctrlc = engine_state.ctrlc.clone();
|
||||
|
||||
// handle -l flag
|
||||
if list {
|
||||
return Ok(generate_character_list(ctrlc, call_span));
|
||||
return Ok(generate_character_list(
|
||||
engine_state.signals().clone(),
|
||||
call_span,
|
||||
));
|
||||
}
|
||||
|
||||
// handle -i flag
|
||||
@@ -289,7 +293,7 @@ impl Command for Char {
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_character_list(ctrlc: Option<Arc<AtomicBool>>, call_span: Span) -> PipelineData {
|
||||
fn generate_character_list(signals: Signals, call_span: Span) -> PipelineData {
|
||||
CHAR_MAP
|
||||
.iter()
|
||||
.map(move |(name, s)| {
|
||||
@@ -308,7 +312,7 @@ fn generate_character_list(ctrlc: Option<Arc<AtomicBool>>, call_span: Span) -> P
|
||||
|
||||
Value::record(record, call_span)
|
||||
})
|
||||
.into_pipeline_data(call_span, ctrlc)
|
||||
.into_pipeline_data(call_span, signals)
|
||||
}
|
||||
|
||||
fn handle_integer_flag(
|
||||
|
@@ -199,7 +199,7 @@ fn guess_width(
|
||||
Err(e) => Value::error(e, input_span),
|
||||
}
|
||||
})
|
||||
.into_pipeline_data(input_span, engine_state.ctrlc.clone()))
|
||||
.into_pipeline_data(input_span, engine_state.signals().clone()))
|
||||
} else {
|
||||
let length = result[0].len();
|
||||
let columns: Vec<String> = (0..length).map(|n| format!("column{n}")).collect();
|
||||
@@ -224,7 +224,7 @@ fn guess_width(
|
||||
Err(e) => Value::error(e, input_span),
|
||||
}
|
||||
})
|
||||
.into_pipeline_data(input_span, engine_state.ctrlc.clone()))
|
||||
.into_pipeline_data(input_span, engine_state.signals().clone()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +235,6 @@ fn detect_columns(
|
||||
args: Arguments,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let name_span = call.head;
|
||||
let ctrlc = engine_state.ctrlc.clone();
|
||||
let config = engine_state.get_config();
|
||||
let input = input.collect_string("", config)?;
|
||||
|
||||
@@ -316,7 +315,7 @@ fn detect_columns(
|
||||
None => Value::record(record, name_span),
|
||||
}
|
||||
})
|
||||
.into_pipeline_data(call.head, ctrlc))
|
||||
.into_pipeline_data(call.head, engine_state.signals().clone()))
|
||||
} else {
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
@@ -75,7 +75,7 @@ pub fn operate(
|
||||
cell_paths,
|
||||
};
|
||||
|
||||
general_operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
general_operate(action, args, input, call.head, engine_state.signals())
|
||||
}
|
||||
|
||||
fn action(
|
||||
|
@@ -127,7 +127,7 @@ fn run(
|
||||
Some(format) => format_helper(value, format.item.as_str(), format.span, head),
|
||||
None => format_helper_rfc2822(value, head),
|
||||
},
|
||||
engine_state.ctrlc.clone(),
|
||||
engine_state.signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -81,7 +81,7 @@ impl Command for FormatDuration {
|
||||
arg,
|
||||
input,
|
||||
call.head,
|
||||
engine_state.ctrlc.clone(),
|
||||
engine_state.signals(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ impl Command for FormatDuration {
|
||||
arg,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
working_set.permanent().signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -76,7 +76,7 @@ impl Command for FormatFilesize {
|
||||
arg,
|
||||
input,
|
||||
call.head,
|
||||
engine_state.ctrlc.clone(),
|
||||
engine_state.signals(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ impl Command for FormatFilesize {
|
||||
arg,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
working_set.permanent().signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -1,10 +1,7 @@
|
||||
use fancy_regex::{Captures, Regex};
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::{engine::StateWorkingSet, ListStream};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
sync::{atomic::AtomicBool, Arc},
|
||||
};
|
||||
use nu_protocol::{engine::StateWorkingSet, ListStream, Signals};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Parse;
|
||||
@@ -163,8 +160,6 @@ fn operate(
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let ctrlc = engine_state.ctrlc.clone();
|
||||
|
||||
match input {
|
||||
PipelineData::Empty => Ok(PipelineData::Empty),
|
||||
PipelineData::Value(value, ..) => match value {
|
||||
@@ -192,10 +187,10 @@ fn operate(
|
||||
columns,
|
||||
iter,
|
||||
span: head,
|
||||
ctrlc,
|
||||
signals: engine_state.signals().clone(),
|
||||
};
|
||||
|
||||
Ok(ListStream::new(iter, head, None).into())
|
||||
Ok(ListStream::new(iter, head, Signals::empty()).into())
|
||||
}
|
||||
value => Err(ShellError::PipelineMismatch {
|
||||
exp_input_type: "string".into(),
|
||||
@@ -220,7 +215,7 @@ fn operate(
|
||||
columns,
|
||||
iter,
|
||||
span: head,
|
||||
ctrlc,
|
||||
signals: engine_state.signals().clone(),
|
||||
}
|
||||
})
|
||||
.into()),
|
||||
@@ -232,10 +227,10 @@ fn operate(
|
||||
columns,
|
||||
iter: lines,
|
||||
span: head,
|
||||
ctrlc,
|
||||
signals: engine_state.signals().clone(),
|
||||
};
|
||||
|
||||
Ok(ListStream::new(iter, head, None).into())
|
||||
Ok(ListStream::new(iter, head, Signals::empty()).into())
|
||||
} else {
|
||||
Ok(PipelineData::Empty)
|
||||
}
|
||||
@@ -302,7 +297,7 @@ struct ParseIter<I: Iterator<Item = Result<String, ShellError>>> {
|
||||
columns: Vec<String>,
|
||||
iter: I,
|
||||
span: Span,
|
||||
ctrlc: Option<Arc<AtomicBool>>,
|
||||
signals: Signals,
|
||||
}
|
||||
|
||||
impl<I: Iterator<Item = Result<String, ShellError>>> ParseIter<I> {
|
||||
@@ -320,7 +315,7 @@ impl<I: Iterator<Item = Result<String, ShellError>>> Iterator for ParseIter<I> {
|
||||
|
||||
fn next(&mut self) -> Option<Value> {
|
||||
loop {
|
||||
if nu_utils::ctrl_c::was_pressed(&self.ctrlc) {
|
||||
if self.signals.interrupted() {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@@ -124,7 +124,7 @@ fn split_chars(
|
||||
let span = call.head;
|
||||
input.map(
|
||||
move |x| split_chars_helper(&x, span, graphemes),
|
||||
engine_state.ctrlc.clone(),
|
||||
engine_state.signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -170,7 +170,7 @@ fn split_column(
|
||||
|
||||
input.flat_map(
|
||||
move |x| split_column_helper(&x, ®ex, &args.rest, args.collapse_empty, name_span),
|
||||
engine_state.ctrlc.clone(),
|
||||
engine_state.signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -215,9 +215,7 @@ fn split_list(
|
||||
|
||||
let matcher = Matcher::new(has_regex, separator)?;
|
||||
for val in input {
|
||||
if nu_utils::ctrl_c::was_pressed(&engine_state.ctrlc) {
|
||||
break;
|
||||
}
|
||||
engine_state.signals().check(call.head)?;
|
||||
|
||||
if matcher.compare(&val)? {
|
||||
if !temp_list.is_empty() {
|
||||
|
@@ -170,7 +170,7 @@ fn split_row(
|
||||
})?;
|
||||
input.flat_map(
|
||||
move |x| split_row_helper(&x, ®ex, args.max_split, name_span),
|
||||
engine_state.ctrlc.clone(),
|
||||
engine_state.signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -177,7 +177,7 @@ fn split_words(
|
||||
|
||||
input.map(
|
||||
move |x| split_words_helper(&x, args.word_length, span, args.graphemes),
|
||||
engine_state.ctrlc.clone(),
|
||||
engine_state.signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -108,7 +108,7 @@ fn operate(
|
||||
ret
|
||||
}
|
||||
},
|
||||
engine_state.ctrlc.clone(),
|
||||
engine_state.signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -116,7 +116,7 @@ fn operate(
|
||||
ret
|
||||
}
|
||||
},
|
||||
engine_state.ctrlc.clone(),
|
||||
engine_state.signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -38,7 +38,7 @@ where
|
||||
case_operation,
|
||||
cell_paths,
|
||||
};
|
||||
general_operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
general_operate(action, args, input, call.head, engine_state.signals())
|
||||
}
|
||||
|
||||
fn action<F>(input: &Value, args: &Arguments<F>, head: Span) -> Value
|
||||
|
@@ -93,7 +93,7 @@ fn operate(
|
||||
ret
|
||||
}
|
||||
},
|
||||
engine_state.ctrlc.clone(),
|
||||
engine_state.signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -68,7 +68,7 @@ impl Command for SubCommand {
|
||||
cell_paths,
|
||||
case_insensitive: call.has_flag(engine_state, stack, "ignore-case")?,
|
||||
};
|
||||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
operate(action, args, input, call.head, engine_state.signals())
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
@@ -103,7 +103,7 @@ impl Command for SubCommand {
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
working_set.permanent().signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -39,7 +39,7 @@ impl Command for SubCommand {
|
||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||
let args = CellPathOnlyArgs::from(cell_paths);
|
||||
|
||||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
operate(action, args, input, call.head, engine_state.signals())
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
@@ -56,7 +56,7 @@ impl Command for SubCommand {
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
working_set.permanent().signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -67,7 +67,7 @@ impl Command for SubCommand {
|
||||
compare_string,
|
||||
cell_paths,
|
||||
};
|
||||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
operate(action, args, input, call.head, engine_state.signals())
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
@@ -88,7 +88,7 @@ impl Command for SubCommand {
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
working_set.permanent().signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -68,7 +68,7 @@ impl Command for SubCommand {
|
||||
cell_paths,
|
||||
case_insensitive: call.has_flag(engine_state, stack, "ignore-case")?,
|
||||
};
|
||||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
operate(action, args, input, call.head, engine_state.signals())
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
@@ -89,7 +89,7 @@ impl Command for SubCommand {
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
working_set.permanent().signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -233,7 +233,7 @@ fn run(
|
||||
),
|
||||
}
|
||||
},
|
||||
engine_state.ctrlc.clone(),
|
||||
engine_state.signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -93,7 +93,7 @@ impl Command for SubCommand {
|
||||
cell_paths,
|
||||
graphemes: grapheme_flags(engine_state, stack, call)?,
|
||||
};
|
||||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
operate(action, args, input, call.head, engine_state.signals())
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
@@ -117,7 +117,7 @@ impl Command for SubCommand {
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
working_set.permanent().signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::Signals;
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
@@ -88,30 +89,35 @@ fn run(
|
||||
let mut iter = input.into_iter();
|
||||
let mut first = true;
|
||||
|
||||
let output = ByteStream::from_fn(span, None, ByteStreamType::String, move |buffer| {
|
||||
// Write each input to the buffer
|
||||
if let Some(value) = iter.next() {
|
||||
// Write the separator if this is not the first
|
||||
if first {
|
||||
first = false;
|
||||
} else if let Some(separator) = &separator {
|
||||
write!(buffer, "{}", separator)?;
|
||||
}
|
||||
|
||||
match value {
|
||||
Value::Error { error, .. } => {
|
||||
return Err(*error);
|
||||
let output = ByteStream::from_fn(
|
||||
span,
|
||||
Signals::empty(),
|
||||
ByteStreamType::String,
|
||||
move |buffer| {
|
||||
// Write each input to the buffer
|
||||
if let Some(value) = iter.next() {
|
||||
// Write the separator if this is not the first
|
||||
if first {
|
||||
first = false;
|
||||
} else if let Some(separator) = &separator {
|
||||
write!(buffer, "{}", separator)?;
|
||||
}
|
||||
// Hmm, not sure what we actually want.
|
||||
// `to_expanded_string` formats dates as human readable which feels funny.
|
||||
Value::Date { val, .. } => write!(buffer, "{val:?}")?,
|
||||
value => write!(buffer, "{}", value.to_expanded_string("\n", &config))?,
|
||||
|
||||
match value {
|
||||
Value::Error { error, .. } => {
|
||||
return Err(*error);
|
||||
}
|
||||
// Hmm, not sure what we actually want.
|
||||
// `to_expanded_string` formats dates as human readable which feels funny.
|
||||
Value::Date { val, .. } => write!(buffer, "{val:?}")?,
|
||||
value => write!(buffer, "{}", value.to_expanded_string("\n", &config))?,
|
||||
}
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
Ok(PipelineData::ByteStream(output, metadata))
|
||||
}
|
||||
|
@@ -130,7 +130,7 @@ fn run(
|
||||
cell_paths: (!cell_paths.is_empty()).then_some(cell_paths),
|
||||
graphemes,
|
||||
};
|
||||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
operate(action, args, input, call.head, engine_state.signals())
|
||||
}
|
||||
|
||||
fn action(input: &Value, arg: &Arguments, head: Span) -> Value {
|
||||
|
@@ -102,7 +102,7 @@ impl Command for SubCommand {
|
||||
no_regex,
|
||||
multiline,
|
||||
};
|
||||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
operate(action, args, input, call.head, engine_state.signals())
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
@@ -134,7 +134,7 @@ impl Command for SubCommand {
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
working_set.permanent().signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -50,7 +50,7 @@ impl Command for SubCommand {
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||
let args = CellPathOnlyArgs::from(cell_paths);
|
||||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
operate(action, args, input, call.head, engine_state.signals())
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
@@ -66,7 +66,7 @@ impl Command for SubCommand {
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
working_set.permanent().signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -70,7 +70,7 @@ impl Command for SubCommand {
|
||||
cell_paths,
|
||||
case_insensitive: call.has_flag(engine_state, stack, "ignore-case")?,
|
||||
};
|
||||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
operate(action, args, input, call.head, engine_state.signals())
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
@@ -92,7 +92,7 @@ impl Command for SubCommand {
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
working_set.permanent().signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -122,7 +122,7 @@ fn stats(
|
||||
),
|
||||
}
|
||||
},
|
||||
engine_state.ctrlc.clone(),
|
||||
engine_state.signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -103,7 +103,7 @@ impl Command for SubCommand {
|
||||
cell_paths,
|
||||
graphemes: grapheme_flags(engine_state, stack, call)?,
|
||||
};
|
||||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
operate(action, args, input, call.head, engine_state.signals())
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
@@ -133,7 +133,7 @@ impl Command for SubCommand {
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
working_set.permanent().signals(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -190,7 +190,7 @@ fn run(
|
||||
cell_paths,
|
||||
mode,
|
||||
};
|
||||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
operate(action, args, input, call.head, engine_state.signals())
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
Reference in New Issue
Block a user