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,11 +1,8 @@
use nu_ansi_term::*;
use nu_engine::command_prelude::*;
use nu_protocol::engine::StateWorkingSet;
use nu_protocol::{engine::StateWorkingSet, Signals};
use once_cell::sync::Lazy;
use std::{
collections::HashMap,
sync::{atomic::AtomicBool, Arc},
};
use std::collections::HashMap;
#[derive(Clone)]
pub struct AnsiCommand;
@ -657,10 +654,13 @@ Operating system commands:
let escape: bool = call.has_flag(engine_state, stack, "escape")?;
let osc: bool = call.has_flag(engine_state, stack, "osc")?;
let use_ansi_coloring = engine_state.get_config().use_ansi_coloring;
let ctrlc = engine_state.ctrlc.clone();
if list {
return Ok(generate_ansi_code_list(ctrlc, call.head, use_ansi_coloring));
return Ok(generate_ansi_code_list(
engine_state.signals().clone(),
call.head,
use_ansi_coloring,
));
}
// The code can now be one of the ansi abbreviations like green_bold
@ -691,10 +691,13 @@ Operating system commands:
let escape: bool = call.has_flag_const(working_set, "escape")?;
let osc: bool = call.has_flag_const(working_set, "osc")?;
let use_ansi_coloring = working_set.get_config().use_ansi_coloring;
let ctrlc = working_set.permanent().ctrlc.clone();
if list {
return Ok(generate_ansi_code_list(ctrlc, call.head, use_ansi_coloring));
return Ok(generate_ansi_code_list(
working_set.permanent().signals().clone(),
call.head,
use_ansi_coloring,
));
}
// The code can now be one of the ansi abbreviations like green_bold
@ -827,7 +830,7 @@ pub fn str_to_ansi(s: &str) -> Option<String> {
}
fn generate_ansi_code_list(
ctrlc: Option<Arc<AtomicBool>>,
signals: Signals,
call_span: Span,
use_ansi_coloring: bool,
) -> PipelineData {
@ -862,7 +865,7 @@ fn generate_ansi_code_list(
Value::record(record, call_span)
})
.into_pipeline_data(call_span, ctrlc)
.into_pipeline_data(call_span, signals.clone())
}
fn build_ansi_hashmap(v: &[AnsiCode]) -> HashMap<&str, &str> {

View File

@ -91,12 +91,12 @@ fn operate(
if column_paths.is_empty() {
input.map(
move |v| process_value(&v, text.as_deref()),
engine_state.ctrlc.clone(),
engine_state.signals(),
)
} else {
input.map(
move |v| process_each_path(v, &column_paths, text.as_deref(), command_span),
engine_state.ctrlc.clone(),
engine_state.signals(),
)
}
}

View File

@ -56,7 +56,7 @@ impl Command for SubCommand {
cell_paths,
config: config.clone(),
};
operate(action, args, input, call.head, engine_state.ctrlc.clone())
operate(action, args, input, call.head, engine_state.signals())
}
fn examples(&self) -> Vec<Example> {

View File

@ -1,10 +1,7 @@
use filesize::file_real_size_fast;
use nu_glob::Pattern;
use nu_protocol::{record, ShellError, Span, Value};
use std::{
path::PathBuf,
sync::{atomic::AtomicBool, Arc},
};
use nu_protocol::{record, ShellError, Signals, Span, Value};
use std::path::PathBuf;
#[derive(Debug, Clone)]
pub struct DirBuilder {
@ -82,8 +79,9 @@ impl DirInfo {
path: impl Into<PathBuf>,
params: &DirBuilder,
depth: Option<u64>,
ctrl_c: Option<Arc<AtomicBool>>,
) -> Self {
span: Span,
signals: &Signals,
) -> Result<Self, ShellError> {
let path = path.into();
let mut s = Self {
@ -107,14 +105,12 @@ impl DirInfo {
match std::fs::read_dir(&s.path) {
Ok(d) => {
for f in d {
if nu_utils::ctrl_c::was_pressed(&ctrl_c) {
break;
}
signals.check(span)?;
match f {
Ok(i) => match i.file_type() {
Ok(t) if t.is_dir() => {
s = s.add_dir(i.path(), depth, params, ctrl_c.clone())
s = s.add_dir(i.path(), depth, params, span, signals)?
}
Ok(_t) => s = s.add_file(i.path(), params),
Err(e) => s = s.add_error(e.into()),
@ -125,7 +121,7 @@ impl DirInfo {
}
Err(e) => s = s.add_error(e.into()),
}
s
Ok(s)
}
fn add_dir(
@ -133,21 +129,22 @@ impl DirInfo {
path: impl Into<PathBuf>,
mut depth: Option<u64>,
params: &DirBuilder,
ctrl_c: Option<Arc<AtomicBool>>,
) -> Self {
span: Span,
signals: &Signals,
) -> Result<Self, ShellError> {
if let Some(current) = depth {
if let Some(new) = current.checked_sub(1) {
depth = Some(new);
} else {
return self;
return Ok(self);
}
}
let d = DirInfo::new(path, params, depth, ctrl_c);
let d = DirInfo::new(path, params, depth, span, signals)?;
self.size += d.size;
self.blocks += d.blocks;
self.dirs.push(d);
self
Ok(self)
}
fn add_file(mut self, f: impl Into<PathBuf>, params: &DirBuilder) -> Self {

View File

@ -56,12 +56,7 @@ impl Command for Sleep {
break;
}
thread::sleep(CTRL_C_CHECK_INTERVAL.min(time_until_deadline));
// exit early if Ctrl+C was pressed
if nu_utils::ctrl_c::was_pressed(&engine_state.ctrlc) {
return Err(ShellError::InterruptedByUser {
span: Some(call.head),
});
}
engine_state.signals().check(call.head)?;
}
Ok(Value::nothing(call.head).into_pipeline_data())