Reduce unwraps

Remove a number of unwraps. In some cases, a `?` just worked as is. I also made it possible to use `?` to go from Result<OutputStream, ShellError> to OutputStream. Finally, started updating PerItemCommand to be able to use the signature deserialization logic, which substantially reduces unwraps.

This is still in-progress work, but tests pass and it should be clear to merge and keep iterating on master.
This commit is contained in:
Yehuda Katz 2019-08-16 20:53:39 -07:00
parent 0dc4b2b686
commit 5bfb96447a
16 changed files with 240 additions and 101 deletions

View File

@ -52,9 +52,9 @@ fn load_plugin(path: &std::path::Path, context: &mut Context) -> Result<(), Shel
let mut reader = BufReader::new(stdout); let mut reader = BufReader::new(stdout);
let request = JsonRpc::new("config", Vec::<Value>::new()); let request = JsonRpc::new("config", Vec::<Value>::new());
let request_raw = serde_json::to_string(&request).unwrap(); let request_raw = serde_json::to_string(&request)?;
stdin.write(format!("{}\n", request_raw).as_bytes())?; stdin.write(format!("{}\n", request_raw).as_bytes())?;
let path = dunce::canonicalize(path).unwrap(); let path = dunce::canonicalize(path)?;
let mut input = String::new(); let mut input = String::new();
match reader.read_line(&mut input) { match reader.read_line(&mut input) {
@ -90,13 +90,13 @@ fn load_plugin(path: &std::path::Path, context: &mut Context) -> Result<(), Shel
} }
fn load_plugins_in_dir(path: &std::path::PathBuf, context: &mut Context) -> Result<(), ShellError> { fn load_plugins_in_dir(path: &std::path::PathBuf, context: &mut Context) -> Result<(), ShellError> {
let re_bin = Regex::new(r"^nu_plugin_[A-Za-z_]+$").unwrap(); let re_bin = Regex::new(r"^nu_plugin_[A-Za-z_]+$")?;
let re_exe = Regex::new(r"^nu_plugin_[A-Za-z_]+\.exe$").unwrap(); let re_exe = Regex::new(r"^nu_plugin_[A-Za-z_]+\.exe$")?;
match std::fs::read_dir(path) { match std::fs::read_dir(path) {
Ok(p) => { Ok(p) => {
for entry in p { for entry in p {
let entry = entry.unwrap(); let entry = entry?;
let filename = entry.file_name(); let filename = entry.file_name();
let f_name = filename.to_string_lossy(); let f_name = filename.to_string_lossy();
if re_bin.is_match(&f_name) || re_exe.is_match(&f_name) { if re_bin.is_match(&f_name) || re_exe.is_match(&f_name) {
@ -270,8 +270,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
&files, &files,
&diag, &diag,
&language_reporting::DefaultConfig, &language_reporting::DefaultConfig,
) )?;
.unwrap();
} }
LineResult::Break => { LineResult::Break => {
@ -288,7 +287,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
} }
ctrlcbreak = false; ctrlcbreak = false;
} }
rl.save_history("history.txt").unwrap(); rl.save_history("history.txt")?;
Ok(()) Ok(())
} }

View File

@ -17,7 +17,7 @@ impl WholeStreamCommand for Autoview {
args: CommandArgs, args: CommandArgs,
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
args.process_raw(registry, autoview)?.run() Ok(args.process_raw(registry, autoview)?.run())
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
@ -40,28 +40,20 @@ pub fn autoview(
} = input[0usize] } = input[0usize]
{ {
let binary = context.expect_command("binaryview"); let binary = context.expect_command("binaryview");
let result = binary.run(raw.with_input(input), &context.commands).await.unwrap(); let result = binary.run(raw.with_input(input), &context.commands);
result.collect::<Vec<_>>().await; result.collect::<Vec<_>>().await;
} else if is_single_text_value(&input) { } else if is_single_text_value(&input) {
let text = context.expect_command("textview"); let text = context.expect_command("textview");
let result = text.run(raw.with_input(input), &context.commands).await.unwrap(); let result = text.run(raw.with_input(input), &context.commands);
result.collect::<Vec<_>>().await; result.collect::<Vec<_>>().await;
} else if equal_shapes(&input) { } else if equal_shapes(&input) {
let table = context.expect_command("table"); let table = context.expect_command("table");
let result = table.run(raw.with_input(input), &context.commands).await.unwrap(); let result = table.run(raw.with_input(input), &context.commands);
result.collect::<Vec<_>>().await; result.collect::<Vec<_>>().await;
} else { } else {
let table = context.expect_command("table"); let table = context.expect_command("table");
let result = table.run(raw.with_input(input), &context.commands).await.unwrap(); let result = table.run(raw.with_input(input), &context.commands);
result.collect::<Vec<_>>().await; result.collect::<Vec<_>>().await;
//println!("TODO!")
// TODO
// let mut host = context.host.lock().unwrap();
// for i in input.iter() {
// let view = GenericView::new(&i);
// handle_unexpected(&mut *host, |host| crate::format::print_view(&view, host));
// host.stdout("");
// }
} }
} }
})) }))

View File

@ -117,16 +117,14 @@ impl InternalCommand {
let objects: InputStream = let objects: InputStream =
trace_stream!(target: "nu::trace_stream::internal", "input" = input.objects); trace_stream!(target: "nu::trace_stream::internal", "input" = input.objects);
let result = context let result = context.run_command(
.run_command( self.command,
self.command, self.name_span.clone(),
self.name_span.clone(), context.source_map.clone(),
context.source_map.clone(), self.args,
self.args, source,
source, objects,
objects, );
)
.await?;
let mut result = result.values; let mut result = result.values;
@ -285,7 +283,7 @@ impl ExternalCommand {
continue; continue;
} }
process = process.arg(&arg.replace("$it", &i.as_string().unwrap())); process = process.arg(&arg.replace("$it", &i.as_string()?));
} }
} }
} else { } else {

View File

@ -77,6 +77,25 @@ pub struct CallInfo {
pub name_span: Span, pub name_span: Span,
} }
impl CallInfo {
pub fn process<'de, T: Deserialize<'de>>(
&self,
shell_manager: &ShellManager,
callback: fn(T, &RunnablePerItemContext) -> Result<VecDeque<ReturnValue>, ShellError>,
) -> Result<RunnablePerItemArgs<T>, ShellError> {
let mut deserializer = ConfigDeserializer::from_call_info(self.clone());
Ok(RunnablePerItemArgs {
args: T::deserialize(&mut deserializer)?,
context: RunnablePerItemContext {
shell_manager: shell_manager.clone(),
name: self.name_span,
},
callback,
})
}
}
#[derive(Getters)] #[derive(Getters)]
#[get = "crate"] #[get = "crate"]
pub struct CommandArgs { pub struct CommandArgs {
@ -147,7 +166,7 @@ impl CommandArgs {
let args = self.evaluate_once(registry)?; let args = self.evaluate_once(registry)?;
let (input, args) = args.split(); let (input, args) = args.split();
let name_span = args.call_info.name_span; let name_span = args.call_info.name_span;
let mut deserializer = ConfigDeserializer::from_call_node(args); let mut deserializer = ConfigDeserializer::from_call_info(args.call_info);
Ok(RunnableArgs { Ok(RunnableArgs {
args: T::deserialize(&mut deserializer)?, args: T::deserialize(&mut deserializer)?,
@ -180,7 +199,7 @@ impl CommandArgs {
let args = self.evaluate_once(registry)?; let args = self.evaluate_once(registry)?;
let (input, args) = args.split(); let (input, args) = args.split();
let name_span = args.call_info.name_span; let name_span = args.call_info.name_span;
let mut deserializer = ConfigDeserializer::from_call_node(args); let mut deserializer = ConfigDeserializer::from_call_info(args.call_info);
Ok(RunnableRawArgs { Ok(RunnableRawArgs {
args: T::deserialize(&mut deserializer)?, args: T::deserialize(&mut deserializer)?,
@ -198,6 +217,17 @@ impl CommandArgs {
} }
} }
pub struct RunnablePerItemContext {
pub shell_manager: ShellManager,
pub name: Span,
}
impl RunnablePerItemContext {
pub fn cwd(&self) -> PathBuf {
PathBuf::from(self.shell_manager.path())
}
}
pub struct RunnableContext { pub struct RunnableContext {
pub input: InputStream, pub input: InputStream,
pub shell_manager: ShellManager, pub shell_manager: ShellManager,
@ -219,6 +249,18 @@ impl RunnableContext {
} }
} }
pub struct RunnablePerItemArgs<T> {
args: T,
context: RunnablePerItemContext,
callback: fn(T, &RunnablePerItemContext) -> Result<VecDeque<ReturnValue>, ShellError>,
}
impl<T> RunnablePerItemArgs<T> {
pub fn run(self) -> Result<VecDeque<ReturnValue>, ShellError> {
(self.callback)(self.args, &self.context)
}
}
pub struct RunnableArgs<T> { pub struct RunnableArgs<T> {
args: T, args: T,
context: RunnableContext, context: RunnableContext,
@ -239,8 +281,11 @@ pub struct RunnableRawArgs<T> {
} }
impl<T> RunnableRawArgs<T> { impl<T> RunnableRawArgs<T> {
pub fn run(self) -> Result<OutputStream, ShellError> { pub fn run(self) -> OutputStream {
(self.callback)(self.args, self.context, self.raw_args) match (self.callback)(self.args, self.context, self.raw_args) {
Ok(stream) => stream,
Err(err) => OutputStream::one(Err(err)),
}
} }
} }
@ -475,13 +520,12 @@ impl Command {
} }
} }
pub async fn run( pub fn run(&self, args: CommandArgs, registry: &registry::CommandRegistry) -> OutputStream {
&self,
args: CommandArgs,
registry: &registry::CommandRegistry,
) -> Result<OutputStream, ShellError> {
match self { match self {
Command::WholeStream(command) => command.run(args, registry), Command::WholeStream(command) => match command.run(args, registry) {
Ok(stream) => stream,
Err(err) => OutputStream::one(Err(err)),
},
Command::PerItem(command) => self.run_helper(command.clone(), args, registry.clone()), Command::PerItem(command) => self.run_helper(command.clone(), args, registry.clone()),
} }
} }
@ -491,7 +535,7 @@ impl Command {
command: Arc<dyn PerItemCommand>, command: Arc<dyn PerItemCommand>,
args: CommandArgs, args: CommandArgs,
registry: CommandRegistry, registry: CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> OutputStream {
let raw_args = RawCommandArgs { let raw_args = RawCommandArgs {
host: args.host, host: args.host,
shell_manager: args.shell_manager, shell_manager: args.shell_manager,
@ -515,7 +559,7 @@ impl Command {
}) })
.flatten(); .flatten();
Ok(out.to_output_stream()) out.to_output_stream()
} else { } else {
let nothing = Value::nothing().tagged(Tag::unknown()); let nothing = Value::nothing().tagged(Tag::unknown());
let call_info = raw_args let call_info = raw_args
@ -524,11 +568,15 @@ impl Command {
.evaluate(&registry, &Scope::it_value(nothing.clone())) .evaluate(&registry, &Scope::it_value(nothing.clone()))
.unwrap(); .unwrap();
// We don't have an $it or block, so just execute what we have // We don't have an $it or block, so just execute what we have
let out = match command.run(&call_info, &registry, &raw_args.shell_manager, nothing) {
Ok(o) => o, command
Err(e) => VecDeque::from(vec![ReturnValue::Err(e)]), .run(&call_info, &registry, &raw_args.shell_manager, nothing)?
}; .into()
Ok(out.to_output_stream()) // let out = match command.run(&call_info, &registry, &raw_args.shell_manager, nothing) {
// Ok(o) => o,
// Err(e) => VecDeque::from(vec![ReturnValue::Err(e)]),
// };
// Ok(out.to_output_stream())
} }
} }
} }

View File

@ -1,3 +1,4 @@
use crate::commands::command::RunnablePerItemContext;
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::parser::hir::SyntaxType; use crate::parser::hir::SyntaxType;
use crate::parser::registry::{CommandRegistry, Signature}; use crate::parser::registry::{CommandRegistry, Signature};
@ -7,15 +8,22 @@ use std::path::PathBuf;
pub struct Cpy; pub struct Cpy;
#[derive(Deserialize)]
pub struct CopyArgs {
source: Tagged<PathBuf>,
destination: Tagged<PathBuf>,
recursive: Tagged<bool>,
}
impl PerItemCommand for Cpy { impl PerItemCommand for Cpy {
fn run( fn run(
&self, &self,
call_info: &CallInfo, call_info: &CallInfo,
_registry: &CommandRegistry, _registry: &CommandRegistry,
shell_manager: &ShellManager, shell_manager: &ShellManager,
_input: Tagged<Value>, input: Tagged<Value>,
) -> Result<VecDeque<ReturnValue>, ShellError> { ) -> Result<VecDeque<ReturnValue>, ShellError> {
cp(call_info, shell_manager) call_info.process(shell_manager, cp)?.run()
} }
fn name(&self) -> &str { fn name(&self) -> &str {
@ -24,42 +32,24 @@ impl PerItemCommand for Cpy {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("cp") Signature::build("cp")
.required("source", SyntaxType::Path)
.required("destination", SyntaxType::Path)
.named("file", SyntaxType::Any) .named("file", SyntaxType::Any)
.switch("recursive") .switch("recursive")
} }
} }
pub fn cp( pub fn cp(
call_info: &CallInfo, args: CopyArgs,
shell_manager: &ShellManager, context: &RunnablePerItemContext,
) -> Result<VecDeque<ReturnValue>, ShellError> { ) -> Result<VecDeque<ReturnValue>, ShellError> {
let mut source = PathBuf::from(shell_manager.path()); let mut source = PathBuf::from(context.shell_manager.path());
let mut destination = PathBuf::from(shell_manager.path()); let mut destination = PathBuf::from(context.shell_manager.path());
let name_span = call_info.name_span; let name_span = context.name;
match call_info source.push(&args.source.item);
.args
.nth(0)
.ok_or_else(|| ShellError::string(&format!("No file or directory specified")))?
.as_string()?
.as_str()
{
file => {
source.push(file);
}
}
match call_info destination.push(&args.destination.item);
.args
.nth(1)
.ok_or_else(|| ShellError::string(&format!("No file or directory specified")))?
.as_string()?
.as_str()
{
file => {
destination.push(file);
}
}
let sources = glob::glob(&source.to_string_lossy()); let sources = glob::glob(&source.to_string_lossy());
@ -67,7 +57,7 @@ pub fn cp(
return Err(ShellError::labeled_error( return Err(ShellError::labeled_error(
"Invalid pattern.", "Invalid pattern.",
"Invalid pattern.", "Invalid pattern.",
call_info.args.nth(0).unwrap().span(), args.source.tag,
)); ));
} }
@ -75,11 +65,11 @@ pub fn cp(
if sources.len() == 1 { if sources.len() == 1 {
if let Ok(entry) = &sources[0] { if let Ok(entry) = &sources[0] {
if entry.is_dir() && !call_info.args.has("recursive") { if entry.is_dir() && !args.recursive.item {
return Err(ShellError::labeled_error( return Err(ShellError::labeled_error(
"is a directory (not copied). Try using \"--recursive\".", "is a directory (not copied). Try using \"--recursive\".",
"is a directory (not copied). Try using \"--recursive\".", "is a directory (not copied). Try using \"--recursive\".",
call_info.args.nth(0).unwrap().span(), args.source.tag,
)); ));
} }
@ -248,7 +238,7 @@ pub fn cp(
return Err(ShellError::labeled_error( return Err(ShellError::labeled_error(
"Copy aborted (directories found). Recursive copying in patterns not supported yet (try copying the directory directly)", "Copy aborted (directories found). Recursive copying in patterns not supported yet (try copying the directory directly)",
"Copy aborted (directories found). Recursive copying in patterns not supported yet (try copying the directory directly)", "Copy aborted (directories found). Recursive copying in patterns not supported yet (try copying the directory directly)",
call_info.args.nth(0).unwrap().span(), args.source.tag,
)); ));
} }
@ -263,7 +253,7 @@ pub fn cp(
return Err(ShellError::labeled_error( return Err(ShellError::labeled_error(
e.to_string(), e.to_string(),
e.to_string(), e.to_string(),
call_info.args.nth(0).unwrap().span(), args.source.tag,
)); ));
} }
Ok(o) => o, Ok(o) => o,
@ -281,7 +271,7 @@ pub fn cp(
"Copy aborted. (Does {:?} exist?)", "Copy aborted. (Does {:?} exist?)",
&destination.file_name().unwrap() &destination.file_name().unwrap()
), ),
call_info.args.nth(1).unwrap().span(), args.destination.span(),
)); ));
} }
} }

View File

@ -115,7 +115,7 @@ impl Context {
self.registry.get_command(name).unwrap() self.registry.get_command(name).unwrap()
} }
crate async fn run_command<'a>( crate fn run_command<'a>(
&mut self, &mut self,
command: Arc<Command>, command: Arc<Command>,
name_span: Span, name_span: Span,
@ -123,9 +123,9 @@ impl Context {
args: hir::Call, args: hir::Call,
source: Text, source: Text,
input: InputStream, input: InputStream,
) -> Result<OutputStream, ShellError> { ) -> OutputStream {
let command_args = self.command_args(args, input, source, source_map, name_span); let command_args = self.command_args(args, input, source, source_map, name_span);
command.run(command_args, self.registry()).await command.run(command_args, self.registry())
} }
fn call_info( fn call_info(

View File

@ -106,6 +106,14 @@ impl ShellError {
ProximateShellError::MissingProperty { subpath, expr }.start() ProximateShellError::MissingProperty { subpath, expr }.start()
} }
crate fn missing_value(span: Option<Span>, reason: impl Into<String>) -> ShellError {
ProximateShellError::MissingValue {
span,
reason: reason.into(),
}
.start()
}
crate fn argument_error( crate fn argument_error(
command: impl Into<String>, command: impl Into<String>,
kind: ArgumentError, kind: ArgumentError,
@ -148,6 +156,18 @@ impl ShellError {
Diagnostic::new(Severity::Error, "Invalid command") Diagnostic::new(Severity::Error, "Invalid command")
.with_label(Label::new_primary(command.span)) .with_label(Label::new_primary(command.span))
} }
ProximateShellError::MissingValue { span, reason } => {
let mut d = Diagnostic::new(
Severity::Bug,
format!("Internal Error (missing value) :: {}", reason),
);
if let Some(span) = span {
d = d.with_label(Label::new_primary(span));
}
d
}
ProximateShellError::ArgumentError { ProximateShellError::ArgumentError {
command, command,
error, error,
@ -245,11 +265,11 @@ impl ShellError {
pub fn labeled_error( pub fn labeled_error(
msg: impl Into<String>, msg: impl Into<String>,
label: impl Into<String>, label: impl Into<String>,
span: Span, span: impl Into<Span>,
) -> ShellError { ) -> ShellError {
ShellError::diagnostic( ShellError::diagnostic(
Diagnostic::new(Severity::Error, msg.into()) Diagnostic::new(Severity::Error, msg.into())
.with_label(Label::new_primary(span).with_message(label.into())), .with_label(Label::new_primary(span.into()).with_message(label.into())),
) )
} }
@ -299,6 +319,10 @@ pub enum ProximateShellError {
subpath: Description, subpath: Description,
expr: Description, expr: Description,
}, },
MissingValue {
span: Option<Span>,
reason: String,
},
ArgumentError { ArgumentError {
command: String, command: String,
error: ArgumentError, error: ArgumentError,
@ -372,6 +396,7 @@ impl std::fmt::Display for ShellError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match &self.error { match &self.error {
ProximateShellError::String(s) => write!(f, "{}", &s.title), ProximateShellError::String(s) => write!(f, "{}", &s.title),
ProximateShellError::MissingValue { .. } => write!(f, "MissingValue"),
ProximateShellError::InvalidCommand { .. } => write!(f, "InvalidCommand"), ProximateShellError::InvalidCommand { .. } => write!(f, "InvalidCommand"),
ProximateShellError::TypeError { .. } => write!(f, "TypeError"), ProximateShellError::TypeError { .. } => write!(f, "TypeError"),
ProximateShellError::SyntaxError { .. } => write!(f, "SyntaxError"), ProximateShellError::SyntaxError { .. } => write!(f, "SyntaxError"),
@ -414,3 +439,36 @@ impl std::convert::From<toml::ser::Error> for ShellError {
.start() .start()
} }
} }
impl std::convert::From<serde_json::Error> for ShellError {
fn from(input: serde_json::Error) -> ShellError {
ProximateShellError::String(StringError {
title: format!("{:?}", input),
error: Value::nothing(),
})
.start()
}
}
impl std::convert::From<regex::Error> for ShellError {
fn from(input: regex::Error) -> ShellError {
ProximateShellError::String(StringError {
title: format!("{:?}", input),
error: Value::nothing(),
})
.start()
}
}
pub trait ShellErrorUtils<T> {
fn unwrap_error(self, desc: impl Into<String>) -> Result<T, ShellError>;
}
impl<T> ShellErrorUtils<Tagged<T>> for Option<Tagged<T>> {
fn unwrap_error(self, desc: impl Into<String>) -> Result<Tagged<T>, ShellError> {
match self {
Some(value) => Ok(value),
None => Err(ShellError::missing_value(None, desc.into())),
}
}
}

View File

@ -197,6 +197,18 @@ impl From<&Span> for Tag {
} }
} }
impl From<Tag> for Span {
fn from(tag: Tag) -> Self {
tag.span
}
}
impl From<&Tag> for Span {
fn from(tag: &Tag) -> Self {
tag.span
}
}
impl Tag { impl Tag {
pub fn unknown_origin(span: Span) -> Tag { pub fn unknown_origin(span: Span) -> Tag {
Tag { origin: None, span } Tag { origin: None, span }

View File

@ -1,4 +1,5 @@
use crate::commands::command::EvaluatedCommandArgs; use crate::commands::command::EvaluatedCommandArgs;
use crate::parser::registry::EvaluatedArgs;
use crate::prelude::*; use crate::prelude::*;
use log::trace; use log::trace;
use serde::{de, forward_to_deserialize_any}; use serde::{de, forward_to_deserialize_any};
@ -11,16 +12,16 @@ pub struct DeserializerItem<'de> {
} }
pub struct ConfigDeserializer<'de> { pub struct ConfigDeserializer<'de> {
args: EvaluatedCommandArgs, call: CallInfo,
stack: Vec<DeserializerItem<'de>>, stack: Vec<DeserializerItem<'de>>,
saw_root: bool, saw_root: bool,
position: usize, position: usize,
} }
impl ConfigDeserializer<'de> { impl ConfigDeserializer<'de> {
pub fn from_call_node(args: EvaluatedCommandArgs) -> ConfigDeserializer<'de> { pub fn from_call_info(call: CallInfo) -> ConfigDeserializer<'de> {
ConfigDeserializer { ConfigDeserializer {
args, call,
stack: vec![], stack: vec![],
saw_root: false, saw_root: false,
position: 0, position: 0,
@ -29,16 +30,16 @@ impl ConfigDeserializer<'de> {
pub fn push(&mut self, name: &'static str) -> Result<(), ShellError> { pub fn push(&mut self, name: &'static str) -> Result<(), ShellError> {
let value: Option<Tagged<Value>> = if name == "rest" { let value: Option<Tagged<Value>> = if name == "rest" {
let positional = self.args.slice_from(self.position); let positional = self.call.args.slice_from(self.position);
self.position += positional.len(); self.position += positional.len();
Some(Value::List(positional).tagged_unknown()) // TODO: correct span Some(Value::List(positional).tagged_unknown()) // TODO: correct span
} else { } else {
if self.args.has(name) { if self.call.args.has(name) {
self.args.get(name).map(|x| x.clone()) self.call.args.get(name).map(|x| x.clone())
} else { } else {
let position = self.position; let position = self.position;
self.position += 1; self.position += 1;
self.args.nth(position).map(|x| x.clone()) self.call.args.nth(position).map(|x| x.clone())
} }
}; };
@ -48,7 +49,7 @@ impl ConfigDeserializer<'de> {
key: name.to_string(), key: name.to_string(),
struct_field: name, struct_field: name,
val: value.unwrap_or_else(|| { val: value.unwrap_or_else(|| {
Value::nothing().tagged(Tag::unknown_origin(self.args.call_info.name_span)) Value::nothing().tagged(Tag::unknown_origin(self.call.name_span))
}), }),
}); });

View File

@ -142,6 +142,17 @@ pub struct EvaluatedArgs {
pub named: Option<IndexMap<String, Tagged<Value>>>, pub named: Option<IndexMap<String, Tagged<Value>>>,
} }
impl EvaluatedArgs {
pub fn slice_from(&self, from: usize) -> Vec<Tagged<Value>> {
let positional = &self.positional;
match positional {
None => vec![],
Some(list) => list[from..].to_vec(),
}
}
}
#[derive(new)] #[derive(new)]
pub struct DebugEvaluatedPositional<'a> { pub struct DebugEvaluatedPositional<'a> {
positional: &'a Option<Vec<Tagged<Value>>>, positional: &'a Option<Vec<Tagged<Value>>>,

View File

@ -41,7 +41,7 @@ crate use crate::context::CommandRegistry;
crate use crate::context::{Context, SpanSource}; crate use crate::context::{Context, SpanSource};
crate use crate::env::host::handle_unexpected; crate use crate::env::host::handle_unexpected;
crate use crate::env::Host; crate use crate::env::Host;
crate use crate::errors::ShellError; crate use crate::errors::{ShellError, ShellErrorUtils};
crate use crate::object::base as value; crate use crate::object::base as value;
crate use crate::object::meta::{Tag, Tagged, TaggedItem}; crate use crate::object::meta::{Tag, Tagged, TaggedItem};
crate use crate::object::types::ExtractType; crate use crate::object::types::ExtractType;

View File

@ -7,12 +7,19 @@ use crate::shell::shell::Shell;
use rustyline::completion::FilenameCompleter; use rustyline::completion::FilenameCompleter;
use rustyline::hint::{Hinter, HistoryHinter}; use rustyline::hint::{Hinter, HistoryHinter};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
pub struct FilesystemShell { pub struct FilesystemShell {
crate path: String, crate path: String,
completer: NuCompleter, completer: NuCompleter,
hinter: HistoryHinter, hinter: HistoryHinter,
} }
impl std::fmt::Debug for FilesystemShell {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "FilesystemShell @ {}", self.path)
}
}
impl Clone for FilesystemShell { impl Clone for FilesystemShell {
fn clone(&self) -> Self { fn clone(&self) -> Self {
FilesystemShell { FilesystemShell {

View File

@ -3,7 +3,7 @@ use crate::context::SourceMap;
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::stream::OutputStream; use crate::stream::OutputStream;
pub trait Shell { pub trait Shell: std::fmt::Debug {
fn name(&self, source_map: &SourceMap) -> String; fn name(&self, source_map: &SourceMap) -> String;
fn ls(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError>; fn ls(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError>;
fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError>; fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError>;

View File

@ -7,7 +7,7 @@ use crate::stream::OutputStream;
use std::error::Error; use std::error::Error;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
#[derive(Clone)] #[derive(Clone, Debug)]
pub struct ShellManager { pub struct ShellManager {
crate shells: Arc<Mutex<Vec<Box<dyn Shell + Send>>>>, crate shells: Arc<Mutex<Vec<Box<dyn Shell + Send>>>>,
} }

View File

@ -5,7 +5,7 @@ use crate::shell::shell::Shell;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::path::PathBuf; use std::path::PathBuf;
#[derive(Clone)] #[derive(Clone, Debug)]
pub struct ValueShell { pub struct ValueShell {
crate path: String, crate path: String,
crate value: Tagged<Value>, crate value: Tagged<Value>,

View File

@ -75,6 +75,29 @@ impl OutputStream {
values: input.map(ReturnSuccess::value).boxed(), values: input.map(ReturnSuccess::value).boxed(),
} }
} }
pub fn drain_vec(&mut self) -> impl Future<Output = Vec<ReturnValue>> {
let mut values: BoxStream<'static, ReturnValue> = VecDeque::new().boxed();
std::mem::swap(&mut values, &mut self.values);
values.collect()
}
}
impl std::ops::Try for OutputStream {
type Ok = OutputStream;
type Error = ShellError;
fn into_result(self) -> Result<Self::Ok, Self::Error> {
Ok(self)
}
fn from_error(v: Self::Error) -> Self {
OutputStream::one(Err(v))
}
fn from_ok(v: Self::Ok) -> Self {
v
}
} }
impl Stream for OutputStream { impl Stream for OutputStream {