Merge branch 'main' of https://git.tebibyte.media/mars/breed
This commit is contained in:
commit
6f81bab277
|
@ -33,7 +33,7 @@ use crate::{Cursor, Direction};
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct Buffer {
|
||||
styles: Arc<Mutex<StyleStore>>,
|
||||
text: Rope,
|
||||
pub text: Rope,
|
||||
syntax_set: Arc<SyntaxSet>,
|
||||
parser: ParseState,
|
||||
style_dirty: bool,
|
||||
|
|
98
src/main.rs
98
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<Mutex<StyleStore>>,
|
||||
pub buffer: Buffer,
|
||||
pub cursor: Cursor,
|
||||
pub file: Option<OsString>,
|
||||
pub mode: Mode,
|
||||
pub scroll: Cursor,
|
||||
pub size: (usize, usize),
|
||||
pub mode: Mode,
|
||||
pub quit: bool,
|
||||
pub theme_tx: Sender<PathBuf>,
|
||||
}
|
||||
|
||||
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 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::<Vec<u8>>();
|
||||
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::<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(())
|
||||
}
|
||||
|
||||
|
@ -363,23 +412,34 @@ fn screen_main(stdout: &mut Stdout, mut state: State) -> Result<()> {
|
|||
fn main() -> Result<()> {
|
||||
let argv = args().collect::<Vec<String>>();
|
||||
let mut buf = Vec::new();
|
||||
let file_name: Option<OsString>;
|
||||
|
||||
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()
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
Some(path) => std::fs::File::open(path).unwrap_or_else(|_| {
|
||||
eprintln!("{}: {}: No such file or directory.", argv[0], argv[1]);
|
||||
eprintln!("{}: {}: {}", argv[0], path, err);
|
||||
exit(EX_UNAVAILABLE);
|
||||
}),
|
||||
}
|
||||
.read_to_end(&mut buf)
|
||||
.unwrap();
|
||||
})
|
||||
},
|
||||
}.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)?;
|
||||
|
|
Loading…
Reference in New Issue