@@ -8,6 +8,7 @@ use nu_protocol::{
88 byte_stream:: copy_with_signals, process:: ChildPipe , shell_error:: io:: IoError ,
99} ;
1010use std:: {
11+ borrow:: Cow ,
1112 fs:: File ,
1213 io:: { self , BufRead , BufReader , Read , Write } ,
1314 path:: { Path , PathBuf } ,
@@ -224,8 +225,28 @@ impl Command for Save {
224225 ) ?;
225226 }
226227
227- let bytes =
228- input_to_bytes ( input, Path :: new ( & path. item ) , raw, engine_state, stack, span) ?;
228+ // Try to convert the input pipeline into another type if we know the extension
229+ let ext = extract_extension ( & input, & path. item , raw) ;
230+ let converted = match ext {
231+ None => input,
232+ Some ( ext) => convert_to_extension ( engine_state, & ext, stack, input, span) ?,
233+ } ;
234+
235+ // Save custom value however they implement saving
236+ if let PipelineData :: Value ( Value :: Custom { val, internal_span } , ..) = converted {
237+ return val
238+ . save (
239+ Spanned {
240+ item : & path. item ,
241+ span : path. span ,
242+ } ,
243+ internal_span,
244+ span,
245+ )
246+ . map ( |( ) | PipelineData :: empty ( ) ) ;
247+ }
248+
249+ let bytes = value_to_bytes ( converted. into_value ( span) ?) ?;
229250
230251 // Only open file after successful conversion
231252 let ( mut file, _) =
@@ -321,34 +342,14 @@ fn check_saving_to_source_file(
321342 Ok ( ( ) )
322343}
323344
324- /// Convert [`PipelineData`] bytes to write in file, possibly converting
325- /// to format of output file
326- fn input_to_bytes (
327- input : PipelineData ,
328- path : & Path ,
329- raw : bool ,
330- engine_state : & EngineState ,
331- stack : & mut Stack ,
332- span : Span ,
333- ) -> Result < Vec < u8 > , ShellError > {
334- let ext = if raw {
335- None
336- } else if let PipelineData :: ByteStream ( ..) = input {
337- None
338- } else if let PipelineData :: Value ( Value :: String { .. } , ..) = input {
339- None
340- } else {
341- path. extension ( )
342- . map ( |name| name. to_string_lossy ( ) . to_string ( ) )
343- } ;
344-
345- let input = if let Some ( ext) = ext {
346- convert_to_extension ( engine_state, & ext, stack, input, span) ?
347- } else {
348- input
349- } ;
350-
351- value_to_bytes ( input. into_value ( span) ?)
345+ /// Extract extension for conversion.
346+ fn extract_extension < ' e > ( input : & PipelineData , path : & ' e Path , raw : bool ) -> Option < Cow < ' e , str > > {
347+ match ( raw, input) {
348+ ( true , _)
349+ | ( _, PipelineData :: ByteStream ( ..) )
350+ | ( _, PipelineData :: Value ( Value :: String { .. } , ..) ) => None ,
351+ _ => path. extension ( ) . map ( |name| name. to_string_lossy ( ) ) ,
352+ }
352353}
353354
354355/// Convert given data into content of file of specified extension if
0 commit comments