diff --git a/crates/nu-command/src/database/commands/into_sqlite.rs b/crates/nu-command/src/database/commands/into_sqlite.rs index 27417fca2f..a529c024b0 100644 --- a/crates/nu-command/src/database/commands/into_sqlite.rs +++ b/crates/nu-command/src/database/commands/into_sqlite.rs @@ -241,7 +241,7 @@ fn insert_in_transaction( let tx = table.try_init(&first_val)?; for stream_value in stream { - if let Err(err) = signals.check(span) { + if let Err(err) = signals.check(&span) { tx.rollback().map_err(|e| ShellError::GenericError { error: "Failed to rollback SQLite transaction".into(), msg: e.to_string(), diff --git a/crates/nu-command/src/database/values/sqlite.rs b/crates/nu-command/src/database/values/sqlite.rs index 23f744fa9f..fa14fa96f1 100644 --- a/crates/nu-command/src/database/values/sqlite.rs +++ b/crates/nu-command/src/database/values/sqlite.rs @@ -588,7 +588,7 @@ fn prepared_statement_to_nu_list( let mut row_values = vec![]; for row_result in row_results { - signals.check(call_span)?; + signals.check(&call_span)?; if let Ok(row_value) = row_result { row_values.push(row_value); } @@ -614,7 +614,7 @@ fn prepared_statement_to_nu_list( let mut row_values = vec![]; for row_result in row_results { - signals.check(call_span)?; + signals.check(&call_span)?; if let Ok(row_value) = row_result { row_values.push(row_value); } diff --git a/crates/nu-command/src/filesystem/glob.rs b/crates/nu-command/src/filesystem/glob.rs index 7b200f3852..29afb84bfe 100644 --- a/crates/nu-command/src/filesystem/glob.rs +++ b/crates/nu-command/src/filesystem/glob.rs @@ -329,7 +329,7 @@ fn glob_to_value( ) -> ListStream { let map_signals = signals.clone(); let result = glob_results.filter_map(move |entry| { - if let Err(err) = map_signals.check(span) { + if let Err(err) = map_signals.check(&span) { return Some(Value::error(err, span)); }; let file_type = entry.file_type(); diff --git a/crates/nu-command/src/filesystem/ls.rs b/crates/nu-command/src/filesystem/ls.rs index e887ccfdbf..dced514a0d 100644 --- a/crates/nu-command/src/filesystem/ls.rs +++ b/crates/nu-command/src/filesystem/ls.rs @@ -341,7 +341,7 @@ fn ls_for_one_pattern( let mut paths_peek = paths.peekable(); let no_matches = paths_peek.peek().is_none(); - signals.check(call_span)?; + signals.check(&call_span)?; if no_matches { return Err(ShellError::GenericError { error: format!("No matches found for {:?}", path.item), @@ -979,14 +979,14 @@ fn read_dir( .read_dir() .map_err(|err| IoError::new(err, span, f.clone()))? .map(move |d| { - signals_clone.check(span)?; + signals_clone.check(&span)?; d.map(|r| r.path()) .map_err(|err| IoError::new(err, span, f.clone())) .map_err(ShellError::from) }); if !use_threads { let mut collected = items.collect::>(); - signals.check(span)?; + signals.check(&span)?; collected.sort_by(|a, b| match (a, b) { (Ok(a), Ok(b)) => a.cmp(b), (Ok(_), Err(_)) => Ordering::Greater, diff --git a/crates/nu-command/src/filesystem/rm.rs b/crates/nu-command/src/filesystem/rm.rs index 67e2402697..fedfe1b6d2 100644 --- a/crates/nu-command/src/filesystem/rm.rs +++ b/crates/nu-command/src/filesystem/rm.rs @@ -454,7 +454,7 @@ fn rm( }); for result in iter { - engine_state.signals().check(call.head)?; + engine_state.signals().check(&call.head)?; match result { Ok(None) => {} Ok(Some(msg)) => eprintln!("{msg}"), diff --git a/crates/nu-command/src/filesystem/save.rs b/crates/nu-command/src/filesystem/save.rs index efc42eda03..7549b0f2fd 100644 --- a/crates/nu-command/src/filesystem/save.rs +++ b/crates/nu-command/src/filesystem/save.rs @@ -543,7 +543,7 @@ fn stream_to_file( let mut reader = BufReader::new(source); let res = loop { - if let Err(err) = signals.check(span) { + if let Err(err) = signals.check(&span) { bar.abandoned_msg("# Cancelled #".to_owned()); return Err(err); } diff --git a/crates/nu-command/src/filters/last.rs b/crates/nu-command/src/filters/last.rs index b44bb98b5a..8f9a5d33a0 100644 --- a/crates/nu-command/src/filters/last.rs +++ b/crates/nu-command/src/filters/last.rs @@ -100,7 +100,7 @@ impl Command for Last { let mut buf = VecDeque::new(); for row in iterator { - engine_state.signals().check(head)?; + engine_state.signals().check(&head)?; if buf.len() == rows { buf.pop_front(); } diff --git a/crates/nu-command/src/filters/reduce.rs b/crates/nu-command/src/filters/reduce.rs index 6fc222c371..6983100d02 100644 --- a/crates/nu-command/src/filters/reduce.rs +++ b/crates/nu-command/src/filters/reduce.rs @@ -119,7 +119,7 @@ impl Command for Reduce { let mut closure = ClosureEval::new(engine_state, stack, closure); for value in iter { - engine_state.signals().check(head)?; + engine_state.signals().check(&head)?; acc = closure .add_arg(value) .add_arg(acc.clone()) diff --git a/crates/nu-command/src/filters/utils.rs b/crates/nu-command/src/filters/utils.rs index 6230bc2ab2..2cffb4db67 100644 --- a/crates/nu-command/src/filters/utils.rs +++ b/crates/nu-command/src/filters/utils.rs @@ -31,7 +31,7 @@ pub fn boolean_fold( let mut closure = ClosureEval::new(engine_state, stack, closure); for value in input { - engine_state.signals().check(head)?; + engine_state.signals().check(&head)?; let pred = closure.run_with_value(value)?.into_value(head)?.is_true(); if pred == accumulator { diff --git a/crates/nu-command/src/network/http/client.rs b/crates/nu-command/src/network/http/client.rs index 0d6097988a..985d6ceaae 100644 --- a/crates/nu-command/src/network/http/client.rs +++ b/crates/nu-command/src/network/http/client.rs @@ -468,7 +468,7 @@ fn send_cancellable_request( // ...and poll the channel for responses loop { - signals.check(span)?; + signals.check(&span)?; // 100ms wait time chosen arbitrarily match rx.recv_timeout(Duration::from_millis(100)) { @@ -526,7 +526,7 @@ fn send_cancellable_request_bytes( // ...and poll the channel for responses loop { - signals.check(span)?; + signals.check(&span)?; // 100ms wait time chosen arbitrarily match rx.recv_timeout(Duration::from_millis(100)) { diff --git a/crates/nu-command/src/platform/dir_info.rs b/crates/nu-command/src/platform/dir_info.rs index 6f64007019..9df6f49461 100644 --- a/crates/nu-command/src/platform/dir_info.rs +++ b/crates/nu-command/src/platform/dir_info.rs @@ -115,7 +115,7 @@ impl DirInfo { match std::fs::read_dir(&s.path) { Ok(d) => { for f in d { - signals.check(span)?; + signals.check(&span)?; match f { Ok(i) => match i.file_type() { diff --git a/crates/nu-command/src/platform/sleep.rs b/crates/nu-command/src/platform/sleep.rs index f995ac85be..939f009b54 100644 --- a/crates/nu-command/src/platform/sleep.rs +++ b/crates/nu-command/src/platform/sleep.rs @@ -56,7 +56,7 @@ impl Command for Sleep { break; } thread::sleep(CTRL_C_CHECK_INTERVAL.min(time_until_deadline)); - engine_state.signals().check(call.head)?; + engine_state.signals().check(&call.head)?; } Ok(Value::nothing(call.head).into_pipeline_data()) diff --git a/crates/nu-command/src/system/run_external.rs b/crates/nu-command/src/system/run_external.rs index 09d4d6c9f2..2df5e1aa08 100644 --- a/crates/nu-command/src/system/run_external.rs +++ b/crates/nu-command/src/system/run_external.rs @@ -431,7 +431,7 @@ fn expand_glob( let mut result: Vec = vec![]; for m in matches { - signals.check(span)?; + signals.check(&span)?; if let Ok(arg) = m { let arg = resolve_globbed_path_to_cwd_relative(arg, prefix.as_ref(), cwd); result.push(arg.into()); diff --git a/crates/nu-engine/src/compile/builder.rs b/crates/nu-engine/src/compile/builder.rs index 0526954ed2..6d6215a42d 100644 --- a/crates/nu-engine/src/compile/builder.rs +++ b/crates/nu-engine/src/compile/builder.rs @@ -347,7 +347,9 @@ impl BlockBuilder { /// Deallocate a register and set it to `Empty`, if it is allocated pub(crate) fn drop_reg(&mut self, reg_id: RegId) -> Result<(), CompileError> { if self.is_allocated(reg_id) { - self.push(Instruction::Drop { src: reg_id }.into_spanned(Span::unknown()))?; + // try using the block Span if available, since that's slightly more helpful than Span::unknown + let span = self.block_span.unwrap_or(Span::unknown()); + self.push(Instruction::Drop { src: reg_id }.into_spanned(span))?; } Ok(()) } diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index 6fecf9dd7a..92d737d505 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -18,7 +18,7 @@ pub fn eval_call( call: &Call, input: PipelineData, ) -> Result { - engine_state.signals().check(call.head)?; + engine_state.signals().check(&call.head)?; let decl = engine_state.get_decl(call.decl_id); if !decl.is_known_external() && call.named_iter().any(|(flag, _, _)| flag.item == "help") { diff --git a/crates/nu-engine/src/eval_ir.rs b/crates/nu-engine/src/eval_ir.rs index 802f58e249..576c5e77a3 100644 --- a/crates/nu-engine/src/eval_ir.rs +++ b/crates/nu-engine/src/eval_ir.rs @@ -292,6 +292,9 @@ fn eval_instruction( ) -> Result { use self::InstructionResult::*; + // Check for interrupt if necessary + instruction.check_interrupt(ctx.engine_state, span)?; + // See the docs for `Instruction` for more information on what these instructions are supposed // to do. match instruction { diff --git a/crates/nu-protocol/src/ir/mod.rs b/crates/nu-protocol/src/ir/mod.rs index 6cb2840874..73a7190fb8 100644 --- a/crates/nu-protocol/src/ir/mod.rs +++ b/crates/nu-protocol/src/ir/mod.rs @@ -1,5 +1,5 @@ use crate::{ - BlockId, DeclId, Filesize, RegId, Span, Value, VarId, + BlockId, DeclId, Filesize, RegId, ShellError, Span, Value, VarId, ast::{CellPath, Expression, Operator, Pattern, RangeInclusion}, engine::EngineState, }; @@ -382,6 +382,20 @@ impl Instruction { } Ok(()) } + + /// Check for an interrupt before certain instructions + pub fn check_interrupt( + &self, + engine_state: &EngineState, + span: &Span, + ) -> Result<(), ShellError> { + match self { + Instruction::Jump { .. } | Instruction::Return { .. } => { + engine_state.signals().check(span) + } + _ => Ok(()), + } + } } // This is to document/enforce the size of `Instruction` in bytes. diff --git a/crates/nu-protocol/src/pipeline/byte_stream.rs b/crates/nu-protocol/src/pipeline/byte_stream.rs index 4723a8134b..2d3e412e7f 100644 --- a/crates/nu-protocol/src/pipeline/byte_stream.rs +++ b/crates/nu-protocol/src/pipeline/byte_stream.rs @@ -814,7 +814,7 @@ impl Reader { impl Read for Reader { fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.signals.check(self.span).map_err(ShellErrorBridge)?; + self.signals.check(&self.span).map_err(ShellErrorBridge)?; self.reader.read(buf) } } @@ -1295,7 +1295,7 @@ fn generic_copy( let buf = &mut [0; DEFAULT_BUF_SIZE]; let mut len = 0; loop { - signals.check(span)?; + signals.check(&span)?; let n = match reader.read(buf) { Ok(0) => break, Ok(n) => n, diff --git a/crates/nu-protocol/src/pipeline/pipeline_data.rs b/crates/nu-protocol/src/pipeline/pipeline_data.rs index d2981da7e3..c5a0f34051 100644 --- a/crates/nu-protocol/src/pipeline/pipeline_data.rs +++ b/crates/nu-protocol/src/pipeline/pipeline_data.rs @@ -784,7 +784,7 @@ where let span = span.unwrap_or(Span::unknown()); const OUTPUT_CHUNK_SIZE: usize = 8192; for chunk in data.as_ref().chunks(OUTPUT_CHUNK_SIZE) { - signals.check(span)?; + signals.check(&span)?; destination .write_all(chunk) .map_err(|err| io_error_map(err, location!()))?; diff --git a/crates/nu-protocol/src/pipeline/signals.rs b/crates/nu-protocol/src/pipeline/signals.rs index f9a00329e7..f2222cb953 100644 --- a/crates/nu-protocol/src/pipeline/signals.rs +++ b/crates/nu-protocol/src/pipeline/signals.rs @@ -44,11 +44,11 @@ impl Signals { /// /// Otherwise, returns `Ok`. #[inline] - pub fn check(&self, span: Span) -> Result<(), ShellError> { + pub fn check(&self, span: &Span) -> Result<(), ShellError> { #[inline] #[cold] - fn interrupt_error(span: Span) -> Result<(), ShellError> { - Err(ShellError::Interrupted { span }) + fn interrupt_error(span: &Span) -> Result<(), ShellError> { + Err(ShellError::Interrupted { span: *span }) } if self.interrupted() { diff --git a/crates/nu-table/src/types/expanded.rs b/crates/nu-table/src/types/expanded.rs index 81897f251d..82abc42917 100644 --- a/crates/nu-table/src/types/expanded.rs +++ b/crates/nu-table/src/types/expanded.rs @@ -153,7 +153,7 @@ fn expand_list(input: &[Value], cfg: Cfg<'_>) -> TableResult { table.set_indent(cfg.opts.config.table.padding); for (row, item) in input.iter().enumerate() { - cfg.opts.signals.check(cfg.opts.span)?; + cfg.opts.signals.check(&cfg.opts.span)?; check_value(item)?; let inner_cfg = cfg_expand_reset_table(cfg.clone(), available_width); @@ -177,7 +177,7 @@ fn expand_list(input: &[Value], cfg: Cfg<'_>) -> TableResult { let mut index_column_width = 0; for (row, item) in input.iter().enumerate() { - cfg.opts.signals.check(cfg.opts.span)?; + cfg.opts.signals.check(&cfg.opts.span)?; check_value(item)?; let index = row + row_offset; @@ -202,7 +202,7 @@ fn expand_list(input: &[Value], cfg: Cfg<'_>) -> TableResult { available_width -= index_column_width + extra_width + pad_width; for (row, item) in input.iter().enumerate() { - cfg.opts.signals.check(cfg.opts.span)?; + cfg.opts.signals.check(&cfg.opts.span)?; check_value(item)?; let inner_cfg = cfg_expand_reset_table(cfg.clone(), available_width); @@ -233,7 +233,7 @@ fn expand_list(input: &[Value], cfg: Cfg<'_>) -> TableResult { let mut index_column_width = 1; for (row, item) in input.iter().enumerate() { - cfg.opts.signals.check(cfg.opts.span)?; + cfg.opts.signals.check(&cfg.opts.span)?; check_value(item)?; let index = row + row_offset; @@ -292,7 +292,7 @@ fn expand_list(input: &[Value], cfg: Cfg<'_>) -> TableResult { let mut column_width = 0; for (row, item) in input.iter().enumerate() { - cfg.opts.signals.check(cfg.opts.span)?; + cfg.opts.signals.check(&cfg.opts.span)?; check_value(item)?; let inner_cfg = cfg_expand_reset_table(cfg.clone(), available); @@ -410,7 +410,7 @@ fn expanded_table_kv(record: &Record, cfg: Cfg<'_>) -> CellResult { table.set_indent(cfg.opts.config.table.padding); for (i, (key, value)) in record.iter().enumerate() { - cfg.opts.signals.check(cfg.opts.span)?; + cfg.opts.signals.check(&cfg.opts.span)?; let cell = match expand_value(value, value_width, &cfg)? { Some(val) => val, diff --git a/crates/nu-table/src/types/general.rs b/crates/nu-table/src/types/general.rs index 2727e89022..7b732c9a90 100644 --- a/crates/nu-table/src/types/general.rs +++ b/crates/nu-table/src/types/general.rs @@ -50,7 +50,7 @@ fn kv_table(record: Record, opts: TableOpts<'_>) -> StringResult { table.set_indent(opts.config.table.padding); for (i, (key, value)) in record.into_iter().enumerate() { - opts.signals.check(opts.span)?; + opts.signals.check(&opts.span)?; let value = nu_value_to_string_colored(&value, opts.config, &opts.style_computer); @@ -100,7 +100,7 @@ fn create_table_with_header( table.set_indent(opts.config.table.padding); for (row, item) in input.into_iter().enumerate() { - opts.signals.check(opts.span)?; + opts.signals.check(&opts.span)?; check_value(&item)?; for (col, header) in headers.iter().enumerate() { @@ -137,7 +137,7 @@ fn create_table_with_header_and_index( table.set_row(0, head.clone()); for (row, item) in input.into_iter().enumerate() { - opts.signals.check(opts.span)?; + opts.signals.check(&opts.span)?; check_value(&item)?; let text = get_table_row_index(&item, opts.config, row, row_offset); @@ -164,7 +164,7 @@ fn create_table_with_no_header( table.set_indent(opts.config.table.padding); for (row, item) in input.into_iter().enumerate() { - opts.signals.check(opts.span)?; + opts.signals.check(&opts.span)?; check_value(&item)?; let (text, style) = get_string_value(&item, opts); @@ -186,7 +186,7 @@ fn create_table_with_no_header_and_index( table.set_indent(opts.config.table.padding); for (row, item) in input.into_iter().enumerate() { - opts.signals.check(opts.span)?; + opts.signals.check(&opts.span)?; check_value(&item)?; let index = get_table_row_index(&item, opts.config, row, row_offset);