From aee17365c6b000d6c48f505157c489b97e48ae39 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 12 Apr 2023 01:22:16 -0400 Subject: [PATCH 1/3] basic file handling --- src/main.rs | 65 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1f78c67..c5b84d4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,7 +19,8 @@ use std::{ env::args, - fs::File, + ffi::OsString, + fs::{ File, write }, io::{ Read, stdout, @@ -27,6 +28,7 @@ use std::{ Write, }, os::fd::FromRawFd, + path::{ Path } }; use crossterm::{ @@ -194,22 +196,24 @@ enum Direction { struct State { pub buffer: Buffer, pub cursor: Cursor, + pub file: Option, + pub mode: Mode, pub scroll: Cursor, pub size: (usize, usize), - pub mode: Mode, pub quit: bool, } impl State { - pub fn from_str(text: &str) -> Result { + pub fn from_str(file_name: Option, text: &str) -> Result { let (cols, rows) = terminal::size()?; Ok(Self { buffer: Buffer::from_str(text), cursor: Cursor::default(), + file: file_name, + mode: Mode::default(), scroll: Cursor::default(), size: (cols as usize, rows as usize), - mode: Mode::default(), quit: false, }) } @@ -410,12 +414,40 @@ impl State { } } + fn write_buffer(&mut self, file: OsString) -> std::result::Result<(), String> { + let out = self.buffer.text.bytes().collect::>(); + + let handle = file + .clone() + .into_string() + .map_err(|err| { + format!("{:?}", err) + })?; + + write(handle, out.as_slice()) + .map_err(|err| { + format!("{:?}", err) + })?; + + Ok(()) + } + fn execute_command(&mut self, command: &str) -> std::result::Result<(), String> { match command { "q" => self.quit = true, - command => return Err(format!("unrecognized command {:?}", command)), - } + "w" => { + let handle = self.file.clone().unwrap_or_else(|| { + OsString::from("file") + }); + self.write_buffer(handle)?; + }, + command => { + return Err( + format!("{:?}: Unrecognized command.", command) + ); + }, + } Ok(()) } @@ -449,21 +481,28 @@ fn screen_main(stdout: &mut Stdout, mut state: State) -> Result<()> { fn main() -> Result<()> { let argv = args().collect::>(); let mut buf = Vec::new(); + let file_name: Option; match argv.get(1).map(|s| s.as_str()) { Some("-") | None => { + file_name = None; let stdin = 0; // get stdin as a file descriptor if unsafe { libc::isatty(stdin) } == 0 { unsafe { File::from_raw_fd(stdin) } } else { File::open("/dev/null").unwrap() } }, Some(path) => { - std::fs::File::open(path).unwrap_or_else(|_| { - eprintln!( - "{}: {}: No such file or directory.", - argv[0], - argv[1] - ); + let input_file = Path::new(path); + file_name = input_file.clone().file_name().map(|f| f.to_owned()); + + File::open(input_file).unwrap_or_else(|_| { + let mut err = String::new(); + if !input_file.exists() { + err = "No such file or directory.".to_string(); + } else if input_file.is_dir() { + err = "Is a directory.".to_string(); + } + eprintln!("{}: {}: {}", argv[0], path, err); exit(EX_UNAVAILABLE); }) }, @@ -476,7 +515,7 @@ fn main() -> Result<()> { exit(EX_DATAERR); }); - let state = State::from_str(&text)?; + let state = State::from_str(file_name, &text)?; let mut stdout = stdout(); terminal::enable_raw_mode()?; stdout.execute(terminal::EnterAlternateScreen)?; From 0ff694c6c1e1addcb63fbde91a56c6fe561e2da4 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 12 Apr 2023 11:52:21 -0400 Subject: [PATCH 2/3] better command parsing with file name argument for :w --- src/main.rs | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index c5b84d4..6dc6ac5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -433,20 +433,40 @@ impl State { } fn execute_command(&mut self, command: &str) -> std::result::Result<(), String> { - match command { - "q" => self.quit = true, - "w" => { - let handle = self.file.clone().unwrap_or_else(|| { - OsString::from("file") - }); + let command_parts = command.split(' ').collect::>(); - self.write_buffer(handle)?; - }, - command => { - return Err( - format!("{:?}: Unrecognized command.", command) - ); - }, + let commands = match command_parts.get(0) { + Some(parts) => parts.chars().collect::>(), + None => return Ok(()), + }; + + for command in commands.clone().iter() { + match command { + 'q' => self.quit = true, + 'w' => { + let handle: OsString; + + if let Some(part) = self.file.clone() { + handle = part; + } else { + handle = match command_parts.get(1) { + Some(part) => OsString::from(part), + None => { + return Err( + format!("{}: No file name.", command) + ); + }, + }; + } + + self.write_buffer(handle)?; + }, + command => { + return Err( + format!("{}: Unrecognized command.", command) + ); + }, + } } Ok(()) } From 6ef5182cea1a048842a0ee757fd5069cfa032551 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 12 Apr 2023 12:44:37 -0400 Subject: [PATCH 3/3] fixed file path resolution --- src/main.rs | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/main.rs b/src/main.rs index 902563f..ca2a82d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,7 +20,7 @@ use std::{ env::args, ffi::OsString, - fs::{ File, write }, + fs::{ File, OpenOptions }, io::{ Read, stdout, @@ -335,20 +335,11 @@ impl State { } } - fn write_buffer(&mut self, file: OsString) -> std::result::Result<(), String> { + fn write_buffer(&mut self, file: OsString) -> Result<()> { let out = self.buffer.text.bytes().collect::>(); + let mut handle = OpenOptions::new().write(true).open(file)?; - let handle = file - .clone() - .into_string() - .map_err(|err| { - format!("{:?}", err) - })?; - - write(handle, out.as_slice()) - .map_err(|err| { - format!("{:?}", err) - })?; + handle.write_all(out.as_slice())?; Ok(()) } @@ -380,7 +371,9 @@ impl State { }; } - self.write_buffer(handle)?; + self.write_buffer(handle).map_err(|err| { + format!("{}", err) + })?; }, command => { return Err( @@ -434,7 +427,9 @@ fn main() -> Result<()> { }, Some(path) => { let input_file = Path::new(path); - file_name = input_file.clone().file_name().map(|f| f.to_owned()); + file_name = Some(OsString::from( + input_file.clone().display().to_string() + )); File::open(input_file).unwrap_or_else(|_| { let mut err = String::new();