use std::{path::PathBuf, rc::Rc}; use super::{CommandResult, EditorBuffer, EditorBufferState}; use crate::{Point, TextBuffer, TextBufferReader, TextBufferWriter}; #[doc(hidden)] impl EditorBuffer { pub fn open_file(&self, filepath: PathBuf) -> CommandResult { match std::fs::File::open(&filepath) { Ok(mut file) => { let mut buffer = TextBuffer::new(); match std::io::copy(&mut file, &mut TextBufferWriter::new(&mut buffer)) { Ok(bytes_read) => { let msg = format!( "Read {bytes_read} bytes from \"{}\"", filepath.to_string_lossy() ); let state = Rc::new(EditorBufferState { filepath: Some(filepath), ..*self.state }); let cursor = Point::default(); let buffer = buffer; CommandResult::success_with_message( Self { state, cursor, buffer, ..self.clone() }, msg, ) } Err(err) => CommandResult::fail_with_message(self.clone(), format!("{}", err)), } } Err(err) => { if err.kind() == std::io::ErrorKind::NotFound { CommandResult::fail_with_message( self.clone(), format!("File not found: \"{}\"", filepath.to_string_lossy()), ) } else { CommandResult::fail_with_message(self.clone(), format!("{}", err)) } } } } pub fn save_file(&self, filepath: Option) -> CommandResult { if let Some(filepath) = filepath.as_ref().or(self.state.filepath.as_ref()) { match std::fs::File::create(filepath) { Ok(mut file) => { match std::io::copy(&mut TextBufferReader::new(&self.buffer), &mut file) { Ok(bytes_read) => CommandResult::success_with_message( self.clone(), format!( "Read {bytes_read} bytes to \"{}\"", filepath.to_string_lossy() ), ), Err(err) => { CommandResult::fail_with_message(self.clone(), format!("{}", err)) } } } Err(err) => CommandResult::fail_with_message(self.clone(), format!("{}", err)), } } else { CommandResult::fail_with_message(self.clone(), "Attempting to same file with no name.") } } } #[cfg(test)] mod tests { use crate::{Command, CommandResponse, EditorBuffer, TextBufferReader}; use std::{io::Read, path::PathBuf}; use tempfile::tempdir; #[test] fn load_file_loads_expected_contents() { let test_file_path: PathBuf = [ env!("CARGO_MANIFEST_DIR"), r"test_data/Les_Trois_Mousquetaires.txt", ] .iter() .collect(); let expected_text = std::fs::read_to_string(&test_file_path).unwrap(); let target = EditorBuffer::new(); let result = target.execute(Command::OpenFile(test_file_path)); assert!(result.is_ok()); let target = result.buffer; let mut buffer_bytes = Vec::new(); TextBufferReader::new(&target.buffer) .read_to_end(&mut buffer_bytes) .unwrap(); let buffer_text = String::from_utf8(buffer_bytes).unwrap(); assert_eq!(&expected_text, &buffer_text); } #[test] fn load_file_reports_error_with_missing_file() { let test_file_path: PathBuf = [env!("CARGO_MANIFEST_DIR"), r"test_data/Not_a_File.txt"] .iter() .collect(); let expected_message = format!("File not found: \"{}\"", test_file_path.to_string_lossy()); let target = EditorBuffer::new(); let result = target.execute(Command::OpenFile(test_file_path)); assert!(!result.is_ok()); match result.response { CommandResponse::Message(s) => assert_eq!(expected_message, s), _ => panic!(), } } #[test] fn save_file_saves_file_with_expected_contents() { let test_file_path: PathBuf = [ env!("CARGO_MANIFEST_DIR"), r"test_data/Les_Trois_Mousquetaires.txt", ] .iter() .collect(); let target = EditorBuffer::new(); let target = target.execute(Command::OpenFile(test_file_path.clone())).buffer; let temp_dir = tempdir().unwrap(); let tmp_file_path = temp_dir.path().join(r"Les_Trois_Mousquetaires.txt"); let result = target.execute(Command::SaveAs(tmp_file_path.clone())); assert!(result.is_ok()); let read_text = std::fs::read_to_string(&tmp_file_path).unwrap(); let expected_text = std::fs::read_to_string(&test_file_path).unwrap(); assert_eq!(&expected_text, &read_text); } }