From 761cc3db14fb728109d550cb28a696966149f217 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Sat, 31 Aug 2019 12:59:21 +1200 Subject: [PATCH] Finish up enter and save --- src/commands/classified.rs | 38 +------ src/commands/enter.rs | 105 +++++++++++++++++-- src/commands/save.rs | 205 +++++++++++++++++-------------------- 3 files changed, 197 insertions(+), 151 deletions(-) diff --git a/src/commands/classified.rs b/src/commands/classified.rs index cf3689c1e6..1430707637 100644 --- a/src/commands/classified.rs +++ b/src/commands/classified.rs @@ -146,41 +146,9 @@ impl InternalCommand { .insert_at_current(Box::new(ValueShell::new(value))); } 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( - FilesystemShell::with_location( - 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), - ))) - } + context.shell_manager.insert_at_current(Box::new( + FilesystemShell::with_location(location, context.registry().clone())?, + )); } CommandAction::PreviousShell => { context.shell_manager.prev(); diff --git a/src/commands/enter.rs b/src/commands/enter.rs index 19f6b9c8cb..63316b7082 100644 --- a/src/commands/enter.rs +++ b/src/commands/enter.rs @@ -1,8 +1,10 @@ use crate::commands::command::CommandAction; use crate::commands::PerItemCommand; +use crate::commands::UnevaluatedCallInfo; use crate::errors::ShellError; use crate::parser::registry; use crate::prelude::*; +use std::path::PathBuf; pub struct Enter; @@ -18,18 +20,109 @@ impl PerItemCommand for Enter { fn run( &self, call_info: &CallInfo, - _registry: ®istry::CommandRegistry, - _raw_args: &RawCommandArgs, + registry: ®istry::CommandRegistry, + raw_args: &RawCommandArgs, _input: Tagged, ) -> Result { + let registry = registry.clone(); + let raw_args = raw_args.clone(); match call_info.args.expect_nth(0)? { Tagged { item: Value::Primitive(Primitive::String(location)), .. - } => Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterShell( - location.to_string(), - )))] - .into()), + } => { + 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()) + } 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]), + ®istry, + ); + let result_vec: Vec> = + 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( vec![Ok(ReturnSuccess::Action(CommandAction::EnterValueShell( x.clone(), diff --git a/src/commands/save.rs b/src/commands/save.rs index 1ecd22e91f..11b245ef9c 100644 --- a/src/commands/save.rs +++ b/src/commands/save.rs @@ -1,8 +1,4 @@ -use crate::commands::to_csv::{to_string as to_csv_to_string, value_to_csv_value}; -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::UnevaluatedCallInfo; use crate::commands::WholeStreamCommand; use crate::errors::ShellError; use crate::object::Value; @@ -33,7 +29,7 @@ impl WholeStreamCommand for Save { args: CommandArgs, registry: &CommandRegistry, ) -> Result { - args.process(registry, save)?.run() + Ok(args.process_raw(registry, save)?.run()) } } @@ -47,16 +43,19 @@ fn save( name, shell_manager, source_map, + host, + commands: registry, .. }: RunnableContext, + raw_args: RawCommandArgs, ) -> Result { let mut full_path = PathBuf::from(shell_manager.path()); let name_span = name; - if path.is_none() { - let source_map = source_map.clone(); - let stream = async_stream_block! { - let input: Vec> = input.values.collect().await; + let source_map = source_map.clone(); + let stream = async_stream_block! { + let input: Vec> = input.values.collect().await; + if path.is_none() { // If there is no filename, check the metadata for the origin filename if input.len() > 0 { let origin = input[0].origin(); @@ -88,50 +87,99 @@ fn save( 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())), + } else { + if let Some(file) = path { + full_path.push(file.item()); } - - }; - - Ok(OutputStream::new(stream)) - } else { - if let Some(file) = path { - full_path.push(file.item()); } - let stream = async_stream_block! { - let input: Vec> = input.values.collect().await; - - let content = if !save_raw { - to_string_for(full_path.extension(), &input).await + let content = if !save_raw { + 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), ®istry); + let result_vec: Vec> = 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 { - 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())), + 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 { + string_from(&input) }; - Ok(OutputStream::new(stream)) - } + 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)) } fn string_from(input: &Vec>) -> Result { @@ -153,66 +201,3 @@ fn string_from(input: &Vec>) -> Result { Ok(save_data) } - -async fn to_string_for( - ext: Option<&std::ffi::OsStr>, - input: &Vec>, -) -> Result { - 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) -}