diff --git a/crates/nu-cli/src/commands/open.rs b/crates/nu-cli/src/commands/open.rs index d3ee1bb4df..102ea00cfe 100644 --- a/crates/nu-cli/src/commands/open.rs +++ b/crates/nu-cli/src/commands/open.rs @@ -1,17 +1,14 @@ -use crate::commands::classified::maybe_text_codec::{MaybeTextCodec, StringOrBinary}; +use crate::commands::classified::maybe_text_codec::StringOrBinary; +use crate::commands::constants::BAT_LANGUAGES; use crate::commands::WholeStreamCommand; use crate::prelude::*; -use futures_codec::FramedRead; +use encoding_rs::{Encoding, UTF_8}; +use futures_util::StreamExt; +use log::debug; use nu_errors::ShellError; use nu_protocol::{CommandAction, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_source::{AnchorLocation, Span, Tagged}; use std::path::PathBuf; -extern crate encoding_rs; -use crate::commands::constants::BAT_LANGUAGES; -use encoding_rs::*; -use futures::prelude::*; -use log::debug; -use std::fs::File; pub struct Open; @@ -103,6 +100,7 @@ pub fn get_encoding(opt: Option>) -> Result<&'static Encoding, Sh async fn open(args: CommandArgs, registry: &CommandRegistry) -> Result { let cwd = PathBuf::from(args.shell_manager.path()); let registry = registry.clone(); + let shell_manager = args.shell_manager.clone(); let ( OpenArgs { @@ -159,17 +157,8 @@ async fn open(args: CommandArgs, registry: &CommandRegistry) -> Result match std::fs::write(full_path, save_data) { - Ok(_) => Ok(OutputStream::empty()), - Err(e) => Err(ShellError::labeled_error( - e.to_string(), - "IO error while saving", - name, - )), - }, + Ok(save_data) => shell_manager.save(&full_path, &save_data, name.span), Err(e) => Err(e), } } diff --git a/crates/nu-cli/src/shell/filesystem_shell.rs b/crates/nu-cli/src/shell/filesystem_shell.rs index 748f4089ac..32f7b5f197 100644 --- a/crates/nu-cli/src/shell/filesystem_shell.rs +++ b/crates/nu-cli/src/shell/filesystem_shell.rs @@ -18,6 +18,11 @@ use std::collections::HashMap; use std::io::{Error, ErrorKind}; use std::path::{Path, PathBuf}; +use crate::commands::classified::maybe_text_codec::{MaybeTextCodec, StringOrBinary}; +use encoding_rs::Encoding; +use futures_codec::FramedRead; +use futures_util::TryStreamExt; + #[cfg(unix)] use std::os::unix::fs::PermissionsExt; @@ -679,6 +684,45 @@ impl Shell for FilesystemShell { self.path = path.to_string_lossy().to_string(); } + fn open( + &self, + path: &PathBuf, + name: Span, + with_encoding: Option<&'static Encoding>, + ) -> Result>, ShellError> { + let f = std::fs::File::open(&path).map_err(|e| { + ShellError::labeled_error( + format!("Error opening file: {:?}", e), + "Error opening file", + name, + ) + })?; + let async_reader = futures::io::AllowStdIo::new(f); + let sob_stream = FramedRead::new(async_reader, MaybeTextCodec::new(with_encoding)) + .map_err(|e| { + ShellError::unexpected(format!("AsyncRead failed in open function: {:?}", e)) + }) + .into_stream(); + + Ok(sob_stream.boxed()) + } + + fn save( + &mut self, + full_path: &PathBuf, + save_data: &[u8], + name: Span, + ) -> Result { + match std::fs::write(full_path, save_data) { + Ok(_) => Ok(OutputStream::empty()), + Err(e) => Err(ShellError::labeled_error( + e.to_string(), + "IO error while saving", + name, + )), + } + } + fn complete( &self, line: &str, diff --git a/crates/nu-cli/src/shell/help_shell.rs b/crates/nu-cli/src/shell/help_shell.rs index a92857705f..cb7e2759f2 100644 --- a/crates/nu-cli/src/shell/help_shell.rs +++ b/crates/nu-cli/src/shell/help_shell.rs @@ -12,6 +12,8 @@ use crate::shell::shell::Shell; use std::ffi::OsStr; use std::path::PathBuf; +use crate::commands::classified::maybe_text_codec::StringOrBinary; +use encoding_rs::Encoding; use nu_errors::ShellError; use nu_protocol::{ Primitive, ReturnSuccess, ShellTypeName, TaggedDictBuilder, UntaggedValue, Value, @@ -197,6 +199,28 @@ impl Shell for HelpShell { Ok(OutputStream::empty()) } + fn open( + &self, + _path: &PathBuf, + _name: Span, + _with_encoding: Option<&'static Encoding>, + ) -> Result>, ShellError> { + Err(ShellError::unimplemented( + "open on help shell is not supported", + )) + } + + fn save( + &mut self, + _path: &PathBuf, + _contents: &[u8], + _name: Span, + ) -> Result { + Err(ShellError::unimplemented( + "save on help shell is not supported", + )) + } + fn complete( &self, line: &str, diff --git a/crates/nu-cli/src/shell/shell.rs b/crates/nu-cli/src/shell/shell.rs index 2c8f0d50b8..36a3e337f7 100644 --- a/crates/nu-cli/src/shell/shell.rs +++ b/crates/nu-cli/src/shell/shell.rs @@ -1,4 +1,5 @@ use crate::commands::cd::CdArgs; +use crate::commands::classified::maybe_text_codec::StringOrBinary; use crate::commands::command::EvaluatedWholeStreamCommandArgs; use crate::commands::cp::CopyArgs; use crate::commands::ls::LsArgs; @@ -7,6 +8,7 @@ use crate::commands::move_::mv::Arguments as MvArgs; use crate::commands::rm::RemoveArgs; use crate::prelude::*; use crate::stream::OutputStream; +use encoding_rs::Encoding; use nu_errors::ShellError; use std::path::PathBuf; @@ -28,6 +30,18 @@ pub trait Shell: std::fmt::Debug { fn path(&self) -> String; fn pwd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result; fn set_path(&mut self, path: String); + fn open( + &self, + path: &PathBuf, + name: Span, + with_encoding: Option<&'static Encoding>, + ) -> Result>, ShellError>; + fn save( + &mut self, + path: &PathBuf, + contents: &[u8], + name: Span, + ) -> Result; fn complete( &self, diff --git a/crates/nu-cli/src/shell/shell_manager.rs b/crates/nu-cli/src/shell/shell_manager.rs index b9dd163f87..325540fd95 100644 --- a/crates/nu-cli/src/shell/shell_manager.rs +++ b/crates/nu-cli/src/shell/shell_manager.rs @@ -1,4 +1,5 @@ use crate::commands::cd::CdArgs; +use crate::commands::classified::maybe_text_codec::StringOrBinary; use crate::commands::command::EvaluatedWholeStreamCommandArgs; use crate::commands::cp::CopyArgs; use crate::commands::ls::LsArgs; @@ -9,6 +10,7 @@ use crate::prelude::*; use crate::shell::filesystem_shell::FilesystemShell; use crate::shell::shell::Shell; use crate::stream::OutputStream; +use encoding_rs::Encoding; use nu_errors::ShellError; use parking_lot::Mutex; use std::error::Error; @@ -81,6 +83,25 @@ impl ShellManager { self.shells.lock()[self.current_shell()].set_path(path) } + pub fn open( + &self, + full_path: &PathBuf, + name: Span, + with_encoding: Option<&'static Encoding>, + ) -> Result> + Send + 'static, ShellError> + { + self.shells.lock()[self.current_shell()].open(full_path, name, with_encoding) + } + + pub fn save( + &mut self, + full_path: &PathBuf, + save_data: &[u8], + name: Span, + ) -> Result { + self.shells.lock()[self.current_shell()].save(full_path, save_data, name) + } + pub fn complete( &self, line: &str, diff --git a/crates/nu-cli/src/shell/value_shell.rs b/crates/nu-cli/src/shell/value_shell.rs index 11fcdc9f49..08ad6461a7 100644 --- a/crates/nu-cli/src/shell/value_shell.rs +++ b/crates/nu-cli/src/shell/value_shell.rs @@ -9,6 +9,8 @@ use crate::prelude::*; use crate::shell::shell::Shell; use crate::utils::ValueStructure; +use crate::commands::classified::maybe_text_codec::StringOrBinary; +use encoding_rs::Encoding; use std::ffi::OsStr; use std::path::{Path, PathBuf}; @@ -230,6 +232,28 @@ impl Shell for ValueShell { self.path = path; } + fn open( + &self, + _path: &PathBuf, + _name: Span, + _with_encoding: Option<&'static Encoding>, + ) -> Result>, ShellError> { + Err(ShellError::unimplemented( + "open on help shell is not supported", + )) + } + + fn save( + &mut self, + _path: &PathBuf, + _contents: &[u8], + _name: Span, + ) -> Result { + Err(ShellError::unimplemented( + "save on help shell is not supported", + )) + } + fn complete( &self, line: &str,