Finish up enter and save

This commit is contained in:
Jonathan Turner 2019-08-31 12:59:21 +12:00
parent fa2c6ec227
commit 761cc3db14
3 changed files with 197 additions and 151 deletions

View File

@ -146,41 +146,9 @@ impl InternalCommand {
.insert_at_current(Box::new(ValueShell::new(value))); .insert_at_current(Box::new(ValueShell::new(value)));
} }
CommandAction::EnterShell(location) => { CommandAction::EnterShell(location) => {
let path = std::path::Path::new(&location);
if path.is_dir() {
// If it's a directory, add a new filesystem shell
context.shell_manager.insert_at_current(Box::new( context.shell_manager.insert_at_current(Box::new(
FilesystemShell::with_location( FilesystemShell::with_location(location, context.registry().clone())?,
location,
context.registry().clone(),
)?,
)); ));
} else {
// If it's a file, attempt to open the file as a value and enter it
let cwd = context.shell_manager.path();
let full_path = std::path::PathBuf::from(cwd);
let (_file_extension, contents, contents_tag, span_source) =
crate::commands::open::fetch(
&full_path,
&location,
Span::unknown(),
)
.await?;
if let Some(uuid) = contents_tag.origin {
// If we have loaded something, track its source
context.add_span_source(uuid, span_source);
}
context
.shell_manager
.insert_at_current(Box::new(ValueShell::new(
contents.tagged(contents_tag),
)))
}
} }
CommandAction::PreviousShell => { CommandAction::PreviousShell => {
context.shell_manager.prev(); context.shell_manager.prev();

View File

@ -1,8 +1,10 @@
use crate::commands::command::CommandAction; use crate::commands::command::CommandAction;
use crate::commands::PerItemCommand; use crate::commands::PerItemCommand;
use crate::commands::UnevaluatedCallInfo;
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::parser::registry; use crate::parser::registry;
use crate::prelude::*; use crate::prelude::*;
use std::path::PathBuf;
pub struct Enter; pub struct Enter;
@ -18,18 +20,109 @@ impl PerItemCommand for Enter {
fn run( fn run(
&self, &self,
call_info: &CallInfo, call_info: &CallInfo,
_registry: &registry::CommandRegistry, registry: &registry::CommandRegistry,
_raw_args: &RawCommandArgs, raw_args: &RawCommandArgs,
_input: Tagged<Value>, _input: Tagged<Value>,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let raw_args = raw_args.clone();
match call_info.args.expect_nth(0)? { match call_info.args.expect_nth(0)? {
Tagged { Tagged {
item: Value::Primitive(Primitive::String(location)), item: Value::Primitive(Primitive::String(location)),
.. ..
} => Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterShell( } => {
location.to_string(), let location = location.to_string();
let location_clone = location.to_string();
if PathBuf::from(location).is_dir() {
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterShell(
location_clone,
)))] )))]
.into()), .into())
} else {
let stream = async_stream_block! {
// If it's a file, attempt to open the file as a value and enter it
let cwd = raw_args.shell_manager.path();
let full_path = std::path::PathBuf::from(cwd);
let (file_extension, contents, contents_tag, span_source) =
crate::commands::open::fetch(
&full_path,
&location_clone,
Span::unknown(),
)
.await.unwrap();
if let Some(uuid) = contents_tag.origin {
// If we have loaded something, track its source
yield ReturnSuccess::action(CommandAction::AddSpanSource(
uuid,
span_source,
));
}
match contents {
Value::Primitive(Primitive::String(_)) => {
let tagged_contents = contents.tagged(contents_tag);
if let Some(extension) = file_extension {
let command_name = format!("from-{}", extension);
if let Some(converter) =
registry.get_command(&command_name)
{
let new_args = RawCommandArgs {
host: raw_args.host,
shell_manager: raw_args.shell_manager,
call_info: UnevaluatedCallInfo {
args: crate::parser::hir::Call {
head: raw_args.call_info.args.head,
positional: None,
named: None,
},
source: raw_args.call_info.source,
source_map: raw_args.call_info.source_map,
name_span: raw_args.call_info.name_span,
},
};
let mut result = converter.run(
new_args.with_input(vec![tagged_contents]),
&registry,
);
let result_vec: Vec<Result<ReturnSuccess, ShellError>> =
result.drain_vec().await;
for res in result_vec {
match res {
Ok(ReturnSuccess::Value(Tagged {
item,
..
})) => {
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(
Tagged {
item: item,
tag: contents_tag,
})));
}
x => yield x,
}
}
} else {
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(tagged_contents)));
}
} else {
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(tagged_contents)));
}
}
_ => {
let tagged_contents = contents.tagged(contents_tag);
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(tagged_contents)));
}
}
};
Ok(stream.to_output_stream())
}
}
x => Ok( x => Ok(
vec![Ok(ReturnSuccess::Action(CommandAction::EnterValueShell( vec![Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(
x.clone(), x.clone(),

View File

@ -1,8 +1,4 @@
use crate::commands::to_csv::{to_string as to_csv_to_string, value_to_csv_value}; use crate::commands::UnevaluatedCallInfo;
use crate::commands::to_tsv::{to_string as to_tsv_to_string, value_to_tsv_value};
use crate::commands::to_json::value_to_json_value;
use crate::commands::to_toml::value_to_toml_value;
use crate::commands::to_yaml::value_to_yaml_value;
use crate::commands::WholeStreamCommand; use crate::commands::WholeStreamCommand;
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::object::Value; use crate::object::Value;
@ -33,7 +29,7 @@ impl WholeStreamCommand for Save {
args: CommandArgs, args: CommandArgs,
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
args.process(registry, save)?.run() Ok(args.process_raw(registry, save)?.run())
} }
} }
@ -47,16 +43,19 @@ fn save(
name, name,
shell_manager, shell_manager,
source_map, source_map,
host,
commands: registry,
.. ..
}: RunnableContext, }: RunnableContext,
raw_args: RawCommandArgs,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let mut full_path = PathBuf::from(shell_manager.path()); let mut full_path = PathBuf::from(shell_manager.path());
let name_span = name; let name_span = name;
if path.is_none() {
let source_map = source_map.clone(); let source_map = source_map.clone();
let stream = async_stream_block! { let stream = async_stream_block! {
let input: Vec<Tagged<Value>> = input.values.collect().await; let input: Vec<Tagged<Value>> = input.values.collect().await;
if path.is_none() {
// If there is no filename, check the metadata for the origin filename // If there is no filename, check the metadata for the origin filename
if input.len() > 0 { if input.len() > 0 {
let origin = input[0].origin(); let origin = input[0].origin();
@ -88,34 +87,84 @@ fn save(
name_span, name_span,
)); ));
} }
let content = if !save_raw {
to_string_for(full_path.extension(), &input).await
} else {
string_from(&input)
};
match content {
Ok(save_data) => match std::fs::write(full_path, save_data) {
Ok(o) => o,
Err(e) => yield Err(ShellError::string(e.to_string())),
},
Err(e) => yield Err(ShellError::string(e.to_string())),
}
};
Ok(OutputStream::new(stream))
} else { } else {
if let Some(file) = path { if let Some(file) = path {
full_path.push(file.item()); full_path.push(file.item());
} }
}
let stream = async_stream_block! {
let input: Vec<Tagged<Value>> = input.values.collect().await;
let content = if !save_raw { let content = if !save_raw {
to_string_for(full_path.extension(), &input).await if let Some(extension) = full_path.extension() {
let command_name = format!("to-{}", extension.to_str().unwrap());
if let Some(converter) = registry.get_command(&command_name) {
let new_args = RawCommandArgs {
host: host,
shell_manager: shell_manager,
call_info: UnevaluatedCallInfo {
args: crate::parser::hir::Call {
head: raw_args.call_info.args.head,
positional: None,
named: None
},
source: raw_args.call_info.source,
source_map: raw_args.call_info.source_map,
name_span: raw_args.call_info.name_span,
}
};
let mut result = converter.run(new_args.with_input(input), &registry);
let result_vec: Vec<Result<ReturnSuccess, ShellError>> = result.drain_vec().await;
let mut result_string = String::new();
for res in result_vec {
match res {
Ok(ReturnSuccess::Value(Tagged { item: Value::Primitive(Primitive::String(s)), .. })) => {
result_string.push_str(&s);
}
_ => {
yield Err(ShellError::labeled_error(
"Save could not successfully save",
"unexpected data during saveS",
name_span,
));
},
}
}
Ok(result_string)
} else {
let mut result_string = String::new();
for res in input {
match res {
Tagged { item: Value::Primitive(Primitive::String(s)), .. } => {
result_string.push_str(&s);
}
_ => {
yield Err(ShellError::labeled_error(
"Save could not successfully save",
"unexpected data during saveS",
name_span,
));
},
}
}
Ok(result_string)
}
} else {
let mut result_string = String::new();
for res in input {
match res {
Tagged { item: Value::Primitive(Primitive::String(s)), .. } => {
result_string.push_str(&s);
}
_ => {
yield Err(ShellError::labeled_error(
"Save could not successfully save",
"unexpected data during saveS",
name_span,
));
},
}
}
Ok(result_string)
}
} else { } else {
string_from(&input) string_from(&input)
}; };
@ -131,7 +180,6 @@ fn save(
}; };
Ok(OutputStream::new(stream)) Ok(OutputStream::new(stream))
}
} }
fn string_from(input: &Vec<Tagged<Value>>) -> Result<String, ShellError> { fn string_from(input: &Vec<Tagged<Value>>) -> Result<String, ShellError> {
@ -153,66 +201,3 @@ fn string_from(input: &Vec<Tagged<Value>>) -> Result<String, ShellError> {
Ok(save_data) Ok(save_data)
} }
async fn to_string_for(
ext: Option<&std::ffi::OsStr>,
input: &Vec<Tagged<Value>>,
) -> Result<String, ShellError> {
let contents = match ext {
Some(x) if x == "csv" => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to csv requires a single object (or use --raw)",
));
}
to_csv_to_string(&value_to_csv_value(&input[0]))?
}
Some(x) if x == "tsv" => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to tsv requires a single object (or use --raw)",
));
}
to_tsv_to_string(&value_to_tsv_value(&input[0]))?
}
Some(x) if x == "toml" => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to toml requires a single object (or use --raw)",
));
}
toml::to_string(&value_to_toml_value(&input[0]))?
}
Some(x) if x == "json" => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to json requires a single object (or use --raw)",
));
}
serde_json::to_string(&value_to_json_value(&input[0]))?
}
Some(x) if x == "yml" => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to yml requires a single object (or use --raw)",
));
}
serde_yaml::to_string(&value_to_yaml_value(&input[0]))?
}
Some(x) if x == "yaml" => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to yaml requires a single object (or use --raw)",
));
}
serde_yaml::to_string(&value_to_yaml_value(&input[0]))?
}
_ => {
return Err(ShellError::string(
"tried saving a single object with an unrecognized format.",
))
}
};
Ok(contents)
}