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,10 +1,10 @@
//! Implements the stream multiplexing interface for both the plugin side and the engine side.
use nu_plugin_protocol::{ByteStreamInfo, ListStreamInfo, PipelineDataHeader, StreamMessage};
use nu_protocol::{ByteStream, IntoSpanned, ListStream, PipelineData, Reader, ShellError};
use nu_protocol::{ByteStream, IntoSpanned, ListStream, PipelineData, Reader, ShellError, Signals};
use std::{
io::{Read, Write},
sync::{atomic::AtomicBool, Arc, Mutex},
sync::Mutex,
thread,
};
@ -170,7 +170,7 @@ pub trait InterfaceManager {
fn read_pipeline_data(
&self,
header: PipelineDataHeader,
ctrlc: Option<&Arc<AtomicBool>>,
signals: &Signals,
) -> Result<PipelineData, ShellError> {
self.prepare_pipeline_data(match header {
PipelineDataHeader::Empty => PipelineData::Empty,
@ -178,12 +178,12 @@ pub trait InterfaceManager {
PipelineDataHeader::ListStream(info) => {
let handle = self.stream_manager().get_handle();
let reader = handle.read_stream(info.id, self.get_interface())?;
ListStream::new(reader, info.span, ctrlc.cloned()).into()
ListStream::new(reader, info.span, signals.clone()).into()
}
PipelineDataHeader::ByteStream(info) => {
let handle = self.stream_manager().get_handle();
let reader = handle.read_stream(info.id, self.get_interface())?;
ByteStream::from_result_iter(reader, info.span, ctrlc.cloned(), info.type_).into()
ByteStream::from_result_iter(reader, info.span, signals.clone(), info.type_).into()
}
})
}

View File

@ -11,7 +11,7 @@ use nu_plugin_protocol::{
};
use nu_protocol::{
ByteStream, ByteStreamSource, ByteStreamType, DataSource, ListStream, PipelineData,
PipelineMetadata, ShellError, Span, Value,
PipelineMetadata, ShellError, Signals, Span, Value,
};
use std::{path::Path, sync::Arc};
@ -129,7 +129,7 @@ fn read_pipeline_data_empty() -> Result<(), ShellError> {
let header = PipelineDataHeader::Empty;
assert!(matches!(
manager.read_pipeline_data(header, None)?,
manager.read_pipeline_data(header, &Signals::empty())?,
PipelineData::Empty
));
Ok(())
@ -141,7 +141,7 @@ fn read_pipeline_data_value() -> Result<(), ShellError> {
let value = Value::test_int(4);
let header = PipelineDataHeader::Value(value.clone());
match manager.read_pipeline_data(header, None)? {
match manager.read_pipeline_data(header, &Signals::empty())? {
PipelineData::Value(read_value, ..) => assert_eq!(value, read_value),
PipelineData::ListStream(..) => panic!("unexpected ListStream"),
PipelineData::ByteStream(..) => panic!("unexpected ByteStream"),
@ -168,7 +168,7 @@ fn read_pipeline_data_list_stream() -> Result<(), ShellError> {
span: Span::test_data(),
});
let pipe = manager.read_pipeline_data(header, None)?;
let pipe = manager.read_pipeline_data(header, &Signals::empty())?;
assert!(
matches!(pipe, PipelineData::ListStream(..)),
"unexpected PipelineData: {pipe:?}"
@ -212,7 +212,7 @@ fn read_pipeline_data_byte_stream() -> Result<(), ShellError> {
type_: ByteStreamType::Unknown,
});
let pipe = manager.read_pipeline_data(header, None)?;
let pipe = manager.read_pipeline_data(header, &Signals::empty())?;
// need to consume input
manager.consume_all()?;
@ -257,7 +257,7 @@ fn read_pipeline_data_prepared_properly() -> Result<(), ShellError> {
id: 0,
span: Span::test_data(),
});
match manager.read_pipeline_data(header, None)? {
match manager.read_pipeline_data(header, &Signals::empty())? {
PipelineData::ListStream(_, meta) => match meta {
Some(PipelineMetadata { data_source, .. }) => match data_source {
DataSource::FilePath(path) => {
@ -353,7 +353,11 @@ fn write_pipeline_data_list_stream() -> Result<(), ShellError> {
// Set up pipeline data for a list stream
let pipe = PipelineData::ListStream(
ListStream::new(values.clone().into_iter(), Span::test_data(), None),
ListStream::new(
values.clone().into_iter(),
Span::test_data(),
Signals::empty(),
),
None,
);
@ -406,7 +410,7 @@ fn write_pipeline_data_byte_stream() -> Result<(), ShellError> {
ByteStream::read(
std::io::Cursor::new(expected),
span,
None,
Signals::empty(),
ByteStreamType::Unknown,
),
None,