forked from mars/breed
1
0
Fork 0

Merge pull request 'basic file handling' (#7) from emma/breed:main into main

Reviewed-on: mars/breed#7
This commit is contained in:
mars 2023-04-12 21:13:38 +00:00
commit aa013fc422
2 changed files with 84 additions and 23 deletions

View File

@ -33,7 +33,7 @@ use crate::{Cursor, Direction};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Buffer { pub struct Buffer {
styles: Arc<Mutex<StyleStore>>, styles: Arc<Mutex<StyleStore>>,
text: Rope, pub text: Rope,
syntax_set: Arc<SyntaxSet>, syntax_set: Arc<SyntaxSet>,
parser: ParseState, parser: ParseState,
styled: Vec<Vec<(Style, Range<usize>)>>, styled: Vec<Vec<(Style, Range<usize>)>>,

View File

@ -19,9 +19,16 @@
use std::{ use std::{
env::args, env::args,
fs::File, ffi::OsString,
io::{stdout, Read, Stdout, Write}, fs::{ File, OpenOptions },
io::{
Read,
stdout,
Stdout,
Write,
},
os::fd::FromRawFd, os::fd::FromRawFd,
path::{ Path },
sync::Arc, sync::Arc,
}; };
@ -99,14 +106,15 @@ struct State {
pub styles: Arc<Mutex<StyleStore>>, pub styles: Arc<Mutex<StyleStore>>,
pub buffer: Buffer, pub buffer: Buffer,
pub cursor: Cursor, pub cursor: Cursor,
pub file: Option<OsString>,
pub mode: Mode,
pub scroll: Cursor, pub scroll: Cursor,
pub size: (usize, usize), pub size: (usize, usize),
pub mode: Mode,
pub quit: bool, pub quit: bool,
} }
impl State { impl State {
pub fn from_str(text: &str) -> Result<Self> { pub fn from_str(file_name: Option<OsString>, text: &str) -> Result<Self> {
let styles = Arc::new(Mutex::new(StyleStore::default())); let styles = Arc::new(Mutex::new(StyleStore::default()));
let buffer = Buffer::from_str(styles.clone(), text); let buffer = Buffer::from_str(styles.clone(), text);
let (cols, rows) = terminal::size()?; let (cols, rows) = terminal::size()?;
@ -115,9 +123,10 @@ impl State {
styles, styles,
buffer, buffer,
cursor: Cursor::default(), cursor: Cursor::default(),
file: file_name,
mode: Mode::default(),
scroll: Cursor::default(), scroll: Cursor::default(),
size: (cols as usize, rows as usize), size: (cols as usize, rows as usize),
mode: Mode::default(),
quit: false, quit: false,
}) })
} }
@ -331,12 +340,53 @@ impl State {
} }
} }
fn execute_command(&mut self, command: &str) -> std::result::Result<(), String> { fn write_buffer(&mut self, file: OsString) -> Result<()> {
match command { let out = self.buffer.text.bytes().collect::<Vec<u8>>();
"q" => self.quit = true, let mut handle = OpenOptions::new().write(true).open(file)?;
command => return Err(format!("unrecognized command {:?}", command)),
}
handle.write_all(out.as_slice())?;
Ok(())
}
fn execute_command(&mut self, command: &str) -> std::result::Result<(), String> {
let command_parts = command.split(' ').collect::<Vec<&str>>();
let commands = match command_parts.get(0) {
Some(parts) => parts.chars().collect::<Vec<char>>(),
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(()) Ok(())
} }
@ -370,23 +420,34 @@ fn screen_main(stdout: &mut Stdout, mut state: State) -> Result<()> {
fn main() -> Result<()> { fn main() -> Result<()> {
let argv = args().collect::<Vec<String>>(); let argv = args().collect::<Vec<String>>();
let mut buf = Vec::new(); let mut buf = Vec::new();
let file_name: Option<OsString>;
match argv.get(1).map(|s| s.as_str()) { match argv.get(1).map(|s| s.as_str()) {
Some("-") | None => { Some("-") | None => {
file_name = None;
let stdin = 0; // get stdin as a file descriptor let stdin = 0; // get stdin as a file descriptor
if unsafe { libc::isatty(stdin) } == 0 { if unsafe { libc::isatty(stdin) } == 0 {
unsafe { File::from_raw_fd(stdin) } unsafe { File::from_raw_fd(stdin) }
} else { } else { File::open("/dev/null").unwrap() }
File::open("/dev/null").unwrap() },
} Some(path) => {
} let input_file = Path::new(path);
Some(path) => std::fs::File::open(path).unwrap_or_else(|_| { file_name = Some(OsString::from(
eprintln!("{}: {}: No such file or directory.", argv[0], argv[1]); input_file.clone().display().to_string()
exit(EX_UNAVAILABLE); ));
}),
} File::open(input_file).unwrap_or_else(|_| {
.read_to_end(&mut buf) let mut err = String::new();
.unwrap(); 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(|_| { let text = String::from_utf8(buf).unwrap_or_else(|_| {
eprintln!( eprintln!(
@ -396,7 +457,7 @@ fn main() -> Result<()> {
exit(EX_DATAERR); exit(EX_DATAERR);
}); });
let state = State::from_str(&text)?; let state = State::from_str(file_name, &text)?;
let mut stdout = stdout(); let mut stdout = stdout();
terminal::enable_raw_mode()?; terminal::enable_raw_mode()?;
stdout.execute(terminal::EnterAlternateScreen)?; stdout.execute(terminal::EnterAlternateScreen)?;