mirror of
https://github.com/nushell/nushell.git
synced 2025-04-17 17:58:18 +02:00
Add ErrSpan
extension trait for Result
(#12626)
# Description This adds an extension trait to `Result` that wraps errors in `Spanned`, saving the effort of calling `.map_err(|err| err.into_spanned(span))` every time. This will hopefully make it even more likely that someone will want to use a spanned `io::Error` and make it easier to remove the impl for `From<io::Error> for ShellError` because that doesn't have span information.
This commit is contained in:
parent
b0acc1d890
commit
5c7f7883c8
@ -117,7 +117,7 @@ impl Command for Do {
|
|||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.map_err(|e| e.into_spanned(call.head))
|
.err_span(call.head)
|
||||||
})
|
})
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
|
||||||
|
@ -106,9 +106,7 @@ apparent the next time `nu` is next launched with that plugin cache file.
|
|||||||
|
|
||||||
let shell_expanded = shell
|
let shell_expanded = shell
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|s| {
|
.map(|s| nu_path::canonicalize_with(&s.item, &cwd).err_span(s.span))
|
||||||
nu_path::canonicalize_with(&s.item, &cwd).map_err(|err| err.into_spanned(s.span))
|
|
||||||
})
|
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
|
||||||
// Parse the plugin filename so it can be used to spawn the plugin
|
// Parse the plugin filename so it can be used to spawn the plugin
|
||||||
|
@ -30,7 +30,7 @@ pub(crate) fn modify_plugin_file(
|
|||||||
// Try to read the plugin file if it exists
|
// Try to read the plugin file if it exists
|
||||||
let mut contents = if fs::metadata(&plugin_cache_file_path).is_ok_and(|m| m.len() > 0) {
|
let mut contents = if fs::metadata(&plugin_cache_file_path).is_ok_and(|m| m.len() > 0) {
|
||||||
PluginCacheFile::read_from(
|
PluginCacheFile::read_from(
|
||||||
File::open(&plugin_cache_file_path).map_err(|err| err.into_spanned(span))?,
|
File::open(&plugin_cache_file_path).err_span(span)?,
|
||||||
Some(span),
|
Some(span),
|
||||||
)?
|
)?
|
||||||
} else {
|
} else {
|
||||||
@ -42,7 +42,7 @@ pub(crate) fn modify_plugin_file(
|
|||||||
|
|
||||||
// Save the modified file on success
|
// Save the modified file on success
|
||||||
contents.write_to(
|
contents.write_to(
|
||||||
File::create(&plugin_cache_file_path).map_err(|err| err.into_spanned(span))?,
|
File::create(&plugin_cache_file_path).err_span(span)?,
|
||||||
Some(span),
|
Some(span),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ impl Command for Save {
|
|||||||
.spawn(move || stderr.drain()),
|
.spawn(move || stderr.drain()),
|
||||||
})
|
})
|
||||||
.transpose()
|
.transpose()
|
||||||
.map_err(|e| e.into_spanned(span))?;
|
.err_span(span)?;
|
||||||
|
|
||||||
let res = stream_to_file(stdout, file, span, progress);
|
let res = stream_to_file(stdout, file, span, progress);
|
||||||
if let Some(h) = handler {
|
if let Some(h) = handler {
|
||||||
|
@ -125,8 +125,7 @@ use it in your pipeline."#
|
|||||||
if use_stderr {
|
if use_stderr {
|
||||||
let stderr = stderr
|
let stderr = stderr
|
||||||
.map(|stderr| {
|
.map(|stderr| {
|
||||||
let iter = tee(stderr.stream, with_stream)
|
let iter = tee(stderr.stream, with_stream).err_span(call.head)?;
|
||||||
.map_err(|e| e.into_spanned(call.head))?;
|
|
||||||
Ok::<_, ShellError>(RawStream::new(
|
Ok::<_, ShellError>(RawStream::new(
|
||||||
Box::new(iter.map(flatten_result)),
|
Box::new(iter.map(flatten_result)),
|
||||||
stderr.ctrlc,
|
stderr.ctrlc,
|
||||||
@ -146,8 +145,7 @@ use it in your pipeline."#
|
|||||||
} else {
|
} else {
|
||||||
let stdout = stdout
|
let stdout = stdout
|
||||||
.map(|stdout| {
|
.map(|stdout| {
|
||||||
let iter = tee(stdout.stream, with_stream)
|
let iter = tee(stdout.stream, with_stream).err_span(call.head)?;
|
||||||
.map_err(|e| e.into_spanned(call.head))?;
|
|
||||||
Ok::<_, ShellError>(RawStream::new(
|
Ok::<_, ShellError>(RawStream::new(
|
||||||
Box::new(iter.map(flatten_result)),
|
Box::new(iter.map(flatten_result)),
|
||||||
stdout.ctrlc,
|
stdout.ctrlc,
|
||||||
@ -189,7 +187,7 @@ use it in your pipeline."#
|
|||||||
// Make sure to drain any iterator produced to avoid unexpected behavior
|
// Make sure to drain any iterator produced to avoid unexpected behavior
|
||||||
result.and_then(|data| data.drain())
|
result.and_then(|data| data.drain())
|
||||||
})
|
})
|
||||||
.map_err(|e| e.into_spanned(call.head))?
|
.err_span(call.head)?
|
||||||
.map(move |result| result.unwrap_or_else(|err| Value::error(err, closure_span)))
|
.map(move |result| result.unwrap_or_else(|err| Value::error(err, closure_span)))
|
||||||
.into_pipeline_data_with_metadata(metadata, engine_state.ctrlc.clone());
|
.into_pipeline_data_with_metadata(metadata, engine_state.ctrlc.clone());
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ impl Command for Complete {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map(|handle| (handle, stderr_span))
|
.map(|handle| (handle, stderr_span))
|
||||||
.map_err(|err| err.into_spanned(call.head))
|
.err_span(call.head)
|
||||||
})
|
})
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
|
||||||
|
@ -495,7 +495,7 @@ impl ExternalCommand {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.map_err(|e| e.into_spanned(head))?;
|
.err_span(head)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -580,7 +580,7 @@ impl ExternalCommand {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map_err(|e| e.into_spanned(head))?;
|
.err_span(head)?;
|
||||||
|
|
||||||
let exit_code_receiver = ValueReceiver::new(exit_code_rx);
|
let exit_code_receiver = ValueReceiver::new(exit_code_rx);
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ pub use crate::CallExt;
|
|||||||
pub use nu_protocol::{
|
pub use nu_protocol::{
|
||||||
ast::{Call, CellPath},
|
ast::{Call, CellPath},
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
record, Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, IntoSpanned,
|
record, Category, ErrSpan, Example, IntoInterruptiblePipelineData, IntoPipelineData,
|
||||||
PipelineData, Record, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
|
IntoSpanned, PipelineData, Record, ShellError, Signature, Span, Spanned, SyntaxShape, Type,
|
||||||
|
Value,
|
||||||
};
|
};
|
||||||
|
@ -3550,8 +3550,7 @@ pub fn parse_where(working_set: &mut StateWorkingSet, lite_command: &LiteCommand
|
|||||||
pub fn parse_register(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) -> Pipeline {
|
pub fn parse_register(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) -> Pipeline {
|
||||||
use nu_plugin::{get_signature, PersistentPlugin, PluginDeclaration};
|
use nu_plugin::{get_signature, PersistentPlugin, PluginDeclaration};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::Stack, IntoSpanned, PluginCacheItem, PluginIdentity, PluginSignature,
|
engine::Stack, ErrSpan, PluginCacheItem, PluginIdentity, PluginSignature, RegisteredPlugin,
|
||||||
RegisteredPlugin,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let spans = &lite_command.parts;
|
let spans = &lite_command.parts;
|
||||||
@ -3694,8 +3693,7 @@ pub fn parse_register(working_set: &mut StateWorkingSet, lite_command: &LiteComm
|
|||||||
let path = path.path_buf();
|
let path = path.path_buf();
|
||||||
|
|
||||||
// Create the plugin identity. This validates that the plugin name starts with `nu_plugin_`
|
// Create the plugin identity. This validates that the plugin name starts with `nu_plugin_`
|
||||||
let identity =
|
let identity = PluginIdentity::new(path, shell).err_span(path_span)?;
|
||||||
PluginIdentity::new(path, shell).map_err(|err| err.into_spanned(path_span))?;
|
|
||||||
|
|
||||||
// Find garbage collection config
|
// Find garbage collection config
|
||||||
let gc_config = working_set
|
let gc_config = working_set
|
||||||
|
@ -147,3 +147,34 @@ pub fn span(spans: &[Span]) -> Span {
|
|||||||
Span::new(spans[0].start, end)
|
Span::new(spans[0].start, end)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An extension trait for `Result`, which adds a span to the error type.
|
||||||
|
pub trait ErrSpan {
|
||||||
|
type Result;
|
||||||
|
|
||||||
|
/// Add the given span to the error type `E`, turning it into a `Spanned<E>`.
|
||||||
|
///
|
||||||
|
/// Some auto-conversion methods to `ShellError` from other error types are available on spanned
|
||||||
|
/// errors, to give users better information about where an error came from. For example, it is
|
||||||
|
/// preferred when working with `std::io::Error`:
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use nu_protocol::{ErrSpan, ShellError, Span};
|
||||||
|
/// use std::io::Read;
|
||||||
|
///
|
||||||
|
/// fn read_from(mut reader: impl Read, span: Span) -> Result<Vec<u8>, ShellError> {
|
||||||
|
/// let mut vec = vec![];
|
||||||
|
/// reader.read_to_end(&mut vec).err_span(span)?;
|
||||||
|
/// Ok(vec)
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
fn err_span(self, span: Span) -> Self::Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E> ErrSpan for Result<T, E> {
|
||||||
|
type Result = Result<T, Spanned<E>>;
|
||||||
|
|
||||||
|
fn err_span(self, span: Span) -> Self::Result {
|
||||||
|
self.map_err(|err| err.into_spanned(span))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user