diff --git a/src/buffer.rs b/src/buffer.rs index 70d3b54..73975d5 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -33,7 +33,7 @@ use crate::{Cursor, Direction}; #[derive(Clone, Debug)] pub struct Buffer { styles: Arc>, - text: Rope, + pub text: Rope, syntax_set: Arc, parser: ParseState, style_dirty: bool, diff --git a/src/main.rs b/src/main.rs index 7c7f8d7..4dec4f2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,8 +19,14 @@ use std::{ env::args, - fs::File, - io::{stdout, Read, Stdout, Write}, + ffi::OsString, + fs::{ File, OpenOptions }, + io::{ + Read, + stdout, + Stdout, + Write, + }, os::fd::FromRawFd, path::PathBuf, sync::Arc, @@ -103,15 +109,16 @@ pub struct State { pub styles: Arc>, 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, pub theme_tx: Sender, } impl State { - pub fn from_str(text: &str) -> Result { + pub fn from_str(file_name: Option, text: &str) -> Result { let styles = Arc::new(Mutex::new(StyleStore::default())); let buffer = Buffer::from_str(styles.clone(), text); let (cols, rows) = terminal::size()?; @@ -121,9 +128,10 @@ impl State { styles, buffer, cursor: Cursor::default(), + file: file_name, + mode: Mode::default(), scroll: Cursor::default(), size: (cols as usize, rows as usize), - mode: Mode::default(), quit: false, theme_tx, }) @@ -321,12 +329,53 @@ impl State { } } - fn execute_command(&mut self, command: &str) -> std::result::Result<(), String> { - match command { - "q" => self.quit = true, - command => return Err(format!("unrecognized command {:?}", command)), - } + fn write_buffer(&mut self, file: OsString) -> Result<()> { + let out = self.buffer.text.bytes().collect::>(); + let mut handle = OpenOptions::new().write(true).open(file)?; + handle.write_all(out.as_slice())?; + + Ok(()) + } + + fn execute_command(&mut self, command: &str) -> std::result::Result<(), String> { + let command_parts = command.split(' ').collect::>(); + + 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).map_err(|err| { + format!("{}", err) + })?; + }, + command => { + return Err( + format!("{}: Unrecognized command.", command) + ); + }, + } + } Ok(()) } @@ -363,23 +412,34 @@ 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]); - exit(EX_UNAVAILABLE); - }), - } - .read_to_end(&mut buf) - .unwrap(); + } else { File::open("/dev/null").unwrap() } + }, + Some(path) => { + let input_file = Path::new(path); + file_name = Some(OsString::from( + input_file.clone().display().to_string() + )); + + 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); + }) + }, + }.read_to_end(&mut buf).unwrap(); let text = String::from_utf8(buf).unwrap_or_else(|_| { eprintln!( @@ -389,7 +449,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)?;