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:
Ian Manske
2024-07-07 22:29:01 +00:00
committed by GitHub
parent c6b6b1b7a8
commit 399a7c8836
246 changed files with 1332 additions and 1234 deletions

View File

@@ -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(

View File

@@ -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())
}

View File

@@ -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(

View File

@@ -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(),
)
}

View File

@@ -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(),
)
}

View File

@@ -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(),
)
}

View File

@@ -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;
}

View File

@@ -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(),
)
}

View File

@@ -170,7 +170,7 @@ fn split_column(
input.flat_map(
move |x| split_column_helper(&x, &regex, &args.rest, args.collapse_empty, name_span),
engine_state.ctrlc.clone(),
engine_state.signals(),
)
}

View File

@@ -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() {

View File

@@ -170,7 +170,7 @@ fn split_row(
})?;
input.flat_map(
move |x| split_row_helper(&x, &regex, args.max_split, name_span),
engine_state.ctrlc.clone(),
engine_state.signals(),
)
}

View File

@@ -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(),
)
}

View File

@@ -108,7 +108,7 @@ fn operate(
ret
}
},
engine_state.ctrlc.clone(),
engine_state.signals(),
)
}

View File

@@ -116,7 +116,7 @@ fn operate(
ret
}
},
engine_state.ctrlc.clone(),
engine_state.signals(),
)
}

View File

@@ -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

View File

@@ -93,7 +93,7 @@ fn operate(
ret
}
},
engine_state.ctrlc.clone(),
engine_state.signals(),
)
}

View File

@@ -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(),
)
}

View File

@@ -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(),
)
}

View File

@@ -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(),
)
}

View File

@@ -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(),
)
}

View File

@@ -233,7 +233,7 @@ fn run(
),
}
},
engine_state.ctrlc.clone(),
engine_state.signals(),
)
}

View File

@@ -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(),
)
}

View File

@@ -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))
}

View File

@@ -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 {

View File

@@ -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(),
)
}

View File

@@ -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(),
)
}

View File

@@ -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(),
)
}

View File

@@ -122,7 +122,7 @@ fn stats(
),
}
},
engine_state.ctrlc.clone(),
engine_state.signals(),
)
}

View File

@@ -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(),
)
}

View File

@@ -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)]